diff --git a/.buildkite/pipelines/bazel_cache.yml b/.buildkite/pipelines/bazel_cache.yml
index daf56eb712a8..9aa961bcddbd 100644
--- a/.buildkite/pipelines/bazel_cache.yml
+++ b/.buildkite/pipelines/bazel_cache.yml
@@ -1,5 +1,7 @@
steps:
- label: ':pipeline: Create pipeline with priority'
+ agents:
+ queue: kibana-default
concurrency_group: bazel_macos
concurrency: 1
concurrency_method: eager
diff --git a/.buildkite/pipelines/es_snapshots/promote.yml b/.buildkite/pipelines/es_snapshots/promote.yml
index 5a003321246a..f2f7b423c94c 100644
--- a/.buildkite/pipelines/es_snapshots/promote.yml
+++ b/.buildkite/pipelines/es_snapshots/promote.yml
@@ -10,3 +10,5 @@ steps:
required: true
- label: Promote Snapshot
command: .buildkite/scripts/steps/es_snapshots/promote.sh
+ agents:
+ queue: kibana-default
diff --git a/.buildkite/pipelines/es_snapshots/verify.yml b/.buildkite/pipelines/es_snapshots/verify.yml
index f98626ef25c0..18f3440b4acf 100755
--- a/.buildkite/pipelines/es_snapshots/verify.yml
+++ b/.buildkite/pipelines/es_snapshots/verify.yml
@@ -14,6 +14,8 @@ steps:
- command: .buildkite/scripts/lifecycle/pre_build.sh
label: Pre-Build
timeout_in_minutes: 10
+ agents:
+ queue: kibana-default
- wait
@@ -65,7 +67,7 @@ steps:
- command: .buildkite/scripts/steps/test/jest_integration.sh
label: 'Jest Integration Tests'
- parallelism: 2
+ parallelism: 3
agents:
queue: n2-4
timeout_in_minutes: 120
@@ -85,6 +87,8 @@ steps:
- command: .buildkite/scripts/steps/es_snapshots/trigger_promote.sh
label: Trigger promotion
timeout_in_minutes: 10
+ agents:
+ queue: kibana-default
depends_on:
- default-cigroup
- default-cigroup-docker
@@ -98,3 +102,5 @@ steps:
- command: .buildkite/scripts/lifecycle/post_build.sh
label: Post-Build
timeout_in_minutes: 10
+ agents:
+ queue: kibana-default
diff --git a/.buildkite/pipelines/flaky_tests/groups.json b/.buildkite/pipelines/flaky_tests/groups.json
index b47ccf16a018..aa061af00bd6 100644
--- a/.buildkite/pipelines/flaky_tests/groups.json
+++ b/.buildkite/pipelines/flaky_tests/groups.json
@@ -13,6 +13,18 @@
"key": "oss/accessibility",
"name": "OSS Accessibility"
},
+ {
+ "key": "xpack/cypress/security_solution",
+ "name": "Security Solution - Cypress"
+ },
+ {
+ "key": "xpack/cypress/osquery_cypress",
+ "name": "Osquery - Cypress"
+ },
+ {
+ "key": "xpack/cypress/fleet_cypress",
+ "name": "Fleet - Cypress"
+ },
{
"key": "xpack/cigroup",
"name": "Default CI Group",
diff --git a/.buildkite/pipelines/flaky_tests/pipeline.js b/.buildkite/pipelines/flaky_tests/pipeline.js
index cb5c37bf5834..b7f93412edb3 100644
--- a/.buildkite/pipelines/flaky_tests/pipeline.js
+++ b/.buildkite/pipelines/flaky_tests/pipeline.js
@@ -51,6 +51,9 @@ const pipeline = {
{
command: '.buildkite/pipelines/flaky_tests/runner.sh',
label: 'Create pipeline',
+ agents: {
+ queue: 'kibana-default',
+ },
},
],
};
diff --git a/.buildkite/pipelines/flaky_tests/runner.js b/.buildkite/pipelines/flaky_tests/runner.js
index cff4f9c0f29e..aa2e1f21c149 100644
--- a/.buildkite/pipelines/flaky_tests/runner.js
+++ b/.buildkite/pipelines/flaky_tests/runner.js
@@ -7,6 +7,9 @@
*/
const { execSync } = require('child_process');
+const groups = /** @type {Array<{key: string, name: string, ciGroups: number }>} */ (
+ require('./groups.json').groups
+);
const concurrency = 25;
const defaultCount = concurrency * 2;
@@ -113,7 +116,7 @@ steps.push({
label: 'Build Kibana Distribution and Plugins',
agents: { queue: 'c2-8' },
key: 'build',
- if: "build.env('BUILD_ID_FOR_ARTIFACTS') == null || build.env('BUILD_ID_FOR_ARTIFACTS') == ''",
+ if: "build.env('KIBANA_BUILD_ID') == null || build.env('KIBANA_BUILD_ID') == ''",
});
for (const testSuite of testSuites) {
@@ -183,6 +186,24 @@ for (const testSuite of testSuites) {
concurrency_group: UUID,
concurrency_method: 'eager',
});
+ case 'cypress':
+ const CYPRESS_SUITE = CI_GROUP;
+ const group = groups.find((group) => group.key.includes(CYPRESS_SUITE));
+ if (!group) {
+ throw new Error(
+ `Group configuration was not found in groups.json for the following cypress suite: {${CYPRESS_SUITE}}.`
+ );
+ }
+ steps.push({
+ command: `.buildkite/scripts/steps/functional/${CYPRESS_SUITE}.sh`,
+ label: group.name,
+ agents: { queue: 'ci-group-6' },
+ depends_on: 'build',
+ parallelism: RUN_COUNT,
+ concurrency: concurrency,
+ concurrency_group: UUID,
+ concurrency_method: 'eager',
+ });
break;
}
}
diff --git a/.buildkite/pipelines/hourly.yml b/.buildkite/pipelines/hourly.yml
index 6953c146050e..a236f9c37b31 100644
--- a/.buildkite/pipelines/hourly.yml
+++ b/.buildkite/pipelines/hourly.yml
@@ -2,6 +2,8 @@ steps:
- command: .buildkite/scripts/lifecycle/pre_build.sh
label: Pre-Build
timeout_in_minutes: 10
+ agents:
+ queue: kibana-default
- wait
@@ -127,10 +129,10 @@ steps:
- command: .buildkite/scripts/steps/test/jest_integration.sh
label: 'Jest Integration Tests'
- parallelism: 2
+ parallelism: 3
agents:
queue: n2-4
- timeout_in_minutes: 90
+ timeout_in_minutes: 120
key: jest-integration
- command: .buildkite/scripts/steps/test/api_integration.sh
@@ -174,3 +176,5 @@ steps:
- command: .buildkite/scripts/lifecycle/post_build.sh
label: Post-Build
timeout_in_minutes: 10
+ agents:
+ queue: kibana-default
diff --git a/.buildkite/pipelines/on_merge.yml b/.buildkite/pipelines/on_merge.yml
index e5f6dcc2d1d5..c6acb48b3e21 100644
--- a/.buildkite/pipelines/on_merge.yml
+++ b/.buildkite/pipelines/on_merge.yml
@@ -5,6 +5,8 @@ steps:
- command: .buildkite/scripts/lifecycle/pre_build.sh
label: Pre-Build
timeout_in_minutes: 10
+ agents:
+ queue: kibana-default
- wait
@@ -34,3 +36,5 @@ steps:
- command: .buildkite/scripts/lifecycle/post_build.sh
label: Post-Build
timeout_in_minutes: 10
+ agents:
+ queue: kibana-default
diff --git a/.buildkite/pipelines/performance/daily.yml b/.buildkite/pipelines/performance/daily.yml
index 208456f9c67a..658ab3a72f18 100644
--- a/.buildkite/pipelines/performance/daily.yml
+++ b/.buildkite/pipelines/performance/daily.yml
@@ -1,33 +1,27 @@
steps:
- - block: ":gear: Performance Tests Configuration"
- prompt: "Fill out the details for performance test"
- fields:
- - text: ":arrows_counterclockwise: Iterations"
- key: "performance-test-iteration-count"
- hint: "How many times you want to run tests? "
- required: true
- if: build.env('PERF_TEST_COUNT') == null
-
- - label: ":male-mechanic::skin-tone-2: Pre-Build"
+ - label: ':male-mechanic::skin-tone-2: Pre-Build'
command: .buildkite/scripts/lifecycle/pre_build.sh
+ agents:
+ queue: kibana-default
- wait
- - label: ":factory_worker: Build Kibana Distribution and Plugins"
+ - label: ':factory_worker: Build Kibana Distribution and Plugins'
command: .buildkite/scripts/steps/build_kibana.sh
agents:
queue: c2-16
key: build
- - label: ":muscle: Performance Tests with Playwright config"
+ - label: ':muscle: Performance Tests with Playwright config'
command: .buildkite/scripts/steps/functional/performance_playwright.sh
agents:
- queue: c2-16
+ queue: kb-static-ubuntu
depends_on: build
- wait: ~
continue_on_failure: true
- - label: ":male_superhero::skin-tone-2: Post-Build"
+ - label: ':male_superhero::skin-tone-2: Post-Build'
command: .buildkite/scripts/lifecycle/post_build.sh
-
+ agents:
+ queue: kibana-default
diff --git a/.buildkite/pipelines/pull_request.yml b/.buildkite/pipelines/pull_request.yml
deleted file mode 100644
index 41c13bb403e1..000000000000
--- a/.buildkite/pipelines/pull_request.yml
+++ /dev/null
@@ -1,17 +0,0 @@
-env:
- GITHUB_COMMIT_STATUS_ENABLED: 'true'
- GITHUB_COMMIT_STATUS_CONTEXT: 'buildkite/kibana-pull-request'
-steps:
- - command: .buildkite/scripts/lifecycle/pre_build.sh
- label: Pre-Build
-
- - wait
-
- - command: echo 'Hello World'
- label: Test
-
- - wait: ~
- continue_on_failure: true
-
- - command: .buildkite/scripts/lifecycle/post_build.sh
- label: Post-Build
diff --git a/.buildkite/pipelines/pull_request/base.yml b/.buildkite/pipelines/pull_request/base.yml
index d832717906bb..894f4c4368a3 100644
--- a/.buildkite/pipelines/pull_request/base.yml
+++ b/.buildkite/pipelines/pull_request/base.yml
@@ -2,6 +2,8 @@ steps:
- command: .buildkite/scripts/lifecycle/pre_build.sh
label: Pre-Build
timeout_in_minutes: 10
+ agents:
+ queue: kibana-default
- wait
@@ -127,10 +129,10 @@ steps:
- command: .buildkite/scripts/steps/test/jest_integration.sh
label: 'Jest Integration Tests'
- parallelism: 2
+ parallelism: 3
agents:
queue: n2-4
- timeout_in_minutes: 90
+ timeout_in_minutes: 120
key: jest-integration
- command: .buildkite/scripts/steps/test/api_integration.sh
diff --git a/.buildkite/pipelines/pull_request/post_build.yml b/.buildkite/pipelines/pull_request/post_build.yml
index 4f252bf8abc1..63f716933458 100644
--- a/.buildkite/pipelines/pull_request/post_build.yml
+++ b/.buildkite/pipelines/pull_request/post_build.yml
@@ -4,3 +4,5 @@ steps:
- command: .buildkite/scripts/lifecycle/post_build.sh
label: Post-Build
+ agents:
+ queue: kibana-default
diff --git a/.buildkite/pipelines/purge_cloud_deployments.yml b/.buildkite/pipelines/purge_cloud_deployments.yml
index 8287abf2ca5a..9567f67a047f 100644
--- a/.buildkite/pipelines/purge_cloud_deployments.yml
+++ b/.buildkite/pipelines/purge_cloud_deployments.yml
@@ -2,3 +2,5 @@ steps:
- command: .buildkite/scripts/steps/cloud/purge.sh
label: Purge old cloud deployments
timeout_in_minutes: 10
+ agents:
+ queue: kibana-default
diff --git a/.buildkite/pipelines/update_demo_env.yml b/.buildkite/pipelines/update_demo_env.yml
index e2dfdd782fd4..12c4f296f5df 100644
--- a/.buildkite/pipelines/update_demo_env.yml
+++ b/.buildkite/pipelines/update_demo_env.yml
@@ -2,6 +2,8 @@ steps:
- command: .buildkite/scripts/steps/demo_env/es_and_init.sh
label: Initialize Environment and Deploy ES
timeout_in_minutes: 10
+ agents:
+ queue: kibana-default
- command: .buildkite/scripts/steps/demo_env/kibana.sh
label: Build and Deploy Kibana
diff --git a/.buildkite/scripts/steps/demo_env/kibana.sh b/.buildkite/scripts/steps/demo_env/kibana.sh
index f38d43b5479e..77f2151f952c 100755
--- a/.buildkite/scripts/steps/demo_env/kibana.sh
+++ b/.buildkite/scripts/steps/demo_env/kibana.sh
@@ -9,7 +9,7 @@ source "$(dirname "${0}")/config.sh"
export KIBANA_IMAGE="gcr.io/elastic-kibana-184716/demo/kibana:$DEPLOYMENT_NAME-$(git rev-parse HEAD)"
echo '--- Build Kibana'
-node scripts/build --debug --docker-images --example-plugins --skip-docker-ubi
+node scripts/build --debug --docker-images --example-plugins --skip-docker-ubi --skip-docker-cloud --skip-docker-contexts
echo '--- Build Docker image with example plugins'
cd target/example_plugins
diff --git a/.buildkite/scripts/steps/functional/performance_playwright.sh b/.buildkite/scripts/steps/functional/performance_playwright.sh
index c38ef5e56dbe..596304d156cf 100644
--- a/.buildkite/scripts/steps/functional/performance_playwright.sh
+++ b/.buildkite/scripts/steps/functional/performance_playwright.sh
@@ -1,24 +1,55 @@
-#!/bin/bash
+#!/usr/bin/env bash
-set -uo pipefail
+set -euo pipefail
-if [ -z "${PERF_TEST_COUNT+x}" ]; then
- TEST_COUNT="$(buildkite-agent meta-data get performance-test-iteration-count)"
-else
- TEST_COUNT=$PERF_TEST_COUNT
-fi
+source .buildkite/scripts/common/util.sh
-tput setab 2; tput setaf 0; echo "Performance test will be run at ${BUILDKITE_BRANCH} ${TEST_COUNT} times"
+.buildkite/scripts/bootstrap.sh
+.buildkite/scripts/download_build_artifacts.sh
-cat << EOF | buildkite-agent pipeline upload
-steps:
- - command: .buildkite/scripts/steps/functional/performance_sub_playwright.sh
- parallelism: "$TEST_COUNT"
- concurrency: 20
- concurrency_group: 'performance-test-group'
- agents:
- queue: c2-16
-EOF
+echo --- Run Performance Tests with Playwright config
+node scripts/es snapshot&
+esPid=$!
+export TEST_ES_URL=http://elastic:changeme@localhost:9200
+export TEST_ES_DISABLE_STARTUP=true
+
+sleep 120
+
+cd "$XPACK_DIR"
+
+jobId=$(npx uuid)
+export TEST_JOB_ID="$jobId"
+
+journeys=("ecommerce_dashboard" "flight_dashboard" "web_logs_dashboard" "promotion_tracking_dashboard")
+
+for i in "${journeys[@]}"; do
+ echo "JOURNEY[${i}] is running"
+
+ export TEST_PERFORMANCE_PHASE=WARMUP
+ export ELASTIC_APM_ACTIVE=false
+ export JOURNEY_NAME="${i}"
+
+ checks-reporter-with-killswitch "Run Performance Tests with Playwright Config (Journey:${i},Phase: WARMUP)" \
+ node scripts/functional_tests \
+ --config test/performance/config.playwright.ts \
+ --include "test/performance/tests/playwright/${i}.ts" \
+ --kibana-install-dir "$KIBANA_BUILD_LOCATION" \
+ --debug \
+ --bail
+
+ export TEST_PERFORMANCE_PHASE=TEST
+ export ELASTIC_APM_ACTIVE=true
+
+ checks-reporter-with-killswitch "Run Performance Tests with Playwright Config (Journey:${i},Phase: TEST)" \
+ node scripts/functional_tests \
+ --config test/performance/config.playwright.ts \
+ --include "test/performance/tests/playwright/${i}.ts" \
+ --kibana-install-dir "$KIBANA_BUILD_LOCATION" \
+ --debug \
+ --bail
+done
+
+kill "$esPid"
diff --git a/.buildkite/scripts/steps/functional/performance_sub_playwright.sh b/.buildkite/scripts/steps/functional/performance_sub_playwright.sh
deleted file mode 100644
index fee171aef9a4..000000000000
--- a/.buildkite/scripts/steps/functional/performance_sub_playwright.sh
+++ /dev/null
@@ -1,41 +0,0 @@
-#!/usr/bin/env bash
-
-set -euo pipefail
-
-source .buildkite/scripts/common/util.sh
-
-.buildkite/scripts/bootstrap.sh
-.buildkite/scripts/download_build_artifacts.sh
-
-echo --- Run Performance Tests with Playwright config
-
-node scripts/es snapshot&
-
-esPid=$!
-
-export TEST_PERFORMANCE_PHASE=WARMUP
-export TEST_ES_URL=http://elastic:changeme@localhost:9200
-export TEST_ES_DISABLE_STARTUP=true
-export ELASTIC_APM_ACTIVE=false
-
-sleep 120
-
-cd "$XPACK_DIR"
-
-# warmup round 1
-checks-reporter-with-killswitch "Run Performance Tests with Playwright Config (Phase: WARMUP)" \
- node scripts/functional_tests \
- --debug --bail \
- --kibana-install-dir "$KIBANA_BUILD_LOCATION" \
- --config "test/performance/config.playwright.ts";
-
-export TEST_PERFORMANCE_PHASE=TEST
-export ELASTIC_APM_ACTIVE=true
-
-checks-reporter-with-killswitch "Run Performance Tests with Playwright Config (Phase: TEST)" \
- node scripts/functional_tests \
- --debug --bail \
- --kibana-install-dir "$KIBANA_BUILD_LOCATION" \
- --config "test/performance/config.playwright.ts";
-
-kill "$esPid"
diff --git a/.buildkite/scripts/steps/functional/uptime.sh b/.buildkite/scripts/steps/functional/uptime.sh
index 5a59f4dfa48b..a1c8c2bf6c85 100755
--- a/.buildkite/scripts/steps/functional/uptime.sh
+++ b/.buildkite/scripts/steps/functional/uptime.sh
@@ -14,4 +14,4 @@ echo "--- Uptime @elastic/synthetics Tests"
cd "$XPACK_DIR"
checks-reporter-with-killswitch "Uptime @elastic/synthetics Tests" \
- node plugins/uptime/scripts/e2e.js --kibana-install-dir "$KIBANA_BUILD_LOCATION"
+ node plugins/uptime/scripts/e2e.js --kibana-install-dir "$KIBANA_BUILD_LOCATION" ${GREP:+--grep \"${GREP}\"}
diff --git a/.buildkite/scripts/steps/package_testing/test.sh b/.buildkite/scripts/steps/package_testing/test.sh
index 8fcb665b67a9..a9a46502d5b3 100755
--- a/.buildkite/scripts/steps/package_testing/test.sh
+++ b/.buildkite/scripts/steps/package_testing/test.sh
@@ -10,13 +10,13 @@ mkdir -p target
cd target
if [[ "$TEST_PACKAGE" == "deb" ]]; then
buildkite-agent artifact download 'kibana-*.deb' . --build "${KIBANA_BUILD_ID:-$BUILDKITE_BUILD_ID}"
- KIBANA_IP_ADDRESS="192.168.50.5"
+ KIBANA_IP_ADDRESS="192.168.56.5"
elif [[ "$TEST_PACKAGE" == "rpm" ]]; then
buildkite-agent artifact download 'kibana-*.rpm' . --build "${KIBANA_BUILD_ID:-$BUILDKITE_BUILD_ID}"
- KIBANA_IP_ADDRESS="192.168.50.6"
+ KIBANA_IP_ADDRESS="192.168.56.6"
elif [[ "$TEST_PACKAGE" == "docker" ]]; then
buildkite-agent artifact download "kibana-$KIBANA_PKG_VERSION-SNAPSHOT-docker-image.tar.gz" . --build "${KIBANA_BUILD_ID:-$BUILDKITE_BUILD_ID}"
- KIBANA_IP_ADDRESS="192.168.50.7"
+ KIBANA_IP_ADDRESS="192.168.56.7"
fi
cd ..
@@ -24,7 +24,7 @@ export VAGRANT_CWD=test/package
vagrant up "$TEST_PACKAGE" --no-provision
node scripts/es snapshot \
- -E network.bind_host=127.0.0.1,192.168.50.1 \
+ -E network.bind_host=127.0.0.1,192.168.56.1 \
-E discovery.type=single-node \
--license=trial &
while ! timeout 1 bash -c "echo > /dev/tcp/localhost/9200"; do sleep 30; done
@@ -33,7 +33,7 @@ vagrant provision "$TEST_PACKAGE"
export TEST_BROWSER_HEADLESS=1
export TEST_KIBANA_URL="http://elastic:changeme@$KIBANA_IP_ADDRESS:5601"
-export TEST_ES_URL=http://elastic:changeme@192.168.50.1:9200
+export TEST_ES_URL=http://elastic:changeme@192.168.56.1:9200
cd x-pack
node scripts/functional_test_runner.js --include-tag=smoke
diff --git a/.ci/package-testing/Jenkinsfile b/.ci/package-testing/Jenkinsfile
deleted file mode 100644
index fec7dc9ea4cd..000000000000
--- a/.ci/package-testing/Jenkinsfile
+++ /dev/null
@@ -1,29 +0,0 @@
-#!/bin/groovy
-library 'kibana-pipeline-library'
-kibanaLibrary.load()
-kibanaPipeline(timeoutMinutes: 120) {
- slackNotifications.onFailure {
- ciStats.trackBuild {
- workers.ci(ramDisk: false, name: "package-build", size: 'l', runErrorReporter: false) {
- withGcpServiceAccount.fromVaultSecret('secret/kibana-issues/dev/ci-artifacts-key', 'value') {
- kibanaPipeline.bash("test/scripts/jenkins_xpack_package_build.sh", "Package builds")
- }
- }
- def packageTypes = ['deb', 'docker', 'rpm']
- def workers = [:]
- packageTypes.each { type ->
- workers["package-${type}"] = {
- testPackage(type)
- }
- }
- parallel(workers)
- }
- }
-}
-def testPackage(packageType) {
- workers.ci(ramDisk: false, name: "package-${packageType}", size: 's', runErrorReporter: false) {
- withGcpServiceAccount.fromVaultSecret('secret/kibana-issues/dev/ci-artifacts-key', 'value') {
- kibanaPipeline.bash("test/scripts/jenkins_xpack_package_${packageType}.sh", "Execute package testing for ${packageType}")
- }
- }
-}
diff --git a/.eslintignore b/.eslintignore
index 7b9b7f77e837..9b745756b670 100644
--- a/.eslintignore
+++ b/.eslintignore
@@ -1,4 +1,5 @@
**/*.js.snap
+__tmp__
/.es
/.chromium
/build
@@ -31,6 +32,7 @@ snapshots.js
# package overrides
/packages/elastic-eslint-config-kibana
/packages/kbn-plugin-generator/template
+/packages/kbn-generate/templates
/packages/kbn-pm/dist
/packages/kbn-test/src/functional_test_runner/__tests__/fixtures/
/packages/kbn-test/src/functional_test_runner/lib/config/__tests__/fixtures/
diff --git a/.eslintrc.js b/.eslintrc.js
index 6c98a016469f..af9d77c4a966 100644
--- a/.eslintrc.js
+++ b/.eslintrc.js
@@ -6,6 +6,11 @@
* Side Public License, v 1.
*/
+const Path = require('path');
+const Fs = require('fs');
+
+const globby = require('globby');
+
const APACHE_2_0_LICENSE_HEADER = `
/*
* Licensed to Elasticsearch B.V. under one or more contributor
@@ -89,22 +94,16 @@ const SAFER_LODASH_SET_DEFINITELYTYPED_HEADER = `
*/
`;
+const packagePkgJsons = globby.sync('*/package.json', {
+ cwd: Path.resolve(__dirname, 'packages'),
+ absolute: true,
+});
+
/** Packages which should not be included within production code. */
-const DEV_PACKAGES = [
- 'kbn-babel-code-parser',
- 'kbn-dev-utils',
- 'kbn-cli-dev-mode',
- 'kbn-docs-utils',
- 'kbn-es*',
- 'kbn-eslint*',
- 'kbn-optimizer',
- 'kbn-plugin-generator',
- 'kbn-plugin-helpers',
- 'kbn-pm',
- 'kbn-storybook',
- 'kbn-telemetry-tools',
- 'kbn-test',
-];
+const DEV_PACKAGES = packagePkgJsons.flatMap((path) => {
+ const pkg = JSON.parse(Fs.readFileSync(path, 'utf8'));
+ return pkg.kibana && pkg.kibana.devOnly ? Path.dirname(Path.basename(path)) : [];
+});
/** Directories (at any depth) which include dev-only code. */
const DEV_DIRECTORIES = [
@@ -1489,6 +1488,10 @@ module.exports = {
'import/newline-after-import': 'error',
'react-hooks/exhaustive-deps': 'off',
'react/jsx-boolean-value': ['error', 'never'],
+ '@typescript-eslint/no-unused-vars': [
+ 'error',
+ { vars: 'all', args: 'after-used', ignoreRestSiblings: true, varsIgnorePattern: '^_' },
+ ],
},
},
{
@@ -1632,28 +1635,6 @@ module.exports = {
},
},
- /**
- * Prettier disables all conflicting rules, listing as last override so it takes precedence
- */
- {
- files: ['**/*'],
- rules: {
- ...require('eslint-config-prettier').rules,
- ...require('eslint-config-prettier/react').rules,
- ...require('eslint-config-prettier/@typescript-eslint').rules,
- },
- },
- /**
- * Enterprise Search Prettier override
- * Lints unnecessary backticks - @see https://github.com/prettier/eslint-config-prettier/blob/main/README.md#forbid-unnecessary-backticks
- */
- {
- files: ['x-pack/plugins/enterprise_search/**/*.{ts,tsx}'],
- rules: {
- quotes: ['error', 'single', { avoidEscape: true, allowTemplateLiterals: false }],
- },
- },
-
/**
* Platform Security Team overrides
*/
@@ -1768,5 +1749,34 @@ module.exports = {
'@kbn/eslint/no_export_all': 'error',
},
},
+
+ {
+ files: ['packages/kbn-type-summarizer/**/*.ts'],
+ rules: {
+ 'no-bitwise': 'off',
+ },
+ },
+
+ /**
+ * Prettier disables all conflicting rules, listing as last override so it takes precedence
+ */
+ {
+ files: ['**/*'],
+ rules: {
+ ...require('eslint-config-prettier').rules,
+ ...require('eslint-config-prettier/react').rules,
+ ...require('eslint-config-prettier/@typescript-eslint').rules,
+ },
+ },
+ /**
+ * Enterprise Search Prettier override
+ * Lints unnecessary backticks - @see https://github.com/prettier/eslint-config-prettier/blob/main/README.md#forbid-unnecessary-backticks
+ */
+ {
+ files: ['x-pack/plugins/enterprise_search/**/*.{ts,tsx}'],
+ rules: {
+ quotes: ['error', 'single', { avoidEscape: true, allowTemplateLiterals: false }],
+ },
+ },
],
};
diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS
index 63e335067199..b8563e3e44e8 100644
--- a/.github/CODEOWNERS
+++ b/.github/CODEOWNERS
@@ -72,8 +72,6 @@
/src/plugins/field_formats/ @elastic/kibana-app-services
/src/plugins/data_view_editor/ @elastic/kibana-app-services
/src/plugins/inspector/ @elastic/kibana-app-services
-/src/plugins/kibana_react/ @elastic/kibana-app-services
-/src/plugins/kibana_react/public/code_editor @elastic/kibana-presentation
/src/plugins/kibana_utils/ @elastic/kibana-app-services
/src/plugins/navigation/ @elastic/kibana-app-services
/src/plugins/share/ @elastic/kibana-app-services
@@ -223,9 +221,11 @@
/packages/kbn-test/ @elastic/kibana-operations
/packages/kbn-ui-shared-deps-npm/ @elastic/kibana-operations
/packages/kbn-ui-shared-deps-src/ @elastic/kibana-operations
+/packages/kbn-bazel-packages/ @elastic/kibana-operations
/packages/kbn-es-archiver/ @elastic/kibana-operations
/packages/kbn-utils/ @elastic/kibana-operations
/packages/kbn-cli-dev-mode/ @elastic/kibana-operations
+/packages/kbn-generate/ @elastic/kibana-operations
/src/cli/keystore/ @elastic/kibana-operations
/.ci/es-snapshots/ @elastic/kibana-operations
/.github/workflows/ @elastic/kibana-operations
@@ -416,14 +416,17 @@ x-pack/plugins/security_solution/cypress/upgrade_integration @elastic/security-e
x-pack/plugins/security_solution/cypress/README.md @elastic/security-engineering-productivity
x-pack/test/security_solution_cypress @elastic/security-engineering-productivity
+## Security Solution sub teams - adaptive-workload-protection
+x-pack/plugins/session_view @elastic/awp-platform
+
# Security Intelligence And Analytics
/x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules @elastic/security-intelligence-analytics
# Security Asset Management
/x-pack/plugins/osquery @elastic/security-asset-management
-# Cloud Posture Security
-/x-pack/plugins/cloud_security_posture/ @elastic/cloud-posture-security
+# Cloud Security Posture
+/x-pack/plugins/cloud_security_posture/ @elastic/cloud-security-posture-control-plane
# Design (at the bottom for specificity of SASS files)
**/*.scss @elastic/kibana-design
@@ -464,9 +467,11 @@ x-pack/test/security_solution_cypress @elastic/security-engineering-productivity
#CC# /x-pack/plugins/reporting/ @elastic/kibana-reporting-services
# EUI design
-/src/plugins/kibana_react/public/page_template/ @elastic/eui-design @elastic/kibana-app-services
+/src/plugins/kibana_react/public/page_template/ @elastic/eui-design @elastic/shared-ux
# Application Experience
## Shared UX
-/src/plugins/shared_ux @elastic/shared-ux
+/src/plugins/shared_ux/ @elastic/shared-ux
+/src/plugins/kibana_react/ @elastic/shared-ux
+/src/plugins/kibana_react/public/code_editor @elastic/kibana-presentation
diff --git a/.github/workflows/add-to-imui-project.yml b/.github/workflows/add-to-imui-project.yml
new file mode 100644
index 000000000000..3cf120b2e81b
--- /dev/null
+++ b/.github/workflows/add-to-imui-project.yml
@@ -0,0 +1,31 @@
+name: Add to Infra Monitoring UI project
+on:
+ issues:
+ types:
+ - labeled
+jobs:
+ add_to_project:
+ runs-on: ubuntu-latest
+ if: |
+ contains(github.event.issue.labels.*.name, 'Team:Infra Monitoring UI') ||
+ contains(github.event.issue.labels.*.name, 'Feature:Stack Monitoring') ||
+ contains(github.event.issue.labels.*.name, 'Feature:Logs UI') ||
+ contains(github.event.issue.labels.*.name, 'Feature:Metrics UI')
+ steps:
+ - uses: octokit/graphql-action@v2.x
+ id: add_to_project
+ with:
+ headers: '{"GraphQL-Features": "projects_next_graphql"}'
+ query: |
+ mutation add_to_project($projectid:ID!,$contentid:ID!) {
+ addProjectNextItem(input:{projectId:$projectid contentId:$contentid}) {
+ projectNextItem {
+ id
+ }
+ }
+ }
+ projectid: ${{ env.PROJECT_ID }}
+ contentid: ${{ github.event.issue.node_id }}
+ env:
+ PROJECT_ID: "PN_kwDOAGc3Zs1EEA"
+ GITHUB_TOKEN: ${{ secrets.PROJECT_ASSIGNER_TOKEN }}
diff --git a/.github/workflows/backport-next.yml b/.github/workflows/backport-next.yml
deleted file mode 100644
index 6779bb424724..000000000000
--- a/.github/workflows/backport-next.yml
+++ /dev/null
@@ -1,27 +0,0 @@
-on:
- pull_request_target:
- branches:
- - main
- types:
- - labeled
- - closed
-
-jobs:
- backport:
- name: Backport PR
- runs-on: ubuntu-latest
- if: |
- github.event.pull_request.merged == true
- && contains(github.event.pull_request.labels.*.name, 'auto-backport-next')
- && (
- (github.event.action == 'labeled' && github.event.label.name == 'auto-backport-next')
- || (github.event.action == 'closed')
- )
- steps:
- - name: Backport Action
- uses: sqren/backport-github-action@v7.3.1
- with:
- github_token: ${{secrets.KIBANAMACHINE_TOKEN}}
-
- - name: Backport log
- run: cat /home/runner/.backport/backport.log
diff --git a/.github/workflows/backport.yml b/.github/workflows/backport.yml
index d126ea6ec9b3..375854b9c54b 100644
--- a/.github/workflows/backport.yml
+++ b/.github/workflows/backport.yml
@@ -9,6 +9,7 @@ on:
jobs:
backport:
name: Backport PR
+ runs-on: ubuntu-latest
if: |
github.event.pull_request.merged == true
&& contains(github.event.pull_request.labels.*.name, 'auto-backport')
@@ -16,26 +17,11 @@ jobs:
(github.event.action == 'labeled' && github.event.label.name == 'auto-backport')
|| (github.event.action == 'closed')
)
- runs-on: ubuntu-latest
steps:
- - name: Checkout Actions
- uses: actions/checkout@v2
- with:
- repository: 'elastic/kibana-github-actions'
- ref: main
- path: ./actions
-
- - name: Install Actions
- run: npm install --production --prefix ./actions
-
- - name: Fix Version Label Gaps
- uses: ./actions/fix-version-gaps
+ - name: Backport Action
+ uses: sqren/backport-github-action@v7.4.0
with:
github_token: ${{secrets.KIBANAMACHINE_TOKEN}}
- - name: Run Backport
- uses: ./actions/backport
- with:
- github_token: ${{secrets.KIBANAMACHINE_TOKEN}}
- commit_user: kibanamachine
- commit_email: 42973632+kibanamachine@users.noreply.github.com
+ - name: Backport log
+ run: cat ~/.backport/backport.log
diff --git a/.github/workflows/label-qa-fixed-in.yml b/.github/workflows/label-qa-fixed-in.yml
index 836aa308e92c..99803c2c4e88 100644
--- a/.github/workflows/label-qa-fixed-in.yml
+++ b/.github/workflows/label-qa-fixed-in.yml
@@ -19,7 +19,7 @@ jobs:
github.event.pull_request.merged_at &&
contains(github.event.pull_request.labels.*.name, 'Team:Fleet')
outputs:
- matrix: ${{ steps.issues_to_label.outputs.value }}
+ issue_ids: ${{ steps.issues_to_label.outputs.value }}
label_ids: ${{ steps.label_ids.outputs.value }}
steps:
- uses: octokit/graphql-action@v2.x
@@ -66,22 +66,28 @@ jobs:
label_issues:
needs: fetch_issues_to_label
runs-on: ubuntu-latest
- # For each issue closed by the PR run this job
+
+ # For each issue closed by the PR x each label to apply, run this job
+ if: |
+ fromJSON(needs.fetch_issues_to_label.outputs.issue_ids).length > 0 &&
+ fromJSON(needs.fetch_issues_to_label.outputs.label_ids).length > 0
strategy:
matrix:
- issueNodeId: ${{ fromJSON(needs.fetch_issues_to_label.outputs.matrix) }}
- name: Label issue ${{ matrix.issueNodeId }}
+ issueId: ${{ fromJSON(needs.fetch_issues_to_label.outputs.issue_ids) }}
+ labelId: ${{ fromJSON(needs.fetch_issues_to_label.outputs.label_ids) }}
+
+ name: Label issue ${{ matrix.issueId }} with ${{ matrix.labelId }}
steps:
- uses: octokit/graphql-action@v2.x
id: add_labels_to_closed_issue
with:
query: |
- mutation add_label($issueid: ID!, $labelids:[ID!]!) {
- addLabelsToLabelable(input: {labelableId: $issueid, labelIds: $labelids}) {
+ mutation add_label($issueid: ID!, $labelid:ID!) {
+ addLabelsToLabelable(input: {labelableId: $issueid, labelIds: [$labelid]}) {
clientMutationId
}
}
- issueid: ${{ matrix.issueNodeId }}
- labelids: ${{ fromJSON(needs.fetch_issues_to_label.outputs.label_ids) }}
+ issueid: ${{ matrix.issueId }}
+ labelid: ${{ matrix.labelId }}
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
diff --git a/.github/workflows/project-assigner.yml b/.github/workflows/project-assigner.yml
index 65808dffd801..8c381dd1ecde 100644
--- a/.github/workflows/project-assigner.yml
+++ b/.github/workflows/project-assigner.yml
@@ -18,8 +18,6 @@ jobs:
{"label": "Feature:Canvas", "projectNumber": 38, "columnName": "Inbox"},
{"label": "Feature:Dashboard", "projectNumber": 68, "columnName": "Inbox"},
{"label": "Feature:Drilldowns", "projectNumber": 68, "columnName": "Inbox"},
- {"label": "Feature:Input Controls", "projectNumber": 72, "columnName": "Inbox"},
- {"label": "Team:Security", "projectNumber": 320, "columnName": "Awaiting triage", "projectScope": "org"},
- {"label": "Team:Operations", "projectNumber": 314, "columnName": "Triage", "projectScope": "org"}
+ {"label": "Feature:Input Controls", "projectNumber": 72, "columnName": "Inbox"}
]
ghToken: ${{ secrets.PROJECT_ASSIGNER_TOKEN }}
diff --git a/.gitignore b/.gitignore
index 818d3a472d52..4704247e6f54 100644
--- a/.gitignore
+++ b/.gitignore
@@ -20,6 +20,7 @@ target
*.iml
*.log
types.eslint.config.js
+__tmp__
# Ignore example plugin builds
/examples/*/build
@@ -95,4 +96,3 @@ fleet-server-*
elastic-agent.yml
fleet-server.yml
-/x-pack/plugins/fleet/server/bundled_packages
diff --git a/.i18nrc.json b/.i18nrc.json
index 5c362908a187..eeb2578ef347 100644
--- a/.i18nrc.json
+++ b/.i18nrc.json
@@ -66,7 +66,9 @@
"uiActions": "src/plugins/ui_actions",
"uiActionsExamples": "examples/ui_action_examples",
"usageCollection": "src/plugins/usage_collection",
+ "utils": "packages/kbn-securitysolution-utils/src",
"visDefaultEditor": "src/plugins/vis_default_editor",
+ "visTypeGauge": "src/plugins/vis_types/gauge",
"visTypeHeatmap": "src/plugins/vis_types/heatmap",
"visTypeMarkdown": "src/plugins/vis_type_markdown",
"visTypeMetric": "src/plugins/vis_types/metric",
diff --git a/WORKSPACE.bazel b/WORKSPACE.bazel
index 76c516ecc605..04f61b7f9506 100644
--- a/WORKSPACE.bazel
+++ b/WORKSPACE.bazel
@@ -64,4 +64,8 @@ yarn_install(
symlink_node_modules = True,
quiet = False,
frozen_lockfile = False,
+ environment = {
+ "SASS_BINARY_SITE": "https://us-central1-elastic-kibana-184716.cloudfunctions.net/kibana-ci-proxy-cache/node-sass",
+ "RE2_DOWNLOAD_MIRROR": "https://us-central1-elastic-kibana-184716.cloudfunctions.net/kibana-ci-proxy-cache/node-re2",
+ }
)
diff --git a/config/kibana.yml b/config/kibana.yml
index 9143b23d590f..8ca8eb673c27 100644
--- a/config/kibana.yml
+++ b/config/kibana.yml
@@ -128,7 +128,7 @@
#ops.interval: 5000
# Specifies locale to be used for all localizable strings, dates and number formats.
-# Supported languages are the following: English - en , by default , Chinese - zh-CN .
+# Supported languages are the following: English (default) "en", Chinese "zh-CN", Japanese "ja-JP", French "fr-FR".
#i18n.locale: "en"
# =================== Frequently used (Optional)===================
diff --git a/dev_docs/contributing/best_practices.mdx b/dev_docs/contributing/best_practices.mdx
index d7aa42946eac..e1f3b5ad4dbb 100644
--- a/dev_docs/contributing/best_practices.mdx
+++ b/dev_docs/contributing/best_practices.mdx
@@ -9,140 +9,12 @@ tags: ['kibana', 'onboarding', 'dev', 'architecture']
## General
-First things first, be sure to review our and check out all the available
-platform that can simplify plugin development.
+Be sure to follow our
+and .
+
+## Documentation
-## Developer documentation
-
-### High-level documentation
-
-#### Structure
-
-Refer to [divio documentation](https://documentation.divio.com/) for guidance on where and how to structure our high-level documentation.
-
- and
- sections are both _explanation_ oriented,
- covers both _tutorials_ and _How to_, and the section covers _reference_ material.
-
-#### Location
-
-If the information spans multiple plugins, consider adding it to the [dev_docs](https://github.com/elastic/kibana/tree/main/dev_docs) folder. If it is plugin specific, consider adding it inside the plugin folder. Write it in an mdx file if you would like it to show up in our new (beta) documentation system.
-
-
-
-To add docs into the new docs system, create an `.mdx` file that
-contains . Read about the syntax . An extra step is needed to add a menu item. will walk you through how to set the docs system
-up locally and edit the nav menu.
-
-
-
-#### Keep content fresh
-
-A fresh pair of eyes are invaluable. Recruit new hires to read, review and update documentation. Leads should also periodically review documentation to ensure it stays up to date. File issues any time you notice documentation is outdated.
-
-#### Consider your target audience
-
-Documentation in the Kibana Developer Guide is targeted towards developers building Kibana plugins. Keep implementation details about internal plugin code out of these docs.
-
-#### High to low level
-
-When a developer first lands in our docs, think about their journey. Introduce basic concepts before diving into details. The left navigation should be set up so documents on top are higher level than documents near the bottom.
-
-#### Think outside-in
-
-It's easy to forget what it felt like to first write code in Kibana, but do your best to frame these docs "outside-in". Don't use esoteric, internal language unless a definition is documented and linked. The fresh eyes of a new hire can be a great asset.
-
-### API documentation
-
-We automatically generate . The following guidelines will help ensure your are useful.
-
-#### Code comments
-
-Every publicly exposed function, class, interface, type, parameter and property should have a comment using JSDoc style comments.
-
-- Use `@param` tags for every function parameter.
-- Use `@returns` tags for return types.
-- Use `@throws` when appropriate.
-- Use `@beta` or `@deprecated` when appropriate.
-- Use `@removeBy {version}` on `@deprecated` APIs. The version should be the last version the API will work in. For example, `@removeBy 7.15` means the API will be removed in 7.16. This lets us avoid mid-release cycle coordination. The API can be removed as soon as the 7.15 branch is cut.
-- Use `@internal` to indicate this API item is intended for internal use only, which will also remove it from the docs.
-
-#### Interfaces vs inlined types
-
-Prefer types and interfaces over complex inline objects. For example, prefer:
-
-```ts
-/**
-* The SearchSpec interface contains settings for creating a new SearchService, like
-* username and password.
-*/
-export interface SearchSpec {
- /**
- * Stores the username. Duh,
- */
- username: string;
- /**
- * Stores the password. I hope it's encrypted!
- */
- password: string;
-}
-
- /**
- * Retrieve search services
- * @param searchSpec Configuration information for initializing the search service.
- * @returns the id of the search service
- */
-export getSearchService: (searchSpec: SearchSpec) => string;
-```
-
-over:
-
-```ts
-/**
- * Retrieve search services
- * @param searchSpec Configuration information for initializing the search service.
- * @returns the id of the search service
- */
-export getSearchService: (searchSpec: { username: string; password: string }) => string;
-```
-
-In the former, there will be a link to the `SearchSpec` interface with documentation for the `username` and `password` properties. In the latter the object will render inline, without comments:
-
-![prefer interfaces documentation](../assets/dev_docs_nested_object.png)
-
-#### Export every type used in a public API
-
-When a publicly exported API items references a private type, this results in a broken link in our docs system. The private type is, by proxy, part of your public API, and as such, should be exported.
-
-Do:
-
-```ts
-export interface AnInterface { bar: string };
-export type foo: string | AnInterface;
-```
-
-Don't:
-
-```ts
-interface AnInterface { bar: string };
-export type foo: string | AnInterface;
-```
-
-#### Avoid “Pick”
-
-`Pick` not only ends up being unhelpful in our documentation system, but it's also of limited help in your IDE. For that reason, avoid `Pick` and other similarly complex types on your public API items. Using these semantics internally is fine.
-
-![pick api documentation](../assets/api_doc_pick.png)
-
-### Example plugins
-
-Running Kibana with `yarn start --run-examples` will include all [example plugins](https://github.com/elastic/kibana/tree/main/examples). These are tested examples of platform services in use. We strongly encourage anyone providing a platform level service or to include a tutorial that links to a tested example plugin. This is better than relying on copied code snippets, which can quickly get out of date.
-
-You can also visit these [examples plugins hosted online](https://demo.kibana.dev/8.0/app/home). Note that because anonymous access is enabled, some
-of the demos are currently not working.
+Documentation best practices can be found .
## Performance
@@ -182,11 +54,27 @@ We use es-lint rules when possible, but please review our [styleguide](https://g
Es-lint overrides on a per-plugin level are discouraged.
-## Plugin best practices
+## Using the SavedObjectClient
-Don't export without reason. Make your public APIs as small as possible. You will have to maintain them, and consider backward compatibility when making changes.
+The should always be used for reading and writing saved objects that you manage. For saved objects managed by other plugins, their plugin APIs should be used instead.
+
+Good:
+```
+const dataView = dataViewStartContract.get(dataViewId);
+```
+
+Bad:
+```
+const dataView = savedObjectsClient.get(dataViewId) as DataView;
+```
+
+## Resusable react components
-Add `README.md` to all your plugins and services and include contact information.
+Use [EUI](https://elastic.github.io/eui) for all your basic UI components to create a consistent UI experience. We also have generic UI components offered from the plugin and the plugin.
+
+## Don't export code that doesn't need to be public
+
+Don't export without reason. Make your public APIs as small as possible. You will have to maintain them, and consider backward compatibility when making changes.
## Re-inventing the wheel
@@ -248,6 +136,77 @@ There are some exceptions where a separate repo makes sense. However, they are e
It may be tempting to get caught up in the dream of writing the next package which is published to npm and downloaded millions of times a week. Knowing the quality of developers that are working on Kibana, this is a real possibility. However, knowing which packages will see mass adoption is impossible to predict. Instead of jumping directly to writing code in a separate repo and accepting all of the complications that come along with it, prefer keeping code inside the Kibana repo. A [Kibana package](https://github.com/elastic/kibana/tree/main/packages) can be used to publish a package to npm, while still keeping the code inside the Kibana repo. Move code to an external repo only when there is a good reason, for example to enable external contributions.
+## Licensing
+
+
+
+Has there been a discussion about which license this feature should be available under? Open up a license issue in [https://github.com/elastic/dev](https://github.com/elastic/dev) if you are unsure.
+
+
+
+## Testing scenarios
+
+Every PR submitted should be accompanied by tests. Read through the for how to test.
+
+### Browser coverage
+
+Refer to the list of browsers and OS Kibana supports https://www.elastic.co/support/matrix
+
+Does the feature work efficiently on the below listed browsers
+ - chrome
+ - Firefox
+ - Safari
+ - IE11
+
+### Upgrade Scenarios
+ - Migration scenarios- Does the feature affect old indices, saved objects ?
+ - Has the feature been tested with Kibana aliases
+ - Read/Write privileges of the indices before and after the upgrade?
+
+### Test coverage
+ - Does the feature have sufficient unit test coverage? (does it handle storeinSessions?)
+ - Does the feature have sufficient Functional UI test coverage?
+ - Does the feature have sufficient Rest API coverage test coverage?
+ - Does the feature have sufficient Integration test coverage?
+
+### Environment configurations
+
+- Kibana should be fully [cross cluster search](https://www.elastic.co/guide/en/elasticsearch/reference/master/modules-cross-cluster-search.html) compatible (aside from admin UIs which only work on the local cluster).
+- How does your plugin behave when optional dependencies are disabled?
+- How does your app behave under anonymous access, or with security disabled?
+- Make sure to test your PR in a cloud environment. Read about the label which makes this very easy.
+
+
+## Backward compatibility
+
+Any time you change state that is part of a Saved Object you will have to write a .
+
+Never store state from another plugin in your Saved Objects or URLs unless it implements the . Remember to check for migrations when deserializing that state.
+
+If you expose state and you wish to allow other plugins to persist you must ensure it implements the . This is very common for `by value` entities, like visualizations that exist on a dashboard but are not part of the visualization library. If you make a breaking change to this state you must remember to register a migration for it.
+
+Saved objects exported from past Kibana versions should always continue to work. Bookmarked URLs should also always work. Check out to learn about migrating state in URLs.
+
+## Avoid these common mistakes
+
+### Treating Kibana's filesystem as durable storage
+
+Plugins should rarely, if ever, access Kibana's filesystem directly. Kibana instances are commonly ephemeral and anything written to the filesystem will potentially
+not be there on restart.
+
+### Storing state in server memory
+
+There are generally multiple instances of Kibana all hosted behind a round-robin load-balancer. As a result, storing state in server memory is risky as there is no
+guarantee that a single end-user's HTTP requests will be served by the same Kibana instance.
+
+### Using WebSockets
+
+Kibana has a number of platform services that don't work with WebSockets, for example authentication and authorization. If your use-case would benefit substantially
+from websockets, talk to the Kibana Core team about adding support. Do not hack around this limitation, everytime that someone has, it's created so many problems
+it's been eventually removed.
+
+
+
## Security best practices
When writing code for Kibana, be sure to follow these best practices to avoid common vulnerabilities. Refer to the included Open Web
diff --git a/dev_docs/contributing/documentation.mdx b/dev_docs/contributing/documentation.mdx
new file mode 100644
index 000000000000..ad9286dd07ab
--- /dev/null
+++ b/dev_docs/contributing/documentation.mdx
@@ -0,0 +1,195 @@
+---
+id: kibDocumentation
+slug: /kibana-dev-docs/contributing/documentation
+title: Documentation
+summary: Writing documentation during development
+date: 2022-03-01
+tags: ['kibana', 'onboarding', 'dev']
+---
+
+Docs should be written during development and accompany PRs when relevant. There are multiple types of documentation, and different places to add each.
+
+## End-user documentation
+
+User-facing features should be documented in [asciidoc](http://asciidoc.org/) at [https://github.com/elastic/kibana/tree/main/docs](https://github.com/elastic/kibana/tree/main/docs)
+
+To build the docs, you must clone the [elastic/docs](https://github.com/elastic/docs) repo as a sibling of your Kibana repo. Follow the instructions in that project’s [README](https://github.com/elastic/docs#readme) for getting the docs tooling set up.
+
+To build the docs:
+
+```bash
+node scripts/docs.js --open
+```
+
+## REST APIs
+REST APIs should be documented using the following formats:
+
+- [API doc template](https://raw.githubusercontent.com/elastic/docs/main/shared/api-ref-ex.asciidoc)
+- [API object definition template](https://raw.githubusercontent.com/elastic/docs/main/shared/api-definitions-ex.asciidoc)
+
+## Developer documentation
+
+Developer documentation can be segmented into two types: internal plugin details, and information on extending Kibana. Our [Kibana Developer Guide](https://docs.elastic.dev/kibana-dev-docs/getting-started/welcome) is meant to serve the latter. The guide can only be accessed internally at the moment, though the raw content is public in our [public repository]((https://github.com/elastic/kibana/tree/main/dev_docs)).
+
+Internal plugin details can be kept alongside the code it describes. Information about extending Kibana may go in the root of your plugin folder, or inside the top-level [dev_docs](https://github.com/elastic/kibana/tree/main/dev_docs) folder.
+
+
+
+Only `mdx` files with the appropriate are rendered inside the Developer Guide. Read about the syntax . Edit [kibana/nav-kibana-dev.docnav.json](https://github.com/elastic/kibana/blob/main/nav-kibana-dev.docnav.json) to have a link to your document appear in the navigation menu. Read for more details on how to add new content and test locally.
+
+
+
+### Structure
+
+The high-level developer documentation located in the [dev_docs](https://github.com/elastic/kibana/tree/main/dev_docs) folder attempts to follow [divio documentation](https://documentation.divio.com/) guidance. and sections are _explanation_ oriented, while
+ falls under both _tutorials_ and _how to_. The section is _reference_ material.
+
+Developers may choose to keep information that is specific to a particular plugin along side the code.
+
+### Best practices
+
+#### Keep content fresh
+
+A fresh pair of eyes are invaluable. Recruit new hires to read, review and update documentation. Leads should also periodically review documentation to ensure it stays up to date. File issues any time you notice documentation is outdated.
+
+#### Consider your target audience
+
+Documentation in the Kibana Developer Guide is targeted towards developers building Kibana plugins. Keep implementation details about internal plugin code out of these docs.
+
+#### High to low level
+
+When a developer first lands in our docs, think about their journey. Introduce basic concepts before diving into details. The left navigation should be set up so documents on top are higher level than documents near the bottom.
+
+#### Think outside-in
+
+It's easy to forget what it felt like to first write code in Kibana, but do your best to frame these docs "outside-in". Don't use esoteric, internal language unless a definition is documented and linked. The fresh eyes of a new hire can be a great asset.
+
+
+## API documentation
+
+We automatically generate . The following guidelines will help ensure your are useful.
+
+If you encounter an error of the form:
+
+
+
+You can increase [max memory](https://nodejs.org/api/cli.html#--max-old-space-sizesize-in-megabytes) for node as follows:
+
+```bash
+# As a runtime argument
+node --max-old-space-size=8192 foo/bar
+
+# As an env variable, in order to apply it systematically
+export NODE_OPTIONS=--max-old-space-size=8192
+```
+
+### Code comments
+
+Every function, class, interface, type, parameter and property that is exposed to other plugins should have a [TSDoc](https://tsdoc.org/)-style comment.
+
+- Use `@param` tags for every function parameter.
+- Use `@returns` tags for return types.
+- Use `@throws` when appropriate.
+- Use `@beta` or `@deprecated` when appropriate.
+- Use `@removeBy {version}` on `@deprecated` APIs. The version should be the last version the API will work in. For example, `@removeBy 7.15` means the API will be removed in 7.16. This lets us avoid mid-release cycle coordination. The API can be removed as soon as the 7.15 branch is cut.
+- Use `@internal` to indicate this API item is intended for internal use only, which will also remove it from the docs.
+
+### Interfaces vs inlined types
+
+Prefer types and interfaces over complex inline objects. For example, prefer:
+
+```ts
+/**
+* The SearchSpec interface contains settings for creating a new SearchService, like
+* username and password.
+*/
+export interface SearchSpec {
+ /**
+ * Stores the username. Duh,
+ */
+ username: string;
+ /**
+ * Stores the password. I hope it's encrypted!
+ */
+ password: string;
+}
+
+ /**
+ * Retrieve search services
+ * @param searchSpec Configuration information for initializing the search service.
+ * @returns the id of the search service
+ */
+export getSearchService: (searchSpec: SearchSpec) => string;
+```
+
+over:
+
+```ts
+/**
+ * Retrieve search services
+ * @param searchSpec Configuration information for initializing the search service.
+ * @returns the id of the search service
+ */
+export getSearchService: (searchSpec: { username: string; password: string }) => string;
+```
+
+In the former, there will be a link to the `SearchSpec` interface with documentation for the `username` and `password` properties. In the latter the object will render inline, without comments:
+
+![prefer interfaces documentation](../assets/dev_docs_nested_object.png)
+
+### Export every type used in a public API
+
+When a publicly exported API item references a private type, this results in a broken link in our docs system. The private type is, by proxy, part of your public API, and as such, should be exported.
+
+Do:
+
+```ts
+export interface AnInterface { bar: string };
+export type foo: string | AnInterface;
+```
+
+Don't:
+
+```ts
+interface AnInterface { bar: string };
+export type foo: string | AnInterface;
+```
+
+### Avoid “Pick”
+
+`Pick` not only ends up being unhelpful in our documentation system, but it's also of limited help in your IDE. For that reason, avoid `Pick` and other similarly complex types on your public API items. Using these semantics internally is fine.
+
+![pick api documentation](../assets/api_doc_pick.png)
+
+
+### Debugging tips
+
+There are three great ways to debug issues with the API infrastructure.
+
+1. Write a test
+
+[api_doc_suite.test.ts](https://github.com/elastic/kibana/blob/main/packages/kbn-docs-utils/src/api_docs/tests/api_doc_suite.test.ts) is a pretty comprehensive test suite that builds the test docs inside the [**fixtures** folder](https://github.com/elastic/kibana/tree/main/packages/kbn-docs-utils/src/api_docs/tests/__fixtures__/src).
+
+Edit the code inside `__fixtures__` to replicate the bug, write a test to track what should happen, then run `yarn jest api_doc_suite`.
+
+Once you've verified the bug is reproducible, use debug messages to narrow down the problem. This is much faster than running the entire suite to debug.
+
+2. Use [ts-ast-viewer.com](https://ts-ast-viewer.com/#code/KYDwDg9gTgLgBASwHY2FAZgQwMbDgMQgjgG8AoOSudJAfgC44AKdIxgZximQHMBKOAF4AfHE7ckPANxkAvkA)
+
+This nifty website will let you add some types and see how the system parses it. For example, the link above shows there is a `QuestionToken` as a sibling to the `FunctionType` which is why [this bug](https://github.com/elastic/kibana/issues/107145) reported children being lost. The API infra system didn't categorize the node as a function type node.
+
+3. Play around with `ts-morph` in a Code Sandbox.
+
+You can fork [this Code Sandbox example](https://codesandbox.io/s/typescript-compiler-issue-0lkwx?file=/src/use_ts_compiler.ts) that was used to explore how to generate the node signature in different ways (e.g. `node.getType.getText()` shows different results than `node.getType.getText(node)`). Here is [another messy example](https://codesandbox.io/s/admiring-field-5btxs).
+
+The code sandbox approach can be a lot faster to iterate compared to running it in Kibana.
+
+## Example plugins
+
+Running Kibana with `yarn start --run-examples` will include all [example plugins](https://github.com/elastic/kibana/tree/main/examples). These are tested examples of platform services in use. We strongly encourage anyone providing a platform level service or to include a tutorial that links to a tested example plugin. This is better than relying on copied code snippets, which can quickly get out of date.
+
+You can also visit these [examples plugins hosted online](https://demo.kibana.dev/8.2/app/home). Note that because anonymous access is enabled, some
+of the demos are currently not working.
diff --git a/docs/api/saved-objects/resolve_import_errors.asciidoc b/docs/api/saved-objects/resolve_import_errors.asciidoc
index 7a57e03875e3..162e9589e4f9 100644
--- a/docs/api/saved-objects/resolve_import_errors.asciidoc
+++ b/docs/api/saved-objects/resolve_import_errors.asciidoc
@@ -25,7 +25,7 @@ To resolve errors, you can:
==== Path parameters
`space_id`::
- (Optional, string) An identifier for the <>. When `space_id` is unspecfied in the URL, the default space is used.
+ (Optional, string) An identifier for the <>. When `space_id` is unspecified in the URL, the default space is used.
[[saved-objects-api-resolve-import-errors-query-params]]
==== Query parameters
diff --git a/docs/api/spaces-management/resolve_copy_saved_objects_conflicts.asciidoc b/docs/api/spaces-management/resolve_copy_saved_objects_conflicts.asciidoc
index d79df2c085b1..9d26f9656d3f 100644
--- a/docs/api/spaces-management/resolve_copy_saved_objects_conflicts.asciidoc
+++ b/docs/api/spaces-management/resolve_copy_saved_objects_conflicts.asciidoc
@@ -68,7 +68,7 @@ Execute the <>, w
`id`::::
(Required, string) The saved object ID.
`overwrite`::::
- (Required, boolean) When set to `true`, the saved object from the source space (desigated by the <>) overwrites the conflicting object in the destination space. When set to `false`, this does nothing.
+ (Required, boolean) When set to `true`, the saved object from the source space (designated by the <>) overwrites the conflicting object in the destination space. When set to `false`, this does nothing.
`destinationId`::::
(Optional, string) Specifies the destination ID that the copied object should have, if different from the current ID.
`ignoreMissingReferences`:::
diff --git a/docs/api/upgrade-assistant/default-field.asciidoc b/docs/api/upgrade-assistant/default-field.asciidoc
index 8bdcd359d566..bbe44d894963 100644
--- a/docs/api/upgrade-assistant/default-field.asciidoc
+++ b/docs/api/upgrade-assistant/default-field.asciidoc
@@ -26,7 +26,7 @@ GET /api/upgrade_assistant/add_query_default_field/myIndex
// KIBANA
<1> A required array of {es} field types that generate the list of fields.
-<2> An optional array of additional field names, dot-deliminated.
+<2> An optional array of additional field names, dot-delimited.
To add the `index.query.default_field` index setting to the specified index, {kib} generates an array of all fields from the index mapping.
The fields contain the types specified in `fieldTypes`. {kib} appends any other fields specified in `otherFields` to the array of default fields.
diff --git a/docs/apm/service-maps.asciidoc b/docs/apm/service-maps.asciidoc
index f76b9976dd1d..8a2beef22b6b 100644
--- a/docs/apm/service-maps.asciidoc
+++ b/docs/apm/service-maps.asciidoc
@@ -84,7 +84,7 @@ image:apm/images/red-service.png[APM red service]:: Max anomaly score **≥75**.
[role="screenshot"]
image::apm/images/apm-service-map-anomaly.png[Example view of anomaly scores on service maps in the APM app]
-If an anomaly has been detected, click *view anomalies* to view the anomaly detection metric viewier in the Machine learning app.
+If an anomaly has been detected, click *view anomalies* to view the anomaly detection metric viewer in the Machine learning app.
This time series analysis will display additional details on the severity and time of the detected anomalies.
To learn how to create a machine learning job, see <>.
diff --git a/docs/developer/advanced/development-es-snapshots.asciidoc b/docs/developer/advanced/development-es-snapshots.asciidoc
index 38146e65b632..ad9eb17ec309 100644
--- a/docs/developer/advanced/development-es-snapshots.asciidoc
+++ b/docs/developer/advanced/development-es-snapshots.asciidoc
@@ -13,6 +13,7 @@ https://ci.kibana.dev/es-snapshots[A dashboard] is available that shows the curr
2. Each snapshot is uploaded to a public Google Cloud Storage bucket, `kibana-ci-es-snapshots-daily`.
** At this point, the snapshot is not automatically used in CI or local development. It needs to be tested/verified first.
3. Each snapshot is tested with the latest commit of the corresponding {kib} branch, using the full CI suite.
+3a. If a test fails during snapshot verification the Kibana Operations team will skip it and create an issue for the team to fix the test, or work with the Elasticsearch team to get a fix implemented there. Once the fix is ready a Kibana PR can be opened to unskip the test.
4. After CI
** If the snapshot passes, it is promoted and automatically used in CI and local development.
** If the snapshot fails, the issue must be investigated and resolved. A new incompatibility may exist between {es} and {kib}.
diff --git a/docs/developer/architecture/kibana-platform-plugin-api.asciidoc b/docs/developer/architecture/kibana-platform-plugin-api.asciidoc
index 2005a90bb87b..9cf60cda76f7 100644
--- a/docs/developer/architecture/kibana-platform-plugin-api.asciidoc
+++ b/docs/developer/architecture/kibana-platform-plugin-api.asciidoc
@@ -221,7 +221,7 @@ These are the contracts exposed by the core services for each lifecycle:
[cols=",,",options="header",]
|===
|lifecycle |server contract|browser contract
-|_contructor_
+|_constructor_
|{kib-repo}blob/{branch}/docs/development/core/server/kibana-plugin-core-server.plugininitializercontext.md[PluginInitializerContext]
|{kib-repo}blob/{branch}/docs/development/core/public/kibana-plugin-core-public.plugininitializercontext.md[PluginInitializerContext]
diff --git a/docs/developer/best-practices/typescript.asciidoc b/docs/developer/best-practices/typescript.asciidoc
index 2631ee717c3d..92b6818a0986 100644
--- a/docs/developer/best-practices/typescript.asciidoc
+++ b/docs/developer/best-practices/typescript.asciidoc
@@ -51,7 +51,7 @@ Additionally, in order to migrate into project refs, you also need to make sure
],
"references": [
{ "path": "../../core/tsconfig.json" },
- // add references to other TypeScript projects your plugin dependes on
+ // add references to other TypeScript projects your plugin depends on
]
}
----
diff --git a/docs/developer/contributing/development-ci-metrics.asciidoc b/docs/developer/contributing/development-ci-metrics.asciidoc
index 3a133e64ea52..2905bd72a501 100644
--- a/docs/developer/contributing/development-ci-metrics.asciidoc
+++ b/docs/developer/contributing/development-ci-metrics.asciidoc
@@ -137,4 +137,4 @@ If you only want to run the build once you can run:
node scripts/build_kibana_platform_plugins --validate-limits --focus {pluginId}
-----------
-This command needs to apply production optimizations to get the right sizes, which means that the optimizer will take significantly longer to run and on most developmer machines will consume all of your machines resources for 20 minutes or more. If you'd like to multi-task while this is running you might need to limit the number of workers using the `--max-workers` flag.
\ No newline at end of file
+This command needs to apply production optimizations to get the right sizes, which means that the optimizer will take significantly longer to run and on most developer machines will consume all of your machines resources for 20 minutes or more. If you'd like to multi-task while this is running you might need to limit the number of workers using the `--max-workers` flag.
\ No newline at end of file
diff --git a/docs/developer/contributing/development-documentation.asciidoc b/docs/developer/contributing/development-documentation.asciidoc
index 7137d5bad051..9f221c0f0130 100644
--- a/docs/developer/contributing/development-documentation.asciidoc
+++ b/docs/developer/contributing/development-documentation.asciidoc
@@ -3,14 +3,6 @@
Docs should be written during development and accompany PRs when relevant. There are multiple types of documentation, and different places to add each.
-[discrete]
-=== Developer services documentation
-
-Documentation about specific services a plugin offers should be encapsulated in:
-
-* README.asciidoc at the base of the plugin folder.
-* Typescript comments for all public services.
-
[discrete]
=== End user documentation
@@ -31,7 +23,7 @@ node scripts/docs.js --open
REST APIs should be documented using the following recommended formats:
-* https://raw.githubusercontent.com/elastic/docs/master/shared/api-ref-ex.asciidoc[API doc templaate]
+* https://raw.githubusercontent.com/elastic/docs/master/shared/api-ref-ex.asciidoc[API doc template]
* https://raw.githubusercontent.com/elastic/docs/master/shared/api-definitions-ex.asciidoc[API object definition template]
[discrete]
diff --git a/docs/developer/contributing/development-package-tests.asciidoc b/docs/developer/contributing/development-package-tests.asciidoc
index 7883ce2d8320..2b4301399287 100644
--- a/docs/developer/contributing/development-package-tests.asciidoc
+++ b/docs/developer/contributing/development-package-tests.asciidoc
@@ -27,9 +27,9 @@ pip3 install --user ansible
[cols=",,",options="header",]
|===
|Hostname |IP |Description
-|deb |192.168.50.5 |Installation of Kibana’s deb package
-|rpm |192.168.50.6 |Installation of Kibana’s rpm package
-|docker |192.168.50.7 |Installation of Kibana’s docker image
+|deb |192.168.56.5 |Installation of Kibana’s deb package
+|rpm |192.168.56.6 |Installation of Kibana’s rpm package
+|docker |192.168.56.7 |Installation of Kibana’s docker image
|===
=== Running
@@ -49,11 +49,11 @@ vagrant provision
# Running functional tests
node scripts/es snapshot \
- -E network.bind_host=127.0.0.1,192.168.50.1 \
+ -E network.bind_host=127.0.0.1,192.168.56.1 \
-E discovery.type=single-node \
--license=trial
TEST_KIBANA_URL=http://elastic:changeme@:5601 \
-TEST_ES_URL=http://elastic:changeme@192.168.50.1:9200 \
+TEST_ES_URL=http://elastic:changeme@192.168.56.1:9200 \
node scripts/functional_test_runner.js --include-tag=smoke
```
diff --git a/docs/developer/contributing/interpreting-ci-failures.asciidoc b/docs/developer/contributing/interpreting-ci-failures.asciidoc
index ffbe448d79a4..eead720f03c6 100644
--- a/docs/developer/contributing/interpreting-ci-failures.asciidoc
+++ b/docs/developer/contributing/interpreting-ci-failures.asciidoc
@@ -22,7 +22,7 @@ image::images/job_view.png[Jenkins job view showing a test failure]
1. *Git Changes:* the list of commits that were in this build which weren't in the previous build. For Pull Requests this list is calculated by comparing against the most recent Pull Request which was tested, it is not limited to build for this specific Pull Request, so it's not very useful.
2. *Test Results:* A link to the test results screen, and shortcuts to the failed tests. Functional tests capture and store the log output from each specific test, and make it visible at these links. For other test runners only the error message is visible and log output must be tracked down in the *Pipeline Steps*.
3. *Google Cloud Storage (GCS) Upload Report:* Link to the screen which lists out the artifacts uploaded to GCS during this job execution.
-4. *Pipeline Steps:*: A breakdown of the pipline that was executed, along with individual log output for each step in the pipeline.
+4. *Pipeline Steps:*: A breakdown of the pipeline that was executed, along with individual log output for each step in the pipeline.
[discrete]
=== Viewing ciGroup/test Logs
diff --git a/docs/developer/index.asciidoc b/docs/developer/index.asciidoc
index 86d1d32e75e3..7d9116a72d06 100644
--- a/docs/developer/index.asciidoc
+++ b/docs/developer/index.asciidoc
@@ -2,6 +2,9 @@
= Developer guide
--
+
+NOTE: This is our legacy developer guide, and while we strive to keep it accurate, new content is added inside the {kib-repo}blob/{branch}/dev_docs[Kibana repo]. The rendered https://docs.elastic.dev/kibana-dev-docs/getting-started/welcome[guide] can only be accessed internally at the moment, though the raw content is public in our {kib-repo}blob/{branch}/dev_docs[public repository].
+
Contributing to {kib} can be daunting at first, but it doesn't have to be. The following sections should get you up and
running in no time. If you have any problems, file an issue in the https://github.com/elastic/kibana/issues[Kibana repo].
diff --git a/docs/developer/plugin-list.asciidoc b/docs/developer/plugin-list.asciidoc
index 2dd78be3c101..bf81ab1e0bec 100644
--- a/docs/developer/plugin-list.asciidoc
+++ b/docs/developer/plugin-list.asciidoc
@@ -297,6 +297,10 @@ It acts as a container for a particular visualization and options tabs. Contains
The plugin exposes the static DefaultEditorController class to consume.
+|{kib-repo}blob/{branch}/src/plugins/vis_types/gauge[visTypeGauge]
+|WARNING: Missing README.
+
+
|{kib-repo}blob/{branch}/src/plugins/vis_types/heatmap[visTypeHeatmap]
|WARNING: Missing README.
@@ -519,8 +523,12 @@ newly created modules as well.
Elastic.
-|{kib-repo}blob/{branch}/x-pack/plugins/monitoring[monitoring]
-|WARNING: Missing README.
+|{kib-repo}blob/{branch}/x-pack/plugins/monitoring/readme.md[monitoring]
+|This plugin provides the Stack Monitoring kibana application.
+
+
+|{kib-repo}blob/{branch}/x-pack/plugins/monitoring_collection/README.md[monitoringCollection]
+|This plugin allows for other plugins to add data to Kibana stack monitoring documents.
|{kib-repo}blob/{branch}/x-pack/plugins/observability/README.md[observability]
@@ -580,6 +588,10 @@ Kibana.
|Welcome to the Kibana Security Solution plugin! This README will go over getting started with development and testing.
+|{kib-repo}blob/{branch}/x-pack/plugins/session_view/README.md[sessionView]
+|Session View is meant to provide a visualization into what is going on in a particular Linux environment where the agent is running. It looks likes a terminal emulator; however, it is a tool for introspecting process activity and understanding user and service behaviour in your Linux servers and infrastructure. It is a time-ordered series of process executions displayed in a tree over time.
+
+
|{kib-repo}blob/{branch}/x-pack/plugins/snapshot_restore/README.md[snapshotRestore]
|or
diff --git a/docs/development/core/public/kibana-plugin-core-public.asyncplugin.md b/docs/development/core/public/kibana-plugin-core-public.asyncplugin.md
deleted file mode 100644
index cb9559dddc68..000000000000
--- a/docs/development/core/public/kibana-plugin-core-public.asyncplugin.md
+++ /dev/null
@@ -1,27 +0,0 @@
-
-
-[Home](./index.md) > [kibana-plugin-core-public](./kibana-plugin-core-public.md) > [AsyncPlugin](./kibana-plugin-core-public.asyncplugin.md)
-
-## AsyncPlugin interface
-
-> Warning: This API is now obsolete.
->
-> Asynchronous lifecycles are deprecated, and should be migrated to sync
->
-
-A plugin with asynchronous lifecycle methods.
-
-Signature:
-
-```typescript
-export interface AsyncPlugin
-```
-
-## Methods
-
-| Method | Description |
-| --- | --- |
-| [setup(core, plugins)](./kibana-plugin-core-public.asyncplugin.setup.md) | |
-| [start(core, plugins)](./kibana-plugin-core-public.asyncplugin.start.md) | |
-| [stop()?](./kibana-plugin-core-public.asyncplugin.stop.md) | (Optional) |
-
diff --git a/docs/development/core/public/kibana-plugin-core-public.asyncplugin.setup.md b/docs/development/core/public/kibana-plugin-core-public.asyncplugin.setup.md
deleted file mode 100644
index 67a5dad22a0a..000000000000
--- a/docs/development/core/public/kibana-plugin-core-public.asyncplugin.setup.md
+++ /dev/null
@@ -1,23 +0,0 @@
-
-
-[Home](./index.md) > [kibana-plugin-core-public](./kibana-plugin-core-public.md) > [AsyncPlugin](./kibana-plugin-core-public.asyncplugin.md) > [setup](./kibana-plugin-core-public.asyncplugin.setup.md)
-
-## AsyncPlugin.setup() method
-
-Signature:
-
-```typescript
-setup(core: CoreSetup, plugins: TPluginsSetup): TSetup | Promise;
-```
-
-## Parameters
-
-| Parameter | Type | Description |
-| --- | --- | --- |
-| core | CoreSetup<TPluginsStart, TStart> | |
-| plugins | TPluginsSetup | |
-
-Returns:
-
-TSetup \| Promise<TSetup>
-
diff --git a/docs/development/core/public/kibana-plugin-core-public.asyncplugin.start.md b/docs/development/core/public/kibana-plugin-core-public.asyncplugin.start.md
deleted file mode 100644
index 89554a1afaf1..000000000000
--- a/docs/development/core/public/kibana-plugin-core-public.asyncplugin.start.md
+++ /dev/null
@@ -1,23 +0,0 @@
-
-
-[Home](./index.md) > [kibana-plugin-core-public](./kibana-plugin-core-public.md) > [AsyncPlugin](./kibana-plugin-core-public.asyncplugin.md) > [start](./kibana-plugin-core-public.asyncplugin.start.md)
-
-## AsyncPlugin.start() method
-
-Signature:
-
-```typescript
-start(core: CoreStart, plugins: TPluginsStart): TStart | Promise;
-```
-
-## Parameters
-
-| Parameter | Type | Description |
-| --- | --- | --- |
-| core | CoreStart | |
-| plugins | TPluginsStart | |
-
-Returns:
-
-TStart \| Promise<TStart>
-
diff --git a/docs/development/core/public/kibana-plugin-core-public.asyncplugin.stop.md b/docs/development/core/public/kibana-plugin-core-public.asyncplugin.stop.md
deleted file mode 100644
index 3fb7504879cf..000000000000
--- a/docs/development/core/public/kibana-plugin-core-public.asyncplugin.stop.md
+++ /dev/null
@@ -1,15 +0,0 @@
-
-
-[Home](./index.md) > [kibana-plugin-core-public](./kibana-plugin-core-public.md) > [AsyncPlugin](./kibana-plugin-core-public.asyncplugin.md) > [stop](./kibana-plugin-core-public.asyncplugin.stop.md)
-
-## AsyncPlugin.stop() method
-
-Signature:
-
-```typescript
-stop?(): void;
-```
-Returns:
-
-void
-
diff --git a/docs/development/core/public/kibana-plugin-core-public.coresetup.executioncontext.md b/docs/development/core/public/kibana-plugin-core-public.coresetup.executioncontext.md
new file mode 100644
index 000000000000..be5689ad7b08
--- /dev/null
+++ b/docs/development/core/public/kibana-plugin-core-public.coresetup.executioncontext.md
@@ -0,0 +1,13 @@
+
+
+[Home](./index.md) > [kibana-plugin-core-public](./kibana-plugin-core-public.md) > [CoreSetup](./kibana-plugin-core-public.coresetup.md) > [executionContext](./kibana-plugin-core-public.coresetup.executioncontext.md)
+
+## CoreSetup.executionContext property
+
+[ExecutionContextSetup](./kibana-plugin-core-public.executioncontextsetup.md)
+
+Signature:
+
+```typescript
+executionContext: ExecutionContextSetup;
+```
diff --git a/docs/development/core/public/kibana-plugin-core-public.coresetup.md b/docs/development/core/public/kibana-plugin-core-public.coresetup.md
index 9488b8a26b86..31793ec6f7a5 100644
--- a/docs/development/core/public/kibana-plugin-core-public.coresetup.md
+++ b/docs/development/core/public/kibana-plugin-core-public.coresetup.md
@@ -17,6 +17,7 @@ export interface CoreSetup
+
+[Home](./index.md) > [kibana-plugin-core-public](./kibana-plugin-core-public.md) > [CoreStart](./kibana-plugin-core-public.corestart.md) > [executionContext](./kibana-plugin-core-public.corestart.executioncontext.md)
+
+## CoreStart.executionContext property
+
+[ExecutionContextStart](./kibana-plugin-core-public.executioncontextstart.md)
+
+Signature:
+
+```typescript
+executionContext: ExecutionContextStart;
+```
diff --git a/docs/development/core/public/kibana-plugin-core-public.corestart.md b/docs/development/core/public/kibana-plugin-core-public.corestart.md
index ae67696e1250..edd80e1adb9f 100644
--- a/docs/development/core/public/kibana-plugin-core-public.corestart.md
+++ b/docs/development/core/public/kibana-plugin-core-public.corestart.md
@@ -20,6 +20,7 @@ export interface CoreStart
| [chrome](./kibana-plugin-core-public.corestart.chrome.md) | ChromeStart | [ChromeStart](./kibana-plugin-core-public.chromestart.md) |
| [deprecations](./kibana-plugin-core-public.corestart.deprecations.md) | DeprecationsServiceStart | [DeprecationsServiceStart](./kibana-plugin-core-public.deprecationsservicestart.md) |
| [docLinks](./kibana-plugin-core-public.corestart.doclinks.md) | DocLinksStart | [DocLinksStart](./kibana-plugin-core-public.doclinksstart.md) |
+| [executionContext](./kibana-plugin-core-public.corestart.executioncontext.md) | ExecutionContextStart | [ExecutionContextStart](./kibana-plugin-core-public.executioncontextstart.md) |
| [fatalErrors](./kibana-plugin-core-public.corestart.fatalerrors.md) | FatalErrorsStart | [FatalErrorsStart](./kibana-plugin-core-public.fatalerrorsstart.md) |
| [http](./kibana-plugin-core-public.corestart.http.md) | HttpStart | [HttpStart](./kibana-plugin-core-public.httpstart.md) |
| [i18n](./kibana-plugin-core-public.corestart.i18n.md) | I18nStart | [I18nStart](./kibana-plugin-core-public.i18nstart.md) |
diff --git a/docs/development/core/public/kibana-plugin-core-public.executioncontextsetup.clear.md b/docs/development/core/public/kibana-plugin-core-public.executioncontextsetup.clear.md
new file mode 100644
index 000000000000..94936b94d071
--- /dev/null
+++ b/docs/development/core/public/kibana-plugin-core-public.executioncontextsetup.clear.md
@@ -0,0 +1,17 @@
+
+
+[Home](./index.md) > [kibana-plugin-core-public](./kibana-plugin-core-public.md) > [ExecutionContextSetup](./kibana-plugin-core-public.executioncontextsetup.md) > [clear](./kibana-plugin-core-public.executioncontextsetup.clear.md)
+
+## ExecutionContextSetup.clear() method
+
+clears the context
+
+Signature:
+
+```typescript
+clear(): void;
+```
+Returns:
+
+void
+
diff --git a/docs/development/core/public/kibana-plugin-core-public.executioncontextsetup.context_.md b/docs/development/core/public/kibana-plugin-core-public.executioncontextsetup.context_.md
new file mode 100644
index 000000000000..d6c74db6d603
--- /dev/null
+++ b/docs/development/core/public/kibana-plugin-core-public.executioncontextsetup.context_.md
@@ -0,0 +1,13 @@
+
+
+[Home](./index.md) > [kibana-plugin-core-public](./kibana-plugin-core-public.md) > [ExecutionContextSetup](./kibana-plugin-core-public.executioncontextsetup.md) > [context$](./kibana-plugin-core-public.executioncontextsetup.context_.md)
+
+## ExecutionContextSetup.context$ property
+
+The current context observable
+
+Signature:
+
+```typescript
+context$: Observable;
+```
diff --git a/docs/development/core/public/kibana-plugin-core-public.executioncontextsetup.get.md b/docs/development/core/public/kibana-plugin-core-public.executioncontextsetup.get.md
new file mode 100644
index 000000000000..65e9b1218649
--- /dev/null
+++ b/docs/development/core/public/kibana-plugin-core-public.executioncontextsetup.get.md
@@ -0,0 +1,17 @@
+
+
+[Home](./index.md) > [kibana-plugin-core-public](./kibana-plugin-core-public.md) > [ExecutionContextSetup](./kibana-plugin-core-public.executioncontextsetup.md) > [get](./kibana-plugin-core-public.executioncontextsetup.get.md)
+
+## ExecutionContextSetup.get() method
+
+Get the current top level context
+
+Signature:
+
+```typescript
+get(): KibanaExecutionContext;
+```
+Returns:
+
+KibanaExecutionContext
+
diff --git a/docs/development/core/public/kibana-plugin-core-public.executioncontextsetup.getaslabels.md b/docs/development/core/public/kibana-plugin-core-public.executioncontextsetup.getaslabels.md
new file mode 100644
index 000000000000..0f0bda4e2913
--- /dev/null
+++ b/docs/development/core/public/kibana-plugin-core-public.executioncontextsetup.getaslabels.md
@@ -0,0 +1,17 @@
+
+
+[Home](./index.md) > [kibana-plugin-core-public](./kibana-plugin-core-public.md) > [ExecutionContextSetup](./kibana-plugin-core-public.executioncontextsetup.md) > [getAsLabels](./kibana-plugin-core-public.executioncontextsetup.getaslabels.md)
+
+## ExecutionContextSetup.getAsLabels() method
+
+returns apm labels
+
+Signature:
+
+```typescript
+getAsLabels(): Labels;
+```
+Returns:
+
+Labels
+
diff --git a/docs/development/core/public/kibana-plugin-core-public.executioncontextsetup.md b/docs/development/core/public/kibana-plugin-core-public.executioncontextsetup.md
new file mode 100644
index 000000000000..01581d2e80a5
--- /dev/null
+++ b/docs/development/core/public/kibana-plugin-core-public.executioncontextsetup.md
@@ -0,0 +1,30 @@
+
+
+[Home](./index.md) > [kibana-plugin-core-public](./kibana-plugin-core-public.md) > [ExecutionContextSetup](./kibana-plugin-core-public.executioncontextsetup.md)
+
+## ExecutionContextSetup interface
+
+Kibana execution context. Used to provide execution context to Elasticsearch, reporting, performance monitoring, etc.
+
+Signature:
+
+```typescript
+export interface ExecutionContextSetup
+```
+
+## Properties
+
+| Property | Type | Description |
+| --- | --- | --- |
+| [context$](./kibana-plugin-core-public.executioncontextsetup.context_.md) | Observable<KibanaExecutionContext> | The current context observable |
+
+## Methods
+
+| Method | Description |
+| --- | --- |
+| [clear()](./kibana-plugin-core-public.executioncontextsetup.clear.md) | clears the context |
+| [get()](./kibana-plugin-core-public.executioncontextsetup.get.md) | Get the current top level context |
+| [getAsLabels()](./kibana-plugin-core-public.executioncontextsetup.getaslabels.md) | returns apm labels |
+| [set(c$)](./kibana-plugin-core-public.executioncontextsetup.set.md) | Set the current top level context |
+| [withGlobalContext(context)](./kibana-plugin-core-public.executioncontextsetup.withglobalcontext.md) | merges the current top level context with the specific event context |
+
diff --git a/docs/development/core/public/kibana-plugin-core-public.executioncontextsetup.set.md b/docs/development/core/public/kibana-plugin-core-public.executioncontextsetup.set.md
new file mode 100644
index 000000000000..e3dcea78c827
--- /dev/null
+++ b/docs/development/core/public/kibana-plugin-core-public.executioncontextsetup.set.md
@@ -0,0 +1,24 @@
+
+
+[Home](./index.md) > [kibana-plugin-core-public](./kibana-plugin-core-public.md) > [ExecutionContextSetup](./kibana-plugin-core-public.executioncontextsetup.md) > [set](./kibana-plugin-core-public.executioncontextsetup.set.md)
+
+## ExecutionContextSetup.set() method
+
+Set the current top level context
+
+Signature:
+
+```typescript
+set(c$: KibanaExecutionContext): void;
+```
+
+## Parameters
+
+| Parameter | Type | Description |
+| --- | --- | --- |
+| c$ | KibanaExecutionContext | |
+
+Returns:
+
+void
+
diff --git a/docs/development/core/public/kibana-plugin-core-public.executioncontextsetup.withglobalcontext.md b/docs/development/core/public/kibana-plugin-core-public.executioncontextsetup.withglobalcontext.md
new file mode 100644
index 000000000000..574d0fd98975
--- /dev/null
+++ b/docs/development/core/public/kibana-plugin-core-public.executioncontextsetup.withglobalcontext.md
@@ -0,0 +1,24 @@
+
+
+[Home](./index.md) > [kibana-plugin-core-public](./kibana-plugin-core-public.md) > [ExecutionContextSetup](./kibana-plugin-core-public.executioncontextsetup.md) > [withGlobalContext](./kibana-plugin-core-public.executioncontextsetup.withglobalcontext.md)
+
+## ExecutionContextSetup.withGlobalContext() method
+
+merges the current top level context with the specific event context
+
+Signature:
+
+```typescript
+withGlobalContext(context?: KibanaExecutionContext): KibanaExecutionContext;
+```
+
+## Parameters
+
+| Parameter | Type | Description |
+| --- | --- | --- |
+| context | KibanaExecutionContext | |
+
+Returns:
+
+KibanaExecutionContext
+
diff --git a/docs/development/core/public/kibana-plugin-core-public.executioncontextstart.md b/docs/development/core/public/kibana-plugin-core-public.executioncontextstart.md
new file mode 100644
index 000000000000..0d210ba5bb1c
--- /dev/null
+++ b/docs/development/core/public/kibana-plugin-core-public.executioncontextstart.md
@@ -0,0 +1,13 @@
+
+
+[Home](./index.md) > [kibana-plugin-core-public](./kibana-plugin-core-public.md) > [ExecutionContextStart](./kibana-plugin-core-public.executioncontextstart.md)
+
+## ExecutionContextStart type
+
+See [ExecutionContextSetup](./kibana-plugin-core-public.executioncontextsetup.md).
+
+Signature:
+
+```typescript
+export declare type ExecutionContextStart = ExecutionContextSetup;
+```
diff --git a/docs/development/core/public/kibana-plugin-core-public.kibanaexecutioncontext.md b/docs/development/core/public/kibana-plugin-core-public.kibanaexecutioncontext.md
index 6266639b6397..d8f8a77d84b2 100644
--- a/docs/development/core/public/kibana-plugin-core-public.kibanaexecutioncontext.md
+++ b/docs/development/core/public/kibana-plugin-core-public.kibanaexecutioncontext.md
@@ -10,9 +10,10 @@ Represents a meta-information about a Kibana entity initiating a search request.
```typescript
export declare type KibanaExecutionContext = {
- readonly type: string;
- readonly name: string;
- readonly id: string;
+ readonly type?: string;
+ readonly name?: string;
+ readonly page?: string;
+ readonly id?: string;
readonly description?: string;
readonly url?: string;
child?: KibanaExecutionContext;
diff --git a/docs/development/core/public/kibana-plugin-core-public.md b/docs/development/core/public/kibana-plugin-core-public.md
index b51f5ed833fd..2e51a036dfe9 100644
--- a/docs/development/core/public/kibana-plugin-core-public.md
+++ b/docs/development/core/public/kibana-plugin-core-public.md
@@ -39,7 +39,6 @@ The plugin integrates with the core system via lifecycle events: `setup`
| [ApplicationStart](./kibana-plugin-core-public.applicationstart.md) | |
| [AppMountParameters](./kibana-plugin-core-public.appmountparameters.md) | |
| [AppNavOptions](./kibana-plugin-core-public.appnavoptions.md) | App navigation menu options |
-| [AsyncPlugin](./kibana-plugin-core-public.asyncplugin.md) | A plugin with asynchronous lifecycle methods. |
| [Capabilities](./kibana-plugin-core-public.capabilities.md) | The read-only set of capabilities available for the current UI session. Capabilities are simple key-value pairs of (string, boolean), where the string denotes the capability ID, and the boolean is a flag indicating if the capability is enabled or disabled. |
| [ChromeBadge](./kibana-plugin-core-public.chromebadge.md) | |
| [ChromeDocTitle](./kibana-plugin-core-public.chromedoctitle.md) | APIs for accessing and updating the document title. |
@@ -62,6 +61,7 @@ The plugin integrates with the core system via lifecycle events: `setup`
| [DeprecationsServiceStart](./kibana-plugin-core-public.deprecationsservicestart.md) | DeprecationsService provides methods to fetch domain deprecation details from the Kibana server. |
| [DocLinksStart](./kibana-plugin-core-public.doclinksstart.md) | |
| [ErrorToastOptions](./kibana-plugin-core-public.errortoastoptions.md) | Options available for [IToasts](./kibana-plugin-core-public.itoasts.md) error APIs. |
+| [ExecutionContextSetup](./kibana-plugin-core-public.executioncontextsetup.md) | Kibana execution context. Used to provide execution context to Elasticsearch, reporting, performance monitoring, etc. |
| [FatalErrorInfo](./kibana-plugin-core-public.fatalerrorinfo.md) | Represents the message
and stack
of a fatal Error |
| [FatalErrorsSetup](./kibana-plugin-core-public.fatalerrorssetup.md) | FatalErrors stop the Kibana Public Core and displays a fatal error screen with details about the Kibana build and the error. |
| [HttpFetchOptions](./kibana-plugin-core-public.httpfetchoptions.md) | All options that may be used with a [HttpHandler](./kibana-plugin-core-public.httphandler.md). |
@@ -160,6 +160,7 @@ The plugin integrates with the core system via lifecycle events: `setup`
| [ChromeBreadcrumb](./kibana-plugin-core-public.chromebreadcrumb.md) | |
| [ChromeHelpExtensionLinkBase](./kibana-plugin-core-public.chromehelpextensionlinkbase.md) | |
| [ChromeHelpExtensionMenuLink](./kibana-plugin-core-public.chromehelpextensionmenulink.md) | |
+| [ExecutionContextStart](./kibana-plugin-core-public.executioncontextstart.md) | See [ExecutionContextSetup](./kibana-plugin-core-public.executioncontextsetup.md). |
| [FatalErrorsStart](./kibana-plugin-core-public.fatalerrorsstart.md) | FatalErrors stop the Kibana Public Core and displays a fatal error screen with details about the Kibana build and the error. |
| [HttpStart](./kibana-plugin-core-public.httpstart.md) | See [HttpSetup](./kibana-plugin-core-public.httpsetup.md) |
| [IToasts](./kibana-plugin-core-public.itoasts.md) | Methods for adding and removing global toast messages. See [ToastsApi](./kibana-plugin-core-public.toastsapi.md). |
diff --git a/docs/development/core/public/kibana-plugin-core-public.plugininitializer.md b/docs/development/core/public/kibana-plugin-core-public.plugininitializer.md
index b7c3e11e492b..1fcc2999dfd2 100644
--- a/docs/development/core/public/kibana-plugin-core-public.plugininitializer.md
+++ b/docs/development/core/public/kibana-plugin-core-public.plugininitializer.md
@@ -9,5 +9,5 @@ The `plugin` export at the root of a plugin's `public` directory should conform
Signature:
```typescript
-export declare type PluginInitializer = (core: PluginInitializerContext) => Plugin | AsyncPlugin;
+export declare type PluginInitializer = (core: PluginInitializerContext) => Plugin;
```
diff --git a/docs/development/core/public/kibana-plugin-core-public.savedobjectsclient.bulkupdate.md b/docs/development/core/public/kibana-plugin-core-public.savedobjectsclient.bulkupdate.md
index 0e3bfb2bd896..0cbfe4fcdead 100644
--- a/docs/development/core/public/kibana-plugin-core-public.savedobjectsclient.bulkupdate.md
+++ b/docs/development/core/public/kibana-plugin-core-public.savedobjectsclient.bulkupdate.md
@@ -9,7 +9,7 @@ Update multiple documents at once
Signature:
```typescript
-bulkUpdate(objects?: SavedObjectsBulkUpdateObject[]): Promise>;
+bulkUpdate(objects?: SavedObjectsBulkUpdateObject[]): Promise>;
```
## Parameters
@@ -20,7 +20,7 @@ bulkUpdate(objects?: SavedObjectsBulkUpdateObject[]): PromiseReturns:
-Promise<SavedObjectsBatchResponse<unknown>>
+Promise<SavedObjectsBatchResponse<T>>
The result of the update operation containing both failed and updated saved objects.
diff --git a/docs/development/core/public/kibana-plugin-core-public.savedobjectsimportfailure.md b/docs/development/core/public/kibana-plugin-core-public.savedobjectsimportfailure.md
index be1a20b3c71a..e7de1014bdaf 100644
--- a/docs/development/core/public/kibana-plugin-core-public.savedobjectsimportfailure.md
+++ b/docs/development/core/public/kibana-plugin-core-public.savedobjectsimportfailure.md
@@ -20,6 +20,5 @@ export interface SavedObjectsImportFailure
| [id](./kibana-plugin-core-public.savedobjectsimportfailure.id.md) | string | |
| [meta](./kibana-plugin-core-public.savedobjectsimportfailure.meta.md) | { title?: string; icon?: string; } | |
| [overwrite?](./kibana-plugin-core-public.savedobjectsimportfailure.overwrite.md) | boolean | (Optional) If overwrite
is specified, an attempt was made to overwrite an existing object. |
-| [title?](./kibana-plugin-core-public.savedobjectsimportfailure.title.md) | string | (Optional) |
| [type](./kibana-plugin-core-public.savedobjectsimportfailure.type.md) | string | |
diff --git a/docs/development/core/public/kibana-plugin-core-public.savedobjectsimportfailure.title.md b/docs/development/core/public/kibana-plugin-core-public.savedobjectsimportfailure.title.md
deleted file mode 100644
index 0024358bda03..000000000000
--- a/docs/development/core/public/kibana-plugin-core-public.savedobjectsimportfailure.title.md
+++ /dev/null
@@ -1,16 +0,0 @@
-
-
-[Home](./index.md) > [kibana-plugin-core-public](./kibana-plugin-core-public.md) > [SavedObjectsImportFailure](./kibana-plugin-core-public.savedobjectsimportfailure.md) > [title](./kibana-plugin-core-public.savedobjectsimportfailure.title.md)
-
-## SavedObjectsImportFailure.title property
-
-> Warning: This API is now obsolete.
->
-> Use `meta.title` instead
->
-
-Signature:
-
-```typescript
-title?: string;
-```
diff --git a/docs/development/core/public/kibana-plugin-core-public.simplesavedobject._constructor_.md b/docs/development/core/public/kibana-plugin-core-public.simplesavedobject._constructor_.md
index f53b6e529286..412154f7ac2e 100644
--- a/docs/development/core/public/kibana-plugin-core-public.simplesavedobject._constructor_.md
+++ b/docs/development/core/public/kibana-plugin-core-public.simplesavedobject._constructor_.md
@@ -9,7 +9,7 @@ Constructs a new instance of the `SimpleSavedObject` class
Signature:
```typescript
-constructor(client: SavedObjectsClientContract, { id, type, version, attributes, error, references, migrationVersion, coreMigrationVersion, namespaces, }: SavedObjectType);
+constructor(client: SavedObjectsClientContract, { id, type, version, attributes, error, references, migrationVersion, coreMigrationVersion, namespaces, updated_at: updatedAt, }: SavedObjectType);
```
## Parameters
@@ -17,5 +17,5 @@ constructor(client: SavedObjectsClientContract, { id, type, version, attributes,
| Parameter | Type | Description |
| --- | --- | --- |
| client | SavedObjectsClientContract | |
-| { id, type, version, attributes, error, references, migrationVersion, coreMigrationVersion, namespaces, } | SavedObjectType<T> | |
+| { id, type, version, attributes, error, references, migrationVersion, coreMigrationVersion, namespaces, updated\_at: updatedAt, } | SavedObjectType<T> | |
diff --git a/docs/development/core/public/kibana-plugin-core-public.simplesavedobject.md b/docs/development/core/public/kibana-plugin-core-public.simplesavedobject.md
index 2aac93f9b5bc..512fc74d538e 100644
--- a/docs/development/core/public/kibana-plugin-core-public.simplesavedobject.md
+++ b/docs/development/core/public/kibana-plugin-core-public.simplesavedobject.md
@@ -18,7 +18,7 @@ export declare class SimpleSavedObject
| Constructor | Modifiers | Description |
| --- | --- | --- |
-| [(constructor)(client, { id, type, version, attributes, error, references, migrationVersion, coreMigrationVersion, namespaces, })](./kibana-plugin-core-public.simplesavedobject._constructor_.md) | | Constructs a new instance of the SimpleSavedObject
class |
+| [(constructor)(client, { id, type, version, attributes, error, references, migrationVersion, coreMigrationVersion, namespaces, updated\_at: updatedAt, })](./kibana-plugin-core-public.simplesavedobject._constructor_.md) | | Constructs a new instance of the SimpleSavedObject
class |
## Properties
@@ -33,6 +33,7 @@ export declare class SimpleSavedObject
| [namespaces](./kibana-plugin-core-public.simplesavedobject.namespaces.md) | | SavedObjectType<T>\['namespaces'\] | Space(s) that this saved object exists in. This attribute is not used for "global" saved object types which are registered with namespaceType: 'agnostic'
. |
| [references](./kibana-plugin-core-public.simplesavedobject.references.md) | | SavedObjectType<T>\['references'\] | |
| [type](./kibana-plugin-core-public.simplesavedobject.type.md) | | SavedObjectType<T>\['type'\] | |
+| [updatedAt](./kibana-plugin-core-public.simplesavedobject.updatedat.md) | | SavedObjectType<T>\['updated\_at'\] | |
## Methods
diff --git a/docs/development/core/public/kibana-plugin-core-public.simplesavedobject.updatedat.md b/docs/development/core/public/kibana-plugin-core-public.simplesavedobject.updatedat.md
new file mode 100644
index 000000000000..80b1f9596993
--- /dev/null
+++ b/docs/development/core/public/kibana-plugin-core-public.simplesavedobject.updatedat.md
@@ -0,0 +1,11 @@
+
+
+[Home](./index.md) > [kibana-plugin-core-public](./kibana-plugin-core-public.md) > [SimpleSavedObject](./kibana-plugin-core-public.simplesavedobject.md) > [updatedAt](./kibana-plugin-core-public.simplesavedobject.updatedat.md)
+
+## SimpleSavedObject.updatedAt property
+
+Signature:
+
+```typescript
+updatedAt: SavedObjectType['updated_at'];
+```
diff --git a/docs/development/core/server/kibana-plugin-core-server.elasticsearchclient.md b/docs/development/core/server/kibana-plugin-core-server.elasticsearchclient.md
index 9a04a1d58176..1dfb1ab7a0b4 100644
--- a/docs/development/core/server/kibana-plugin-core-server.elasticsearchclient.md
+++ b/docs/development/core/server/kibana-plugin-core-server.elasticsearchclient.md
@@ -9,5 +9,5 @@ Client used to query the elasticsearch cluster.
Signature:
```typescript
-export declare type ElasticsearchClient = Omit;
+export declare type ElasticsearchClient = Omit;
```
diff --git a/docs/development/core/server/kibana-plugin-core-server.elasticsearchservicesetup.legacy.md b/docs/development/core/server/kibana-plugin-core-server.elasticsearchservicesetup.legacy.md
index bcc2f474fa48..03e2be0da7a1 100644
--- a/docs/development/core/server/kibana-plugin-core-server.elasticsearchservicesetup.legacy.md
+++ b/docs/development/core/server/kibana-plugin-core-server.elasticsearchservicesetup.legacy.md
@@ -6,7 +6,6 @@
> Warning: This API is now obsolete.
>
-> Use [ElasticsearchServiceStart.legacy](./kibana-plugin-core-server.elasticsearchservicestart.legacy.md) instead.
>
Signature:
diff --git a/docs/development/core/server/kibana-plugin-core-server.elasticsearchservicestart.legacy.md b/docs/development/core/server/kibana-plugin-core-server.elasticsearchservicestart.legacy.md
deleted file mode 100644
index 844ebf3815a9..000000000000
--- a/docs/development/core/server/kibana-plugin-core-server.elasticsearchservicestart.legacy.md
+++ /dev/null
@@ -1,18 +0,0 @@
-
-
-[Home](./index.md) > [kibana-plugin-core-server](./kibana-plugin-core-server.md) > [ElasticsearchServiceStart](./kibana-plugin-core-server.elasticsearchservicestart.md) > [legacy](./kibana-plugin-core-server.elasticsearchservicestart.legacy.md)
-
-## ElasticsearchServiceStart.legacy property
-
-> Warning: This API is now obsolete.
->
-> Provided for the backward compatibility. Switch to the new elasticsearch client as soon as https://github.com/elastic/kibana/issues/35508 done.
->
-
-Signature:
-
-```typescript
-legacy: {
- readonly config$: Observable;
- };
-```
diff --git a/docs/development/core/server/kibana-plugin-core-server.elasticsearchservicestart.md b/docs/development/core/server/kibana-plugin-core-server.elasticsearchservicestart.md
index 5bd8f9d0a433..66ff94ee9c80 100644
--- a/docs/development/core/server/kibana-plugin-core-server.elasticsearchservicestart.md
+++ b/docs/development/core/server/kibana-plugin-core-server.elasticsearchservicestart.md
@@ -17,5 +17,4 @@ export interface ElasticsearchServiceStart
| --- | --- | --- |
| [client](./kibana-plugin-core-server.elasticsearchservicestart.client.md) | IClusterClient | A pre-configured [Elasticsearch client](./kibana-plugin-core-server.iclusterclient.md) |
| [createClient](./kibana-plugin-core-server.elasticsearchservicestart.createclient.md) | (type: string, clientConfig?: Partial<ElasticsearchClientConfig>) => ICustomClusterClient | Create application specific Elasticsearch cluster API client with customized config. See [IClusterClient](./kibana-plugin-core-server.iclusterclient.md). |
-| [legacy](./kibana-plugin-core-server.elasticsearchservicestart.legacy.md) | { readonly config$: Observable<ElasticsearchConfig>; } | |
diff --git a/docs/development/core/server/kibana-plugin-core-server.executioncontextsetup.getaslabels.md b/docs/development/core/server/kibana-plugin-core-server.executioncontextsetup.getaslabels.md
new file mode 100644
index 000000000000..c8816a3deee4
--- /dev/null
+++ b/docs/development/core/server/kibana-plugin-core-server.executioncontextsetup.getaslabels.md
@@ -0,0 +1,15 @@
+
+
+[Home](./index.md) > [kibana-plugin-core-server](./kibana-plugin-core-server.md) > [ExecutionContextSetup](./kibana-plugin-core-server.executioncontextsetup.md) > [getAsLabels](./kibana-plugin-core-server.executioncontextsetup.getaslabels.md)
+
+## ExecutionContextSetup.getAsLabels() method
+
+Signature:
+
+```typescript
+getAsLabels(): apm.Labels;
+```
+Returns:
+
+apm.Labels
+
diff --git a/docs/development/core/server/kibana-plugin-core-server.executioncontextsetup.md b/docs/development/core/server/kibana-plugin-core-server.executioncontextsetup.md
index 24591648ad95..7fdc4d1ec1d5 100644
--- a/docs/development/core/server/kibana-plugin-core-server.executioncontextsetup.md
+++ b/docs/development/core/server/kibana-plugin-core-server.executioncontextsetup.md
@@ -15,5 +15,6 @@ export interface ExecutionContextSetup
| Method | Description |
| --- | --- |
+| [getAsLabels()](./kibana-plugin-core-server.executioncontextsetup.getaslabels.md) | |
| [withContext(context, fn)](./kibana-plugin-core-server.executioncontextsetup.withcontext.md) | Keeps track of execution context while the passed function is executed. Data are carried over all async operations spawned by the passed function. The nested calls stack the registered context on top of each other. |
diff --git a/docs/development/core/server/kibana-plugin-core-server.httpservicesetup.auth.md b/docs/development/core/server/kibana-plugin-core-server.httpservicesetup.auth.md
deleted file mode 100644
index da348a2282b1..000000000000
--- a/docs/development/core/server/kibana-plugin-core-server.httpservicesetup.auth.md
+++ /dev/null
@@ -1,18 +0,0 @@
-
-
-[Home](./index.md) > [kibana-plugin-core-server](./kibana-plugin-core-server.md) > [HttpServiceSetup](./kibana-plugin-core-server.httpservicesetup.md) > [auth](./kibana-plugin-core-server.httpservicesetup.auth.md)
-
-## HttpServiceSetup.auth property
-
-> Warning: This API is now obsolete.
->
-> use [the start contract](./kibana-plugin-core-server.httpservicestart.auth.md) instead.
->
-
-Auth status. See [HttpAuth](./kibana-plugin-core-server.httpauth.md)
-
-Signature:
-
-```typescript
-auth: HttpAuth;
-```
diff --git a/docs/development/core/server/kibana-plugin-core-server.httpservicesetup.md b/docs/development/core/server/kibana-plugin-core-server.httpservicesetup.md
index 81ddeaaaa5a1..f3be1a9130b9 100644
--- a/docs/development/core/server/kibana-plugin-core-server.httpservicesetup.md
+++ b/docs/development/core/server/kibana-plugin-core-server.httpservicesetup.md
@@ -77,7 +77,6 @@ async (context, request, response) => {
| Property | Type | Description |
| --- | --- | --- |
-| [auth](./kibana-plugin-core-server.httpservicesetup.auth.md) | HttpAuth | Auth status. See [HttpAuth](./kibana-plugin-core-server.httpauth.md) |
| [basePath](./kibana-plugin-core-server.httpservicesetup.basepath.md) | IBasePath | Access or manipulate the Kibana base path See [IBasePath](./kibana-plugin-core-server.ibasepath.md). |
| [createCookieSessionStorageFactory](./kibana-plugin-core-server.httpservicesetup.createcookiesessionstoragefactory.md) | <T>(cookieOptions: SessionStorageCookieOptions<T>) => Promise<SessionStorageFactory<T>> | Creates cookie based session storage factory [SessionStorageFactory](./kibana-plugin-core-server.sessionstoragefactory.md) |
| [createRouter](./kibana-plugin-core-server.httpservicesetup.createrouter.md) | <Context extends RequestHandlerContext = RequestHandlerContext>() => IRouter<Context> | Provides ability to declare a handler function for a particular path and HTTP request method. |
diff --git a/docs/development/core/server/kibana-plugin-core-server.kibanaexecutioncontext.md b/docs/development/core/server/kibana-plugin-core-server.kibanaexecutioncontext.md
index 0d65a3662da6..792af8f69386 100644
--- a/docs/development/core/server/kibana-plugin-core-server.kibanaexecutioncontext.md
+++ b/docs/development/core/server/kibana-plugin-core-server.kibanaexecutioncontext.md
@@ -10,9 +10,10 @@ Represents a meta-information about a Kibana entity initiating a search request.
```typescript
export declare type KibanaExecutionContext = {
- readonly type: string;
- readonly name: string;
- readonly id: string;
+ readonly type?: string;
+ readonly name?: string;
+ readonly page?: string;
+ readonly id?: string;
readonly description?: string;
readonly url?: string;
child?: KibanaExecutionContext;
diff --git a/docs/development/core/server/kibana-plugin-core-server.savedobjectsimportfailure.md b/docs/development/core/server/kibana-plugin-core-server.savedobjectsimportfailure.md
index 52db837479cf..4bdc3d99028a 100644
--- a/docs/development/core/server/kibana-plugin-core-server.savedobjectsimportfailure.md
+++ b/docs/development/core/server/kibana-plugin-core-server.savedobjectsimportfailure.md
@@ -20,6 +20,5 @@ export interface SavedObjectsImportFailure
| [id](./kibana-plugin-core-server.savedobjectsimportfailure.id.md) | string | |
| [meta](./kibana-plugin-core-server.savedobjectsimportfailure.meta.md) | { title?: string; icon?: string; } | |
| [overwrite?](./kibana-plugin-core-server.savedobjectsimportfailure.overwrite.md) | boolean | (Optional) If overwrite
is specified, an attempt was made to overwrite an existing object. |
-| [title?](./kibana-plugin-core-server.savedobjectsimportfailure.title.md) | string | (Optional) |
| [type](./kibana-plugin-core-server.savedobjectsimportfailure.type.md) | string | |
diff --git a/docs/development/core/server/kibana-plugin-core-server.savedobjectsimportfailure.title.md b/docs/development/core/server/kibana-plugin-core-server.savedobjectsimportfailure.title.md
deleted file mode 100644
index 12326e6b0e4b..000000000000
--- a/docs/development/core/server/kibana-plugin-core-server.savedobjectsimportfailure.title.md
+++ /dev/null
@@ -1,16 +0,0 @@
-
-
-[Home](./index.md) > [kibana-plugin-core-server](./kibana-plugin-core-server.md) > [SavedObjectsImportFailure](./kibana-plugin-core-server.savedobjectsimportfailure.md) > [title](./kibana-plugin-core-server.savedobjectsimportfailure.title.md)
-
-## SavedObjectsImportFailure.title property
-
-> Warning: This API is now obsolete.
->
-> Use `meta.title` instead
->
-
-Signature:
-
-```typescript
-title?: string;
-```
diff --git a/docs/management/cases/add-connectors.asciidoc b/docs/management/cases/add-connectors.asciidoc
new file mode 100644
index 000000000000..cd0ed1e1b640
--- /dev/null
+++ b/docs/management/cases/add-connectors.asciidoc
@@ -0,0 +1,56 @@
+[[add-case-connectors]]
+== Add connectors
+
+preview::[]
+
+You can add connectors to cases to push information to these external incident
+management systems:
+
+* IBM Resilient
+* Jira
+* ServiceNow ITSM
+* ServiceNow SecOps
+* {swimlane}
+
+NOTE: To create connectors and send cases to external systems, you must have the
+appropriate {kib} feature privileges. Refer to <>.
+
+[discrete]
+[[create-case-connectors]]
+== Create connectors
+
+You can create connectors in *Management > {stack-manage-app} > {rules-ui}*, as
+described in <>. Alternatively, you can create them in
+*Management > {stack-manage-app} > Cases*:
+
+. Click *Edit external connection*.
++
+[role="screenshot"]
+image::images/cases-connectors.png[]
+
+. From the *Incident management system* list, select *Add new connector*.
+
+. Select an external incident management system.
+
+. Enter your required settings. Refer to <>,
+<>, <>, <>,
+or <> for connector configuration details.
+
+. Click *Save*.
+
+[discrete]
+[[edit-case-connector-settings]]
+== Edit connector settings
+
+You can create additional connectors, update existing connectors, change
+the default connector, and change case closure options.
+
+. Go to *Management > {stack-manage-app} > Cases*, click *Edit external connection*.
+
+. To change whether cases are automatically closed after they are sent to an
+external system, update the case closure options.
+
+. To change the default connector for new cases, select the connector from the
+*Incident management system* list.
+
+. To update a connector, click *Update * and edit the connector fields as required.
diff --git a/docs/management/cases/cases.asciidoc b/docs/management/cases/cases.asciidoc
new file mode 100644
index 000000000000..c08b99894eea
--- /dev/null
+++ b/docs/management/cases/cases.asciidoc
@@ -0,0 +1,22 @@
+[[cases]]
+== Cases
+
+preview::[]
+
+Cases are used to open and track issues directly in {kib}. All cases list
+the original reporter and all the users who contribute to a case (_participants_).
+You can also send cases to external incident management systems by configuring
+connectors.
+
+[role="screenshot"]
+image::images/cases.png[Cases page]
+
+NOTE: If you create cases in the {observability} or {security-app}, they are not
+visible in *{stack-manage-app}*. Likewise, the cases you create in
+*{stack-manage-app}* are not visible in the {observability} or {security-app}.
+You also cannot attach alerts from the {observability} or {security-app} to
+cases in *{stack-manage-app}*.
+
+* <>
+* <>
+* <>
\ No newline at end of file
diff --git a/docs/management/cases/images/cases-connectors.png b/docs/management/cases/images/cases-connectors.png
new file mode 100644
index 000000000000..95af429aef2d
Binary files /dev/null and b/docs/management/cases/images/cases-connectors.png differ
diff --git a/docs/management/cases/images/cases-visualization.png b/docs/management/cases/images/cases-visualization.png
new file mode 100644
index 000000000000..77f249f26d09
Binary files /dev/null and b/docs/management/cases/images/cases-visualization.png differ
diff --git a/docs/management/cases/images/cases.png b/docs/management/cases/images/cases.png
new file mode 100644
index 000000000000..7b0c551cb690
Binary files /dev/null and b/docs/management/cases/images/cases.png differ
diff --git a/docs/management/cases/index.asciidoc b/docs/management/cases/index.asciidoc
new file mode 100644
index 000000000000..981c8a9821a9
--- /dev/null
+++ b/docs/management/cases/index.asciidoc
@@ -0,0 +1,4 @@
+include::cases.asciidoc[]
+include::setup-cases.asciidoc[leveloffset=+1]
+include::manage-cases.asciidoc[leveloffset=+1]
+include::add-connectors.asciidoc[leveloffset=+1]
\ No newline at end of file
diff --git a/docs/management/cases/manage-cases.asciidoc b/docs/management/cases/manage-cases.asciidoc
new file mode 100644
index 000000000000..f4693ef25950
--- /dev/null
+++ b/docs/management/cases/manage-cases.asciidoc
@@ -0,0 +1,70 @@
+[[manage-cases]]
+== Open and manage cases
+
+preview::[]
+
+[[open-case]]
+=== Open a new case
+
+Open a new case to keep track of issues and share their details with colleagues.
+
+. Go to *Management > {stack-manage-app} > Cases*, then click *Create case*.
+
+. Give the case a name, add any relevant tags and a description.
++
+TIP: In the `Description` area, you can use
+https://www.markdownguide.org/cheat-sheet[Markdown] syntax to create formatted
+text.
+
+. For *External incident management system*, select a connector. For more
+information, refer to <>.
+
+. After you've completed all of the required fields, click *Create case*.
+
+[[add-case-visualization]]
+=== Add a visualization
+
+After you create a case, you can optionally add a visualization. For
+example, you can portray event and alert data through charts and graphs.
+
+[role="screenshot"]
+image::images/cases-visualization.png[Cases page]
+
+To add a visualization to a comment within your case:
+
+. Click the *Visualization* button. The *Add visualization* dialog appears.
+
+. Select an existing visualization from your Visualize Library or create a new
+visualization.
++
+IMPORTANT: Set an absolute time range for your visualization. This ensures your
+visualization doesn't change over time after you save it to your case and
+provides important context for viewers.
+
+. After you've finished creating your visualization, click *Save and return* to
+go back to your case.
+
+. Click *Preview* to see how the visualization will appear in the case comment.
+
+. Click *Add Comment* to add the visualization to your case.
+
+After a visualization has been added to a case, you can modify or interact with
+it by clicking the *Open Visualization* option in the comment menu.
+
+[[manage-case]]
+=== Manage cases
+
+In *Management > {stack-manage-app} > Cases*, you can search cases and filter
+them by tags, reporter.
+
+To view a case, click on its name. You can then:
+
+* Add a new comment.
+* Edit existing comments and the description.
+* Add a connector.
+* Send updates to external systems (if external connections are configured).
+* Edit tags.
+* Refresh the case to retrieve the latest updates.
+* Change the status.
+* Close or delete the case.
+* Reopen a closed case.
\ No newline at end of file
diff --git a/docs/management/cases/setup-cases.asciidoc b/docs/management/cases/setup-cases.asciidoc
new file mode 100644
index 000000000000..b0d68a22d991
--- /dev/null
+++ b/docs/management/cases/setup-cases.asciidoc
@@ -0,0 +1,28 @@
+[[setup-cases]]
+== Configure access to cases
+
+preview::[]
+
+To access cases in *{stack-manage-app}*, you must have the appropriate {kib}
+privileges:
+
+[options="header"]
+|===
+
+| Action | {kib} privileges
+| Give full access to manage cases
+a|
+* `All` for the *Cases* feature under *Management*.
+* `All` for the *Actions and Connectors* feature under *Management*.
+
+NOTE: The `All` *Actions and Connectors* feature privilege is required to
+create, add, delete, and modify case connectors and to send updates to external
+systems.
+
+| Give view-only access for cases | `Read` for the *Cases* feature under *Management*.
+
+| Revoke all access to cases | `None` for the *Cases* feature under *Management*.
+
+|===
+
+For more details, refer to <>.
diff --git a/docs/management/connectors/images/jira-connector.png b/docs/management/connectors/images/jira-connector.png
index 5ff5ebf83afc..fc9a8ab31f87 100644
Binary files a/docs/management/connectors/images/jira-connector.png and b/docs/management/connectors/images/jira-connector.png differ
diff --git a/docs/management/connectors/images/servicenow-connector.png b/docs/management/connectors/images/servicenow-connector.png
index 9891a80ee758..cb74e8abcfba 100644
Binary files a/docs/management/connectors/images/servicenow-connector.png and b/docs/management/connectors/images/servicenow-connector.png differ
diff --git a/docs/management/connectors/images/servicenow-sir-connector.png b/docs/management/connectors/images/servicenow-sir-connector.png
index fbb137bd4f7d..71c7ce5ed05f 100644
Binary files a/docs/management/connectors/images/servicenow-sir-connector.png and b/docs/management/connectors/images/servicenow-sir-connector.png differ
diff --git a/docs/management/connectors/images/swimlane-connector.png b/docs/management/connectors/images/swimlane-connector.png
index 520c35d00381..6f557e694f41 100644
Binary files a/docs/management/connectors/images/swimlane-connector.png and b/docs/management/connectors/images/swimlane-connector.png differ
diff --git a/docs/management/managing-licenses.asciidoc b/docs/management/managing-licenses.asciidoc
index 8944414f6bfb..cf501518ea53 100644
--- a/docs/management/managing-licenses.asciidoc
+++ b/docs/management/managing-licenses.asciidoc
@@ -79,6 +79,7 @@ cluster.
* The deprecation API is disabled.
* SQL support is disabled.
* Aggregations provided by the analytics plugin are no longer usable.
+* All searchable snapshots indices are unassigned and cannot be searched.
[discrete]
[[expiration-watcher]]
diff --git a/docs/osquery/osquery.asciidoc b/docs/osquery/osquery.asciidoc
index 3231d2162f2e..e745835c8799 100644
--- a/docs/osquery/osquery.asciidoc
+++ b/docs/osquery/osquery.asciidoc
@@ -273,12 +273,18 @@ for an agent policy through Fleet.
This integration supports x64 architecture on Windows, MacOS, and Linux platforms,
and ARM64 architecture on Linux.
-NOTE: The original {filebeat-ref}/filebeat-module-osquery.html[Filebeat Osquery module]
+[NOTE]
+=========================
+
+* The original {filebeat-ref}/filebeat-module-osquery.html[Filebeat Osquery module]
and the https://docs.elastic.co/en/integrations/osquery[Osquery]
integration collect logs from self-managed Osquery deployments.
The *Osquery Manager* integration manages Osquery deployments
and supports running and scheduling queries from {kib}.
+* *Osquery Manager* cannot be integrated with an Elastic Agent in standalone mode.
+=========================
+
[float]
=== Customize Osquery sub-feature privileges
diff --git a/docs/settings/enterprise-search-settings.asciidoc b/docs/settings/enterprise-search-settings.asciidoc
new file mode 100644
index 000000000000..736a7614b31e
--- /dev/null
+++ b/docs/settings/enterprise-search-settings.asciidoc
@@ -0,0 +1,26 @@
+[role="xpack"]
+[[enterprise-search-settings-kb]]
+=== Enterprise Search settings in {kib}
+++++
+Enterprise Search settings
+++++
+
+On Elastic Cloud, you do not need to configure any settings to use Enterprise Search in {kib}. It is enabled by default. On self-managed installations, you must configure `enterpriseSearch.host`.
+
+`enterpriseSearch.host`::
+The http(s) URL of your Enterprise Search instance. For example, in a local self-managed setup,
+set this to `http://localhost:3002`. Authentication between {kib} and the Enterprise Search host URL,
+such as via OAuth, is not supported. You can also
+{enterprise-search-ref}/configure-ssl-tls.html#configure-ssl-tls-in-kibana[configure {kib} to trust
+your Enterprise Search TLS certificate authority].
+
+
+`enterpriseSearch.accessCheckTimeout`::
+When launching the Enterprise Search UI, the maximum number of milliseconds for {kib} to wait
+for a response from Enterprise Search
+before considering the attempt failed and logging a warning.
+Default: 5000.
+
+`enterpriseSearch.accessCheckTimeoutWarning`::
+When launching the Enterprise Search UI, the maximum number of milliseconds for {kib} to wait for a response from
+Enterprise Search before logging a warning. Default: 300.
diff --git a/docs/settings/monitoring-settings.asciidoc b/docs/settings/monitoring-settings.asciidoc
index a328700ebeb5..ddc9b1c096b5 100644
--- a/docs/settings/monitoring-settings.asciidoc
+++ b/docs/settings/monitoring-settings.asciidoc
@@ -29,10 +29,17 @@ For more information, see
[[monitoring-general-settings]]
==== General monitoring settings
+`monitoring.cluster_alerts.email_notifications.enabled`::
+deprecated:[7.11.0]
+When enabled, sends email notifications for Watcher alerts to the specified email address. The default is `true`.
+
+`monitoring.cluster_alerts.email_notifications.email_address` {ess-icon}::
+deprecated:[7.11.0]
+When enabled, specifies the email address where you want to receive cluster alert notifications.
+
`monitoring.ui.ccs.enabled`::
Set to `true` (default) to enable {ref}/modules-cross-cluster-search.html[cross-cluster search] of your monitoring data. The {ref}/modules-remote-clusters.html#remote-cluster-settings[`remote_cluster_client`] role must exist on each node.
-
`monitoring.ui.elasticsearch.hosts`::
Specifies the location of the {es} cluster where your monitoring data is stored.
+
diff --git a/docs/setup/configuring-reporting.asciidoc b/docs/setup/configuring-reporting.asciidoc
index 0b2fe4867077..6bdf6e5b27a6 100644
--- a/docs/setup/configuring-reporting.asciidoc
+++ b/docs/setup/configuring-reporting.asciidoc
@@ -6,7 +6,16 @@
Configure reporting
++++
-To enable users to manually and automatically generate reports, install the reporting packages, grant users access to the {report-features}, and secure the reporting endpoints.
+For security, you grant users access to the {report-features} and secure the reporting endpoints
+with TLS/SSL encryption. Additionally, you can install graphical packages into the operating system
+to enable the {kib} server to have screenshotting capabilities.
+
+* <>
+* <>
+* <>
+* <>
+* <>
+* <>
[float]
[[install-reporting-packages]]
@@ -30,8 +39,9 @@ If you are using Ubuntu/Debian systems, install the following packages:
* `fonts-liberation`
* `libfontconfig1`
+* `libnss3`
-If the system is missing dependencies, *Reporting* fails in a non-deterministic way. {kib} runs a self-test at server startup, and
+If the system is missing dependencies, a screenshot report job may fail in a non-deterministic way. {kib} runs a self-test at server startup, and
if it encounters errors, logs them in the Console. The error message does not include
information about why Chromium failed to run. The most common error message is `Error: connect ECONNREFUSED`, which indicates
that {kib} could not connect to the Chromium process.
@@ -52,7 +62,7 @@ xpack.reporting.roles.enabled: false
+
NOTE: If you use the default settings, you can still create a custom role that grants reporting privileges. The default role is `reporting_user`. This behavior is being deprecated and does not allow application-level access controls for {report-features}, and does not allow API keys or authentication tokens to authorize report generation. Refer to <> for information and caveats about the deprecated access control features.
-. Create the reporting role.
+. Create the reporting role.
.. Open the main menu, then click *Stack Management*.
@@ -76,14 +86,13 @@ For more information, refer to {ref}/security-privileges.html[Security privilege
.. Click *Customize*, then click *Analytics*.
-.. Next each application listed, click *All* or click *Read*. You will need to enable the *Customize sub-feature
-privileges* checkbox to grant reporting privileges if you select *Read*.
+.. For each application, select *All*, or to customize the privileges, select *Read* and *Customize sub-feature privileges*.
+
-If you’ve followed the example above, you should end up on a screen defining your customized privileges that looks like this:
+NOTE: If you have a Basic license, sub-feature privileges are unavailable. For details, check out <>.
[role="screenshot"]
-image::user/reporting/images/kibana-privileges-with-reporting.png["Kibana privileges with Reporting options"]
+image::user/reporting/images/kibana-privileges-with-reporting.png["Kibana privileges with Reporting options, Gold or higher license"]
+
-NOTE: If *Reporting* options for application features are not available, contact your administrator, or <>.
+NOTE: If the *Reporting* options for application features are unavailable, and the cluster license is higher than Basic, contact your administrator, or <>.
.. Click *Add {kib} privilege*.
@@ -93,7 +102,7 @@ NOTE: If *Reporting* options for application features are not available, contact
.. Open the main menu, then click *Stack Management*.
-.. Click *Users*, then click the user you want to assign the reporting role to.
+.. Click *Users*, then click the user you want to assign the reporting role to.
.. From the *Roles* dropdown, select *custom_reporting_user*.
@@ -104,29 +113,43 @@ Granting the privilege to generate reports also grants the user the privilege to
[float]
[[reporting-roles-user-api]]
==== Grant access with the role API
-With <> enabled in Reporting, you can also use the {ref}/security-api-put-role.html[role API] to grant access to the {report-features}. Grant custom reporting roles to users in combination with other roles that grant read access to the data in {es}, and at least read access in the applications where users can generate reports.
+With <> enabled in Reporting, you can also use the {ref}/security-api-put-role.html[role API] to grant access to the {report-features}, using *All* privileges, or sub-feature privileges.
-[source, sh]
+NOTE: If you have a Basic license, sub-feature privileges are unavailable. For details, check out the API command to grant *All* privileges in <>.
+
+Grant users custom Reporting roles, other roles that grant read access to the data in {es}, and at least read access in the applications where users can generate reports.
+
+[source, json]
---------------------------------------------------------------
-POST /_security/role/custom_reporting_user
+PUT localhost:5601/api/security/role/custom_reporting_user
{
- metadata: {},
- elasticsearch: { cluster: [], indices: [], run_as: [] },
- kibana: [
+ "elasticsearch": { "cluster": [], "indices": [], "run_as": [] },
+ "kibana": [
{
- base: [],
- feature: {
- dashboard: [
- 'generate_report', <1>
- 'download_csv_report' <2>
+ "base": [],
+ "feature": {
+ "dashboard": [
+ "minimal_read",
+ "generate_report", <1>
+ "download_csv_report" <2>
+ ],
+ "discover": [
+ "minimal_read",
+ "generate_report" <3>
+ ],
+ "canvas": [
+ "minimal_read",
+ "generate_report" <4>
],
- discover: ['generate_report'], <3>
- canvas: ['generate_report'], <4>
- visualize: ['generate_report'], <5>
+ "visualize": [
+ "minimal_read",
+ "generate_report" <5>
+ ]
},
- spaces: ['*'],
+ "spaces": [ "*" ]
}
- ]
+ ],
+ "metadata": {} // optional
}
---------------------------------------------------------------
// CONSOLE
@@ -138,6 +161,41 @@ POST /_security/role/custom_reporting_user
<5> Grants access to generate PNG and PDF reports in *Visualize Library*.
[float]
+[[grant-user-access-basic]]
+=== Grant users access with a Basic license
+
+With a Basic license, you can grant users access with custom roles to {report-features} with <>. However, with a Basic license, sub-feature privileges are unavailable. <>, then select *All* privileges for the applications where users can create reports.
+
+[role="screenshot"]
+image::user/reporting/images/kibana-privileges-with-reporting-basic.png["Kibana privileges with Reporting options, Basic license"]
+
+With a Basic license, sub-feature application privileges are unavailable, but you can use the {ref}/security-api-put-role.html[role API] to grant access to CSV {report-features}:
+
+[source, sh]
+---------------------------------------------------------------
+PUT localhost:5601/api/security/role/custom_reporting_user
+{
+ "elasticsearch": { "cluster": [], "indices": [], "run_as": [] },
+ "kibana": [
+ {
+ "base": [],
+ "feature": {
+ "dashboard": [ "all" ], <1>
+ "discover": [ "all" ], <2>
+ },
+ "spaces": [ "*" ]
+ }
+ ],
+ "metadata": {} // optional
+}
+---------------------------------------------------------------
+// CONSOLE
+
+<1> Grants access to generate CSV reports from saved searches in *Discover*.
+<2> Grants access to download CSV reports from saved search panels in *Dashboard*.
+
+[float]
+[[grant-user-access-external-provider]]
==== Grant access using an external provider
If you are using an external identity provider, such as LDAP or Active Directory, you can assign roles to individual users or groups of users. Role mappings are configured in {ref}/mapping-roles.html[`config/role_mapping.yml`].
diff --git a/docs/setup/connect-to-elasticsearch.asciidoc b/docs/setup/connect-to-elasticsearch.asciidoc
index 1d698e908793..9e1ee62f093f 100644
--- a/docs/setup/connect-to-elasticsearch.asciidoc
+++ b/docs/setup/connect-to-elasticsearch.asciidoc
@@ -55,7 +55,7 @@ https://www.elastic.co/guide/en/elasticsearch/client/index.html[{es} Client docu
If you are running {kib} on our hosted {es} Service,
click *View deployment details* on the *Integrations* view
-to verify your {es} endpoint and Cloud ID, and create API keys for integestion.
+to verify your {es} endpoint and Cloud ID, and create API keys for integration.
[float]
=== Add sample data
diff --git a/docs/setup/settings.asciidoc b/docs/setup/settings.asciidoc
index e55a94a516d6..3a1e0f1a7f4f 100644
--- a/docs/setup/settings.asciidoc
+++ b/docs/setup/settings.asciidoc
@@ -282,9 +282,6 @@ on the {kib} index at startup. {kib} users still need to authenticate with
that the {kib} server uses to perform maintenance on the {kib} index at startup. This setting
is an alternative to `elasticsearch.username` and `elasticsearch.password`.
-| `enterpriseSearch.host`
- | The http(s) URL of your Enterprise Search instance. For example, in a local self-managed setup, set this to `http://localhost:3002`. Authentication between Kibana and the Enterprise Search host URL, such as via OAuth, is not supported. You can also {enterprise-search-ref}/configure-ssl-tls.html#configure-ssl-tls-in-kibana[configure Kibana to trust your Enterprise Search TLS certificate authority].
-
| `interpreter.enableInVisualize`
| Enables use of interpreter in Visualize. *Default: `true`*
@@ -719,6 +716,7 @@ Valid locales are: `en`, `zh-CN`, `ja-JP`. *Default: `en`*
include::{kib-repo-dir}/settings/alert-action-settings.asciidoc[]
include::{kib-repo-dir}/settings/apm-settings.asciidoc[]
include::{kib-repo-dir}/settings/banners-settings.asciidoc[]
+include::{kib-repo-dir}/settings/enterprise-search-settings.asciidoc[]
include::{kib-repo-dir}/settings/fleet-settings.asciidoc[]
include::{kib-repo-dir}/settings/i18n-settings.asciidoc[]
include::{kib-repo-dir}/settings/logging-settings.asciidoc[]
@@ -726,8 +724,8 @@ include::{kib-repo-dir}/settings/logs-ui-settings.asciidoc[]
include::{kib-repo-dir}/settings/infrastructure-ui-settings.asciidoc[]
include::{kib-repo-dir}/settings/monitoring-settings.asciidoc[]
include::{kib-repo-dir}/settings/reporting-settings.asciidoc[]
-include::secure-settings.asciidoc[]
include::{kib-repo-dir}/settings/search-sessions-settings.asciidoc[]
+include::secure-settings.asciidoc[]
include::{kib-repo-dir}/settings/security-settings.asciidoc[]
include::{kib-repo-dir}/settings/spaces-settings.asciidoc[]
include::{kib-repo-dir}/settings/task-manager-settings.asciidoc[]
diff --git a/docs/user/dashboard/aggregation-based.asciidoc b/docs/user/dashboard/aggregation-based.asciidoc
index c4f26e701bcc..bf13661b9aad 100644
--- a/docs/user/dashboard/aggregation-based.asciidoc
+++ b/docs/user/dashboard/aggregation-based.asciidoc
@@ -111,6 +111,8 @@ Choose the type of visualization you want to create, then use the editor to conf
.. Select the visualization type you want to create.
.. Select the data source you want to visualize.
++
+NOTE: There is no performance impact on the data source you select. For example, *Discover* saved searches perform the same as {data-sources}.
. Add the <> you want to visualize using the editor, then click *Update*.
+
diff --git a/docs/user/dashboard/tsvb.asciidoc b/docs/user/dashboard/tsvb.asciidoc
index a097e34b2091..56e3606c18b7 100644
--- a/docs/user/dashboard/tsvb.asciidoc
+++ b/docs/user/dashboard/tsvb.asciidoc
@@ -276,20 +276,4 @@ For other types of month over month calculations, use <> o
Calculating the duration between the start and end of an event is unsupported in *TSVB* because *TSVB* requires correlation between different time periods.
*TSVB* requires that the duration is pre-calculated.
-====
-
-[discrete]
-[group-on-multiple-fields]
-.*How do I group on multiple fields?*
-[%collapsible]
-====
-
-To group with multiple fields, create runtime fields in the {data-source} you are visualizing.
-
-. Create a runtime field. Refer to <> for more information.
-+
-[role="screenshot"]
-image::images/tsvb_group_by_multiple_fields.png[Group by multiple fields]
-
-. Create a *TSVB* visualization and group by this field.
====
\ No newline at end of file
diff --git a/docs/user/management.asciidoc b/docs/user/management.asciidoc
index 6c309d56f229..908cdc792431 100644
--- a/docs/user/management.asciidoc
+++ b/docs/user/management.asciidoc
@@ -78,6 +78,9 @@ You can add and remove remote clusters, and check their connectivity.
| Centrally <> across {kib}. Create and <> for triggering actions.
+| <>
+| Create and manage cases to investigate issues.
+
| <>
| Monitor the generation of reports—PDF, PNG, and CSV—and download reports that you previously generated.
A report can contain a dashboard, visualization, saved search, or Canvas workpad.
@@ -175,6 +178,8 @@ see the https://www.elastic.co/subscriptions[subscription page].
include::{kib-repo-dir}/management/advanced-options.asciidoc[]
+include::{kib-repo-dir}/management/cases/index.asciidoc[]
+
include::{kib-repo-dir}/management/action-types.asciidoc[]
include::{kib-repo-dir}/management/managing-licenses.asciidoc[]
diff --git a/docs/user/monitoring/xpack-monitoring.asciidoc b/docs/user/monitoring/xpack-monitoring.asciidoc
index c3aafe7f90db..751710d1e74f 100644
--- a/docs/user/monitoring/xpack-monitoring.asciidoc
+++ b/docs/user/monitoring/xpack-monitoring.asciidoc
@@ -17,9 +17,6 @@ instance, and Beat is considered unique based on its persistent
UUID, which is written to the <> directory when the node
or instance starts.
-NOTE: Watcher must be enabled to view cluster alerts. If you have a Basic
-license, Top Cluster Alerts are not displayed.
-
For more information, see <> and
{ref}/monitor-elasticsearch-cluster.html[Monitor a cluster].
diff --git a/docs/user/production-considerations/task-manager-production-considerations.asciidoc b/docs/user/production-considerations/task-manager-production-considerations.asciidoc
index 672c310f138e..28c5f6e4f14c 100644
--- a/docs/user/production-considerations/task-manager-production-considerations.asciidoc
+++ b/docs/user/production-considerations/task-manager-production-considerations.asciidoc
@@ -101,7 +101,7 @@ Scaling {kib} instances horizontally requires a higher degree of coordination, w
A recommended strategy is to follow these steps:
1. Produce a <> as a guide to provisioning as many {kib} instances as needed. Include any growth in tasks that you predict experiencing in the near future, and a buffer to better address ad-hoc tasks.
-2. After provisioning a deployment, assess whether the provisioned {kib} instances achieve the required throughput by evaluating the <> as described in <>.
+2. After provisioning a deployment, assess whether the provisioned {kib} instances achieve the required throughput by evaluating the <> as described in <>.
3. If the throughput is insufficient, and {kib} instances exhibit low resource usage, incrementally scale vertically while <> the impact of these changes.
4. If the throughput is insufficient, and {kib} instances are exhibiting high resource usage, incrementally scale horizontally by provisioning new {kib} instances and reassess.
diff --git a/docs/user/production-considerations/task-manager-troubleshooting.asciidoc b/docs/user/production-considerations/task-manager-troubleshooting.asciidoc
index a22d46902f54..606dd3c8a24e 100644
--- a/docs/user/production-considerations/task-manager-troubleshooting.asciidoc
+++ b/docs/user/production-considerations/task-manager-troubleshooting.asciidoc
@@ -412,7 +412,7 @@ This assessment is based on the following:
* Comparing the `last_successful_poll` to the `timestamp` (value of `2021-02-16T11:38:10.077Z`) at the root, where you can see the last polling cycle took place 1 second before the monitoring stats were exposed by the health monitoring API.
* Comparing the `last_polling_delay` to the `timestamp` (value of `2021-02-16T11:38:10.077Z`) at the root, where you can see the last polling cycle delay took place 2 days ago, suggesting {kib} instances are not conflicting often.
-* The `p50` of the `duration` shows that at least 50% of polling cycles take, at most, 13 millisconds to complete.
+* The `p50` of the `duration` shows that at least 50% of polling cycles take, at most, 13 milliseconds to complete.
* Evaluating the `result_frequency_percent_as_number`:
** 80% of the polling cycles completed without claiming any tasks (suggesting that there aren't any overdue tasks).
** 20% completed with Task Manager claiming tasks that were then executed.
@@ -508,7 +508,7 @@ For details on achieving higher throughput by adjusting your scaling strategy, s
Tasks run for too long, overrunning their schedule
*Diagnosis*:
-The <> theory analyzed a hypothetical scenario where both drift and load were unusually high.
+The <> theory analyzed a hypothetical scenario where both drift and load were unusually high.
Suppose an alternate scenario, where `drift` is high, but `load` is not, such as the following:
@@ -688,7 +688,7 @@ Keep in mind that these stats give you a glimpse at a moment in time, and even t
[[task-manager-health-evaluate-the-workload]]
===== Evaluate the Workload
-Predicting the required throughput a deplyment might need to support Task Manager is difficult, as features can schedule an unpredictable number of tasks at a variety of scheduled cadences.
+Predicting the required throughput a deployment might need to support Task Manager is difficult, as features can schedule an unpredictable number of tasks at a variety of scheduled cadences.
<> provides statistics that make it easier to monitor the adequacy of the existing throughput.
By evaluating the workload, the required throughput can be estimated, which is used when following the Task Manager <>.
diff --git a/docs/user/reporting/images/kibana-privileges-with-reporting-basic.png b/docs/user/reporting/images/kibana-privileges-with-reporting-basic.png
new file mode 100644
index 000000000000..6d2c3ba645b5
Binary files /dev/null and b/docs/user/reporting/images/kibana-privileges-with-reporting-basic.png differ
diff --git a/docs/user/reporting/reporting-troubleshooting.asciidoc b/docs/user/reporting/reporting-troubleshooting.asciidoc
index 50a163c08858..7d2d0dff37a0 100644
--- a/docs/user/reporting/reporting-troubleshooting.asciidoc
+++ b/docs/user/reporting/reporting-troubleshooting.asciidoc
@@ -1,6 +1,7 @@
[role="xpack"]
[[reporting-troubleshooting]]
== Reporting troubleshooting
+
++++
Troubleshooting
++++
diff --git a/docs/user/security/authentication/index.asciidoc b/docs/user/security/authentication/index.asciidoc
index 2f2b27938979..446de62326f8 100644
--- a/docs/user/security/authentication/index.asciidoc
+++ b/docs/user/security/authentication/index.asciidoc
@@ -5,7 +5,7 @@
Authentication
++++
:keywords: administrator, concept, security, authentication
-:description: A list of the supported authentication mechanisms in {kib}.
+:description: A list of the supported authentication mechanisms in {kib}.
{kib} supports the following authentication mechanisms:
@@ -483,4 +483,4 @@ To make this iframe leverage anonymous access automatically, you will need to mo
NOTE: `auth_provider_hint` query string parameter goes *before* the hash URL fragment.
-For more information on how to embed, refer to <>.
+For more information, refer to <>.
diff --git a/examples/embeddable_examples/public/list_container/list_container_component.tsx b/examples/embeddable_examples/public/list_container/list_container_component.tsx
index 031100c07409..d939cc2029f6 100644
--- a/examples/embeddable_examples/public/list_container/list_container_component.tsx
+++ b/examples/embeddable_examples/public/list_container/list_container_component.tsx
@@ -15,6 +15,7 @@ import {
ContainerInput,
ContainerOutput,
EmbeddableStart,
+ EmbeddableChildPanel,
} from '../../../../src/plugins/embeddable/public';
interface Props {
@@ -31,7 +32,6 @@ function renderList(
) {
let number = 0;
const list = Object.values(panels).map((panel) => {
- const child = embeddable.getChild(panel.explicitInput.id);
number++;
return (
@@ -42,7 +42,11 @@ function renderList(
-
+
diff --git a/logs.tar.gz b/logs.tar.gz
deleted file mode 100644
index 2a1acc4b5eba..000000000000
Binary files a/logs.tar.gz and /dev/null differ
diff --git a/nav-kibana-dev.docnav.json b/nav-kibana-dev.docnav.json
index a86772d3ef27..43ca1ed4bf81 100644
--- a/nav-kibana-dev.docnav.json
+++ b/nav-kibana-dev.docnav.json
@@ -6,7 +6,7 @@
"description": "Developer documentation for building custom Kibana plugins and extending Kibana functionality.",
"items": [
{
- "category": "Getting started",
+ "label": "Getting started",
"items": [
{ "id": "kibDevDocsWelcome" },
{ "id": "kibDevTutorialSetupDevEnv" },
@@ -16,7 +16,20 @@
]
},
{
- "category": "Key concepts",
+ "label": "Contributing",
+ "items": [
+ { "id": "kibDevPrinciples" },
+ { "id": "kibRepoStructure" },
+ { "id": "kibStandards" },
+ { "id": "kibBestPractices" },
+ { "id": "kibDocumentation" },
+ { "id": "kibStyleGuide" },
+ { "id": "ktRFCProcess" },
+ { "id": "kibGitHub" }
+ ]
+ },
+ {
+ "label": "Key concepts",
"items": [
{ "id": "kibPlatformIntro" },
{ "id": "kibDevAnatomyOfAPlugin" },
@@ -32,7 +45,7 @@
]
},
{
- "category": "Tutorials",
+ "label": "Tutorials",
"items": [
{ "id": "kibDevTutorialTestingPlugins" },
{ "id": "kibDevTutorialSavedObject" },
@@ -53,19 +66,7 @@
]
},
{
- "category": "Contributing",
- "items": [
- { "id": "kibRepoStructure" },
- { "id": "kibDevPrinciples" },
- { "id": "kibStandards" },
- { "id": "ktRFCProcess" },
- { "id": "kibBestPractices" },
- { "id": "kibStyleGuide" },
- { "id": "kibGitHub" }
- ]
- },
- {
- "category": "Contributors Newsletters",
+ "label": "Contributors Newsletters",
"items": [
{ "id": "kibFebruary2022ContributorNewsletter" },
{ "id": "kibJanuary2022ContributorNewsletter" },
@@ -82,7 +83,7 @@
]
},
{
- "category": "API documentation",
+ "label": "API documentation",
"items": [
{ "id": "kibDevDocsApiWelcome" },
{ "id": "kibDevDocsPluginDirectory" },
diff --git a/package.json b/package.json
index fdb358c25fb8..b756d9cb05f1 100644
--- a/package.json
+++ b/package.json
@@ -50,7 +50,6 @@
"docs:acceptApiChanges": "node --max-old-space-size=6144 scripts/check_published_api_changes.js --accept",
"es": "node scripts/es",
"preinstall": "node ./preinstall_check",
- "postinstall": "node scripts/kbn patch_native_modules",
"kbn": "node scripts/kbn",
"lint": "yarn run lint:es && yarn run lint:style",
"lint:es": "node scripts/eslint",
@@ -85,6 +84,7 @@
"**/isomorphic-fetch/node-fetch": "^2.6.7",
"**/istanbul-lib-coverage": "^3.2.0",
"**/json-schema": "^0.4.0",
+ "**/minimatch": "^3.1.2",
"**/minimist": "^1.2.5",
"**/node-forge": "^1.2.1",
"**/pdfkit/crypto-js": "4.0.0",
@@ -92,7 +92,7 @@
"**/react-syntax-highlighter/**/highlight.js": "^10.4.1",
"**/refractor/prismjs": "~1.27.0",
"**/trim": "1.0.1",
- "**/typescript": "4.5.3",
+ "**/typescript": "4.6.2",
"**/underscore": "^1.13.1",
"globby/fast-glob": "3.2.7",
"puppeteer/node-fetch": "^2.6.7"
@@ -107,8 +107,8 @@
"@elastic/apm-synthtrace": "link:bazel-bin/packages/elastic-apm-synthtrace",
"@elastic/charts": "43.1.1",
"@elastic/datemath": "link:bazel-bin/packages/elastic-datemath",
- "@elastic/elasticsearch": "npm:@elastic/elasticsearch-canary@8.1.0-canary.3",
- "@elastic/ems-client": "8.0.0",
+ "@elastic/elasticsearch": "npm:@elastic/elasticsearch-canary@8.2.0-canary.1",
+ "@elastic/ems-client": "8.1.0",
"@elastic/eui": "48.1.1",
"@elastic/filesaver": "1.1.2",
"@elastic/node-crypto": "1.2.1",
@@ -278,7 +278,7 @@
"js-search": "^1.4.3",
"js-sha256": "^0.9.0",
"js-sql-parser": "^1.4.1",
- "js-yaml": "^3.14.0",
+ "js-yaml": "^3.14.1",
"json-stable-stringify": "^1.0.1",
"json-stringify-pretty-compact": "1.2.0",
"json-stringify-safe": "5.0.1",
@@ -299,7 +299,7 @@
"mime": "^2.4.4",
"mime-types": "^2.1.27",
"mini-css-extract-plugin": "1.1.0",
- "minimatch": "^3.0.4",
+ "minimatch": "^3.1.2",
"moment": "^2.24.0",
"moment-duration-format": "^2.3.2",
"moment-timezone": "^0.5.27",
@@ -333,7 +333,7 @@
"raw-loader": "^3.1.0",
"rbush": "^3.0.1",
"re-resizable": "^6.1.1",
- "re2": "^1.16.0",
+ "re2": "1.17.4",
"react": "^16.12.0",
"react-ace": "^7.0.5",
"react-beautiful-dnd": "^13.1.0",
@@ -348,7 +348,7 @@
"react-moment-proptypes": "^1.7.0",
"react-monaco-editor": "^0.41.2",
"react-popper-tooltip": "^2.10.1",
- "react-query": "^3.34.0",
+ "react-query": "^3.34.7",
"react-redux": "^7.2.0",
"react-resizable": "^1.7.5",
"react-resize-detector": "^4.2.0",
@@ -425,16 +425,16 @@
},
"devDependencies": {
"@apidevtools/swagger-parser": "^10.0.3",
- "@babel/cli": "^7.17.0",
- "@babel/core": "^7.17.2",
+ "@babel/cli": "^7.17.6",
+ "@babel/core": "^7.17.5",
"@babel/eslint-parser": "^7.17.0",
"@babel/eslint-plugin": "^7.16.5",
- "@babel/generator": "^7.17.0",
- "@babel/parser": "^7.17.0",
+ "@babel/generator": "^7.17.3",
+ "@babel/parser": "^7.17.3",
"@babel/plugin-proposal-class-properties": "^7.16.7",
"@babel/plugin-proposal-export-namespace-from": "^7.16.7",
"@babel/plugin-proposal-nullish-coalescing-operator": "^7.16.7",
- "@babel/plugin-proposal-object-rest-spread": "^7.16.7",
+ "@babel/plugin-proposal-object-rest-spread": "^7.17.3",
"@babel/plugin-proposal-optional-chaining": "^7.16.7",
"@babel/plugin-proposal-private-methods": "^7.16.11",
"@babel/plugin-transform-runtime": "^7.17.0",
@@ -442,7 +442,7 @@
"@babel/preset-react": "^7.16.7",
"@babel/preset-typescript": "^7.16.7",
"@babel/register": "^7.17.0",
- "@babel/traverse": "^7.17.0",
+ "@babel/traverse": "^7.17.3",
"@babel/types": "^7.17.0",
"@bazel/ibazel": "^0.15.10",
"@bazel/typescript": "4.0.0",
@@ -462,6 +462,7 @@
"@jest/reporters": "^26.6.2",
"@kbn/babel-code-parser": "link:bazel-bin/packages/kbn-babel-code-parser",
"@kbn/babel-preset": "link:bazel-bin/packages/kbn-babel-preset",
+ "@kbn/bazel-packages": "link:bazel-bin/packages/kbn-bazel-packages",
"@kbn/cli-dev-mode": "link:bazel-bin/packages/kbn-cli-dev-mode",
"@kbn/dev-utils": "link:bazel-bin/packages/kbn-dev-utils",
"@kbn/docs-utils": "link:bazel-bin/packages/kbn-docs-utils",
@@ -470,6 +471,7 @@
"@kbn/eslint-import-resolver-kibana": "link:bazel-bin/packages/kbn-eslint-import-resolver-kibana",
"@kbn/eslint-plugin-eslint": "link:bazel-bin/packages/kbn-eslint-plugin-eslint",
"@kbn/expect": "link:bazel-bin/packages/kbn-expect",
+ "@kbn/generate": "link:bazel-bin/packages/kbn-generate",
"@kbn/optimizer": "link:bazel-bin/packages/kbn-optimizer",
"@kbn/plugin-generator": "link:bazel-bin/packages/kbn-plugin-generator",
"@kbn/plugin-helpers": "link:bazel-bin/packages/kbn-plugin-helpers",
@@ -480,6 +482,7 @@
"@kbn/test": "link:bazel-bin/packages/kbn-test",
"@kbn/test-jest-helpers": "link:bazel-bin/packages/kbn-test-jest-helpers",
"@kbn/test-subj-selector": "link:bazel-bin/packages/kbn-test-subj-selector",
+ "@kbn/type-summarizer": "link:bazel-bin/packages/kbn-type-summarizer",
"@loaders.gl/polyfills": "^2.3.5",
"@mapbox/vector-tile": "1.3.1",
"@microsoft/api-documenter": "7.13.68",
@@ -567,7 +570,7 @@
"@types/js-levenshtein": "^1.1.0",
"@types/js-search": "^1.4.0",
"@types/js-yaml": "^3.11.1",
- "@types/jsdom": "^16.2.13",
+ "@types/jsdom": "^16.2.14",
"@types/json-stable-stringify": "^1.0.32",
"@types/json5": "^0.0.30",
"@types/kbn__ace": "link:bazel-bin/packages/kbn-ace/npm_module_types",
@@ -575,6 +578,7 @@
"@types/kbn__analytics": "link:bazel-bin/packages/kbn-analytics/npm_module_types",
"@types/kbn__apm-config-loader": "link:bazel-bin/packages/kbn-apm-config-loader/npm_module_types",
"@types/kbn__apm-utils": "link:bazel-bin/packages/kbn-apm-utils/npm_module_types",
+ "@types/kbn__bazel-packages": "link:bazel-bin/packages/kbn-bazel-packages/npm_module_types",
"@types/kbn__cli-dev-mode": "link:bazel-bin/packages/kbn-cli-dev-mode/npm_module_types",
"@types/kbn__config": "link:bazel-bin/packages/kbn-config/npm_module_types",
"@types/kbn__config-schema": "link:bazel-bin/packages/kbn-config-schema/npm_module_types",
@@ -585,6 +589,7 @@
"@types/kbn__es-archiver": "link:bazel-bin/packages/kbn-es-archiver/npm_module_types",
"@types/kbn__es-query": "link:bazel-bin/packages/kbn-es-query/npm_module_types",
"@types/kbn__field-types": "link:bazel-bin/packages/kbn-field-types/npm_module_types",
+ "@types/kbn__generate": "link:bazel-bin/packages/kbn-generate/npm_module_types",
"@types/kbn__i18n": "link:bazel-bin/packages/kbn-i18n/npm_module_types",
"@types/kbn__i18n-react": "link:bazel-bin/packages/kbn-i18n-react/npm_module_types",
"@types/kbn__interpreter": "link:bazel-bin/packages/kbn-interpreter/npm_module_types",
@@ -645,7 +650,7 @@
"@types/nock": "^10.0.3",
"@types/node": "16.10.2",
"@types/node-fetch": "^2.6.0",
- "@types/node-forge": "^1.0.0",
+ "@types/node-forge": "^1.0.1",
"@types/nodemailer": "^6.4.0",
"@types/normalize-path": "^3.0.0",
"@types/object-hash": "^1.3.0",
@@ -714,9 +719,9 @@
"@types/yargs": "^15.0.0",
"@types/yauzl": "^2.9.1",
"@types/zen-observable": "^0.8.0",
- "@typescript-eslint/eslint-plugin": "^5.6.0",
- "@typescript-eslint/parser": "^5.6.0",
- "@typescript-eslint/typescript-estree": "^5.6.0",
+ "@typescript-eslint/eslint-plugin": "^5.14.0",
+ "@typescript-eslint/parser": "^5.14.0",
+ "@typescript-eslint/typescript-estree": "^5.14.0",
"@yarnpkg/lockfile": "^1.1.0",
"abab": "^2.0.4",
"aggregate-error": "^3.1.0",
@@ -731,13 +736,13 @@
"babel-plugin-add-module-exports": "^1.0.4",
"babel-plugin-istanbul": "^6.1.1",
"babel-plugin-require-context-hook": "^1.0.0",
- "babel-plugin-styled-components": "^2.0.2",
+ "babel-plugin-styled-components": "^2.0.6",
"babel-plugin-transform-react-remove-prop-types": "^0.4.24",
"backport": "^7.3.1",
"callsites": "^3.1.0",
"chai": "3.5.0",
"chance": "1.0.18",
- "chromedriver": "^98.0.0",
+ "chromedriver": "^99.0.0",
"clean-webpack-plugin": "^3.0.0",
"cmd-shim": "^2.1.0",
"compression-webpack-plugin": "^4.0.0",
@@ -842,7 +847,7 @@
"multimatch": "^4.0.0",
"mutation-observer": "^1.0.3",
"ncp": "^2.0.0",
- "node-sass": "^6.0.1",
+ "node-sass": "6.0.1",
"null-loader": "^3.0.0",
"nyc": "^15.1.0",
"oboe": "^2.1.4",
@@ -870,6 +875,7 @@
"simple-git": "1.116.0",
"sinon": "^7.4.2",
"sort-package-json": "^1.53.1",
+ "source-map": "^0.7.3",
"spawn-sync": "^1.0.15",
"string-replace-loader": "^2.2.0",
"strong-log-transformer": "^2.1.0",
@@ -888,7 +894,7 @@
"ts-loader": "^7.0.5",
"ts-morph": "^13.0.2",
"tsd": "^0.13.1",
- "typescript": "4.5.3",
+ "typescript": "4.6.2",
"unlazy-loader": "^0.1.3",
"url-loader": "^2.2.0",
"val-loader": "^1.1.1",
diff --git a/packages/BUILD.bazel b/packages/BUILD.bazel
index 02e82476cd88..66361060f1ee 100644
--- a/packages/BUILD.bazel
+++ b/packages/BUILD.bazel
@@ -1,78 +1,87 @@
+################
+################
+## This file is automatically generated, to create a new package use `node scripts/generate package --help`
+################
+################
+
# It will build all declared code packages
filegroup(
name = "build_pkg_code",
srcs = [
- "//packages/elastic-apm-synthtrace:build",
- "//packages/elastic-datemath:build",
- "//packages/elastic-eslint-config-kibana:build",
- "//packages/elastic-safer-lodash-set:build",
- "//packages/kbn-ace:build",
- "//packages/kbn-alerts:build",
- "//packages/kbn-analytics:build",
- "//packages/kbn-apm-config-loader:build",
- "//packages/kbn-apm-utils:build",
- "//packages/kbn-babel-code-parser:build",
- "//packages/kbn-babel-preset:build",
- "//packages/kbn-cli-dev-mode:build",
- "//packages/kbn-config:build",
- "//packages/kbn-config-schema:build",
- "//packages/kbn-crypto:build",
- "//packages/kbn-dev-utils:build",
- "//packages/kbn-doc-links:build",
- "//packages/kbn-docs-utils:build",
- "//packages/kbn-es:build",
- "//packages/kbn-es-archiver:build",
- "//packages/kbn-es-query:build",
- "//packages/kbn-eslint-import-resolver-kibana:build",
- "//packages/kbn-eslint-plugin-eslint:build",
- "//packages/kbn-expect:build",
- "//packages/kbn-field-types:build",
- "//packages/kbn-flot-charts:build",
- "//packages/kbn-i18n:build",
- "//packages/kbn-i18n-react:build",
- "//packages/kbn-interpreter:build",
- "//packages/kbn-io-ts-utils:build",
- "//packages/kbn-logging:build",
- "//packages/kbn-logging-mocks:build",
- "//packages/kbn-mapbox-gl:build",
- "//packages/kbn-monaco:build",
- "//packages/kbn-optimizer:build",
- "//packages/kbn-plugin-generator:build",
- "//packages/kbn-plugin-helpers:build",
- "//packages/kbn-react-field:build",
- "//packages/kbn-rule-data-utils:build",
- "//packages/kbn-securitysolution-autocomplete:build",
- "//packages/kbn-securitysolution-list-constants:build",
- "//packages/kbn-securitysolution-io-ts-types:build",
- "//packages/kbn-securitysolution-io-ts-alerting-types:build",
- "//packages/kbn-securitysolution-io-ts-list-types:build",
- "//packages/kbn-securitysolution-io-ts-utils:build",
- "//packages/kbn-securitysolution-list-api:build",
- "//packages/kbn-securitysolution-list-hooks:build",
- "//packages/kbn-securitysolution-list-utils:build",
- "//packages/kbn-securitysolution-rules:build",
- "//packages/kbn-securitysolution-utils:build",
- "//packages/kbn-securitysolution-es-utils:build",
- "//packages/kbn-securitysolution-t-grid:build",
- "//packages/kbn-securitysolution-hook-utils:build",
- "//packages/kbn-server-http-tools:build",
- "//packages/kbn-server-route-repository:build",
- "//packages/kbn-spec-to-console:build",
- "//packages/kbn-std:build",
- "//packages/kbn-storybook:build",
- "//packages/kbn-telemetry-tools:build",
- "//packages/kbn-test:build",
- "//packages/kbn-test-jest-helpers:build",
- "//packages/kbn-test-subj-selector:build",
- "//packages/kbn-timelion-grammar:build",
- "//packages/kbn-tinymath:build",
- "//packages/kbn-typed-react-router-config:build",
- "//packages/kbn-ui-framework:build",
- "//packages/kbn-ui-shared-deps-npm:build",
- "//packages/kbn-ui-shared-deps-src:build",
- "//packages/kbn-ui-theme:build",
- "//packages/kbn-utility-types:build",
- "//packages/kbn-utils:build",
+ "//packages/elastic-apm-synthtrace:build",
+ "//packages/elastic-datemath:build",
+ "//packages/elastic-eslint-config-kibana:build",
+ "//packages/elastic-safer-lodash-set:build",
+ "//packages/kbn-ace:build",
+ "//packages/kbn-alerts:build",
+ "//packages/kbn-analytics:build",
+ "//packages/kbn-apm-config-loader:build",
+ "//packages/kbn-apm-utils:build",
+ "//packages/kbn-babel-code-parser:build",
+ "//packages/kbn-babel-preset:build",
+ "//packages/kbn-bazel-packages:build",
+ "//packages/kbn-cli-dev-mode:build",
+ "//packages/kbn-config-schema:build",
+ "//packages/kbn-config:build",
+ "//packages/kbn-crypto:build",
+ "//packages/kbn-dev-utils:build",
+ "//packages/kbn-doc-links:build",
+ "//packages/kbn-docs-utils:build",
+ "//packages/kbn-es-archiver:build",
+ "//packages/kbn-es-query:build",
+ "//packages/kbn-es:build",
+ "//packages/kbn-eslint-import-resolver-kibana:build",
+ "//packages/kbn-eslint-plugin-eslint:build",
+ "//packages/kbn-expect:build",
+ "//packages/kbn-field-types:build",
+ "//packages/kbn-flot-charts:build",
+ "//packages/kbn-generate:build",
+ "//packages/kbn-i18n-react:build",
+ "//packages/kbn-i18n:build",
+ "//packages/kbn-interpreter:build",
+ "//packages/kbn-io-ts-utils:build",
+ "//packages/kbn-logging-mocks:build",
+ "//packages/kbn-logging:build",
+ "//packages/kbn-mapbox-gl:build",
+ "//packages/kbn-monaco:build",
+ "//packages/kbn-optimizer:build",
+ "//packages/kbn-plugin-generator:build",
+ "//packages/kbn-plugin-helpers:build",
+ "//packages/kbn-react-field:build",
+ "//packages/kbn-rule-data-utils:build",
+ "//packages/kbn-securitysolution-autocomplete:build",
+ "//packages/kbn-securitysolution-es-utils:build",
+ "//packages/kbn-securitysolution-hook-utils:build",
+ "//packages/kbn-securitysolution-io-ts-alerting-types:build",
+ "//packages/kbn-securitysolution-io-ts-list-types:build",
+ "//packages/kbn-securitysolution-io-ts-types:build",
+ "//packages/kbn-securitysolution-io-ts-utils:build",
+ "//packages/kbn-securitysolution-list-api:build",
+ "//packages/kbn-securitysolution-list-constants:build",
+ "//packages/kbn-securitysolution-list-hooks:build",
+ "//packages/kbn-securitysolution-list-utils:build",
+ "//packages/kbn-securitysolution-rules:build",
+ "//packages/kbn-securitysolution-t-grid:build",
+ "//packages/kbn-securitysolution-utils:build",
+ "//packages/kbn-server-http-tools:build",
+ "//packages/kbn-server-route-repository:build",
+ "//packages/kbn-spec-to-console:build",
+ "//packages/kbn-std:build",
+ "//packages/kbn-storybook:build",
+ "//packages/kbn-telemetry-tools:build",
+ "//packages/kbn-test-jest-helpers:build",
+ "//packages/kbn-test-subj-selector:build",
+ "//packages/kbn-test:build",
+ "//packages/kbn-timelion-grammar:build",
+ "//packages/kbn-tinymath:build",
+ "//packages/kbn-type-summarizer:build",
+ "//packages/kbn-typed-react-router-config:build",
+ "//packages/kbn-ui-framework:build",
+ "//packages/kbn-ui-shared-deps-npm:build",
+ "//packages/kbn-ui-shared-deps-src:build",
+ "//packages/kbn-ui-theme:build",
+ "//packages/kbn-utility-types:build",
+ "//packages/kbn-utils:build",
],
)
@@ -80,76 +89,77 @@ filegroup(
filegroup(
name = "build_pkg_types",
srcs = [
- "//packages/elastic-apm-synthtrace:build_types",
- "//packages/elastic-datemath:build_types",
- "//packages/elastic-safer-lodash-set:build_types",
- "//packages/kbn-ace:build_types",
- "//packages/kbn-alerts:build_types",
- "//packages/kbn-analytics:build_types",
- "//packages/kbn-apm-config-loader:build_types",
- "//packages/kbn-apm-utils:build_types",
- "//packages/kbn-cli-dev-mode:build_types",
- "//packages/kbn-config:build_types",
- "//packages/kbn-config-schema:build_types",
- "//packages/kbn-crypto:build_types",
- "//packages/kbn-dev-utils:build_types",
- "//packages/kbn-doc-links:build_types",
- "//packages/kbn-docs-utils:build_types",
- "//packages/kbn-es-archiver:build_types",
- "//packages/kbn-es-query:build_types",
- "//packages/kbn-field-types:build_types",
- "//packages/kbn-i18n:build_types",
- "//packages/kbn-i18n-react:build_types",
- "//packages/kbn-interpreter:build_types",
- "//packages/kbn-io-ts-utils:build_types",
- "//packages/kbn-logging:build_types",
- "//packages/kbn-logging-mocks:build_types",
- "//packages/kbn-mapbox-gl:build_types",
- "//packages/kbn-monaco:build_types",
- "//packages/kbn-optimizer:build_types",
- "//packages/kbn-plugin-generator:build_types",
- "//packages/kbn-plugin-helpers:build_types",
- "//packages/kbn-react-field:build_types",
- "//packages/kbn-rule-data-utils:build_types",
- "//packages/kbn-securitysolution-autocomplete:build_types",
- "//packages/kbn-securitysolution-es-utils:build_types",
- "//packages/kbn-securitysolution-hook-utils:build_types",
- "//packages/kbn-securitysolution-io-ts-alerting-types:build_types",
- "//packages/kbn-securitysolution-io-ts-list-types:build_types",
- "//packages/kbn-securitysolution-io-ts-types:build_types",
- "//packages/kbn-securitysolution-io-ts-utils:build_types",
- "//packages/kbn-securitysolution-list-api:build_types",
- "//packages/kbn-securitysolution-list-constants:build_types",
- "//packages/kbn-securitysolution-list-hooks:build_types",
- "//packages/kbn-securitysolution-list-utils:build_types",
- "//packages/kbn-securitysolution-rules:build_types",
- "//packages/kbn-securitysolution-t-grid:build_types",
- "//packages/kbn-securitysolution-utils:build_types",
- "//packages/kbn-server-http-tools:build_types",
- "//packages/kbn-server-route-repository:build_types",
- "//packages/kbn-std:build_types",
- "//packages/kbn-storybook:build_types",
- "//packages/kbn-telemetry-tools:build_types",
- "//packages/kbn-test:build_types",
- "//packages/kbn-test-jest-helpers:build_types",
- "//packages/kbn-typed-react-router-config:build_types",
- "//packages/kbn-ui-shared-deps-npm:build_types",
- "//packages/kbn-ui-shared-deps-src:build_types",
- "//packages/kbn-ui-theme:build_types",
- "//packages/kbn-utility-types:build_types",
- "//packages/kbn-utils:build_types",
+ "//packages/elastic-apm-synthtrace:build_types",
+ "//packages/elastic-datemath:build_types",
+ "//packages/elastic-safer-lodash-set:build_types",
+ "//packages/kbn-ace:build_types",
+ "//packages/kbn-alerts:build_types",
+ "//packages/kbn-analytics:build_types",
+ "//packages/kbn-apm-config-loader:build_types",
+ "//packages/kbn-apm-utils:build_types",
+ "//packages/kbn-bazel-packages:build_types",
+ "//packages/kbn-cli-dev-mode:build_types",
+ "//packages/kbn-config-schema:build_types",
+ "//packages/kbn-config:build_types",
+ "//packages/kbn-crypto:build_types",
+ "//packages/kbn-dev-utils:build_types",
+ "//packages/kbn-doc-links:build_types",
+ "//packages/kbn-docs-utils:build_types",
+ "//packages/kbn-es-archiver:build_types",
+ "//packages/kbn-es-query:build_types",
+ "//packages/kbn-field-types:build_types",
+ "//packages/kbn-generate:build_types",
+ "//packages/kbn-i18n-react:build_types",
+ "//packages/kbn-i18n:build_types",
+ "//packages/kbn-interpreter:build_types",
+ "//packages/kbn-io-ts-utils:build_types",
+ "//packages/kbn-logging-mocks:build_types",
+ "//packages/kbn-logging:build_types",
+ "//packages/kbn-mapbox-gl:build_types",
+ "//packages/kbn-monaco:build_types",
+ "//packages/kbn-optimizer:build_types",
+ "//packages/kbn-plugin-generator:build_types",
+ "//packages/kbn-plugin-helpers:build_types",
+ "//packages/kbn-react-field:build_types",
+ "//packages/kbn-rule-data-utils:build_types",
+ "//packages/kbn-securitysolution-autocomplete:build_types",
+ "//packages/kbn-securitysolution-es-utils:build_types",
+ "//packages/kbn-securitysolution-hook-utils:build_types",
+ "//packages/kbn-securitysolution-io-ts-alerting-types:build_types",
+ "//packages/kbn-securitysolution-io-ts-list-types:build_types",
+ "//packages/kbn-securitysolution-io-ts-types:build_types",
+ "//packages/kbn-securitysolution-io-ts-utils:build_types",
+ "//packages/kbn-securitysolution-list-api:build_types",
+ "//packages/kbn-securitysolution-list-constants:build_types",
+ "//packages/kbn-securitysolution-list-hooks:build_types",
+ "//packages/kbn-securitysolution-list-utils:build_types",
+ "//packages/kbn-securitysolution-rules:build_types",
+ "//packages/kbn-securitysolution-t-grid:build_types",
+ "//packages/kbn-securitysolution-utils:build_types",
+ "//packages/kbn-server-http-tools:build_types",
+ "//packages/kbn-server-route-repository:build_types",
+ "//packages/kbn-std:build_types",
+ "//packages/kbn-storybook:build_types",
+ "//packages/kbn-telemetry-tools:build_types",
+ "//packages/kbn-test-jest-helpers:build_types",
+ "//packages/kbn-test:build_types",
+ "//packages/kbn-type-summarizer:build_types",
+ "//packages/kbn-typed-react-router-config:build_types",
+ "//packages/kbn-ui-shared-deps-npm:build_types",
+ "//packages/kbn-ui-shared-deps-src:build_types",
+ "//packages/kbn-ui-theme:build_types",
+ "//packages/kbn-utility-types:build_types",
+ "//packages/kbn-utils:build_types",
],
)
-
-
# Grouping target to call all underlying packages build
# targets so we can build them all at once
# It will auto build all declared code packages and types packages
filegroup(
name = "build",
srcs = [
- ":build_pkg_code",
- ":build_pkg_types"
+ ":build_pkg_code",
+ ":build_pkg_types"
],
)
diff --git a/packages/elastic-apm-synthtrace/BUILD.bazel b/packages/elastic-apm-synthtrace/BUILD.bazel
index 09406644f44b..646b94891f7c 100644
--- a/packages/elastic-apm-synthtrace/BUILD.bazel
+++ b/packages/elastic-apm-synthtrace/BUILD.bazel
@@ -32,6 +32,7 @@ RUNTIME_DEPS = [
"@npm//object-hash",
"@npm//p-limit",
"@npm//yargs",
+ "@npm//node-fetch",
]
TYPES_DEPS = [
@@ -43,6 +44,7 @@ TYPES_DEPS = [
"@npm//@types/object-hash",
"@npm//moment",
"@npm//p-limit",
+ "@npm//@types/node-fetch",
]
jsts_transpiler(
diff --git a/packages/elastic-apm-synthtrace/src/index.ts b/packages/elastic-apm-synthtrace/src/index.ts
index 381222ee10ef..0138a6525baf 100644
--- a/packages/elastic-apm-synthtrace/src/index.ts
+++ b/packages/elastic-apm-synthtrace/src/index.ts
@@ -14,3 +14,4 @@ export { createLogger, LogLevel } from './lib/utils/create_logger';
export type { Fields } from './lib/entity';
export type { ApmException, ApmSynthtraceEsClient } from './lib/apm';
+export type { SpanIterable } from './lib/span_iterable';
diff --git a/packages/elastic-apm-synthtrace/src/lib/apm/apm_fields.ts b/packages/elastic-apm-synthtrace/src/lib/apm/apm_fields.ts
index 4afebf0352a6..f117fc879c0e 100644
--- a/packages/elastic-apm-synthtrace/src/lib/apm/apm_fields.ts
+++ b/packages/elastic-apm-synthtrace/src/lib/apm/apm_fields.ts
@@ -31,9 +31,14 @@ export type ApmUserAgentFields = Partial<{
export interface ApmException {
message: string;
}
+export interface Observer {
+ version: string;
+ version_major: number;
+}
export type ApmFields = Fields &
Partial<{
+ 'timestamp.us'?: number;
'agent.name': string;
'agent.version': string;
'container.id': string;
@@ -47,8 +52,7 @@ export type ApmFields = Fields &
'host.name': string;
'kubernetes.pod.uid': string;
'metricset.name': string;
- 'observer.version': string;
- 'observer.version_major': number;
+ observer: Observer;
'parent.id': string;
'processor.event': string;
'processor.name': string;
diff --git a/packages/elastic-apm-synthtrace/src/lib/apm/base_span.ts b/packages/elastic-apm-synthtrace/src/lib/apm/base_span.ts
index 4fd5ee269860..fa57c2871d8a 100644
--- a/packages/elastic-apm-synthtrace/src/lib/apm/base_span.ts
+++ b/packages/elastic-apm-synthtrace/src/lib/apm/base_span.ts
@@ -24,7 +24,7 @@ export class BaseSpan extends Serializable {
});
}
- parent(span: BaseSpan) {
+ parent(span: BaseSpan): this {
this.fields['trace.id'] = span.fields['trace.id'];
this.fields['parent.id'] = span.isSpan()
? span.fields['span.id']
@@ -40,7 +40,7 @@ export class BaseSpan extends Serializable {
return this;
}
- children(...children: BaseSpan[]) {
+ children(...children: BaseSpan[]): this {
children.forEach((child) => {
child.parent(this);
});
@@ -50,17 +50,17 @@ export class BaseSpan extends Serializable {
return this;
}
- success() {
+ success(): this {
this.fields['event.outcome'] = 'success';
return this;
}
- failure() {
+ failure(): this {
this.fields['event.outcome'] = 'failure';
return this;
}
- outcome(outcome: 'success' | 'failure' | 'unknown') {
+ outcome(outcome: 'success' | 'failure' | 'unknown'): this {
this.fields['event.outcome'] = outcome;
return this;
}
diff --git a/packages/elastic-apm-synthtrace/src/lib/apm/client/apm_synthtrace_es_client.ts b/packages/elastic-apm-synthtrace/src/lib/apm/client/apm_synthtrace_es_client.ts
index 4a25d7009ad0..f5d68d8614e6 100644
--- a/packages/elastic-apm-synthtrace/src/lib/apm/client/apm_synthtrace_es_client.ts
+++ b/packages/elastic-apm-synthtrace/src/lib/apm/client/apm_synthtrace_es_client.ts
@@ -7,56 +7,115 @@
*/
import { Client } from '@elastic/elasticsearch';
-import { uploadEvents } from '../../../scripts/utils/upload_events';
-import { Fields } from '../../entity';
import { cleanWriteTargets } from '../../utils/clean_write_targets';
-import { getBreakdownMetrics } from '../utils/get_breakdown_metrics';
-import { getSpanDestinationMetrics } from '../utils/get_span_destination_metrics';
-import { getTransactionMetrics } from '../utils/get_transaction_metrics';
import { getApmWriteTargets } from '../utils/get_apm_write_targets';
import { Logger } from '../../utils/create_logger';
-import { apmEventsToElasticsearchOutput } from '../utils/apm_events_to_elasticsearch_output';
+import { ApmFields } from '../apm_fields';
+import { SpanIterable } from '../../span_iterable';
+import { StreamProcessor } from '../../stream_processor';
+import { SpanGeneratorsUnion } from '../../span_generators_union';
+
+export interface StreamToBulkOptions {
+ concurrency?: number;
+ maxDocs?: number;
+ mapToIndex?: (document: Record) => string;
+}
export class ApmSynthtraceEsClient {
- constructor(private readonly client: Client, private readonly logger: Logger) {}
+ constructor(
+ private readonly client: Client,
+ private readonly logger: Logger,
+ private readonly forceDataStreams: boolean
+ ) {}
private getWriteTargets() {
- return getApmWriteTargets({ client: this.client });
+ return getApmWriteTargets({ client: this.client, forceDataStreams: this.forceDataStreams });
}
clean() {
- return this.getWriteTargets().then((writeTargets) =>
- cleanWriteTargets({
+ return this.getWriteTargets().then(async (writeTargets) => {
+ const indices = Object.values(writeTargets);
+ this.logger.info(`Attempting to clean: ${indices}`);
+ if (this.forceDataStreams) {
+ for (const name of indices) {
+ const dataStream = await this.client.indices.getDataStream({ name }, { ignore: [404] });
+ if (dataStream.data_streams && dataStream.data_streams.length > 0) {
+ this.logger.debug(`Deleting datastream: ${name}`);
+ await this.client.indices.deleteDataStream({ name });
+ }
+ }
+ return;
+ }
+
+ return cleanWriteTargets({
client: this.client,
- targets: Object.values(writeTargets),
+ targets: indices,
logger: this.logger,
- })
- );
+ });
+ });
}
- async index(events: Fields[]) {
- const writeTargets = await this.getWriteTargets();
+ async updateComponentTemplates(numberOfPrimaryShards: number) {
+ const response = await this.client.cluster.getComponentTemplate({ name: '*apm*@custom' });
+ for (const componentTemplate of response.component_templates) {
+ if (componentTemplate.component_template._meta?.package?.name !== 'apm') continue;
- const eventsToIndex = apmEventsToElasticsearchOutput({
- events: [
- ...events,
- ...getTransactionMetrics(events),
- ...getSpanDestinationMetrics(events),
- ...getBreakdownMetrics(events),
- ],
- writeTargets,
- });
+ componentTemplate.component_template.template.settings = {
+ index: {
+ number_of_shards: numberOfPrimaryShards,
+ },
+ };
- await uploadEvents({
- batchSize: 1000,
- client: this.client,
- clientWorkers: 5,
- events: eventsToIndex,
- logger: this.logger,
+ const putTemplate = await this.client.cluster.putComponentTemplate({
+ name: componentTemplate.name,
+ ...componentTemplate.component_template,
+ });
+ this.logger.info(
+ `- updated component template ${componentTemplate.name}, acknowledged: ${putTemplate.acknowledged}`
+ );
+ }
+ }
+
+ async index(events: SpanIterable | SpanIterable[], options?: StreamToBulkOptions) {
+ const dataStream = Array.isArray(events) ? new SpanGeneratorsUnion(events) : events;
+
+ const writeTargets = await this.getWriteTargets();
+ // TODO logger.perf
+ await this.client.helpers.bulk({
+ concurrency: options?.concurrency ?? 10,
+ refresh: false,
+ refreshOnCompletion: false,
+ datasource: new StreamProcessor({
+ processors: StreamProcessor.apmProcessors,
+ maxSourceEvents: options?.maxDocs,
+ logger: this.logger,
+ })
+ // TODO https://github.com/elastic/elasticsearch-js/issues/1610
+ // having to map here is awkward, it'd be better to map just before serialization.
+ .streamToDocumentAsync(StreamProcessor.toDocument, dataStream),
+ onDrop: (doc) => {
+ this.logger.info(doc);
+ },
+ // TODO bug in client not passing generic to BulkHelperOptions<>
+ // https://github.com/elastic/elasticsearch-js/issues/1611
+ onDocument: (doc: unknown) => {
+ const d = doc as Record;
+ const index = options?.mapToIndex
+ ? options?.mapToIndex(d)
+ : this.forceDataStreams
+ ? StreamProcessor.getDataStreamForEvent(d, writeTargets)
+ : StreamProcessor.getIndexForEvent(d, writeTargets);
+ return { create: { _index: index } };
+ },
});
+ const indices = Object.values(writeTargets);
+ this.logger.info(`Indexed all data attempting to refresh: ${indices}`);
+
return this.client.indices.refresh({
- index: Object.values(writeTargets),
+ index: indices,
+ allow_no_indices: true,
+ ignore_unavailable: true,
});
}
}
diff --git a/packages/elastic-apm-synthtrace/src/lib/apm/client/apm_synthtrace_kibana_client.ts b/packages/elastic-apm-synthtrace/src/lib/apm/client/apm_synthtrace_kibana_client.ts
new file mode 100644
index 000000000000..6abd3e7633c6
--- /dev/null
+++ b/packages/elastic-apm-synthtrace/src/lib/apm/client/apm_synthtrace_kibana_client.ts
@@ -0,0 +1,43 @@
+/*
+ * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
+ * or more contributor license agreements. Licensed under the Elastic License
+ * 2.0 and the Server Side Public License, v 1; you may not use this file except
+ * in compliance with, at your election, the Elastic License 2.0 or the Server
+ * Side Public License, v 1.
+ */
+
+import fetch from 'node-fetch';
+import { Logger } from '../../utils/create_logger';
+
+export class ApmSynthtraceKibanaClient {
+ constructor(private readonly logger: Logger) {}
+
+ async migrateCloudToManagedApm(cloudId: string, username: string, password: string) {
+ await this.logger.perf('migrate_apm_on_cloud', async () => {
+ this.logger.info('attempting to migrate cloud instance over to managed APM');
+ const cloudUrls = Buffer.from(cloudId.split(':')[1], 'base64').toString().split('$');
+ const kibanaCloudUrl = `https://${cloudUrls[2]}.${cloudUrls[0]}`;
+ const response = await fetch(
+ kibanaCloudUrl + '/internal/apm/fleet/cloud_apm_package_policy',
+ {
+ method: 'POST', // *GET, POST, PUT, DELETE, etc.
+ headers: {
+ Authorization: 'Basic ' + Buffer.from(username + ':' + password).toString('base64'),
+ Accept: 'application/json',
+ 'Content-Type': 'application/json',
+ 'kbn-xsrf': 'kibana',
+ },
+ }
+ );
+ const responseJson = await response.json();
+ if (responseJson.message) {
+ this.logger.info(`Cloud Instance already migrated to managed APM: ${responseJson.message}`);
+ }
+ if (responseJson.cloudApmPackagePolicy) {
+ this.logger.info(
+ `Cloud Instance migrated to managed APM: ${responseJson.cloudApmPackagePolicy.package.version}`
+ );
+ }
+ });
+ }
+}
diff --git a/packages/elastic-apm-synthtrace/src/lib/apm/index.ts b/packages/elastic-apm-synthtrace/src/lib/apm/index.ts
index f020d9a1282e..fcb8e078bf02 100644
--- a/packages/elastic-apm-synthtrace/src/lib/apm/index.ts
+++ b/packages/elastic-apm-synthtrace/src/lib/apm/index.ts
@@ -7,12 +7,10 @@
*/
import { service } from './service';
import { browser } from './browser';
-import { getTransactionMetrics } from './utils/get_transaction_metrics';
-import { getSpanDestinationMetrics } from './utils/get_span_destination_metrics';
-import { getObserverDefaults } from './defaults/get_observer_defaults';
+import { getTransactionMetrics } from './processors/get_transaction_metrics';
+import { getSpanDestinationMetrics } from './processors/get_span_destination_metrics';
import { getChromeUserAgentDefaults } from './defaults/get_chrome_user_agent_defaults';
-import { apmEventsToElasticsearchOutput } from './utils/apm_events_to_elasticsearch_output';
-import { getBreakdownMetrics } from './utils/get_breakdown_metrics';
+import { getBreakdownMetrics } from './processors/get_breakdown_metrics';
import { getApmWriteTargets } from './utils/get_apm_write_targets';
import { ApmSynthtraceEsClient } from './client/apm_synthtrace_es_client';
@@ -23,9 +21,7 @@ export const apm = {
browser,
getTransactionMetrics,
getSpanDestinationMetrics,
- getObserverDefaults,
getChromeUserAgentDefaults,
- apmEventsToElasticsearchOutput,
getBreakdownMetrics,
getApmWriteTargets,
ApmSynthtraceEsClient,
diff --git a/packages/elastic-apm-synthtrace/src/lib/apm/utils/get_breakdown_metrics.ts b/packages/elastic-apm-synthtrace/src/lib/apm/processors/get_breakdown_metrics.ts
similarity index 96%
rename from packages/elastic-apm-synthtrace/src/lib/apm/utils/get_breakdown_metrics.ts
rename to packages/elastic-apm-synthtrace/src/lib/apm/processors/get_breakdown_metrics.ts
index 4f29a31d5d27..1772b5f65571 100644
--- a/packages/elastic-apm-synthtrace/src/lib/apm/utils/get_breakdown_metrics.ts
+++ b/packages/elastic-apm-synthtrace/src/lib/apm/processors/get_breakdown_metrics.ts
@@ -8,7 +8,7 @@
import objectHash from 'object-hash';
import { groupBy, pickBy } from 'lodash';
import { ApmFields } from '../apm_fields';
-import { createPicker } from './create_picker';
+import { createPicker } from '../utils/create_picker';
const instanceFields = [
'container.*',
@@ -41,7 +41,10 @@ export function getBreakdownMetrics(events: ApmFields[]) {
Object.keys(txWithSpans).forEach((transactionId) => {
const txEvents = txWithSpans[transactionId];
- const transaction = txEvents.find((event) => event['processor.event'] === 'transaction')!;
+ const transaction = txEvents.find((event) => event['processor.event'] === 'transaction');
+ if (transaction === undefined) {
+ return;
+ }
const eventsById: Record = {};
const activityByParentId: Record> = {};
diff --git a/packages/elastic-apm-synthtrace/src/lib/apm/utils/get_span_destination_metrics.ts b/packages/elastic-apm-synthtrace/src/lib/apm/processors/get_span_destination_metrics.ts
similarity index 95%
rename from packages/elastic-apm-synthtrace/src/lib/apm/utils/get_span_destination_metrics.ts
rename to packages/elastic-apm-synthtrace/src/lib/apm/processors/get_span_destination_metrics.ts
index 7adcdaa6ff94..b806948a0949 100644
--- a/packages/elastic-apm-synthtrace/src/lib/apm/utils/get_span_destination_metrics.ts
+++ b/packages/elastic-apm-synthtrace/src/lib/apm/processors/get_span_destination_metrics.ts
@@ -7,7 +7,7 @@
*/
import { ApmFields } from '../apm_fields';
-import { aggregate } from './aggregate';
+import { aggregate } from '../utils/aggregate';
export function getSpanDestinationMetrics(events: ApmFields[]) {
const exitSpans = events.filter((event) => !!event['span.destination.service.resource']);
diff --git a/packages/elastic-apm-synthtrace/src/lib/apm/utils/get_transaction_metrics.ts b/packages/elastic-apm-synthtrace/src/lib/apm/processors/get_transaction_metrics.ts
similarity index 94%
rename from packages/elastic-apm-synthtrace/src/lib/apm/utils/get_transaction_metrics.ts
rename to packages/elastic-apm-synthtrace/src/lib/apm/processors/get_transaction_metrics.ts
index baa9f57a19a4..c5d8de7d4299 100644
--- a/packages/elastic-apm-synthtrace/src/lib/apm/utils/get_transaction_metrics.ts
+++ b/packages/elastic-apm-synthtrace/src/lib/apm/processors/get_transaction_metrics.ts
@@ -8,7 +8,7 @@
import { sortBy } from 'lodash';
import { ApmFields } from '../apm_fields';
-import { aggregate } from './aggregate';
+import { aggregate } from '../utils/aggregate';
function sortAndCompressHistogram(histogram?: { values: number[]; counts: number[] }) {
return sortBy(histogram?.values).reduce(
@@ -34,12 +34,13 @@ export function getTransactionMetrics(events: ApmFields[]) {
.map((transaction) => {
return {
...transaction,
- ['trace.root']: transaction['parent.id'] === undefined,
+ ['transaction.root']: transaction['parent.id'] === undefined,
};
});
const metricsets = aggregate(transactions, [
'trace.root',
+ 'transaction.root',
'transaction.name',
'transaction.type',
'event.outcome',
@@ -77,7 +78,6 @@ export function getTransactionMetrics(events: ApmFields[]) {
histogram.counts.push(1);
histogram.values.push(Number(transaction['transaction.duration.us']));
}
-
return {
...metricset.key,
'metricset.name': 'transaction',
diff --git a/packages/elastic-apm-synthtrace/src/lib/apm/utils/aggregate.ts b/packages/elastic-apm-synthtrace/src/lib/apm/utils/aggregate.ts
index 505f7452fe5d..0a57debc5922 100644
--- a/packages/elastic-apm-synthtrace/src/lib/apm/utils/aggregate.ts
+++ b/packages/elastic-apm-synthtrace/src/lib/apm/utils/aggregate.ts
@@ -29,7 +29,6 @@ export function aggregate(events: ApmFields[], fields: string[]) {
const id = objectHash(key);
let metricset = metricsets.get(id);
-
if (!metricset) {
metricset = {
key: { ...key, 'processor.event': 'metric', 'processor.name': 'metric' },
@@ -37,7 +36,6 @@ export function aggregate(events: ApmFields[], fields: string[]) {
};
metricsets.set(id, metricset);
}
-
metricset.events.push(event);
}
diff --git a/packages/elastic-apm-synthtrace/src/lib/apm/utils/apm_events_to_elasticsearch_output.ts b/packages/elastic-apm-synthtrace/src/lib/apm/utils/apm_events_to_elasticsearch_output.ts
deleted file mode 100644
index 46456098df4a..000000000000
--- a/packages/elastic-apm-synthtrace/src/lib/apm/utils/apm_events_to_elasticsearch_output.ts
+++ /dev/null
@@ -1,60 +0,0 @@
-/*
- * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
- * or more contributor license agreements. Licensed under the Elastic License
- * 2.0 and the Server Side Public License, v 1; you may not use this file except
- * in compliance with, at your election, the Elastic License 2.0 or the Server
- * Side Public License, v 1.
- */
-
-import { getObserverDefaults } from '../defaults/get_observer_defaults';
-import { ApmFields } from '../apm_fields';
-import { dedot } from '../../utils/dedot';
-import { ElasticsearchOutput } from '../../utils/to_elasticsearch_output';
-
-export interface ApmElasticsearchOutputWriteTargets {
- transaction: string;
- span: string;
- error: string;
- metric: string;
-}
-
-const observerDefaults = getObserverDefaults();
-
-const esDocumentDefaults = {
- ecs: {
- version: '1.4',
- },
-};
-
-dedot(observerDefaults, esDocumentDefaults);
-
-export function apmEventsToElasticsearchOutput({
- events,
- writeTargets,
-}: {
- events: ApmFields[];
- writeTargets: ApmElasticsearchOutputWriteTargets;
-}): ElasticsearchOutput[] {
- return events.map((event) => {
- const values = {};
-
- Object.assign(values, event, {
- '@timestamp': new Date(event['@timestamp']!).toISOString(),
- 'timestamp.us': event['@timestamp']! * 1000,
- 'service.node.name':
- event['service.node.name'] || event['container.id'] || event['host.name'],
- });
-
- const document = {};
-
- Object.assign(document, esDocumentDefaults);
-
- dedot(values, document);
-
- return {
- _index: writeTargets[event['processor.event'] as keyof ApmElasticsearchOutputWriteTargets],
- _source: document,
- timestamp: event['@timestamp']!,
- };
- });
-}
diff --git a/packages/elastic-apm-synthtrace/src/lib/apm/utils/get_apm_write_targets.ts b/packages/elastic-apm-synthtrace/src/lib/apm/utils/get_apm_write_targets.ts
index f040ca46a9db..ec2e675d415f 100644
--- a/packages/elastic-apm-synthtrace/src/lib/apm/utils/get_apm_write_targets.ts
+++ b/packages/elastic-apm-synthtrace/src/lib/apm/utils/get_apm_write_targets.ts
@@ -7,13 +7,32 @@
*/
import { Client } from '@elastic/elasticsearch';
-import { ApmElasticsearchOutputWriteTargets } from './apm_events_to_elasticsearch_output';
+
+export interface ApmElasticsearchOutputWriteTargets {
+ transaction: string;
+ span: string;
+ error: string;
+ metric: string;
+ app_metric: string;
+}
export async function getApmWriteTargets({
client,
+ forceDataStreams,
}: {
client: Client;
+ forceDataStreams?: boolean;
}): Promise {
+ if (forceDataStreams) {
+ return {
+ transaction: 'traces-apm-default',
+ span: 'traces-apm-default',
+ metric: 'metrics-apm.internal-default',
+ app_metric: 'metrics-apm.app-default',
+ error: 'logs-apm.error-default',
+ };
+ }
+
const [indicesResponse, datastreamsResponse] = await Promise.all([
client.indices.getAlias({
index: 'apm-*',
@@ -40,11 +59,12 @@ export async function getApmWriteTargets({
.find(({ key, writeIndexAlias }) => writeIndexAlias && key.includes(filter))
?.writeIndexAlias!;
}
-
+ const metricsTarget = getDataStreamName('metrics-apm') || getAlias('-metric');
const targets = {
transaction: getDataStreamName('traces-apm') || getAlias('-transaction'),
span: getDataStreamName('traces-apm') || getAlias('-span'),
- metric: getDataStreamName('metrics-apm') || getAlias('-metric'),
+ metric: metricsTarget,
+ app_metric: metricsTarget,
error: getDataStreamName('logs-apm') || getAlias('-error'),
};
diff --git a/packages/elastic-apm-synthtrace/src/lib/interval.ts b/packages/elastic-apm-synthtrace/src/lib/interval.ts
index bafd1a06c534..fc31d0290968 100644
--- a/packages/elastic-apm-synthtrace/src/lib/interval.ts
+++ b/packages/elastic-apm-synthtrace/src/lib/interval.ts
@@ -6,27 +6,69 @@
* Side Public License, v 1.
*/
import moment from 'moment';
+import { ApmFields } from './apm/apm_fields';
+import { SpanIterable } from './span_iterable';
+import { SpanGenerator } from './span_generator';
-export class Interval {
+export function parseInterval(interval: string): [number, string] {
+ const args = interval.match(/(\d+)(s|m|h|d)/);
+ if (!args || args.length < 3) {
+ throw new Error('Failed to parse interval');
+ }
+ return [Number(args[1]), args[2] as any];
+}
+
+export class Interval implements Iterable {
constructor(
- private readonly from: number,
- private readonly to: number,
- private readonly interval: string
- ) {}
+ public readonly from: Date,
+ public readonly to: Date,
+ public readonly interval: string,
+ public readonly yieldRate: number = 1
+ ) {
+ [this.intervalAmount, this.intervalUnit] = parseInterval(interval);
+ }
- rate(rate: number) {
- let now = this.from;
- const args = this.interval.match(/(.*)(s|m|h|d)/);
- if (!args) {
- throw new Error('Failed to parse interval');
- }
- const timestamps: number[] = [];
- while (now < this.to) {
- timestamps.push(...new Array(rate).fill(now));
- now = moment(now)
- .add(Number(args[1]), args[2] as any)
- .valueOf();
+ private readonly intervalAmount: number;
+ private readonly intervalUnit: any;
+
+ spans(map: (timestamp: number, index?: number) => ApmFields[]): SpanIterable {
+ return new SpanGenerator(this, [
+ function* (i) {
+ let index = 0;
+ for (const x of i) {
+ for (const a of map(x, index)) {
+ yield a;
+ index++;
+ }
+ }
+ },
+ ]);
+ }
+
+ rate(rate: number): Interval {
+ return new Interval(this.from, this.to, this.interval, rate);
+ }
+ private yieldRateTimestamps(timestamp: number) {
+ return new Array(this.yieldRate).fill(timestamp);
+ }
+
+ private *_generate(): Iterable {
+ if (this.from > this.to) {
+ let now = this.from;
+ do {
+ yield* this.yieldRateTimestamps(now.getTime());
+ now = new Date(moment(now).subtract(this.intervalAmount, this.intervalUnit).valueOf());
+ } while (now > this.to);
+ } else {
+ let now = this.from;
+ do {
+ yield* this.yieldRateTimestamps(now.getTime());
+ now = new Date(moment(now).add(this.intervalAmount, this.intervalUnit).valueOf());
+ } while (now < this.to);
}
- return timestamps;
+ }
+
+ [Symbol.iterator]() {
+ return this._generate()[Symbol.iterator]();
}
}
diff --git a/packages/elastic-apm-synthtrace/src/lib/serializable.ts b/packages/elastic-apm-synthtrace/src/lib/serializable.ts
index e9ffe3ae9699..1211098519da 100644
--- a/packages/elastic-apm-synthtrace/src/lib/serializable.ts
+++ b/packages/elastic-apm-synthtrace/src/lib/serializable.ts
@@ -15,7 +15,7 @@ export class Serializable extends Entity {
});
}
- timestamp(time: number) {
+ timestamp(time: number): this {
this.fields['@timestamp'] = time;
return this;
}
diff --git a/packages/elastic-apm-synthtrace/src/lib/span_generator.ts b/packages/elastic-apm-synthtrace/src/lib/span_generator.ts
new file mode 100644
index 000000000000..aa043e982b50
--- /dev/null
+++ b/packages/elastic-apm-synthtrace/src/lib/span_generator.ts
@@ -0,0 +1,50 @@
+/*
+ * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
+ * or more contributor license agreements. Licensed under the Elastic License
+ * 2.0 and the Server Side Public License, v 1; you may not use this file except
+ * in compliance with, at your election, the Elastic License 2.0 or the Server
+ * Side Public License, v 1.
+ */
+
+import { Interval } from './interval';
+import { ApmFields } from './apm/apm_fields';
+import { SpanGeneratorsUnion } from './span_generators_union';
+import { SpanIterable } from './span_iterable';
+
+export class SpanGenerator implements SpanIterable {
+ constructor(
+ private readonly interval: Interval,
+ private readonly dataGenerator: Array<(interval: Interval) => Generator>
+ ) {
+ this._order = interval.from > interval.to ? 'desc' : 'asc';
+ }
+
+ private readonly _order: 'desc' | 'asc';
+ order() {
+ return this._order;
+ }
+
+ toArray(): ApmFields[] {
+ return Array.from(this);
+ }
+
+ concat(...iterables: SpanGenerator[]) {
+ return new SpanGeneratorsUnion([this, ...iterables]);
+ }
+
+ *[Symbol.iterator]() {
+ for (const iterator of this.dataGenerator) {
+ for (const fields of iterator(this.interval)) {
+ yield fields;
+ }
+ }
+ }
+
+ async *[Symbol.asyncIterator]() {
+ for (const iterator of this.dataGenerator) {
+ for (const fields of iterator(this.interval)) {
+ yield fields;
+ }
+ }
+ }
+}
diff --git a/packages/elastic-apm-synthtrace/src/lib/span_generators_union.ts b/packages/elastic-apm-synthtrace/src/lib/span_generators_union.ts
new file mode 100644
index 000000000000..9bbea307276c
--- /dev/null
+++ b/packages/elastic-apm-synthtrace/src/lib/span_generators_union.ts
@@ -0,0 +1,49 @@
+/*
+ * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
+ * or more contributor license agreements. Licensed under the Elastic License
+ * 2.0 and the Server Side Public License, v 1; you may not use this file except
+ * in compliance with, at your election, the Elastic License 2.0 or the Server
+ * Side Public License, v 1.
+ */
+
+import { ApmFields } from './apm/apm_fields';
+import { SpanIterable } from './span_iterable';
+import { merge } from './utils/merge_iterable';
+
+export class SpanGeneratorsUnion implements SpanIterable {
+ constructor(private readonly dataGenerators: SpanIterable[]) {
+ const orders = new Set<'desc' | 'asc'>(dataGenerators.map((d) => d.order()));
+ if (orders.size > 1) throw Error('Can only combine intervals with the same order()');
+ this._order = orders.has('asc') ? 'asc' : 'desc';
+ }
+
+ static empty: SpanGeneratorsUnion = new SpanGeneratorsUnion([]);
+
+ private readonly _order: 'desc' | 'asc';
+ order() {
+ return this._order;
+ }
+
+ toArray(): ApmFields[] {
+ return Array.from(this);
+ }
+
+ concat(...iterables: SpanIterable[]) {
+ return new SpanGeneratorsUnion([...this.dataGenerators, ...iterables]);
+ }
+
+ *[Symbol.iterator]() {
+ const iterator = merge(this.dataGenerators);
+ for (const fields of iterator) {
+ yield fields;
+ }
+ }
+
+ async *[Symbol.asyncIterator]() {
+ for (const iterator of this.dataGenerators) {
+ for (const fields of iterator) {
+ yield fields;
+ }
+ }
+ }
+}
diff --git a/packages/elastic-apm-synthtrace/src/lib/span_iterable.ts b/packages/elastic-apm-synthtrace/src/lib/span_iterable.ts
new file mode 100644
index 000000000000..f40658feba1f
--- /dev/null
+++ b/packages/elastic-apm-synthtrace/src/lib/span_iterable.ts
@@ -0,0 +1,46 @@
+/*
+ * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
+ * or more contributor license agreements. Licensed under the Elastic License
+ * 2.0 and the Server Side Public License, v 1; you may not use this file except
+ * in compliance with, at your election, the Elastic License 2.0 or the Server
+ * Side Public License, v 1.
+ */
+
+import { ApmFields } from './apm/apm_fields';
+import { SpanGeneratorsUnion } from './span_generators_union';
+
+export interface SpanIterable extends Iterable, AsyncIterable {
+ order(): 'desc' | 'asc';
+
+ toArray(): ApmFields[];
+
+ concat(...iterables: SpanIterable[]): SpanGeneratorsUnion;
+}
+
+export class SpanArrayIterable implements SpanIterable {
+ constructor(private fields: ApmFields[]) {
+ const timestamps = fields.filter((f) => f['@timestamp']).map((f) => f['@timestamp']!);
+ this._order = timestamps.length > 1 ? (timestamps[0] > timestamps[1] ? 'desc' : 'asc') : 'asc';
+ }
+
+ private readonly _order: 'desc' | 'asc';
+ order() {
+ return this._order;
+ }
+
+ async *[Symbol.asyncIterator](): AsyncIterator {
+ return this.fields[Symbol.iterator]();
+ }
+
+ [Symbol.iterator](): Iterator {
+ return this.fields[Symbol.iterator]();
+ }
+
+ concat(...iterables: SpanIterable[]): SpanGeneratorsUnion {
+ return new SpanGeneratorsUnion([this, ...iterables]);
+ }
+
+ toArray(): ApmFields[] {
+ return this.fields;
+ }
+}
diff --git a/packages/elastic-apm-synthtrace/src/lib/stack_monitoring/cluster_stats.ts b/packages/elastic-apm-synthtrace/src/lib/stack_monitoring/cluster_stats.ts
index 0995013cbcbb..1505303e6b83 100644
--- a/packages/elastic-apm-synthtrace/src/lib/stack_monitoring/cluster_stats.ts
+++ b/packages/elastic-apm-synthtrace/src/lib/stack_monitoring/cluster_stats.ts
@@ -17,13 +17,13 @@ export class ClusterStats extends Serializable {
this.fields['license.status'] = 'active';
}
- timestamp(timestamp: number) {
+ timestamp(timestamp: number): this {
super.timestamp(timestamp);
this.fields['cluster_stats.timestamp'] = new Date(timestamp).toISOString();
return this;
}
- indices(count: number) {
+ indices(count: number): this {
this.fields['cluster_stats.indices.count'] = count;
return this;
}
diff --git a/packages/elastic-apm-synthtrace/src/lib/stack_monitoring/kibana_stats.ts b/packages/elastic-apm-synthtrace/src/lib/stack_monitoring/kibana_stats.ts
index 495e5f013600..96df653119fd 100644
--- a/packages/elastic-apm-synthtrace/src/lib/stack_monitoring/kibana_stats.ts
+++ b/packages/elastic-apm-synthtrace/src/lib/stack_monitoring/kibana_stats.ts
@@ -10,15 +10,15 @@ import { Serializable } from '../serializable';
import { StackMonitoringFields } from './stack_monitoring_fields';
export class KibanaStats extends Serializable {
- timestamp(timestamp: number) {
- super.timestamp(timestamp);
+ timestamp(timestamp: number): this {
this.fields['kibana_stats.timestamp'] = new Date(timestamp).toISOString();
this.fields['kibana_stats.response_times.max'] = 250;
this.fields['kibana_stats.kibana.status'] = 'green';
+ this.fields.timestamp = timestamp;
return this;
}
- requests(disconnects: number, total: number) {
+ requests(disconnects: number, total: number): this {
this.fields['kibana_stats.requests.disconnects'] = disconnects;
this.fields['kibana_stats.requests.total'] = total;
return this;
diff --git a/packages/elastic-apm-synthtrace/src/lib/stack_monitoring/stack_monitoring_fields.ts b/packages/elastic-apm-synthtrace/src/lib/stack_monitoring/stack_monitoring_fields.ts
index 3e80d1e9f733..1d79b9b01411 100644
--- a/packages/elastic-apm-synthtrace/src/lib/stack_monitoring/stack_monitoring_fields.ts
+++ b/packages/elastic-apm-synthtrace/src/lib/stack_monitoring/stack_monitoring_fields.ts
@@ -26,4 +26,5 @@ export type StackMonitoringFields = Fields &
'kibana_stats.requests.total': number;
'kibana_stats.timestamp': string;
'kibana_stats.response_times.max': number;
+ timestamp: number;
}>;
diff --git a/packages/elastic-apm-synthtrace/src/lib/stream_processor.ts b/packages/elastic-apm-synthtrace/src/lib/stream_processor.ts
new file mode 100644
index 000000000000..35cb8d05582d
--- /dev/null
+++ b/packages/elastic-apm-synthtrace/src/lib/stream_processor.ts
@@ -0,0 +1,207 @@
+/*
+ * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
+ * or more contributor license agreements. Licensed under the Elastic License
+ * 2.0 and the Server Side Public License, v 1; you may not use this file except
+ * in compliance with, at your election, the Elastic License 2.0 or the Server
+ * Side Public License, v 1.
+ */
+
+import moment from 'moment';
+import { ApmFields } from './apm/apm_fields';
+import { SpanIterable } from './span_iterable';
+import { getTransactionMetrics } from './apm/processors/get_transaction_metrics';
+import { getSpanDestinationMetrics } from './apm/processors/get_span_destination_metrics';
+import { getBreakdownMetrics } from './apm/processors/get_breakdown_metrics';
+import { parseInterval } from './interval';
+import { dedot } from './utils/dedot';
+import { ApmElasticsearchOutputWriteTargets } from './apm/utils/get_apm_write_targets';
+import { Logger } from './utils/create_logger';
+
+export interface StreamProcessorOptions {
+ processors: Array<(events: ApmFields[]) => ApmFields[]>;
+ flushInterval?: string;
+ maxBufferSize?: number;
+ // the maximum source events to process, not the maximum documents outputted by the processor
+ maxSourceEvents?: number;
+ logger?: Logger;
+}
+
+export class StreamProcessor {
+ public static readonly apmProcessors = [
+ getTransactionMetrics,
+ getSpanDestinationMetrics,
+ getBreakdownMetrics,
+ ];
+
+ constructor(private readonly options: StreamProcessorOptions) {
+ [this.intervalAmount, this.intervalUnit] = this.options.flushInterval
+ ? parseInterval(this.options.flushInterval)
+ : parseInterval('1m');
+ }
+ private readonly intervalAmount: number;
+ private readonly intervalUnit: any;
+
+ // TODO move away from chunking and feed this data one by one to processors
+ *stream(...eventSources: SpanIterable[]) {
+ const maxBufferSize = this.options.maxBufferSize ?? 10000;
+ const maxSourceEvents = this.options.maxSourceEvents;
+ let localBuffer = [];
+ let flushAfter: number | null = null;
+ let sourceEventsYielded = 0;
+ for (const eventSource of eventSources) {
+ const order = eventSource.order();
+ this.options.logger?.info(`order: ${order}`);
+ for (const event of eventSource) {
+ const eventDate = event['@timestamp'] as number;
+ localBuffer.push(event);
+ if (flushAfter === null && eventDate !== null) {
+ flushAfter = this.calculateFlushAfter(eventDate, order);
+ }
+
+ yield StreamProcessor.enrich(event);
+ sourceEventsYielded++;
+ if (maxSourceEvents && sourceEventsYielded % (maxSourceEvents / 10) === 0) {
+ this.options.logger?.info(`Yielded ${sourceEventsYielded} events`);
+ }
+ if (maxSourceEvents && sourceEventsYielded >= maxSourceEvents) {
+ // yielded the maximum source events, we still want the local buffer to generate derivative documents
+ break;
+ }
+ if (
+ localBuffer.length === maxBufferSize ||
+ (flushAfter != null &&
+ ((order === 'asc' && eventDate > flushAfter) ||
+ (order === 'desc' && eventDate < flushAfter)))
+ ) {
+ const e = new Date(eventDate).toISOString();
+ const f = new Date(flushAfter!).toISOString();
+ this.options.logger?.debug(
+ `flush ${localBuffer.length} documents ${order}: ${e} => ${f}`
+ );
+ for (const processor of this.options.processors) {
+ yield* processor(localBuffer).map(StreamProcessor.enrich);
+ }
+ localBuffer = [];
+ flushAfter = this.calculateFlushAfter(flushAfter, order);
+ }
+ }
+ if (maxSourceEvents && sourceEventsYielded >= maxSourceEvents) {
+ this.options.logger?.info(`Yielded maximum number of documents: ${maxSourceEvents}`);
+ break;
+ }
+ }
+ if (localBuffer.length > 0) {
+ this.options.logger?.info(`Processing remaining buffer: ${localBuffer.length} items left`);
+ for (const processor of this.options.processors) {
+ yield* processor(localBuffer).map(StreamProcessor.enrich);
+ }
+ }
+ }
+
+ private calculateFlushAfter(eventDate: number | null, order: 'asc' | 'desc') {
+ if (order === 'desc') {
+ return moment(eventDate).subtract(this.intervalAmount, this.intervalUnit).valueOf();
+ } else {
+ return moment(eventDate).add(this.intervalAmount, this.intervalUnit).valueOf();
+ }
+ }
+
+ async *streamAsync(...eventSources: SpanIterable[]): AsyncIterator {
+ yield* this.stream(...eventSources);
+ }
+ *streamToDocument(
+ map: (d: ApmFields) => TDocument,
+ ...eventSources: SpanIterable[]
+ ): Generator {
+ for (const apmFields of this.stream(...eventSources)) {
+ yield map(apmFields);
+ }
+ }
+ async *streamToDocumentAsync(
+ map: (d: ApmFields) => TDocument,
+ ...eventSources: SpanIterable[]
+ ): AsyncIterator {
+ for (const apmFields of this.stream(...eventSources)) {
+ yield map(apmFields);
+ }
+ }
+ streamToArray(...eventSources: SpanIterable[]) {
+ return Array.from(this.stream(...eventSources));
+ }
+
+ static enrich(document: ApmFields): ApmFields {
+ // see https://github.com/elastic/apm-server/issues/7088 can not be provided as flat key/values
+ document.observer = {
+ version: '8.0.0',
+ version_major: 8,
+ };
+ document['service.node.name'] =
+ document['service.node.name'] || document['container.id'] || document['host.name'];
+ document['ecs.version'] = '1.4';
+ // TODO this non standard field should not be enriched here
+ if (document['processor.event'] !== 'metric') {
+ document['timestamp.us'] = document['@timestamp']! * 1000;
+ }
+ return document;
+ }
+
+ static toDocument(document: ApmFields): Record {
+ if (!document.observer) {
+ document = StreamProcessor.enrich(document);
+ }
+ const newDoc: Record = {};
+ dedot(document, newDoc);
+ if (typeof newDoc['@timestamp'] === 'number') {
+ const timestamp = newDoc['@timestamp'];
+ newDoc['@timestamp'] = new Date(timestamp).toISOString();
+ }
+ return newDoc;
+ }
+
+ static getDataStreamForEvent(
+ d: Record,
+ writeTargets: ApmElasticsearchOutputWriteTargets
+ ) {
+ if (!d.processor?.event) {
+ throw Error("'processor.event' is not set on document, can not determine target index");
+ }
+ const eventType = d.processor.event as keyof ApmElasticsearchOutputWriteTargets;
+ let dataStream = writeTargets[eventType];
+ if (eventType === 'metric') {
+ if (!d.service?.name) {
+ dataStream = 'metrics-apm.app-default';
+ } else {
+ if (!d.transaction && !d.span) {
+ dataStream = 'metrics-apm.app-default';
+ }
+ }
+ }
+ return dataStream;
+ }
+
+ static getIndexForEvent(
+ d: Record,
+ writeTargets: ApmElasticsearchOutputWriteTargets
+ ) {
+ if (!d.processor?.event) {
+ throw Error("'processor.event' is not set on document, can not determine target index");
+ }
+
+ const eventType = d.processor.event as keyof ApmElasticsearchOutputWriteTargets;
+ return writeTargets[eventType];
+ }
+}
+
+export async function* streamProcessAsync(
+ processors: Array<(events: ApmFields[]) => ApmFields[]>,
+ ...eventSources: SpanIterable[]
+) {
+ return new StreamProcessor({ processors }).streamAsync(...eventSources);
+}
+
+export function streamProcessToArray(
+ processors: Array<(events: ApmFields[]) => ApmFields[]>,
+ ...eventSources: SpanIterable[]
+) {
+ return new StreamProcessor({ processors }).streamToArray(...eventSources);
+}
diff --git a/packages/elastic-apm-synthtrace/src/lib/timerange.ts b/packages/elastic-apm-synthtrace/src/lib/timerange.ts
index 14111ad7b849..95e998e9ca20 100644
--- a/packages/elastic-apm-synthtrace/src/lib/timerange.ts
+++ b/packages/elastic-apm-synthtrace/src/lib/timerange.ts
@@ -9,13 +9,16 @@
import { Interval } from './interval';
export class Timerange {
- constructor(private from: number, private to: number) {}
+ constructor(private from: Date, private to: Date) {}
interval(interval: string) {
return new Interval(this.from, this.to, interval);
}
}
-export function timerange(from: number, to: number) {
- return new Timerange(from, to);
+export function timerange(from: Date | number, to: Date | number) {
+ return new Timerange(
+ from instanceof Date ? from : new Date(from),
+ to instanceof Date ? to : new Date(to)
+ );
}
diff --git a/packages/elastic-apm-synthtrace/src/lib/utils/merge_iterable.ts b/packages/elastic-apm-synthtrace/src/lib/utils/merge_iterable.ts
new file mode 100644
index 000000000000..415aa7eccfa1
--- /dev/null
+++ b/packages/elastic-apm-synthtrace/src/lib/utils/merge_iterable.ts
@@ -0,0 +1,37 @@
+/*
+ * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
+ * or more contributor license agreements. Licensed under the Elastic License
+ * 2.0 and the Server Side Public License, v 1; you may not use this file except
+ * in compliance with, at your election, the Elastic License 2.0 or the Server
+ * Side Public License, v 1.
+ */
+
+import { ApmFields } from '../apm/apm_fields';
+import { SpanIterable } from '../span_iterable';
+
+export function merge(iterables: SpanIterable[]): Iterable {
+ if (iterables.length === 1) return iterables[0];
+
+ const iterators = iterables.map>((i) => {
+ return i[Symbol.iterator]();
+ });
+ let done = false;
+ const myIterable: Iterable = {
+ *[Symbol.iterator]() {
+ do {
+ const items = iterators.map((i) => i.next());
+ done = items.every((item) => item.done);
+ if (!done) {
+ yield* items.filter((i) => !i.done).map((i) => i.value);
+ }
+ } while (!done);
+ // Done for the first time: close all iterators
+ for (const iterator of iterators) {
+ if (typeof iterator.return === 'function') {
+ iterator.return();
+ }
+ }
+ },
+ };
+ return myIterable;
+}
diff --git a/packages/elastic-apm-synthtrace/src/lib/utils/to_elasticsearch_output.ts b/packages/elastic-apm-synthtrace/src/lib/utils/to_elasticsearch_output.ts
deleted file mode 100644
index 58bafffaff69..000000000000
--- a/packages/elastic-apm-synthtrace/src/lib/utils/to_elasticsearch_output.ts
+++ /dev/null
@@ -1,44 +0,0 @@
-/*
- * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
- * or more contributor license agreements. Licensed under the Elastic License
- * 2.0 and the Server Side Public License, v 1; you may not use this file except
- * in compliance with, at your election, the Elastic License 2.0 or the Server
- * Side Public License, v 1.
- */
-
-import { Fields } from '../entity';
-import { dedot } from './dedot';
-
-export interface ElasticsearchOutput {
- _index: string;
- _source: unknown;
- timestamp: number;
-}
-
-export function eventsToElasticsearchOutput({
- events,
- writeTarget,
-}: {
- events: Fields[];
- writeTarget: string;
-}): ElasticsearchOutput[] {
- return events.map((event) => {
- const values = {};
-
- const timestamp = event['@timestamp']!;
-
- Object.assign(values, event, {
- '@timestamp': new Date(timestamp).toISOString(),
- });
-
- const document = {};
-
- dedot(values, document);
-
- return {
- _index: writeTarget,
- _source: document,
- timestamp,
- };
- });
-}
diff --git a/packages/elastic-apm-synthtrace/src/scripts/examples/01_simple_trace.ts b/packages/elastic-apm-synthtrace/src/scripts/examples/01_simple_trace.ts
index 4ea1af15f43e..b8792f6e1753 100644
--- a/packages/elastic-apm-synthtrace/src/scripts/examples/01_simple_trace.ts
+++ b/packages/elastic-apm-synthtrace/src/scripts/examples/01_simple_trace.ts
@@ -7,16 +7,15 @@
*/
import { apm, timerange } from '../../index';
-import { apmEventsToElasticsearchOutput } from '../../lib/apm/utils/apm_events_to_elasticsearch_output';
-import { getApmWriteTargets } from '../../lib/apm/utils/get_apm_write_targets';
+import { Instance } from '../../lib/apm/instance';
import { Scenario } from '../scenario';
import { getCommonServices } from '../utils/get_common_services';
+import { RunOptions } from '../utils/parse_run_cli_flags';
-const scenario: Scenario = async ({ target, logLevel, scenarioOpts }) => {
- const { client, logger } = getCommonServices({ target, logLevel });
- const writeTargets = await getApmWriteTargets({ client });
+const scenario: Scenario = async (runOptions: RunOptions) => {
+ const { logger } = getCommonServices(runOptions);
- const { numServices = 3 } = scenarioOpts || {};
+ const { numServices = 3 } = runOptions.scenarioOpts || {};
return {
generate: ({ from, to }) => {
@@ -28,79 +27,65 @@ const scenario: Scenario = async ({ target, logLevel, scenarioOpts }) => {
const failedTimestamps = range.interval('1s').rate(1);
- return new Array(numServices).fill(undefined).flatMap((_, index) => {
- const events = logger.perf('generating_apm_events', () => {
- const instance = apm
- .service(`opbeans-go-${index}`, 'production', 'go')
- .instance('instance');
+ const instances = [...Array(numServices).keys()].map((index) =>
+ apm.service(`opbeans-go-${index}`, 'production', 'go').instance('instance')
+ );
+ const instanceSpans = (instance: Instance) => {
+ const successfulTraceEvents = successfulTimestamps.spans((timestamp) =>
+ instance
+ .transaction(transactionName)
+ .timestamp(timestamp)
+ .duration(1000)
+ .success()
+ .children(
+ instance
+ .span('GET apm-*/_search', 'db', 'elasticsearch')
+ .duration(1000)
+ .success()
+ .destination('elasticsearch')
+ .timestamp(timestamp),
+ instance
+ .span('custom_operation', 'custom')
+ .duration(100)
+ .success()
+ .timestamp(timestamp)
+ )
+ .serialize()
+ );
- const successfulTraceEvents = successfulTimestamps.flatMap((timestamp) =>
- instance
- .transaction(transactionName)
- .timestamp(timestamp)
- .duration(1000)
- .success()
- .children(
- instance
- .span('GET apm-*/_search', 'db', 'elasticsearch')
- .duration(1000)
- .success()
- .destination('elasticsearch')
- .timestamp(timestamp),
- instance
- .span('custom_operation', 'custom')
- .duration(100)
- .success()
- .timestamp(timestamp)
- )
- .serialize()
- );
+ const failedTraceEvents = failedTimestamps.spans((timestamp) =>
+ instance
+ .transaction(transactionName)
+ .timestamp(timestamp)
+ .duration(1000)
+ .failure()
+ .errors(
+ instance.error('[ResponseError] index_not_found_exception').timestamp(timestamp + 50)
+ )
+ .serialize()
+ );
- const failedTraceEvents = failedTimestamps.flatMap((timestamp) =>
+ const metricsets = range
+ .interval('30s')
+ .rate(1)
+ .spans((timestamp) =>
instance
- .transaction(transactionName)
+ .appMetrics({
+ 'system.memory.actual.free': 800,
+ 'system.memory.total': 1000,
+ 'system.cpu.total.norm.pct': 0.6,
+ 'system.process.cpu.total.norm.pct': 0.7,
+ })
.timestamp(timestamp)
- .duration(1000)
- .failure()
- .errors(
- instance
- .error('[ResponseError] index_not_found_exception')
- .timestamp(timestamp + 50)
- )
.serialize()
);
- const metricsets = range
- .interval('30s')
- .rate(1)
- .flatMap((timestamp) =>
- instance
- .appMetrics({
- 'system.memory.actual.free': 800,
- 'system.memory.total': 1000,
- 'system.cpu.total.norm.pct': 0.6,
- 'system.process.cpu.total.norm.pct': 0.7,
- })
- .timestamp(timestamp)
- .serialize()
- );
- return [...successfulTraceEvents, ...failedTraceEvents, ...metricsets];
- });
+ return successfulTraceEvents.concat(failedTraceEvents, metricsets);
+ };
- return logger.perf('apm_events_to_es_output', () =>
- apmEventsToElasticsearchOutput({
- events: [
- ...events,
- ...logger.perf('get_transaction_metrics', () => apm.getTransactionMetrics(events)),
- ...logger.perf('get_span_destination_metrics', () =>
- apm.getSpanDestinationMetrics(events)
- ),
- ...logger.perf('get_breakdown_metrics', () => apm.getBreakdownMetrics(events)),
- ],
- writeTargets,
- })
- );
- });
+ return instances
+ .map((instance) => logger.perf('generating_apm_events', () => instanceSpans(instance)))
+ .reduce((p, c) => p.concat(c));
},
};
};
diff --git a/packages/elastic-apm-synthtrace/src/scripts/examples/02_kibana_stats.ts b/packages/elastic-apm-synthtrace/src/scripts/examples/02_kibana_stats.ts
index 2ba3c4a29c52..a19f0454e344 100644
--- a/packages/elastic-apm-synthtrace/src/scripts/examples/02_kibana_stats.ts
+++ b/packages/elastic-apm-synthtrace/src/scripts/examples/02_kibana_stats.ts
@@ -7,14 +7,14 @@
*/
import { stackMonitoring, timerange } from '../../index';
-import { eventsToElasticsearchOutput } from '../../lib/utils/to_elasticsearch_output';
import { Scenario } from '../scenario';
import { getCommonServices } from '../utils/get_common_services';
+import { RunOptions } from '../utils/parse_run_cli_flags';
-const scenario: Scenario = async ({ target, writeTarget, logLevel }) => {
- const { logger } = getCommonServices({ target, logLevel });
+const scenario: Scenario = async (runOptions: RunOptions) => {
+ const { logger } = getCommonServices(runOptions);
- if (!writeTarget) {
+ if (!runOptions.writeTarget) {
throw new Error('Write target is not defined');
}
@@ -26,20 +26,11 @@ const scenario: Scenario = async ({ target, writeTarget, logLevel }) => {
return range
.interval('30s')
.rate(1)
- .flatMap((timestamp) => {
+ .spans((timestamp) => {
const events = logger.perf('generating_sm_events', () => {
return kibanaStats.timestamp(timestamp).requests(10, 20).serialize();
});
-
- return logger.perf('sm_events_to_es_output', () => {
- const smEvents = eventsToElasticsearchOutput({ events, writeTarget });
- smEvents.forEach((event: any) => {
- const ts = event._source['@timestamp'];
- delete event._source['@timestamp'];
- event._source.timestamp = ts;
- });
- return smEvents;
- });
+ return events;
});
},
};
diff --git a/packages/elastic-apm-synthtrace/src/scripts/examples/03_monitoring.ts b/packages/elastic-apm-synthtrace/src/scripts/examples/03_monitoring.ts
index 53dcd820f551..cd98cf6ca063 100644
--- a/packages/elastic-apm-synthtrace/src/scripts/examples/03_monitoring.ts
+++ b/packages/elastic-apm-synthtrace/src/scripts/examples/03_monitoring.ts
@@ -9,32 +9,19 @@
// Run with: node ./src/scripts/run ./src/scripts/examples/03_monitoring.ts --target=http://elastic:changeme@localhost:9200
import { stackMonitoring, timerange } from '../../index';
-import {
- ElasticsearchOutput,
- eventsToElasticsearchOutput,
-} from '../../lib/utils/to_elasticsearch_output';
import { Scenario } from '../scenario';
import { getCommonServices } from '../utils/get_common_services';
-import { StackMonitoringFields } from '../../lib/stack_monitoring/stack_monitoring_fields';
+import { RunOptions } from '../utils/parse_run_cli_flags';
-// TODO (mat): move this into a function like utils/apm_events_to_elasticsearch_output.ts
-function smEventsToElasticsearchOutput(
- events: StackMonitoringFields[],
- writeTarget: string
-): ElasticsearchOutput[] {
- const smEvents = eventsToElasticsearchOutput({ events, writeTarget });
- smEvents.forEach((event: any) => {
- const ts = event._source['@timestamp'];
- delete event._source['@timestamp'];
- event._source.timestamp = ts;
- });
- return smEvents;
-}
-
-const scenario: Scenario = async ({ target, logLevel }) => {
- const { logger } = getCommonServices({ target, logLevel });
+const scenario: Scenario = async (runOptions: RunOptions) => {
+ const { logger } = getCommonServices(runOptions);
return {
+ mapToIndex: (data) => {
+ return data.kibana_stats?.kibana?.name
+ ? '.monitoring-kibana-7-synthtrace'
+ : '.monitoring-es-7-synthtrace';
+ },
generate: ({ from, to }) => {
const cluster = stackMonitoring.cluster('test-cluster');
const clusterStats = cluster.stats();
@@ -44,24 +31,14 @@ const scenario: Scenario = async ({ target, logLevel }) => {
return range
.interval('10s')
.rate(1)
- .flatMap((timestamp) => {
+ .spans((timestamp) => {
const clusterEvents = logger.perf('generating_es_events', () => {
return clusterStats.timestamp(timestamp).indices(115).serialize();
});
- const clusterOutputs = smEventsToElasticsearchOutput(
- clusterEvents,
- '.monitoring-es-7-synthtrace'
- );
-
const kibanaEvents = logger.perf('generating_kb_events', () => {
return kibanaStats.timestamp(timestamp).requests(10, 20).serialize();
});
- const kibanaOutputs = smEventsToElasticsearchOutput(
- kibanaEvents,
- '.monitoring-kibana-7-synthtrace'
- );
-
- return [...clusterOutputs, ...kibanaOutputs];
+ return [...clusterEvents, ...kibanaEvents];
});
},
};
diff --git a/packages/elastic-apm-synthtrace/src/scripts/run.ts b/packages/elastic-apm-synthtrace/src/scripts/run.ts
index 96bef3e958bd..36b3974c1216 100644
--- a/packages/elastic-apm-synthtrace/src/scripts/run.ts
+++ b/packages/elastic-apm-synthtrace/src/scripts/run.ts
@@ -13,6 +13,8 @@ import { startHistoricalDataUpload } from './utils/start_historical_data_upload'
import { startLiveDataUpload } from './utils/start_live_data_upload';
import { parseRunCliFlags } from './utils/parse_run_cli_flags';
import { getCommonServices } from './utils/get_common_services';
+import { ApmSynthtraceKibanaClient } from '../lib/apm/client/apm_synthtrace_kibana_client';
+import { ApmSynthtraceEsClient } from '../lib/apm/client/apm_synthtrace_es_client';
function options(y: Argv) {
return y
@@ -22,9 +24,23 @@ function options(y: Argv) {
string: true,
})
.option('target', {
- describe: 'Elasticsearch target, including username/password',
+ describe: 'Elasticsearch target',
+ string: true,
+ })
+ .option('cloudId', {
+ describe:
+ 'Provide connection information and will force APM on the cloud to migrate to run as a Fleet integration',
+ string: true,
+ })
+ .option('username', {
+ describe: 'Basic authentication username',
+ string: true,
demandOption: true,
+ })
+ .option('password', {
+ describe: 'Basic authentication password',
string: true,
+ demandOption: true,
})
.option('from', {
description: 'The start of the time window',
@@ -36,6 +52,20 @@ function options(y: Argv) {
description: 'Generate and index data continuously',
boolean: true,
})
+ .option('--dryRun', {
+ description: 'Enumerates the stream without sending events to Elasticsearch ',
+ boolean: true,
+ })
+ .option('maxDocs', {
+ description:
+ 'The maximum number of documents we are allowed to generate, should be multiple of 10.000',
+ number: true,
+ })
+ .option('numShards', {
+ description:
+ 'Updates the component templates to update the number of primary shards, requires cloudId to be provided',
+ number: true,
+ })
.option('clean', {
describe: 'Clean APM indices before indexing new data',
default: false,
@@ -75,7 +105,9 @@ function options(y: Argv) {
return arg as Record | undefined;
},
})
- .conflicts('to', 'live');
+ .conflicts('to', 'live')
+ .conflicts('maxDocs', 'live')
+ .conflicts('target', 'cloudId');
}
export type RunCliFlags = ReturnType['argv'];
@@ -84,38 +116,57 @@ yargs(process.argv.slice(2))
.command('*', 'Generate data and index into Elasticsearch', options, async (argv) => {
const runOptions = parseRunCliFlags(argv);
- const { logger } = getCommonServices(runOptions);
+ const { logger, client } = getCommonServices(runOptions);
- const to = datemath.parse(String(argv.to ?? 'now'))!.valueOf();
- const from = argv.from
+ const toMs = datemath.parse(String(argv.to ?? 'now'))!.valueOf();
+ const to = new Date(toMs);
+ const defaultTimeRange = !runOptions.maxDocs ? '15m' : '52w';
+ const fromMs = argv.from
? datemath.parse(String(argv.from))!.valueOf()
- : to - intervalToMs('15m');
+ : toMs - intervalToMs(defaultTimeRange);
+ const from = new Date(fromMs);
const live = argv.live;
+ const forceDataStreams = !!runOptions.cloudId;
+ const esClient = new ApmSynthtraceEsClient(client, logger, forceDataStreams);
+ if (runOptions.dryRun) {
+ await startHistoricalDataUpload(esClient, logger, runOptions, from, to);
+ return;
+ }
+ if (runOptions.cloudId) {
+ const kibanaClient = new ApmSynthtraceKibanaClient(logger);
+ await kibanaClient.migrateCloudToManagedApm(
+ runOptions.cloudId,
+ runOptions.username,
+ runOptions.password
+ );
+ }
+
+ if (runOptions.cloudId && runOptions.numShards && runOptions.numShards > 0) {
+ await esClient.updateComponentTemplates(runOptions.numShards);
+ }
+
+ if (argv.clean) {
+ await esClient.clean();
+ }
+
logger.info(
`Starting data generation\n: ${JSON.stringify(
{
...runOptions,
- from: new Date(from).toISOString(),
- to: new Date(to).toISOString(),
+ from: from.toISOString(),
+ to: to.toISOString(),
},
null,
2
)}`
);
- startHistoricalDataUpload({
- ...runOptions,
- from,
- to,
- });
+ await startHistoricalDataUpload(esClient, logger, runOptions, from, to);
if (live) {
- startLiveDataUpload({
- ...runOptions,
- start: to,
- });
+ await startLiveDataUpload(esClient, logger, runOptions, to);
}
})
.parse();
diff --git a/packages/elastic-apm-synthtrace/src/scripts/scenario.ts b/packages/elastic-apm-synthtrace/src/scripts/scenario.ts
index c134c08cd835..089babab0441 100644
--- a/packages/elastic-apm-synthtrace/src/scripts/scenario.ts
+++ b/packages/elastic-apm-synthtrace/src/scripts/scenario.ts
@@ -6,8 +6,11 @@
* Side Public License, v 1.
*/
-import { ElasticsearchOutput } from '../lib/utils/to_elasticsearch_output';
import { RunOptions } from './utils/parse_run_cli_flags';
+import { SpanIterable } from '../lib/span_iterable';
-type Generate = (range: { from: number; to: number }) => ElasticsearchOutput[];
-export type Scenario = (options: RunOptions) => Promise<{ generate: Generate }>;
+type Generate = (range: { from: Date; to: Date }) => SpanIterable;
+export type Scenario = (options: RunOptions) => Promise<{
+ generate: Generate;
+ mapToIndex?: (data: Record) => string;
+}>;
diff --git a/packages/elastic-apm-synthtrace/src/scripts/utils/get_common_services.ts b/packages/elastic-apm-synthtrace/src/scripts/utils/get_common_services.ts
index 0dee6dbc951e..88e5c75e3999 100644
--- a/packages/elastic-apm-synthtrace/src/scripts/utils/get_common_services.ts
+++ b/packages/elastic-apm-synthtrace/src/scripts/utils/get_common_services.ts
@@ -6,13 +6,21 @@
* Side Public License, v 1.
*/
-import { Client } from '@elastic/elasticsearch';
-import { createLogger, LogLevel } from '../../lib/utils/create_logger';
+import { Client, ClientOptions } from '@elastic/elasticsearch';
+import { createLogger } from '../../lib/utils/create_logger';
+import { RunOptions } from './parse_run_cli_flags';
-export function getCommonServices({ target, logLevel }: { target: string; logLevel: LogLevel }) {
- const client = new Client({
- node: target,
- });
+export function getCommonServices({ target, cloudId, username, password, logLevel }: RunOptions) {
+ if (!target && !cloudId) {
+ throw Error('target or cloudId needs to be specified');
+ }
+ const options: ClientOptions = !!target ? { node: target } : { cloud: { id: cloudId! } };
+ options.auth = {
+ username,
+ password,
+ };
+
+ const client = new Client(options);
const logger = createLogger(logLevel);
diff --git a/packages/elastic-apm-synthtrace/src/scripts/utils/parse_run_cli_flags.ts b/packages/elastic-apm-synthtrace/src/scripts/utils/parse_run_cli_flags.ts
index 47359bd07aa8..5a8b6f96c631 100644
--- a/packages/elastic-apm-synthtrace/src/scripts/utils/parse_run_cli_flags.ts
+++ b/packages/elastic-apm-synthtrace/src/scripts/utils/parse_run_cli_flags.ts
@@ -49,12 +49,18 @@ export function parseRunCliFlags(flags: RunCliFlags) {
return {
...pick(
flags,
+ 'maxDocs',
'target',
+ 'cloudId',
+ 'username',
+ 'password',
'workers',
'clientWorkers',
'batchSize',
'writeTarget',
- 'scenarioOpts'
+ 'numShards',
+ 'scenarioOpts',
+ 'dryRun'
),
intervalInMs,
bucketSizeInMs,
diff --git a/packages/elastic-apm-synthtrace/src/scripts/utils/start_historical_data_upload.ts b/packages/elastic-apm-synthtrace/src/scripts/utils/start_historical_data_upload.ts
index ee462085ef79..415292a85e0e 100644
--- a/packages/elastic-apm-synthtrace/src/scripts/utils/start_historical_data_upload.ts
+++ b/packages/elastic-apm-synthtrace/src/scripts/utils/start_historical_data_upload.ts
@@ -5,101 +5,55 @@
* in compliance with, at your election, the Elastic License 2.0 or the Server
* Side Public License, v 1.
*/
-import pLimit from 'p-limit';
-import Path from 'path';
-import { Worker } from 'worker_threads';
-import { getCommonServices } from './get_common_services';
import { RunOptions } from './parse_run_cli_flags';
-import { WorkerData } from './upload_next_batch';
-
-export async function startHistoricalDataUpload({
- from,
- to,
- intervalInMs,
- bucketSizeInMs,
- workers,
- clientWorkers,
- batchSize,
- logLevel,
- target,
- file,
- writeTarget,
- scenarioOpts,
-}: RunOptions & { from: number; to: number }) {
- let requestedUntil: number = from;
-
- const { logger } = getCommonServices({ target, logLevel });
-
- function processNextBatch() {
- const bucketFrom = requestedUntil;
- const bucketTo = Math.min(to, bucketFrom + bucketSizeInMs);
-
- if (bucketFrom === bucketTo) {
- return;
- }
-
- requestedUntil = bucketTo;
-
- logger.info(
- `Starting worker for ${new Date(bucketFrom).toISOString()} to ${new Date(
- bucketTo
- ).toISOString()}`
- );
-
- const workerData: WorkerData = {
- bucketFrom,
- bucketTo,
- file,
- logLevel,
- batchSize,
- bucketSizeInMs,
- clientWorkers,
- intervalInMs,
- target,
- workers,
- writeTarget,
- scenarioOpts,
- };
-
- const worker = new Worker(Path.join(__dirname, './upload_next_batch.js'), {
- workerData,
- });
-
- logger.perf('created_worker', () => {
- return new Promise((resolve, reject) => {
- worker.on('online', () => {
- resolve();
- });
- });
- });
-
- logger.perf('completed_worker', () => {
- return new Promise((resolve, reject) => {
- worker.on('exit', () => {
- resolve();
- });
- });
- });
-
- return new Promise((resolve, reject) => {
- worker.on('error', (err) => {
- reject(err);
- });
-
- worker.on('exit', (code) => {
- if (code !== 0) {
- reject(new Error(`Worker stopped: exit code ${code}`));
- return;
- }
- logger.debug('Worker completed');
- resolve();
- });
+import { getScenario } from './get_scenario';
+import { ApmSynthtraceEsClient } from '../../lib/apm';
+import { Logger } from '../../lib/utils/create_logger';
+import { StreamProcessor } from '../../lib/stream_processor';
+
+export async function startHistoricalDataUpload(
+ esClient: ApmSynthtraceEsClient,
+ logger: Logger,
+ runOptions: RunOptions,
+ from: Date,
+ to: Date
+) {
+ const file = runOptions.file;
+ const scenario = await logger.perf('get_scenario', () => getScenario({ file, logger }));
+
+ const { generate, mapToIndex } = await scenario(runOptions);
+
+ // if we want to generate a maximum number of documents reverse generation to descend.
+ [from, to] = runOptions.maxDocs ? [to, from] : [from, to];
+
+ logger.info(`Generating data from ${from} to ${to}`);
+
+ const events = logger.perf('generate_scenario', () => generate({ from, to }));
+
+ if (runOptions.dryRun) {
+ const maxDocs = runOptions.maxDocs;
+ const stream = new StreamProcessor({
+ processors: StreamProcessor.apmProcessors,
+ maxSourceEvents: maxDocs,
+ logger,
+ }).streamToDocument(StreamProcessor.toDocument, events);
+ logger.perf('enumerate_scenario', () => {
+ // @ts-ignore
+ // We just want to enumerate
+ let yielded = 0;
+ for (const _ of stream) {
+ yielded++;
+ }
});
+ return;
}
- const numBatches = Math.ceil((to - from) / bucketSizeInMs);
-
- const limiter = pLimit(workers);
-
- return Promise.all(new Array(numBatches).fill(undefined).map((_) => limiter(processNextBatch)));
+ const clientWorkers = runOptions.clientWorkers;
+ await logger.perf('index_scenario', () =>
+ esClient.index(events, {
+ concurrency: clientWorkers,
+ maxDocs: runOptions.maxDocs,
+ mapToIndex,
+ })
+ );
}
diff --git a/packages/elastic-apm-synthtrace/src/scripts/utils/start_live_data_upload.ts b/packages/elastic-apm-synthtrace/src/scripts/utils/start_live_data_upload.ts
index ab4eee4f255b..b3e477649878 100644
--- a/packages/elastic-apm-synthtrace/src/scripts/utils/start_live_data_upload.ts
+++ b/packages/elastic-apm-synthtrace/src/scripts/utils/start_live_data_upload.ts
@@ -8,49 +8,36 @@
import { partition } from 'lodash';
import { getScenario } from './get_scenario';
-import { uploadEvents } from './upload_events';
import { RunOptions } from './parse_run_cli_flags';
-import { getCommonServices } from './get_common_services';
-import { ElasticsearchOutput } from '../../lib/utils/to_elasticsearch_output';
+import { ApmFields } from '../../lib/apm/apm_fields';
+import { ApmSynthtraceEsClient } from '../../lib/apm';
+import { Logger } from '../../lib/utils/create_logger';
+import { SpanArrayIterable } from '../../lib/span_iterable';
-export async function startLiveDataUpload({
- file,
- start,
- bucketSizeInMs,
- intervalInMs,
- clientWorkers,
- batchSize,
- target,
- logLevel,
- workers,
- writeTarget,
- scenarioOpts,
-}: RunOptions & { start: number }) {
- let queuedEvents: ElasticsearchOutput[] = [];
- let requestedUntil: number = start;
-
- const { logger, client } = getCommonServices({ target, logLevel });
+export async function startLiveDataUpload(
+ esClient: ApmSynthtraceEsClient,
+ logger: Logger,
+ runOptions: RunOptions,
+ start: Date
+) {
+ const file = runOptions.file;
const scenario = await getScenario({ file, logger });
- const { generate } = await scenario({
- batchSize,
- bucketSizeInMs,
- clientWorkers,
- file,
- intervalInMs,
- logLevel,
- target,
- workers,
- writeTarget,
- scenarioOpts,
- });
+ const { generate, mapToIndex } = await scenario(runOptions);
+
+ let queuedEvents: ApmFields[] = [];
+ let requestedUntil: Date = start;
- function uploadNextBatch() {
- const end = new Date().getTime();
+ async function uploadNextBatch() {
+ const end = new Date();
if (end > requestedUntil) {
const bucketFrom = requestedUntil;
- const bucketTo = requestedUntil + bucketSizeInMs;
- const nextEvents = generate({ from: bucketFrom, to: bucketTo });
+ const bucketTo = new Date(requestedUntil.getTime() + runOptions.bucketSizeInMs);
+ // TODO this materializes into an array, assumption is that the live buffer will fit in memory
+ const nextEvents = logger.perf('execute_scenario', () =>
+ generate({ from: bucketFrom, to: bucketTo }).toArray()
+ );
+
logger.debug(
`Requesting ${new Date(bucketFrom).toISOString()} to ${new Date(
bucketTo
@@ -62,23 +49,27 @@ export async function startLiveDataUpload({
const [eventsToUpload, eventsToRemainInQueue] = partition(
queuedEvents,
- (event) => event.timestamp <= end
+ (event) => event['@timestamp'] !== undefined && event['@timestamp'] <= end.getTime()
);
logger.info(`Uploading until ${new Date(end).toISOString()}, events: ${eventsToUpload.length}`);
queuedEvents = eventsToRemainInQueue;
- uploadEvents({
- events: eventsToUpload,
- clientWorkers,
- batchSize,
- logger,
- client,
- });
+ await logger.perf('index_live_scenario', () =>
+ esClient.index(new SpanArrayIterable(eventsToUpload), {
+ concurrency: runOptions.clientWorkers,
+ maxDocs: runOptions.maxDocs,
+ mapToIndex,
+ })
+ );
}
- setInterval(uploadNextBatch, intervalInMs);
-
- uploadNextBatch();
+ do {
+ await uploadNextBatch();
+ await delay(runOptions.intervalInMs);
+ } while (true);
+}
+async function delay(ms: number) {
+ return await new Promise((resolve) => setTimeout(resolve, ms));
}
diff --git a/packages/elastic-apm-synthtrace/src/scripts/utils/upload_events.ts b/packages/elastic-apm-synthtrace/src/scripts/utils/upload_events.ts
deleted file mode 100644
index d68a1b88132b..000000000000
--- a/packages/elastic-apm-synthtrace/src/scripts/utils/upload_events.ts
+++ /dev/null
@@ -1,66 +0,0 @@
-/*
- * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
- * or more contributor license agreements. Licensed under the Elastic License
- * 2.0 and the Server Side Public License, v 1; you may not use this file except
- * in compliance with, at your election, the Elastic License 2.0 or the Server
- * Side Public License, v 1.
- */
-import { Client } from '@elastic/elasticsearch';
-import { chunk } from 'lodash';
-import pLimit from 'p-limit';
-import { inspect } from 'util';
-import { ElasticsearchOutput } from '../../lib/utils/to_elasticsearch_output';
-import { Logger } from '../../lib/utils/create_logger';
-
-export function uploadEvents({
- events,
- client,
- clientWorkers,
- batchSize,
- logger,
-}: {
- events: ElasticsearchOutput[];
- client: Client;
- clientWorkers: number;
- batchSize: number;
- logger: Logger;
-}) {
- const fn = pLimit(clientWorkers);
-
- const batches = chunk(events, batchSize);
-
- if (!batches.length) {
- return;
- }
-
- logger.debug(`Uploading ${events.length} in ${batches.length} batches`);
-
- const time = new Date().getTime();
-
- return Promise.all(
- batches.map((batch) =>
- fn(() => {
- return logger.perf('bulk_upload', () =>
- client.bulk({
- refresh: false,
- body: batch.flatMap((doc) => {
- return [{ index: { _index: doc._index } }, doc._source];
- }),
- })
- );
- })
- )
- ).then((results) => {
- const errors = results
- .flatMap((result) => result.items)
- .filter((item) => !!item.index?.error)
- .map((item) => item.index?.error);
-
- if (errors.length) {
- logger.error(inspect(errors.slice(0, 10), { depth: null }));
- throw new Error('Failed to upload some items');
- }
-
- logger.debug(`Uploaded ${events.length} in ${new Date().getTime() - time}ms`);
- });
-}
diff --git a/packages/elastic-apm-synthtrace/src/scripts/utils/upload_next_batch.ts b/packages/elastic-apm-synthtrace/src/scripts/utils/upload_next_batch.ts
deleted file mode 100644
index 973cbc2266cb..000000000000
--- a/packages/elastic-apm-synthtrace/src/scripts/utils/upload_next_batch.ts
+++ /dev/null
@@ -1,95 +0,0 @@
-/*
- * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
- * or more contributor license agreements. Licensed under the Elastic License
- * 2.0 and the Server Side Public License, v 1; you may not use this file except
- * in compliance with, at your election, the Elastic License 2.0 or the Server
- * Side Public License, v 1.
- */
-
-// add this to workerExample.js file.
-import { Client } from '@elastic/elasticsearch';
-import { workerData } from 'worker_threads';
-import { getScenario } from './get_scenario';
-import { createLogger, LogLevel } from '../../lib/utils/create_logger';
-import { uploadEvents } from './upload_events';
-
-export interface WorkerData {
- bucketFrom: number;
- bucketTo: number;
- file: string;
- scenarioOpts: Record | undefined;
- logLevel: LogLevel;
- clientWorkers: number;
- batchSize: number;
- intervalInMs: number;
- bucketSizeInMs: number;
- target: string;
- workers: number;
- writeTarget?: string;
-}
-
-const {
- bucketFrom,
- bucketTo,
- file,
- logLevel,
- clientWorkers,
- batchSize,
- intervalInMs,
- bucketSizeInMs,
- workers,
- target,
- writeTarget,
- scenarioOpts,
-} = workerData as WorkerData;
-
-async function uploadNextBatch() {
- if (bucketFrom === bucketTo) {
- return;
- }
-
- const logger = createLogger(logLevel);
- const client = new Client({
- node: target,
- });
-
- const scenario = await logger.perf('get_scenario', () => getScenario({ file, logger }));
-
- const { generate } = await scenario({
- intervalInMs,
- bucketSizeInMs,
- logLevel,
- file,
- clientWorkers,
- batchSize,
- target,
- workers,
- writeTarget,
- scenarioOpts,
- });
-
- const events = logger.perf('execute_scenario', () =>
- generate({ from: bucketFrom, to: bucketTo })
- );
-
- return uploadEvents({
- events,
- client,
- clientWorkers,
- batchSize,
- logger,
- });
-}
-
-uploadNextBatch()
- .then(() => {
- process.exit(0);
- })
- .catch((error) => {
- // eslint-disable-next-line
- console.log(error);
- // make sure error shows up in console before process is killed
- setTimeout(() => {
- process.exit(1);
- }, 100);
- });
diff --git a/packages/elastic-apm-synthtrace/src/test/apm_events_to_elasticsearch_output.test.ts b/packages/elastic-apm-synthtrace/src/test/apm_events_to_elasticsearch_output.test.ts
index b8d030255892..defdcc73cf6c 100644
--- a/packages/elastic-apm-synthtrace/src/test/apm_events_to_elasticsearch_output.test.ts
+++ b/packages/elastic-apm-synthtrace/src/test/apm_events_to_elasticsearch_output.test.ts
@@ -6,15 +6,8 @@
* Side Public License, v 1.
*/
-import { apmEventsToElasticsearchOutput } from '../lib/apm/utils/apm_events_to_elasticsearch_output';
import { ApmFields } from '../lib/apm/apm_fields';
-
-const writeTargets = {
- transaction: 'apm-8.0.0-transaction',
- span: 'apm-8.0.0-span',
- metric: 'apm-8.0.0-metric',
- error: 'apm-8.0.0-error',
-};
+import { StreamProcessor } from '../lib/stream_processor';
describe('output apm events to elasticsearch', () => {
let event: ApmFields;
@@ -29,32 +22,31 @@ describe('output apm events to elasticsearch', () => {
});
it('properly formats @timestamp', () => {
- const doc = apmEventsToElasticsearchOutput({ events: [event], writeTargets })[0] as any;
-
- expect(doc._source['@timestamp']).toEqual('2020-12-31T23:00:00.000Z');
+ const doc = StreamProcessor.toDocument(event);
+ expect(doc['@timestamp']).toEqual('2020-12-31T23:00:00.000Z');
});
it('formats a nested object', () => {
- const doc = apmEventsToElasticsearchOutput({ events: [event], writeTargets })[0] as any;
+ const doc = StreamProcessor.toDocument(event);
- expect(doc._source.processor).toEqual({
+ expect(doc.processor).toEqual({
event: 'transaction',
name: 'transaction',
});
});
it('formats all fields consistently', () => {
- const doc = apmEventsToElasticsearchOutput({ events: [event], writeTargets })[0] as any;
+ const doc = StreamProcessor.toDocument(event);
- expect(doc._source).toMatchInlineSnapshot(`
+ expect(doc).toMatchInlineSnapshot(`
Object {
"@timestamp": "2020-12-31T23:00:00.000Z",
"ecs": Object {
"version": "1.4",
},
"observer": Object {
- "version": "7.16.0",
- "version_major": 7,
+ "version": "8.0.0",
+ "version_major": 8,
},
"processor": Object {
"event": "transaction",
diff --git a/packages/elastic-apm-synthtrace/src/test/scenarios/01_simple_trace.test.ts b/packages/elastic-apm-synthtrace/src/test/scenarios/01_simple_trace.test.ts
index a78f1ec987bc..ce42dfc2a8e6 100644
--- a/packages/elastic-apm-synthtrace/src/test/scenarios/01_simple_trace.test.ts
+++ b/packages/elastic-apm-synthtrace/src/test/scenarios/01_simple_trace.test.ts
@@ -17,14 +17,14 @@ describe('simple trace', () => {
const javaInstance = javaService.instance('instance-1');
const range = timerange(
- new Date('2021-01-01T00:00:00.000Z').getTime(),
- new Date('2021-01-01T00:15:00.000Z').getTime()
+ new Date('2021-01-01T00:00:00.000Z'),
+ new Date('2021-01-01T00:15:00.000Z')
);
events = range
.interval('1m')
.rate(1)
- .flatMap((timestamp) =>
+ .spans((timestamp) =>
javaInstance
.transaction('GET /api/product/list')
.duration(1000)
@@ -38,7 +38,8 @@ describe('simple trace', () => {
.timestamp(timestamp + 50)
)
.serialize()
- );
+ )
+ .toArray();
});
it('generates the same data every time', () => {
diff --git a/packages/elastic-apm-synthtrace/src/test/scenarios/02_transaction_metrics.test.ts b/packages/elastic-apm-synthtrace/src/test/scenarios/02_transaction_metrics.test.ts
index d074bcbf6c1f..f5a99b3f389d 100644
--- a/packages/elastic-apm-synthtrace/src/test/scenarios/02_transaction_metrics.test.ts
+++ b/packages/elastic-apm-synthtrace/src/test/scenarios/02_transaction_metrics.test.ts
@@ -8,7 +8,8 @@
import { apm } from '../../lib/apm';
import { timerange } from '../../lib/timerange';
-import { getTransactionMetrics } from '../../lib/apm/utils/get_transaction_metrics';
+import { getTransactionMetrics } from '../../lib/apm/processors/get_transaction_metrics';
+import { StreamProcessor } from '../../lib/stream_processor';
describe('transaction metrics', () => {
let events: Array>;
@@ -18,36 +19,29 @@ describe('transaction metrics', () => {
const javaInstance = javaService.instance('instance-1');
const range = timerange(
- new Date('2021-01-01T00:00:00.000Z').getTime(),
- new Date('2021-01-01T00:15:00.000Z').getTime()
+ new Date('2021-01-01T00:00:00.000Z'),
+ new Date('2021-01-01T00:15:00.000Z')
);
- events = getTransactionMetrics(
- range
- .interval('1m')
- .rate(25)
- .flatMap((timestamp) =>
- javaInstance
- .transaction('GET /api/product/list')
- .duration(1000)
- .success()
- .timestamp(timestamp)
- .serialize()
- )
- .concat(
- range
- .interval('1m')
- .rate(50)
- .flatMap((timestamp) =>
- javaInstance
- .transaction('GET /api/product/list')
- .duration(1000)
- .failure()
- .timestamp(timestamp)
- .serialize()
- )
- )
- );
+ const span = (timestamp: number) =>
+ javaInstance.transaction('GET /api/product/list').duration(1000).timestamp(timestamp);
+
+ const processor = new StreamProcessor({
+ processors: [getTransactionMetrics],
+ flushInterval: '15m',
+ });
+ events = processor
+ .streamToArray(
+ range
+ .interval('1m')
+ .rate(25)
+ .spans((timestamp) => span(timestamp).success().serialize()),
+ range
+ .interval('1m')
+ .rate(50)
+ .spans((timestamp) => span(timestamp).failure().serialize())
+ )
+ .filter((fields) => fields['metricset.name'] === 'transaction');
});
it('generates the right amount of transaction metrics', () => {
diff --git a/packages/elastic-apm-synthtrace/src/test/scenarios/03_span_destination_metrics.test.ts b/packages/elastic-apm-synthtrace/src/test/scenarios/03_span_destination_metrics.test.ts
index fe4734c65739..b81dea452206 100644
--- a/packages/elastic-apm-synthtrace/src/test/scenarios/03_span_destination_metrics.test.ts
+++ b/packages/elastic-apm-synthtrace/src/test/scenarios/03_span_destination_metrics.test.ts
@@ -8,7 +8,8 @@
import { apm } from '../../lib/apm';
import { timerange } from '../../lib/timerange';
-import { getSpanDestinationMetrics } from '../../lib/apm/utils/get_span_destination_metrics';
+import { getSpanDestinationMetrics } from '../../lib/apm/processors/get_span_destination_metrics';
+import { StreamProcessor } from '../../lib/stream_processor';
describe('span destination metrics', () => {
let events: Array>;
@@ -18,57 +19,57 @@ describe('span destination metrics', () => {
const javaInstance = javaService.instance('instance-1');
const range = timerange(
- new Date('2021-01-01T00:00:00.000Z').getTime(),
- new Date('2021-01-01T00:15:00.000Z').getTime()
- );
-
- events = getSpanDestinationMetrics(
- range
- .interval('1m')
- .rate(25)
- .flatMap((timestamp) =>
- javaInstance
- .transaction('GET /api/product/list')
- .duration(1000)
- .success()
- .timestamp(timestamp)
- .children(
- javaInstance
- .span('GET apm-*/_search', 'db', 'elasticsearch')
- .timestamp(timestamp)
- .duration(1000)
- .destination('elasticsearch')
- .success()
- )
- .serialize()
- )
- .concat(
- range
- .interval('1m')
- .rate(50)
- .flatMap((timestamp) =>
- javaInstance
- .transaction('GET /api/product/list')
- .duration(1000)
- .failure()
- .timestamp(timestamp)
- .children(
- javaInstance
- .span('GET apm-*/_search', 'db', 'elasticsearch')
- .timestamp(timestamp)
- .duration(1000)
- .destination('elasticsearch')
- .failure(),
- javaInstance
- .span('custom_operation', 'app')
- .timestamp(timestamp)
- .duration(500)
- .success()
- )
- .serialize()
- )
- )
+ new Date('2021-01-01T00:00:00.000Z'),
+ new Date('2021-01-01T00:15:00.000Z')
);
+ const processor = new StreamProcessor({ processors: [getSpanDestinationMetrics] });
+ events = processor
+ .streamToArray(
+ range
+ .interval('1m')
+ .rate(25)
+ .spans((timestamp) =>
+ javaInstance
+ .transaction('GET /api/product/list')
+ .duration(1000)
+ .success()
+ .timestamp(timestamp)
+ .children(
+ javaInstance
+ .span('GET apm-*/_search', 'db', 'elasticsearch')
+ .timestamp(timestamp)
+ .duration(1000)
+ .destination('elasticsearch')
+ .success()
+ )
+ .serialize()
+ ),
+ range
+ .interval('1m')
+ .rate(50)
+ .spans((timestamp) =>
+ javaInstance
+ .transaction('GET /api/product/list')
+ .duration(1000)
+ .failure()
+ .timestamp(timestamp)
+ .children(
+ javaInstance
+ .span('GET apm-*/_search', 'db', 'elasticsearch')
+ .timestamp(timestamp)
+ .duration(1000)
+ .destination('elasticsearch')
+ .failure(),
+ javaInstance
+ .span('custom_operation', 'app')
+ .timestamp(timestamp)
+ .duration(500)
+ .success()
+ )
+ .serialize()
+ )
+ )
+ .filter((fields) => fields['metricset.name'] === 'span_destination');
});
it('generates the right amount of span metrics', () => {
diff --git a/packages/elastic-apm-synthtrace/src/test/scenarios/04_breakdown_metrics.test.ts b/packages/elastic-apm-synthtrace/src/test/scenarios/04_breakdown_metrics.test.ts
index 817f0aad9f5e..45f956834d76 100644
--- a/packages/elastic-apm-synthtrace/src/test/scenarios/04_breakdown_metrics.test.ts
+++ b/packages/elastic-apm-synthtrace/src/test/scenarios/04_breakdown_metrics.test.ts
@@ -8,8 +8,9 @@
import { sumBy } from 'lodash';
import { apm } from '../../lib/apm';
import { timerange } from '../../lib/timerange';
-import { getBreakdownMetrics } from '../../lib/apm/utils/get_breakdown_metrics';
+import { getBreakdownMetrics } from '../../lib/apm/processors/get_breakdown_metrics';
import { ApmFields } from '../../lib/apm/apm_fields';
+import { StreamProcessor } from '../../lib/stream_processor';
describe('breakdown metrics', () => {
let events: ApmFields[];
@@ -24,51 +25,58 @@ describe('breakdown metrics', () => {
const javaService = apm.service('opbeans-java', 'production', 'java');
const javaInstance = javaService.instance('instance-1');
- const start = new Date('2021-01-01T00:00:00.000Z').getTime();
-
- const range = timerange(start, start + INTERVALS * 30 * 1000);
-
- events = getBreakdownMetrics([
- ...range
- .interval('30s')
- .rate(LIST_RATE)
- .flatMap((timestamp) =>
- javaInstance
- .transaction('GET /api/product/list')
- .timestamp(timestamp)
- .duration(1000)
- .children(
- javaInstance
- .span('GET apm-*/_search', 'db', 'elasticsearch')
- .timestamp(timestamp + 150)
- .duration(500),
- javaInstance.span('GET foo', 'db', 'redis').timestamp(timestamp).duration(100)
- )
- .serialize()
- ),
- ...range
- .interval('30s')
- .rate(ID_RATE)
- .flatMap((timestamp) =>
- javaInstance
- .transaction('GET /api/product/:id')
- .timestamp(timestamp)
- .duration(1000)
- .children(
- javaInstance
- .span('GET apm-*/_search', 'db', 'elasticsearch')
- .duration(500)
- .timestamp(timestamp + 100)
- .children(
- javaInstance
- .span('bar', 'external', 'http')
- .timestamp(timestamp + 200)
- .duration(100)
- )
- )
- .serialize()
- ),
- ]).filter((event) => event['processor.event'] === 'metric');
+ const start = new Date('2021-01-01T00:00:00.000Z');
+
+ const range = timerange(start, new Date(start.getTime() + INTERVALS * 30 * 1000));
+
+ const listSpans = range
+ .interval('30s')
+ .rate(LIST_RATE)
+ .spans((timestamp) =>
+ javaInstance
+ .transaction('GET /api/product/list')
+ .timestamp(timestamp)
+ .duration(1000)
+ .children(
+ javaInstance
+ .span('GET apm-*/_search', 'db', 'elasticsearch')
+ .timestamp(timestamp + 150)
+ .duration(500),
+ javaInstance.span('GET foo', 'db', 'redis').timestamp(timestamp).duration(100)
+ )
+ .serialize()
+ );
+
+ const productPageSpans = range
+ .interval('30s')
+ .rate(ID_RATE)
+ .spans((timestamp) =>
+ javaInstance
+ .transaction('GET /api/product/:id')
+ .timestamp(timestamp)
+ .duration(1000)
+ .children(
+ javaInstance
+ .span('GET apm-*/_search', 'db', 'elasticsearch')
+ .duration(500)
+ .timestamp(timestamp + 100)
+ .children(
+ javaInstance
+ .span('bar', 'external', 'http')
+ .timestamp(timestamp + 200)
+ .duration(100)
+ )
+ )
+ .serialize()
+ );
+
+ const processor = new StreamProcessor({
+ processors: [getBreakdownMetrics],
+ flushInterval: '15m',
+ });
+ events = processor
+ .streamToArray(listSpans, productPageSpans)
+ .filter((event) => event['processor.event'] === 'metric');
});
it('generates the right amount of breakdown metrics', () => {
diff --git a/packages/elastic-eslint-config-kibana/typescript.js b/packages/elastic-eslint-config-kibana/typescript.js
index 3ada725cb180..c0c91bd5cd91 100644
--- a/packages/elastic-eslint-config-kibana/typescript.js
+++ b/packages/elastic-eslint-config-kibana/typescript.js
@@ -168,6 +168,22 @@ module.exports = {
selector: 'enum',
format: ['PascalCase', 'UPPER_CASE', 'camelCase'],
},
+ // https://typescript-eslint.io/rules/naming-convention/#ignore-properties-that-require-quotes
+ // restore check behavior before https://github.com/typescript-eslint/typescript-eslint/pull/4582
+ {
+ selector: [
+ 'classProperty',
+ 'objectLiteralProperty',
+ 'typeProperty',
+ 'classMethod',
+ 'objectLiteralMethod',
+ 'typeMethod',
+ 'accessor',
+ 'enumMember'
+ ],
+ format: null,
+ modifiers: ['requiresQuotes']
+ }
],
'@typescript-eslint/explicit-member-accessibility': ['error',
{
diff --git a/packages/kbn-babel-code-parser/package.json b/packages/kbn-babel-code-parser/package.json
index 7018cb3f8815..7ff913087f5b 100755
--- a/packages/kbn-babel-code-parser/package.json
+++ b/packages/kbn-babel-code-parser/package.json
@@ -8,5 +8,8 @@
"repository": {
"type": "git",
"url": "https://github.com/elastic/kibana/tree/main/packages/kbn-babel-code-parser"
+ },
+ "kibana": {
+ "devOnly": true
}
}
diff --git a/packages/kbn-babel-preset/node_preset.js b/packages/kbn-babel-preset/node_preset.js
index 1c74d6771633..b69c59f5e2cc 100644
--- a/packages/kbn-babel-preset/node_preset.js
+++ b/packages/kbn-babel-preset/node_preset.js
@@ -31,7 +31,7 @@ module.exports = (_, options = {}) => {
// Because of that we should use for that value the same version we install
// in the package.json in order to have the same polyfills between the environment
// and the tests
- corejs: '3.2.1',
+ corejs: '3.21.1',
bugfixes: true,
...(options['@babel/preset-env'] || {}),
diff --git a/packages/kbn-babel-preset/webpack_preset.js b/packages/kbn-babel-preset/webpack_preset.js
index ea49c406d50f..7bf1f518012a 100644
--- a/packages/kbn-babel-preset/webpack_preset.js
+++ b/packages/kbn-babel-preset/webpack_preset.js
@@ -18,7 +18,7 @@ module.exports = () => {
modules: false,
// Please read the explanation for this
// in node_preset.js
- corejs: '3.2.1',
+ corejs: '3.21.1',
bugfixes: true,
},
],
@@ -55,7 +55,7 @@ module.exports = () => {
[
require.resolve('@emotion/babel-preset-css-prop'),
{
- labelFormat: '[local]',
+ labelFormat: '[filename]--[local]',
},
],
],
diff --git a/packages/kbn-bazel-packages/BUILD.bazel b/packages/kbn-bazel-packages/BUILD.bazel
new file mode 100644
index 000000000000..08ffbe24ba2a
--- /dev/null
+++ b/packages/kbn-bazel-packages/BUILD.bazel
@@ -0,0 +1,120 @@
+load("@npm//@bazel/typescript:index.bzl", "ts_config")
+load("@build_bazel_rules_nodejs//:index.bzl", "js_library")
+load("//src/dev/bazel:index.bzl", "jsts_transpiler", "pkg_npm", "pkg_npm_types", "ts_project")
+
+PKG_DIRNAME = "kbn-bazel-packages"
+PKG_REQUIRE_NAME = "@kbn/bazel-packages"
+
+SOURCE_FILES = glob(
+ [
+ "src/**/*.ts",
+ ],
+ exclude = [
+ "**/*.test.*",
+ ],
+)
+
+SRCS = SOURCE_FILES
+
+filegroup(
+ name = "srcs",
+ srcs = SRCS,
+)
+
+NPM_MODULE_EXTRA_FILES = [
+ "package.json",
+ "README.md",
+]
+
+# In this array place runtime dependencies, including other packages and NPM packages
+# which must be available for this code to run.
+#
+# To reference other packages use:
+# "//repo/relative/path/to/package"
+# eg. "//packages/kbn-utils"
+#
+# To reference a NPM package use:
+# "@npm//name-of-package"
+# eg. "@npm//lodash"
+RUNTIME_DEPS = [
+ "//packages/kbn-utils",
+ "//packages/kbn-std",
+ "@npm//globby",
+]
+
+# In this array place dependencies necessary to build the types, which will include the
+# :npm_module_types target of other packages and packages from NPM, including @types/*
+# packages.
+#
+# To reference the types for another package use:
+# "//repo/relative/path/to/package:npm_module_types"
+# eg. "//packages/kbn-utils:npm_module_types"
+#
+# References to NPM packages work the same as RUNTIME_DEPS:
+# eg. "@npm//@types/babel__core"
+TYPES_DEPS = [
+ "//packages/kbn-utils:npm_module_types",
+ "//packages/kbn-std:npm_module_types",
+ "@npm//globby",
+]
+
+jsts_transpiler(
+ name = "target_node",
+ srcs = SRCS,
+ build_pkg_name = package_name(),
+)
+
+ts_config(
+ name = "tsconfig",
+ src = "tsconfig.json",
+ deps = [
+ "//:tsconfig.base.json",
+ "//:tsconfig.bazel.json",
+ ],
+)
+
+ts_project(
+ name = "tsc_types",
+ args = ['--pretty'],
+ srcs = SRCS,
+ deps = TYPES_DEPS,
+ declaration = True,
+ emit_declaration_only = True,
+ out_dir = "target_types",
+ root_dir = "src",
+ tsconfig = ":tsconfig",
+)
+
+js_library(
+ name = PKG_DIRNAME,
+ srcs = NPM_MODULE_EXTRA_FILES,
+ deps = RUNTIME_DEPS + [":target_node"],
+ package_name = PKG_REQUIRE_NAME,
+ visibility = ["//visibility:public"],
+)
+
+pkg_npm(
+ name = "npm_module",
+ deps = [":" + PKG_DIRNAME],
+)
+
+filegroup(
+ name = "build",
+ srcs = [":npm_module"],
+ visibility = ["//visibility:public"],
+)
+
+pkg_npm_types(
+ name = "npm_module_types",
+ srcs = SRCS,
+ deps = [":tsc_types"],
+ package_name = PKG_REQUIRE_NAME,
+ tsconfig = ":tsconfig",
+ visibility = ["//visibility:public"],
+)
+
+filegroup(
+ name = "build_types",
+ srcs = [":npm_module_types"],
+ visibility = ["//visibility:public"],
+)
diff --git a/packages/kbn-bazel-packages/README.md b/packages/kbn-bazel-packages/README.md
new file mode 100644
index 000000000000..fa34cd7facb8
--- /dev/null
+++ b/packages/kbn-bazel-packages/README.md
@@ -0,0 +1,3 @@
+# @kbn/bazel-packages
+
+APIs for dealing with bazel packages in the Kibana repo
diff --git a/packages/kbn-bazel-packages/jest.config.js b/packages/kbn-bazel-packages/jest.config.js
new file mode 100644
index 000000000000..c3fd73c73ca8
--- /dev/null
+++ b/packages/kbn-bazel-packages/jest.config.js
@@ -0,0 +1,13 @@
+/*
+ * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
+ * or more contributor license agreements. Licensed under the Elastic License
+ * 2.0 and the Server Side Public License, v 1; you may not use this file except
+ * in compliance with, at your election, the Elastic License 2.0 or the Server
+ * Side Public License, v 1.
+ */
+
+module.exports = {
+ preset: '@kbn/test/jest_node',
+ rootDir: '../..',
+ roots: ['/packages/kbn-bazel-packages'],
+};
diff --git a/packages/kbn-bazel-packages/package.json b/packages/kbn-bazel-packages/package.json
new file mode 100644
index 000000000000..085f0bb4510f
--- /dev/null
+++ b/packages/kbn-bazel-packages/package.json
@@ -0,0 +1,10 @@
+{
+ "name": "@kbn/bazel-packages",
+ "private": true,
+ "version": "1.0.0",
+ "main": "./target_node/index.js",
+ "license": "SSPL-1.0 OR Elastic License 2.0",
+ "kibana": {
+ "devOnly": true
+ }
+}
diff --git a/packages/kbn-bazel-packages/src/bazel_package.test.ts b/packages/kbn-bazel-packages/src/bazel_package.test.ts
new file mode 100644
index 000000000000..884cf0e646ba
--- /dev/null
+++ b/packages/kbn-bazel-packages/src/bazel_package.test.ts
@@ -0,0 +1,38 @@
+/*
+ * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
+ * or more contributor license agreements. Licensed under the Elastic License
+ * 2.0 and the Server Side Public License, v 1; you may not use this file except
+ * in compliance with, at your election, the Elastic License 2.0 or the Server
+ * Side Public License, v 1.
+ */
+
+import Fs from 'fs';
+import Path from 'path';
+
+import { BazelPackage } from './bazel_package';
+
+const OWN_BAZEL_BUILD_FILE = Fs.readFileSync(Path.resolve(__dirname, '../BUILD.bazel'), 'utf8');
+
+describe('hasBuildRule()', () => {
+ it('returns true if there is a rule with the name "build"', () => {
+ const pkg = new BazelPackage('foo', {}, OWN_BAZEL_BUILD_FILE);
+ expect(pkg.hasBuildRule()).toBe(true);
+ });
+
+ it('returns false if there is no rule with name "build"', () => {
+ const pkg = new BazelPackage('foo', {}, ``);
+ expect(pkg.hasBuildRule()).toBe(false);
+ });
+});
+
+describe('hasBuildTypesRule()', () => {
+ it('returns true if there is a rule with the name "build_types"', () => {
+ const pkg = new BazelPackage('foo', {}, OWN_BAZEL_BUILD_FILE);
+ expect(pkg.hasBuildTypesRule()).toBe(true);
+ });
+
+ it('returns false if there is no rule with name "build_types"', () => {
+ const pkg = new BazelPackage('foo', {}, ``);
+ expect(pkg.hasBuildTypesRule()).toBe(false);
+ });
+});
diff --git a/packages/kbn-bazel-packages/src/bazel_package.ts b/packages/kbn-bazel-packages/src/bazel_package.ts
new file mode 100644
index 000000000000..28170cb68a5d
--- /dev/null
+++ b/packages/kbn-bazel-packages/src/bazel_package.ts
@@ -0,0 +1,50 @@
+/*
+ * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
+ * or more contributor license agreements. Licensed under the Elastic License
+ * 2.0 and the Server Side Public License, v 1; you may not use this file except
+ * in compliance with, at your election, the Elastic License 2.0 or the Server
+ * Side Public License, v 1.
+ */
+
+import Path from 'path';
+import Fsp from 'fs/promises';
+import { REPO_ROOT } from '@kbn/utils';
+
+const BUILD_RULE_NAME = /(^|\s)name\s*=\s*"build"/;
+const BUILD_TYPES_RULE_NAME = /(^|\s)name\s*=\s*"build_types"/;
+
+export class BazelPackage {
+ static async fromDir(dir: string) {
+ let pkg;
+ try {
+ pkg = JSON.parse(await Fsp.readFile(Path.resolve(dir, 'package.json'), 'utf8'));
+ } catch (error) {
+ throw new Error(`unable to parse package.json in [${dir}]: ${error.message}`);
+ }
+
+ let buildBazelContent;
+ if (pkg.name !== '@kbn/pm') {
+ try {
+ buildBazelContent = await Fsp.readFile(Path.resolve(dir, 'BUILD.bazel'), 'utf8');
+ } catch (error) {
+ throw new Error(`unable to read BUILD.bazel file in [${dir}]: ${error.message}`);
+ }
+ }
+
+ return new BazelPackage(Path.relative(REPO_ROOT, dir), pkg, buildBazelContent);
+ }
+
+ constructor(
+ public readonly repoRelativeDir: string,
+ public readonly pkg: any,
+ public readonly buildBazelContent?: string
+ ) {}
+
+ hasBuildRule() {
+ return !!(this.buildBazelContent && BUILD_RULE_NAME.test(this.buildBazelContent));
+ }
+
+ hasBuildTypesRule() {
+ return !!(this.buildBazelContent && BUILD_TYPES_RULE_NAME.test(this.buildBazelContent));
+ }
+}
diff --git a/packages/kbn-bazel-packages/src/discover_packages.ts b/packages/kbn-bazel-packages/src/discover_packages.ts
new file mode 100644
index 000000000000..0c84c388c7c0
--- /dev/null
+++ b/packages/kbn-bazel-packages/src/discover_packages.ts
@@ -0,0 +1,32 @@
+/*
+ * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
+ * or more contributor license agreements. Licensed under the Elastic License
+ * 2.0 and the Server Side Public License, v 1; you may not use this file except
+ * in compliance with, at your election, the Elastic License 2.0 or the Server
+ * Side Public License, v 1.
+ */
+
+import Path from 'path';
+
+import globby from 'globby';
+import { REPO_ROOT } from '@kbn/utils';
+import { asyncMapWithLimit } from '@kbn/std';
+
+import { BazelPackage } from './bazel_package';
+
+/**
+ * Search the local Kibana repo for bazel packages and return an array of BazelPackage objects
+ * representing each package found.
+ */
+export async function discoverBazelPackages() {
+ const packageJsons = globby.sync('*/package.json', {
+ cwd: Path.resolve(REPO_ROOT, 'packages'),
+ absolute: true,
+ });
+
+ return await asyncMapWithLimit(
+ packageJsons.sort((a, b) => a.localeCompare(b)),
+ 10,
+ (path) => BazelPackage.fromDir(Path.dirname(path))
+ );
+}
diff --git a/packages/kbn-bazel-packages/src/generate_packages_build_bazel_file.test.ts b/packages/kbn-bazel-packages/src/generate_packages_build_bazel_file.test.ts
new file mode 100644
index 000000000000..2d9fd2ed48ad
--- /dev/null
+++ b/packages/kbn-bazel-packages/src/generate_packages_build_bazel_file.test.ts
@@ -0,0 +1,85 @@
+/*
+ * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
+ * or more contributor license agreements. Licensed under the Elastic License
+ * 2.0 and the Server Side Public License, v 1; you may not use this file except
+ * in compliance with, at your election, the Elastic License 2.0 or the Server
+ * Side Public License, v 1.
+ */
+
+import { generatePackagesBuildBazelFile } from './generate_packages_build_bazel_file';
+
+import { BazelPackage } from './bazel_package';
+
+it('produces a valid BUILD.bazel file', () => {
+ const packages = [
+ new BazelPackage(
+ 'foo',
+ {},
+ `
+ rule(
+ name = "build"
+ )
+ rule(
+ name = "build_types"
+ )
+ `
+ ),
+ new BazelPackage(
+ 'bar',
+ {},
+ `
+ rule(
+ name= "build_types"
+ )
+ `
+ ),
+ new BazelPackage(
+ 'bar',
+ {},
+ `
+ rule(
+ name ="build"
+ )
+ `
+ ),
+ new BazelPackage('bar', {}),
+ ];
+
+ expect(generatePackagesBuildBazelFile(packages)).toMatchInlineSnapshot(`
+ "################
+ ################
+ ## This file is automatically generated, to create a new package use \`node scripts/generate package --help\`
+ ################
+ ################
+
+ # It will build all declared code packages
+ filegroup(
+ name = \\"build_pkg_code\\",
+ srcs = [
+ \\"//foo:build\\",
+ \\"//bar:build\\",
+ ],
+ )
+
+ # It will build all declared package types
+ filegroup(
+ name = \\"build_pkg_types\\",
+ srcs = [
+ \\"//foo:build_types\\",
+ \\"//bar:build_types\\",
+ ],
+ )
+
+ # Grouping target to call all underlying packages build
+ # targets so we can build them all at once
+ # It will auto build all declared code packages and types packages
+ filegroup(
+ name = \\"build\\",
+ srcs = [
+ \\":build_pkg_code\\",
+ \\":build_pkg_types\\"
+ ],
+ )
+ "
+ `);
+});
diff --git a/packages/kbn-bazel-packages/src/generate_packages_build_bazel_file.ts b/packages/kbn-bazel-packages/src/generate_packages_build_bazel_file.ts
new file mode 100644
index 000000000000..d1dd3561ed39
--- /dev/null
+++ b/packages/kbn-bazel-packages/src/generate_packages_build_bazel_file.ts
@@ -0,0 +1,49 @@
+/*
+ * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
+ * or more contributor license agreements. Licensed under the Elastic License
+ * 2.0 and the Server Side Public License, v 1; you may not use this file except
+ * in compliance with, at your election, the Elastic License 2.0 or the Server
+ * Side Public License, v 1.
+ */
+
+import { BazelPackage } from './bazel_package';
+
+export function generatePackagesBuildBazelFile(packages: BazelPackage[]) {
+ return `################
+################
+## This file is automatically generated, to create a new package use \`node scripts/generate package --help\`
+################
+################
+
+# It will build all declared code packages
+filegroup(
+ name = "build_pkg_code",
+ srcs = [
+${packages
+ .flatMap((p) => (p.hasBuildRule() ? ` "//${p.repoRelativeDir}:build",` : []))
+ .join('\n')}
+ ],
+)
+
+# It will build all declared package types
+filegroup(
+ name = "build_pkg_types",
+ srcs = [
+${packages
+ .flatMap((p) => (p.hasBuildTypesRule() ? ` "//${p.repoRelativeDir}:build_types",` : []))
+ .join('\n')}
+ ],
+)
+
+# Grouping target to call all underlying packages build
+# targets so we can build them all at once
+# It will auto build all declared code packages and types packages
+filegroup(
+ name = "build",
+ srcs = [
+ ":build_pkg_code",
+ ":build_pkg_types"
+ ],
+)
+`;
+}
diff --git a/packages/kbn-bazel-packages/src/index.ts b/packages/kbn-bazel-packages/src/index.ts
new file mode 100644
index 000000000000..7e73fcd0a63e
--- /dev/null
+++ b/packages/kbn-bazel-packages/src/index.ts
@@ -0,0 +1,11 @@
+/*
+ * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
+ * or more contributor license agreements. Licensed under the Elastic License
+ * 2.0 and the Server Side Public License, v 1; you may not use this file except
+ * in compliance with, at your election, the Elastic License 2.0 or the Server
+ * Side Public License, v 1.
+ */
+
+export * from './discover_packages';
+export type { BazelPackage } from './bazel_package';
+export * from './generate_packages_build_bazel_file';
diff --git a/packages/kbn-bazel-packages/tsconfig.json b/packages/kbn-bazel-packages/tsconfig.json
new file mode 100644
index 000000000000..a8cfc2cceb08
--- /dev/null
+++ b/packages/kbn-bazel-packages/tsconfig.json
@@ -0,0 +1,17 @@
+{
+ "extends": "../../tsconfig.bazel.json",
+ "compilerOptions": {
+ "declaration": true,
+ "emitDeclarationOnly": true,
+ "outDir": "target_types",
+ "rootDir": "src",
+ "stripInternal": false,
+ "types": [
+ "jest",
+ "node"
+ ]
+ },
+ "include": [
+ "src/**/*"
+ ]
+}
diff --git a/packages/kbn-crypto/BUILD.bazel b/packages/kbn-crypto/BUILD.bazel
index de8c97ed3b71..09c5fbb47e3a 100644
--- a/packages/kbn-crypto/BUILD.bazel
+++ b/packages/kbn-crypto/BUILD.bazel
@@ -61,6 +61,7 @@ ts_project(
srcs = SRCS,
deps = TYPES_DEPS,
declaration = True,
+ declaration_map = True,
emit_declaration_only = True,
out_dir = "target_types",
root_dir = "src",
diff --git a/packages/kbn-crypto/tsconfig.json b/packages/kbn-crypto/tsconfig.json
index 272363e976ba..fc929cba6868 100644
--- a/packages/kbn-crypto/tsconfig.json
+++ b/packages/kbn-crypto/tsconfig.json
@@ -2,6 +2,7 @@
"extends": "../../tsconfig.bazel.json",
"compilerOptions": {
"declaration": true,
+ "declarationMap": true,
"emitDeclarationOnly": true,
"outDir": "./target_types",
"rootDir": "src",
diff --git a/packages/kbn-dev-utils/BUILD.bazel b/packages/kbn-dev-utils/BUILD.bazel
index 7be527c65a06..5f31a8ba0748 100644
--- a/packages/kbn-dev-utils/BUILD.bazel
+++ b/packages/kbn-dev-utils/BUILD.bazel
@@ -38,13 +38,14 @@ NPM_MODULE_EXTRA_FILES = [
"README.md",
":certs",
"ci_stats_reporter/package.json",
+ "sort_package_json/package.json",
"stdio/package.json",
"tooling_log/package.json"
]
RUNTIME_DEPS = [
- "//packages/kbn-utils",
"//packages/kbn-std",
+ "//packages/kbn-utils",
"@npm//@babel/core",
"@npm//axios",
"@npm//chalk",
@@ -54,11 +55,14 @@ RUNTIME_DEPS = [
"@npm//exit-hook",
"@npm//getopts",
"@npm//globby",
+ "@npm//jest-diff",
"@npm//load-json-file",
"@npm//markdown-it",
"@npm//normalize-path",
"@npm//prettier",
"@npm//rxjs",
+ "@npm//strip-ansi",
+ "@npm//sort-package-json",
"@npm//tar",
"@npm//tree-kill",
"@npm//vinyl",
@@ -66,8 +70,8 @@ RUNTIME_DEPS = [
]
TYPES_DEPS = [
- "//packages/kbn-utils:npm_module_types",
"//packages/kbn-std:npm_module_types",
+ "//packages/kbn-utils:npm_module_types",
"@npm//@babel/parser",
"@npm//@babel/types",
"@npm//@types/babel__core",
@@ -88,7 +92,10 @@ TYPES_DEPS = [
"@npm//execa",
"@npm//exit-hook",
"@npm//getopts",
+ "@npm//jest-diff",
"@npm//rxjs",
+ "@npm//sort-package-json",
+ "@npm//strip-ansi",
"@npm//tree-kill",
]
diff --git a/packages/kbn-dev-utils/sort_package_json/package.json b/packages/kbn-dev-utils/sort_package_json/package.json
new file mode 100644
index 000000000000..e075ec436de3
--- /dev/null
+++ b/packages/kbn-dev-utils/sort_package_json/package.json
@@ -0,0 +1,4 @@
+{
+ "main": "../target_node/sort_package_json",
+ "types": "../target_types/sort_package_json"
+}
\ No newline at end of file
diff --git a/packages/kbn-dev-utils/src/diff_strings.test.ts b/packages/kbn-dev-utils/src/diff_strings.test.ts
new file mode 100644
index 000000000000..411004c8412e
--- /dev/null
+++ b/packages/kbn-dev-utils/src/diff_strings.test.ts
@@ -0,0 +1,106 @@
+/*
+ * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
+ * or more contributor license agreements. Licensed under the Elastic License
+ * 2.0 and the Server Side Public License, v 1; you may not use this file except
+ * in compliance with, at your election, the Elastic License 2.0 or the Server
+ * Side Public License, v 1.
+ */
+
+import { diffStrings } from './diff_strings';
+
+const json = (x: any) => JSON.stringify(x, null, 2);
+
+describe('diffStrings()', () => {
+ it('returns undefined if values are equal', () => {
+ expect(diffStrings('1', '1')).toBe(undefined);
+ expect(diffStrings(json(['1', '2', { a: 'b' }]), json(['1', '2', { a: 'b' }]))).toBe(undefined);
+ expect(
+ diffStrings(
+ json({
+ a: '1',
+ b: '2',
+ }),
+ json({
+ a: '1',
+ b: '2',
+ })
+ )
+ ).toBe(undefined);
+ });
+
+ it('returns a diff if the values are different', () => {
+ const diff = diffStrings(json(['1', '2', { a: 'b' }]), json(['1', '2', { b: 'a' }]));
+
+ expect(diff).toMatchInlineSnapshot(`
+ "[32m- Expected[39m
+ [31m+ Received[39m
+
+ [2m [[22m
+ [2m \\"1\\",[22m
+ [2m \\"2\\",[22m
+ [2m {[22m
+ [32m- \\"a\\": \\"b\\"[39m
+ [31m+ \\"b\\": \\"a\\"[39m
+ [2m }[22m
+ [2m ][22m"
+ `);
+
+ const diff2 = diffStrings(
+ json({
+ a: '1',
+ b: '1',
+ }),
+ json({
+ b: '2',
+ a: '2',
+ })
+ );
+
+ expect(diff2).toMatchInlineSnapshot(`
+ "[32m- Expected[39m
+ [31m+ Received[39m
+
+ [2m {[22m
+ [32m- \\"a\\": \\"1\\",[39m
+ [32m- \\"b\\": \\"1\\"[39m
+ [31m+ \\"b\\": \\"2\\",[39m
+ [31m+ \\"a\\": \\"2\\"[39m
+ [2m }[22m"
+ `);
+ });
+
+ it('formats large diffs to focus on the changed lines', () => {
+ const diff = diffStrings(
+ json({
+ a: ['1', '1', '1', '1', '1', '1', '1', '2', '1', '1', '1', '1', '1', '1', '1', '1', '1'],
+ }),
+ json({
+ b: ['1', '1', '1', '1', '1', '1', '1', '1', '1', '1', '1', '1', '2', '1', '1', '1', '1'],
+ })
+ );
+
+ expect(diff).toMatchInlineSnapshot(`
+ "[32m- Expected[39m
+ [31m+ Received[39m
+
+ [2m {[22m
+ [32m- \\"a\\": [[39m
+ [31m+ \\"b\\": [[39m
+ [2m \\"1\\",[22m
+ [2m \\"1\\",[22m
+ [2m ...[22m
+ [2m \\"1\\",[22m
+ [2m \\"1\\",[22m
+ [32m- \\"2\\",[39m
+ [2m \\"1\\",[22m
+ [2m \\"1\\",[22m
+ [2m ...[22m
+ [2m \\"1\\",[22m
+ [2m \\"1\\",[22m
+ [31m+ \\"2\\",[39m
+ [2m \\"1\\",[22m
+ [2m \\"1\\",[22m
+ [2m ...[22m"
+ `);
+ });
+});
diff --git a/packages/kbn-dev-utils/src/diff_strings.ts b/packages/kbn-dev-utils/src/diff_strings.ts
new file mode 100644
index 000000000000..11b7e574c756
--- /dev/null
+++ b/packages/kbn-dev-utils/src/diff_strings.ts
@@ -0,0 +1,97 @@
+/*
+ * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
+ * or more contributor license agreements. Licensed under the Elastic License
+ * 2.0 and the Server Side Public License, v 1; you may not use this file except
+ * in compliance with, at your election, the Elastic License 2.0 or the Server
+ * Side Public License, v 1.
+ */
+
+import jestDiff from 'jest-diff';
+import stripAnsi from 'strip-ansi';
+import Chalk from 'chalk';
+
+function reformatJestDiff(diff: string) {
+ const diffLines = diff.split('\n');
+
+ if (
+ diffLines.length < 4 ||
+ stripAnsi(diffLines[0]) !== '- Expected' ||
+ stripAnsi(diffLines[1]) !== '+ Received'
+ ) {
+ throw new Error(`unexpected diff format: ${diff}`);
+ }
+
+ const outputLines = [diffLines.shift(), diffLines.shift(), diffLines.shift()];
+
+ /**
+ * buffer which contains between 0 and 5 lines from the diff which aren't additions or
+ * deletions. The first three are the first three lines seen since the buffer was cleared
+ * and the last two lines are the last two lines seen.
+ *
+ * When flushContext() is called we write the first two lines to output, an elipses if there
+ * are five lines, and then the last two lines.
+ *
+ * At the very end we will write the last two lines of context if they're defined
+ */
+ const contextBuffer: string[] = [];
+
+ /**
+ * Convert a line to an empty line with elipses placed where the text on that line starts
+ */
+ const toElipses = (line: string) => {
+ return stripAnsi(line).replace(/^(\s*).*/, '$1...');
+ };
+
+ while (diffLines.length) {
+ const line = diffLines.shift()!;
+ const plainLine = stripAnsi(line);
+ if (plainLine.startsWith('+ ') || plainLine.startsWith('- ')) {
+ // write contextBuffer to the outputLines
+ if (contextBuffer.length) {
+ outputLines.push(
+ ...contextBuffer.slice(0, 2),
+ ...(contextBuffer.length === 5
+ ? [Chalk.dim(toElipses(contextBuffer[2])), ...contextBuffer.slice(3, 5)]
+ : contextBuffer.slice(2, 4))
+ );
+
+ contextBuffer.length = 0;
+ }
+
+ // add this line to the outputLines
+ outputLines.push(line);
+ } else {
+ // update the contextBuffer with this line which doesn't represent a change
+ if (contextBuffer.length === 5) {
+ contextBuffer[3] = contextBuffer[4];
+ contextBuffer[4] = line;
+ } else {
+ contextBuffer.push(line);
+ }
+ }
+ }
+
+ if (contextBuffer.length) {
+ outputLines.push(
+ ...contextBuffer.slice(0, 2),
+ ...(contextBuffer.length > 2 ? [Chalk.dim(toElipses(contextBuffer[2]))] : [])
+ );
+ }
+
+ return outputLines.join('\n');
+}
+
+/**
+ * Produces a diff string which is nicely formatted to show the differences between two strings. This will
+ * be a multi-line string so it's generally a good idea to include a `\n` before this first line of the diff
+ * if you are concatenating it with another message.
+ */
+export function diffStrings(expected: string, received: string) {
+ const diff = jestDiff(expected, received);
+
+ if (!diff || stripAnsi(diff) === 'Compared values have no visual difference.') {
+ return undefined;
+ }
+
+ return reformatJestDiff(diff);
+}
diff --git a/packages/kbn-dev-utils/src/index.ts b/packages/kbn-dev-utils/src/index.ts
index 9b207ad9e996..db96db46bde7 100644
--- a/packages/kbn-dev-utils/src/index.ts
+++ b/packages/kbn-dev-utils/src/index.ts
@@ -32,3 +32,5 @@ export * from './streams';
export * from './babel';
export * from './extract';
export * from './vscode_config';
+export * from './sort_package_json';
+export * from './diff_strings';
diff --git a/packages/kbn-dev-utils/src/sort_package_json.ts b/packages/kbn-dev-utils/src/sort_package_json.ts
new file mode 100644
index 000000000000..9873244eb367
--- /dev/null
+++ b/packages/kbn-dev-utils/src/sort_package_json.ts
@@ -0,0 +1,43 @@
+/*
+ * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
+ * or more contributor license agreements. Licensed under the Elastic License
+ * 2.0 and the Server Side Public License, v 1; you may not use this file except
+ * in compliance with, at your election, the Elastic License 2.0 or the Server
+ * Side Public License, v 1.
+ */
+
+import sorter from 'sort-package-json';
+
+export function sortPackageJson(json: string) {
+ return (
+ JSON.stringify(
+ sorter(JSON.parse(json), {
+ // top level keys in the order they were written when this was implemented
+ sortOrder: [
+ 'name',
+ 'description',
+ 'keywords',
+ 'private',
+ 'version',
+ 'branch',
+ 'main',
+ 'browser',
+ 'types',
+ 'tsdocMetadata',
+ 'build',
+ 'homepage',
+ 'bugs',
+ 'license',
+ 'kibana',
+ 'author',
+ 'scripts',
+ 'repository',
+ 'engines',
+ 'resolutions',
+ ],
+ }),
+ null,
+ 2
+ ) + '\n'
+ );
+}
diff --git a/packages/kbn-dev-utils/src/tooling_log/tooling_log.ts b/packages/kbn-dev-utils/src/tooling_log/tooling_log.ts
index 84e9159dfcd4..e9b5ab04a739 100644
--- a/packages/kbn-dev-utils/src/tooling_log/tooling_log.ts
+++ b/packages/kbn-dev-utils/src/tooling_log/tooling_log.ts
@@ -62,7 +62,10 @@ export class ToolingLog {
* @param delta the number of spaces to increase/decrease the indentation
* @param block a function to run and reset any indentation changes after
*/
- public indent(delta = 0, block?: () => Promise) {
+ public indent(delta: number): undefined;
+ public indent(delta: number, block: () => Promise): Promise;
+ public indent(delta: number, block: () => T): T;
+ public indent(delta = 0, block?: () => T | Promise) {
const originalWidth = this.indentWidth$.getValue();
this.indentWidth$.next(Math.max(originalWidth + delta, 0));
if (!block) {
diff --git a/packages/kbn-doc-links/src/get_doc_links.ts b/packages/kbn-doc-links/src/get_doc_links.ts
index d73760b280d4..03948af63791 100644
--- a/packages/kbn-doc-links/src/get_doc_links.ts
+++ b/packages/kbn-doc-links/src/get_doc_links.ts
@@ -196,6 +196,7 @@ export const getDocLinks = ({ kibanaBranch }: GetDocLinkOptions): DocLinks => {
std_dev: `${ELASTICSEARCH_DOCS}search-aggregations-metrics-extendedstats-aggregation.html`,
sum: `${ELASTICSEARCH_DOCS}search-aggregations-metrics-sum-aggregation.html`,
top_hits: `${ELASTICSEARCH_DOCS}search-aggregations-metrics-top-hits-aggregation.html`,
+ top_metrics: `${ELASTICSEARCH_DOCS}search-aggregations-metrics-top-metrics.html`,
},
runtimeFields: {
overview: `${ELASTICSEARCH_DOCS}runtime.html`,
diff --git a/packages/kbn-docs-utils/src/api_docs/tests/snapshots/plugin_a.mdx b/packages/kbn-docs-utils/src/api_docs/tests/snapshots/plugin_a.mdx
index 9d3b2f5d3cf9..ab80f1f02d0a 100644
--- a/packages/kbn-docs-utils/src/api_docs/tests/snapshots/plugin_a.mdx
+++ b/packages/kbn-docs-utils/src/api_docs/tests/snapshots/plugin_a.mdx
@@ -4,7 +4,7 @@ slug: /kibana-dev-docs/api/pluginA
title: "pluginA"
image: https://source.unsplash.com/400x175/?github
summary: API docs for the pluginA plugin
-date: 2020-11-16
+date: 2022-02-14
tags: ['contributor', 'dev', 'apidocs', 'kibana', 'pluginA']
warning: This document is auto-generated and is meant to be viewed inside our experimental, new docs system. Reach out in #docs-engineering for more info.
---
diff --git a/packages/kbn-docs-utils/src/api_docs/tests/snapshots/plugin_a_foo.mdx b/packages/kbn-docs-utils/src/api_docs/tests/snapshots/plugin_a_foo.mdx
index 6d7f42982b89..e9873f822301 100644
--- a/packages/kbn-docs-utils/src/api_docs/tests/snapshots/plugin_a_foo.mdx
+++ b/packages/kbn-docs-utils/src/api_docs/tests/snapshots/plugin_a_foo.mdx
@@ -4,7 +4,7 @@ slug: /kibana-dev-docs/api/pluginA-foo
title: "pluginA.foo"
image: https://source.unsplash.com/400x175/?github
summary: API docs for the pluginA.foo plugin
-date: 2020-11-16
+date: 2022-02-14
tags: ['contributor', 'dev', 'apidocs', 'kibana', 'pluginA.foo']
warning: This document is auto-generated and is meant to be viewed inside our experimental, new docs system. Reach out in #docs-engineering for more info.
---
diff --git a/packages/kbn-docs-utils/src/api_docs/tests/snapshots/plugin_b.mdx b/packages/kbn-docs-utils/src/api_docs/tests/snapshots/plugin_b.mdx
index c86fbed82c23..1671cd7a529d 100644
--- a/packages/kbn-docs-utils/src/api_docs/tests/snapshots/plugin_b.mdx
+++ b/packages/kbn-docs-utils/src/api_docs/tests/snapshots/plugin_b.mdx
@@ -4,7 +4,7 @@ slug: /kibana-dev-docs/api/pluginB
title: "pluginB"
image: https://source.unsplash.com/400x175/?github
summary: API docs for the pluginB plugin
-date: 2020-11-16
+date: 2022-02-14
tags: ['contributor', 'dev', 'apidocs', 'kibana', 'pluginB']
warning: This document is auto-generated and is meant to be viewed inside our experimental, new docs system. Reach out in #docs-engineering for more info.
---
diff --git a/packages/kbn-es/src/cli_commands/build_snapshots.js b/packages/kbn-es/src/cli_commands/build_snapshots.js
index d6ea76faf2cf..070f11b8b5f8 100644
--- a/packages/kbn-es/src/cli_commands/build_snapshots.js
+++ b/packages/kbn-es/src/cli_commands/build_snapshots.js
@@ -42,32 +42,31 @@ exports.run = async (defaults = {}) => {
for (const license of ['oss', 'trial']) {
for (const platform of ['darwin', 'win32', 'linux']) {
log.info('Building', platform, license === 'trial' ? 'default' : 'oss', 'snapshot');
- log.indent(4);
+ await log.indent(4, async () => {
+ const snapshotPath = await buildSnapshot({
+ license,
+ sourcePath: options.sourcePath,
+ log,
+ platform,
+ });
- const snapshotPath = await buildSnapshot({
- license,
- sourcePath: options.sourcePath,
- log,
- platform,
- });
-
- const filename = basename(snapshotPath);
- const outputPath = resolve(outputDir, filename);
- const hash = createHash('sha512');
- await pipelineAsync(
- Fs.createReadStream(snapshotPath),
- new Transform({
- transform(chunk, _, cb) {
- hash.update(chunk);
- cb(undefined, chunk);
- },
- }),
- Fs.createWriteStream(outputPath)
- );
+ const filename = basename(snapshotPath);
+ const outputPath = resolve(outputDir, filename);
+ const hash = createHash('sha512');
+ await pipelineAsync(
+ Fs.createReadStream(snapshotPath),
+ new Transform({
+ transform(chunk, _, cb) {
+ hash.update(chunk);
+ cb(undefined, chunk);
+ },
+ }),
+ Fs.createWriteStream(outputPath)
+ );
- Fs.writeFileSync(`${outputPath}.sha512`, `${hash.digest('hex')} ${filename}`);
- log.success('snapshot and shasum written to', outputPath);
- log.indent(-4);
+ Fs.writeFileSync(`${outputPath}.sha512`, `${hash.digest('hex')} ${filename}`);
+ log.success('snapshot and shasum written to', outputPath);
+ });
}
}
};
diff --git a/packages/kbn-es/src/cli_commands/snapshot.js b/packages/kbn-es/src/cli_commands/snapshot.js
index 1c902796a0a0..095ce3cb0429 100644
--- a/packages/kbn-es/src/cli_commands/snapshot.js
+++ b/packages/kbn-es/src/cli_commands/snapshot.js
@@ -33,6 +33,8 @@ exports.help = (defaults = {}) => {
--use-cached Skips cache verification and use cached ES snapshot.
--skip-ready-check Disable the ready check,
--ready-timeout Customize the ready check timeout, in seconds or "Xm" format, defaults to 1m
+ --plugins Comma seperated list of Elasticsearch plugins to install
+ --secure-files Comma seperated list of secure_setting_name=/path pairs
Example:
@@ -58,6 +60,7 @@ exports.run = async (defaults = {}) => {
useCached: 'use-cached',
skipReadyCheck: 'skip-ready-check',
readyTimeout: 'ready-timeout',
+ secureFiles: 'secure-files',
},
string: ['version', 'ready-timeout'],
@@ -76,6 +79,13 @@ exports.run = async (defaults = {}) => {
if (options.dataArchive) {
await cluster.extractDataDirectory(installPath, options.dataArchive);
}
+ if (options.plugins) {
+ await cluster.installPlugins(installPath, options.plugins, options);
+ }
+ if (options.secureFiles) {
+ const pairs = options.secureFiles.split(',').map((kv) => kv.split('=').map((v) => v.trim()));
+ await cluster.configureKeystoreWithSecureSettingsFiles(installPath, pairs);
+ }
reportTime(installStartTime, 'installed', {
success: true,
diff --git a/packages/kbn-es/src/cli_commands/source.js b/packages/kbn-es/src/cli_commands/source.js
index c16e89e2c7f3..d1f8e02b5568 100644
--- a/packages/kbn-es/src/cli_commands/source.js
+++ b/packages/kbn-es/src/cli_commands/source.js
@@ -27,6 +27,8 @@ exports.help = (defaults = {}) => {
--password Sets password for elastic user [default: ${password}]
--password.[user] Sets password for native realm user [default: ${password}]
--ssl Sets up SSL on Elasticsearch
+ --plugins Comma seperated list of Elasticsearch plugins to install
+ --secure-files Comma seperated list of secure_setting_name=/path pairs
-E Additional key=value settings to pass to Elasticsearch
--skip-ready-check Disable the ready check,
--ready-timeout Customize the ready check timeout, in seconds or "Xm" format, defaults to 1m
@@ -47,6 +49,7 @@ exports.run = async (defaults = {}) => {
dataArchive: 'data-archive',
skipReadyCheck: 'skip-ready-check',
readyTimeout: 'ready-timeout',
+ secureFiles: 'secure-files',
esArgs: 'E',
},
@@ -62,6 +65,13 @@ exports.run = async (defaults = {}) => {
if (options.dataArchive) {
await cluster.extractDataDirectory(installPath, options.dataArchive);
}
+ if (options.plugins) {
+ await cluster.installPlugins(installPath, options.plugins, options);
+ }
+ if (options.secureFiles) {
+ const pairs = options.secureFiles.split(',').map((kv) => kv.split('=').map((v) => v.trim()));
+ await cluster.configureKeystoreWithSecureSettingsFiles(installPath, pairs);
+ }
await cluster.run(installPath, {
...options,
diff --git a/packages/kbn-es/src/cluster.js b/packages/kbn-es/src/cluster.js
index 22ff9ae3c0cd..a6faffc2cfcd 100644
--- a/packages/kbn-es/src/cluster.js
+++ b/packages/kbn-es/src/cluster.js
@@ -12,7 +12,7 @@ const chalk = require('chalk');
const path = require('path');
const { Client } = require('@elastic/elasticsearch');
const { downloadSnapshot, installSnapshot, installSource, installArchive } = require('./install');
-const { ES_BIN } = require('./paths');
+const { ES_BIN, ES_PLUGIN_BIN, ES_KEYSTORE_BIN } = require('./paths');
const {
log: defaultLog,
parseEsLog,
@@ -59,13 +59,10 @@ exports.Cluster = class Cluster {
*/
async installSource(options = {}) {
this._log.info(chalk.bold('Installing from source'));
- this._log.indent(4);
-
- const { installPath } = await installSource({ log: this._log, ...options });
-
- this._log.indent(-4);
-
- return { installPath };
+ return await this._log.indent(4, async () => {
+ const { installPath } = await installSource({ log: this._log, ...options });
+ return { installPath };
+ });
}
/**
@@ -78,16 +75,14 @@ exports.Cluster = class Cluster {
*/
async downloadSnapshot(options = {}) {
this._log.info(chalk.bold('Downloading snapshot'));
- this._log.indent(4);
+ return await this._log.indent(4, async () => {
+ const { installPath } = await downloadSnapshot({
+ log: this._log,
+ ...options,
+ });
- const { installPath } = await downloadSnapshot({
- log: this._log,
- ...options,
+ return { installPath };
});
-
- this._log.indent(-4);
-
- return { installPath };
}
/**
@@ -100,16 +95,14 @@ exports.Cluster = class Cluster {
*/
async installSnapshot(options = {}) {
this._log.info(chalk.bold('Installing from snapshot'));
- this._log.indent(4);
+ return await this._log.indent(4, async () => {
+ const { installPath } = await installSnapshot({
+ log: this._log,
+ ...options,
+ });
- const { installPath } = await installSnapshot({
- log: this._log,
- ...options,
+ return { installPath };
});
-
- this._log.indent(-4);
-
- return { installPath };
}
/**
@@ -122,16 +115,14 @@ exports.Cluster = class Cluster {
*/
async installArchive(path, options = {}) {
this._log.info(chalk.bold('Installing from an archive'));
- this._log.indent(4);
+ return await this._log.indent(4, async () => {
+ const { installPath } = await installArchive(path, {
+ log: this._log,
+ ...options,
+ });
- const { installPath } = await installArchive(path, {
- log: this._log,
- ...options,
+ return { installPath };
});
-
- this._log.indent(-4);
-
- return { installPath };
}
/**
@@ -144,21 +135,55 @@ exports.Cluster = class Cluster {
*/
async extractDataDirectory(installPath, archivePath, extractDirName = 'data') {
this._log.info(chalk.bold(`Extracting data directory`));
- this._log.indent(4);
-
- // stripComponents=1 excludes the root directory as that is how our archives are
- // structured. This works in our favor as we can explicitly extract into the data dir
- const extractPath = path.resolve(installPath, extractDirName);
- this._log.info(`Data archive: ${archivePath}`);
- this._log.info(`Extract path: ${extractPath}`);
-
- await extract({
- archivePath,
- targetDir: extractPath,
- stripComponents: 1,
+ await this._log.indent(4, async () => {
+ // stripComponents=1 excludes the root directory as that is how our archives are
+ // structured. This works in our favor as we can explicitly extract into the data dir
+ const extractPath = path.resolve(installPath, extractDirName);
+ this._log.info(`Data archive: ${archivePath}`);
+ this._log.info(`Extract path: ${extractPath}`);
+
+ await extract({
+ archivePath,
+ targetDir: extractPath,
+ stripComponents: 1,
+ });
});
+ }
+
+ /**
+ * Starts ES and returns resolved promise once started
+ *
+ * @param {String} installPath
+ * @param {String} plugins - comma separated list of plugins to install
+ * @param {Object} options
+ * @returns {Promise}
+ */
+ async installPlugins(installPath, plugins, options) {
+ const esJavaOpts = this.javaOptions(options);
+ for (const plugin of plugins.split(',')) {
+ await execa(ES_PLUGIN_BIN, ['install', plugin.trim()], {
+ cwd: installPath,
+ env: {
+ JAVA_HOME: '', // By default, we want to always unset JAVA_HOME so that the bundled JDK will be used
+ ES_JAVA_OPTS: esJavaOpts.trim(),
+ },
+ });
+ }
+ }
- this._log.indent(-4);
+ async configureKeystoreWithSecureSettingsFiles(installPath, secureSettingsFiles) {
+ const env = { JAVA_HOME: '' };
+ for (const [secureSettingName, secureSettingFile] of secureSettingsFiles) {
+ this._log.info(
+ `setting secure setting %s to %s`,
+ chalk.bold(secureSettingName),
+ chalk.bold(secureSettingFile)
+ );
+ await execa(ES_KEYSTORE_BIN, ['add-file', secureSettingName, secureSettingFile], {
+ cwd: installPath,
+ env,
+ });
+ }
}
/**
@@ -169,24 +194,27 @@ exports.Cluster = class Cluster {
* @returns {Promise}
*/
async start(installPath, options = {}) {
- this._exec(installPath, options);
-
- await Promise.race([
- // wait for native realm to be setup and es to be started
- Promise.all([
- first(this._process.stdout, (data) => {
- if (/started/.test(data)) {
- return true;
- }
- }),
- this._setupPromise,
- ]),
+ // _exec indents and we wait for our own end condition, so reset the indent level to it's current state after we're done waiting
+ await this._log.indent(0, async () => {
+ this._exec(installPath, options);
+
+ await Promise.race([
+ // wait for native realm to be setup and es to be started
+ Promise.all([
+ first(this._process.stdout, (data) => {
+ if (/started/.test(data)) {
+ return true;
+ }
+ }),
+ this._setupPromise,
+ ]),
- // await the outcome of the process in case it exits before starting
- this._outcome.then(() => {
- throw createCliError('ES exited without starting');
- }),
- ]);
+ // await the outcome of the process in case it exits before starting
+ this._outcome.then(() => {
+ throw createCliError('ES exited without starting');
+ }),
+ ]);
+ });
}
/**
@@ -197,16 +225,19 @@ exports.Cluster = class Cluster {
* @returns {Promise}
*/
async run(installPath, options = {}) {
- this._exec(installPath, options);
+ // _exec indents and we wait for our own end condition, so reset the indent level to it's current state after we're done waiting
+ await this._log.indent(0, async () => {
+ this._exec(installPath, options);
+
+ // log native realm setup errors so they aren't uncaught
+ this._setupPromise.catch((error) => {
+ this._log.error(error);
+ this.stop();
+ });
- // log native realm setup errors so they aren't uncaught
- this._setupPromise.catch((error) => {
- this._log.error(error);
- this.stop();
+ // await the final outcome of the process
+ await this._outcome;
});
-
- // await the final outcome of the process
- await this._outcome;
}
/**
@@ -285,19 +316,9 @@ exports.Cluster = class Cluster {
);
this._log.info('%s %s', ES_BIN, args.join(' '));
+ const esJavaOpts = this.javaOptions(options);
- let esJavaOpts = `${options.esJavaOpts || ''} ${process.env.ES_JAVA_OPTS || ''}`;
-
- // ES now automatically sets heap size to 50% of the machine's available memory
- // so we need to set it to a smaller size for local dev and CI
- // especially because we currently run many instances of ES on the same machine during CI
- // inital and max must be the same, so we only need to check the max
- if (!esJavaOpts.includes('Xmx')) {
- // 1536m === 1.5g
- esJavaOpts += ' -Xms1536m -Xmx1536m';
- }
-
- this._log.info('ES_JAVA_OPTS: %s', esJavaOpts.trim());
+ this._log.info('ES_JAVA_OPTS: %s', esJavaOpts);
this._process = execa(ES_BIN, args, {
cwd: installPath,
@@ -305,7 +326,7 @@ exports.Cluster = class Cluster {
...(installPath ? { ES_TMPDIR: path.resolve(installPath, 'ES_TMPDIR') } : {}),
...process.env,
JAVA_HOME: '', // By default, we want to always unset JAVA_HOME so that the bundled JDK will be used
- ES_JAVA_OPTS: esJavaOpts.trim(),
+ ES_JAVA_OPTS: esJavaOpts,
},
stdio: ['ignore', 'pipe', 'pipe'],
});
@@ -434,4 +455,18 @@ exports.Cluster = class Cluster {
}
}
}
+
+ javaOptions(options) {
+ let esJavaOpts = `${options.esJavaOpts || ''} ${process.env.ES_JAVA_OPTS || ''}`;
+
+ // ES now automatically sets heap size to 50% of the machine's available memory
+ // so we need to set it to a smaller size for local dev and CI
+ // especially because we currently run many instances of ES on the same machine during CI
+ // inital and max must be the same, so we only need to check the max
+ if (!esJavaOpts.includes('Xmx')) {
+ // 1536m === 1.5g
+ esJavaOpts += ' -Xms1536m -Xmx1536m';
+ }
+ return esJavaOpts.trim();
+ }
};
diff --git a/packages/kbn-es/src/paths.ts b/packages/kbn-es/src/paths.ts
index c1b859af4e1f..1d909f523302 100644
--- a/packages/kbn-es/src/paths.ts
+++ b/packages/kbn-es/src/paths.ts
@@ -19,6 +19,7 @@ export const BASE_PATH = Path.resolve(tempDir, 'kbn-es');
export const GRADLE_BIN = maybeUseBat('./gradlew');
export const ES_BIN = maybeUseBat('bin/elasticsearch');
+export const ES_PLUGIN_BIN = maybeUseBat('bin/elasticsearch-plugin');
export const ES_CONFIG = 'config/elasticsearch.yml';
export const ES_KEYSTORE_BIN = maybeUseBat('./bin/elasticsearch-keystore');
diff --git a/packages/kbn-flot-charts/lib/jquery_flot.js b/packages/kbn-flot-charts/lib/jquery_flot.js
index 43db1cc3d93d..5252356279e5 100644
--- a/packages/kbn-flot-charts/lib/jquery_flot.js
+++ b/packages/kbn-flot-charts/lib/jquery_flot.js
@@ -351,7 +351,7 @@ Licensed under the MIT license.
if (info == null) {
- var element = $("").html(text)
+ var element = $("").text(text)
.css({
position: "absolute",
'max-width': width,
diff --git a/packages/kbn-generate/BUILD.bazel b/packages/kbn-generate/BUILD.bazel
new file mode 100644
index 000000000000..8eda65869a45
--- /dev/null
+++ b/packages/kbn-generate/BUILD.bazel
@@ -0,0 +1,110 @@
+load("@npm//@bazel/typescript:index.bzl", "ts_config")
+load("@build_bazel_rules_nodejs//:index.bzl", "js_library")
+load("//src/dev/bazel:index.bzl", "jsts_transpiler", "pkg_npm", "pkg_npm_types", "ts_project")
+
+PKG_BASE_NAME = "kbn-generate"
+PKG_REQUIRE_NAME = "@kbn/generate"
+
+SOURCE_FILES = glob(
+ [
+ "src/**/*.ts",
+ ],
+ exclude = [
+ "**/*.test.*"
+ ],
+)
+
+SRCS = SOURCE_FILES
+
+filegroup(
+ name = "srcs",
+ srcs = SRCS,
+)
+
+NPM_MODULE_EXTRA_FILES = glob(["templates/**/*"]) + [
+ "package.json",
+]
+
+RUNTIME_DEPS = [
+ "//packages/kbn-dev-utils",
+ "//packages/kbn-bazel-packages",
+ "//packages/kbn-utils",
+ "@npm//ejs",
+ "@npm//normalize-path",
+]
+
+TYPES_DEPS = [
+ "//packages/kbn-dev-utils:npm_module_types",
+ "//packages/kbn-bazel-packages:npm_module_types",
+ "//packages/kbn-utils:npm_module_types",
+ "@npm//ejs",
+ "@npm//normalize-path",
+ "@npm//@types/ejs",
+]
+
+jsts_transpiler(
+ name = "target_node",
+ srcs = SRCS,
+ build_pkg_name = package_name(),
+)
+
+ts_config(
+ name = "tsconfig",
+ src = "tsconfig.json",
+ deps = [
+ "//:tsconfig.base.json",
+ "//:tsconfig.bazel.json",
+ ],
+)
+
+ts_project(
+ name = "tsc_types",
+ args = ['--pretty'],
+ srcs = SRCS,
+ deps = TYPES_DEPS,
+ declaration = True,
+ emit_declaration_only = True,
+ out_dir = "target_types",
+ root_dir = "src",
+ tsconfig = ":tsconfig",
+)
+
+js_library(
+ name = PKG_BASE_NAME,
+ srcs = NPM_MODULE_EXTRA_FILES,
+ deps = RUNTIME_DEPS + [":target_node"],
+ package_name = PKG_REQUIRE_NAME,
+ visibility = ["//visibility:public"],
+)
+
+pkg_npm(
+ name = "npm_module",
+ deps = [
+ ":%s" % PKG_BASE_NAME,
+ ]
+)
+
+filegroup(
+ name = "build",
+ srcs = [
+ ":npm_module",
+ ],
+ visibility = ["//visibility:public"],
+)
+
+pkg_npm_types(
+ name = "npm_module_types",
+ srcs = SRCS,
+ deps = [":tsc_types"],
+ package_name = PKG_REQUIRE_NAME,
+ tsconfig = ":tsconfig",
+ visibility = ["//visibility:public"],
+)
+
+filegroup(
+ name = "build_types",
+ srcs = [
+ ":npm_module_types",
+ ],
+ visibility = ["//visibility:public"],
+)
diff --git a/packages/kbn-generate/README.md b/packages/kbn-generate/README.md
new file mode 100644
index 000000000000..8257d61ade72
--- /dev/null
+++ b/packages/kbn-generate/README.md
@@ -0,0 +1,7 @@
+# @kbn/generate
+
+Provides a CLI for generating different components within Kibana
+
+## `node scripts/generate package`
+
+Generate a Kibana package, run `node scripts/generate package --help` for details about options.
\ No newline at end of file
diff --git a/packages/kbn-generate/jest.config.js b/packages/kbn-generate/jest.config.js
new file mode 100644
index 000000000000..b72f891cfb1a
--- /dev/null
+++ b/packages/kbn-generate/jest.config.js
@@ -0,0 +1,13 @@
+/*
+ * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
+ * or more contributor license agreements. Licensed under the Elastic License
+ * 2.0 and the Server Side Public License, v 1; you may not use this file except
+ * in compliance with, at your election, the Elastic License 2.0 or the Server
+ * Side Public License, v 1.
+ */
+
+module.exports = {
+ preset: '@kbn/test/jest_node',
+ rootDir: '../..',
+ roots: ['/packages/kbn-generate'],
+};
diff --git a/packages/kbn-generate/package.json b/packages/kbn-generate/package.json
new file mode 100644
index 000000000000..aacf8c6aab81
--- /dev/null
+++ b/packages/kbn-generate/package.json
@@ -0,0 +1,10 @@
+{
+ "name": "@kbn/generate",
+ "version": "1.0.0",
+ "private": true,
+ "license": "SSPL-1.0 OR Elastic License 2.0",
+ "main": "./target_node/index.js",
+ "kibana": {
+ "devOnly": true
+ }
+}
\ No newline at end of file
diff --git a/packages/kbn-generate/src/cli.ts b/packages/kbn-generate/src/cli.ts
new file mode 100644
index 000000000000..9ade4f68366f
--- /dev/null
+++ b/packages/kbn-generate/src/cli.ts
@@ -0,0 +1,31 @@
+/*
+ * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
+ * or more contributor license agreements. Licensed under the Elastic License
+ * 2.0 and the Server Side Public License, v 1; you may not use this file except
+ * in compliance with, at your election, the Elastic License 2.0 or the Server
+ * Side Public License, v 1.
+ */
+
+import { RunWithCommands } from '@kbn/dev-utils';
+
+import { Render } from './lib/render';
+import { ContextExtensions } from './generate_command';
+
+import { PackageCommand } from './commands/package_command';
+
+/**
+ * Runs the generate CLI. Called by `node scripts/generate` and not intended for use outside of that script
+ */
+export function runGenerateCli() {
+ new RunWithCommands(
+ {
+ description: 'Run generators for different components in Kibana',
+ extendContext(context) {
+ return {
+ render: new Render(context.log),
+ };
+ },
+ },
+ [PackageCommand]
+ ).execute();
+}
diff --git a/packages/kbn-generate/src/commands/package_command.ts b/packages/kbn-generate/src/commands/package_command.ts
new file mode 100644
index 000000000000..284b3b96a030
--- /dev/null
+++ b/packages/kbn-generate/src/commands/package_command.ts
@@ -0,0 +1,141 @@
+/*
+ * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
+ * or more contributor license agreements. Licensed under the Elastic License
+ * 2.0 and the Server Side Public License, v 1; you may not use this file except
+ * in compliance with, at your election, the Elastic License 2.0 or the Server
+ * Side Public License, v 1.
+ */
+
+import Fsp from 'fs/promises';
+import Path from 'path';
+
+import normalizePath from 'normalize-path';
+import globby from 'globby';
+
+import { REPO_ROOT } from '@kbn/utils';
+import { discoverBazelPackages, generatePackagesBuildBazelFile } from '@kbn/bazel-packages';
+import { createFailError, createFlagError, isFailError, sortPackageJson } from '@kbn/dev-utils';
+
+import { ROOT_PKG_DIR, PKG_TEMPLATE_DIR } from '../paths';
+import type { GenerateCommand } from '../generate_command';
+
+export const PackageCommand: GenerateCommand = {
+ name: 'package',
+ description: 'Generate a basic package',
+ usage: 'node scripts/generate package [name]',
+ flags: {
+ boolean: ['web', 'force', 'dev'],
+ string: ['dir'],
+ help: `
+ --dev Generate a package which is intended for dev-only use and can access things like devDependencies
+ --web Build webpack-compatible version of sources for this package. If your package is intended to be
+ used in the browser and Node.js then you need to opt-into these sources being created.
+ --dir Directory where this package will live, defaults to [./packages]
+ --force If the packageDir already exists, delete it before generation
+ `,
+ },
+ async run({ log, flags, render }) {
+ const [name] = flags._;
+ if (!name) {
+ throw createFlagError(`missing package name`);
+ }
+ if (!name.startsWith('@kbn/')) {
+ throw createFlagError(`package name must start with @kbn/`);
+ }
+
+ const typePkgName = `@types/${name.slice(1).replace('/', '__')}`;
+ const web = !!flags.web;
+ const dev = !!flags.dev;
+
+ const containingDir = flags.dir ? Path.resolve(`${flags.dir}`) : ROOT_PKG_DIR;
+ const packageDir = Path.resolve(containingDir, name.slice(1).replace('/', '-'));
+ const repoRelativeDir = normalizePath(Path.relative(REPO_ROOT, packageDir));
+
+ try {
+ await Fsp.readdir(packageDir);
+ if (!!flags.force) {
+ await Fsp.rm(packageDir, { recursive: true });
+ log.warning('deleted existing package at', packageDir);
+ } else {
+ throw createFailError(
+ `Package dir [${packageDir}] already exists, either choose a new package name, or pass --force to delete the package and regenerate it`
+ );
+ }
+ } catch (error) {
+ if (isFailError(error)) {
+ throw error;
+ }
+ }
+
+ const templateFiles = await globby('**/*', {
+ cwd: PKG_TEMPLATE_DIR,
+ absolute: false,
+ dot: true,
+ onlyFiles: true,
+ });
+
+ if (!templateFiles.length) {
+ throw new Error('unable to find package template files');
+ }
+
+ await Fsp.mkdir(packageDir, { recursive: true });
+
+ for (const rel of templateFiles) {
+ const destDir = Path.resolve(packageDir, Path.dirname(rel));
+
+ await Fsp.mkdir(destDir, { recursive: true });
+
+ if (Path.basename(rel) === '.empty') {
+ log.debug('created dir', destDir);
+ // ignore .empty files in the template, just create the directory
+ continue;
+ }
+
+ const ejs = !!rel.endsWith('.ejs');
+ const src = Path.resolve(PKG_TEMPLATE_DIR, rel);
+ const dest = Path.resolve(packageDir, ejs ? rel.slice(0, -4) : rel);
+
+ if (!ejs) {
+ // read+write rather than `Fsp.copyFile` so that permissions of bazel-out are not copied to target
+ await Fsp.writeFile(dest, await Fsp.readFile(src));
+ log.debug('copied', rel);
+ continue;
+ }
+
+ await render.toFile(src, dest, {
+ pkg: {
+ name,
+ web,
+ dev,
+ directoryName: Path.basename(repoRelativeDir),
+ repoRelativeDir,
+ },
+ });
+ }
+
+ log.info('Wrote plugin files to', packageDir);
+
+ const packageJsonPath = Path.resolve(REPO_ROOT, 'package.json');
+ const packageJson = JSON.parse(await Fsp.readFile(packageJsonPath, 'utf8'));
+
+ const [addDeps, removeDeps] = dev
+ ? [packageJson.devDependencies, packageJson.dependencies]
+ : [packageJson.dependencies, packageJson.devDependencies];
+
+ addDeps[name] = `link:bazel-bin/${repoRelativeDir}`;
+ addDeps[typePkgName] = `link:bazel-bin/${repoRelativeDir}/npm_module_types`;
+ delete removeDeps[name];
+ delete removeDeps[typePkgName];
+
+ await Fsp.writeFile(packageJsonPath, sortPackageJson(JSON.stringify(packageJson)));
+ log.info('Updated package.json file');
+
+ await Fsp.writeFile(
+ Path.resolve(REPO_ROOT, 'packages/BUILD.bazel'),
+ generatePackagesBuildBazelFile(await discoverBazelPackages())
+ );
+ log.info('Updated packages/BUILD.bazel');
+
+ log.success(`Generated ${name}! Please bootstrap to make sure it works.`);
+ },
+};
diff --git a/packages/kbn-test/src/functional_test_runner/lib/config/__fixtures__/config.3.js b/packages/kbn-generate/src/generate_command.ts
similarity index 61%
rename from packages/kbn-test/src/functional_test_runner/lib/config/__fixtures__/config.3.js
rename to packages/kbn-generate/src/generate_command.ts
index b68a5115553f..180fcee890c4 100644
--- a/packages/kbn-test/src/functional_test_runner/lib/config/__fixtures__/config.3.js
+++ b/packages/kbn-generate/src/generate_command.ts
@@ -6,12 +6,12 @@
* Side Public License, v 1.
*/
-export default async function ({ readConfigFile }) {
- const config4 = await readConfigFile(require.resolve('./config.4'));
- return {
- testFiles: ['baz'],
- screenshots: {
- ...config4.get('screenshots'),
- },
- };
+import { Command } from '@kbn/dev-utils';
+
+import { Render } from './lib/render';
+
+export interface ContextExtensions {
+ render: Render;
}
+
+export type GenerateCommand = Command;
diff --git a/packages/kbn-generate/src/index.ts b/packages/kbn-generate/src/index.ts
new file mode 100644
index 000000000000..7ee97ec9aa05
--- /dev/null
+++ b/packages/kbn-generate/src/index.ts
@@ -0,0 +1,9 @@
+/*
+ * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
+ * or more contributor license agreements. Licensed under the Elastic License
+ * 2.0 and the Server Side Public License, v 1; you may not use this file except
+ * in compliance with, at your election, the Elastic License 2.0 or the Server
+ * Side Public License, v 1.
+ */
+
+export * from './cli';
diff --git a/packages/kbn-generate/src/lib/render.ts b/packages/kbn-generate/src/lib/render.ts
new file mode 100644
index 000000000000..23595dbbe43d
--- /dev/null
+++ b/packages/kbn-generate/src/lib/render.ts
@@ -0,0 +1,85 @@
+/*
+ * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
+ * or more contributor license agreements. Licensed under the Elastic License
+ * 2.0 and the Server Side Public License, v 1; you may not use this file except
+ * in compliance with, at your election, the Elastic License 2.0 or the Server
+ * Side Public License, v 1.
+ */
+
+import Path from 'path';
+import Fsp from 'fs/promises';
+
+import Ejs from 'ejs';
+import normalizePath from 'normalize-path';
+import { ToolingLog, sortPackageJson } from '@kbn/dev-utils';
+import { REPO_ROOT } from '@kbn/utils';
+
+export type Vars = Record;
+export interface RenderContext extends Vars {
+ /**
+ * convert any serializable value into prett-printed JSON
+ */
+ json(arg: any): string;
+ /**
+ * convert string values into valid and pretty JS
+ */
+ js(arg: string): string;
+ /**
+ * create a normalized relative path from the generated files location to a repo-relative path
+ */
+ relativePathTo(rootRelativePath: string): string;
+}
+
+export class Render {
+ jsonHelper: RenderContext['json'] = (arg) => JSON.stringify(arg, null, 2);
+ jsHelper: RenderContext['js'] = (arg) => {
+ if (typeof arg !== 'string') {
+ throw new Error('js() only supports strings right now');
+ }
+
+ const hasSingle = arg.includes(`'`);
+ const hasBacktick = arg.includes('`');
+
+ if (!hasSingle) {
+ return `'${arg}'`;
+ }
+
+ if (!hasBacktick) {
+ return `\`${arg}\``;
+ }
+
+ return `'${arg.replaceAll(`'`, `\\'`)}'`;
+ };
+
+ constructor(private readonly log: ToolingLog) {}
+
+ /**
+ * Render an ejs template to a string
+ */
+ async toString(templatePath: string, destPath: string, vars: Vars) {
+ const context: RenderContext = {
+ ...vars,
+
+ // helpers
+ json: this.jsonHelper,
+ js: this.jsHelper,
+ relativePathTo: (rootRelativePath: string) =>
+ normalizePath(
+ Path.relative(Path.dirname(destPath), Path.resolve(REPO_ROOT, rootRelativePath))
+ ),
+ };
+
+ this.log.debug('Rendering', templatePath, 'with context', context);
+ const content = await Ejs.renderFile(templatePath, context);
+ return Path.basename(destPath) === 'package.json' ? sortPackageJson(content) : content;
+ }
+
+ /**
+ * Render an ejs template to a file
+ */
+ async toFile(templatePath: string, destPath: string, vars: Vars) {
+ const content = await this.toString(templatePath, destPath, vars);
+ this.log.debug('Writing to', destPath);
+ return await Fsp.writeFile(destPath, content);
+ }
+}
diff --git a/packages/kbn-generate/src/paths.ts b/packages/kbn-generate/src/paths.ts
new file mode 100644
index 000000000000..c26c82a39f8a
--- /dev/null
+++ b/packages/kbn-generate/src/paths.ts
@@ -0,0 +1,15 @@
+/*
+ * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
+ * or more contributor license agreements. Licensed under the Elastic License
+ * 2.0 and the Server Side Public License, v 1; you may not use this file except
+ * in compliance with, at your election, the Elastic License 2.0 or the Server
+ * Side Public License, v 1.
+ */
+
+import Path from 'path';
+
+import { REPO_ROOT } from '@kbn/utils';
+
+export const ROOT_PKG_DIR = Path.resolve(REPO_ROOT, 'packages');
+export const TEMPLATE_DIR = Path.resolve(__dirname, '../templates');
+export const PKG_TEMPLATE_DIR = Path.resolve(TEMPLATE_DIR, 'package');
diff --git a/packages/kbn-generate/templates/package/BUILD.bazel.ejs b/packages/kbn-generate/templates/package/BUILD.bazel.ejs
new file mode 100644
index 000000000000..1e7a198f6d9b
--- /dev/null
+++ b/packages/kbn-generate/templates/package/BUILD.bazel.ejs
@@ -0,0 +1,121 @@
+load("@npm//@bazel/typescript:index.bzl", "ts_config")
+load("@build_bazel_rules_nodejs//:index.bzl", "js_library")
+load("//src/dev/bazel:index.bzl", "jsts_transpiler", "pkg_npm", "pkg_npm_types", "ts_project")
+
+PKG_DIRNAME = <%- json(pkg.directoryName) %>
+PKG_REQUIRE_NAME = <%- json(pkg.name) %>
+
+SOURCE_FILES = glob(
+ [
+ "src/**/*.ts",
+ ],
+ exclude = [
+ "**/*.test.*",
+ ],
+)
+
+SRCS = SOURCE_FILES
+
+filegroup(
+ name = "srcs",
+ srcs = SRCS,
+)
+
+NPM_MODULE_EXTRA_FILES = [
+ "package.json",
+]
+
+# In this array place runtime dependencies, including other packages and NPM packages
+# which must be available for this code to run.
+#
+# To reference other packages use:
+# "//repo/relative/path/to/package"
+# eg. "//packages/kbn-utils"
+#
+# To reference a NPM package use:
+# "@npm//name-of-package"
+# eg. "@npm//lodash"
+RUNTIME_DEPS = [
+]
+
+# In this array place dependencies necessary to build the types, which will include the
+# :npm_module_types target of other packages and packages from NPM, including @types/*
+# packages.
+#
+# To reference the types for another package use:
+# "//repo/relative/path/to/package:npm_module_types"
+# eg. "//packages/kbn-utils:npm_module_types"
+#
+# References to NPM packages work the same as RUNTIME_DEPS
+TYPES_DEPS = [
+ "@npm//@types/node",
+ "@npm//@types/jest",
+]
+
+jsts_transpiler(
+ name = "target_node",
+ srcs = SRCS,
+ build_pkg_name = package_name(),
+)
+<% if (pkg.web) { %>
+jsts_transpiler(
+ name = "target_web",
+ srcs = SRCS,
+ build_pkg_name = package_name(),
+ web = True,
+)
+<% } %>
+ts_config(
+ name = "tsconfig",
+ src = "tsconfig.json",
+ deps = [
+ "//:tsconfig.base.json",
+ "//:tsconfig.bazel.json",
+ ],
+)
+
+ts_project(
+ name = "tsc_types",
+ args = ['--pretty'],
+ srcs = SRCS,
+ deps = TYPES_DEPS,
+ declaration = True,
+ emit_declaration_only = True,
+ out_dir = "target_types",
+ root_dir = "src",
+ tsconfig = ":tsconfig",
+)
+
+js_library(
+ name = PKG_DIRNAME,
+ srcs = NPM_MODULE_EXTRA_FILES,
+ deps = RUNTIME_DEPS + <%- pkg.web ? '[":target_node", ":target_web"]' : '[":target_node"]' %>,
+ package_name = PKG_REQUIRE_NAME,
+ visibility = ["//visibility:public"],
+)
+
+pkg_npm(
+ name = "npm_module",
+ deps = [":" + PKG_DIRNAME],
+)
+
+filegroup(
+ name = "build",
+ srcs = [":npm_module"],
+ visibility = ["//visibility:public"],
+)
+
+pkg_npm_types(
+ name = "npm_module_types",
+ srcs = SRCS,
+ deps = [":tsc_types"],
+ package_name = PKG_REQUIRE_NAME,
+ tsconfig = ":tsconfig",
+ visibility = ["//visibility:public"],
+)
+
+filegroup(
+ name = "build_types",
+ srcs = [":npm_module_types"],
+ visibility = ["//visibility:public"],
+)
diff --git a/packages/kbn-generate/templates/package/README.md.ejs b/packages/kbn-generate/templates/package/README.md.ejs
new file mode 100644
index 000000000000..769f536648a6
--- /dev/null
+++ b/packages/kbn-generate/templates/package/README.md.ejs
@@ -0,0 +1,3 @@
+# <%- pkg.name %>
+
+Empty package generated by @kbn/generate
diff --git a/packages/kbn-generate/templates/package/jest.config.js.ejs b/packages/kbn-generate/templates/package/jest.config.js.ejs
new file mode 100644
index 000000000000..1846d6a8f96f
--- /dev/null
+++ b/packages/kbn-generate/templates/package/jest.config.js.ejs
@@ -0,0 +1,5 @@
+module.exports = {
+ preset: <%- js(pkg.web ? '@kbn/test' : '@kbn/test/jest_node') %>,
+ rootDir: '../..',
+ roots: [<%- js(`/${pkg.repoRelativeDir}`) %>],
+};
diff --git a/packages/kbn-generate/templates/package/package.json.ejs b/packages/kbn-generate/templates/package/package.json.ejs
new file mode 100644
index 000000000000..93b2813daffa
--- /dev/null
+++ b/packages/kbn-generate/templates/package/package.json.ejs
@@ -0,0 +1,15 @@
+{
+ "name": <%- json(pkg.name) %>,
+ "version": "1.0.0",
+ "private": true,
+ "license": "SSPL-1.0 OR Elastic License 2.0",
+ "main": "./target_node/index.js"
+ <%_ if (pkg.web) { %>,
+ "browser": "./target_web/index.js"
+ <%_ } %>
+ <% if (pkg.dev) { %>,
+ "kibana": {
+ "devOnly": true
+ }
+ <% } %>
+}
diff --git a/packages/kbn-generate/templates/package/src/index.ts b/packages/kbn-generate/templates/package/src/index.ts
new file mode 100644
index 000000000000..7657a38ed92e
--- /dev/null
+++ b/packages/kbn-generate/templates/package/src/index.ts
@@ -0,0 +1,3 @@
+export function foo() {
+ return 'hello world';
+}
diff --git a/packages/kbn-generate/templates/package/tsconfig.json.ejs b/packages/kbn-generate/templates/package/tsconfig.json.ejs
new file mode 100644
index 000000000000..55edb60925e3
--- /dev/null
+++ b/packages/kbn-generate/templates/package/tsconfig.json.ejs
@@ -0,0 +1,17 @@
+{
+ "extends": "<%- relativePathTo("tsconfig.bazel.json") %>",
+ "compilerOptions": {
+ "declaration": true,
+ "emitDeclarationOnly": true,
+ "outDir": "target_types",
+ "rootDir": "src",
+ "stripInternal": false,
+ "types": [
+ "jest",
+ "node"
+ ]
+ },
+ "include": [
+ "src/**/*"
+ ]
+}
diff --git a/packages/kbn-generate/tsconfig.json b/packages/kbn-generate/tsconfig.json
new file mode 100644
index 000000000000..a8cfc2cceb08
--- /dev/null
+++ b/packages/kbn-generate/tsconfig.json
@@ -0,0 +1,17 @@
+{
+ "extends": "../../tsconfig.bazel.json",
+ "compilerOptions": {
+ "declaration": true,
+ "emitDeclarationOnly": true,
+ "outDir": "target_types",
+ "rootDir": "src",
+ "stripInternal": false,
+ "types": [
+ "jest",
+ "node"
+ ]
+ },
+ "include": [
+ "src/**/*"
+ ]
+}
diff --git a/packages/kbn-optimizer/BUILD.bazel b/packages/kbn-optimizer/BUILD.bazel
index 680ca0e58b8e..057e00066ddf 100644
--- a/packages/kbn-optimizer/BUILD.bazel
+++ b/packages/kbn-optimizer/BUILD.bazel
@@ -46,7 +46,6 @@ RUNTIME_DEPS = [
"@npm//dedent",
"@npm//del",
"@npm//execa",
- "@npm//jest-diff",
"@npm//json-stable-stringify",
"@npm//js-yaml",
"@npm//lmdb-store",
@@ -76,7 +75,6 @@ TYPES_DEPS = [
"@npm//cpy",
"@npm//del",
"@npm//execa",
- "@npm//jest-diff",
"@npm//lmdb-store",
"@npm//pirates",
"@npm//rxjs",
diff --git a/packages/kbn-optimizer/limits.yml b/packages/kbn-optimizer/limits.yml
index 3a999272c3a4..4df5d02e010d 100644
--- a/packages/kbn-optimizer/limits.yml
+++ b/packages/kbn-optimizer/limits.yml
@@ -41,7 +41,7 @@ pageLoadAssetSize:
monitoring: 80000
navigation: 37269
newsfeed: 42228
- observability: 89709
+ observability: 95000
painlessLab: 179748
remoteClusters: 51327
rollup: 97204
@@ -121,4 +121,6 @@ pageLoadAssetSize:
expressionPartitionVis: 26338
sharedUX: 16225
ux: 20784
+ sessionView: 77750
cloudSecurityPosture: 19109
+ visTypeGauge: 24113
\ No newline at end of file
diff --git a/packages/kbn-optimizer/package.json b/packages/kbn-optimizer/package.json
index a7d8a5092763..4d3d17c5242c 100644
--- a/packages/kbn-optimizer/package.json
+++ b/packages/kbn-optimizer/package.json
@@ -3,5 +3,8 @@
"version": "1.0.0",
"private": true,
"license": "SSPL-1.0 OR Elastic License 2.0",
- "main": "./target_node/index.js"
+ "main": "./target_node/index.js",
+ "kibana": {
+ "devOnly": true
+ }
}
\ No newline at end of file
diff --git a/packages/kbn-optimizer/src/integration_tests/__snapshots__/basic_optimization.test.ts.snap b/packages/kbn-optimizer/src/integration_tests/__snapshots__/basic_optimization.test.ts.snap
index ddcdd980153f..52a183bc04b4 100644
--- a/packages/kbn-optimizer/src/integration_tests/__snapshots__/basic_optimization.test.ts.snap
+++ b/packages/kbn-optimizer/src/integration_tests/__snapshots__/basic_optimization.test.ts.snap
@@ -214,14 +214,7 @@ exports[`prepares assets for distribution: bar bundle 1`] = `
function (e, n, t) {
\\"use strict\\";
var r,
- o = function () {
- return (
- void 0 === r &&
- (r = Boolean(window && document && document.all && !window.atob)),
- r
- );
- },
- i = (function () {
+ o = (function () {
var e = {};
return function (n) {
if (void 0 === e[n]) {
@@ -240,37 +233,37 @@ exports[`prepares assets for distribution: bar bundle 1`] = `
return e[n];
};
})(),
- a = [];
+ i = [];
function c(e) {
- for (var n = -1, t = 0; t < a.length; t++)
- if (a[t].identifier === e) {
+ for (var n = -1, t = 0; t < i.length; t++)
+ if (i[t].identifier === e) {
n = t;
break;
}
return n;
}
- function u(e, n) {
+ function a(e, n) {
for (var t = {}, r = [], o = 0; o < e.length; o++) {
- var i = e[o],
- u = n.base ? i[0] + n.base : i[0],
+ var a = e[o],
+ u = n.base ? a[0] + n.base : a[0],
s = t[u] || 0,
f = \\"\\".concat(u, \\" \\").concat(s);
t[u] = s + 1;
var l = c(f),
- d = { css: i[1], media: i[2], sourceMap: i[3] };
+ d = { css: a[1], media: a[2], sourceMap: a[3] };
-1 !== l
- ? (a[l].references++, a[l].updater(d))
- : a.push({ identifier: f, updater: h(d, n), references: 1 }),
+ ? (i[l].references++, i[l].updater(d))
+ : i.push({ identifier: f, updater: v(d, n), references: 1 }),
r.push(f);
}
return r;
}
- function s(e) {
+ function u(e) {
var n = document.createElement(\\"style\\"),
r = e.attributes || {};
if (void 0 === r.nonce) {
- var o = t.nc;
- o && (r.nonce = o);
+ var i = t.nc;
+ i && (r.nonce = i);
}
if (
(Object.keys(r).forEach(function (e) {
@@ -280,36 +273,36 @@ exports[`prepares assets for distribution: bar bundle 1`] = `
)
e.insert(n);
else {
- var a = i(e.insert || \\"head\\");
- if (!a)
+ var c = o(e.insert || \\"head\\");
+ if (!c)
throw new Error(
\\"Couldn't find a style target. This probably means that the value for the 'insert' parameter is invalid.\\"
);
- a.appendChild(n);
+ c.appendChild(n);
}
return n;
}
- var f,
- l =
- ((f = []),
+ var s,
+ f =
+ ((s = []),
function (e, n) {
- return (f[e] = n), f.filter(Boolean).join(\\"\\\\n\\");
+ return (s[e] = n), s.filter(Boolean).join(\\"\\\\n\\");
});
- function d(e, n, t, r) {
+ function l(e, n, t, r) {
var o = t
? \\"\\"
: r.media
? \\"@media \\".concat(r.media, \\" {\\").concat(r.css, \\"}\\")
: r.css;
- if (e.styleSheet) e.styleSheet.cssText = l(n, o);
+ if (e.styleSheet) e.styleSheet.cssText = f(n, o);
else {
var i = document.createTextNode(o),
- a = e.childNodes;
- a[n] && e.removeChild(a[n]),
- a.length ? e.insertBefore(i, a[n]) : e.appendChild(i);
+ c = e.childNodes;
+ c[n] && e.removeChild(c[n]),
+ c.length ? e.insertBefore(i, c[n]) : e.appendChild(i);
}
}
- function p(e, n, t) {
+ function d(e, n, t) {
var r = t.css,
o = t.media,
i = t.sourceMap;
@@ -329,18 +322,18 @@ exports[`prepares assets for distribution: bar bundle 1`] = `
e.appendChild(document.createTextNode(r));
}
}
- var v = null,
+ var p = null,
b = 0;
- function h(e, n) {
+ function v(e, n) {
var t, r, o;
if (n.singleton) {
var i = b++;
- (t = v || (v = s(n))),
- (r = d.bind(null, t, i, !1)),
- (o = d.bind(null, t, i, !0));
+ (t = p || (p = u(n))),
+ (r = l.bind(null, t, i, !1)),
+ (o = l.bind(null, t, i, !0));
} else
- (t = s(n)),
- (r = p.bind(null, t, n)),
+ (t = u(n)),
+ (r = d.bind(null, t, n)),
(o = function () {
!(function (e) {
if (null === e.parentNode) return !1;
@@ -365,8 +358,11 @@ exports[`prepares assets for distribution: bar bundle 1`] = `
e.exports = function (e, n) {
(n = n || {}).singleton ||
\\"boolean\\" == typeof n.singleton ||
- (n.singleton = o());
- var t = u((e = e || []), n);
+ (n.singleton =
+ (void 0 === r &&
+ (r = Boolean(window && document && document.all && !window.atob)),
+ r));
+ var t = a((e = e || []), n);
return function (e) {
if (
((e = e || []),
@@ -374,13 +370,13 @@ exports[`prepares assets for distribution: bar bundle 1`] = `
) {
for (var r = 0; r < t.length; r++) {
var o = c(t[r]);
- a[o].references--;
+ i[o].references--;
}
- for (var i = u(e, n), s = 0; s < t.length; s++) {
+ for (var u = a(e, n), s = 0; s < t.length; s++) {
var f = c(t[s]);
- 0 === a[f].references && (a[f].updater(), a.splice(f, 1));
+ 0 === i[f].references && (i[f].updater(), i.splice(f, 1));
}
- t = i;
+ t = u;
}
};
};
@@ -393,27 +389,29 @@ exports[`prepares assets for distribution: bar bundle 1`] = `
(n.toString = function () {
return this.map(function (n) {
var t = (function (e, n) {
- var t = e[1] || \\"\\",
- r = e[3];
- if (!r) return t;
+ var t,
+ r,
+ o,
+ i = e[1] || \\"\\",
+ c = e[3];
+ if (!c) return i;
if (n && \\"function\\" == typeof btoa) {
- var o =
- ((a = r),
- (c = btoa(unescape(encodeURIComponent(JSON.stringify(a))))),
- (u =
+ var a =
+ ((t = c),
+ (r = btoa(unescape(encodeURIComponent(JSON.stringify(t))))),
+ (o =
\\"sourceMappingURL=data:application/json;charset=utf-8;base64,\\".concat(
- c
+ r
)),
- \\"/*# \\".concat(u, \\" */\\")),
- i = r.sources.map(function (e) {
+ \\"/*# \\".concat(o, \\" */\\")),
+ u = c.sources.map(function (e) {
return \\"/*# sourceURL=\\"
- .concat(r.sourceRoot || \\"\\")
+ .concat(c.sourceRoot || \\"\\")
.concat(e, \\" */\\");
});
- return [t].concat(i).concat([o]).join(\\"\\\\n\\");
+ return [i].concat(u).concat([a]).join(\\"\\\\n\\");
}
- var a, c, u;
- return [t].join(\\"\\\\n\\");
+ return [i].join(\\"\\\\n\\");
})(n, e);
return n[2] ? \\"@media \\".concat(n[2], \\" {\\").concat(t, \\"}\\") : t;
}).join(\\"\\");
@@ -423,11 +421,11 @@ exports[`prepares assets for distribution: bar bundle 1`] = `
var o = {};
if (r)
for (var i = 0; i < this.length; i++) {
- var a = this[i][0];
- null != a && (o[a] = !0);
+ var c = this[i][0];
+ null != c && (o[c] = !0);
}
- for (var c = 0; c < e.length; c++) {
- var u = [].concat(e[c]);
+ for (var a = 0; a < e.length; a++) {
+ var u = [].concat(e[a]);
(r && o[u[0]]) ||
(t &&
(u[2]
@@ -464,9 +462,7 @@ exports[`prepares assets for distribution: bar bundle 1`] = `
o = t(7);
\\"string\\" == typeof (o = o.__esModule ? o.default : o) &&
(o = [[e.i, o, \\"\\"]]);
- var i = { insert: \\"head\\", singleton: !1 };
- r(o, i);
- e.exports = o.locals || {};
+ r(o, { insert: \\"head\\", singleton: !1 }), (e.exports = o.locals || {});
},
function (e, n, t) {
(n = t(1)(!1)).push([
@@ -481,9 +477,7 @@ exports[`prepares assets for distribution: bar bundle 1`] = `
o = t(9);
\\"string\\" == typeof (o = o.__esModule ? o.default : o) &&
(o = [[e.i, o, \\"\\"]]);
- var i = { insert: \\"head\\", singleton: !1 };
- r(o, i);
- e.exports = o.locals || {};
+ r(o, { insert: \\"head\\", singleton: !1 }), (e.exports = o.locals || {});
},
function (e, n, t) {
(n = t(1)(!1)).push([
@@ -506,9 +500,7 @@ exports[`prepares assets for distribution: bar bundle 1`] = `
o = t(12);
\\"string\\" == typeof (o = o.__esModule ? o.default : o) &&
(o = [[e.i, o, \\"\\"]]);
- var i = { insert: \\"head\\", singleton: !1 };
- r(o, i);
- e.exports = o.locals || {};
+ r(o, { insert: \\"head\\", singleton: !1 }), (e.exports = o.locals || {});
},
function (e, n, t) {
(n = t(1)(!1)).push([e.i, \\"body{color:green}\\\\n\\", \\"\\"]), (e.exports = n);
@@ -518,9 +510,7 @@ exports[`prepares assets for distribution: bar bundle 1`] = `
o = t(14);
\\"string\\" == typeof (o = o.__esModule ? o.default : o) &&
(o = [[e.i, o, \\"\\"]]);
- var i = { insert: \\"head\\", singleton: !1 };
- r(o, i);
- e.exports = o.locals || {};
+ r(o, { insert: \\"head\\", singleton: !1 }), (e.exports = o.locals || {});
},
function (e, n, t) {
(n = t(1)(!1)).push([e.i, \\"body{color:green}\\\\n\\", \\"\\"]), (e.exports = n);
@@ -533,8 +523,9 @@ exports[`prepares assets for distribution: bar bundle 1`] = `
}),
t.d(n, \\"fooLibFn\\", function () {
return r.fooLibFn;
- });
- t(5), t(10);
+ }),
+ t(5),
+ t(10);
var r = t(2);
function o() {
return \\"bar\\";
diff --git a/packages/kbn-optimizer/src/log_optimizer_state.ts b/packages/kbn-optimizer/src/log_optimizer_state.ts
index 517e3bbfa513..060f05a445eb 100644
--- a/packages/kbn-optimizer/src/log_optimizer_state.ts
+++ b/packages/kbn-optimizer/src/log_optimizer_state.ts
@@ -95,16 +95,16 @@ export function logOptimizerState(log: ToolingLog, config: OptimizerConfig) {
if (state.phase === 'issue') {
log.error(`webpack compile errors`);
- log.indent(4);
- for (const b of state.compilerStates) {
- if (b.type === 'compiler issue') {
- log.error(`[${b.bundleId}] build`);
- log.indent(4);
- log.error(b.failure);
- log.indent(-4);
+ log.indent(4, () => {
+ for (const b of state.compilerStates) {
+ if (b.type === 'compiler issue') {
+ log.error(`[${b.bundleId}] build`);
+ log.indent(4, () => {
+ log.error(b.failure);
+ });
+ }
}
- }
- log.indent(-4);
+ });
return;
}
diff --git a/packages/kbn-optimizer/src/optimizer/cache_keys.test.ts b/packages/kbn-optimizer/src/optimizer/cache_keys.test.ts
index 335a4fd7f74c..728736284947 100644
--- a/packages/kbn-optimizer/src/optimizer/cache_keys.test.ts
+++ b/packages/kbn-optimizer/src/optimizer/cache_keys.test.ts
@@ -8,11 +8,10 @@
import Path from 'path';
-import jestDiff from 'jest-diff';
import { REPO_ROOT } from '@kbn/utils';
import { createAbsolutePathSerializer } from '@kbn/dev-utils';
-import { reformatJestDiff, getOptimizerCacheKey, diffCacheKey } from './cache_keys';
+import { getOptimizerCacheKey } from './cache_keys';
import { OptimizerConfig } from './optimizer_config';
jest.mock('./get_changes.ts', () => ({
@@ -101,98 +100,3 @@ describe('getOptimizerCacheKey()', () => {
`);
});
});
-
-describe('diffCacheKey()', () => {
- it('returns undefined if values are equal', () => {
- expect(diffCacheKey('1', '1')).toBe(undefined);
- expect(diffCacheKey(1, 1)).toBe(undefined);
- expect(diffCacheKey(['1', '2', { a: 'b' }], ['1', '2', { a: 'b' }])).toBe(undefined);
- expect(
- diffCacheKey(
- {
- a: '1',
- b: '2',
- },
- {
- b: '2',
- a: '1',
- }
- )
- ).toBe(undefined);
- });
-
- it('returns a diff if the values are different', () => {
- expect(diffCacheKey(['1', '2', { a: 'b' }], ['1', '2', { b: 'a' }])).toMatchInlineSnapshot(`
- "[32m- Expected[39m
- [31m+ Received[39m
-
- [2m [[22m
- [2m \\"1\\",[22m
- [2m \\"2\\",[22m
- [2m {[22m
- [32m- \\"a\\": \\"b\\"[39m
- [31m+ \\"b\\": \\"a\\"[39m
- [2m }[22m
- [2m ][22m"
- `);
- expect(
- diffCacheKey(
- {
- a: '1',
- b: '1',
- },
- {
- b: '2',
- a: '2',
- }
- )
- ).toMatchInlineSnapshot(`
- "[32m- Expected[39m
- [31m+ Received[39m
-
- [2m {[22m
- [32m- \\"a\\": \\"1\\",[39m
- [32m- \\"b\\": \\"1\\"[39m
- [31m+ \\"a\\": \\"2\\",[39m
- [31m+ \\"b\\": \\"2\\"[39m
- [2m }[22m"
- `);
- });
-});
-
-describe('reformatJestDiff()', () => {
- it('reformats large jestDiff output to focus on the changed lines', () => {
- const diff = jestDiff(
- {
- a: ['1', '1', '1', '1', '1', '1', '1', '2', '1', '1', '1', '1', '1', '1', '1', '1', '1'],
- },
- {
- b: ['1', '1', '1', '1', '1', '1', '1', '1', '1', '1', '1', '1', '2', '1', '1', '1', '1'],
- }
- );
-
- expect(reformatJestDiff(diff)).toMatchInlineSnapshot(`
- "[32m- Expected[39m
- [31m+ Received[39m
-
- [2m Object {[22m
- [32m- \\"a\\": Array [[39m
- [31m+ \\"b\\": Array [[39m
- [2m \\"1\\",[22m
- [2m \\"1\\",[22m
- [2m ...[22m
- [2m \\"1\\",[22m
- [2m \\"1\\",[22m
- [32m- \\"2\\",[39m
- [2m \\"1\\",[22m
- [2m \\"1\\",[22m
- [2m ...[22m
- [2m \\"1\\",[22m
- [2m \\"1\\",[22m
- [31m+ \\"2\\",[39m
- [2m \\"1\\",[22m
- [2m \\"1\\",[22m
- [2m ...[22m"
- `);
- });
-});
diff --git a/packages/kbn-optimizer/src/optimizer/cache_keys.ts b/packages/kbn-optimizer/src/optimizer/cache_keys.ts
index da06b76327a8..a30dbe27dff0 100644
--- a/packages/kbn-optimizer/src/optimizer/cache_keys.ts
+++ b/packages/kbn-optimizer/src/optimizer/cache_keys.ts
@@ -9,12 +9,10 @@
import Path from 'path';
import Fs from 'fs';
-import Chalk from 'chalk';
import execa from 'execa';
import { REPO_ROOT } from '@kbn/utils';
-import stripAnsi from 'strip-ansi';
+import { diffStrings } from '@kbn/dev-utils';
-import jestDiff from 'jest-diff';
import jsonStable from 'json-stable-stringify';
import { ascending, CacheableWorkerConfig } from '../common';
@@ -36,78 +34,7 @@ export function diffCacheKey(expected?: unknown, actual?: unknown) {
return;
}
- return reformatJestDiff(jestDiff(expectedJson, actualJson));
-}
-
-export function reformatJestDiff(diff: string | null) {
- const diffLines = diff?.split('\n') || [];
-
- if (
- diffLines.length < 4 ||
- stripAnsi(diffLines[0]) !== '- Expected' ||
- stripAnsi(diffLines[1]) !== '+ Received'
- ) {
- throw new Error(`unexpected diff format: ${diff}`);
- }
-
- const outputLines = [diffLines.shift(), diffLines.shift(), diffLines.shift()];
-
- /**
- * buffer which contains between 0 and 5 lines from the diff which aren't additions or
- * deletions. The first three are the first three lines seen since the buffer was cleared
- * and the last two lines are the last two lines seen.
- *
- * When flushContext() is called we write the first two lines to output, an elipses if there
- * are five lines, and then the last two lines.
- *
- * At the very end we will write the last two lines of context if they're defined
- */
- const contextBuffer: string[] = [];
-
- /**
- * Convert a line to an empty line with elipses placed where the text on that line starts
- */
- const toElipses = (line: string) => {
- return stripAnsi(line).replace(/^(\s*).*/, '$1...');
- };
-
- while (diffLines.length) {
- const line = diffLines.shift()!;
- const plainLine = stripAnsi(line);
- if (plainLine.startsWith('+ ') || plainLine.startsWith('- ')) {
- // write contextBuffer to the outputLines
- if (contextBuffer.length) {
- outputLines.push(
- ...contextBuffer.slice(0, 2),
- ...(contextBuffer.length === 5
- ? [Chalk.dim(toElipses(contextBuffer[2])), ...contextBuffer.slice(3, 5)]
- : contextBuffer.slice(2, 4))
- );
-
- contextBuffer.length = 0;
- }
-
- // add this line to the outputLines
- outputLines.push(line);
- } else {
- // update the contextBuffer with this line which doesn't represent a change
- if (contextBuffer.length === 5) {
- contextBuffer[3] = contextBuffer[4];
- contextBuffer[4] = line;
- } else {
- contextBuffer.push(line);
- }
- }
- }
-
- if (contextBuffer.length) {
- outputLines.push(
- ...contextBuffer.slice(0, 2),
- ...(contextBuffer.length > 2 ? [Chalk.dim(toElipses(contextBuffer[2]))] : [])
- );
- }
-
- return outputLines.join('\n');
+ return diffStrings(expectedJson, actualJson);
}
export interface OptimizerCacheKey {
diff --git a/packages/kbn-optimizer/src/worker/webpack.config.ts b/packages/kbn-optimizer/src/worker/webpack.config.ts
index 9454456a35c9..fe4b04548244 100644
--- a/packages/kbn-optimizer/src/worker/webpack.config.ts
+++ b/packages/kbn-optimizer/src/worker/webpack.config.ts
@@ -266,6 +266,9 @@ export function getWebpackConfig(bundle: Bundle, bundleRefs: BundleRefs, worker:
filename: '[path].br',
test: /\.(js|css)$/,
cache: false,
+ compressionOptions: {
+ level: 11,
+ },
}),
new CompressionPlugin({
algorithm: 'gzip',
@@ -283,7 +286,7 @@ export function getWebpackConfig(bundle: Bundle, bundleRefs: BundleRefs, worker:
extractComments: false,
parallel: false,
terserOptions: {
- compress: true,
+ compress: { passes: 2 },
keep_classnames: true,
mangle: true,
},
diff --git a/packages/kbn-plugin-generator/package.json b/packages/kbn-plugin-generator/package.json
index 28b7e849ab3c..0b6c11709b90 100644
--- a/packages/kbn-plugin-generator/package.json
+++ b/packages/kbn-plugin-generator/package.json
@@ -3,5 +3,8 @@
"version": "1.0.0",
"private": true,
"license": "SSPL-1.0 OR Elastic License 2.0",
- "main": "target_node/index.js"
+ "main": "target_node/index.js",
+ "kibana": {
+ "devOnly": true
+ }
}
\ No newline at end of file
diff --git a/packages/kbn-plugin-helpers/src/integration_tests/build.test.ts b/packages/kbn-plugin-helpers/src/integration_tests/build.test.ts
index 71a3fbe60371..2d7664aa1332 100644
--- a/packages/kbn-plugin-helpers/src/integration_tests/build.test.ts
+++ b/packages/kbn-plugin-helpers/src/integration_tests/build.test.ts
@@ -43,8 +43,14 @@ it('builds a generated plugin into a viable archive', async () => {
all: true,
}
);
+ const filterLogs = (logs: string | undefined) => {
+ return logs
+ ?.split('\n')
+ .filter((l) => !l.includes('failed to reach ci-stats service'))
+ .join('\n');
+ };
- expect(generateProc.all).toMatchInlineSnapshot(`
+ expect(filterLogs(generateProc.all)).toMatchInlineSnapshot(`
" succ 🎉
Your plugin has been created in plugins/foo_test_plugin
@@ -60,12 +66,7 @@ it('builds a generated plugin into a viable archive', async () => {
}
);
- expect(
- buildProc.all
- ?.split('\n')
- .filter((l) => !l.includes('failed to reach ci-stats service'))
- .join('\n')
- ).toMatchInlineSnapshot(`
+ expect(filterLogs(buildProc.all)).toMatchInlineSnapshot(`
" info deleting the build and target directories
info running @kbn/optimizer
│ info initialized, 0 bundles cached
diff --git a/packages/kbn-plugin-helpers/src/tasks/optimize.ts b/packages/kbn-plugin-helpers/src/tasks/optimize.ts
index c0f984eb03fc..ee05fa3d3354 100644
--- a/packages/kbn-plugin-helpers/src/tasks/optimize.ts
+++ b/packages/kbn-plugin-helpers/src/tasks/optimize.ts
@@ -23,26 +23,25 @@ export async function optimize({ log, plugin, sourceDir, buildDir }: BuildContex
}
log.info('running @kbn/optimizer');
- log.indent(2);
-
- // build bundles into target
- const config = OptimizerConfig.create({
- repoRoot: REPO_ROOT,
- pluginPaths: [sourceDir],
- cache: false,
- dist: true,
- filter: [plugin.manifest.id],
+ await log.indent(2, async () => {
+ // build bundles into target
+ const config = OptimizerConfig.create({
+ repoRoot: REPO_ROOT,
+ pluginPaths: [sourceDir],
+ cache: false,
+ dist: true,
+ filter: [plugin.manifest.id],
+ });
+
+ const target = Path.resolve(sourceDir, 'target');
+
+ await runOptimizer(config).pipe(logOptimizerState(log, config)).toPromise();
+
+ // clean up unnecessary files
+ Fs.unlinkSync(Path.resolve(target, 'public/metrics.json'));
+ Fs.unlinkSync(Path.resolve(target, 'public/.kbn-optimizer-cache'));
+
+ // move target into buildDir
+ await asyncRename(target, Path.resolve(buildDir, 'target'));
});
-
- const target = Path.resolve(sourceDir, 'target');
-
- await runOptimizer(config).pipe(logOptimizerState(log, config)).toPromise();
-
- // clean up unnecessary files
- Fs.unlinkSync(Path.resolve(target, 'public/metrics.json'));
- Fs.unlinkSync(Path.resolve(target, 'public/.kbn-optimizer-cache'));
-
- // move target into buildDir
- await asyncRename(target, Path.resolve(buildDir, 'target'));
- log.indent(-2);
}
diff --git a/packages/kbn-pm/dist/index.js b/packages/kbn-pm/dist/index.js
index 647d42181959..6c64d0bd2ca0 100644
--- a/packages/kbn-pm/dist/index.js
+++ b/packages/kbn-pm/dist/index.js
@@ -8817,12 +8817,11 @@ exports.ToolingLogCollectingWriter = ToolingLogCollectingWriter;
__webpack_require__.r(__webpack_exports__);
/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "commands", function() { return commands; });
/* harmony import */ var _bootstrap__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(130);
-/* harmony import */ var _build__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(528);
-/* harmony import */ var _clean__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(529);
-/* harmony import */ var _reset__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(553);
-/* harmony import */ var _run__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(554);
-/* harmony import */ var _watch__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__(556);
-/* harmony import */ var _patch_native_modules__WEBPACK_IMPORTED_MODULE_6__ = __webpack_require__(557);
+/* harmony import */ var _build__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(529);
+/* harmony import */ var _clean__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(530);
+/* harmony import */ var _reset__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(554);
+/* harmony import */ var _run__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(555);
+/* harmony import */ var _watch__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__(557);
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License
@@ -8836,15 +8835,13 @@ __webpack_require__.r(__webpack_exports__);
-
const commands = {
bootstrap: _bootstrap__WEBPACK_IMPORTED_MODULE_0__["BootstrapCommand"],
build: _build__WEBPACK_IMPORTED_MODULE_1__["BuildCommand"],
clean: _clean__WEBPACK_IMPORTED_MODULE_2__["CleanCommand"],
reset: _reset__WEBPACK_IMPORTED_MODULE_3__["ResetCommand"],
run: _run__WEBPACK_IMPORTED_MODULE_4__["RunCommand"],
- watch: _watch__WEBPACK_IMPORTED_MODULE_5__["WatchCommand"],
- patch_native_modules: _patch_native_modules__WEBPACK_IMPORTED_MODULE_6__["PatchNativeModulesCommand"]
+ watch: _watch__WEBPACK_IMPORTED_MODULE_5__["WatchCommand"]
};
/***/ }),
@@ -8864,9 +8861,9 @@ __webpack_require__.r(__webpack_exports__);
/* harmony import */ var _utils_projects__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__(340);
/* harmony import */ var _utils_yarn_lock__WEBPACK_IMPORTED_MODULE_6__ = __webpack_require__(408);
/* harmony import */ var _utils_sort_package_json__WEBPACK_IMPORTED_MODULE_7__ = __webpack_require__(411);
-/* harmony import */ var _utils_validate_dependencies__WEBPACK_IMPORTED_MODULE_8__ = __webpack_require__(419);
-/* harmony import */ var _utils_bazel__WEBPACK_IMPORTED_MODULE_9__ = __webpack_require__(421);
-/* harmony import */ var _utils_bazel_setup_remote_cache__WEBPACK_IMPORTED_MODULE_10__ = __webpack_require__(527);
+/* harmony import */ var _utils_validate_dependencies__WEBPACK_IMPORTED_MODULE_8__ = __webpack_require__(420);
+/* harmony import */ var _utils_bazel__WEBPACK_IMPORTED_MODULE_9__ = __webpack_require__(422);
+/* harmony import */ var _utils_bazel_setup_remote_cache__WEBPACK_IMPORTED_MODULE_10__ = __webpack_require__(528);
function ownKeys(object, enumerableOnly) { var keys = Object.keys(object); if (Object.getOwnPropertySymbols) { var symbols = Object.getOwnPropertySymbols(object); enumerableOnly && (symbols = symbols.filter(function (sym) { return Object.getOwnPropertyDescriptor(object, sym).enumerable; })), keys.push.apply(keys, symbols); } return keys; }
function _objectSpread(target) { for (var i = 1; i < arguments.length; i++) { var source = null != arguments[i] ? arguments[i] : {}; i % 2 ? ownKeys(Object(source), !0).forEach(function (key) { _defineProperty(target, key, source[key]); }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(target, Object.getOwnPropertyDescriptors(source)) : ownKeys(Object(source)).forEach(function (key) { Object.defineProperty(target, key, Object.getOwnPropertyDescriptor(source, key)); }); } return target; }
@@ -8911,10 +8908,24 @@ const BootstrapCommand = {
const kibanaProjectPath = ((_projects$get = projects.get('kibana')) === null || _projects$get === void 0 ? void 0 : _projects$get.path) || '';
const runOffline = (options === null || options === void 0 ? void 0 : options.offline) === true;
const reporter = _kbn_dev_utils_ci_stats_reporter__WEBPACK_IMPORTED_MODULE_1__["CiStatsReporter"].fromEnv(_utils_log__WEBPACK_IMPORTED_MODULE_2__["log"]);
- const timings = []; // Force install is set in case a flag is passed or
+ const timings = [];
+
+ const time = async (id, body) => {
+ const start = Date.now();
+
+ try {
+ return await body();
+ } finally {
+ timings.push({
+ id,
+ ms: Date.now() - start
+ });
+ }
+ }; // Force install is set in case a flag is passed or
// if the `.yarn-integrity` file is not found which
// will be indicated by the return of yarnIntegrityFileExists.
+
const forceInstall = !!options && options['force-install'] === true || !(await Object(_utils_bazel__WEBPACK_IMPORTED_MODULE_9__["yarnIntegrityFileExists"])(Object(path__WEBPACK_IMPORTED_MODULE_0__["resolve"])(kibanaProjectPath, 'node_modules'))); // Ensure we have a `node_modules/.yarn-integrity` file as we depend on it
// for bazel to know it has to re-install the node_modules after a reset or a clean
@@ -8933,20 +8944,14 @@ const BootstrapCommand = {
//
if (forceInstall) {
- const forceInstallStartTime = Date.now();
- await Object(_utils_bazel__WEBPACK_IMPORTED_MODULE_9__["runBazel"])(['run', '@nodejs//:yarn'], runOffline);
- timings.push({
- id: 'force install dependencies',
- ms: Date.now() - forceInstallStartTime
+ await time('force install dependencies', async () => {
+ await Object(_utils_bazel__WEBPACK_IMPORTED_MODULE_9__["runBazel"])(['run', '@nodejs//:yarn'], runOffline);
});
} // build packages
- const packageStartTime = Date.now();
- await Object(_utils_bazel__WEBPACK_IMPORTED_MODULE_9__["runBazel"])(['build', '//packages:build', '--show_result=1'], runOffline);
- timings.push({
- id: 'build packages',
- ms: Date.now() - packageStartTime
+ await time('build packages', async () => {
+ await Object(_utils_bazel__WEBPACK_IMPORTED_MODULE_9__["runBazel"])(['build', '//packages:build', '--show_result=1'], runOffline);
}); // Install monorepo npm dependencies outside of the Bazel managed ones
for (const batch of batchedNonBazelProjects) {
@@ -8968,25 +8973,33 @@ const BootstrapCommand = {
}
}
- await Object(_utils_sort_package_json__WEBPACK_IMPORTED_MODULE_7__["sortPackageJson"])(kbn);
- const yarnLock = await Object(_utils_yarn_lock__WEBPACK_IMPORTED_MODULE_6__["readYarnLock"])(kbn);
+ await time('sort package json', async () => {
+ await Object(_utils_sort_package_json__WEBPACK_IMPORTED_MODULE_7__["sortPackageJson"])(kbn);
+ });
+ const yarnLock = await time('read yarn.lock', async () => await Object(_utils_yarn_lock__WEBPACK_IMPORTED_MODULE_6__["readYarnLock"])(kbn));
if (options.validate) {
- await Object(_utils_validate_dependencies__WEBPACK_IMPORTED_MODULE_8__["validateDependencies"])(kbn, yarnLock);
+ await time('validate dependencies', async () => {
+ await Object(_utils_validate_dependencies__WEBPACK_IMPORTED_MODULE_8__["validateDependencies"])(kbn, yarnLock);
+ });
} // Assure all kbn projects with bin defined scripts
// copy those scripts into the top level node_modules folder
//
// NOTE: We don't probably need this anymore, is actually not being used
- await Object(_utils_link_project_executables__WEBPACK_IMPORTED_MODULE_4__["linkProjectExecutables"])(projects, projectGraph); // Update vscode settings
-
- await Object(_utils_child_process__WEBPACK_IMPORTED_MODULE_3__["spawnStreaming"])(process.execPath, ['scripts/update_vscode_config'], {
- cwd: kbn.getAbsolute(),
- env: process.env
- }, {
- prefix: '[vscode]',
- debug: false
+ await time('link project executables', async () => {
+ await Object(_utils_link_project_executables__WEBPACK_IMPORTED_MODULE_4__["linkProjectExecutables"])(projects, projectGraph);
+ });
+ await time('update vscode config', async () => {
+ // Update vscode settings
+ await Object(_utils_child_process__WEBPACK_IMPORTED_MODULE_3__["spawnStreaming"])(process.execPath, ['scripts/update_vscode_config'], {
+ cwd: kbn.getAbsolute(),
+ env: process.env
+ }, {
+ prefix: '[vscode]',
+ debug: false
+ });
}); // send timings
await reporter.timings({
@@ -19770,10 +19783,10 @@ exports.realpath = function realpath(p, cache, cb) {
module.exports = minimatch
minimatch.Minimatch = Minimatch
-var path = { sep: '/' }
-try {
- path = __webpack_require__(4)
-} catch (er) {}
+var path = (function () { try { return __webpack_require__(4) } catch (e) {}}()) || {
+ sep: '/'
+}
+minimatch.sep = path.sep
var GLOBSTAR = minimatch.GLOBSTAR = Minimatch.GLOBSTAR = {}
var expand = __webpack_require__(248)
@@ -19825,43 +19838,64 @@ function filter (pattern, options) {
}
function ext (a, b) {
- a = a || {}
b = b || {}
var t = {}
- Object.keys(b).forEach(function (k) {
- t[k] = b[k]
- })
Object.keys(a).forEach(function (k) {
t[k] = a[k]
})
+ Object.keys(b).forEach(function (k) {
+ t[k] = b[k]
+ })
return t
}
minimatch.defaults = function (def) {
- if (!def || !Object.keys(def).length) return minimatch
+ if (!def || typeof def !== 'object' || !Object.keys(def).length) {
+ return minimatch
+ }
var orig = minimatch
var m = function minimatch (p, pattern, options) {
- return orig.minimatch(p, pattern, ext(def, options))
+ return orig(p, pattern, ext(def, options))
}
m.Minimatch = function Minimatch (pattern, options) {
return new orig.Minimatch(pattern, ext(def, options))
}
+ m.Minimatch.defaults = function defaults (options) {
+ return orig.defaults(ext(def, options)).Minimatch
+ }
+
+ m.filter = function filter (pattern, options) {
+ return orig.filter(pattern, ext(def, options))
+ }
+
+ m.defaults = function defaults (options) {
+ return orig.defaults(ext(def, options))
+ }
+
+ m.makeRe = function makeRe (pattern, options) {
+ return orig.makeRe(pattern, ext(def, options))
+ }
+
+ m.braceExpand = function braceExpand (pattern, options) {
+ return orig.braceExpand(pattern, ext(def, options))
+ }
+
+ m.match = function (list, pattern, options) {
+ return orig.match(list, pattern, ext(def, options))
+ }
return m
}
Minimatch.defaults = function (def) {
- if (!def || !Object.keys(def).length) return Minimatch
return minimatch.defaults(def).Minimatch
}
function minimatch (p, pattern, options) {
- if (typeof pattern !== 'string') {
- throw new TypeError('glob pattern string required')
- }
+ assertValidPattern(pattern)
if (!options) options = {}
@@ -19870,9 +19904,6 @@ function minimatch (p, pattern, options) {
return false
}
- // "" only matches ""
- if (pattern.trim() === '') return p === ''
-
return new Minimatch(pattern, options).match(p)
}
@@ -19881,15 +19912,14 @@ function Minimatch (pattern, options) {
return new Minimatch(pattern, options)
}
- if (typeof pattern !== 'string') {
- throw new TypeError('glob pattern string required')
- }
+ assertValidPattern(pattern)
if (!options) options = {}
+
pattern = pattern.trim()
// windows support: need to use /, not \
- if (path.sep !== '/') {
+ if (!options.allowWindowsEscape && path.sep !== '/') {
pattern = pattern.split(path.sep).join('/')
}
@@ -19900,6 +19930,7 @@ function Minimatch (pattern, options) {
this.negate = false
this.comment = false
this.empty = false
+ this.partial = !!options.partial
// make the set of regexps etc.
this.make()
@@ -19909,9 +19940,6 @@ Minimatch.prototype.debug = function () {}
Minimatch.prototype.make = make
function make () {
- // don't do it more than once.
- if (this._made) return
-
var pattern = this.pattern
var options = this.options
@@ -19931,7 +19959,7 @@ function make () {
// step 2: expand braces
var set = this.globSet = this.braceExpand()
- if (options.debug) this.debug = console.error
+ if (options.debug) this.debug = function debug() { console.error.apply(console, arguments) }
this.debug(this.pattern, set)
@@ -20011,12 +20039,11 @@ function braceExpand (pattern, options) {
pattern = typeof pattern === 'undefined'
? this.pattern : pattern
- if (typeof pattern === 'undefined') {
- throw new TypeError('undefined pattern')
- }
+ assertValidPattern(pattern)
- if (options.nobrace ||
- !pattern.match(/\{.*\}/)) {
+ // Thanks to Yeting Li for
+ // improving this regexp to avoid a ReDOS vulnerability.
+ if (options.nobrace || !/\{(?:(?!\{).)*\}/.test(pattern)) {
// shortcut. no need to expand.
return [pattern]
}
@@ -20024,6 +20051,17 @@ function braceExpand (pattern, options) {
return expand(pattern)
}
+var MAX_PATTERN_LENGTH = 1024 * 64
+var assertValidPattern = function (pattern) {
+ if (typeof pattern !== 'string') {
+ throw new TypeError('invalid pattern')
+ }
+
+ if (pattern.length > MAX_PATTERN_LENGTH) {
+ throw new TypeError('pattern is too long')
+ }
+}
+
// parse a component of the expanded set.
// At this point, no pattern may contain "/" in it
// so we're going to return a 2d array, where each entry is the full
@@ -20038,14 +20076,17 @@ function braceExpand (pattern, options) {
Minimatch.prototype.parse = parse
var SUBPARSE = {}
function parse (pattern, isSub) {
- if (pattern.length > 1024 * 64) {
- throw new TypeError('pattern is too long')
- }
+ assertValidPattern(pattern)
var options = this.options
// shortcuts
- if (!options.noglobstar && pattern === '**') return GLOBSTAR
+ if (pattern === '**') {
+ if (!options.noglobstar)
+ return GLOBSTAR
+ else
+ pattern = '*'
+ }
if (pattern === '') return ''
var re = ''
@@ -20101,10 +20142,12 @@ function parse (pattern, isSub) {
}
switch (c) {
- case '/':
+ /* istanbul ignore next */
+ case '/': {
// completely not allowed, even escaped.
// Should already be path-split by now.
return false
+ }
case '\\':
clearStateChar()
@@ -20223,25 +20266,23 @@ function parse (pattern, isSub) {
// handle the case where we left a class open.
// "[z-a]" is valid, equivalent to "\[z-a\]"
- if (inClass) {
- // split where the last [ was, make sure we don't have
- // an invalid re. if so, re-walk the contents of the
- // would-be class to re-translate any characters that
- // were passed through as-is
- // TODO: It would probably be faster to determine this
- // without a try/catch and a new RegExp, but it's tricky
- // to do safely. For now, this is safe and works.
- var cs = pattern.substring(classStart + 1, i)
- try {
- RegExp('[' + cs + ']')
- } catch (er) {
- // not a valid class!
- var sp = this.parse(cs, SUBPARSE)
- re = re.substr(0, reClassStart) + '\\[' + sp[0] + '\\]'
- hasMagic = hasMagic || sp[1]
- inClass = false
- continue
- }
+ // split where the last [ was, make sure we don't have
+ // an invalid re. if so, re-walk the contents of the
+ // would-be class to re-translate any characters that
+ // were passed through as-is
+ // TODO: It would probably be faster to determine this
+ // without a try/catch and a new RegExp, but it's tricky
+ // to do safely. For now, this is safe and works.
+ var cs = pattern.substring(classStart + 1, i)
+ try {
+ RegExp('[' + cs + ']')
+ } catch (er) {
+ // not a valid class!
+ var sp = this.parse(cs, SUBPARSE)
+ re = re.substr(0, reClassStart) + '\\[' + sp[0] + '\\]'
+ hasMagic = hasMagic || sp[1]
+ inClass = false
+ continue
}
// finish up the class.
@@ -20325,9 +20366,7 @@ function parse (pattern, isSub) {
// something that could conceivably capture a dot
var addPatternStart = false
switch (re.charAt(0)) {
- case '.':
- case '[':
- case '(': addPatternStart = true
+ case '[': case '.': case '(': addPatternStart = true
}
// Hack to work around lack of negative lookbehind in JS
@@ -20389,7 +20428,7 @@ function parse (pattern, isSub) {
var flags = options.nocase ? 'i' : ''
try {
var regExp = new RegExp('^' + re + '$', flags)
- } catch (er) {
+ } catch (er) /* istanbul ignore next - should be impossible */ {
// If it was an invalid regular expression, then it can't match
// anything. This trick looks for a character after the end of
// the string, which is of course impossible, except in multi-line
@@ -20447,7 +20486,7 @@ function makeRe () {
try {
this.regexp = new RegExp(re, flags)
- } catch (ex) {
+ } catch (ex) /* istanbul ignore next - should be impossible */ {
this.regexp = false
}
return this.regexp
@@ -20465,8 +20504,8 @@ minimatch.match = function (list, pattern, options) {
return list
}
-Minimatch.prototype.match = match
-function match (f, partial) {
+Minimatch.prototype.match = function match (f, partial) {
+ if (typeof partial === 'undefined') partial = this.partial
this.debug('match', f, this.pattern)
// short-circuit in the case of busted things.
// comments, etc.
@@ -20548,6 +20587,7 @@ Minimatch.prototype.matchOne = function (file, pattern, partial) {
// should be impossible.
// some invalid regexp stuff in the set.
+ /* istanbul ignore if */
if (p === false) return false
if (p === GLOBSTAR) {
@@ -20621,6 +20661,7 @@ Minimatch.prototype.matchOne = function (file, pattern, partial) {
// no match was found.
// However, in partial mode, we can't say this is necessarily over.
// If there's more *pattern* left, then
+ /* istanbul ignore if */
if (partial) {
// ran out of file
this.debug('\n>>> no match, partial?', file, fr, pattern, pr)
@@ -20634,11 +20675,7 @@ Minimatch.prototype.matchOne = function (file, pattern, partial) {
// patterns with magic have been turned into regexps.
var hit
if (typeof p === 'string') {
- if (options.nocase) {
- hit = f.toLowerCase() === p.toLowerCase()
- } else {
- hit = f === p
- }
+ hit = f === p
this.debug('string match', p, f, hit)
} else {
hit = f.match(p)
@@ -20669,16 +20706,16 @@ Minimatch.prototype.matchOne = function (file, pattern, partial) {
// this is ok if we're doing the match as part of
// a glob fs traversal.
return partial
- } else if (pi === pl) {
+ } else /* istanbul ignore else */ if (pi === pl) {
// ran out of pattern, still have file left.
// this is only acceptable if we're on the very last
// empty segment of a file with a trailing slash.
// a/* should match a/b/
- var emptyFileEnd = (fi === fl - 1) && (file[fi] === '')
- return emptyFileEnd
+ return (fi === fl - 1) && (file[fi] === '')
}
// should be unreachable.
+ /* istanbul ignore next */
throw new Error('wtf?')
}
@@ -31422,7 +31459,7 @@ function getChalk(options) {
}
function highlight(code, options = {}) {
- if (shouldHighlight(options)) {
+ if (code !== "" && shouldHighlight(options)) {
const chalk = getChalk(options);
const defs = getDefs(chalk);
return highlightTokens(defs, code);
@@ -31470,16 +31507,16 @@ exports.matchToToken = function(match) {
Object.defineProperty(exports, "__esModule", {
value: true
});
-Object.defineProperty(exports, "isIdentifierName", {
+Object.defineProperty(exports, "isIdentifierChar", {
enumerable: true,
get: function () {
- return _identifier.isIdentifierName;
+ return _identifier.isIdentifierChar;
}
});
-Object.defineProperty(exports, "isIdentifierChar", {
+Object.defineProperty(exports, "isIdentifierName", {
enumerable: true,
get: function () {
- return _identifier.isIdentifierChar;
+ return _identifier.isIdentifierName;
}
});
Object.defineProperty(exports, "isIdentifierStart", {
@@ -31488,6 +31525,12 @@ Object.defineProperty(exports, "isIdentifierStart", {
return _identifier.isIdentifierStart;
}
});
+Object.defineProperty(exports, "isKeyword", {
+ enumerable: true,
+ get: function () {
+ return _keyword.isKeyword;
+ }
+});
Object.defineProperty(exports, "isReservedWord", {
enumerable: true,
get: function () {
@@ -31512,12 +31555,6 @@ Object.defineProperty(exports, "isStrictReservedWord", {
return _keyword.isStrictReservedWord;
}
});
-Object.defineProperty(exports, "isKeyword", {
- enumerable: true,
- get: function () {
- return _keyword.isKeyword;
- }
-});
var _identifier = __webpack_require__(354);
@@ -31533,9 +31570,9 @@ var _keyword = __webpack_require__(355);
Object.defineProperty(exports, "__esModule", {
value: true
});
-exports.isIdentifierStart = isIdentifierStart;
exports.isIdentifierChar = isIdentifierChar;
exports.isIdentifierName = isIdentifierName;
+exports.isIdentifierStart = isIdentifierStart;
let nonASCIIidentifierStartChars = "\xaa\xb5\xba\xc0-\xd6\xd8-\xf6\xf8-\u02c1\u02c6-\u02d1\u02e0-\u02e4\u02ec\u02ee\u0370-\u0374\u0376\u0377\u037a-\u037d\u037f\u0386\u0388-\u038a\u038c\u038e-\u03a1\u03a3-\u03f5\u03f7-\u0481\u048a-\u052f\u0531-\u0556\u0559\u0560-\u0588\u05d0-\u05ea\u05ef-\u05f2\u0620-\u064a\u066e\u066f\u0671-\u06d3\u06d5\u06e5\u06e6\u06ee\u06ef\u06fa-\u06fc\u06ff\u0710\u0712-\u072f\u074d-\u07a5\u07b1\u07ca-\u07ea\u07f4\u07f5\u07fa\u0800-\u0815\u081a\u0824\u0828\u0840-\u0858\u0860-\u086a\u0870-\u0887\u0889-\u088e\u08a0-\u08c9\u0904-\u0939\u093d\u0950\u0958-\u0961\u0971-\u0980\u0985-\u098c\u098f\u0990\u0993-\u09a8\u09aa-\u09b0\u09b2\u09b6-\u09b9\u09bd\u09ce\u09dc\u09dd\u09df-\u09e1\u09f0\u09f1\u09fc\u0a05-\u0a0a\u0a0f\u0a10\u0a13-\u0a28\u0a2a-\u0a30\u0a32\u0a33\u0a35\u0a36\u0a38\u0a39\u0a59-\u0a5c\u0a5e\u0a72-\u0a74\u0a85-\u0a8d\u0a8f-\u0a91\u0a93-\u0aa8\u0aaa-\u0ab0\u0ab2\u0ab3\u0ab5-\u0ab9\u0abd\u0ad0\u0ae0\u0ae1\u0af9\u0b05-\u0b0c\u0b0f\u0b10\u0b13-\u0b28\u0b2a-\u0b30\u0b32\u0b33\u0b35-\u0b39\u0b3d\u0b5c\u0b5d\u0b5f-\u0b61\u0b71\u0b83\u0b85-\u0b8a\u0b8e-\u0b90\u0b92-\u0b95\u0b99\u0b9a\u0b9c\u0b9e\u0b9f\u0ba3\u0ba4\u0ba8-\u0baa\u0bae-\u0bb9\u0bd0\u0c05-\u0c0c\u0c0e-\u0c10\u0c12-\u0c28\u0c2a-\u0c39\u0c3d\u0c58-\u0c5a\u0c5d\u0c60\u0c61\u0c80\u0c85-\u0c8c\u0c8e-\u0c90\u0c92-\u0ca8\u0caa-\u0cb3\u0cb5-\u0cb9\u0cbd\u0cdd\u0cde\u0ce0\u0ce1\u0cf1\u0cf2\u0d04-\u0d0c\u0d0e-\u0d10\u0d12-\u0d3a\u0d3d\u0d4e\u0d54-\u0d56\u0d5f-\u0d61\u0d7a-\u0d7f\u0d85-\u0d96\u0d9a-\u0db1\u0db3-\u0dbb\u0dbd\u0dc0-\u0dc6\u0e01-\u0e30\u0e32\u0e33\u0e40-\u0e46\u0e81\u0e82\u0e84\u0e86-\u0e8a\u0e8c-\u0ea3\u0ea5\u0ea7-\u0eb0\u0eb2\u0eb3\u0ebd\u0ec0-\u0ec4\u0ec6\u0edc-\u0edf\u0f00\u0f40-\u0f47\u0f49-\u0f6c\u0f88-\u0f8c\u1000-\u102a\u103f\u1050-\u1055\u105a-\u105d\u1061\u1065\u1066\u106e-\u1070\u1075-\u1081\u108e\u10a0-\u10c5\u10c7\u10cd\u10d0-\u10fa\u10fc-\u1248\u124a-\u124d\u1250-\u1256\u1258\u125a-\u125d\u1260-\u1288\u128a-\u128d\u1290-\u12b0\u12b2-\u12b5\u12b8-\u12be\u12c0\u12c2-\u12c5\u12c8-\u12d6\u12d8-\u1310\u1312-\u1315\u1318-\u135a\u1380-\u138f\u13a0-\u13f5\u13f8-\u13fd\u1401-\u166c\u166f-\u167f\u1681-\u169a\u16a0-\u16ea\u16ee-\u16f8\u1700-\u1711\u171f-\u1731\u1740-\u1751\u1760-\u176c\u176e-\u1770\u1780-\u17b3\u17d7\u17dc\u1820-\u1878\u1880-\u18a8\u18aa\u18b0-\u18f5\u1900-\u191e\u1950-\u196d\u1970-\u1974\u1980-\u19ab\u19b0-\u19c9\u1a00-\u1a16\u1a20-\u1a54\u1aa7\u1b05-\u1b33\u1b45-\u1b4c\u1b83-\u1ba0\u1bae\u1baf\u1bba-\u1be5\u1c00-\u1c23\u1c4d-\u1c4f\u1c5a-\u1c7d\u1c80-\u1c88\u1c90-\u1cba\u1cbd-\u1cbf\u1ce9-\u1cec\u1cee-\u1cf3\u1cf5\u1cf6\u1cfa\u1d00-\u1dbf\u1e00-\u1f15\u1f18-\u1f1d\u1f20-\u1f45\u1f48-\u1f4d\u1f50-\u1f57\u1f59\u1f5b\u1f5d\u1f5f-\u1f7d\u1f80-\u1fb4\u1fb6-\u1fbc\u1fbe\u1fc2-\u1fc4\u1fc6-\u1fcc\u1fd0-\u1fd3\u1fd6-\u1fdb\u1fe0-\u1fec\u1ff2-\u1ff4\u1ff6-\u1ffc\u2071\u207f\u2090-\u209c\u2102\u2107\u210a-\u2113\u2115\u2118-\u211d\u2124\u2126\u2128\u212a-\u2139\u213c-\u213f\u2145-\u2149\u214e\u2160-\u2188\u2c00-\u2ce4\u2ceb-\u2cee\u2cf2\u2cf3\u2d00-\u2d25\u2d27\u2d2d\u2d30-\u2d67\u2d6f\u2d80-\u2d96\u2da0-\u2da6\u2da8-\u2dae\u2db0-\u2db6\u2db8-\u2dbe\u2dc0-\u2dc6\u2dc8-\u2dce\u2dd0-\u2dd6\u2dd8-\u2dde\u3005-\u3007\u3021-\u3029\u3031-\u3035\u3038-\u303c\u3041-\u3096\u309b-\u309f\u30a1-\u30fa\u30fc-\u30ff\u3105-\u312f\u3131-\u318e\u31a0-\u31bf\u31f0-\u31ff\u3400-\u4dbf\u4e00-\ua48c\ua4d0-\ua4fd\ua500-\ua60c\ua610-\ua61f\ua62a\ua62b\ua640-\ua66e\ua67f-\ua69d\ua6a0-\ua6ef\ua717-\ua71f\ua722-\ua788\ua78b-\ua7ca\ua7d0\ua7d1\ua7d3\ua7d5-\ua7d9\ua7f2-\ua801\ua803-\ua805\ua807-\ua80a\ua80c-\ua822\ua840-\ua873\ua882-\ua8b3\ua8f2-\ua8f7\ua8fb\ua8fd\ua8fe\ua90a-\ua925\ua930-\ua946\ua960-\ua97c\ua984-\ua9b2\ua9cf\ua9e0-\ua9e4\ua9e6-\ua9ef\ua9fa-\ua9fe\uaa00-\uaa28\uaa40-\uaa42\uaa44-\uaa4b\uaa60-\uaa76\uaa7a\uaa7e-\uaaaf\uaab1\uaab5\uaab6\uaab9-\uaabd\uaac0\uaac2\uaadb-\uaadd\uaae0-\uaaea\uaaf2-\uaaf4\uab01-\uab06\uab09-\uab0e\uab11-\uab16\uab20-\uab26\uab28-\uab2e\uab30-\uab5a\uab5c-\uab69\uab70-\uabe2\uac00-\ud7a3\ud7b0-\ud7c6\ud7cb-\ud7fb\uf900-\ufa6d\ufa70-\ufad9\ufb00-\ufb06\ufb13-\ufb17\ufb1d\ufb1f-\ufb28\ufb2a-\ufb36\ufb38-\ufb3c\ufb3e\ufb40\ufb41\ufb43\ufb44\ufb46-\ufbb1\ufbd3-\ufd3d\ufd50-\ufd8f\ufd92-\ufdc7\ufdf0-\ufdfb\ufe70-\ufe74\ufe76-\ufefc\uff21-\uff3a\uff41-\uff5a\uff66-\uffbe\uffc2-\uffc7\uffca-\uffcf\uffd2-\uffd7\uffda-\uffdc";
let nonASCIIidentifierChars = "\u200c\u200d\xb7\u0300-\u036f\u0387\u0483-\u0487\u0591-\u05bd\u05bf\u05c1\u05c2\u05c4\u05c5\u05c7\u0610-\u061a\u064b-\u0669\u0670\u06d6-\u06dc\u06df-\u06e4\u06e7\u06e8\u06ea-\u06ed\u06f0-\u06f9\u0711\u0730-\u074a\u07a6-\u07b0\u07c0-\u07c9\u07eb-\u07f3\u07fd\u0816-\u0819\u081b-\u0823\u0825-\u0827\u0829-\u082d\u0859-\u085b\u0898-\u089f\u08ca-\u08e1\u08e3-\u0903\u093a-\u093c\u093e-\u094f\u0951-\u0957\u0962\u0963\u0966-\u096f\u0981-\u0983\u09bc\u09be-\u09c4\u09c7\u09c8\u09cb-\u09cd\u09d7\u09e2\u09e3\u09e6-\u09ef\u09fe\u0a01-\u0a03\u0a3c\u0a3e-\u0a42\u0a47\u0a48\u0a4b-\u0a4d\u0a51\u0a66-\u0a71\u0a75\u0a81-\u0a83\u0abc\u0abe-\u0ac5\u0ac7-\u0ac9\u0acb-\u0acd\u0ae2\u0ae3\u0ae6-\u0aef\u0afa-\u0aff\u0b01-\u0b03\u0b3c\u0b3e-\u0b44\u0b47\u0b48\u0b4b-\u0b4d\u0b55-\u0b57\u0b62\u0b63\u0b66-\u0b6f\u0b82\u0bbe-\u0bc2\u0bc6-\u0bc8\u0bca-\u0bcd\u0bd7\u0be6-\u0bef\u0c00-\u0c04\u0c3c\u0c3e-\u0c44\u0c46-\u0c48\u0c4a-\u0c4d\u0c55\u0c56\u0c62\u0c63\u0c66-\u0c6f\u0c81-\u0c83\u0cbc\u0cbe-\u0cc4\u0cc6-\u0cc8\u0cca-\u0ccd\u0cd5\u0cd6\u0ce2\u0ce3\u0ce6-\u0cef\u0d00-\u0d03\u0d3b\u0d3c\u0d3e-\u0d44\u0d46-\u0d48\u0d4a-\u0d4d\u0d57\u0d62\u0d63\u0d66-\u0d6f\u0d81-\u0d83\u0dca\u0dcf-\u0dd4\u0dd6\u0dd8-\u0ddf\u0de6-\u0def\u0df2\u0df3\u0e31\u0e34-\u0e3a\u0e47-\u0e4e\u0e50-\u0e59\u0eb1\u0eb4-\u0ebc\u0ec8-\u0ecd\u0ed0-\u0ed9\u0f18\u0f19\u0f20-\u0f29\u0f35\u0f37\u0f39\u0f3e\u0f3f\u0f71-\u0f84\u0f86\u0f87\u0f8d-\u0f97\u0f99-\u0fbc\u0fc6\u102b-\u103e\u1040-\u1049\u1056-\u1059\u105e-\u1060\u1062-\u1064\u1067-\u106d\u1071-\u1074\u1082-\u108d\u108f-\u109d\u135d-\u135f\u1369-\u1371\u1712-\u1715\u1732-\u1734\u1752\u1753\u1772\u1773\u17b4-\u17d3\u17dd\u17e0-\u17e9\u180b-\u180d\u180f-\u1819\u18a9\u1920-\u192b\u1930-\u193b\u1946-\u194f\u19d0-\u19da\u1a17-\u1a1b\u1a55-\u1a5e\u1a60-\u1a7c\u1a7f-\u1a89\u1a90-\u1a99\u1ab0-\u1abd\u1abf-\u1ace\u1b00-\u1b04\u1b34-\u1b44\u1b50-\u1b59\u1b6b-\u1b73\u1b80-\u1b82\u1ba1-\u1bad\u1bb0-\u1bb9\u1be6-\u1bf3\u1c24-\u1c37\u1c40-\u1c49\u1c50-\u1c59\u1cd0-\u1cd2\u1cd4-\u1ce8\u1ced\u1cf4\u1cf7-\u1cf9\u1dc0-\u1dff\u203f\u2040\u2054\u20d0-\u20dc\u20e1\u20e5-\u20f0\u2cef-\u2cf1\u2d7f\u2de0-\u2dff\u302a-\u302f\u3099\u309a\ua620-\ua629\ua66f\ua674-\ua67d\ua69e\ua69f\ua6f0\ua6f1\ua802\ua806\ua80b\ua823-\ua827\ua82c\ua880\ua881\ua8b4-\ua8c5\ua8d0-\ua8d9\ua8e0-\ua8f1\ua8ff-\ua909\ua926-\ua92d\ua947-\ua953\ua980-\ua983\ua9b3-\ua9c0\ua9d0-\ua9d9\ua9e5\ua9f0-\ua9f9\uaa29-\uaa36\uaa43\uaa4c\uaa4d\uaa50-\uaa59\uaa7b-\uaa7d\uaab0\uaab2-\uaab4\uaab7\uaab8\uaabe\uaabf\uaac1\uaaeb-\uaaef\uaaf5\uaaf6\uabe3-\uabea\uabec\uabed\uabf0-\uabf9\ufb1e\ufe00-\ufe0f\ufe20-\ufe2f\ufe33\ufe34\ufe4d-\ufe4f\uff10-\uff19\uff3f";
const nonASCIIidentifierStart = new RegExp("[" + nonASCIIidentifierStartChars + "]");
@@ -31623,11 +31660,11 @@ function isIdentifierName(name) {
Object.defineProperty(exports, "__esModule", {
value: true
});
+exports.isKeyword = isKeyword;
exports.isReservedWord = isReservedWord;
-exports.isStrictReservedWord = isStrictReservedWord;
exports.isStrictBindOnlyReservedWord = isStrictBindOnlyReservedWord;
exports.isStrictBindReservedWord = isStrictBindReservedWord;
-exports.isKeyword = isKeyword;
+exports.isStrictReservedWord = isStrictReservedWord;
const reservedWords = {
keyword: ["break", "case", "catch", "continue", "debugger", "default", "do", "else", "finally", "for", "function", "if", "return", "switch", "throw", "try", "var", "const", "while", "with", "new", "this", "super", "class", "extends", "export", "import", "null", "true", "false", "in", "instanceof", "typeof", "void", "delete"],
strict: ["implements", "interface", "let", "package", "private", "protected", "public", "static", "yield"],
@@ -41163,7 +41200,11 @@ async function installInDir(directory, extraArgs = []) {
// given time (e.g. to avoid conflicts).
await Object(_child_process__WEBPACK_IMPORTED_MODULE_0__["spawn"])(YARN_EXEC, options, {
- cwd: directory
+ cwd: directory,
+ env: {
+ SASS_BINARY_SITE: 'https://us-central1-elastic-kibana-184716.cloudfunctions.net/kibana-ci-proxy-cache/node-sass',
+ RE2_DOWNLOAD_MIRROR: 'https://us-central1-elastic-kibana-184716.cloudfunctions.net/kibana-ci-proxy-cache/node-re2'
+ }
});
}
/**
@@ -51597,8 +51638,8 @@ __webpack_require__.r(__webpack_exports__);
/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "sortPackageJson", function() { return sortPackageJson; });
/* harmony import */ var fs_promises__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(412);
/* harmony import */ var fs_promises__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(fs_promises__WEBPACK_IMPORTED_MODULE_0__);
-/* harmony import */ var sort_package_json__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(413);
-/* harmony import */ var sort_package_json__WEBPACK_IMPORTED_MODULE_1___default = /*#__PURE__*/__webpack_require__.n(sort_package_json__WEBPACK_IMPORTED_MODULE_1__);
+/* harmony import */ var _kbn_dev_utils_sort_package_json__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(413);
+/* harmony import */ var _kbn_dev_utils_sort_package_json__WEBPACK_IMPORTED_MODULE_1___default = /*#__PURE__*/__webpack_require__.n(_kbn_dev_utils_sort_package_json__WEBPACK_IMPORTED_MODULE_1__);
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License
@@ -51610,11 +51651,7 @@ __webpack_require__.r(__webpack_exports__);
async function sortPackageJson(kbn) {
const packageJsonPath = kbn.getAbsolute('package.json');
- const packageJson = await fs_promises__WEBPACK_IMPORTED_MODULE_0___default.a.readFile(packageJsonPath, 'utf-8');
- await fs_promises__WEBPACK_IMPORTED_MODULE_0___default.a.writeFile(packageJsonPath, JSON.stringify(sort_package_json__WEBPACK_IMPORTED_MODULE_1___default()(JSON.parse(packageJson), {
- // top level keys in the order they were written when this was implemented
- sortOrder: ['name', 'description', 'keywords', 'private', 'version', 'branch', 'types', 'tsdocMetadata', 'build', 'homepage', 'bugs', 'kibana', 'author', 'scripts', 'repository', 'engines', 'resolutions']
- }), null, 2) + '\n');
+ await fs_promises__WEBPACK_IMPORTED_MODULE_0___default.a.writeFile(packageJsonPath, Object(_kbn_dev_utils_sort_package_json__WEBPACK_IMPORTED_MODULE_1__["sortPackageJson"])(await fs_promises__WEBPACK_IMPORTED_MODULE_0___default.a.readFile(packageJsonPath, 'utf-8')));
}
/***/ }),
@@ -51627,11 +51664,41 @@ module.exports = require("fs/promises");
/* 413 */
/***/ (function(module, exports, __webpack_require__) {
-const sortObjectKeys = __webpack_require__(414)
-const detectIndent = __webpack_require__(415)
-const detectNewline = __webpack_require__(416).graceful
-const gitHooks = __webpack_require__(417)
-const isPlainObject = __webpack_require__(418)
+"use strict";
+
+
+var _interopRequireDefault = __webpack_require__(7);
+
+Object.defineProperty(exports, "__esModule", {
+ value: true
+});
+exports.sortPackageJson = sortPackageJson;
+
+var _sortPackageJson = _interopRequireDefault(__webpack_require__(414));
+
+/*
+ * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
+ * or more contributor license agreements. Licensed under the Elastic License
+ * 2.0 and the Server Side Public License, v 1; you may not use this file except
+ * in compliance with, at your election, the Elastic License 2.0 or the Server
+ * Side Public License, v 1.
+ */
+function sortPackageJson(json) {
+ return JSON.stringify((0, _sortPackageJson.default)(JSON.parse(json), {
+ // top level keys in the order they were written when this was implemented
+ sortOrder: ['name', 'description', 'keywords', 'private', 'version', 'branch', 'main', 'browser', 'types', 'tsdocMetadata', 'build', 'homepage', 'bugs', 'license', 'kibana', 'author', 'scripts', 'repository', 'engines', 'resolutions']
+ }), null, 2) + '\n';
+}
+
+/***/ }),
+/* 414 */
+/***/ (function(module, exports, __webpack_require__) {
+
+const sortObjectKeys = __webpack_require__(415)
+const detectIndent = __webpack_require__(416)
+const detectNewline = __webpack_require__(417).graceful
+const gitHooks = __webpack_require__(418)
+const isPlainObject = __webpack_require__(419)
const hasOwnProperty = (object, property) =>
Object.prototype.hasOwnProperty.call(object, property)
@@ -51990,7 +52057,7 @@ module.exports.default = sortPackageJson
/***/ }),
-/* 414 */
+/* 415 */
/***/ (function(module, exports) {
module.exports = function sortObjectByKeyNameList(object, sortWith) {
@@ -52014,7 +52081,7 @@ module.exports = function sortObjectByKeyNameList(object, sortWith) {
/***/ }),
-/* 415 */
+/* 416 */
/***/ (function(module, exports, __webpack_require__) {
"use strict";
@@ -52181,7 +52248,7 @@ module.exports = string => {
/***/ }),
-/* 416 */
+/* 417 */
/***/ (function(module, exports, __webpack_require__) {
"use strict";
@@ -52209,13 +52276,13 @@ module.exports.graceful = string => (typeof string === 'string' && detectNewline
/***/ }),
-/* 417 */
+/* 418 */
/***/ (function(module) {
module.exports = JSON.parse("[\"applypatch-msg\",\"pre-applypatch\",\"post-applypatch\",\"pre-commit\",\"pre-merge-commit\",\"prepare-commit-msg\",\"commit-msg\",\"post-commit\",\"pre-rebase\",\"post-checkout\",\"post-merge\",\"pre-push\",\"pre-receive\",\"update\",\"post-receive\",\"post-update\",\"push-to-checkout\",\"pre-auto-gc\",\"post-rewrite\",\"sendemail-validate\",\"fsmonitor-watchman\",\"p4-pre-submit\",\"post-index-change\"]");
/***/ }),
-/* 418 */
+/* 419 */
/***/ (function(module, exports, __webpack_require__) {
"use strict";
@@ -52232,7 +52299,7 @@ module.exports = value => {
/***/ }),
-/* 419 */
+/* 420 */
/***/ (function(module, __webpack_exports__, __webpack_require__) {
"use strict";
@@ -52249,7 +52316,7 @@ __webpack_require__.r(__webpack_exports__);
/* harmony import */ var _fs__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(231);
/* harmony import */ var _log__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__(220);
/* harmony import */ var _package_json__WEBPACK_IMPORTED_MODULE_6__ = __webpack_require__(343);
-/* harmony import */ var _projects_tree__WEBPACK_IMPORTED_MODULE_7__ = __webpack_require__(420);
+/* harmony import */ var _projects_tree__WEBPACK_IMPORTED_MODULE_7__ = __webpack_require__(421);
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License
@@ -52430,7 +52497,7 @@ function getDevOnlyProductionDepsTree(kbn, projectName) {
}
/***/ }),
-/* 420 */
+/* 421 */
/***/ (function(module, __webpack_exports__, __webpack_require__) {
"use strict";
@@ -52572,27 +52639,27 @@ function addProjectToTree(tree, pathParts, project) {
}
/***/ }),
-/* 421 */
+/* 422 */
/***/ (function(module, __webpack_exports__, __webpack_require__) {
"use strict";
__webpack_require__.r(__webpack_exports__);
-/* harmony import */ var _yarn_integrity__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(422);
+/* harmony import */ var _yarn_integrity__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(423);
/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "yarnIntegrityFileExists", function() { return _yarn_integrity__WEBPACK_IMPORTED_MODULE_0__["yarnIntegrityFileExists"]; });
/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "ensureYarnIntegrityFileExists", function() { return _yarn_integrity__WEBPACK_IMPORTED_MODULE_0__["ensureYarnIntegrityFileExists"]; });
-/* harmony import */ var _get_cache_folders__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(423);
+/* harmony import */ var _get_cache_folders__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(424);
/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "getBazelDiskCacheFolder", function() { return _get_cache_folders__WEBPACK_IMPORTED_MODULE_1__["getBazelDiskCacheFolder"]; });
/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "getBazelRepositoryCacheFolder", function() { return _get_cache_folders__WEBPACK_IMPORTED_MODULE_1__["getBazelRepositoryCacheFolder"]; });
-/* harmony import */ var _install_tools__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(424);
+/* harmony import */ var _install_tools__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(425);
/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "isBazelBinAvailable", function() { return _install_tools__WEBPACK_IMPORTED_MODULE_2__["isBazelBinAvailable"]; });
/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "installBazelTools", function() { return _install_tools__WEBPACK_IMPORTED_MODULE_2__["installBazelTools"]; });
-/* harmony import */ var _run__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(425);
+/* harmony import */ var _run__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(426);
/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "runBazel", function() { return _run__WEBPACK_IMPORTED_MODULE_3__["runBazel"]; });
/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "runIBazel", function() { return _run__WEBPACK_IMPORTED_MODULE_3__["runIBazel"]; });
@@ -52610,7 +52677,7 @@ __webpack_require__.r(__webpack_exports__);
/***/ }),
-/* 422 */
+/* 423 */
/***/ (function(module, __webpack_exports__, __webpack_require__) {
"use strict";
@@ -52657,7 +52724,7 @@ async function ensureYarnIntegrityFileExists(nodeModulesPath) {
}
/***/ }),
-/* 423 */
+/* 424 */
/***/ (function(module, __webpack_exports__, __webpack_require__) {
"use strict";
@@ -52694,7 +52761,7 @@ async function getBazelRepositoryCacheFolder() {
}
/***/ }),
-/* 424 */
+/* 425 */
/***/ (function(module, __webpack_exports__, __webpack_require__) {
"use strict";
@@ -52813,7 +52880,7 @@ async function installBazelTools(repoRootPath) {
}
/***/ }),
-/* 425 */
+/* 426 */
/***/ (function(module, __webpack_exports__, __webpack_require__) {
"use strict";
@@ -52823,8 +52890,8 @@ __webpack_require__.r(__webpack_exports__);
/* harmony import */ var chalk__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(114);
/* harmony import */ var chalk__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(chalk__WEBPACK_IMPORTED_MODULE_0__);
/* harmony import */ var rxjs__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(9);
-/* harmony import */ var rxjs_operators__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(426);
-/* harmony import */ var _kbn_dev_utils_stdio__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(524);
+/* harmony import */ var rxjs_operators__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(427);
+/* harmony import */ var _kbn_dev_utils_stdio__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(525);
/* harmony import */ var _kbn_dev_utils_stdio__WEBPACK_IMPORTED_MODULE_3___default = /*#__PURE__*/__webpack_require__.n(_kbn_dev_utils_stdio__WEBPACK_IMPORTED_MODULE_3__);
/* harmony import */ var _child_process__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(221);
/* harmony import */ var _log__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__(220);
@@ -52890,141 +52957,141 @@ async function runIBazel(bazelArgs, offline = false, runOpts = {}) {
}
/***/ }),
-/* 426 */
+/* 427 */
/***/ (function(module, __webpack_exports__, __webpack_require__) {
"use strict";
__webpack_require__.r(__webpack_exports__);
-/* harmony import */ var _internal_operators_audit__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(427);
+/* harmony import */ var _internal_operators_audit__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(428);
/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "audit", function() { return _internal_operators_audit__WEBPACK_IMPORTED_MODULE_0__["audit"]; });
-/* harmony import */ var _internal_operators_auditTime__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(428);
+/* harmony import */ var _internal_operators_auditTime__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(429);
/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "auditTime", function() { return _internal_operators_auditTime__WEBPACK_IMPORTED_MODULE_1__["auditTime"]; });
-/* harmony import */ var _internal_operators_buffer__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(429);
+/* harmony import */ var _internal_operators_buffer__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(430);
/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "buffer", function() { return _internal_operators_buffer__WEBPACK_IMPORTED_MODULE_2__["buffer"]; });
-/* harmony import */ var _internal_operators_bufferCount__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(430);
+/* harmony import */ var _internal_operators_bufferCount__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(431);
/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "bufferCount", function() { return _internal_operators_bufferCount__WEBPACK_IMPORTED_MODULE_3__["bufferCount"]; });
-/* harmony import */ var _internal_operators_bufferTime__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(431);
+/* harmony import */ var _internal_operators_bufferTime__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(432);
/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "bufferTime", function() { return _internal_operators_bufferTime__WEBPACK_IMPORTED_MODULE_4__["bufferTime"]; });
-/* harmony import */ var _internal_operators_bufferToggle__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__(432);
+/* harmony import */ var _internal_operators_bufferToggle__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__(433);
/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "bufferToggle", function() { return _internal_operators_bufferToggle__WEBPACK_IMPORTED_MODULE_5__["bufferToggle"]; });
-/* harmony import */ var _internal_operators_bufferWhen__WEBPACK_IMPORTED_MODULE_6__ = __webpack_require__(433);
+/* harmony import */ var _internal_operators_bufferWhen__WEBPACK_IMPORTED_MODULE_6__ = __webpack_require__(434);
/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "bufferWhen", function() { return _internal_operators_bufferWhen__WEBPACK_IMPORTED_MODULE_6__["bufferWhen"]; });
-/* harmony import */ var _internal_operators_catchError__WEBPACK_IMPORTED_MODULE_7__ = __webpack_require__(434);
+/* harmony import */ var _internal_operators_catchError__WEBPACK_IMPORTED_MODULE_7__ = __webpack_require__(435);
/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "catchError", function() { return _internal_operators_catchError__WEBPACK_IMPORTED_MODULE_7__["catchError"]; });
-/* harmony import */ var _internal_operators_combineAll__WEBPACK_IMPORTED_MODULE_8__ = __webpack_require__(435);
+/* harmony import */ var _internal_operators_combineAll__WEBPACK_IMPORTED_MODULE_8__ = __webpack_require__(436);
/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "combineAll", function() { return _internal_operators_combineAll__WEBPACK_IMPORTED_MODULE_8__["combineAll"]; });
-/* harmony import */ var _internal_operators_combineLatest__WEBPACK_IMPORTED_MODULE_9__ = __webpack_require__(436);
+/* harmony import */ var _internal_operators_combineLatest__WEBPACK_IMPORTED_MODULE_9__ = __webpack_require__(437);
/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "combineLatest", function() { return _internal_operators_combineLatest__WEBPACK_IMPORTED_MODULE_9__["combineLatest"]; });
-/* harmony import */ var _internal_operators_concat__WEBPACK_IMPORTED_MODULE_10__ = __webpack_require__(437);
+/* harmony import */ var _internal_operators_concat__WEBPACK_IMPORTED_MODULE_10__ = __webpack_require__(438);
/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "concat", function() { return _internal_operators_concat__WEBPACK_IMPORTED_MODULE_10__["concat"]; });
/* harmony import */ var _internal_operators_concatAll__WEBPACK_IMPORTED_MODULE_11__ = __webpack_require__(81);
/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "concatAll", function() { return _internal_operators_concatAll__WEBPACK_IMPORTED_MODULE_11__["concatAll"]; });
-/* harmony import */ var _internal_operators_concatMap__WEBPACK_IMPORTED_MODULE_12__ = __webpack_require__(438);
+/* harmony import */ var _internal_operators_concatMap__WEBPACK_IMPORTED_MODULE_12__ = __webpack_require__(439);
/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "concatMap", function() { return _internal_operators_concatMap__WEBPACK_IMPORTED_MODULE_12__["concatMap"]; });
-/* harmony import */ var _internal_operators_concatMapTo__WEBPACK_IMPORTED_MODULE_13__ = __webpack_require__(439);
+/* harmony import */ var _internal_operators_concatMapTo__WEBPACK_IMPORTED_MODULE_13__ = __webpack_require__(440);
/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "concatMapTo", function() { return _internal_operators_concatMapTo__WEBPACK_IMPORTED_MODULE_13__["concatMapTo"]; });
-/* harmony import */ var _internal_operators_count__WEBPACK_IMPORTED_MODULE_14__ = __webpack_require__(440);
+/* harmony import */ var _internal_operators_count__WEBPACK_IMPORTED_MODULE_14__ = __webpack_require__(441);
/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "count", function() { return _internal_operators_count__WEBPACK_IMPORTED_MODULE_14__["count"]; });
-/* harmony import */ var _internal_operators_debounce__WEBPACK_IMPORTED_MODULE_15__ = __webpack_require__(441);
+/* harmony import */ var _internal_operators_debounce__WEBPACK_IMPORTED_MODULE_15__ = __webpack_require__(442);
/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "debounce", function() { return _internal_operators_debounce__WEBPACK_IMPORTED_MODULE_15__["debounce"]; });
-/* harmony import */ var _internal_operators_debounceTime__WEBPACK_IMPORTED_MODULE_16__ = __webpack_require__(442);
+/* harmony import */ var _internal_operators_debounceTime__WEBPACK_IMPORTED_MODULE_16__ = __webpack_require__(443);
/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "debounceTime", function() { return _internal_operators_debounceTime__WEBPACK_IMPORTED_MODULE_16__["debounceTime"]; });
-/* harmony import */ var _internal_operators_defaultIfEmpty__WEBPACK_IMPORTED_MODULE_17__ = __webpack_require__(443);
+/* harmony import */ var _internal_operators_defaultIfEmpty__WEBPACK_IMPORTED_MODULE_17__ = __webpack_require__(444);
/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "defaultIfEmpty", function() { return _internal_operators_defaultIfEmpty__WEBPACK_IMPORTED_MODULE_17__["defaultIfEmpty"]; });
-/* harmony import */ var _internal_operators_delay__WEBPACK_IMPORTED_MODULE_18__ = __webpack_require__(444);
+/* harmony import */ var _internal_operators_delay__WEBPACK_IMPORTED_MODULE_18__ = __webpack_require__(445);
/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "delay", function() { return _internal_operators_delay__WEBPACK_IMPORTED_MODULE_18__["delay"]; });
-/* harmony import */ var _internal_operators_delayWhen__WEBPACK_IMPORTED_MODULE_19__ = __webpack_require__(446);
+/* harmony import */ var _internal_operators_delayWhen__WEBPACK_IMPORTED_MODULE_19__ = __webpack_require__(447);
/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "delayWhen", function() { return _internal_operators_delayWhen__WEBPACK_IMPORTED_MODULE_19__["delayWhen"]; });
-/* harmony import */ var _internal_operators_dematerialize__WEBPACK_IMPORTED_MODULE_20__ = __webpack_require__(447);
+/* harmony import */ var _internal_operators_dematerialize__WEBPACK_IMPORTED_MODULE_20__ = __webpack_require__(448);
/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "dematerialize", function() { return _internal_operators_dematerialize__WEBPACK_IMPORTED_MODULE_20__["dematerialize"]; });
-/* harmony import */ var _internal_operators_distinct__WEBPACK_IMPORTED_MODULE_21__ = __webpack_require__(448);
+/* harmony import */ var _internal_operators_distinct__WEBPACK_IMPORTED_MODULE_21__ = __webpack_require__(449);
/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "distinct", function() { return _internal_operators_distinct__WEBPACK_IMPORTED_MODULE_21__["distinct"]; });
-/* harmony import */ var _internal_operators_distinctUntilChanged__WEBPACK_IMPORTED_MODULE_22__ = __webpack_require__(449);
+/* harmony import */ var _internal_operators_distinctUntilChanged__WEBPACK_IMPORTED_MODULE_22__ = __webpack_require__(450);
/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "distinctUntilChanged", function() { return _internal_operators_distinctUntilChanged__WEBPACK_IMPORTED_MODULE_22__["distinctUntilChanged"]; });
-/* harmony import */ var _internal_operators_distinctUntilKeyChanged__WEBPACK_IMPORTED_MODULE_23__ = __webpack_require__(450);
+/* harmony import */ var _internal_operators_distinctUntilKeyChanged__WEBPACK_IMPORTED_MODULE_23__ = __webpack_require__(451);
/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "distinctUntilKeyChanged", function() { return _internal_operators_distinctUntilKeyChanged__WEBPACK_IMPORTED_MODULE_23__["distinctUntilKeyChanged"]; });
-/* harmony import */ var _internal_operators_elementAt__WEBPACK_IMPORTED_MODULE_24__ = __webpack_require__(451);
+/* harmony import */ var _internal_operators_elementAt__WEBPACK_IMPORTED_MODULE_24__ = __webpack_require__(452);
/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "elementAt", function() { return _internal_operators_elementAt__WEBPACK_IMPORTED_MODULE_24__["elementAt"]; });
-/* harmony import */ var _internal_operators_endWith__WEBPACK_IMPORTED_MODULE_25__ = __webpack_require__(454);
+/* harmony import */ var _internal_operators_endWith__WEBPACK_IMPORTED_MODULE_25__ = __webpack_require__(455);
/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "endWith", function() { return _internal_operators_endWith__WEBPACK_IMPORTED_MODULE_25__["endWith"]; });
-/* harmony import */ var _internal_operators_every__WEBPACK_IMPORTED_MODULE_26__ = __webpack_require__(455);
+/* harmony import */ var _internal_operators_every__WEBPACK_IMPORTED_MODULE_26__ = __webpack_require__(456);
/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "every", function() { return _internal_operators_every__WEBPACK_IMPORTED_MODULE_26__["every"]; });
-/* harmony import */ var _internal_operators_exhaust__WEBPACK_IMPORTED_MODULE_27__ = __webpack_require__(456);
+/* harmony import */ var _internal_operators_exhaust__WEBPACK_IMPORTED_MODULE_27__ = __webpack_require__(457);
/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "exhaust", function() { return _internal_operators_exhaust__WEBPACK_IMPORTED_MODULE_27__["exhaust"]; });
-/* harmony import */ var _internal_operators_exhaustMap__WEBPACK_IMPORTED_MODULE_28__ = __webpack_require__(457);
+/* harmony import */ var _internal_operators_exhaustMap__WEBPACK_IMPORTED_MODULE_28__ = __webpack_require__(458);
/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "exhaustMap", function() { return _internal_operators_exhaustMap__WEBPACK_IMPORTED_MODULE_28__["exhaustMap"]; });
-/* harmony import */ var _internal_operators_expand__WEBPACK_IMPORTED_MODULE_29__ = __webpack_require__(458);
+/* harmony import */ var _internal_operators_expand__WEBPACK_IMPORTED_MODULE_29__ = __webpack_require__(459);
/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "expand", function() { return _internal_operators_expand__WEBPACK_IMPORTED_MODULE_29__["expand"]; });
/* harmony import */ var _internal_operators_filter__WEBPACK_IMPORTED_MODULE_30__ = __webpack_require__(106);
/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "filter", function() { return _internal_operators_filter__WEBPACK_IMPORTED_MODULE_30__["filter"]; });
-/* harmony import */ var _internal_operators_finalize__WEBPACK_IMPORTED_MODULE_31__ = __webpack_require__(459);
+/* harmony import */ var _internal_operators_finalize__WEBPACK_IMPORTED_MODULE_31__ = __webpack_require__(460);
/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "finalize", function() { return _internal_operators_finalize__WEBPACK_IMPORTED_MODULE_31__["finalize"]; });
-/* harmony import */ var _internal_operators_find__WEBPACK_IMPORTED_MODULE_32__ = __webpack_require__(460);
+/* harmony import */ var _internal_operators_find__WEBPACK_IMPORTED_MODULE_32__ = __webpack_require__(461);
/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "find", function() { return _internal_operators_find__WEBPACK_IMPORTED_MODULE_32__["find"]; });
-/* harmony import */ var _internal_operators_findIndex__WEBPACK_IMPORTED_MODULE_33__ = __webpack_require__(461);
+/* harmony import */ var _internal_operators_findIndex__WEBPACK_IMPORTED_MODULE_33__ = __webpack_require__(462);
/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "findIndex", function() { return _internal_operators_findIndex__WEBPACK_IMPORTED_MODULE_33__["findIndex"]; });
-/* harmony import */ var _internal_operators_first__WEBPACK_IMPORTED_MODULE_34__ = __webpack_require__(462);
+/* harmony import */ var _internal_operators_first__WEBPACK_IMPORTED_MODULE_34__ = __webpack_require__(463);
/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "first", function() { return _internal_operators_first__WEBPACK_IMPORTED_MODULE_34__["first"]; });
/* harmony import */ var _internal_operators_groupBy__WEBPACK_IMPORTED_MODULE_35__ = __webpack_require__(32);
/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "groupBy", function() { return _internal_operators_groupBy__WEBPACK_IMPORTED_MODULE_35__["groupBy"]; });
-/* harmony import */ var _internal_operators_ignoreElements__WEBPACK_IMPORTED_MODULE_36__ = __webpack_require__(463);
+/* harmony import */ var _internal_operators_ignoreElements__WEBPACK_IMPORTED_MODULE_36__ = __webpack_require__(464);
/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "ignoreElements", function() { return _internal_operators_ignoreElements__WEBPACK_IMPORTED_MODULE_36__["ignoreElements"]; });
-/* harmony import */ var _internal_operators_isEmpty__WEBPACK_IMPORTED_MODULE_37__ = __webpack_require__(464);
+/* harmony import */ var _internal_operators_isEmpty__WEBPACK_IMPORTED_MODULE_37__ = __webpack_require__(465);
/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "isEmpty", function() { return _internal_operators_isEmpty__WEBPACK_IMPORTED_MODULE_37__["isEmpty"]; });
-/* harmony import */ var _internal_operators_last__WEBPACK_IMPORTED_MODULE_38__ = __webpack_require__(465);
+/* harmony import */ var _internal_operators_last__WEBPACK_IMPORTED_MODULE_38__ = __webpack_require__(466);
/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "last", function() { return _internal_operators_last__WEBPACK_IMPORTED_MODULE_38__["last"]; });
/* harmony import */ var _internal_operators_map__WEBPACK_IMPORTED_MODULE_39__ = __webpack_require__(67);
/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "map", function() { return _internal_operators_map__WEBPACK_IMPORTED_MODULE_39__["map"]; });
-/* harmony import */ var _internal_operators_mapTo__WEBPACK_IMPORTED_MODULE_40__ = __webpack_require__(467);
+/* harmony import */ var _internal_operators_mapTo__WEBPACK_IMPORTED_MODULE_40__ = __webpack_require__(468);
/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "mapTo", function() { return _internal_operators_mapTo__WEBPACK_IMPORTED_MODULE_40__["mapTo"]; });
-/* harmony import */ var _internal_operators_materialize__WEBPACK_IMPORTED_MODULE_41__ = __webpack_require__(468);
+/* harmony import */ var _internal_operators_materialize__WEBPACK_IMPORTED_MODULE_41__ = __webpack_require__(469);
/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "materialize", function() { return _internal_operators_materialize__WEBPACK_IMPORTED_MODULE_41__["materialize"]; });
-/* harmony import */ var _internal_operators_max__WEBPACK_IMPORTED_MODULE_42__ = __webpack_require__(469);
+/* harmony import */ var _internal_operators_max__WEBPACK_IMPORTED_MODULE_42__ = __webpack_require__(470);
/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "max", function() { return _internal_operators_max__WEBPACK_IMPORTED_MODULE_42__["max"]; });
-/* harmony import */ var _internal_operators_merge__WEBPACK_IMPORTED_MODULE_43__ = __webpack_require__(472);
+/* harmony import */ var _internal_operators_merge__WEBPACK_IMPORTED_MODULE_43__ = __webpack_require__(473);
/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "merge", function() { return _internal_operators_merge__WEBPACK_IMPORTED_MODULE_43__["merge"]; });
/* harmony import */ var _internal_operators_mergeAll__WEBPACK_IMPORTED_MODULE_44__ = __webpack_require__(82);
@@ -53035,175 +53102,175 @@ __webpack_require__.r(__webpack_exports__);
/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "flatMap", function() { return _internal_operators_mergeMap__WEBPACK_IMPORTED_MODULE_45__["flatMap"]; });
-/* harmony import */ var _internal_operators_mergeMapTo__WEBPACK_IMPORTED_MODULE_46__ = __webpack_require__(473);
+/* harmony import */ var _internal_operators_mergeMapTo__WEBPACK_IMPORTED_MODULE_46__ = __webpack_require__(474);
/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "mergeMapTo", function() { return _internal_operators_mergeMapTo__WEBPACK_IMPORTED_MODULE_46__["mergeMapTo"]; });
-/* harmony import */ var _internal_operators_mergeScan__WEBPACK_IMPORTED_MODULE_47__ = __webpack_require__(474);
+/* harmony import */ var _internal_operators_mergeScan__WEBPACK_IMPORTED_MODULE_47__ = __webpack_require__(475);
/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "mergeScan", function() { return _internal_operators_mergeScan__WEBPACK_IMPORTED_MODULE_47__["mergeScan"]; });
-/* harmony import */ var _internal_operators_min__WEBPACK_IMPORTED_MODULE_48__ = __webpack_require__(475);
+/* harmony import */ var _internal_operators_min__WEBPACK_IMPORTED_MODULE_48__ = __webpack_require__(476);
/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "min", function() { return _internal_operators_min__WEBPACK_IMPORTED_MODULE_48__["min"]; });
-/* harmony import */ var _internal_operators_multicast__WEBPACK_IMPORTED_MODULE_49__ = __webpack_require__(476);
+/* harmony import */ var _internal_operators_multicast__WEBPACK_IMPORTED_MODULE_49__ = __webpack_require__(477);
/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "multicast", function() { return _internal_operators_multicast__WEBPACK_IMPORTED_MODULE_49__["multicast"]; });
/* harmony import */ var _internal_operators_observeOn__WEBPACK_IMPORTED_MODULE_50__ = __webpack_require__(42);
/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "observeOn", function() { return _internal_operators_observeOn__WEBPACK_IMPORTED_MODULE_50__["observeOn"]; });
-/* harmony import */ var _internal_operators_onErrorResumeNext__WEBPACK_IMPORTED_MODULE_51__ = __webpack_require__(477);
+/* harmony import */ var _internal_operators_onErrorResumeNext__WEBPACK_IMPORTED_MODULE_51__ = __webpack_require__(478);
/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "onErrorResumeNext", function() { return _internal_operators_onErrorResumeNext__WEBPACK_IMPORTED_MODULE_51__["onErrorResumeNext"]; });
-/* harmony import */ var _internal_operators_pairwise__WEBPACK_IMPORTED_MODULE_52__ = __webpack_require__(478);
+/* harmony import */ var _internal_operators_pairwise__WEBPACK_IMPORTED_MODULE_52__ = __webpack_require__(479);
/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "pairwise", function() { return _internal_operators_pairwise__WEBPACK_IMPORTED_MODULE_52__["pairwise"]; });
-/* harmony import */ var _internal_operators_partition__WEBPACK_IMPORTED_MODULE_53__ = __webpack_require__(479);
+/* harmony import */ var _internal_operators_partition__WEBPACK_IMPORTED_MODULE_53__ = __webpack_require__(480);
/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "partition", function() { return _internal_operators_partition__WEBPACK_IMPORTED_MODULE_53__["partition"]; });
-/* harmony import */ var _internal_operators_pluck__WEBPACK_IMPORTED_MODULE_54__ = __webpack_require__(480);
+/* harmony import */ var _internal_operators_pluck__WEBPACK_IMPORTED_MODULE_54__ = __webpack_require__(481);
/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "pluck", function() { return _internal_operators_pluck__WEBPACK_IMPORTED_MODULE_54__["pluck"]; });
-/* harmony import */ var _internal_operators_publish__WEBPACK_IMPORTED_MODULE_55__ = __webpack_require__(481);
+/* harmony import */ var _internal_operators_publish__WEBPACK_IMPORTED_MODULE_55__ = __webpack_require__(482);
/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "publish", function() { return _internal_operators_publish__WEBPACK_IMPORTED_MODULE_55__["publish"]; });
-/* harmony import */ var _internal_operators_publishBehavior__WEBPACK_IMPORTED_MODULE_56__ = __webpack_require__(482);
+/* harmony import */ var _internal_operators_publishBehavior__WEBPACK_IMPORTED_MODULE_56__ = __webpack_require__(483);
/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "publishBehavior", function() { return _internal_operators_publishBehavior__WEBPACK_IMPORTED_MODULE_56__["publishBehavior"]; });
-/* harmony import */ var _internal_operators_publishLast__WEBPACK_IMPORTED_MODULE_57__ = __webpack_require__(483);
+/* harmony import */ var _internal_operators_publishLast__WEBPACK_IMPORTED_MODULE_57__ = __webpack_require__(484);
/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "publishLast", function() { return _internal_operators_publishLast__WEBPACK_IMPORTED_MODULE_57__["publishLast"]; });
-/* harmony import */ var _internal_operators_publishReplay__WEBPACK_IMPORTED_MODULE_58__ = __webpack_require__(484);
+/* harmony import */ var _internal_operators_publishReplay__WEBPACK_IMPORTED_MODULE_58__ = __webpack_require__(485);
/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "publishReplay", function() { return _internal_operators_publishReplay__WEBPACK_IMPORTED_MODULE_58__["publishReplay"]; });
-/* harmony import */ var _internal_operators_race__WEBPACK_IMPORTED_MODULE_59__ = __webpack_require__(485);
+/* harmony import */ var _internal_operators_race__WEBPACK_IMPORTED_MODULE_59__ = __webpack_require__(486);
/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "race", function() { return _internal_operators_race__WEBPACK_IMPORTED_MODULE_59__["race"]; });
-/* harmony import */ var _internal_operators_reduce__WEBPACK_IMPORTED_MODULE_60__ = __webpack_require__(470);
+/* harmony import */ var _internal_operators_reduce__WEBPACK_IMPORTED_MODULE_60__ = __webpack_require__(471);
/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "reduce", function() { return _internal_operators_reduce__WEBPACK_IMPORTED_MODULE_60__["reduce"]; });
-/* harmony import */ var _internal_operators_repeat__WEBPACK_IMPORTED_MODULE_61__ = __webpack_require__(486);
+/* harmony import */ var _internal_operators_repeat__WEBPACK_IMPORTED_MODULE_61__ = __webpack_require__(487);
/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "repeat", function() { return _internal_operators_repeat__WEBPACK_IMPORTED_MODULE_61__["repeat"]; });
-/* harmony import */ var _internal_operators_repeatWhen__WEBPACK_IMPORTED_MODULE_62__ = __webpack_require__(487);
+/* harmony import */ var _internal_operators_repeatWhen__WEBPACK_IMPORTED_MODULE_62__ = __webpack_require__(488);
/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "repeatWhen", function() { return _internal_operators_repeatWhen__WEBPACK_IMPORTED_MODULE_62__["repeatWhen"]; });
-/* harmony import */ var _internal_operators_retry__WEBPACK_IMPORTED_MODULE_63__ = __webpack_require__(488);
+/* harmony import */ var _internal_operators_retry__WEBPACK_IMPORTED_MODULE_63__ = __webpack_require__(489);
/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "retry", function() { return _internal_operators_retry__WEBPACK_IMPORTED_MODULE_63__["retry"]; });
-/* harmony import */ var _internal_operators_retryWhen__WEBPACK_IMPORTED_MODULE_64__ = __webpack_require__(489);
+/* harmony import */ var _internal_operators_retryWhen__WEBPACK_IMPORTED_MODULE_64__ = __webpack_require__(490);
/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "retryWhen", function() { return _internal_operators_retryWhen__WEBPACK_IMPORTED_MODULE_64__["retryWhen"]; });
/* harmony import */ var _internal_operators_refCount__WEBPACK_IMPORTED_MODULE_65__ = __webpack_require__(31);
/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "refCount", function() { return _internal_operators_refCount__WEBPACK_IMPORTED_MODULE_65__["refCount"]; });
-/* harmony import */ var _internal_operators_sample__WEBPACK_IMPORTED_MODULE_66__ = __webpack_require__(490);
+/* harmony import */ var _internal_operators_sample__WEBPACK_IMPORTED_MODULE_66__ = __webpack_require__(491);
/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "sample", function() { return _internal_operators_sample__WEBPACK_IMPORTED_MODULE_66__["sample"]; });
-/* harmony import */ var _internal_operators_sampleTime__WEBPACK_IMPORTED_MODULE_67__ = __webpack_require__(491);
+/* harmony import */ var _internal_operators_sampleTime__WEBPACK_IMPORTED_MODULE_67__ = __webpack_require__(492);
/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "sampleTime", function() { return _internal_operators_sampleTime__WEBPACK_IMPORTED_MODULE_67__["sampleTime"]; });
-/* harmony import */ var _internal_operators_scan__WEBPACK_IMPORTED_MODULE_68__ = __webpack_require__(471);
+/* harmony import */ var _internal_operators_scan__WEBPACK_IMPORTED_MODULE_68__ = __webpack_require__(472);
/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "scan", function() { return _internal_operators_scan__WEBPACK_IMPORTED_MODULE_68__["scan"]; });
-/* harmony import */ var _internal_operators_sequenceEqual__WEBPACK_IMPORTED_MODULE_69__ = __webpack_require__(492);
+/* harmony import */ var _internal_operators_sequenceEqual__WEBPACK_IMPORTED_MODULE_69__ = __webpack_require__(493);
/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "sequenceEqual", function() { return _internal_operators_sequenceEqual__WEBPACK_IMPORTED_MODULE_69__["sequenceEqual"]; });
-/* harmony import */ var _internal_operators_share__WEBPACK_IMPORTED_MODULE_70__ = __webpack_require__(493);
+/* harmony import */ var _internal_operators_share__WEBPACK_IMPORTED_MODULE_70__ = __webpack_require__(494);
/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "share", function() { return _internal_operators_share__WEBPACK_IMPORTED_MODULE_70__["share"]; });
-/* harmony import */ var _internal_operators_shareReplay__WEBPACK_IMPORTED_MODULE_71__ = __webpack_require__(494);
+/* harmony import */ var _internal_operators_shareReplay__WEBPACK_IMPORTED_MODULE_71__ = __webpack_require__(495);
/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "shareReplay", function() { return _internal_operators_shareReplay__WEBPACK_IMPORTED_MODULE_71__["shareReplay"]; });
-/* harmony import */ var _internal_operators_single__WEBPACK_IMPORTED_MODULE_72__ = __webpack_require__(495);
+/* harmony import */ var _internal_operators_single__WEBPACK_IMPORTED_MODULE_72__ = __webpack_require__(496);
/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "single", function() { return _internal_operators_single__WEBPACK_IMPORTED_MODULE_72__["single"]; });
-/* harmony import */ var _internal_operators_skip__WEBPACK_IMPORTED_MODULE_73__ = __webpack_require__(496);
+/* harmony import */ var _internal_operators_skip__WEBPACK_IMPORTED_MODULE_73__ = __webpack_require__(497);
/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "skip", function() { return _internal_operators_skip__WEBPACK_IMPORTED_MODULE_73__["skip"]; });
-/* harmony import */ var _internal_operators_skipLast__WEBPACK_IMPORTED_MODULE_74__ = __webpack_require__(497);
+/* harmony import */ var _internal_operators_skipLast__WEBPACK_IMPORTED_MODULE_74__ = __webpack_require__(498);
/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "skipLast", function() { return _internal_operators_skipLast__WEBPACK_IMPORTED_MODULE_74__["skipLast"]; });
-/* harmony import */ var _internal_operators_skipUntil__WEBPACK_IMPORTED_MODULE_75__ = __webpack_require__(498);
+/* harmony import */ var _internal_operators_skipUntil__WEBPACK_IMPORTED_MODULE_75__ = __webpack_require__(499);
/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "skipUntil", function() { return _internal_operators_skipUntil__WEBPACK_IMPORTED_MODULE_75__["skipUntil"]; });
-/* harmony import */ var _internal_operators_skipWhile__WEBPACK_IMPORTED_MODULE_76__ = __webpack_require__(499);
+/* harmony import */ var _internal_operators_skipWhile__WEBPACK_IMPORTED_MODULE_76__ = __webpack_require__(500);
/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "skipWhile", function() { return _internal_operators_skipWhile__WEBPACK_IMPORTED_MODULE_76__["skipWhile"]; });
-/* harmony import */ var _internal_operators_startWith__WEBPACK_IMPORTED_MODULE_77__ = __webpack_require__(500);
+/* harmony import */ var _internal_operators_startWith__WEBPACK_IMPORTED_MODULE_77__ = __webpack_require__(501);
/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "startWith", function() { return _internal_operators_startWith__WEBPACK_IMPORTED_MODULE_77__["startWith"]; });
-/* harmony import */ var _internal_operators_subscribeOn__WEBPACK_IMPORTED_MODULE_78__ = __webpack_require__(501);
+/* harmony import */ var _internal_operators_subscribeOn__WEBPACK_IMPORTED_MODULE_78__ = __webpack_require__(502);
/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "subscribeOn", function() { return _internal_operators_subscribeOn__WEBPACK_IMPORTED_MODULE_78__["subscribeOn"]; });
-/* harmony import */ var _internal_operators_switchAll__WEBPACK_IMPORTED_MODULE_79__ = __webpack_require__(503);
+/* harmony import */ var _internal_operators_switchAll__WEBPACK_IMPORTED_MODULE_79__ = __webpack_require__(504);
/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "switchAll", function() { return _internal_operators_switchAll__WEBPACK_IMPORTED_MODULE_79__["switchAll"]; });
-/* harmony import */ var _internal_operators_switchMap__WEBPACK_IMPORTED_MODULE_80__ = __webpack_require__(504);
+/* harmony import */ var _internal_operators_switchMap__WEBPACK_IMPORTED_MODULE_80__ = __webpack_require__(505);
/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "switchMap", function() { return _internal_operators_switchMap__WEBPACK_IMPORTED_MODULE_80__["switchMap"]; });
-/* harmony import */ var _internal_operators_switchMapTo__WEBPACK_IMPORTED_MODULE_81__ = __webpack_require__(505);
+/* harmony import */ var _internal_operators_switchMapTo__WEBPACK_IMPORTED_MODULE_81__ = __webpack_require__(506);
/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "switchMapTo", function() { return _internal_operators_switchMapTo__WEBPACK_IMPORTED_MODULE_81__["switchMapTo"]; });
-/* harmony import */ var _internal_operators_take__WEBPACK_IMPORTED_MODULE_82__ = __webpack_require__(453);
+/* harmony import */ var _internal_operators_take__WEBPACK_IMPORTED_MODULE_82__ = __webpack_require__(454);
/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "take", function() { return _internal_operators_take__WEBPACK_IMPORTED_MODULE_82__["take"]; });
-/* harmony import */ var _internal_operators_takeLast__WEBPACK_IMPORTED_MODULE_83__ = __webpack_require__(466);
+/* harmony import */ var _internal_operators_takeLast__WEBPACK_IMPORTED_MODULE_83__ = __webpack_require__(467);
/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "takeLast", function() { return _internal_operators_takeLast__WEBPACK_IMPORTED_MODULE_83__["takeLast"]; });
-/* harmony import */ var _internal_operators_takeUntil__WEBPACK_IMPORTED_MODULE_84__ = __webpack_require__(506);
+/* harmony import */ var _internal_operators_takeUntil__WEBPACK_IMPORTED_MODULE_84__ = __webpack_require__(507);
/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "takeUntil", function() { return _internal_operators_takeUntil__WEBPACK_IMPORTED_MODULE_84__["takeUntil"]; });
-/* harmony import */ var _internal_operators_takeWhile__WEBPACK_IMPORTED_MODULE_85__ = __webpack_require__(507);
+/* harmony import */ var _internal_operators_takeWhile__WEBPACK_IMPORTED_MODULE_85__ = __webpack_require__(508);
/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "takeWhile", function() { return _internal_operators_takeWhile__WEBPACK_IMPORTED_MODULE_85__["takeWhile"]; });
-/* harmony import */ var _internal_operators_tap__WEBPACK_IMPORTED_MODULE_86__ = __webpack_require__(508);
+/* harmony import */ var _internal_operators_tap__WEBPACK_IMPORTED_MODULE_86__ = __webpack_require__(509);
/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "tap", function() { return _internal_operators_tap__WEBPACK_IMPORTED_MODULE_86__["tap"]; });
-/* harmony import */ var _internal_operators_throttle__WEBPACK_IMPORTED_MODULE_87__ = __webpack_require__(509);
+/* harmony import */ var _internal_operators_throttle__WEBPACK_IMPORTED_MODULE_87__ = __webpack_require__(510);
/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "throttle", function() { return _internal_operators_throttle__WEBPACK_IMPORTED_MODULE_87__["throttle"]; });
-/* harmony import */ var _internal_operators_throttleTime__WEBPACK_IMPORTED_MODULE_88__ = __webpack_require__(510);
+/* harmony import */ var _internal_operators_throttleTime__WEBPACK_IMPORTED_MODULE_88__ = __webpack_require__(511);
/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "throttleTime", function() { return _internal_operators_throttleTime__WEBPACK_IMPORTED_MODULE_88__["throttleTime"]; });
-/* harmony import */ var _internal_operators_throwIfEmpty__WEBPACK_IMPORTED_MODULE_89__ = __webpack_require__(452);
+/* harmony import */ var _internal_operators_throwIfEmpty__WEBPACK_IMPORTED_MODULE_89__ = __webpack_require__(453);
/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "throwIfEmpty", function() { return _internal_operators_throwIfEmpty__WEBPACK_IMPORTED_MODULE_89__["throwIfEmpty"]; });
-/* harmony import */ var _internal_operators_timeInterval__WEBPACK_IMPORTED_MODULE_90__ = __webpack_require__(511);
+/* harmony import */ var _internal_operators_timeInterval__WEBPACK_IMPORTED_MODULE_90__ = __webpack_require__(512);
/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "timeInterval", function() { return _internal_operators_timeInterval__WEBPACK_IMPORTED_MODULE_90__["timeInterval"]; });
-/* harmony import */ var _internal_operators_timeout__WEBPACK_IMPORTED_MODULE_91__ = __webpack_require__(512);
+/* harmony import */ var _internal_operators_timeout__WEBPACK_IMPORTED_MODULE_91__ = __webpack_require__(513);
/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "timeout", function() { return _internal_operators_timeout__WEBPACK_IMPORTED_MODULE_91__["timeout"]; });
-/* harmony import */ var _internal_operators_timeoutWith__WEBPACK_IMPORTED_MODULE_92__ = __webpack_require__(513);
+/* harmony import */ var _internal_operators_timeoutWith__WEBPACK_IMPORTED_MODULE_92__ = __webpack_require__(514);
/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "timeoutWith", function() { return _internal_operators_timeoutWith__WEBPACK_IMPORTED_MODULE_92__["timeoutWith"]; });
-/* harmony import */ var _internal_operators_timestamp__WEBPACK_IMPORTED_MODULE_93__ = __webpack_require__(514);
+/* harmony import */ var _internal_operators_timestamp__WEBPACK_IMPORTED_MODULE_93__ = __webpack_require__(515);
/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "timestamp", function() { return _internal_operators_timestamp__WEBPACK_IMPORTED_MODULE_93__["timestamp"]; });
-/* harmony import */ var _internal_operators_toArray__WEBPACK_IMPORTED_MODULE_94__ = __webpack_require__(515);
+/* harmony import */ var _internal_operators_toArray__WEBPACK_IMPORTED_MODULE_94__ = __webpack_require__(516);
/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "toArray", function() { return _internal_operators_toArray__WEBPACK_IMPORTED_MODULE_94__["toArray"]; });
-/* harmony import */ var _internal_operators_window__WEBPACK_IMPORTED_MODULE_95__ = __webpack_require__(516);
+/* harmony import */ var _internal_operators_window__WEBPACK_IMPORTED_MODULE_95__ = __webpack_require__(517);
/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "window", function() { return _internal_operators_window__WEBPACK_IMPORTED_MODULE_95__["window"]; });
-/* harmony import */ var _internal_operators_windowCount__WEBPACK_IMPORTED_MODULE_96__ = __webpack_require__(517);
+/* harmony import */ var _internal_operators_windowCount__WEBPACK_IMPORTED_MODULE_96__ = __webpack_require__(518);
/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "windowCount", function() { return _internal_operators_windowCount__WEBPACK_IMPORTED_MODULE_96__["windowCount"]; });
-/* harmony import */ var _internal_operators_windowTime__WEBPACK_IMPORTED_MODULE_97__ = __webpack_require__(518);
+/* harmony import */ var _internal_operators_windowTime__WEBPACK_IMPORTED_MODULE_97__ = __webpack_require__(519);
/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "windowTime", function() { return _internal_operators_windowTime__WEBPACK_IMPORTED_MODULE_97__["windowTime"]; });
-/* harmony import */ var _internal_operators_windowToggle__WEBPACK_IMPORTED_MODULE_98__ = __webpack_require__(519);
+/* harmony import */ var _internal_operators_windowToggle__WEBPACK_IMPORTED_MODULE_98__ = __webpack_require__(520);
/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "windowToggle", function() { return _internal_operators_windowToggle__WEBPACK_IMPORTED_MODULE_98__["windowToggle"]; });
-/* harmony import */ var _internal_operators_windowWhen__WEBPACK_IMPORTED_MODULE_99__ = __webpack_require__(520);
+/* harmony import */ var _internal_operators_windowWhen__WEBPACK_IMPORTED_MODULE_99__ = __webpack_require__(521);
/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "windowWhen", function() { return _internal_operators_windowWhen__WEBPACK_IMPORTED_MODULE_99__["windowWhen"]; });
-/* harmony import */ var _internal_operators_withLatestFrom__WEBPACK_IMPORTED_MODULE_100__ = __webpack_require__(521);
+/* harmony import */ var _internal_operators_withLatestFrom__WEBPACK_IMPORTED_MODULE_100__ = __webpack_require__(522);
/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "withLatestFrom", function() { return _internal_operators_withLatestFrom__WEBPACK_IMPORTED_MODULE_100__["withLatestFrom"]; });
-/* harmony import */ var _internal_operators_zip__WEBPACK_IMPORTED_MODULE_101__ = __webpack_require__(522);
+/* harmony import */ var _internal_operators_zip__WEBPACK_IMPORTED_MODULE_101__ = __webpack_require__(523);
/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "zip", function() { return _internal_operators_zip__WEBPACK_IMPORTED_MODULE_101__["zip"]; });
-/* harmony import */ var _internal_operators_zipAll__WEBPACK_IMPORTED_MODULE_102__ = __webpack_require__(523);
+/* harmony import */ var _internal_operators_zipAll__WEBPACK_IMPORTED_MODULE_102__ = __webpack_require__(524);
/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "zipAll", function() { return _internal_operators_zipAll__WEBPACK_IMPORTED_MODULE_102__["zipAll"]; });
/** PURE_IMPORTS_START PURE_IMPORTS_END */
@@ -53314,7 +53381,7 @@ __webpack_require__.r(__webpack_exports__);
/***/ }),
-/* 427 */
+/* 428 */
/***/ (function(module, __webpack_exports__, __webpack_require__) {
"use strict";
@@ -53393,14 +53460,14 @@ var AuditSubscriber = /*@__PURE__*/ (function (_super) {
/***/ }),
-/* 428 */
+/* 429 */
/***/ (function(module, __webpack_exports__, __webpack_require__) {
"use strict";
__webpack_require__.r(__webpack_exports__);
/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "auditTime", function() { return auditTime; });
/* harmony import */ var _scheduler_async__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(56);
-/* harmony import */ var _audit__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(427);
+/* harmony import */ var _audit__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(428);
/* harmony import */ var _observable_timer__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(109);
/** PURE_IMPORTS_START _scheduler_async,_audit,_observable_timer PURE_IMPORTS_END */
@@ -53416,7 +53483,7 @@ function auditTime(duration, scheduler) {
/***/ }),
-/* 429 */
+/* 430 */
/***/ (function(module, __webpack_exports__, __webpack_require__) {
"use strict";
@@ -53463,7 +53530,7 @@ var BufferSubscriber = /*@__PURE__*/ (function (_super) {
/***/ }),
-/* 430 */
+/* 431 */
/***/ (function(module, __webpack_exports__, __webpack_require__) {
"use strict";
@@ -53564,7 +53631,7 @@ var BufferSkipCountSubscriber = /*@__PURE__*/ (function (_super) {
/***/ }),
-/* 431 */
+/* 432 */
/***/ (function(module, __webpack_exports__, __webpack_require__) {
"use strict";
@@ -53725,7 +53792,7 @@ function dispatchBufferClose(arg) {
/***/ }),
-/* 432 */
+/* 433 */
/***/ (function(module, __webpack_exports__, __webpack_require__) {
"use strict";
@@ -53844,7 +53911,7 @@ var BufferToggleSubscriber = /*@__PURE__*/ (function (_super) {
/***/ }),
-/* 433 */
+/* 434 */
/***/ (function(module, __webpack_exports__, __webpack_require__) {
"use strict";
@@ -53937,7 +54004,7 @@ var BufferWhenSubscriber = /*@__PURE__*/ (function (_super) {
/***/ }),
-/* 434 */
+/* 435 */
/***/ (function(module, __webpack_exports__, __webpack_require__) {
"use strict";
@@ -53997,7 +54064,7 @@ var CatchSubscriber = /*@__PURE__*/ (function (_super) {
/***/ }),
-/* 435 */
+/* 436 */
/***/ (function(module, __webpack_exports__, __webpack_require__) {
"use strict";
@@ -54013,7 +54080,7 @@ function combineAll(project) {
/***/ }),
-/* 436 */
+/* 437 */
/***/ (function(module, __webpack_exports__, __webpack_require__) {
"use strict";
@@ -54045,7 +54112,7 @@ function combineLatest() {
/***/ }),
-/* 437 */
+/* 438 */
/***/ (function(module, __webpack_exports__, __webpack_require__) {
"use strict";
@@ -54065,7 +54132,7 @@ function concat() {
/***/ }),
-/* 438 */
+/* 439 */
/***/ (function(module, __webpack_exports__, __webpack_require__) {
"use strict";
@@ -54081,13 +54148,13 @@ function concatMap(project, resultSelector) {
/***/ }),
-/* 439 */
+/* 440 */
/***/ (function(module, __webpack_exports__, __webpack_require__) {
"use strict";
__webpack_require__.r(__webpack_exports__);
/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "concatMapTo", function() { return concatMapTo; });
-/* harmony import */ var _concatMap__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(438);
+/* harmony import */ var _concatMap__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(439);
/** PURE_IMPORTS_START _concatMap PURE_IMPORTS_END */
function concatMapTo(innerObservable, resultSelector) {
@@ -54097,7 +54164,7 @@ function concatMapTo(innerObservable, resultSelector) {
/***/ }),
-/* 440 */
+/* 441 */
/***/ (function(module, __webpack_exports__, __webpack_require__) {
"use strict";
@@ -54162,7 +54229,7 @@ var CountSubscriber = /*@__PURE__*/ (function (_super) {
/***/ }),
-/* 441 */
+/* 442 */
/***/ (function(module, __webpack_exports__, __webpack_require__) {
"use strict";
@@ -54247,7 +54314,7 @@ var DebounceSubscriber = /*@__PURE__*/ (function (_super) {
/***/ }),
-/* 442 */
+/* 443 */
/***/ (function(module, __webpack_exports__, __webpack_require__) {
"use strict";
@@ -54323,7 +54390,7 @@ function dispatchNext(subscriber) {
/***/ }),
-/* 443 */
+/* 444 */
/***/ (function(module, __webpack_exports__, __webpack_require__) {
"use strict";
@@ -54373,7 +54440,7 @@ var DefaultIfEmptySubscriber = /*@__PURE__*/ (function (_super) {
/***/ }),
-/* 444 */
+/* 445 */
/***/ (function(module, __webpack_exports__, __webpack_require__) {
"use strict";
@@ -54381,7 +54448,7 @@ __webpack_require__.r(__webpack_exports__);
/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "delay", function() { return delay; });
/* harmony import */ var tslib__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(13);
/* harmony import */ var _scheduler_async__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(56);
-/* harmony import */ var _util_isDate__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(445);
+/* harmony import */ var _util_isDate__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(446);
/* harmony import */ var _Subscriber__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(12);
/* harmony import */ var _Notification__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(43);
/** PURE_IMPORTS_START tslib,_scheduler_async,_util_isDate,_Subscriber,_Notification PURE_IMPORTS_END */
@@ -54480,7 +54547,7 @@ var DelayMessage = /*@__PURE__*/ (function () {
/***/ }),
-/* 445 */
+/* 446 */
/***/ (function(module, __webpack_exports__, __webpack_require__) {
"use strict";
@@ -54494,7 +54561,7 @@ function isDate(value) {
/***/ }),
-/* 446 */
+/* 447 */
/***/ (function(module, __webpack_exports__, __webpack_require__) {
"use strict";
@@ -54640,7 +54707,7 @@ var SubscriptionDelaySubscriber = /*@__PURE__*/ (function (_super) {
/***/ }),
-/* 447 */
+/* 448 */
/***/ (function(module, __webpack_exports__, __webpack_require__) {
"use strict";
@@ -54678,7 +54745,7 @@ var DeMaterializeSubscriber = /*@__PURE__*/ (function (_super) {
/***/ }),
-/* 448 */
+/* 449 */
/***/ (function(module, __webpack_exports__, __webpack_require__) {
"use strict";
@@ -54754,7 +54821,7 @@ var DistinctSubscriber = /*@__PURE__*/ (function (_super) {
/***/ }),
-/* 449 */
+/* 450 */
/***/ (function(module, __webpack_exports__, __webpack_require__) {
"use strict";
@@ -54825,13 +54892,13 @@ var DistinctUntilChangedSubscriber = /*@__PURE__*/ (function (_super) {
/***/ }),
-/* 450 */
+/* 451 */
/***/ (function(module, __webpack_exports__, __webpack_require__) {
"use strict";
__webpack_require__.r(__webpack_exports__);
/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "distinctUntilKeyChanged", function() { return distinctUntilKeyChanged; });
-/* harmony import */ var _distinctUntilChanged__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(449);
+/* harmony import */ var _distinctUntilChanged__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(450);
/** PURE_IMPORTS_START _distinctUntilChanged PURE_IMPORTS_END */
function distinctUntilKeyChanged(key, compare) {
@@ -54841,7 +54908,7 @@ function distinctUntilKeyChanged(key, compare) {
/***/ }),
-/* 451 */
+/* 452 */
/***/ (function(module, __webpack_exports__, __webpack_require__) {
"use strict";
@@ -54849,9 +54916,9 @@ __webpack_require__.r(__webpack_exports__);
/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "elementAt", function() { return elementAt; });
/* harmony import */ var _util_ArgumentOutOfRangeError__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(63);
/* harmony import */ var _filter__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(106);
-/* harmony import */ var _throwIfEmpty__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(452);
-/* harmony import */ var _defaultIfEmpty__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(443);
-/* harmony import */ var _take__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(453);
+/* harmony import */ var _throwIfEmpty__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(453);
+/* harmony import */ var _defaultIfEmpty__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(444);
+/* harmony import */ var _take__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(454);
/** PURE_IMPORTS_START _util_ArgumentOutOfRangeError,_filter,_throwIfEmpty,_defaultIfEmpty,_take PURE_IMPORTS_END */
@@ -54873,7 +54940,7 @@ function elementAt(index, defaultValue) {
/***/ }),
-/* 452 */
+/* 453 */
/***/ (function(module, __webpack_exports__, __webpack_require__) {
"use strict";
@@ -54939,7 +55006,7 @@ function defaultErrorFactory() {
/***/ }),
-/* 453 */
+/* 454 */
/***/ (function(module, __webpack_exports__, __webpack_require__) {
"use strict";
@@ -55001,7 +55068,7 @@ var TakeSubscriber = /*@__PURE__*/ (function (_super) {
/***/ }),
-/* 454 */
+/* 455 */
/***/ (function(module, __webpack_exports__, __webpack_require__) {
"use strict";
@@ -55023,7 +55090,7 @@ function endWith() {
/***/ }),
-/* 455 */
+/* 456 */
/***/ (function(module, __webpack_exports__, __webpack_require__) {
"use strict";
@@ -55085,7 +55152,7 @@ var EverySubscriber = /*@__PURE__*/ (function (_super) {
/***/ }),
-/* 456 */
+/* 457 */
/***/ (function(module, __webpack_exports__, __webpack_require__) {
"use strict";
@@ -55139,7 +55206,7 @@ var SwitchFirstSubscriber = /*@__PURE__*/ (function (_super) {
/***/ }),
-/* 457 */
+/* 458 */
/***/ (function(module, __webpack_exports__, __webpack_require__) {
"use strict";
@@ -55233,7 +55300,7 @@ var ExhaustMapSubscriber = /*@__PURE__*/ (function (_super) {
/***/ }),
-/* 458 */
+/* 459 */
/***/ (function(module, __webpack_exports__, __webpack_require__) {
"use strict";
@@ -55345,7 +55412,7 @@ var ExpandSubscriber = /*@__PURE__*/ (function (_super) {
/***/ }),
-/* 459 */
+/* 460 */
/***/ (function(module, __webpack_exports__, __webpack_require__) {
"use strict";
@@ -55383,7 +55450,7 @@ var FinallySubscriber = /*@__PURE__*/ (function (_super) {
/***/ }),
-/* 460 */
+/* 461 */
/***/ (function(module, __webpack_exports__, __webpack_require__) {
"use strict";
@@ -55455,13 +55522,13 @@ var FindValueSubscriber = /*@__PURE__*/ (function (_super) {
/***/ }),
-/* 461 */
+/* 462 */
/***/ (function(module, __webpack_exports__, __webpack_require__) {
"use strict";
__webpack_require__.r(__webpack_exports__);
/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "findIndex", function() { return findIndex; });
-/* harmony import */ var _operators_find__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(460);
+/* harmony import */ var _operators_find__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(461);
/** PURE_IMPORTS_START _operators_find PURE_IMPORTS_END */
function findIndex(predicate, thisArg) {
@@ -55471,7 +55538,7 @@ function findIndex(predicate, thisArg) {
/***/ }),
-/* 462 */
+/* 463 */
/***/ (function(module, __webpack_exports__, __webpack_require__) {
"use strict";
@@ -55479,9 +55546,9 @@ __webpack_require__.r(__webpack_exports__);
/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "first", function() { return first; });
/* harmony import */ var _util_EmptyError__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(64);
/* harmony import */ var _filter__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(106);
-/* harmony import */ var _take__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(453);
-/* harmony import */ var _defaultIfEmpty__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(443);
-/* harmony import */ var _throwIfEmpty__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(452);
+/* harmony import */ var _take__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(454);
+/* harmony import */ var _defaultIfEmpty__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(444);
+/* harmony import */ var _throwIfEmpty__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(453);
/* harmony import */ var _util_identity__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__(26);
/** PURE_IMPORTS_START _util_EmptyError,_filter,_take,_defaultIfEmpty,_throwIfEmpty,_util_identity PURE_IMPORTS_END */
@@ -55498,7 +55565,7 @@ function first(predicate, defaultValue) {
/***/ }),
-/* 463 */
+/* 464 */
/***/ (function(module, __webpack_exports__, __webpack_require__) {
"use strict";
@@ -55535,7 +55602,7 @@ var IgnoreElementsSubscriber = /*@__PURE__*/ (function (_super) {
/***/ }),
-/* 464 */
+/* 465 */
/***/ (function(module, __webpack_exports__, __webpack_require__) {
"use strict";
@@ -55579,7 +55646,7 @@ var IsEmptySubscriber = /*@__PURE__*/ (function (_super) {
/***/ }),
-/* 465 */
+/* 466 */
/***/ (function(module, __webpack_exports__, __webpack_require__) {
"use strict";
@@ -55587,9 +55654,9 @@ __webpack_require__.r(__webpack_exports__);
/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "last", function() { return last; });
/* harmony import */ var _util_EmptyError__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(64);
/* harmony import */ var _filter__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(106);
-/* harmony import */ var _takeLast__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(466);
-/* harmony import */ var _throwIfEmpty__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(452);
-/* harmony import */ var _defaultIfEmpty__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(443);
+/* harmony import */ var _takeLast__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(467);
+/* harmony import */ var _throwIfEmpty__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(453);
+/* harmony import */ var _defaultIfEmpty__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(444);
/* harmony import */ var _util_identity__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__(26);
/** PURE_IMPORTS_START _util_EmptyError,_filter,_takeLast,_throwIfEmpty,_defaultIfEmpty,_util_identity PURE_IMPORTS_END */
@@ -55606,7 +55673,7 @@ function last(predicate, defaultValue) {
/***/ }),
-/* 466 */
+/* 467 */
/***/ (function(module, __webpack_exports__, __webpack_require__) {
"use strict";
@@ -55683,7 +55750,7 @@ var TakeLastSubscriber = /*@__PURE__*/ (function (_super) {
/***/ }),
-/* 467 */
+/* 468 */
/***/ (function(module, __webpack_exports__, __webpack_require__) {
"use strict";
@@ -55722,7 +55789,7 @@ var MapToSubscriber = /*@__PURE__*/ (function (_super) {
/***/ }),
-/* 468 */
+/* 469 */
/***/ (function(module, __webpack_exports__, __webpack_require__) {
"use strict";
@@ -55772,13 +55839,13 @@ var MaterializeSubscriber = /*@__PURE__*/ (function (_super) {
/***/ }),
-/* 469 */
+/* 470 */
/***/ (function(module, __webpack_exports__, __webpack_require__) {
"use strict";
__webpack_require__.r(__webpack_exports__);
/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "max", function() { return max; });
-/* harmony import */ var _reduce__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(470);
+/* harmony import */ var _reduce__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(471);
/** PURE_IMPORTS_START _reduce PURE_IMPORTS_END */
function max(comparer) {
@@ -55791,15 +55858,15 @@ function max(comparer) {
/***/ }),
-/* 470 */
+/* 471 */
/***/ (function(module, __webpack_exports__, __webpack_require__) {
"use strict";
__webpack_require__.r(__webpack_exports__);
/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "reduce", function() { return reduce; });
-/* harmony import */ var _scan__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(471);
-/* harmony import */ var _takeLast__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(466);
-/* harmony import */ var _defaultIfEmpty__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(443);
+/* harmony import */ var _scan__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(472);
+/* harmony import */ var _takeLast__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(467);
+/* harmony import */ var _defaultIfEmpty__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(444);
/* harmony import */ var _util_pipe__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(25);
/** PURE_IMPORTS_START _scan,_takeLast,_defaultIfEmpty,_util_pipe PURE_IMPORTS_END */
@@ -55820,7 +55887,7 @@ function reduce(accumulator, seed) {
/***/ }),
-/* 471 */
+/* 472 */
/***/ (function(module, __webpack_exports__, __webpack_require__) {
"use strict";
@@ -55902,7 +55969,7 @@ var ScanSubscriber = /*@__PURE__*/ (function (_super) {
/***/ }),
-/* 472 */
+/* 473 */
/***/ (function(module, __webpack_exports__, __webpack_require__) {
"use strict";
@@ -55922,7 +55989,7 @@ function merge() {
/***/ }),
-/* 473 */
+/* 474 */
/***/ (function(module, __webpack_exports__, __webpack_require__) {
"use strict";
@@ -55947,7 +56014,7 @@ function mergeMapTo(innerObservable, resultSelector, concurrent) {
/***/ }),
-/* 474 */
+/* 475 */
/***/ (function(module, __webpack_exports__, __webpack_require__) {
"use strict";
@@ -56056,13 +56123,13 @@ var MergeScanSubscriber = /*@__PURE__*/ (function (_super) {
/***/ }),
-/* 475 */
+/* 476 */
/***/ (function(module, __webpack_exports__, __webpack_require__) {
"use strict";
__webpack_require__.r(__webpack_exports__);
/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "min", function() { return min; });
-/* harmony import */ var _reduce__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(470);
+/* harmony import */ var _reduce__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(471);
/** PURE_IMPORTS_START _reduce PURE_IMPORTS_END */
function min(comparer) {
@@ -56075,7 +56142,7 @@ function min(comparer) {
/***/ }),
-/* 476 */
+/* 477 */
/***/ (function(module, __webpack_exports__, __webpack_require__) {
"use strict";
@@ -56124,7 +56191,7 @@ var MulticastOperator = /*@__PURE__*/ (function () {
/***/ }),
-/* 477 */
+/* 478 */
/***/ (function(module, __webpack_exports__, __webpack_require__) {
"use strict";
@@ -56214,7 +56281,7 @@ var OnErrorResumeNextSubscriber = /*@__PURE__*/ (function (_super) {
/***/ }),
-/* 478 */
+/* 479 */
/***/ (function(module, __webpack_exports__, __webpack_require__) {
"use strict";
@@ -56262,7 +56329,7 @@ var PairwiseSubscriber = /*@__PURE__*/ (function (_super) {
/***/ }),
-/* 479 */
+/* 480 */
/***/ (function(module, __webpack_exports__, __webpack_require__) {
"use strict";
@@ -56285,7 +56352,7 @@ function partition(predicate, thisArg) {
/***/ }),
-/* 480 */
+/* 481 */
/***/ (function(module, __webpack_exports__, __webpack_require__) {
"use strict";
@@ -56325,14 +56392,14 @@ function plucker(props, length) {
/***/ }),
-/* 481 */
+/* 482 */
/***/ (function(module, __webpack_exports__, __webpack_require__) {
"use strict";
__webpack_require__.r(__webpack_exports__);
/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "publish", function() { return publish; });
/* harmony import */ var _Subject__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(28);
-/* harmony import */ var _multicast__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(476);
+/* harmony import */ var _multicast__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(477);
/** PURE_IMPORTS_START _Subject,_multicast PURE_IMPORTS_END */
@@ -56345,14 +56412,14 @@ function publish(selector) {
/***/ }),
-/* 482 */
+/* 483 */
/***/ (function(module, __webpack_exports__, __webpack_require__) {
"use strict";
__webpack_require__.r(__webpack_exports__);
/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "publishBehavior", function() { return publishBehavior; });
/* harmony import */ var _BehaviorSubject__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(33);
-/* harmony import */ var _multicast__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(476);
+/* harmony import */ var _multicast__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(477);
/** PURE_IMPORTS_START _BehaviorSubject,_multicast PURE_IMPORTS_END */
@@ -56363,14 +56430,14 @@ function publishBehavior(value) {
/***/ }),
-/* 483 */
+/* 484 */
/***/ (function(module, __webpack_exports__, __webpack_require__) {
"use strict";
__webpack_require__.r(__webpack_exports__);
/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "publishLast", function() { return publishLast; });
/* harmony import */ var _AsyncSubject__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(51);
-/* harmony import */ var _multicast__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(476);
+/* harmony import */ var _multicast__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(477);
/** PURE_IMPORTS_START _AsyncSubject,_multicast PURE_IMPORTS_END */
@@ -56381,14 +56448,14 @@ function publishLast() {
/***/ }),
-/* 484 */
+/* 485 */
/***/ (function(module, __webpack_exports__, __webpack_require__) {
"use strict";
__webpack_require__.r(__webpack_exports__);
/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "publishReplay", function() { return publishReplay; });
/* harmony import */ var _ReplaySubject__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(34);
-/* harmony import */ var _multicast__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(476);
+/* harmony import */ var _multicast__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(477);
/** PURE_IMPORTS_START _ReplaySubject,_multicast PURE_IMPORTS_END */
@@ -56404,7 +56471,7 @@ function publishReplay(bufferSize, windowTime, selectorOrScheduler, scheduler) {
/***/ }),
-/* 485 */
+/* 486 */
/***/ (function(module, __webpack_exports__, __webpack_require__) {
"use strict";
@@ -56431,7 +56498,7 @@ function race() {
/***/ }),
-/* 486 */
+/* 487 */
/***/ (function(module, __webpack_exports__, __webpack_require__) {
"use strict";
@@ -56496,7 +56563,7 @@ var RepeatSubscriber = /*@__PURE__*/ (function (_super) {
/***/ }),
-/* 487 */
+/* 488 */
/***/ (function(module, __webpack_exports__, __webpack_require__) {
"use strict";
@@ -56590,7 +56657,7 @@ var RepeatWhenSubscriber = /*@__PURE__*/ (function (_super) {
/***/ }),
-/* 488 */
+/* 489 */
/***/ (function(module, __webpack_exports__, __webpack_require__) {
"use strict";
@@ -56643,7 +56710,7 @@ var RetrySubscriber = /*@__PURE__*/ (function (_super) {
/***/ }),
-/* 489 */
+/* 490 */
/***/ (function(module, __webpack_exports__, __webpack_require__) {
"use strict";
@@ -56729,7 +56796,7 @@ var RetryWhenSubscriber = /*@__PURE__*/ (function (_super) {
/***/ }),
-/* 490 */
+/* 491 */
/***/ (function(module, __webpack_exports__, __webpack_require__) {
"use strict";
@@ -56784,7 +56851,7 @@ var SampleSubscriber = /*@__PURE__*/ (function (_super) {
/***/ }),
-/* 491 */
+/* 492 */
/***/ (function(module, __webpack_exports__, __webpack_require__) {
"use strict";
@@ -56844,7 +56911,7 @@ function dispatchNotification(state) {
/***/ }),
-/* 492 */
+/* 493 */
/***/ (function(module, __webpack_exports__, __webpack_require__) {
"use strict";
@@ -56967,13 +57034,13 @@ var SequenceEqualCompareToSubscriber = /*@__PURE__*/ (function (_super) {
/***/ }),
-/* 493 */
+/* 494 */
/***/ (function(module, __webpack_exports__, __webpack_require__) {
"use strict";
__webpack_require__.r(__webpack_exports__);
/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "share", function() { return share; });
-/* harmony import */ var _multicast__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(476);
+/* harmony import */ var _multicast__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(477);
/* harmony import */ var _refCount__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(31);
/* harmony import */ var _Subject__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(28);
/** PURE_IMPORTS_START _multicast,_refCount,_Subject PURE_IMPORTS_END */
@@ -56990,7 +57057,7 @@ function share() {
/***/ }),
-/* 494 */
+/* 495 */
/***/ (function(module, __webpack_exports__, __webpack_require__) {
"use strict";
@@ -57059,7 +57126,7 @@ function shareReplayOperator(_a) {
/***/ }),
-/* 495 */
+/* 496 */
/***/ (function(module, __webpack_exports__, __webpack_require__) {
"use strict";
@@ -57139,7 +57206,7 @@ var SingleSubscriber = /*@__PURE__*/ (function (_super) {
/***/ }),
-/* 496 */
+/* 497 */
/***/ (function(module, __webpack_exports__, __webpack_require__) {
"use strict";
@@ -57181,7 +57248,7 @@ var SkipSubscriber = /*@__PURE__*/ (function (_super) {
/***/ }),
-/* 497 */
+/* 498 */
/***/ (function(module, __webpack_exports__, __webpack_require__) {
"use strict";
@@ -57243,7 +57310,7 @@ var SkipLastSubscriber = /*@__PURE__*/ (function (_super) {
/***/ }),
-/* 498 */
+/* 499 */
/***/ (function(module, __webpack_exports__, __webpack_require__) {
"use strict";
@@ -57300,7 +57367,7 @@ var SkipUntilSubscriber = /*@__PURE__*/ (function (_super) {
/***/ }),
-/* 499 */
+/* 500 */
/***/ (function(module, __webpack_exports__, __webpack_require__) {
"use strict";
@@ -57356,7 +57423,7 @@ var SkipWhileSubscriber = /*@__PURE__*/ (function (_super) {
/***/ }),
-/* 500 */
+/* 501 */
/***/ (function(module, __webpack_exports__, __webpack_require__) {
"use strict";
@@ -57385,13 +57452,13 @@ function startWith() {
/***/ }),
-/* 501 */
+/* 502 */
/***/ (function(module, __webpack_exports__, __webpack_require__) {
"use strict";
__webpack_require__.r(__webpack_exports__);
/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "subscribeOn", function() { return subscribeOn; });
-/* harmony import */ var _observable_SubscribeOnObservable__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(502);
+/* harmony import */ var _observable_SubscribeOnObservable__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(503);
/** PURE_IMPORTS_START _observable_SubscribeOnObservable PURE_IMPORTS_END */
function subscribeOn(scheduler, delay) {
@@ -57416,7 +57483,7 @@ var SubscribeOnOperator = /*@__PURE__*/ (function () {
/***/ }),
-/* 502 */
+/* 503 */
/***/ (function(module, __webpack_exports__, __webpack_require__) {
"use strict";
@@ -57480,13 +57547,13 @@ var SubscribeOnObservable = /*@__PURE__*/ (function (_super) {
/***/ }),
-/* 503 */
+/* 504 */
/***/ (function(module, __webpack_exports__, __webpack_require__) {
"use strict";
__webpack_require__.r(__webpack_exports__);
/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "switchAll", function() { return switchAll; });
-/* harmony import */ var _switchMap__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(504);
+/* harmony import */ var _switchMap__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(505);
/* harmony import */ var _util_identity__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(26);
/** PURE_IMPORTS_START _switchMap,_util_identity PURE_IMPORTS_END */
@@ -57498,7 +57565,7 @@ function switchAll() {
/***/ }),
-/* 504 */
+/* 505 */
/***/ (function(module, __webpack_exports__, __webpack_require__) {
"use strict";
@@ -57586,13 +57653,13 @@ var SwitchMapSubscriber = /*@__PURE__*/ (function (_super) {
/***/ }),
-/* 505 */
+/* 506 */
/***/ (function(module, __webpack_exports__, __webpack_require__) {
"use strict";
__webpack_require__.r(__webpack_exports__);
/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "switchMapTo", function() { return switchMapTo; });
-/* harmony import */ var _switchMap__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(504);
+/* harmony import */ var _switchMap__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(505);
/** PURE_IMPORTS_START _switchMap PURE_IMPORTS_END */
function switchMapTo(innerObservable, resultSelector) {
@@ -57602,7 +57669,7 @@ function switchMapTo(innerObservable, resultSelector) {
/***/ }),
-/* 506 */
+/* 507 */
/***/ (function(module, __webpack_exports__, __webpack_require__) {
"use strict";
@@ -57650,7 +57717,7 @@ var TakeUntilSubscriber = /*@__PURE__*/ (function (_super) {
/***/ }),
-/* 507 */
+/* 508 */
/***/ (function(module, __webpack_exports__, __webpack_require__) {
"use strict";
@@ -57718,7 +57785,7 @@ var TakeWhileSubscriber = /*@__PURE__*/ (function (_super) {
/***/ }),
-/* 508 */
+/* 509 */
/***/ (function(module, __webpack_exports__, __webpack_require__) {
"use strict";
@@ -57806,7 +57873,7 @@ var TapSubscriber = /*@__PURE__*/ (function (_super) {
/***/ }),
-/* 509 */
+/* 510 */
/***/ (function(module, __webpack_exports__, __webpack_require__) {
"use strict";
@@ -57908,7 +57975,7 @@ var ThrottleSubscriber = /*@__PURE__*/ (function (_super) {
/***/ }),
-/* 510 */
+/* 511 */
/***/ (function(module, __webpack_exports__, __webpack_require__) {
"use strict";
@@ -57917,7 +57984,7 @@ __webpack_require__.r(__webpack_exports__);
/* harmony import */ var tslib__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(13);
/* harmony import */ var _Subscriber__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(12);
/* harmony import */ var _scheduler_async__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(56);
-/* harmony import */ var _throttle__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(509);
+/* harmony import */ var _throttle__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(510);
/** PURE_IMPORTS_START tslib,_Subscriber,_scheduler_async,_throttle PURE_IMPORTS_END */
@@ -58006,7 +58073,7 @@ function dispatchNext(arg) {
/***/ }),
-/* 511 */
+/* 512 */
/***/ (function(module, __webpack_exports__, __webpack_require__) {
"use strict";
@@ -58014,7 +58081,7 @@ __webpack_require__.r(__webpack_exports__);
/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "timeInterval", function() { return timeInterval; });
/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "TimeInterval", function() { return TimeInterval; });
/* harmony import */ var _scheduler_async__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(56);
-/* harmony import */ var _scan__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(471);
+/* harmony import */ var _scan__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(472);
/* harmony import */ var _observable_defer__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(92);
/* harmony import */ var _map__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(67);
/** PURE_IMPORTS_START _scheduler_async,_scan,_observable_defer,_map PURE_IMPORTS_END */
@@ -58050,7 +58117,7 @@ var TimeInterval = /*@__PURE__*/ (function () {
/***/ }),
-/* 512 */
+/* 513 */
/***/ (function(module, __webpack_exports__, __webpack_require__) {
"use strict";
@@ -58058,7 +58125,7 @@ __webpack_require__.r(__webpack_exports__);
/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "timeout", function() { return timeout; });
/* harmony import */ var _scheduler_async__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(56);
/* harmony import */ var _util_TimeoutError__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(65);
-/* harmony import */ var _timeoutWith__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(513);
+/* harmony import */ var _timeoutWith__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(514);
/* harmony import */ var _observable_throwError__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(50);
/** PURE_IMPORTS_START _scheduler_async,_util_TimeoutError,_timeoutWith,_observable_throwError PURE_IMPORTS_END */
@@ -58075,7 +58142,7 @@ function timeout(due, scheduler) {
/***/ }),
-/* 513 */
+/* 514 */
/***/ (function(module, __webpack_exports__, __webpack_require__) {
"use strict";
@@ -58083,7 +58150,7 @@ __webpack_require__.r(__webpack_exports__);
/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "timeoutWith", function() { return timeoutWith; });
/* harmony import */ var tslib__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(13);
/* harmony import */ var _scheduler_async__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(56);
-/* harmony import */ var _util_isDate__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(445);
+/* harmony import */ var _util_isDate__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(446);
/* harmony import */ var _innerSubscribe__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(91);
/** PURE_IMPORTS_START tslib,_scheduler_async,_util_isDate,_innerSubscribe PURE_IMPORTS_END */
@@ -58154,7 +58221,7 @@ var TimeoutWithSubscriber = /*@__PURE__*/ (function (_super) {
/***/ }),
-/* 514 */
+/* 515 */
/***/ (function(module, __webpack_exports__, __webpack_require__) {
"use strict";
@@ -58184,13 +58251,13 @@ var Timestamp = /*@__PURE__*/ (function () {
/***/ }),
-/* 515 */
+/* 516 */
/***/ (function(module, __webpack_exports__, __webpack_require__) {
"use strict";
__webpack_require__.r(__webpack_exports__);
/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "toArray", function() { return toArray; });
-/* harmony import */ var _reduce__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(470);
+/* harmony import */ var _reduce__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(471);
/** PURE_IMPORTS_START _reduce PURE_IMPORTS_END */
function toArrayReducer(arr, item, index) {
@@ -58207,7 +58274,7 @@ function toArray() {
/***/ }),
-/* 516 */
+/* 517 */
/***/ (function(module, __webpack_exports__, __webpack_require__) {
"use strict";
@@ -58285,7 +58352,7 @@ var WindowSubscriber = /*@__PURE__*/ (function (_super) {
/***/ }),
-/* 517 */
+/* 518 */
/***/ (function(module, __webpack_exports__, __webpack_require__) {
"use strict";
@@ -58375,7 +58442,7 @@ var WindowCountSubscriber = /*@__PURE__*/ (function (_super) {
/***/ }),
-/* 518 */
+/* 519 */
/***/ (function(module, __webpack_exports__, __webpack_require__) {
"use strict";
@@ -58545,7 +58612,7 @@ function dispatchWindowClose(state) {
/***/ }),
-/* 519 */
+/* 520 */
/***/ (function(module, __webpack_exports__, __webpack_require__) {
"use strict";
@@ -58688,7 +58755,7 @@ var WindowToggleSubscriber = /*@__PURE__*/ (function (_super) {
/***/ }),
-/* 520 */
+/* 521 */
/***/ (function(module, __webpack_exports__, __webpack_require__) {
"use strict";
@@ -58785,7 +58852,7 @@ var WindowSubscriber = /*@__PURE__*/ (function (_super) {
/***/ }),
-/* 521 */
+/* 522 */
/***/ (function(module, __webpack_exports__, __webpack_require__) {
"use strict";
@@ -58880,7 +58947,7 @@ var WithLatestFromSubscriber = /*@__PURE__*/ (function (_super) {
/***/ }),
-/* 522 */
+/* 523 */
/***/ (function(module, __webpack_exports__, __webpack_require__) {
"use strict";
@@ -58902,7 +58969,7 @@ function zip() {
/***/ }),
-/* 523 */
+/* 524 */
/***/ (function(module, __webpack_exports__, __webpack_require__) {
"use strict";
@@ -58918,7 +58985,7 @@ function zipAll(project) {
/***/ }),
-/* 524 */
+/* 525 */
/***/ (function(module, exports, __webpack_require__) {
"use strict";
@@ -58928,7 +58995,7 @@ Object.defineProperty(exports, "__esModule", {
value: true
});
-var _observe_lines = __webpack_require__(525);
+var _observe_lines = __webpack_require__(526);
Object.keys(_observe_lines).forEach(function (key) {
if (key === "default" || key === "__esModule") return;
@@ -58941,7 +59008,7 @@ Object.keys(_observe_lines).forEach(function (key) {
});
});
-var _observe_readable = __webpack_require__(526);
+var _observe_readable = __webpack_require__(527);
Object.keys(_observe_readable).forEach(function (key) {
if (key === "default" || key === "__esModule") return;
@@ -58955,7 +59022,7 @@ Object.keys(_observe_readable).forEach(function (key) {
});
/***/ }),
-/* 525 */
+/* 526 */
/***/ (function(module, exports, __webpack_require__) {
"use strict";
@@ -58968,9 +59035,9 @@ exports.observeLines = observeLines;
var Rx = _interopRequireWildcard(__webpack_require__(9));
-var _operators = __webpack_require__(426);
+var _operators = __webpack_require__(427);
-var _observe_readable = __webpack_require__(526);
+var _observe_readable = __webpack_require__(527);
function _getRequireWildcardCache(nodeInterop) { if (typeof WeakMap !== "function") return null; var cacheBabelInterop = new WeakMap(); var cacheNodeInterop = new WeakMap(); return (_getRequireWildcardCache = function (nodeInterop) { return nodeInterop ? cacheNodeInterop : cacheBabelInterop; })(nodeInterop); }
@@ -59033,7 +59100,7 @@ function observeLines(readable) {
}
/***/ }),
-/* 526 */
+/* 527 */
/***/ (function(module, exports, __webpack_require__) {
"use strict";
@@ -59046,7 +59113,7 @@ exports.observeReadable = observeReadable;
var Rx = _interopRequireWildcard(__webpack_require__(9));
-var _operators = __webpack_require__(426);
+var _operators = __webpack_require__(427);
function _getRequireWildcardCache(nodeInterop) { if (typeof WeakMap !== "function") return null; var cacheBabelInterop = new WeakMap(); var cacheNodeInterop = new WeakMap(); return (_getRequireWildcardCache = function (nodeInterop) { return nodeInterop ? cacheNodeInterop : cacheBabelInterop; })(nodeInterop); }
@@ -59070,7 +59137,7 @@ function observeReadable(readable) {
}
/***/ }),
-/* 527 */
+/* 528 */
/***/ (function(module, __webpack_exports__, __webpack_require__) {
"use strict";
@@ -59173,13 +59240,13 @@ async function setupRemoteCache(repoRootPath) {
}
/***/ }),
-/* 528 */
+/* 529 */
/***/ (function(module, __webpack_exports__, __webpack_require__) {
"use strict";
__webpack_require__.r(__webpack_exports__);
/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "BuildCommand", function() { return BuildCommand; });
-/* harmony import */ var _utils_bazel__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(421);
+/* harmony import */ var _utils_bazel__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(422);
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License
@@ -59207,7 +59274,7 @@ const BuildCommand = {
};
/***/ }),
-/* 529 */
+/* 530 */
/***/ (function(module, __webpack_exports__, __webpack_require__) {
"use strict";
@@ -59217,11 +59284,11 @@ __webpack_require__.r(__webpack_exports__);
/* harmony import */ var dedent__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(dedent__WEBPACK_IMPORTED_MODULE_0__);
/* harmony import */ var del__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(240);
/* harmony import */ var del__WEBPACK_IMPORTED_MODULE_1___default = /*#__PURE__*/__webpack_require__.n(del__WEBPACK_IMPORTED_MODULE_1__);
-/* harmony import */ var ora__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(530);
+/* harmony import */ var ora__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(531);
/* harmony import */ var ora__WEBPACK_IMPORTED_MODULE_2___default = /*#__PURE__*/__webpack_require__.n(ora__WEBPACK_IMPORTED_MODULE_2__);
/* harmony import */ var path__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(4);
/* harmony import */ var path__WEBPACK_IMPORTED_MODULE_3___default = /*#__PURE__*/__webpack_require__.n(path__WEBPACK_IMPORTED_MODULE_3__);
-/* harmony import */ var _utils_bazel__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(421);
+/* harmony import */ var _utils_bazel__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(422);
/* harmony import */ var _utils_fs__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__(231);
/* harmony import */ var _utils_log__WEBPACK_IMPORTED_MODULE_6__ = __webpack_require__(220);
/*
@@ -59324,20 +59391,20 @@ const CleanCommand = {
};
/***/ }),
-/* 530 */
+/* 531 */
/***/ (function(module, exports, __webpack_require__) {
"use strict";
-const readline = __webpack_require__(531);
-const chalk = __webpack_require__(532);
-const cliCursor = __webpack_require__(535);
-const cliSpinners = __webpack_require__(537);
-const logSymbols = __webpack_require__(539);
-const stripAnsi = __webpack_require__(545);
-const wcwidth = __webpack_require__(547);
-const isInteractive = __webpack_require__(551);
-const MuteStream = __webpack_require__(552);
+const readline = __webpack_require__(532);
+const chalk = __webpack_require__(533);
+const cliCursor = __webpack_require__(536);
+const cliSpinners = __webpack_require__(538);
+const logSymbols = __webpack_require__(540);
+const stripAnsi = __webpack_require__(546);
+const wcwidth = __webpack_require__(548);
+const isInteractive = __webpack_require__(552);
+const MuteStream = __webpack_require__(553);
const TEXT = Symbol('text');
const PREFIX_TEXT = Symbol('prefixText');
@@ -59690,13 +59757,13 @@ module.exports.promise = (action, options) => {
/***/ }),
-/* 531 */
+/* 532 */
/***/ (function(module, exports) {
module.exports = require("readline");
/***/ }),
-/* 532 */
+/* 533 */
/***/ (function(module, exports, __webpack_require__) {
"use strict";
@@ -59706,7 +59773,7 @@ const {stdout: stdoutColor, stderr: stderrColor} = __webpack_require__(121);
const {
stringReplaceAll,
stringEncaseCRLFWithFirstIndex
-} = __webpack_require__(533);
+} = __webpack_require__(534);
// `supportsColor.level` → `ansiStyles.color[name]` mapping
const levelMapping = [
@@ -59907,7 +59974,7 @@ const chalkTag = (chalk, ...strings) => {
}
if (template === undefined) {
- template = __webpack_require__(534);
+ template = __webpack_require__(535);
}
return template(chalk, parts.join(''));
@@ -59936,7 +60003,7 @@ module.exports = chalk;
/***/ }),
-/* 533 */
+/* 534 */
/***/ (function(module, exports, __webpack_require__) {
"use strict";
@@ -59982,7 +60049,7 @@ module.exports = {
/***/ }),
-/* 534 */
+/* 535 */
/***/ (function(module, exports, __webpack_require__) {
"use strict";
@@ -60123,12 +60190,12 @@ module.exports = (chalk, temporary) => {
/***/ }),
-/* 535 */
+/* 536 */
/***/ (function(module, exports, __webpack_require__) {
"use strict";
-const restoreCursor = __webpack_require__(536);
+const restoreCursor = __webpack_require__(537);
let isHidden = false;
@@ -60165,7 +60232,7 @@ exports.toggle = (force, writableStream) => {
/***/ }),
-/* 536 */
+/* 537 */
/***/ (function(module, exports, __webpack_require__) {
"use strict";
@@ -60181,13 +60248,13 @@ module.exports = onetime(() => {
/***/ }),
-/* 537 */
+/* 538 */
/***/ (function(module, exports, __webpack_require__) {
"use strict";
-const spinners = Object.assign({}, __webpack_require__(538));
+const spinners = Object.assign({}, __webpack_require__(539));
const spinnersList = Object.keys(spinners);
@@ -60205,18 +60272,18 @@ module.exports.default = spinners;
/***/ }),
-/* 538 */
+/* 539 */
/***/ (function(module) {
module.exports = JSON.parse("{\"dots\":{\"interval\":80,\"frames\":[\"⠋\",\"⠙\",\"⠹\",\"⠸\",\"⠼\",\"⠴\",\"⠦\",\"⠧\",\"⠇\",\"⠏\"]},\"dots2\":{\"interval\":80,\"frames\":[\"⣾\",\"⣽\",\"⣻\",\"⢿\",\"⡿\",\"⣟\",\"⣯\",\"⣷\"]},\"dots3\":{\"interval\":80,\"frames\":[\"⠋\",\"⠙\",\"⠚\",\"⠞\",\"⠖\",\"⠦\",\"⠴\",\"⠲\",\"⠳\",\"⠓\"]},\"dots4\":{\"interval\":80,\"frames\":[\"⠄\",\"⠆\",\"⠇\",\"⠋\",\"⠙\",\"⠸\",\"⠰\",\"⠠\",\"⠰\",\"⠸\",\"⠙\",\"⠋\",\"⠇\",\"⠆\"]},\"dots5\":{\"interval\":80,\"frames\":[\"⠋\",\"⠙\",\"⠚\",\"⠒\",\"⠂\",\"⠂\",\"⠒\",\"⠲\",\"⠴\",\"⠦\",\"⠖\",\"⠒\",\"⠐\",\"⠐\",\"⠒\",\"⠓\",\"⠋\"]},\"dots6\":{\"interval\":80,\"frames\":[\"⠁\",\"⠉\",\"⠙\",\"⠚\",\"⠒\",\"⠂\",\"⠂\",\"⠒\",\"⠲\",\"⠴\",\"⠤\",\"⠄\",\"⠄\",\"⠤\",\"⠴\",\"⠲\",\"⠒\",\"⠂\",\"⠂\",\"⠒\",\"⠚\",\"⠙\",\"⠉\",\"⠁\"]},\"dots7\":{\"interval\":80,\"frames\":[\"⠈\",\"⠉\",\"⠋\",\"⠓\",\"⠒\",\"⠐\",\"⠐\",\"⠒\",\"⠖\",\"⠦\",\"⠤\",\"⠠\",\"⠠\",\"⠤\",\"⠦\",\"⠖\",\"⠒\",\"⠐\",\"⠐\",\"⠒\",\"⠓\",\"⠋\",\"⠉\",\"⠈\"]},\"dots8\":{\"interval\":80,\"frames\":[\"⠁\",\"⠁\",\"⠉\",\"⠙\",\"⠚\",\"⠒\",\"⠂\",\"⠂\",\"⠒\",\"⠲\",\"⠴\",\"⠤\",\"⠄\",\"⠄\",\"⠤\",\"⠠\",\"⠠\",\"⠤\",\"⠦\",\"⠖\",\"⠒\",\"⠐\",\"⠐\",\"⠒\",\"⠓\",\"⠋\",\"⠉\",\"⠈\",\"⠈\"]},\"dots9\":{\"interval\":80,\"frames\":[\"⢹\",\"⢺\",\"⢼\",\"⣸\",\"⣇\",\"⡧\",\"⡗\",\"⡏\"]},\"dots10\":{\"interval\":80,\"frames\":[\"⢄\",\"⢂\",\"⢁\",\"⡁\",\"⡈\",\"⡐\",\"⡠\"]},\"dots11\":{\"interval\":100,\"frames\":[\"⠁\",\"⠂\",\"⠄\",\"⡀\",\"⢀\",\"⠠\",\"⠐\",\"⠈\"]},\"dots12\":{\"interval\":80,\"frames\":[\"⢀⠀\",\"⡀⠀\",\"⠄⠀\",\"⢂⠀\",\"⡂⠀\",\"⠅⠀\",\"⢃⠀\",\"⡃⠀\",\"⠍⠀\",\"⢋⠀\",\"⡋⠀\",\"⠍⠁\",\"⢋⠁\",\"⡋⠁\",\"⠍⠉\",\"⠋⠉\",\"⠋⠉\",\"⠉⠙\",\"⠉⠙\",\"⠉⠩\",\"⠈⢙\",\"⠈⡙\",\"⢈⠩\",\"⡀⢙\",\"⠄⡙\",\"⢂⠩\",\"⡂⢘\",\"⠅⡘\",\"⢃⠨\",\"⡃⢐\",\"⠍⡐\",\"⢋⠠\",\"⡋⢀\",\"⠍⡁\",\"⢋⠁\",\"⡋⠁\",\"⠍⠉\",\"⠋⠉\",\"⠋⠉\",\"⠉⠙\",\"⠉⠙\",\"⠉⠩\",\"⠈⢙\",\"⠈⡙\",\"⠈⠩\",\"⠀⢙\",\"⠀⡙\",\"⠀⠩\",\"⠀⢘\",\"⠀⡘\",\"⠀⠨\",\"⠀⢐\",\"⠀⡐\",\"⠀⠠\",\"⠀⢀\",\"⠀⡀\"]},\"dots8Bit\":{\"interval\":80,\"frames\":[\"⠀\",\"⠁\",\"⠂\",\"⠃\",\"⠄\",\"⠅\",\"⠆\",\"⠇\",\"⡀\",\"⡁\",\"⡂\",\"⡃\",\"⡄\",\"⡅\",\"⡆\",\"⡇\",\"⠈\",\"⠉\",\"⠊\",\"⠋\",\"⠌\",\"⠍\",\"⠎\",\"⠏\",\"⡈\",\"⡉\",\"⡊\",\"⡋\",\"⡌\",\"⡍\",\"⡎\",\"⡏\",\"⠐\",\"⠑\",\"⠒\",\"⠓\",\"⠔\",\"⠕\",\"⠖\",\"⠗\",\"⡐\",\"⡑\",\"⡒\",\"⡓\",\"⡔\",\"⡕\",\"⡖\",\"⡗\",\"⠘\",\"⠙\",\"⠚\",\"⠛\",\"⠜\",\"⠝\",\"⠞\",\"⠟\",\"⡘\",\"⡙\",\"⡚\",\"⡛\",\"⡜\",\"⡝\",\"⡞\",\"⡟\",\"⠠\",\"⠡\",\"⠢\",\"⠣\",\"⠤\",\"⠥\",\"⠦\",\"⠧\",\"⡠\",\"⡡\",\"⡢\",\"⡣\",\"⡤\",\"⡥\",\"⡦\",\"⡧\",\"⠨\",\"⠩\",\"⠪\",\"⠫\",\"⠬\",\"⠭\",\"⠮\",\"⠯\",\"⡨\",\"⡩\",\"⡪\",\"⡫\",\"⡬\",\"⡭\",\"⡮\",\"⡯\",\"⠰\",\"⠱\",\"⠲\",\"⠳\",\"⠴\",\"⠵\",\"⠶\",\"⠷\",\"⡰\",\"⡱\",\"⡲\",\"⡳\",\"⡴\",\"⡵\",\"⡶\",\"⡷\",\"⠸\",\"⠹\",\"⠺\",\"⠻\",\"⠼\",\"⠽\",\"⠾\",\"⠿\",\"⡸\",\"⡹\",\"⡺\",\"⡻\",\"⡼\",\"⡽\",\"⡾\",\"⡿\",\"⢀\",\"⢁\",\"⢂\",\"⢃\",\"⢄\",\"⢅\",\"⢆\",\"⢇\",\"⣀\",\"⣁\",\"⣂\",\"⣃\",\"⣄\",\"⣅\",\"⣆\",\"⣇\",\"⢈\",\"⢉\",\"⢊\",\"⢋\",\"⢌\",\"⢍\",\"⢎\",\"⢏\",\"⣈\",\"⣉\",\"⣊\",\"⣋\",\"⣌\",\"⣍\",\"⣎\",\"⣏\",\"⢐\",\"⢑\",\"⢒\",\"⢓\",\"⢔\",\"⢕\",\"⢖\",\"⢗\",\"⣐\",\"⣑\",\"⣒\",\"⣓\",\"⣔\",\"⣕\",\"⣖\",\"⣗\",\"⢘\",\"⢙\",\"⢚\",\"⢛\",\"⢜\",\"⢝\",\"⢞\",\"⢟\",\"⣘\",\"⣙\",\"⣚\",\"⣛\",\"⣜\",\"⣝\",\"⣞\",\"⣟\",\"⢠\",\"⢡\",\"⢢\",\"⢣\",\"⢤\",\"⢥\",\"⢦\",\"⢧\",\"⣠\",\"⣡\",\"⣢\",\"⣣\",\"⣤\",\"⣥\",\"⣦\",\"⣧\",\"⢨\",\"⢩\",\"⢪\",\"⢫\",\"⢬\",\"⢭\",\"⢮\",\"⢯\",\"⣨\",\"⣩\",\"⣪\",\"⣫\",\"⣬\",\"⣭\",\"⣮\",\"⣯\",\"⢰\",\"⢱\",\"⢲\",\"⢳\",\"⢴\",\"⢵\",\"⢶\",\"⢷\",\"⣰\",\"⣱\",\"⣲\",\"⣳\",\"⣴\",\"⣵\",\"⣶\",\"⣷\",\"⢸\",\"⢹\",\"⢺\",\"⢻\",\"⢼\",\"⢽\",\"⢾\",\"⢿\",\"⣸\",\"⣹\",\"⣺\",\"⣻\",\"⣼\",\"⣽\",\"⣾\",\"⣿\"]},\"line\":{\"interval\":130,\"frames\":[\"-\",\"\\\\\",\"|\",\"/\"]},\"line2\":{\"interval\":100,\"frames\":[\"⠂\",\"-\",\"–\",\"—\",\"–\",\"-\"]},\"pipe\":{\"interval\":100,\"frames\":[\"┤\",\"┘\",\"┴\",\"└\",\"├\",\"┌\",\"┬\",\"┐\"]},\"simpleDots\":{\"interval\":400,\"frames\":[\". \",\".. \",\"...\",\" \"]},\"simpleDotsScrolling\":{\"interval\":200,\"frames\":[\". \",\".. \",\"...\",\" ..\",\" .\",\" \"]},\"star\":{\"interval\":70,\"frames\":[\"✶\",\"✸\",\"✹\",\"✺\",\"✹\",\"✷\"]},\"star2\":{\"interval\":80,\"frames\":[\"+\",\"x\",\"*\"]},\"flip\":{\"interval\":70,\"frames\":[\"_\",\"_\",\"_\",\"-\",\"`\",\"`\",\"'\",\"´\",\"-\",\"_\",\"_\",\"_\"]},\"hamburger\":{\"interval\":100,\"frames\":[\"☱\",\"☲\",\"☴\"]},\"growVertical\":{\"interval\":120,\"frames\":[\"▁\",\"▃\",\"▄\",\"▅\",\"▆\",\"▇\",\"▆\",\"▅\",\"▄\",\"▃\"]},\"growHorizontal\":{\"interval\":120,\"frames\":[\"▏\",\"▎\",\"▍\",\"▌\",\"▋\",\"▊\",\"▉\",\"▊\",\"▋\",\"▌\",\"▍\",\"▎\"]},\"balloon\":{\"interval\":140,\"frames\":[\" \",\".\",\"o\",\"O\",\"@\",\"*\",\" \"]},\"balloon2\":{\"interval\":120,\"frames\":[\".\",\"o\",\"O\",\"°\",\"O\",\"o\",\".\"]},\"noise\":{\"interval\":100,\"frames\":[\"▓\",\"▒\",\"░\"]},\"bounce\":{\"interval\":120,\"frames\":[\"⠁\",\"⠂\",\"⠄\",\"⠂\"]},\"boxBounce\":{\"interval\":120,\"frames\":[\"▖\",\"▘\",\"▝\",\"▗\"]},\"boxBounce2\":{\"interval\":100,\"frames\":[\"▌\",\"▀\",\"▐\",\"▄\"]},\"triangle\":{\"interval\":50,\"frames\":[\"◢\",\"◣\",\"◤\",\"◥\"]},\"arc\":{\"interval\":100,\"frames\":[\"◜\",\"◠\",\"◝\",\"◞\",\"◡\",\"◟\"]},\"circle\":{\"interval\":120,\"frames\":[\"◡\",\"⊙\",\"◠\"]},\"squareCorners\":{\"interval\":180,\"frames\":[\"◰\",\"◳\",\"◲\",\"◱\"]},\"circleQuarters\":{\"interval\":120,\"frames\":[\"◴\",\"◷\",\"◶\",\"◵\"]},\"circleHalves\":{\"interval\":50,\"frames\":[\"◐\",\"◓\",\"◑\",\"◒\"]},\"squish\":{\"interval\":100,\"frames\":[\"╫\",\"╪\"]},\"toggle\":{\"interval\":250,\"frames\":[\"⊶\",\"⊷\"]},\"toggle2\":{\"interval\":80,\"frames\":[\"▫\",\"▪\"]},\"toggle3\":{\"interval\":120,\"frames\":[\"□\",\"■\"]},\"toggle4\":{\"interval\":100,\"frames\":[\"■\",\"□\",\"▪\",\"▫\"]},\"toggle5\":{\"interval\":100,\"frames\":[\"▮\",\"▯\"]},\"toggle6\":{\"interval\":300,\"frames\":[\"ဝ\",\"၀\"]},\"toggle7\":{\"interval\":80,\"frames\":[\"⦾\",\"⦿\"]},\"toggle8\":{\"interval\":100,\"frames\":[\"◍\",\"◌\"]},\"toggle9\":{\"interval\":100,\"frames\":[\"◉\",\"◎\"]},\"toggle10\":{\"interval\":100,\"frames\":[\"㊂\",\"㊀\",\"㊁\"]},\"toggle11\":{\"interval\":50,\"frames\":[\"⧇\",\"⧆\"]},\"toggle12\":{\"interval\":120,\"frames\":[\"☗\",\"☖\"]},\"toggle13\":{\"interval\":80,\"frames\":[\"=\",\"*\",\"-\"]},\"arrow\":{\"interval\":100,\"frames\":[\"←\",\"↖\",\"↑\",\"↗\",\"→\",\"↘\",\"↓\",\"↙\"]},\"arrow2\":{\"interval\":80,\"frames\":[\"⬆️ \",\"↗️ \",\"➡️ \",\"↘️ \",\"⬇️ \",\"↙️ \",\"⬅️ \",\"↖️ \"]},\"arrow3\":{\"interval\":120,\"frames\":[\"▹▹▹▹▹\",\"▸▹▹▹▹\",\"▹▸▹▹▹\",\"▹▹▸▹▹\",\"▹▹▹▸▹\",\"▹▹▹▹▸\"]},\"bouncingBar\":{\"interval\":80,\"frames\":[\"[ ]\",\"[= ]\",\"[== ]\",\"[=== ]\",\"[ ===]\",\"[ ==]\",\"[ =]\",\"[ ]\",\"[ =]\",\"[ ==]\",\"[ ===]\",\"[====]\",\"[=== ]\",\"[== ]\",\"[= ]\"]},\"bouncingBall\":{\"interval\":80,\"frames\":[\"( ● )\",\"( ● )\",\"( ● )\",\"( ● )\",\"( ●)\",\"( ● )\",\"( ● )\",\"( ● )\",\"( ● )\",\"(● )\"]},\"smiley\":{\"interval\":200,\"frames\":[\"😄 \",\"😝 \"]},\"monkey\":{\"interval\":300,\"frames\":[\"🙈 \",\"🙈 \",\"🙉 \",\"🙊 \"]},\"hearts\":{\"interval\":100,\"frames\":[\"💛 \",\"💙 \",\"💜 \",\"💚 \",\"❤️ \"]},\"clock\":{\"interval\":100,\"frames\":[\"🕛 \",\"🕐 \",\"🕑 \",\"🕒 \",\"🕓 \",\"🕔 \",\"🕕 \",\"🕖 \",\"🕗 \",\"🕘 \",\"🕙 \",\"🕚 \"]},\"earth\":{\"interval\":180,\"frames\":[\"🌍 \",\"🌎 \",\"🌏 \"]},\"material\":{\"interval\":17,\"frames\":[\"█▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁\",\"██▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁\",\"███▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁\",\"████▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁\",\"██████▁▁▁▁▁▁▁▁▁▁▁▁▁▁\",\"██████▁▁▁▁▁▁▁▁▁▁▁▁▁▁\",\"███████▁▁▁▁▁▁▁▁▁▁▁▁▁\",\"████████▁▁▁▁▁▁▁▁▁▁▁▁\",\"█████████▁▁▁▁▁▁▁▁▁▁▁\",\"█████████▁▁▁▁▁▁▁▁▁▁▁\",\"██████████▁▁▁▁▁▁▁▁▁▁\",\"███████████▁▁▁▁▁▁▁▁▁\",\"█████████████▁▁▁▁▁▁▁\",\"██████████████▁▁▁▁▁▁\",\"██████████████▁▁▁▁▁▁\",\"▁██████████████▁▁▁▁▁\",\"▁██████████████▁▁▁▁▁\",\"▁██████████████▁▁▁▁▁\",\"▁▁██████████████▁▁▁▁\",\"▁▁▁██████████████▁▁▁\",\"▁▁▁▁█████████████▁▁▁\",\"▁▁▁▁██████████████▁▁\",\"▁▁▁▁██████████████▁▁\",\"▁▁▁▁▁██████████████▁\",\"▁▁▁▁▁██████████████▁\",\"▁▁▁▁▁██████████████▁\",\"▁▁▁▁▁▁██████████████\",\"▁▁▁▁▁▁██████████████\",\"▁▁▁▁▁▁▁█████████████\",\"▁▁▁▁▁▁▁█████████████\",\"▁▁▁▁▁▁▁▁████████████\",\"▁▁▁▁▁▁▁▁████████████\",\"▁▁▁▁▁▁▁▁▁███████████\",\"▁▁▁▁▁▁▁▁▁███████████\",\"▁▁▁▁▁▁▁▁▁▁██████████\",\"▁▁▁▁▁▁▁▁▁▁██████████\",\"▁▁▁▁▁▁▁▁▁▁▁▁████████\",\"▁▁▁▁▁▁▁▁▁▁▁▁▁███████\",\"▁▁▁▁▁▁▁▁▁▁▁▁▁▁██████\",\"▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁█████\",\"▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁█████\",\"█▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁████\",\"██▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁███\",\"██▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁███\",\"███▁▁▁▁▁▁▁▁▁▁▁▁▁▁███\",\"████▁▁▁▁▁▁▁▁▁▁▁▁▁▁██\",\"█████▁▁▁▁▁▁▁▁▁▁▁▁▁▁█\",\"█████▁▁▁▁▁▁▁▁▁▁▁▁▁▁█\",\"██████▁▁▁▁▁▁▁▁▁▁▁▁▁█\",\"████████▁▁▁▁▁▁▁▁▁▁▁▁\",\"█████████▁▁▁▁▁▁▁▁▁▁▁\",\"█████████▁▁▁▁▁▁▁▁▁▁▁\",\"█████████▁▁▁▁▁▁▁▁▁▁▁\",\"█████████▁▁▁▁▁▁▁▁▁▁▁\",\"███████████▁▁▁▁▁▁▁▁▁\",\"████████████▁▁▁▁▁▁▁▁\",\"████████████▁▁▁▁▁▁▁▁\",\"██████████████▁▁▁▁▁▁\",\"██████████████▁▁▁▁▁▁\",\"▁██████████████▁▁▁▁▁\",\"▁██████████████▁▁▁▁▁\",\"▁▁▁█████████████▁▁▁▁\",\"▁▁▁▁▁████████████▁▁▁\",\"▁▁▁▁▁████████████▁▁▁\",\"▁▁▁▁▁▁███████████▁▁▁\",\"▁▁▁▁▁▁▁▁█████████▁▁▁\",\"▁▁▁▁▁▁▁▁█████████▁▁▁\",\"▁▁▁▁▁▁▁▁▁█████████▁▁\",\"▁▁▁▁▁▁▁▁▁█████████▁▁\",\"▁▁▁▁▁▁▁▁▁▁█████████▁\",\"▁▁▁▁▁▁▁▁▁▁▁████████▁\",\"▁▁▁▁▁▁▁▁▁▁▁████████▁\",\"▁▁▁▁▁▁▁▁▁▁▁▁███████▁\",\"▁▁▁▁▁▁▁▁▁▁▁▁███████▁\",\"▁▁▁▁▁▁▁▁▁▁▁▁▁███████\",\"▁▁▁▁▁▁▁▁▁▁▁▁▁███████\",\"▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁█████\",\"▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁████\",\"▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁████\",\"▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁████\",\"▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁███\",\"▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁███\",\"▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁██\",\"▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁██\",\"▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁██\",\"▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁█\",\"▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁█\",\"▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁█\",\"▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁\",\"▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁\",\"▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁\",\"▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁\"]},\"moon\":{\"interval\":80,\"frames\":[\"🌑 \",\"🌒 \",\"🌓 \",\"🌔 \",\"🌕 \",\"🌖 \",\"🌗 \",\"🌘 \"]},\"runner\":{\"interval\":140,\"frames\":[\"🚶 \",\"🏃 \"]},\"pong\":{\"interval\":80,\"frames\":[\"▐⠂ ▌\",\"▐⠈ ▌\",\"▐ ⠂ ▌\",\"▐ ⠠ ▌\",\"▐ ⡀ ▌\",\"▐ ⠠ ▌\",\"▐ ⠂ ▌\",\"▐ ⠈ ▌\",\"▐ ⠂ ▌\",\"▐ ⠠ ▌\",\"▐ ⡀ ▌\",\"▐ ⠠ ▌\",\"▐ ⠂ ▌\",\"▐ ⠈ ▌\",\"▐ ⠂▌\",\"▐ ⠠▌\",\"▐ ⡀▌\",\"▐ ⠠ ▌\",\"▐ ⠂ ▌\",\"▐ ⠈ ▌\",\"▐ ⠂ ▌\",\"▐ ⠠ ▌\",\"▐ ⡀ ▌\",\"▐ ⠠ ▌\",\"▐ ⠂ ▌\",\"▐ ⠈ ▌\",\"▐ ⠂ ▌\",\"▐ ⠠ ▌\",\"▐ ⡀ ▌\",\"▐⠠ ▌\"]},\"shark\":{\"interval\":120,\"frames\":[\"▐|\\\\____________▌\",\"▐_|\\\\___________▌\",\"▐__|\\\\__________▌\",\"▐___|\\\\_________▌\",\"▐____|\\\\________▌\",\"▐_____|\\\\_______▌\",\"▐______|\\\\______▌\",\"▐_______|\\\\_____▌\",\"▐________|\\\\____▌\",\"▐_________|\\\\___▌\",\"▐__________|\\\\__▌\",\"▐___________|\\\\_▌\",\"▐____________|\\\\▌\",\"▐____________/|▌\",\"▐___________/|_▌\",\"▐__________/|__▌\",\"▐_________/|___▌\",\"▐________/|____▌\",\"▐_______/|_____▌\",\"▐______/|______▌\",\"▐_____/|_______▌\",\"▐____/|________▌\",\"▐___/|_________▌\",\"▐__/|__________▌\",\"▐_/|___________▌\",\"▐/|____________▌\"]},\"dqpb\":{\"interval\":100,\"frames\":[\"d\",\"q\",\"p\",\"b\"]},\"weather\":{\"interval\":100,\"frames\":[\"☀️ \",\"☀️ \",\"☀️ \",\"🌤 \",\"⛅️ \",\"🌥 \",\"☁️ \",\"🌧 \",\"🌨 \",\"🌧 \",\"🌨 \",\"🌧 \",\"🌨 \",\"⛈ \",\"🌨 \",\"🌧 \",\"🌨 \",\"☁️ \",\"🌥 \",\"⛅️ \",\"🌤 \",\"☀️ \",\"☀️ \"]},\"christmas\":{\"interval\":400,\"frames\":[\"🌲\",\"🎄\"]},\"grenade\":{\"interval\":80,\"frames\":[\"، \",\"′ \",\" ´ \",\" ‾ \",\" ⸌\",\" ⸊\",\" |\",\" ⁎\",\" ⁕\",\" ෴ \",\" ⁓\",\" \",\" \",\" \"]},\"point\":{\"interval\":125,\"frames\":[\"∙∙∙\",\"●∙∙\",\"∙●∙\",\"∙∙●\",\"∙∙∙\"]},\"layer\":{\"interval\":150,\"frames\":[\"-\",\"=\",\"≡\"]},\"betaWave\":{\"interval\":80,\"frames\":[\"ρββββββ\",\"βρβββββ\",\"ββρββββ\",\"βββρβββ\",\"ββββρββ\",\"βββββρβ\",\"ββββββρ\"]},\"aesthetic\":{\"interval\":80,\"frames\":[\"▰▱▱▱▱▱▱\",\"▰▰▱▱▱▱▱\",\"▰▰▰▱▱▱▱\",\"▰▰▰▰▱▱▱\",\"▰▰▰▰▰▱▱\",\"▰▰▰▰▰▰▱\",\"▰▰▰▰▰▰▰\",\"▰▱▱▱▱▱▱\"]}}");
/***/ }),
-/* 539 */
+/* 540 */
/***/ (function(module, exports, __webpack_require__) {
"use strict";
-const chalk = __webpack_require__(540);
+const chalk = __webpack_require__(541);
const isSupported = process.platform !== 'win32' || process.env.CI || process.env.TERM === 'xterm-256color';
@@ -60238,16 +60305,16 @@ module.exports = isSupported ? main : fallbacks;
/***/ }),
-/* 540 */
+/* 541 */
/***/ (function(module, exports, __webpack_require__) {
"use strict";
const escapeStringRegexp = __webpack_require__(357);
-const ansiStyles = __webpack_require__(541);
-const stdoutColor = __webpack_require__(542).stdout;
+const ansiStyles = __webpack_require__(542);
+const stdoutColor = __webpack_require__(543).stdout;
-const template = __webpack_require__(544);
+const template = __webpack_require__(545);
const isSimpleWindowsTerm = process.platform === 'win32' && !(process.env.TERM || '').toLowerCase().startsWith('xterm');
@@ -60473,7 +60540,7 @@ module.exports.default = module.exports; // For TypeScript
/***/ }),
-/* 541 */
+/* 542 */
/***/ (function(module, exports, __webpack_require__) {
"use strict";
@@ -60646,13 +60713,13 @@ Object.defineProperty(module, 'exports', {
/* WEBPACK VAR INJECTION */}.call(this, __webpack_require__(116)(module)))
/***/ }),
-/* 542 */
+/* 543 */
/***/ (function(module, exports, __webpack_require__) {
"use strict";
const os = __webpack_require__(122);
-const hasFlag = __webpack_require__(543);
+const hasFlag = __webpack_require__(544);
const env = process.env;
@@ -60784,7 +60851,7 @@ module.exports = {
/***/ }),
-/* 543 */
+/* 544 */
/***/ (function(module, exports, __webpack_require__) {
"use strict";
@@ -60799,7 +60866,7 @@ module.exports = (flag, argv) => {
/***/ }),
-/* 544 */
+/* 545 */
/***/ (function(module, exports, __webpack_require__) {
"use strict";
@@ -60934,18 +61001,18 @@ module.exports = (chalk, tmp) => {
/***/ }),
-/* 545 */
+/* 546 */
/***/ (function(module, exports, __webpack_require__) {
"use strict";
-const ansiRegex = __webpack_require__(546);
+const ansiRegex = __webpack_require__(547);
module.exports = string => typeof string === 'string' ? string.replace(ansiRegex(), '') : string;
/***/ }),
-/* 546 */
+/* 547 */
/***/ (function(module, exports, __webpack_require__) {
"use strict";
@@ -60962,14 +61029,14 @@ module.exports = ({onlyFirst = false} = {}) => {
/***/ }),
-/* 547 */
+/* 548 */
/***/ (function(module, exports, __webpack_require__) {
"use strict";
-var defaults = __webpack_require__(548)
-var combining = __webpack_require__(550)
+var defaults = __webpack_require__(549)
+var combining = __webpack_require__(551)
var DEFAULTS = {
nul: 0,
@@ -61068,10 +61135,10 @@ function bisearch(ucs) {
/***/ }),
-/* 548 */
+/* 549 */
/***/ (function(module, exports, __webpack_require__) {
-var clone = __webpack_require__(549);
+var clone = __webpack_require__(550);
module.exports = function(options, defaults) {
options = options || {};
@@ -61086,7 +61153,7 @@ module.exports = function(options, defaults) {
};
/***/ }),
-/* 549 */
+/* 550 */
/***/ (function(module, exports, __webpack_require__) {
var clone = (function() {
@@ -61258,7 +61325,7 @@ if ( true && module.exports) {
/***/ }),
-/* 550 */
+/* 551 */
/***/ (function(module, exports) {
module.exports = [
@@ -61314,7 +61381,7 @@ module.exports = [
/***/ }),
-/* 551 */
+/* 552 */
/***/ (function(module, exports, __webpack_require__) {
"use strict";
@@ -61330,7 +61397,7 @@ module.exports = ({stream = process.stdout} = {}) => {
/***/ }),
-/* 552 */
+/* 553 */
/***/ (function(module, exports, __webpack_require__) {
var Stream = __webpack_require__(173)
@@ -61481,7 +61548,7 @@ MuteStream.prototype.close = proxy('close')
/***/ }),
-/* 553 */
+/* 554 */
/***/ (function(module, __webpack_exports__, __webpack_require__) {
"use strict";
@@ -61491,11 +61558,11 @@ __webpack_require__.r(__webpack_exports__);
/* harmony import */ var dedent__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(dedent__WEBPACK_IMPORTED_MODULE_0__);
/* harmony import */ var del__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(240);
/* harmony import */ var del__WEBPACK_IMPORTED_MODULE_1___default = /*#__PURE__*/__webpack_require__.n(del__WEBPACK_IMPORTED_MODULE_1__);
-/* harmony import */ var ora__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(530);
+/* harmony import */ var ora__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(531);
/* harmony import */ var ora__WEBPACK_IMPORTED_MODULE_2___default = /*#__PURE__*/__webpack_require__.n(ora__WEBPACK_IMPORTED_MODULE_2__);
/* harmony import */ var path__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(4);
/* harmony import */ var path__WEBPACK_IMPORTED_MODULE_3___default = /*#__PURE__*/__webpack_require__.n(path__WEBPACK_IMPORTED_MODULE_3__);
-/* harmony import */ var _utils_bazel__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(421);
+/* harmony import */ var _utils_bazel__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(422);
/* harmony import */ var _utils_fs__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__(231);
/* harmony import */ var _utils_log__WEBPACK_IMPORTED_MODULE_6__ = __webpack_require__(220);
/*
@@ -61604,7 +61671,7 @@ const ResetCommand = {
};
/***/ }),
-/* 554 */
+/* 555 */
/***/ (function(module, __webpack_exports__, __webpack_require__) {
"use strict";
@@ -61614,7 +61681,7 @@ __webpack_require__.r(__webpack_exports__);
/* harmony import */ var dedent__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(dedent__WEBPACK_IMPORTED_MODULE_0__);
/* harmony import */ var _utils_errors__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(341);
/* harmony import */ var _utils_log__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(220);
-/* harmony import */ var _utils_parallelize__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(555);
+/* harmony import */ var _utils_parallelize__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(556);
/* harmony import */ var _utils_projects__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(340);
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
@@ -61673,7 +61740,7 @@ const RunCommand = {
};
/***/ }),
-/* 555 */
+/* 556 */
/***/ (function(module, __webpack_exports__, __webpack_require__) {
"use strict";
@@ -61728,13 +61795,13 @@ async function parallelize(items, fn, concurrency = 4) {
}
/***/ }),
-/* 556 */
+/* 557 */
/***/ (function(module, __webpack_exports__, __webpack_require__) {
"use strict";
__webpack_require__.r(__webpack_exports__);
/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "WatchCommand", function() { return WatchCommand; });
-/* harmony import */ var _utils_bazel__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(421);
+/* harmony import */ var _utils_bazel__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(422);
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License
@@ -61764,86 +61831,6 @@ const WatchCommand = {
};
-/***/ }),
-/* 557 */
-/***/ (function(module, __webpack_exports__, __webpack_require__) {
-
-"use strict";
-__webpack_require__.r(__webpack_exports__);
-/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "PatchNativeModulesCommand", function() { return PatchNativeModulesCommand; });
-/* harmony import */ var path__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(4);
-/* harmony import */ var path__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(path__WEBPACK_IMPORTED_MODULE_0__);
-/* harmony import */ var fs__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(132);
-/* harmony import */ var fs__WEBPACK_IMPORTED_MODULE_1___default = /*#__PURE__*/__webpack_require__.n(fs__WEBPACK_IMPORTED_MODULE_1__);
-/* harmony import */ var _kbn_dev_utils_ci_stats_reporter__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(131);
-/* harmony import */ var _kbn_dev_utils_ci_stats_reporter__WEBPACK_IMPORTED_MODULE_2___default = /*#__PURE__*/__webpack_require__.n(_kbn_dev_utils_ci_stats_reporter__WEBPACK_IMPORTED_MODULE_2__);
-/* harmony import */ var _utils_log__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(220);
-/* harmony import */ var _utils_child_process__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(221);
-/*
- * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
- * or more contributor license agreements. Licensed under the Elastic License
- * 2.0 and the Server Side Public License, v 1; you may not use this file except
- * in compliance with, at your election, the Elastic License 2.0 or the Server
- * Side Public License, v 1.
- */
-
-
-
-
-
-const PatchNativeModulesCommand = {
- description: 'Patch native modules by running build commands on M1 Macs',
- name: 'patch_native_modules',
-
- async run(projects, _, {
- kbn
- }) {
- var _projects$get;
-
- const kibanaProjectPath = ((_projects$get = projects.get('kibana')) === null || _projects$get === void 0 ? void 0 : _projects$get.path) || '';
- const reporter = _kbn_dev_utils_ci_stats_reporter__WEBPACK_IMPORTED_MODULE_2__["CiStatsReporter"].fromEnv(_utils_log__WEBPACK_IMPORTED_MODULE_3__["log"]);
-
- if (process.platform !== 'darwin' || process.arch !== 'arm64') {
- return;
- }
-
- const startTime = Date.now();
- const nodeSassDir = path__WEBPACK_IMPORTED_MODULE_0___default.a.resolve(kibanaProjectPath, 'node_modules/node-sass');
- const nodeSassNativeDist = path__WEBPACK_IMPORTED_MODULE_0___default.a.resolve(nodeSassDir, `vendor/darwin-arm64-${process.versions.modules}/binding.node`);
-
- if (!fs__WEBPACK_IMPORTED_MODULE_1___default.a.existsSync(nodeSassNativeDist)) {
- _utils_log__WEBPACK_IMPORTED_MODULE_3__["log"].info('Running build script for node-sass');
- await Object(_utils_child_process__WEBPACK_IMPORTED_MODULE_4__["spawn"])('npm', ['run', 'build'], {
- cwd: nodeSassDir
- });
- }
-
- const re2Dir = path__WEBPACK_IMPORTED_MODULE_0___default.a.resolve(kibanaProjectPath, 'node_modules/re2');
- const re2NativeDist = path__WEBPACK_IMPORTED_MODULE_0___default.a.resolve(re2Dir, 'build/Release/re2.node');
-
- if (!fs__WEBPACK_IMPORTED_MODULE_1___default.a.existsSync(re2NativeDist)) {
- _utils_log__WEBPACK_IMPORTED_MODULE_3__["log"].info('Running build script for re2');
- await Object(_utils_child_process__WEBPACK_IMPORTED_MODULE_4__["spawn"])('npm', ['run', 'rebuild'], {
- cwd: re2Dir
- });
- }
-
- _utils_log__WEBPACK_IMPORTED_MODULE_3__["log"].success('native modules should be setup for native ARM Mac development'); // send timings
-
- await reporter.timings({
- upstreamBranch: kbn.kibanaProject.json.branch,
- // prevent loading @kbn/utils by passing null
- kibanaUuid: kbn.getUuid() || null,
- timings: [{
- group: 'scripts/kbn bootstrap',
- id: 'patch native modudles for arm macs',
- ms: Date.now() - startTime
- }]
- });
- }
-
-};
-
/***/ }),
/* 558 */
/***/ (function(module, __webpack_exports__, __webpack_require__) {
@@ -61856,7 +61843,7 @@ __webpack_require__.r(__webpack_exports__);
/* harmony import */ var _utils_errors__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(341);
/* harmony import */ var _utils_log__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(220);
/* harmony import */ var _utils_projects__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(340);
-/* harmony import */ var _utils_projects_tree__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(420);
+/* harmony import */ var _utils_projects_tree__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(421);
/* harmony import */ var _utils_kibana__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__(559);
function ownKeys(object, enumerableOnly) { var keys = Object.keys(object); if (Object.getOwnPropertySymbols) { var symbols = Object.getOwnPropertySymbols(object); enumerableOnly && (symbols = symbols.filter(function (sym) { return Object.getOwnPropertyDescriptor(object, sym).enumerable; })), keys.push.apply(keys, symbols); } return keys; }
@@ -62301,7 +62288,7 @@ __webpack_require__.r(__webpack_exports__);
/* harmony import */ var _build_bazel_production_projects__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(565);
/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "buildBazelProductionProjects", function() { return _build_bazel_production_projects__WEBPACK_IMPORTED_MODULE_0__["buildBazelProductionProjects"]; });
-/* harmony import */ var _build_non_bazel_production_projects__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(812);
+/* harmony import */ var _build_non_bazel_production_projects__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(806);
/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "buildNonBazelProductionProjects", function() { return _build_non_bazel_production_projects__WEBPACK_IMPORTED_MODULE_1__["buildNonBazelProductionProjects"]; });
/*
@@ -62327,8 +62314,8 @@ __webpack_require__.r(__webpack_exports__);
/* harmony import */ var globby__WEBPACK_IMPORTED_MODULE_1___default = /*#__PURE__*/__webpack_require__.n(globby__WEBPACK_IMPORTED_MODULE_1__);
/* harmony import */ var path__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(4);
/* harmony import */ var path__WEBPACK_IMPORTED_MODULE_2___default = /*#__PURE__*/__webpack_require__.n(path__WEBPACK_IMPORTED_MODULE_2__);
-/* harmony import */ var _build_non_bazel_production_projects__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(812);
-/* harmony import */ var _utils_bazel__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(421);
+/* harmony import */ var _build_non_bazel_production_projects__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(806);
+/* harmony import */ var _utils_bazel__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(422);
/* harmony import */ var _utils_fs__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__(231);
/* harmony import */ var _utils_log__WEBPACK_IMPORTED_MODULE_6__ = __webpack_require__(220);
/* harmony import */ var _utils_package_json__WEBPACK_IMPORTED_MODULE_7__ = __webpack_require__(343);
@@ -88979,8 +88966,8 @@ const arrayUnion = __webpack_require__(242);
const merge2 = __webpack_require__(243);
const fastGlob = __webpack_require__(779);
const dirGlob = __webpack_require__(326);
-const gitignore = __webpack_require__(810);
-const {FilterStream, UniqueStream} = __webpack_require__(811);
+const gitignore = __webpack_require__(804);
+const {FilterStream, UniqueStream} = __webpack_require__(805);
const DEFAULT_FILTER = () => false;
@@ -89163,10 +89150,10 @@ module.exports.gitignore = gitignore;
"use strict";
const taskManager = __webpack_require__(780);
-const async_1 = __webpack_require__(796);
-const stream_1 = __webpack_require__(806);
-const sync_1 = __webpack_require__(807);
-const settings_1 = __webpack_require__(809);
+const async_1 = __webpack_require__(790);
+const stream_1 = __webpack_require__(800);
+const sync_1 = __webpack_require__(801);
+const settings_1 = __webpack_require__(803);
const utils = __webpack_require__(781);
async function FastGlob(source, options) {
assertPatternsInput(source);
@@ -89335,9 +89322,9 @@ const path = __webpack_require__(785);
exports.path = path;
const pattern = __webpack_require__(786);
exports.pattern = pattern;
-const stream = __webpack_require__(794);
+const stream = __webpack_require__(788);
exports.stream = stream;
-const string = __webpack_require__(795);
+const string = __webpack_require__(789);
exports.string = string;
@@ -89623,8 +89610,8 @@ exports.matchAny = matchAny;
const util = __webpack_require__(113);
const braces = __webpack_require__(269);
-const picomatch = __webpack_require__(788);
-const utils = __webpack_require__(791);
+const picomatch = __webpack_require__(279);
+const utils = __webpack_require__(282);
const isEmptyString = val => val === '' || val === './';
/**
@@ -90094,8 +90081,22 @@ module.exports = micromatch;
"use strict";
-
-module.exports = __webpack_require__(789);
+Object.defineProperty(exports, "__esModule", { value: true });
+exports.merge = void 0;
+const merge2 = __webpack_require__(243);
+function merge(streams) {
+ const mergedStream = merge2(streams);
+ streams.forEach((stream) => {
+ stream.once('error', (error) => mergedStream.emit('error', error));
+ });
+ mergedStream.once('close', () => propagateCloseEventToSources(streams));
+ mergedStream.once('end', () => propagateCloseEventToSources(streams));
+ return mergedStream;
+}
+exports.merge = merge;
+function propagateCloseEventToSources(streams) {
+ streams.forEach((stream) => stream.emit('close'));
+}
/***/ }),
@@ -90104,2286 +90105,167 @@ module.exports = __webpack_require__(789);
"use strict";
+Object.defineProperty(exports, "__esModule", { value: true });
+exports.isEmpty = exports.isString = void 0;
+function isString(input) {
+ return typeof input === 'string';
+}
+exports.isString = isString;
+function isEmpty(input) {
+ return input === '';
+}
+exports.isEmpty = isEmpty;
-const path = __webpack_require__(4);
-const scan = __webpack_require__(790);
-const parse = __webpack_require__(793);
-const utils = __webpack_require__(791);
-const constants = __webpack_require__(792);
-const isObject = val => val && typeof val === 'object' && !Array.isArray(val);
-
-/**
- * Creates a matcher function from one or more glob patterns. The
- * returned function takes a string to match as its first argument,
- * and returns true if the string is a match. The returned matcher
- * function also takes a boolean as the second argument that, when true,
- * returns an object with additional information.
- *
- * ```js
- * const picomatch = require('picomatch');
- * // picomatch(glob[, options]);
- *
- * const isMatch = picomatch('*.!(*a)');
- * console.log(isMatch('a.a')); //=> false
- * console.log(isMatch('a.b')); //=> true
- * ```
- * @name picomatch
- * @param {String|Array} `globs` One or more glob patterns.
- * @param {Object=} `options`
- * @return {Function=} Returns a matcher function.
- * @api public
- */
-
-const picomatch = (glob, options, returnState = false) => {
- if (Array.isArray(glob)) {
- const fns = glob.map(input => picomatch(input, options, returnState));
- const arrayMatcher = str => {
- for (const isMatch of fns) {
- const state = isMatch(str);
- if (state) return state;
- }
- return false;
- };
- return arrayMatcher;
- }
- const isState = isObject(glob) && glob.tokens && glob.input;
+/***/ }),
+/* 790 */
+/***/ (function(module, exports, __webpack_require__) {
- if (glob === '' || (typeof glob !== 'string' && !isState)) {
- throw new TypeError('Expected pattern to be a non-empty string');
- }
+"use strict";
- const opts = options || {};
- const posix = utils.isWindows(options);
- const regex = isState
- ? picomatch.compileRe(glob, options)
- : picomatch.makeRe(glob, options, false, true);
+Object.defineProperty(exports, "__esModule", { value: true });
+const stream_1 = __webpack_require__(791);
+const provider_1 = __webpack_require__(793);
+class ProviderAsync extends provider_1.default {
+ constructor() {
+ super(...arguments);
+ this._reader = new stream_1.default(this._settings);
+ }
+ read(task) {
+ const root = this._getRootDirectory(task);
+ const options = this._getReaderOptions(task);
+ const entries = [];
+ return new Promise((resolve, reject) => {
+ const stream = this.api(root, task, options);
+ stream.once('error', reject);
+ stream.on('data', (entry) => entries.push(options.transform(entry)));
+ stream.once('end', () => resolve(entries));
+ });
+ }
+ api(root, task, options) {
+ if (task.dynamic) {
+ return this._reader.dynamic(root, options);
+ }
+ return this._reader.static(task.patterns, options);
+ }
+}
+exports.default = ProviderAsync;
- const state = regex.state;
- delete regex.state;
- let isIgnored = () => false;
- if (opts.ignore) {
- const ignoreOpts = { ...options, ignore: null, onMatch: null, onResult: null };
- isIgnored = picomatch(opts.ignore, ignoreOpts, returnState);
- }
+/***/ }),
+/* 791 */
+/***/ (function(module, exports, __webpack_require__) {
- const matcher = (input, returnObject = false) => {
- const { isMatch, match, output } = picomatch.test(input, regex, options, { glob, posix });
- const result = { glob, state, regex, posix, input, output, match, isMatch };
+"use strict";
- if (typeof opts.onResult === 'function') {
- opts.onResult(result);
+Object.defineProperty(exports, "__esModule", { value: true });
+const stream_1 = __webpack_require__(173);
+const fsStat = __webpack_require__(289);
+const fsWalk = __webpack_require__(294);
+const reader_1 = __webpack_require__(792);
+class ReaderStream extends reader_1.default {
+ constructor() {
+ super(...arguments);
+ this._walkStream = fsWalk.walkStream;
+ this._stat = fsStat.stat;
}
-
- if (isMatch === false) {
- result.isMatch = false;
- return returnObject ? result : false;
+ dynamic(root, options) {
+ return this._walkStream(root, options);
}
-
- if (isIgnored(input)) {
- if (typeof opts.onIgnore === 'function') {
- opts.onIgnore(result);
- }
- result.isMatch = false;
- return returnObject ? result : false;
+ static(patterns, options) {
+ const filepaths = patterns.map(this._getFullEntryPath, this);
+ const stream = new stream_1.PassThrough({ objectMode: true });
+ stream._write = (index, _enc, done) => {
+ return this._getEntry(filepaths[index], patterns[index], options)
+ .then((entry) => {
+ if (entry !== null && options.entryFilter(entry)) {
+ stream.push(entry);
+ }
+ if (index === filepaths.length - 1) {
+ stream.end();
+ }
+ done();
+ })
+ .catch(done);
+ };
+ for (let i = 0; i < filepaths.length; i++) {
+ stream.write(i);
+ }
+ return stream;
}
-
- if (typeof opts.onMatch === 'function') {
- opts.onMatch(result);
+ _getEntry(filepath, pattern, options) {
+ return this._getStat(filepath)
+ .then((stats) => this._makeEntry(stats, pattern))
+ .catch((error) => {
+ if (options.errorFilter(error)) {
+ return null;
+ }
+ throw error;
+ });
}
- return returnObject ? result : true;
- };
+ _getStat(filepath) {
+ return new Promise((resolve, reject) => {
+ this._stat(filepath, this._fsStatSettings, (error, stats) => {
+ return error === null ? resolve(stats) : reject(error);
+ });
+ });
+ }
+}
+exports.default = ReaderStream;
- if (returnState) {
- matcher.state = state;
- }
- return matcher;
-};
+/***/ }),
+/* 792 */
+/***/ (function(module, exports, __webpack_require__) {
-/**
- * Test `input` with the given `regex`. This is used by the main
- * `picomatch()` function to test the input string.
- *
- * ```js
- * const picomatch = require('picomatch');
- * // picomatch.test(input, regex[, options]);
- *
- * console.log(picomatch.test('foo/bar', /^(?:([^/]*?)\/([^/]*?))$/));
- * // { isMatch: true, match: [ 'foo/', 'foo', 'bar' ], output: 'foo/bar' }
- * ```
- * @param {String} `input` String to test.
- * @param {RegExp} `regex`
- * @return {Object} Returns an object with matching info.
- * @api public
- */
+"use strict";
-picomatch.test = (input, regex, options, { glob, posix } = {}) => {
- if (typeof input !== 'string') {
- throw new TypeError('Expected input to be a string');
- }
+Object.defineProperty(exports, "__esModule", { value: true });
+const path = __webpack_require__(4);
+const fsStat = __webpack_require__(289);
+const utils = __webpack_require__(781);
+class Reader {
+ constructor(_settings) {
+ this._settings = _settings;
+ this._fsStatSettings = new fsStat.Settings({
+ followSymbolicLink: this._settings.followSymbolicLinks,
+ fs: this._settings.fs,
+ throwErrorOnBrokenSymbolicLink: this._settings.followSymbolicLinks
+ });
+ }
+ _getFullEntryPath(filepath) {
+ return path.resolve(this._settings.cwd, filepath);
+ }
+ _makeEntry(stats, pattern) {
+ const entry = {
+ name: pattern,
+ path: pattern,
+ dirent: utils.fs.createDirentFromStats(pattern, stats)
+ };
+ if (this._settings.stats) {
+ entry.stats = stats;
+ }
+ return entry;
+ }
+ _isFatalError(error) {
+ return !utils.errno.isEnoentCodeError(error) && !this._settings.suppressErrors;
+ }
+}
+exports.default = Reader;
- if (input === '') {
- return { isMatch: false, output: '' };
- }
- const opts = options || {};
- const format = opts.format || (posix ? utils.toPosixSlashes : null);
- let match = input === glob;
- let output = (match && format) ? format(input) : input;
+/***/ }),
+/* 793 */
+/***/ (function(module, exports, __webpack_require__) {
- if (match === false) {
- output = format ? format(input) : input;
- match = output === glob;
- }
-
- if (match === false || opts.capture === true) {
- if (opts.matchBase === true || opts.basename === true) {
- match = picomatch.matchBase(input, regex, options, posix);
- } else {
- match = regex.exec(output);
- }
- }
-
- return { isMatch: Boolean(match), match, output };
-};
-
-/**
- * Match the basename of a filepath.
- *
- * ```js
- * const picomatch = require('picomatch');
- * // picomatch.matchBase(input, glob[, options]);
- * console.log(picomatch.matchBase('foo/bar.js', '*.js'); // true
- * ```
- * @param {String} `input` String to test.
- * @param {RegExp|String} `glob` Glob pattern or regex created by [.makeRe](#makeRe).
- * @return {Boolean}
- * @api public
- */
-
-picomatch.matchBase = (input, glob, options, posix = utils.isWindows(options)) => {
- const regex = glob instanceof RegExp ? glob : picomatch.makeRe(glob, options);
- return regex.test(path.basename(input));
-};
-
-/**
- * Returns true if **any** of the given glob `patterns` match the specified `string`.
- *
- * ```js
- * const picomatch = require('picomatch');
- * // picomatch.isMatch(string, patterns[, options]);
- *
- * console.log(picomatch.isMatch('a.a', ['b.*', '*.a'])); //=> true
- * console.log(picomatch.isMatch('a.a', 'b.*')); //=> false
- * ```
- * @param {String|Array} str The string to test.
- * @param {String|Array} patterns One or more glob patterns to use for matching.
- * @param {Object} [options] See available [options](#options).
- * @return {Boolean} Returns true if any patterns match `str`
- * @api public
- */
-
-picomatch.isMatch = (str, patterns, options) => picomatch(patterns, options)(str);
-
-/**
- * Parse a glob pattern to create the source string for a regular
- * expression.
- *
- * ```js
- * const picomatch = require('picomatch');
- * const result = picomatch.parse(pattern[, options]);
- * ```
- * @param {String} `pattern`
- * @param {Object} `options`
- * @return {Object} Returns an object with useful properties and output to be used as a regex source string.
- * @api public
- */
-
-picomatch.parse = (pattern, options) => {
- if (Array.isArray(pattern)) return pattern.map(p => picomatch.parse(p, options));
- return parse(pattern, { ...options, fastpaths: false });
-};
-
-/**
- * Scan a glob pattern to separate the pattern into segments.
- *
- * ```js
- * const picomatch = require('picomatch');
- * // picomatch.scan(input[, options]);
- *
- * const result = picomatch.scan('!./foo/*.js');
- * console.log(result);
- * { prefix: '!./',
- * input: '!./foo/*.js',
- * start: 3,
- * base: 'foo',
- * glob: '*.js',
- * isBrace: false,
- * isBracket: false,
- * isGlob: true,
- * isExtglob: false,
- * isGlobstar: false,
- * negated: true }
- * ```
- * @param {String} `input` Glob pattern to scan.
- * @param {Object} `options`
- * @return {Object} Returns an object with
- * @api public
- */
-
-picomatch.scan = (input, options) => scan(input, options);
-
-/**
- * Compile a regular expression from the `state` object returned by the
- * [parse()](#parse) method.
- *
- * @param {Object} `state`
- * @param {Object} `options`
- * @param {Boolean} `returnOutput` Intended for implementors, this argument allows you to return the raw output from the parser.
- * @param {Boolean} `returnState` Adds the state to a `state` property on the returned regex. Useful for implementors and debugging.
- * @return {RegExp}
- * @api public
- */
-
-picomatch.compileRe = (state, options, returnOutput = false, returnState = false) => {
- if (returnOutput === true) {
- return state.output;
- }
-
- const opts = options || {};
- const prepend = opts.contains ? '' : '^';
- const append = opts.contains ? '' : '$';
-
- let source = `${prepend}(?:${state.output})${append}`;
- if (state && state.negated === true) {
- source = `^(?!${source}).*$`;
- }
-
- const regex = picomatch.toRegex(source, options);
- if (returnState === true) {
- regex.state = state;
- }
-
- return regex;
-};
-
-/**
- * Create a regular expression from a parsed glob pattern.
- *
- * ```js
- * const picomatch = require('picomatch');
- * const state = picomatch.parse('*.js');
- * // picomatch.compileRe(state[, options]);
- *
- * console.log(picomatch.compileRe(state));
- * //=> /^(?:(?!\.)(?=.)[^/]*?\.js)$/
- * ```
- * @param {String} `state` The object returned from the `.parse` method.
- * @param {Object} `options`
- * @param {Boolean} `returnOutput` Implementors may use this argument to return the compiled output, instead of a regular expression. This is not exposed on the options to prevent end-users from mutating the result.
- * @param {Boolean} `returnState` Implementors may use this argument to return the state from the parsed glob with the returned regular expression.
- * @return {RegExp} Returns a regex created from the given pattern.
- * @api public
- */
-
-picomatch.makeRe = (input, options = {}, returnOutput = false, returnState = false) => {
- if (!input || typeof input !== 'string') {
- throw new TypeError('Expected a non-empty string');
- }
-
- let parsed = { negated: false, fastpaths: true };
-
- if (options.fastpaths !== false && (input[0] === '.' || input[0] === '*')) {
- parsed.output = parse.fastpaths(input, options);
- }
-
- if (!parsed.output) {
- parsed = parse(input, options);
- }
-
- return picomatch.compileRe(parsed, options, returnOutput, returnState);
-};
-
-/**
- * Create a regular expression from the given regex source string.
- *
- * ```js
- * const picomatch = require('picomatch');
- * // picomatch.toRegex(source[, options]);
- *
- * const { output } = picomatch.parse('*.js');
- * console.log(picomatch.toRegex(output));
- * //=> /^(?:(?!\.)(?=.)[^/]*?\.js)$/
- * ```
- * @param {String} `source` Regular expression source string.
- * @param {Object} `options`
- * @return {RegExp}
- * @api public
- */
-
-picomatch.toRegex = (source, options) => {
- try {
- const opts = options || {};
- return new RegExp(source, opts.flags || (opts.nocase ? 'i' : ''));
- } catch (err) {
- if (options && options.debug === true) throw err;
- return /$^/;
- }
-};
-
-/**
- * Picomatch constants.
- * @return {Object}
- */
-
-picomatch.constants = constants;
-
-/**
- * Expose "picomatch"
- */
-
-module.exports = picomatch;
-
-
-/***/ }),
-/* 790 */
-/***/ (function(module, exports, __webpack_require__) {
-
-"use strict";
-
-
-const utils = __webpack_require__(791);
-const {
- CHAR_ASTERISK, /* * */
- CHAR_AT, /* @ */
- CHAR_BACKWARD_SLASH, /* \ */
- CHAR_COMMA, /* , */
- CHAR_DOT, /* . */
- CHAR_EXCLAMATION_MARK, /* ! */
- CHAR_FORWARD_SLASH, /* / */
- CHAR_LEFT_CURLY_BRACE, /* { */
- CHAR_LEFT_PARENTHESES, /* ( */
- CHAR_LEFT_SQUARE_BRACKET, /* [ */
- CHAR_PLUS, /* + */
- CHAR_QUESTION_MARK, /* ? */
- CHAR_RIGHT_CURLY_BRACE, /* } */
- CHAR_RIGHT_PARENTHESES, /* ) */
- CHAR_RIGHT_SQUARE_BRACKET /* ] */
-} = __webpack_require__(792);
-
-const isPathSeparator = code => {
- return code === CHAR_FORWARD_SLASH || code === CHAR_BACKWARD_SLASH;
-};
-
-const depth = token => {
- if (token.isPrefix !== true) {
- token.depth = token.isGlobstar ? Infinity : 1;
- }
-};
-
-/**
- * Quickly scans a glob pattern and returns an object with a handful of
- * useful properties, like `isGlob`, `path` (the leading non-glob, if it exists),
- * `glob` (the actual pattern), `negated` (true if the path starts with `!` but not
- * with `!(`) and `negatedExtglob` (true if the path starts with `!(`).
- *
- * ```js
- * const pm = require('picomatch');
- * console.log(pm.scan('foo/bar/*.js'));
- * { isGlob: true, input: 'foo/bar/*.js', base: 'foo/bar', glob: '*.js' }
- * ```
- * @param {String} `str`
- * @param {Object} `options`
- * @return {Object} Returns an object with tokens and regex source string.
- * @api public
- */
-
-const scan = (input, options) => {
- const opts = options || {};
-
- const length = input.length - 1;
- const scanToEnd = opts.parts === true || opts.scanToEnd === true;
- const slashes = [];
- const tokens = [];
- const parts = [];
-
- let str = input;
- let index = -1;
- let start = 0;
- let lastIndex = 0;
- let isBrace = false;
- let isBracket = false;
- let isGlob = false;
- let isExtglob = false;
- let isGlobstar = false;
- let braceEscaped = false;
- let backslashes = false;
- let negated = false;
- let negatedExtglob = false;
- let finished = false;
- let braces = 0;
- let prev;
- let code;
- let token = { value: '', depth: 0, isGlob: false };
-
- const eos = () => index >= length;
- const peek = () => str.charCodeAt(index + 1);
- const advance = () => {
- prev = code;
- return str.charCodeAt(++index);
- };
-
- while (index < length) {
- code = advance();
- let next;
-
- if (code === CHAR_BACKWARD_SLASH) {
- backslashes = token.backslashes = true;
- code = advance();
-
- if (code === CHAR_LEFT_CURLY_BRACE) {
- braceEscaped = true;
- }
- continue;
- }
-
- if (braceEscaped === true || code === CHAR_LEFT_CURLY_BRACE) {
- braces++;
-
- while (eos() !== true && (code = advance())) {
- if (code === CHAR_BACKWARD_SLASH) {
- backslashes = token.backslashes = true;
- advance();
- continue;
- }
-
- if (code === CHAR_LEFT_CURLY_BRACE) {
- braces++;
- continue;
- }
-
- if (braceEscaped !== true && code === CHAR_DOT && (code = advance()) === CHAR_DOT) {
- isBrace = token.isBrace = true;
- isGlob = token.isGlob = true;
- finished = true;
-
- if (scanToEnd === true) {
- continue;
- }
-
- break;
- }
-
- if (braceEscaped !== true && code === CHAR_COMMA) {
- isBrace = token.isBrace = true;
- isGlob = token.isGlob = true;
- finished = true;
-
- if (scanToEnd === true) {
- continue;
- }
-
- break;
- }
-
- if (code === CHAR_RIGHT_CURLY_BRACE) {
- braces--;
-
- if (braces === 0) {
- braceEscaped = false;
- isBrace = token.isBrace = true;
- finished = true;
- break;
- }
- }
- }
-
- if (scanToEnd === true) {
- continue;
- }
-
- break;
- }
-
- if (code === CHAR_FORWARD_SLASH) {
- slashes.push(index);
- tokens.push(token);
- token = { value: '', depth: 0, isGlob: false };
-
- if (finished === true) continue;
- if (prev === CHAR_DOT && index === (start + 1)) {
- start += 2;
- continue;
- }
-
- lastIndex = index + 1;
- continue;
- }
-
- if (opts.noext !== true) {
- const isExtglobChar = code === CHAR_PLUS
- || code === CHAR_AT
- || code === CHAR_ASTERISK
- || code === CHAR_QUESTION_MARK
- || code === CHAR_EXCLAMATION_MARK;
-
- if (isExtglobChar === true && peek() === CHAR_LEFT_PARENTHESES) {
- isGlob = token.isGlob = true;
- isExtglob = token.isExtglob = true;
- finished = true;
- if (code === CHAR_EXCLAMATION_MARK && index === start) {
- negatedExtglob = true;
- }
-
- if (scanToEnd === true) {
- while (eos() !== true && (code = advance())) {
- if (code === CHAR_BACKWARD_SLASH) {
- backslashes = token.backslashes = true;
- code = advance();
- continue;
- }
-
- if (code === CHAR_RIGHT_PARENTHESES) {
- isGlob = token.isGlob = true;
- finished = true;
- break;
- }
- }
- continue;
- }
- break;
- }
- }
-
- if (code === CHAR_ASTERISK) {
- if (prev === CHAR_ASTERISK) isGlobstar = token.isGlobstar = true;
- isGlob = token.isGlob = true;
- finished = true;
-
- if (scanToEnd === true) {
- continue;
- }
- break;
- }
-
- if (code === CHAR_QUESTION_MARK) {
- isGlob = token.isGlob = true;
- finished = true;
-
- if (scanToEnd === true) {
- continue;
- }
- break;
- }
-
- if (code === CHAR_LEFT_SQUARE_BRACKET) {
- while (eos() !== true && (next = advance())) {
- if (next === CHAR_BACKWARD_SLASH) {
- backslashes = token.backslashes = true;
- advance();
- continue;
- }
-
- if (next === CHAR_RIGHT_SQUARE_BRACKET) {
- isBracket = token.isBracket = true;
- isGlob = token.isGlob = true;
- finished = true;
- break;
- }
- }
-
- if (scanToEnd === true) {
- continue;
- }
-
- break;
- }
-
- if (opts.nonegate !== true && code === CHAR_EXCLAMATION_MARK && index === start) {
- negated = token.negated = true;
- start++;
- continue;
- }
-
- if (opts.noparen !== true && code === CHAR_LEFT_PARENTHESES) {
- isGlob = token.isGlob = true;
-
- if (scanToEnd === true) {
- while (eos() !== true && (code = advance())) {
- if (code === CHAR_LEFT_PARENTHESES) {
- backslashes = token.backslashes = true;
- code = advance();
- continue;
- }
-
- if (code === CHAR_RIGHT_PARENTHESES) {
- finished = true;
- break;
- }
- }
- continue;
- }
- break;
- }
-
- if (isGlob === true) {
- finished = true;
-
- if (scanToEnd === true) {
- continue;
- }
-
- break;
- }
- }
-
- if (opts.noext === true) {
- isExtglob = false;
- isGlob = false;
- }
-
- let base = str;
- let prefix = '';
- let glob = '';
-
- if (start > 0) {
- prefix = str.slice(0, start);
- str = str.slice(start);
- lastIndex -= start;
- }
-
- if (base && isGlob === true && lastIndex > 0) {
- base = str.slice(0, lastIndex);
- glob = str.slice(lastIndex);
- } else if (isGlob === true) {
- base = '';
- glob = str;
- } else {
- base = str;
- }
-
- if (base && base !== '' && base !== '/' && base !== str) {
- if (isPathSeparator(base.charCodeAt(base.length - 1))) {
- base = base.slice(0, -1);
- }
- }
-
- if (opts.unescape === true) {
- if (glob) glob = utils.removeBackslashes(glob);
-
- if (base && backslashes === true) {
- base = utils.removeBackslashes(base);
- }
- }
-
- const state = {
- prefix,
- input,
- start,
- base,
- glob,
- isBrace,
- isBracket,
- isGlob,
- isExtglob,
- isGlobstar,
- negated,
- negatedExtglob
- };
-
- if (opts.tokens === true) {
- state.maxDepth = 0;
- if (!isPathSeparator(code)) {
- tokens.push(token);
- }
- state.tokens = tokens;
- }
-
- if (opts.parts === true || opts.tokens === true) {
- let prevIndex;
-
- for (let idx = 0; idx < slashes.length; idx++) {
- const n = prevIndex ? prevIndex + 1 : start;
- const i = slashes[idx];
- const value = input.slice(n, i);
- if (opts.tokens) {
- if (idx === 0 && start !== 0) {
- tokens[idx].isPrefix = true;
- tokens[idx].value = prefix;
- } else {
- tokens[idx].value = value;
- }
- depth(tokens[idx]);
- state.maxDepth += tokens[idx].depth;
- }
- if (idx !== 0 || value !== '') {
- parts.push(value);
- }
- prevIndex = i;
- }
-
- if (prevIndex && prevIndex + 1 < input.length) {
- const value = input.slice(prevIndex + 1);
- parts.push(value);
-
- if (opts.tokens) {
- tokens[tokens.length - 1].value = value;
- depth(tokens[tokens.length - 1]);
- state.maxDepth += tokens[tokens.length - 1].depth;
- }
- }
-
- state.slashes = slashes;
- state.parts = parts;
- }
-
- return state;
-};
-
-module.exports = scan;
-
-
-/***/ }),
-/* 791 */
-/***/ (function(module, exports, __webpack_require__) {
-
-"use strict";
-
-
-const path = __webpack_require__(4);
-const win32 = process.platform === 'win32';
-const {
- REGEX_BACKSLASH,
- REGEX_REMOVE_BACKSLASH,
- REGEX_SPECIAL_CHARS,
- REGEX_SPECIAL_CHARS_GLOBAL
-} = __webpack_require__(792);
-
-exports.isObject = val => val !== null && typeof val === 'object' && !Array.isArray(val);
-exports.hasRegexChars = str => REGEX_SPECIAL_CHARS.test(str);
-exports.isRegexChar = str => str.length === 1 && exports.hasRegexChars(str);
-exports.escapeRegex = str => str.replace(REGEX_SPECIAL_CHARS_GLOBAL, '\\$1');
-exports.toPosixSlashes = str => str.replace(REGEX_BACKSLASH, '/');
-
-exports.removeBackslashes = str => {
- return str.replace(REGEX_REMOVE_BACKSLASH, match => {
- return match === '\\' ? '' : match;
- });
-};
-
-exports.supportsLookbehinds = () => {
- const segs = process.version.slice(1).split('.').map(Number);
- if (segs.length === 3 && segs[0] >= 9 || (segs[0] === 8 && segs[1] >= 10)) {
- return true;
- }
- return false;
-};
-
-exports.isWindows = options => {
- if (options && typeof options.windows === 'boolean') {
- return options.windows;
- }
- return win32 === true || path.sep === '\\';
-};
-
-exports.escapeLast = (input, char, lastIdx) => {
- const idx = input.lastIndexOf(char, lastIdx);
- if (idx === -1) return input;
- if (input[idx - 1] === '\\') return exports.escapeLast(input, char, idx - 1);
- return `${input.slice(0, idx)}\\${input.slice(idx)}`;
-};
-
-exports.removePrefix = (input, state = {}) => {
- let output = input;
- if (output.startsWith('./')) {
- output = output.slice(2);
- state.prefix = './';
- }
- return output;
-};
-
-exports.wrapOutput = (input, state = {}, options = {}) => {
- const prepend = options.contains ? '' : '^';
- const append = options.contains ? '' : '$';
-
- let output = `${prepend}(?:${input})${append}`;
- if (state.negated === true) {
- output = `(?:^(?!${output}).*$)`;
- }
- return output;
-};
-
-
-/***/ }),
-/* 792 */
-/***/ (function(module, exports, __webpack_require__) {
-
-"use strict";
-
-
-const path = __webpack_require__(4);
-const WIN_SLASH = '\\\\/';
-const WIN_NO_SLASH = `[^${WIN_SLASH}]`;
-
-/**
- * Posix glob regex
- */
-
-const DOT_LITERAL = '\\.';
-const PLUS_LITERAL = '\\+';
-const QMARK_LITERAL = '\\?';
-const SLASH_LITERAL = '\\/';
-const ONE_CHAR = '(?=.)';
-const QMARK = '[^/]';
-const END_ANCHOR = `(?:${SLASH_LITERAL}|$)`;
-const START_ANCHOR = `(?:^|${SLASH_LITERAL})`;
-const DOTS_SLASH = `${DOT_LITERAL}{1,2}${END_ANCHOR}`;
-const NO_DOT = `(?!${DOT_LITERAL})`;
-const NO_DOTS = `(?!${START_ANCHOR}${DOTS_SLASH})`;
-const NO_DOT_SLASH = `(?!${DOT_LITERAL}{0,1}${END_ANCHOR})`;
-const NO_DOTS_SLASH = `(?!${DOTS_SLASH})`;
-const QMARK_NO_DOT = `[^.${SLASH_LITERAL}]`;
-const STAR = `${QMARK}*?`;
-
-const POSIX_CHARS = {
- DOT_LITERAL,
- PLUS_LITERAL,
- QMARK_LITERAL,
- SLASH_LITERAL,
- ONE_CHAR,
- QMARK,
- END_ANCHOR,
- DOTS_SLASH,
- NO_DOT,
- NO_DOTS,
- NO_DOT_SLASH,
- NO_DOTS_SLASH,
- QMARK_NO_DOT,
- STAR,
- START_ANCHOR
-};
-
-/**
- * Windows glob regex
- */
-
-const WINDOWS_CHARS = {
- ...POSIX_CHARS,
-
- SLASH_LITERAL: `[${WIN_SLASH}]`,
- QMARK: WIN_NO_SLASH,
- STAR: `${WIN_NO_SLASH}*?`,
- DOTS_SLASH: `${DOT_LITERAL}{1,2}(?:[${WIN_SLASH}]|$)`,
- NO_DOT: `(?!${DOT_LITERAL})`,
- NO_DOTS: `(?!(?:^|[${WIN_SLASH}])${DOT_LITERAL}{1,2}(?:[${WIN_SLASH}]|$))`,
- NO_DOT_SLASH: `(?!${DOT_LITERAL}{0,1}(?:[${WIN_SLASH}]|$))`,
- NO_DOTS_SLASH: `(?!${DOT_LITERAL}{1,2}(?:[${WIN_SLASH}]|$))`,
- QMARK_NO_DOT: `[^.${WIN_SLASH}]`,
- START_ANCHOR: `(?:^|[${WIN_SLASH}])`,
- END_ANCHOR: `(?:[${WIN_SLASH}]|$)`
-};
-
-/**
- * POSIX Bracket Regex
- */
-
-const POSIX_REGEX_SOURCE = {
- alnum: 'a-zA-Z0-9',
- alpha: 'a-zA-Z',
- ascii: '\\x00-\\x7F',
- blank: ' \\t',
- cntrl: '\\x00-\\x1F\\x7F',
- digit: '0-9',
- graph: '\\x21-\\x7E',
- lower: 'a-z',
- print: '\\x20-\\x7E ',
- punct: '\\-!"#$%&\'()\\*+,./:;<=>?@[\\]^_`{|}~',
- space: ' \\t\\r\\n\\v\\f',
- upper: 'A-Z',
- word: 'A-Za-z0-9_',
- xdigit: 'A-Fa-f0-9'
-};
-
-module.exports = {
- MAX_LENGTH: 1024 * 64,
- POSIX_REGEX_SOURCE,
-
- // regular expressions
- REGEX_BACKSLASH: /\\(?![*+?^${}(|)[\]])/g,
- REGEX_NON_SPECIAL_CHARS: /^[^@![\].,$*+?^{}()|\\/]+/,
- REGEX_SPECIAL_CHARS: /[-*+?.^${}(|)[\]]/,
- REGEX_SPECIAL_CHARS_BACKREF: /(\\?)((\W)(\3*))/g,
- REGEX_SPECIAL_CHARS_GLOBAL: /([-*+?.^${}(|)[\]])/g,
- REGEX_REMOVE_BACKSLASH: /(?:\[.*?[^\\]\]|\\(?=.))/g,
-
- // Replace globs with equivalent patterns to reduce parsing time.
- REPLACEMENTS: {
- '***': '*',
- '**/**': '**',
- '**/**/**': '**'
- },
-
- // Digits
- CHAR_0: 48, /* 0 */
- CHAR_9: 57, /* 9 */
-
- // Alphabet chars.
- CHAR_UPPERCASE_A: 65, /* A */
- CHAR_LOWERCASE_A: 97, /* a */
- CHAR_UPPERCASE_Z: 90, /* Z */
- CHAR_LOWERCASE_Z: 122, /* z */
-
- CHAR_LEFT_PARENTHESES: 40, /* ( */
- CHAR_RIGHT_PARENTHESES: 41, /* ) */
-
- CHAR_ASTERISK: 42, /* * */
-
- // Non-alphabetic chars.
- CHAR_AMPERSAND: 38, /* & */
- CHAR_AT: 64, /* @ */
- CHAR_BACKWARD_SLASH: 92, /* \ */
- CHAR_CARRIAGE_RETURN: 13, /* \r */
- CHAR_CIRCUMFLEX_ACCENT: 94, /* ^ */
- CHAR_COLON: 58, /* : */
- CHAR_COMMA: 44, /* , */
- CHAR_DOT: 46, /* . */
- CHAR_DOUBLE_QUOTE: 34, /* " */
- CHAR_EQUAL: 61, /* = */
- CHAR_EXCLAMATION_MARK: 33, /* ! */
- CHAR_FORM_FEED: 12, /* \f */
- CHAR_FORWARD_SLASH: 47, /* / */
- CHAR_GRAVE_ACCENT: 96, /* ` */
- CHAR_HASH: 35, /* # */
- CHAR_HYPHEN_MINUS: 45, /* - */
- CHAR_LEFT_ANGLE_BRACKET: 60, /* < */
- CHAR_LEFT_CURLY_BRACE: 123, /* { */
- CHAR_LEFT_SQUARE_BRACKET: 91, /* [ */
- CHAR_LINE_FEED: 10, /* \n */
- CHAR_NO_BREAK_SPACE: 160, /* \u00A0 */
- CHAR_PERCENT: 37, /* % */
- CHAR_PLUS: 43, /* + */
- CHAR_QUESTION_MARK: 63, /* ? */
- CHAR_RIGHT_ANGLE_BRACKET: 62, /* > */
- CHAR_RIGHT_CURLY_BRACE: 125, /* } */
- CHAR_RIGHT_SQUARE_BRACKET: 93, /* ] */
- CHAR_SEMICOLON: 59, /* ; */
- CHAR_SINGLE_QUOTE: 39, /* ' */
- CHAR_SPACE: 32, /* */
- CHAR_TAB: 9, /* \t */
- CHAR_UNDERSCORE: 95, /* _ */
- CHAR_VERTICAL_LINE: 124, /* | */
- CHAR_ZERO_WIDTH_NOBREAK_SPACE: 65279, /* \uFEFF */
-
- SEP: path.sep,
-
- /**
- * Create EXTGLOB_CHARS
- */
-
- extglobChars(chars) {
- return {
- '!': { type: 'negate', open: '(?:(?!(?:', close: `))${chars.STAR})` },
- '?': { type: 'qmark', open: '(?:', close: ')?' },
- '+': { type: 'plus', open: '(?:', close: ')+' },
- '*': { type: 'star', open: '(?:', close: ')*' },
- '@': { type: 'at', open: '(?:', close: ')' }
- };
- },
-
- /**
- * Create GLOB_CHARS
- */
-
- globChars(win32) {
- return win32 === true ? WINDOWS_CHARS : POSIX_CHARS;
- }
-};
-
-
-/***/ }),
-/* 793 */
-/***/ (function(module, exports, __webpack_require__) {
-
-"use strict";
-
-
-const constants = __webpack_require__(792);
-const utils = __webpack_require__(791);
-
-/**
- * Constants
- */
-
-const {
- MAX_LENGTH,
- POSIX_REGEX_SOURCE,
- REGEX_NON_SPECIAL_CHARS,
- REGEX_SPECIAL_CHARS_BACKREF,
- REPLACEMENTS
-} = constants;
-
-/**
- * Helpers
- */
-
-const expandRange = (args, options) => {
- if (typeof options.expandRange === 'function') {
- return options.expandRange(...args, options);
- }
-
- args.sort();
- const value = `[${args.join('-')}]`;
-
- try {
- /* eslint-disable-next-line no-new */
- new RegExp(value);
- } catch (ex) {
- return args.map(v => utils.escapeRegex(v)).join('..');
- }
-
- return value;
-};
-
-/**
- * Create the message for a syntax error
- */
-
-const syntaxError = (type, char) => {
- return `Missing ${type}: "${char}" - use "\\\\${char}" to match literal characters`;
-};
-
-/**
- * Parse the given input string.
- * @param {String} input
- * @param {Object} options
- * @return {Object}
- */
-
-const parse = (input, options) => {
- if (typeof input !== 'string') {
- throw new TypeError('Expected a string');
- }
-
- input = REPLACEMENTS[input] || input;
-
- const opts = { ...options };
- const max = typeof opts.maxLength === 'number' ? Math.min(MAX_LENGTH, opts.maxLength) : MAX_LENGTH;
-
- let len = input.length;
- if (len > max) {
- throw new SyntaxError(`Input length: ${len}, exceeds maximum allowed length: ${max}`);
- }
-
- const bos = { type: 'bos', value: '', output: opts.prepend || '' };
- const tokens = [bos];
-
- const capture = opts.capture ? '' : '?:';
- const win32 = utils.isWindows(options);
-
- // create constants based on platform, for windows or posix
- const PLATFORM_CHARS = constants.globChars(win32);
- const EXTGLOB_CHARS = constants.extglobChars(PLATFORM_CHARS);
-
- const {
- DOT_LITERAL,
- PLUS_LITERAL,
- SLASH_LITERAL,
- ONE_CHAR,
- DOTS_SLASH,
- NO_DOT,
- NO_DOT_SLASH,
- NO_DOTS_SLASH,
- QMARK,
- QMARK_NO_DOT,
- STAR,
- START_ANCHOR
- } = PLATFORM_CHARS;
-
- const globstar = opts => {
- return `(${capture}(?:(?!${START_ANCHOR}${opts.dot ? DOTS_SLASH : DOT_LITERAL}).)*?)`;
- };
-
- const nodot = opts.dot ? '' : NO_DOT;
- const qmarkNoDot = opts.dot ? QMARK : QMARK_NO_DOT;
- let star = opts.bash === true ? globstar(opts) : STAR;
-
- if (opts.capture) {
- star = `(${star})`;
- }
-
- // minimatch options support
- if (typeof opts.noext === 'boolean') {
- opts.noextglob = opts.noext;
- }
-
- const state = {
- input,
- index: -1,
- start: 0,
- dot: opts.dot === true,
- consumed: '',
- output: '',
- prefix: '',
- backtrack: false,
- negated: false,
- brackets: 0,
- braces: 0,
- parens: 0,
- quotes: 0,
- globstar: false,
- tokens
- };
-
- input = utils.removePrefix(input, state);
- len = input.length;
-
- const extglobs = [];
- const braces = [];
- const stack = [];
- let prev = bos;
- let value;
-
- /**
- * Tokenizing helpers
- */
-
- const eos = () => state.index === len - 1;
- const peek = state.peek = (n = 1) => input[state.index + n];
- const advance = state.advance = () => input[++state.index] || '';
- const remaining = () => input.slice(state.index + 1);
- const consume = (value = '', num = 0) => {
- state.consumed += value;
- state.index += num;
- };
-
- const append = token => {
- state.output += token.output != null ? token.output : token.value;
- consume(token.value);
- };
-
- const negate = () => {
- let count = 1;
-
- while (peek() === '!' && (peek(2) !== '(' || peek(3) === '?')) {
- advance();
- state.start++;
- count++;
- }
-
- if (count % 2 === 0) {
- return false;
- }
-
- state.negated = true;
- state.start++;
- return true;
- };
-
- const increment = type => {
- state[type]++;
- stack.push(type);
- };
-
- const decrement = type => {
- state[type]--;
- stack.pop();
- };
-
- /**
- * Push tokens onto the tokens array. This helper speeds up
- * tokenizing by 1) helping us avoid backtracking as much as possible,
- * and 2) helping us avoid creating extra tokens when consecutive
- * characters are plain text. This improves performance and simplifies
- * lookbehinds.
- */
-
- const push = tok => {
- if (prev.type === 'globstar') {
- const isBrace = state.braces > 0 && (tok.type === 'comma' || tok.type === 'brace');
- const isExtglob = tok.extglob === true || (extglobs.length && (tok.type === 'pipe' || tok.type === 'paren'));
-
- if (tok.type !== 'slash' && tok.type !== 'paren' && !isBrace && !isExtglob) {
- state.output = state.output.slice(0, -prev.output.length);
- prev.type = 'star';
- prev.value = '*';
- prev.output = star;
- state.output += prev.output;
- }
- }
-
- if (extglobs.length && tok.type !== 'paren') {
- extglobs[extglobs.length - 1].inner += tok.value;
- }
-
- if (tok.value || tok.output) append(tok);
- if (prev && prev.type === 'text' && tok.type === 'text') {
- prev.value += tok.value;
- prev.output = (prev.output || '') + tok.value;
- return;
- }
-
- tok.prev = prev;
- tokens.push(tok);
- prev = tok;
- };
-
- const extglobOpen = (type, value) => {
- const token = { ...EXTGLOB_CHARS[value], conditions: 1, inner: '' };
-
- token.prev = prev;
- token.parens = state.parens;
- token.output = state.output;
- const output = (opts.capture ? '(' : '') + token.open;
-
- increment('parens');
- push({ type, value, output: state.output ? '' : ONE_CHAR });
- push({ type: 'paren', extglob: true, value: advance(), output });
- extglobs.push(token);
- };
-
- const extglobClose = token => {
- let output = token.close + (opts.capture ? ')' : '');
- let rest;
-
- if (token.type === 'negate') {
- let extglobStar = star;
-
- if (token.inner && token.inner.length > 1 && token.inner.includes('/')) {
- extglobStar = globstar(opts);
- }
-
- if (extglobStar !== star || eos() || /^\)+$/.test(remaining())) {
- output = token.close = `)$))${extglobStar}`;
- }
-
- if (token.inner.includes('*') && (rest = remaining()) && /^\.[^\\/.]+$/.test(rest)) {
- output = token.close = `)${rest})${extglobStar})`;
- }
-
- if (token.prev.type === 'bos') {
- state.negatedExtglob = true;
- }
- }
-
- push({ type: 'paren', extglob: true, value, output });
- decrement('parens');
- };
-
- /**
- * Fast paths
- */
-
- if (opts.fastpaths !== false && !/(^[*!]|[/()[\]{}"])/.test(input)) {
- let backslashes = false;
-
- let output = input.replace(REGEX_SPECIAL_CHARS_BACKREF, (m, esc, chars, first, rest, index) => {
- if (first === '\\') {
- backslashes = true;
- return m;
- }
-
- if (first === '?') {
- if (esc) {
- return esc + first + (rest ? QMARK.repeat(rest.length) : '');
- }
- if (index === 0) {
- return qmarkNoDot + (rest ? QMARK.repeat(rest.length) : '');
- }
- return QMARK.repeat(chars.length);
- }
-
- if (first === '.') {
- return DOT_LITERAL.repeat(chars.length);
- }
-
- if (first === '*') {
- if (esc) {
- return esc + first + (rest ? star : '');
- }
- return star;
- }
- return esc ? m : `\\${m}`;
- });
-
- if (backslashes === true) {
- if (opts.unescape === true) {
- output = output.replace(/\\/g, '');
- } else {
- output = output.replace(/\\+/g, m => {
- return m.length % 2 === 0 ? '\\\\' : (m ? '\\' : '');
- });
- }
- }
-
- if (output === input && opts.contains === true) {
- state.output = input;
- return state;
- }
-
- state.output = utils.wrapOutput(output, state, options);
- return state;
- }
-
- /**
- * Tokenize input until we reach end-of-string
- */
-
- while (!eos()) {
- value = advance();
-
- if (value === '\u0000') {
- continue;
- }
-
- /**
- * Escaped characters
- */
-
- if (value === '\\') {
- const next = peek();
-
- if (next === '/' && opts.bash !== true) {
- continue;
- }
-
- if (next === '.' || next === ';') {
- continue;
- }
-
- if (!next) {
- value += '\\';
- push({ type: 'text', value });
- continue;
- }
-
- // collapse slashes to reduce potential for exploits
- const match = /^\\+/.exec(remaining());
- let slashes = 0;
-
- if (match && match[0].length > 2) {
- slashes = match[0].length;
- state.index += slashes;
- if (slashes % 2 !== 0) {
- value += '\\';
- }
- }
-
- if (opts.unescape === true) {
- value = advance();
- } else {
- value += advance();
- }
-
- if (state.brackets === 0) {
- push({ type: 'text', value });
- continue;
- }
- }
-
- /**
- * If we're inside a regex character class, continue
- * until we reach the closing bracket.
- */
-
- if (state.brackets > 0 && (value !== ']' || prev.value === '[' || prev.value === '[^')) {
- if (opts.posix !== false && value === ':') {
- const inner = prev.value.slice(1);
- if (inner.includes('[')) {
- prev.posix = true;
-
- if (inner.includes(':')) {
- const idx = prev.value.lastIndexOf('[');
- const pre = prev.value.slice(0, idx);
- const rest = prev.value.slice(idx + 2);
- const posix = POSIX_REGEX_SOURCE[rest];
- if (posix) {
- prev.value = pre + posix;
- state.backtrack = true;
- advance();
-
- if (!bos.output && tokens.indexOf(prev) === 1) {
- bos.output = ONE_CHAR;
- }
- continue;
- }
- }
- }
- }
-
- if ((value === '[' && peek() !== ':') || (value === '-' && peek() === ']')) {
- value = `\\${value}`;
- }
-
- if (value === ']' && (prev.value === '[' || prev.value === '[^')) {
- value = `\\${value}`;
- }
-
- if (opts.posix === true && value === '!' && prev.value === '[') {
- value = '^';
- }
-
- prev.value += value;
- append({ value });
- continue;
- }
-
- /**
- * If we're inside a quoted string, continue
- * until we reach the closing double quote.
- */
-
- if (state.quotes === 1 && value !== '"') {
- value = utils.escapeRegex(value);
- prev.value += value;
- append({ value });
- continue;
- }
-
- /**
- * Double quotes
- */
-
- if (value === '"') {
- state.quotes = state.quotes === 1 ? 0 : 1;
- if (opts.keepQuotes === true) {
- push({ type: 'text', value });
- }
- continue;
- }
-
- /**
- * Parentheses
- */
-
- if (value === '(') {
- increment('parens');
- push({ type: 'paren', value });
- continue;
- }
-
- if (value === ')') {
- if (state.parens === 0 && opts.strictBrackets === true) {
- throw new SyntaxError(syntaxError('opening', '('));
- }
-
- const extglob = extglobs[extglobs.length - 1];
- if (extglob && state.parens === extglob.parens + 1) {
- extglobClose(extglobs.pop());
- continue;
- }
-
- push({ type: 'paren', value, output: state.parens ? ')' : '\\)' });
- decrement('parens');
- continue;
- }
-
- /**
- * Square brackets
- */
-
- if (value === '[') {
- if (opts.nobracket === true || !remaining().includes(']')) {
- if (opts.nobracket !== true && opts.strictBrackets === true) {
- throw new SyntaxError(syntaxError('closing', ']'));
- }
-
- value = `\\${value}`;
- } else {
- increment('brackets');
- }
-
- push({ type: 'bracket', value });
- continue;
- }
-
- if (value === ']') {
- if (opts.nobracket === true || (prev && prev.type === 'bracket' && prev.value.length === 1)) {
- push({ type: 'text', value, output: `\\${value}` });
- continue;
- }
-
- if (state.brackets === 0) {
- if (opts.strictBrackets === true) {
- throw new SyntaxError(syntaxError('opening', '['));
- }
-
- push({ type: 'text', value, output: `\\${value}` });
- continue;
- }
-
- decrement('brackets');
-
- const prevValue = prev.value.slice(1);
- if (prev.posix !== true && prevValue[0] === '^' && !prevValue.includes('/')) {
- value = `/${value}`;
- }
-
- prev.value += value;
- append({ value });
-
- // when literal brackets are explicitly disabled
- // assume we should match with a regex character class
- if (opts.literalBrackets === false || utils.hasRegexChars(prevValue)) {
- continue;
- }
-
- const escaped = utils.escapeRegex(prev.value);
- state.output = state.output.slice(0, -prev.value.length);
-
- // when literal brackets are explicitly enabled
- // assume we should escape the brackets to match literal characters
- if (opts.literalBrackets === true) {
- state.output += escaped;
- prev.value = escaped;
- continue;
- }
-
- // when the user specifies nothing, try to match both
- prev.value = `(${capture}${escaped}|${prev.value})`;
- state.output += prev.value;
- continue;
- }
-
- /**
- * Braces
- */
-
- if (value === '{' && opts.nobrace !== true) {
- increment('braces');
-
- const open = {
- type: 'brace',
- value,
- output: '(',
- outputIndex: state.output.length,
- tokensIndex: state.tokens.length
- };
-
- braces.push(open);
- push(open);
- continue;
- }
-
- if (value === '}') {
- const brace = braces[braces.length - 1];
-
- if (opts.nobrace === true || !brace) {
- push({ type: 'text', value, output: value });
- continue;
- }
-
- let output = ')';
-
- if (brace.dots === true) {
- const arr = tokens.slice();
- const range = [];
-
- for (let i = arr.length - 1; i >= 0; i--) {
- tokens.pop();
- if (arr[i].type === 'brace') {
- break;
- }
- if (arr[i].type !== 'dots') {
- range.unshift(arr[i].value);
- }
- }
-
- output = expandRange(range, opts);
- state.backtrack = true;
- }
-
- if (brace.comma !== true && brace.dots !== true) {
- const out = state.output.slice(0, brace.outputIndex);
- const toks = state.tokens.slice(brace.tokensIndex);
- brace.value = brace.output = '\\{';
- value = output = '\\}';
- state.output = out;
- for (const t of toks) {
- state.output += (t.output || t.value);
- }
- }
-
- push({ type: 'brace', value, output });
- decrement('braces');
- braces.pop();
- continue;
- }
-
- /**
- * Pipes
- */
-
- if (value === '|') {
- if (extglobs.length > 0) {
- extglobs[extglobs.length - 1].conditions++;
- }
- push({ type: 'text', value });
- continue;
- }
-
- /**
- * Commas
- */
-
- if (value === ',') {
- let output = value;
-
- const brace = braces[braces.length - 1];
- if (brace && stack[stack.length - 1] === 'braces') {
- brace.comma = true;
- output = '|';
- }
-
- push({ type: 'comma', value, output });
- continue;
- }
-
- /**
- * Slashes
- */
-
- if (value === '/') {
- // if the beginning of the glob is "./", advance the start
- // to the current index, and don't add the "./" characters
- // to the state. This greatly simplifies lookbehinds when
- // checking for BOS characters like "!" and "." (not "./")
- if (prev.type === 'dot' && state.index === state.start + 1) {
- state.start = state.index + 1;
- state.consumed = '';
- state.output = '';
- tokens.pop();
- prev = bos; // reset "prev" to the first token
- continue;
- }
-
- push({ type: 'slash', value, output: SLASH_LITERAL });
- continue;
- }
-
- /**
- * Dots
- */
-
- if (value === '.') {
- if (state.braces > 0 && prev.type === 'dot') {
- if (prev.value === '.') prev.output = DOT_LITERAL;
- const brace = braces[braces.length - 1];
- prev.type = 'dots';
- prev.output += value;
- prev.value += value;
- brace.dots = true;
- continue;
- }
-
- if ((state.braces + state.parens) === 0 && prev.type !== 'bos' && prev.type !== 'slash') {
- push({ type: 'text', value, output: DOT_LITERAL });
- continue;
- }
-
- push({ type: 'dot', value, output: DOT_LITERAL });
- continue;
- }
-
- /**
- * Question marks
- */
-
- if (value === '?') {
- const isGroup = prev && prev.value === '(';
- if (!isGroup && opts.noextglob !== true && peek() === '(' && peek(2) !== '?') {
- extglobOpen('qmark', value);
- continue;
- }
-
- if (prev && prev.type === 'paren') {
- const next = peek();
- let output = value;
-
- if (next === '<' && !utils.supportsLookbehinds()) {
- throw new Error('Node.js v10 or higher is required for regex lookbehinds');
- }
-
- if ((prev.value === '(' && !/[!=<:]/.test(next)) || (next === '<' && !/<([!=]|\w+>)/.test(remaining()))) {
- output = `\\${value}`;
- }
-
- push({ type: 'text', value, output });
- continue;
- }
-
- if (opts.dot !== true && (prev.type === 'slash' || prev.type === 'bos')) {
- push({ type: 'qmark', value, output: QMARK_NO_DOT });
- continue;
- }
-
- push({ type: 'qmark', value, output: QMARK });
- continue;
- }
-
- /**
- * Exclamation
- */
-
- if (value === '!') {
- if (opts.noextglob !== true && peek() === '(') {
- if (peek(2) !== '?' || !/[!=<:]/.test(peek(3))) {
- extglobOpen('negate', value);
- continue;
- }
- }
-
- if (opts.nonegate !== true && state.index === 0) {
- negate();
- continue;
- }
- }
-
- /**
- * Plus
- */
-
- if (value === '+') {
- if (opts.noextglob !== true && peek() === '(' && peek(2) !== '?') {
- extglobOpen('plus', value);
- continue;
- }
-
- if ((prev && prev.value === '(') || opts.regex === false) {
- push({ type: 'plus', value, output: PLUS_LITERAL });
- continue;
- }
-
- if ((prev && (prev.type === 'bracket' || prev.type === 'paren' || prev.type === 'brace')) || state.parens > 0) {
- push({ type: 'plus', value });
- continue;
- }
-
- push({ type: 'plus', value: PLUS_LITERAL });
- continue;
- }
-
- /**
- * Plain text
- */
-
- if (value === '@') {
- if (opts.noextglob !== true && peek() === '(' && peek(2) !== '?') {
- push({ type: 'at', extglob: true, value, output: '' });
- continue;
- }
-
- push({ type: 'text', value });
- continue;
- }
-
- /**
- * Plain text
- */
-
- if (value !== '*') {
- if (value === '$' || value === '^') {
- value = `\\${value}`;
- }
-
- const match = REGEX_NON_SPECIAL_CHARS.exec(remaining());
- if (match) {
- value += match[0];
- state.index += match[0].length;
- }
-
- push({ type: 'text', value });
- continue;
- }
-
- /**
- * Stars
- */
-
- if (prev && (prev.type === 'globstar' || prev.star === true)) {
- prev.type = 'star';
- prev.star = true;
- prev.value += value;
- prev.output = star;
- state.backtrack = true;
- state.globstar = true;
- consume(value);
- continue;
- }
-
- let rest = remaining();
- if (opts.noextglob !== true && /^\([^?]/.test(rest)) {
- extglobOpen('star', value);
- continue;
- }
-
- if (prev.type === 'star') {
- if (opts.noglobstar === true) {
- consume(value);
- continue;
- }
-
- const prior = prev.prev;
- const before = prior.prev;
- const isStart = prior.type === 'slash' || prior.type === 'bos';
- const afterStar = before && (before.type === 'star' || before.type === 'globstar');
-
- if (opts.bash === true && (!isStart || (rest[0] && rest[0] !== '/'))) {
- push({ type: 'star', value, output: '' });
- continue;
- }
-
- const isBrace = state.braces > 0 && (prior.type === 'comma' || prior.type === 'brace');
- const isExtglob = extglobs.length && (prior.type === 'pipe' || prior.type === 'paren');
- if (!isStart && prior.type !== 'paren' && !isBrace && !isExtglob) {
- push({ type: 'star', value, output: '' });
- continue;
- }
-
- // strip consecutive `/**/`
- while (rest.slice(0, 3) === '/**') {
- const after = input[state.index + 4];
- if (after && after !== '/') {
- break;
- }
- rest = rest.slice(3);
- consume('/**', 3);
- }
-
- if (prior.type === 'bos' && eos()) {
- prev.type = 'globstar';
- prev.value += value;
- prev.output = globstar(opts);
- state.output = prev.output;
- state.globstar = true;
- consume(value);
- continue;
- }
-
- if (prior.type === 'slash' && prior.prev.type !== 'bos' && !afterStar && eos()) {
- state.output = state.output.slice(0, -(prior.output + prev.output).length);
- prior.output = `(?:${prior.output}`;
-
- prev.type = 'globstar';
- prev.output = globstar(opts) + (opts.strictSlashes ? ')' : '|$)');
- prev.value += value;
- state.globstar = true;
- state.output += prior.output + prev.output;
- consume(value);
- continue;
- }
-
- if (prior.type === 'slash' && prior.prev.type !== 'bos' && rest[0] === '/') {
- const end = rest[1] !== void 0 ? '|$' : '';
-
- state.output = state.output.slice(0, -(prior.output + prev.output).length);
- prior.output = `(?:${prior.output}`;
-
- prev.type = 'globstar';
- prev.output = `${globstar(opts)}${SLASH_LITERAL}|${SLASH_LITERAL}${end})`;
- prev.value += value;
-
- state.output += prior.output + prev.output;
- state.globstar = true;
-
- consume(value + advance());
-
- push({ type: 'slash', value: '/', output: '' });
- continue;
- }
-
- if (prior.type === 'bos' && rest[0] === '/') {
- prev.type = 'globstar';
- prev.value += value;
- prev.output = `(?:^|${SLASH_LITERAL}|${globstar(opts)}${SLASH_LITERAL})`;
- state.output = prev.output;
- state.globstar = true;
- consume(value + advance());
- push({ type: 'slash', value: '/', output: '' });
- continue;
- }
-
- // remove single star from output
- state.output = state.output.slice(0, -prev.output.length);
-
- // reset previous token to globstar
- prev.type = 'globstar';
- prev.output = globstar(opts);
- prev.value += value;
-
- // reset output with globstar
- state.output += prev.output;
- state.globstar = true;
- consume(value);
- continue;
- }
-
- const token = { type: 'star', value, output: star };
-
- if (opts.bash === true) {
- token.output = '.*?';
- if (prev.type === 'bos' || prev.type === 'slash') {
- token.output = nodot + token.output;
- }
- push(token);
- continue;
- }
-
- if (prev && (prev.type === 'bracket' || prev.type === 'paren') && opts.regex === true) {
- token.output = value;
- push(token);
- continue;
- }
-
- if (state.index === state.start || prev.type === 'slash' || prev.type === 'dot') {
- if (prev.type === 'dot') {
- state.output += NO_DOT_SLASH;
- prev.output += NO_DOT_SLASH;
-
- } else if (opts.dot === true) {
- state.output += NO_DOTS_SLASH;
- prev.output += NO_DOTS_SLASH;
-
- } else {
- state.output += nodot;
- prev.output += nodot;
- }
-
- if (peek() !== '*') {
- state.output += ONE_CHAR;
- prev.output += ONE_CHAR;
- }
- }
-
- push(token);
- }
-
- while (state.brackets > 0) {
- if (opts.strictBrackets === true) throw new SyntaxError(syntaxError('closing', ']'));
- state.output = utils.escapeLast(state.output, '[');
- decrement('brackets');
- }
-
- while (state.parens > 0) {
- if (opts.strictBrackets === true) throw new SyntaxError(syntaxError('closing', ')'));
- state.output = utils.escapeLast(state.output, '(');
- decrement('parens');
- }
-
- while (state.braces > 0) {
- if (opts.strictBrackets === true) throw new SyntaxError(syntaxError('closing', '}'));
- state.output = utils.escapeLast(state.output, '{');
- decrement('braces');
- }
-
- if (opts.strictSlashes !== true && (prev.type === 'star' || prev.type === 'bracket')) {
- push({ type: 'maybe_slash', value: '', output: `${SLASH_LITERAL}?` });
- }
-
- // rebuild the output if we had to backtrack at any point
- if (state.backtrack === true) {
- state.output = '';
-
- for (const token of state.tokens) {
- state.output += token.output != null ? token.output : token.value;
-
- if (token.suffix) {
- state.output += token.suffix;
- }
- }
- }
-
- return state;
-};
-
-/**
- * Fast paths for creating regular expressions for common glob patterns.
- * This can significantly speed up processing and has very little downside
- * impact when none of the fast paths match.
- */
-
-parse.fastpaths = (input, options) => {
- const opts = { ...options };
- const max = typeof opts.maxLength === 'number' ? Math.min(MAX_LENGTH, opts.maxLength) : MAX_LENGTH;
- const len = input.length;
- if (len > max) {
- throw new SyntaxError(`Input length: ${len}, exceeds maximum allowed length: ${max}`);
- }
-
- input = REPLACEMENTS[input] || input;
- const win32 = utils.isWindows(options);
-
- // create constants based on platform, for windows or posix
- const {
- DOT_LITERAL,
- SLASH_LITERAL,
- ONE_CHAR,
- DOTS_SLASH,
- NO_DOT,
- NO_DOTS,
- NO_DOTS_SLASH,
- STAR,
- START_ANCHOR
- } = constants.globChars(win32);
-
- const nodot = opts.dot ? NO_DOTS : NO_DOT;
- const slashDot = opts.dot ? NO_DOTS_SLASH : NO_DOT;
- const capture = opts.capture ? '' : '?:';
- const state = { negated: false, prefix: '' };
- let star = opts.bash === true ? '.*?' : STAR;
-
- if (opts.capture) {
- star = `(${star})`;
- }
-
- const globstar = opts => {
- if (opts.noglobstar === true) return star;
- return `(${capture}(?:(?!${START_ANCHOR}${opts.dot ? DOTS_SLASH : DOT_LITERAL}).)*?)`;
- };
-
- const create = str => {
- switch (str) {
- case '*':
- return `${nodot}${ONE_CHAR}${star}`;
-
- case '.*':
- return `${DOT_LITERAL}${ONE_CHAR}${star}`;
-
- case '*.*':
- return `${nodot}${star}${DOT_LITERAL}${ONE_CHAR}${star}`;
-
- case '*/*':
- return `${nodot}${star}${SLASH_LITERAL}${ONE_CHAR}${slashDot}${star}`;
-
- case '**':
- return nodot + globstar(opts);
-
- case '**/*':
- return `(?:${nodot}${globstar(opts)}${SLASH_LITERAL})?${slashDot}${ONE_CHAR}${star}`;
-
- case '**/*.*':
- return `(?:${nodot}${globstar(opts)}${SLASH_LITERAL})?${slashDot}${star}${DOT_LITERAL}${ONE_CHAR}${star}`;
-
- case '**/.*':
- return `(?:${nodot}${globstar(opts)}${SLASH_LITERAL})?${DOT_LITERAL}${ONE_CHAR}${star}`;
-
- default: {
- const match = /^(.*?)\.(\w+)$/.exec(str);
- if (!match) return;
-
- const source = create(match[1]);
- if (!source) return;
-
- return source + DOT_LITERAL + match[2];
- }
- }
- };
-
- const output = utils.removePrefix(input, state);
- let source = create(output);
-
- if (source && opts.strictSlashes !== true) {
- source += `${SLASH_LITERAL}?`;
- }
-
- return source;
-};
-
-module.exports = parse;
-
-
-/***/ }),
-/* 794 */
-/***/ (function(module, exports, __webpack_require__) {
-
-"use strict";
-
-Object.defineProperty(exports, "__esModule", { value: true });
-exports.merge = void 0;
-const merge2 = __webpack_require__(243);
-function merge(streams) {
- const mergedStream = merge2(streams);
- streams.forEach((stream) => {
- stream.once('error', (error) => mergedStream.emit('error', error));
- });
- mergedStream.once('close', () => propagateCloseEventToSources(streams));
- mergedStream.once('end', () => propagateCloseEventToSources(streams));
- return mergedStream;
-}
-exports.merge = merge;
-function propagateCloseEventToSources(streams) {
- streams.forEach((stream) => stream.emit('close'));
-}
-
-
-/***/ }),
-/* 795 */
-/***/ (function(module, exports, __webpack_require__) {
-
-"use strict";
-
-Object.defineProperty(exports, "__esModule", { value: true });
-exports.isEmpty = exports.isString = void 0;
-function isString(input) {
- return typeof input === 'string';
-}
-exports.isString = isString;
-function isEmpty(input) {
- return input === '';
-}
-exports.isEmpty = isEmpty;
-
-
-/***/ }),
-/* 796 */
-/***/ (function(module, exports, __webpack_require__) {
-
-"use strict";
-
-Object.defineProperty(exports, "__esModule", { value: true });
-const stream_1 = __webpack_require__(797);
-const provider_1 = __webpack_require__(799);
-class ProviderAsync extends provider_1.default {
- constructor() {
- super(...arguments);
- this._reader = new stream_1.default(this._settings);
- }
- read(task) {
- const root = this._getRootDirectory(task);
- const options = this._getReaderOptions(task);
- const entries = [];
- return new Promise((resolve, reject) => {
- const stream = this.api(root, task, options);
- stream.once('error', reject);
- stream.on('data', (entry) => entries.push(options.transform(entry)));
- stream.once('end', () => resolve(entries));
- });
- }
- api(root, task, options) {
- if (task.dynamic) {
- return this._reader.dynamic(root, options);
- }
- return this._reader.static(task.patterns, options);
- }
-}
-exports.default = ProviderAsync;
-
-
-/***/ }),
-/* 797 */
-/***/ (function(module, exports, __webpack_require__) {
-
-"use strict";
-
-Object.defineProperty(exports, "__esModule", { value: true });
-const stream_1 = __webpack_require__(173);
-const fsStat = __webpack_require__(289);
-const fsWalk = __webpack_require__(294);
-const reader_1 = __webpack_require__(798);
-class ReaderStream extends reader_1.default {
- constructor() {
- super(...arguments);
- this._walkStream = fsWalk.walkStream;
- this._stat = fsStat.stat;
- }
- dynamic(root, options) {
- return this._walkStream(root, options);
- }
- static(patterns, options) {
- const filepaths = patterns.map(this._getFullEntryPath, this);
- const stream = new stream_1.PassThrough({ objectMode: true });
- stream._write = (index, _enc, done) => {
- return this._getEntry(filepaths[index], patterns[index], options)
- .then((entry) => {
- if (entry !== null && options.entryFilter(entry)) {
- stream.push(entry);
- }
- if (index === filepaths.length - 1) {
- stream.end();
- }
- done();
- })
- .catch(done);
- };
- for (let i = 0; i < filepaths.length; i++) {
- stream.write(i);
- }
- return stream;
- }
- _getEntry(filepath, pattern, options) {
- return this._getStat(filepath)
- .then((stats) => this._makeEntry(stats, pattern))
- .catch((error) => {
- if (options.errorFilter(error)) {
- return null;
- }
- throw error;
- });
- }
- _getStat(filepath) {
- return new Promise((resolve, reject) => {
- this._stat(filepath, this._fsStatSettings, (error, stats) => {
- return error === null ? resolve(stats) : reject(error);
- });
- });
- }
-}
-exports.default = ReaderStream;
-
-
-/***/ }),
-/* 798 */
-/***/ (function(module, exports, __webpack_require__) {
-
-"use strict";
-
-Object.defineProperty(exports, "__esModule", { value: true });
-const path = __webpack_require__(4);
-const fsStat = __webpack_require__(289);
-const utils = __webpack_require__(781);
-class Reader {
- constructor(_settings) {
- this._settings = _settings;
- this._fsStatSettings = new fsStat.Settings({
- followSymbolicLink: this._settings.followSymbolicLinks,
- fs: this._settings.fs,
- throwErrorOnBrokenSymbolicLink: this._settings.followSymbolicLinks
- });
- }
- _getFullEntryPath(filepath) {
- return path.resolve(this._settings.cwd, filepath);
- }
- _makeEntry(stats, pattern) {
- const entry = {
- name: pattern,
- path: pattern,
- dirent: utils.fs.createDirentFromStats(pattern, stats)
- };
- if (this._settings.stats) {
- entry.stats = stats;
- }
- return entry;
- }
- _isFatalError(error) {
- return !utils.errno.isEnoentCodeError(error) && !this._settings.suppressErrors;
- }
-}
-exports.default = Reader;
-
-
-/***/ }),
-/* 799 */
-/***/ (function(module, exports, __webpack_require__) {
-
-"use strict";
+"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
const path = __webpack_require__(4);
-const deep_1 = __webpack_require__(800);
-const entry_1 = __webpack_require__(803);
-const error_1 = __webpack_require__(804);
-const entry_2 = __webpack_require__(805);
+const deep_1 = __webpack_require__(794);
+const entry_1 = __webpack_require__(797);
+const error_1 = __webpack_require__(798);
+const entry_2 = __webpack_require__(799);
class Provider {
constructor(_settings) {
this._settings = _settings;
@@ -92428,14 +90310,14 @@ exports.default = Provider;
/***/ }),
-/* 800 */
+/* 794 */
/***/ (function(module, exports, __webpack_require__) {
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
const utils = __webpack_require__(781);
-const partial_1 = __webpack_require__(801);
+const partial_1 = __webpack_require__(795);
class DeepFilter {
constructor(_settings, _micromatchOptions) {
this._settings = _settings;
@@ -92497,13 +90379,13 @@ exports.default = DeepFilter;
/***/ }),
-/* 801 */
+/* 795 */
/***/ (function(module, exports, __webpack_require__) {
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
-const matcher_1 = __webpack_require__(802);
+const matcher_1 = __webpack_require__(796);
class PartialMatcher extends matcher_1.default {
match(filepath) {
const parts = filepath.split('/');
@@ -92542,7 +90424,7 @@ exports.default = PartialMatcher;
/***/ }),
-/* 802 */
+/* 796 */
/***/ (function(module, exports, __webpack_require__) {
"use strict";
@@ -92599,7 +90481,7 @@ exports.default = Matcher;
/***/ }),
-/* 803 */
+/* 797 */
/***/ (function(module, exports, __webpack_require__) {
"use strict";
@@ -92662,7 +90544,7 @@ exports.default = EntryFilter;
/***/ }),
-/* 804 */
+/* 798 */
/***/ (function(module, exports, __webpack_require__) {
"use strict";
@@ -92684,7 +90566,7 @@ exports.default = ErrorFilter;
/***/ }),
-/* 805 */
+/* 799 */
/***/ (function(module, exports, __webpack_require__) {
"use strict";
@@ -92717,15 +90599,15 @@ exports.default = EntryTransformer;
/***/ }),
-/* 806 */
+/* 800 */
/***/ (function(module, exports, __webpack_require__) {
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
const stream_1 = __webpack_require__(173);
-const stream_2 = __webpack_require__(797);
-const provider_1 = __webpack_require__(799);
+const stream_2 = __webpack_require__(791);
+const provider_1 = __webpack_require__(793);
class ProviderStream extends provider_1.default {
constructor() {
super(...arguments);
@@ -92755,14 +90637,14 @@ exports.default = ProviderStream;
/***/ }),
-/* 807 */
+/* 801 */
/***/ (function(module, exports, __webpack_require__) {
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
-const sync_1 = __webpack_require__(808);
-const provider_1 = __webpack_require__(799);
+const sync_1 = __webpack_require__(802);
+const provider_1 = __webpack_require__(793);
class ProviderSync extends provider_1.default {
constructor() {
super(...arguments);
@@ -92785,7 +90667,7 @@ exports.default = ProviderSync;
/***/ }),
-/* 808 */
+/* 802 */
/***/ (function(module, exports, __webpack_require__) {
"use strict";
@@ -92793,7 +90675,7 @@ exports.default = ProviderSync;
Object.defineProperty(exports, "__esModule", { value: true });
const fsStat = __webpack_require__(289);
const fsWalk = __webpack_require__(294);
-const reader_1 = __webpack_require__(798);
+const reader_1 = __webpack_require__(792);
class ReaderSync extends reader_1.default {
constructor() {
super(...arguments);
@@ -92835,7 +90717,7 @@ exports.default = ReaderSync;
/***/ }),
-/* 809 */
+/* 803 */
/***/ (function(module, exports, __webpack_require__) {
"use strict";
@@ -92899,7 +90781,7 @@ exports.default = Settings;
/***/ }),
-/* 810 */
+/* 804 */
/***/ (function(module, exports, __webpack_require__) {
"use strict";
@@ -93026,7 +90908,7 @@ module.exports.sync = options => {
/***/ }),
-/* 811 */
+/* 805 */
/***/ (function(module, exports, __webpack_require__) {
"use strict";
@@ -93079,7 +90961,7 @@ module.exports = {
/***/ }),
-/* 812 */
+/* 806 */
/***/ (function(module, __webpack_exports__, __webpack_require__) {
"use strict";
diff --git a/packages/kbn-pm/src/commands/bootstrap.ts b/packages/kbn-pm/src/commands/bootstrap.ts
index 0b3141ab9a5a..cf425264ab6d 100644
--- a/packages/kbn-pm/src/commands/bootstrap.ts
+++ b/packages/kbn-pm/src/commands/bootstrap.ts
@@ -40,7 +40,19 @@ export const BootstrapCommand: ICommand = {
const kibanaProjectPath = projects.get('kibana')?.path || '';
const runOffline = options?.offline === true;
const reporter = CiStatsReporter.fromEnv(log);
- const timings = [];
+
+ const timings: Array<{ id: string; ms: number }> = [];
+ const time = async (id: string, body: () => Promise): Promise => {
+ const start = Date.now();
+ try {
+ return await body();
+ } finally {
+ timings.push({
+ id,
+ ms: Date.now() - start,
+ });
+ }
+ };
// Force install is set in case a flag is passed or
// if the `.yarn-integrity` file is not found which
@@ -70,20 +82,14 @@ export const BootstrapCommand: ICommand = {
//
if (forceInstall) {
- const forceInstallStartTime = Date.now();
- await runBazel(['run', '@nodejs//:yarn'], runOffline);
- timings.push({
- id: 'force install dependencies',
- ms: Date.now() - forceInstallStartTime,
+ await time('force install dependencies', async () => {
+ await runBazel(['run', '@nodejs//:yarn'], runOffline);
});
}
// build packages
- const packageStartTime = Date.now();
- await runBazel(['build', '//packages:build', '--show_result=1'], runOffline);
- timings.push({
- id: 'build packages',
- ms: Date.now() - packageStartTime,
+ await time('build packages', async () => {
+ await runBazel(['build', '//packages:build', '--show_result=1'], runOffline);
});
// Install monorepo npm dependencies outside of the Bazel managed ones
@@ -112,30 +118,38 @@ export const BootstrapCommand: ICommand = {
}
}
- await sortPackageJson(kbn);
+ await time('sort package json', async () => {
+ await sortPackageJson(kbn);
+ });
- const yarnLock = await readYarnLock(kbn);
+ const yarnLock = await time('read yarn.lock', async () => await readYarnLock(kbn));
if (options.validate) {
- await validateDependencies(kbn, yarnLock);
+ await time('validate dependencies', async () => {
+ await validateDependencies(kbn, yarnLock);
+ });
}
// Assure all kbn projects with bin defined scripts
// copy those scripts into the top level node_modules folder
//
// NOTE: We don't probably need this anymore, is actually not being used
- await linkProjectExecutables(projects, projectGraph);
-
- // Update vscode settings
- await spawnStreaming(
- process.execPath,
- ['scripts/update_vscode_config'],
- {
- cwd: kbn.getAbsolute(),
- env: process.env,
- },
- { prefix: '[vscode]', debug: false }
- );
+ await time('link project executables', async () => {
+ await linkProjectExecutables(projects, projectGraph);
+ });
+
+ await time('update vscode config', async () => {
+ // Update vscode settings
+ await spawnStreaming(
+ process.execPath,
+ ['scripts/update_vscode_config'],
+ {
+ cwd: kbn.getAbsolute(),
+ env: process.env,
+ },
+ { prefix: '[vscode]', debug: false }
+ );
+ });
// send timings
await reporter.timings({
diff --git a/packages/kbn-pm/src/commands/index.ts b/packages/kbn-pm/src/commands/index.ts
index 70e641f1e935..4c7992859ebd 100644
--- a/packages/kbn-pm/src/commands/index.ts
+++ b/packages/kbn-pm/src/commands/index.ts
@@ -32,7 +32,6 @@ import { CleanCommand } from './clean';
import { ResetCommand } from './reset';
import { RunCommand } from './run';
import { WatchCommand } from './watch';
-import { PatchNativeModulesCommand } from './patch_native_modules';
import { Kibana } from '../utils/kibana';
export const commands: { [key: string]: ICommand } = {
@@ -42,5 +41,4 @@ export const commands: { [key: string]: ICommand } = {
reset: ResetCommand,
run: RunCommand,
watch: WatchCommand,
- patch_native_modules: PatchNativeModulesCommand,
};
diff --git a/packages/kbn-pm/src/commands/patch_native_modules.ts b/packages/kbn-pm/src/commands/patch_native_modules.ts
deleted file mode 100644
index 30fd599b83be..000000000000
--- a/packages/kbn-pm/src/commands/patch_native_modules.ts
+++ /dev/null
@@ -1,68 +0,0 @@
-/*
- * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
- * or more contributor license agreements. Licensed under the Elastic License
- * 2.0 and the Server Side Public License, v 1; you may not use this file except
- * in compliance with, at your election, the Elastic License 2.0 or the Server
- * Side Public License, v 1.
- */
-
-import Path from 'path';
-import Fs from 'fs';
-
-import { CiStatsReporter } from '@kbn/dev-utils/ci_stats_reporter';
-
-import { log } from '../utils/log';
-import { spawn } from '../utils/child_process';
-import { ICommand } from './index';
-
-export const PatchNativeModulesCommand: ICommand = {
- description: 'Patch native modules by running build commands on M1 Macs',
- name: 'patch_native_modules',
-
- async run(projects, _, { kbn }) {
- const kibanaProjectPath = projects.get('kibana')?.path || '';
- const reporter = CiStatsReporter.fromEnv(log);
-
- if (process.platform !== 'darwin' || process.arch !== 'arm64') {
- return;
- }
-
- const startTime = Date.now();
- const nodeSassDir = Path.resolve(kibanaProjectPath, 'node_modules/node-sass');
- const nodeSassNativeDist = Path.resolve(
- nodeSassDir,
- `vendor/darwin-arm64-${process.versions.modules}/binding.node`
- );
- if (!Fs.existsSync(nodeSassNativeDist)) {
- log.info('Running build script for node-sass');
- await spawn('npm', ['run', 'build'], {
- cwd: nodeSassDir,
- });
- }
-
- const re2Dir = Path.resolve(kibanaProjectPath, 'node_modules/re2');
- const re2NativeDist = Path.resolve(re2Dir, 'build/Release/re2.node');
- if (!Fs.existsSync(re2NativeDist)) {
- log.info('Running build script for re2');
- await spawn('npm', ['run', 'rebuild'], {
- cwd: re2Dir,
- });
- }
-
- log.success('native modules should be setup for native ARM Mac development');
-
- // send timings
- await reporter.timings({
- upstreamBranch: kbn.kibanaProject.json.branch,
- // prevent loading @kbn/utils by passing null
- kibanaUuid: kbn.getUuid() || null,
- timings: [
- {
- group: 'scripts/kbn bootstrap',
- id: 'patch native modudles for arm macs',
- ms: Date.now() - startTime,
- },
- ],
- });
- },
-};
diff --git a/packages/kbn-pm/src/utils/scripts.ts b/packages/kbn-pm/src/utils/scripts.ts
index ab013495a326..6e99285e145f 100644
--- a/packages/kbn-pm/src/utils/scripts.ts
+++ b/packages/kbn-pm/src/utils/scripts.ts
@@ -21,6 +21,12 @@ export async function installInDir(directory: string, extraArgs: string[] = [])
// given time (e.g. to avoid conflicts).
await spawn(YARN_EXEC, options, {
cwd: directory,
+ env: {
+ SASS_BINARY_SITE:
+ 'https://us-central1-elastic-kibana-184716.cloudfunctions.net/kibana-ci-proxy-cache/node-sass',
+ RE2_DOWNLOAD_MIRROR:
+ 'https://us-central1-elastic-kibana-184716.cloudfunctions.net/kibana-ci-proxy-cache/node-re2',
+ },
});
}
diff --git a/packages/kbn-pm/src/utils/sort_package_json.ts b/packages/kbn-pm/src/utils/sort_package_json.ts
index b4df5355744f..84a1ed6d8096 100644
--- a/packages/kbn-pm/src/utils/sort_package_json.ts
+++ b/packages/kbn-pm/src/utils/sort_package_json.ts
@@ -7,41 +7,10 @@
*/
import Fs from 'fs/promises';
-
-import sorter from 'sort-package-json';
-
+import { sortPackageJson as sort } from '@kbn/dev-utils/sort_package_json';
import { Kibana } from './kibana';
export async function sortPackageJson(kbn: Kibana) {
const packageJsonPath = kbn.getAbsolute('package.json');
- const packageJson = await Fs.readFile(packageJsonPath, 'utf-8');
- await Fs.writeFile(
- packageJsonPath,
- JSON.stringify(
- sorter(JSON.parse(packageJson), {
- // top level keys in the order they were written when this was implemented
- sortOrder: [
- 'name',
- 'description',
- 'keywords',
- 'private',
- 'version',
- 'branch',
- 'types',
- 'tsdocMetadata',
- 'build',
- 'homepage',
- 'bugs',
- 'kibana',
- 'author',
- 'scripts',
- 'repository',
- 'engines',
- 'resolutions',
- ],
- }),
- null,
- 2
- ) + '\n'
- );
+ await Fs.writeFile(packageJsonPath, sort(await Fs.readFile(packageJsonPath, 'utf-8')));
}
diff --git a/packages/kbn-securitysolution-autocomplete/README.md b/packages/kbn-securitysolution-autocomplete/README.md
index 41bfd9baf628..83b2d6a1882c 100644
--- a/packages/kbn-securitysolution-autocomplete/README.md
+++ b/packages/kbn-securitysolution-autocomplete/README.md
@@ -1,6 +1,6 @@
# Autocomplete Fields
-Need an input that shows available index fields? Or an input that autocompletes based on a selected indexPattern field? Bingo! That's what these components are for. They are generalized enough so that they can be reused throughout and repurposed based on your needs.
+Need an input that shows available index fields? Or an input that auto-completes based on a selected indexPattern field? Bingo! That's what these components are for. They are generalized enough so that they can be reused throughout and repurposed based on your needs.
All three of the available components rely on Eui's combo box.
@@ -119,4 +119,24 @@ The `onChange` handler is passed selected `string[]`.
indexPattern={indexPattern}
onChange={handleFieldMatchAnyValueChange}
/>
+```
+
+## AutocompleteFieldWildcardComponent
+
+This component can be used to allow users to select a single value. It uses the autocomplete hook to display any autocomplete options based on the passed in `indexPattern`, but also allows a user to add their own value.
+
+The `onChange` handler is passed selected `string[]`.
+
+```js
+
```
\ No newline at end of file
diff --git a/packages/kbn-securitysolution-autocomplete/src/field_value_wildcard/index.test.tsx b/packages/kbn-securitysolution-autocomplete/src/field_value_wildcard/index.test.tsx
new file mode 100644
index 000000000000..34769a76563c
--- /dev/null
+++ b/packages/kbn-securitysolution-autocomplete/src/field_value_wildcard/index.test.tsx
@@ -0,0 +1,279 @@
+/*
+ * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
+ * or more contributor license agreements. Licensed under the Elastic License
+ * 2.0 and the Server Side Public License, v 1; you may not use this file except
+ * in compliance with, at your election, the Elastic License 2.0 or the Server
+ * Side Public License, v 1.
+ */
+
+import React from 'react';
+import { ReactWrapper, mount } from 'enzyme';
+import { EuiComboBox, EuiComboBoxOptionOption } from '@elastic/eui';
+import { act } from '@testing-library/react';
+import { AutocompleteFieldWildcardComponent } from '.';
+import { useFieldValueAutocomplete } from '../hooks/use_field_value_autocomplete';
+import { fields, getField } from '../fields/index.mock';
+import { autocompleteStartMock } from '../autocomplete/index.mock';
+
+jest.mock('../hooks/use_field_value_autocomplete');
+
+describe('AutocompleteFieldWildcardComponent', () => {
+ let wrapper: ReactWrapper;
+
+ const getValueSuggestionsMock = jest
+ .fn()
+ .mockResolvedValue([false, true, ['value 3', 'value 4'], jest.fn()]);
+
+ beforeEach(() => {
+ (useFieldValueAutocomplete as jest.Mock).mockReturnValue([
+ false,
+ true,
+ ['value 1', 'value 2'],
+ getValueSuggestionsMock,
+ ]);
+ });
+
+ afterEach(() => {
+ jest.clearAllMocks();
+ wrapper.unmount();
+ });
+
+ test('it renders row label if one passed in', () => {
+ wrapper = mount(
+
+ );
+
+ expect(
+ wrapper.find('[data-test-subj="valuesAutocompleteWildcardLabel"] label').at(0).text()
+ ).toEqual('Row Label');
+ });
+
+ test('it renders disabled if "isDisabled" is true', () => {
+ wrapper = mount(
+
+ );
+
+ expect(
+ wrapper.find('[data-test-subj="valuesAutocompleteWildcard"] input').prop('disabled')
+ ).toBeTruthy();
+ });
+
+ test('it renders loading if "isLoading" is true', () => {
+ wrapper = mount(
+
+ );
+ wrapper.find('[data-test-subj="valuesAutocompleteWildcard"] button').at(0).simulate('click');
+ expect(
+ wrapper
+ .find('EuiComboBoxOptionsList[data-test-subj="valuesAutocompleteWildcard-optionsList"]')
+ .prop('isLoading')
+ ).toBeTruthy();
+ });
+
+ test('it allows user to clear values if "isClearable" is true', () => {
+ wrapper = mount(
+
+ );
+
+ expect(
+ wrapper
+ .find('[data-test-subj="comboBoxInput"]')
+ .hasClass('euiComboBox__inputWrap-isClearable')
+ ).toBeTruthy();
+ });
+
+ test('it correctly displays selected value', () => {
+ wrapper = mount(
+
+ );
+
+ expect(
+ wrapper.find('[data-test-subj="valuesAutocompleteWildcard"] EuiComboBoxPill').at(0).text()
+ ).toEqual('/opt/*/app.dmg');
+ });
+
+ test('it invokes "onChange" when new value created', async () => {
+ const mockOnChange = jest.fn();
+ wrapper = mount(
+
+ );
+
+ (
+ wrapper.find(EuiComboBox).props() as unknown as {
+ onCreateOption: (a: string) => void;
+ }
+ ).onCreateOption('/opt/*/app.dmg');
+
+ expect(mockOnChange).toHaveBeenCalledWith('/opt/*/app.dmg');
+ });
+
+ test('it invokes "onChange" when new value selected', async () => {
+ const mockOnChange = jest.fn();
+ wrapper = mount(
+
+ );
+
+ (
+ wrapper.find(EuiComboBox).props() as unknown as {
+ onChange: (a: EuiComboBoxOptionOption[]) => void;
+ }
+ ).onChange([{ label: 'value 1' }]);
+
+ expect(mockOnChange).toHaveBeenCalledWith('value 1');
+ });
+
+ test('it refreshes autocomplete with search query when new value searched', () => {
+ wrapper = mount(
+
+ );
+ act(() => {
+ (
+ wrapper.find(EuiComboBox).props() as unknown as {
+ onSearchChange: (a: string) => void;
+ }
+ ).onSearchChange('A:\\Some Folder\\inc*.exe');
+ });
+
+ expect(useFieldValueAutocomplete).toHaveBeenCalledWith({
+ autocompleteService: autocompleteStartMock,
+ fieldValue: '',
+ indexPattern: {
+ fields,
+ id: '1234',
+ title: 'logs-endpoint.events.*',
+ },
+ operatorType: 'wildcard',
+ query: 'A:\\Some Folder\\inc*.exe',
+ selectedField: getField('file.path.text'),
+ });
+ });
+});
diff --git a/packages/kbn-securitysolution-autocomplete/src/field_value_wildcard/index.tsx b/packages/kbn-securitysolution-autocomplete/src/field_value_wildcard/index.tsx
new file mode 100644
index 000000000000..159267c3386d
--- /dev/null
+++ b/packages/kbn-securitysolution-autocomplete/src/field_value_wildcard/index.tsx
@@ -0,0 +1,255 @@
+/*
+ * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
+ * or more contributor license agreements. Licensed under the Elastic License
+ * 2.0 and the Server Side Public License, v 1; you may not use this file except
+ * in compliance with, at your election, the Elastic License 2.0 or the Server
+ * Side Public License, v 1.
+ */
+
+import React, { useCallback, useMemo, useState, useEffect, memo } from 'react';
+import { EuiFormRow, EuiComboBoxOptionOption, EuiComboBox } from '@elastic/eui';
+import { DataViewBase, DataViewFieldBase } from '@kbn/es-query';
+
+import { uniq } from 'lodash';
+
+import { ListOperatorTypeEnum as OperatorTypeEnum } from '@kbn/securitysolution-io-ts-list-types';
+
+// TODO: I have to use any here for now, but once this is available below, we should use the correct types, https://github.com/elastic/kibana/issues/100715
+// import { AutocompleteStart } from '../../../../../../../src/plugins/data/public';
+type AutocompleteStart = any;
+
+import * as i18n from '../translations';
+import { useFieldValueAutocomplete } from '../hooks/use_field_value_autocomplete';
+import {
+ getGenericComboBoxProps,
+ GetGenericComboBoxPropsReturn,
+} from '../get_generic_combo_box_props';
+import { paramIsValid } from '../param_is_valid';
+
+const SINGLE_SELECTION = { asPlainText: true };
+
+interface AutocompleteFieldWildcardProps {
+ placeholder: string;
+ selectedField: DataViewFieldBase | undefined;
+ selectedValue: string | undefined;
+ indexPattern: DataViewBase | undefined;
+ isLoading: boolean;
+ isDisabled?: boolean;
+ isClearable?: boolean;
+ isRequired?: boolean;
+ fieldInputWidth?: number;
+ rowLabel?: string;
+ autocompleteService: AutocompleteStart;
+ onChange: (arg: string) => void;
+ onError: (arg: boolean) => void;
+ onWarning: (arg: boolean) => void;
+ warning?: string;
+}
+
+export const AutocompleteFieldWildcardComponent: React.FC = memo(
+ ({
+ autocompleteService,
+ placeholder,
+ rowLabel,
+ selectedField,
+ selectedValue,
+ indexPattern,
+ isLoading,
+ isDisabled = false,
+ isClearable = false,
+ isRequired = false,
+ fieldInputWidth,
+ onChange,
+ onError,
+ onWarning,
+ warning,
+ }): JSX.Element => {
+ const [searchQuery, setSearchQuery] = useState('');
+ const [touched, setIsTouched] = useState(false);
+ const [error, setError] = useState(undefined);
+ const [isLoadingSuggestions, , suggestions] = useFieldValueAutocomplete({
+ autocompleteService,
+ fieldValue: selectedValue,
+ indexPattern,
+ operatorType: OperatorTypeEnum.WILDCARD,
+ query: searchQuery,
+ selectedField,
+ });
+ const getLabel = useCallback((option: string): string => option, []);
+ const optionsMemo = useMemo((): string[] => {
+ const valueAsStr = String(selectedValue);
+ return selectedValue != null && selectedValue.trim() !== ''
+ ? uniq([valueAsStr, ...suggestions])
+ : suggestions;
+ }, [suggestions, selectedValue]);
+ const selectedOptionsMemo = useMemo((): string[] => {
+ const valueAsStr = String(selectedValue);
+ return selectedValue ? [valueAsStr] : [];
+ }, [selectedValue]);
+
+ const handleError = useCallback(
+ (err: string | undefined): void => {
+ setError((existingErr): string | undefined => {
+ const oldErr = existingErr != null;
+ const newErr = err != null;
+ if (oldErr !== newErr && onError != null) {
+ onError(newErr);
+ }
+
+ return err;
+ });
+ },
+ [setError, onError]
+ );
+
+ const handleWarning = useCallback(
+ (warn: string | undefined): void => {
+ onWarning(warn !== undefined);
+ },
+ [onWarning]
+ );
+
+ const { comboOptions, labels, selectedComboOptions } = useMemo(
+ (): GetGenericComboBoxPropsReturn =>
+ getGenericComboBoxProps({
+ getLabel,
+ options: optionsMemo,
+ selectedOptions: selectedOptionsMemo,
+ }),
+ [optionsMemo, selectedOptionsMemo, getLabel]
+ );
+
+ const handleValuesChange = useCallback(
+ (newOptions: EuiComboBoxOptionOption[]): void => {
+ const [newValue] = newOptions.map(({ label }) => optionsMemo[labels.indexOf(label)]);
+ handleError(undefined);
+ handleWarning(undefined);
+ onChange(newValue ?? '');
+ },
+ [handleError, handleWarning, labels, onChange, optionsMemo]
+ );
+
+ const handleSearchChange = useCallback(
+ (searchVal: string): void => {
+ if (searchVal.trim() !== '' && selectedField != null) {
+ const err = paramIsValid(searchVal, selectedField, isRequired, touched);
+ handleError(err);
+ handleWarning(warning);
+ setSearchQuery(searchVal);
+ }
+ },
+ [handleError, isRequired, selectedField, touched, warning, handleWarning]
+ );
+
+ const handleCreateOption = useCallback(
+ (option: string): boolean | undefined => {
+ const err = paramIsValid(option, selectedField, isRequired, touched);
+ handleError(err);
+ handleWarning(warning);
+
+ if (err != null) {
+ // Explicitly reject the user's input
+ return false;
+ } else {
+ onChange(option);
+ return undefined;
+ }
+ },
+ [isRequired, onChange, selectedField, touched, handleError, handleWarning, warning]
+ );
+
+ const setIsTouchedValue = useCallback((): void => {
+ setIsTouched(true);
+
+ const err = paramIsValid(selectedValue, selectedField, isRequired, true);
+ handleError(err);
+ handleWarning(warning);
+ }, [
+ setIsTouched,
+ handleError,
+ selectedValue,
+ selectedField,
+ isRequired,
+ handleWarning,
+ warning,
+ ]);
+
+ const inputPlaceholder = useMemo((): string => {
+ if (isLoading || isLoadingSuggestions) {
+ return i18n.LOADING;
+ } else if (selectedField == null) {
+ return i18n.SELECT_FIELD_FIRST;
+ } else {
+ return placeholder;
+ }
+ }, [isLoading, selectedField, isLoadingSuggestions, placeholder]);
+
+ const isLoadingState = useMemo(
+ (): boolean => isLoading || isLoadingSuggestions,
+ [isLoading, isLoadingSuggestions]
+ );
+
+ useEffect((): void => {
+ setError(undefined);
+ if (onError != null) {
+ onError(false);
+ }
+ if (onWarning != null) {
+ onWarning(false);
+ }
+ }, [selectedField, onError, onWarning]);
+
+ const defaultInput = useMemo((): JSX.Element => {
+ return (
+
+
+
+ );
+ }, [
+ comboOptions,
+ error,
+ fieldInputWidth,
+ handleCreateOption,
+ handleSearchChange,
+ handleValuesChange,
+ inputPlaceholder,
+ isClearable,
+ isDisabled,
+ isLoadingState,
+ rowLabel,
+ selectedComboOptions,
+ selectedField,
+ setIsTouchedValue,
+ warning,
+ ]);
+
+ return defaultInput;
+ }
+);
+
+AutocompleteFieldWildcardComponent.displayName = 'AutocompleteFieldWildcard';
diff --git a/packages/kbn-securitysolution-autocomplete/src/fields/index.mock.ts b/packages/kbn-securitysolution-autocomplete/src/fields/index.mock.ts
index d25dc5d45c9e..b3def81c4336 100644
--- a/packages/kbn-securitysolution-autocomplete/src/fields/index.mock.ts
+++ b/packages/kbn-securitysolution-autocomplete/src/fields/index.mock.ts
@@ -309,6 +309,14 @@ export const fields: DataViewFieldBase[] = [
readFromDocValues: false,
subType: { nested: { path: 'nestedField.nestedChild' } },
},
+ {
+ name: 'file.path.text',
+ type: 'string',
+ esTypes: ['text'],
+ searchable: true,
+ aggregatable: false,
+ subType: { multi: { parent: 'file.path' } },
+ },
] as unknown as DataViewFieldBase[];
export const getField = (name: string) => fields.find((field) => field.name === name);
diff --git a/packages/kbn-securitysolution-autocomplete/src/get_operators/index.test.ts b/packages/kbn-securitysolution-autocomplete/src/get_operators/index.test.ts
index 9ed9c6358c39..24e4d759989e 100644
--- a/packages/kbn-securitysolution-autocomplete/src/get_operators/index.test.ts
+++ b/packages/kbn-securitysolution-autocomplete/src/get_operators/index.test.ts
@@ -8,6 +8,7 @@
import {
doesNotExistOperator,
+ EVENT_FILTERS_OPERATORS,
EXCEPTION_OPERATORS,
existsOperator,
isNotOperator,
@@ -40,6 +41,15 @@ describe('#getOperators', () => {
expect(operator).toEqual([isOperator]);
});
+ test('it includes a "matches" operator when field is "file.path.text"', () => {
+ const operator = getOperators({
+ name: 'file.path.text',
+ type: 'simple',
+ });
+
+ expect(operator).toEqual(EVENT_FILTERS_OPERATORS);
+ });
+
test('it returns all operator types when field type is not null, boolean, or nested', () => {
const operator = getOperators(getField('machine.os.raw'));
diff --git a/packages/kbn-securitysolution-autocomplete/src/get_operators/index.ts b/packages/kbn-securitysolution-autocomplete/src/get_operators/index.ts
index e84dc33e676e..643c330b1524 100644
--- a/packages/kbn-securitysolution-autocomplete/src/get_operators/index.ts
+++ b/packages/kbn-securitysolution-autocomplete/src/get_operators/index.ts
@@ -10,6 +10,7 @@ import { DataViewFieldBase } from '@kbn/es-query';
import {
EXCEPTION_OPERATORS,
+ EVENT_FILTERS_OPERATORS,
OperatorOption,
doesNotExistOperator,
existsOperator,
@@ -30,6 +31,8 @@ export const getOperators = (field: DataViewFieldBase | undefined): OperatorOpti
return [isOperator, isNotOperator, existsOperator, doesNotExistOperator];
} else if (field.type === 'nested') {
return [isOperator];
+ } else if (field.name === 'file.path.text') {
+ return EVENT_FILTERS_OPERATORS;
} else {
return EXCEPTION_OPERATORS;
}
diff --git a/packages/kbn-securitysolution-autocomplete/src/index.ts b/packages/kbn-securitysolution-autocomplete/src/index.ts
index 5fcb3f954189..fcb1ea6b2cde 100644
--- a/packages/kbn-securitysolution-autocomplete/src/index.ts
+++ b/packages/kbn-securitysolution-autocomplete/src/index.ts
@@ -11,6 +11,7 @@ export * from './field_value_exists';
export * from './field_value_lists';
export * from './field_value_match';
export * from './field_value_match_any';
+export * from './field_value_wildcard';
export * from './filter_field_to_list';
export * from './get_generic_combo_box_props';
export * from './get_operators';
diff --git a/packages/kbn-securitysolution-autocomplete/src/operator/index.test.tsx b/packages/kbn-securitysolution-autocomplete/src/operator/index.test.tsx
index 6d1622f0fa95..48f5cbf25b91 100644
--- a/packages/kbn-securitysolution-autocomplete/src/operator/index.test.tsx
+++ b/packages/kbn-securitysolution-autocomplete/src/operator/index.test.tsx
@@ -129,6 +129,9 @@ describe('operator', () => {
{
label: 'is not in list',
},
+ {
+ label: 'matches',
+ },
]);
});
@@ -196,6 +199,30 @@ describe('operator', () => {
]);
});
+ test('it only displays subset of operators if field name is "file.path.text"', () => {
+ const wrapper = mount(
+
+ );
+
+ expect(
+ wrapper.find(`[data-test-subj="operatorAutocompleteComboBox"]`).at(0).prop('options')
+ ).toEqual([
+ { label: 'is' },
+ { label: 'is not' },
+ { label: 'is one of' },
+ { label: 'is not one of' },
+ { label: 'matches' },
+ ]);
+ });
+
test('it invokes "onChange" when option selected', () => {
const mockOnChange = jest.fn();
const wrapper = mount(
diff --git a/packages/kbn-securitysolution-io-ts-list-types/src/common/endpoint/entries/index.mock.ts b/packages/kbn-securitysolution-io-ts-list-types/src/common/endpoint/entries/index.mock.ts
index 176a6357b30e..64f7e1aceeb2 100644
--- a/packages/kbn-securitysolution-io-ts-list-types/src/common/endpoint/entries/index.mock.ts
+++ b/packages/kbn-securitysolution-io-ts-list-types/src/common/endpoint/entries/index.mock.ts
@@ -10,11 +10,11 @@ import { EndpointEntriesArray } from '.';
import { getEndpointEntryMatchMock } from '../entry_match/index.mock';
import { getEndpointEntryMatchAnyMock } from '../entry_match_any/index.mock';
import { getEndpointEntryNestedMock } from '../entry_nested/index.mock';
-import { getEndpointEntryMatchWildcard } from '../entry_match_wildcard/index.mock';
+import { getEndpointEntryMatchWildcardMock } from '../entry_match_wildcard/index.mock';
export const getEndpointEntriesArrayMock = (): EndpointEntriesArray => [
getEndpointEntryMatchMock(),
getEndpointEntryMatchAnyMock(),
getEndpointEntryNestedMock(),
- getEndpointEntryMatchWildcard(),
+ getEndpointEntryMatchWildcardMock(),
];
diff --git a/packages/kbn-securitysolution-io-ts-list-types/src/common/endpoint/entries/index.test.ts b/packages/kbn-securitysolution-io-ts-list-types/src/common/endpoint/entries/index.test.ts
index ca852e15c5c2..08235d35e921 100644
--- a/packages/kbn-securitysolution-io-ts-list-types/src/common/endpoint/entries/index.test.ts
+++ b/packages/kbn-securitysolution-io-ts-list-types/src/common/endpoint/entries/index.test.ts
@@ -20,7 +20,7 @@ import { getEndpointEntryNestedMock } from '../entry_nested/index.mock';
import { getEndpointEntriesArrayMock } from './index.mock';
import { getEntryListMock } from '../../entries_list/index.mock';
import { getEntryExistsMock } from '../../entries_exist/index.mock';
-import { getEndpointEntryMatchWildcard } from '../entry_match_wildcard/index.mock';
+import { getEndpointEntryMatchWildcardMock } from '../entry_match_wildcard/index.mock';
describe('Endpoint', () => {
describe('entriesArray', () => {
@@ -101,7 +101,7 @@ describe('Endpoint', () => {
});
test('it should validate an array with wildcard entry', () => {
- const payload = [getEndpointEntryMatchWildcard()];
+ const payload = [getEndpointEntryMatchWildcardMock()];
const decoded = endpointEntriesArray.decode(payload);
const message = pipe(decoded, foldLeftRight);
diff --git a/packages/kbn-securitysolution-io-ts-list-types/src/common/endpoint/entry_match_wildcard/index.mock.ts b/packages/kbn-securitysolution-io-ts-list-types/src/common/endpoint/entry_match_wildcard/index.mock.ts
index e001552277e0..842e046ea67e 100644
--- a/packages/kbn-securitysolution-io-ts-list-types/src/common/endpoint/entry_match_wildcard/index.mock.ts
+++ b/packages/kbn-securitysolution-io-ts-list-types/src/common/endpoint/entry_match_wildcard/index.mock.ts
@@ -9,7 +9,7 @@
import { ENTRY_VALUE, FIELD, OPERATOR, WILDCARD } from '../../../constants/index.mock';
import { EndpointEntryMatchWildcard } from './index';
-export const getEndpointEntryMatchWildcard = (): EndpointEntryMatchWildcard => ({
+export const getEndpointEntryMatchWildcardMock = (): EndpointEntryMatchWildcard => ({
field: FIELD,
operator: OPERATOR,
type: WILDCARD,
diff --git a/packages/kbn-securitysolution-io-ts-list-types/src/common/endpoint/entry_match_wildcard/index.test.ts b/packages/kbn-securitysolution-io-ts-list-types/src/common/endpoint/entry_match_wildcard/index.test.ts
new file mode 100644
index 000000000000..9671e721f20c
--- /dev/null
+++ b/packages/kbn-securitysolution-io-ts-list-types/src/common/endpoint/entry_match_wildcard/index.test.ts
@@ -0,0 +1,99 @@
+/*
+ * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
+ * or more contributor license agreements. Licensed under the Elastic License
+ * 2.0 and the Server Side Public License, v 1; you may not use this file except
+ * in compliance with, at your election, the Elastic License 2.0 or the Server
+ * Side Public License, v 1.
+ */
+
+import { pipe } from 'fp-ts/lib/pipeable';
+import { left } from 'fp-ts/lib/Either';
+import { getEndpointEntryMatchWildcardMock } from './index.mock';
+import { EndpointEntryMatchWildcard, endpointEntryMatchWildcard } from '.';
+import { foldLeftRight, getPaths } from '@kbn/securitysolution-io-ts-utils';
+import { getEntryMatchWildcardMock } from '../../entry_match_wildcard/index.mock';
+
+describe('endpointEntryMatchWildcard', () => {
+ test('it should validate an entry', () => {
+ const payload = getEndpointEntryMatchWildcardMock();
+ const decoded = endpointEntryMatchWildcard.decode(payload);
+ const message = pipe(decoded, foldLeftRight);
+
+ expect(getPaths(left(message.errors))).toEqual([]);
+ expect(message.schema).toEqual(payload);
+ });
+
+ test('it should NOT validate when "operator" is "excluded"', () => {
+ const payload = getEntryMatchWildcardMock();
+ payload.operator = 'excluded';
+ const decoded = endpointEntryMatchWildcard.decode(payload);
+ const message = pipe(decoded, foldLeftRight);
+
+ expect(getPaths(left(message.errors))).toEqual([
+ 'Invalid value "excluded" supplied to "operator"',
+ ]);
+ expect(message.schema).toEqual({});
+ });
+
+ test('it should FAIL validation when "field" is empty string', () => {
+ const payload: Omit & { field: string } = {
+ ...getEndpointEntryMatchWildcardMock(),
+ field: '',
+ };
+ const decoded = endpointEntryMatchWildcard.decode(payload);
+ const message = pipe(decoded, foldLeftRight);
+
+ expect(getPaths(left(message.errors))).toEqual(['Invalid value "" supplied to "field"']);
+ expect(message.schema).toEqual({});
+ });
+
+ test('it should FAIL validation when "value" is not string', () => {
+ const payload: Omit & { value: string[] } = {
+ ...getEndpointEntryMatchWildcardMock(),
+ value: ['some value'],
+ };
+ const decoded = endpointEntryMatchWildcard.decode(payload);
+ const message = pipe(decoded, foldLeftRight);
+
+ expect(getPaths(left(message.errors))).toEqual([
+ 'Invalid value "["some value"]" supplied to "value"',
+ ]);
+ expect(message.schema).toEqual({});
+ });
+
+ test('it should FAIL validation when "value" is empty string', () => {
+ const payload: Omit & { value: string } = {
+ ...getEndpointEntryMatchWildcardMock(),
+ value: '',
+ };
+ const decoded = endpointEntryMatchWildcard.decode(payload);
+ const message = pipe(decoded, foldLeftRight);
+
+ expect(getPaths(left(message.errors))).toEqual(['Invalid value "" supplied to "value"']);
+ expect(message.schema).toEqual({});
+ });
+
+ test('it should FAIL validation when "type" is not "wildcard"', () => {
+ const payload: Omit & { type: string } = {
+ ...getEndpointEntryMatchWildcardMock(),
+ type: 'match',
+ };
+ const decoded = endpointEntryMatchWildcard.decode(payload);
+ const message = pipe(decoded, foldLeftRight);
+
+ expect(getPaths(left(message.errors))).toEqual(['Invalid value "match" supplied to "type"']);
+ expect(message.schema).toEqual({});
+ });
+
+ test('it should strip out extra keys', () => {
+ const payload: EndpointEntryMatchWildcard & {
+ extraKey?: string;
+ } = getEndpointEntryMatchWildcardMock();
+ payload.extraKey = 'some value';
+ const decoded = endpointEntryMatchWildcard.decode(payload);
+ const message = pipe(decoded, foldLeftRight);
+
+ expect(getPaths(left(message.errors))).toEqual([]);
+ expect(message.schema).toEqual(getEntryMatchWildcardMock());
+ });
+});
diff --git a/packages/kbn-securitysolution-list-utils/src/autocomplete_operators/index.ts b/packages/kbn-securitysolution-list-utils/src/autocomplete_operators/index.ts
index 101076bdfcff..ac3236528b67 100644
--- a/packages/kbn-securitysolution-list-utils/src/autocomplete_operators/index.ts
+++ b/packages/kbn-securitysolution-list-utils/src/autocomplete_operators/index.ts
@@ -85,11 +85,21 @@ export const isNotInListOperator: OperatorOption = {
value: 'is_not_in_list',
};
+export const matchesOperator: OperatorOption = {
+ message: i18n.translate('lists.exceptions.matchesOperatorLabel', {
+ defaultMessage: 'matches',
+ }),
+ operator: OperatorEnum.INCLUDED,
+ type: OperatorTypeEnum.WILDCARD,
+ value: 'matches',
+};
+
export const EVENT_FILTERS_OPERATORS: OperatorOption[] = [
isOperator,
isNotOperator,
isOneOfOperator,
isNotOneOfOperator,
+ matchesOperator,
];
export const EXCEPTION_OPERATORS: OperatorOption[] = [
@@ -101,6 +111,7 @@ export const EXCEPTION_OPERATORS: OperatorOption[] = [
doesNotExistOperator,
isInListOperator,
isNotInListOperator,
+ matchesOperator,
];
export const EXCEPTION_OPERATORS_SANS_LISTS: OperatorOption[] = [
diff --git a/packages/kbn-securitysolution-list-utils/src/helpers/index.ts b/packages/kbn-securitysolution-list-utils/src/helpers/index.ts
index 394d4f02b877..eabf8dfa33f9 100644
--- a/packages/kbn-securitysolution-list-utils/src/helpers/index.ts
+++ b/packages/kbn-securitysolution-list-utils/src/helpers/index.ts
@@ -172,6 +172,8 @@ export const getOperatorType = (item: BuilderEntry): OperatorTypeEnum => {
return OperatorTypeEnum.MATCH;
case 'match_any':
return OperatorTypeEnum.MATCH_ANY;
+ case 'wildcard':
+ return OperatorTypeEnum.WILDCARD;
case 'list':
return OperatorTypeEnum.LIST;
default:
@@ -207,6 +209,7 @@ export const getEntryValue = (item: BuilderEntry): string | string[] | undefined
switch (item.type) {
case OperatorTypeEnum.MATCH:
case OperatorTypeEnum.MATCH_ANY:
+ case OperatorTypeEnum.WILDCARD:
return item.value;
case OperatorTypeEnum.EXISTS:
return undefined;
@@ -523,6 +526,54 @@ export const getEntryOnMatchChange = (
}
};
+/**
+ * Determines proper entry update when user updates value
+ * when operator is of type "wildcard"
+ *
+ * @param item - current exception item entry values
+ * @param newField - newly entered value
+ *
+ */
+export const getEntryOnWildcardChange = (
+ item: FormattedBuilderEntry,
+ newField: string
+): { index: number; updatedEntry: BuilderEntry } => {
+ const { nested, parent, entryIndex, field, operator } = item;
+
+ if (nested != null && parent != null) {
+ const fieldName = field != null ? field.name.split('.').slice(-1)[0] : '';
+
+ return {
+ index: parent.parentIndex,
+ updatedEntry: {
+ ...parent.parent,
+ entries: [
+ ...parent.parent.entries.slice(0, entryIndex),
+ {
+ field: fieldName,
+ id: item.id,
+ operator: operator.operator,
+ type: OperatorTypeEnum.WILDCARD,
+ value: newField,
+ },
+ ...parent.parent.entries.slice(entryIndex + 1),
+ ],
+ },
+ };
+ } else {
+ return {
+ index: entryIndex,
+ updatedEntry: {
+ field: field != null ? field.name : '',
+ id: item.id,
+ operator: operator.operator,
+ type: OperatorTypeEnum.WILDCARD,
+ value: newField,
+ },
+ };
+ }
+};
+
/**
* On operator change, determines whether value needs to be cleared or not
*
@@ -563,6 +614,15 @@ export const getEntryFromOperator = (
operator: selectedOperator.operator,
type: OperatorTypeEnum.LIST,
};
+ case 'wildcard':
+ return {
+ field: fieldValue,
+ id: currentEntry.id,
+ operator: selectedOperator.operator,
+ type: OperatorTypeEnum.WILDCARD,
+ value:
+ isSameOperatorType && typeof currentEntry.value === 'string' ? currentEntry.value : '',
+ };
default:
return {
field: fieldValue,
diff --git a/packages/kbn-securitysolution-utils/BUILD.bazel b/packages/kbn-securitysolution-utils/BUILD.bazel
index cfb6b722ea2e..70ecc2712d4a 100644
--- a/packages/kbn-securitysolution-utils/BUILD.bazel
+++ b/packages/kbn-securitysolution-utils/BUILD.bazel
@@ -28,11 +28,13 @@ NPM_MODULE_EXTRA_FILES = [
]
RUNTIME_DEPS = [
+ "//packages/kbn-i18n",
"@npm//tslib",
- "@npm//uuid",
+ "@npm//uuid"
]
TYPES_DEPS = [
+ "//packages/kbn-i18n:npm_module_types",
"@npm//tslib",
"@npm//@types/jest",
"@npm//@types/node",
diff --git a/packages/kbn-securitysolution-utils/src/index.ts b/packages/kbn-securitysolution-utils/src/index.ts
index 755bbd2203df..e3442a3ec7dc 100644
--- a/packages/kbn-securitysolution-utils/src/index.ts
+++ b/packages/kbn-securitysolution-utils/src/index.ts
@@ -8,3 +8,4 @@
export * from './add_remove_id_to_item';
export * from './transform_data_to_ndjson';
+export * from './path_validations';
diff --git a/x-pack/plugins/security_solution/common/endpoint/service/trusted_apps/validations.test.ts b/packages/kbn-securitysolution-utils/src/path_validations/index.test.ts
similarity index 84%
rename from x-pack/plugins/security_solution/common/endpoint/service/trusted_apps/validations.test.ts
rename to packages/kbn-securitysolution-utils/src/path_validations/index.test.ts
index 952a2fa234ac..ee2d8764a30a 100644
--- a/x-pack/plugins/security_solution/common/endpoint/service/trusted_apps/validations.test.ts
+++ b/packages/kbn-securitysolution-utils/src/path_validations/index.test.ts
@@ -1,12 +1,84 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License
- * 2.0; you may not use this file except in compliance with the Elastic License
- * 2.0.
+ * 2.0 and the Server Side Public License, v 1; you may not use this file except
+ * in compliance with, at your election, the Elastic License 2.0 or the Server
+ * Side Public License, v 1.
*/
-import { isPathValid, hasSimpleExecutableName } from './validations';
-import { OperatingSystem, ConditionEntryField } from '../../types';
+import {
+ isPathValid,
+ hasSimpleExecutableName,
+ OperatingSystem,
+ ConditionEntryField,
+ validateFilePathInput,
+ FILENAME_WILDCARD_WARNING,
+ FILEPATH_WARNING,
+} from '.';
+
+describe('validateFilePathInput', () => {
+ describe('windows', () => {
+ const os = OperatingSystem.WINDOWS;
+
+ it('warns on wildcard in file name at the end of the path', () => {
+ expect(validateFilePathInput({ os, value: 'c:\\path*.exe' })).toEqual(
+ FILENAME_WILDCARD_WARNING
+ );
+ });
+
+ it('warns on unix paths or non-windows paths', () => {
+ expect(validateFilePathInput({ os, value: '/opt/bin' })).toEqual(FILEPATH_WARNING);
+ });
+
+ it('warns on malformed paths', () => {
+ expect(validateFilePathInput({ os, value: 'c:\\path/opt' })).toEqual(FILEPATH_WARNING);
+ expect(validateFilePathInput({ os, value: '1242' })).toEqual(FILEPATH_WARNING);
+ expect(validateFilePathInput({ os, value: 'w12efdfa' })).toEqual(FILEPATH_WARNING);
+ });
+ });
+ describe('unix paths', () => {
+ const os =
+ parseInt((Math.random() * 2).toString(), 10) === 1
+ ? OperatingSystem.MAC
+ : OperatingSystem.LINUX;
+
+ it('warns on wildcard in file name at the end of the path', () => {
+ expect(validateFilePathInput({ os, value: '/opt/bin*' })).toEqual(FILENAME_WILDCARD_WARNING);
+ });
+
+ it('warns on windows paths', () => {
+ expect(validateFilePathInput({ os, value: 'd:\\path\\file.exe' })).toEqual(FILEPATH_WARNING);
+ });
+
+ it('warns on malformed paths', () => {
+ expect(validateFilePathInput({ os, value: 'opt/bin\\file.exe' })).toEqual(FILEPATH_WARNING);
+ expect(validateFilePathInput({ os, value: '1242' })).toEqual(FILEPATH_WARNING);
+ expect(validateFilePathInput({ os, value: 'w12efdfa' })).toEqual(FILEPATH_WARNING);
+ });
+ });
+});
+
+describe('No Warnings', () => {
+ it('should not show warnings on non path entries ', () => {
+ expect(
+ isPathValid({
+ os: OperatingSystem.WINDOWS,
+ field: ConditionEntryField.HASH,
+ type: 'match',
+ value: '5d5b09f6dcb2d53a5fffc60c4ac0d55fabdf556069d6631545f42aa6e3500f2e',
+ })
+ ).toEqual(true);
+
+ expect(
+ isPathValid({
+ os: OperatingSystem.WINDOWS,
+ field: ConditionEntryField.SIGNER,
+ type: 'match',
+ value: '',
+ })
+ ).toEqual(true);
+ });
+});
describe('Unacceptable Windows wildcard paths', () => {
it('should not accept paths that do not have a folder name with a wildcard ', () => {
diff --git a/packages/kbn-securitysolution-utils/src/path_validations/index.ts b/packages/kbn-securitysolution-utils/src/path_validations/index.ts
new file mode 100644
index 000000000000..82d2cc3151b9
--- /dev/null
+++ b/packages/kbn-securitysolution-utils/src/path_validations/index.ts
@@ -0,0 +1,178 @@
+/*
+ * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
+ * or more contributor license agreements. Licensed under the Elastic License
+ * 2.0 and the Server Side Public License, v 1; you may not use this file except
+ * in compliance with, at your election, the Elastic License 2.0 or the Server
+ * Side Public License, v 1.
+ */
+
+import { i18n } from '@kbn/i18n';
+
+export const FILENAME_WILDCARD_WARNING = i18n.translate('utils.filename.wildcardWarning', {
+ defaultMessage: `A wildcard in the filename will affect the endpoint's performance`,
+});
+
+export const FILEPATH_WARNING = i18n.translate('utils.filename.pathWarning', {
+ defaultMessage: `Path may be formed incorrectly; verify value`,
+});
+
+export const enum ConditionEntryField {
+ HASH = 'process.hash.*',
+ PATH = 'process.executable.caseless',
+ SIGNER = 'process.Ext.code_signature',
+}
+
+export const enum OperatingSystem {
+ LINUX = 'linux',
+ MAC = 'macos',
+ WINDOWS = 'windows',
+}
+
+export type TrustedAppEntryTypes = 'match' | 'wildcard';
+/*
+ * regex to match executable names
+ * starts matching from the eol of the path
+ * file names with a single or multiple spaces (for spaced names)
+ * and hyphens and combinations of these that produce complex names
+ * such as:
+ * c:\home\lib\dmp.dmp
+ * c:\home\lib\my-binary-app-+/ some/ x/ dmp.dmp
+ * /home/lib/dmp.dmp
+ * /home/lib/my-binary-app+-\ some\ x\ dmp.dmp
+ */
+export const WIN_EXEC_PATH = /(\\[-\w]+|\\[-\w]+[\.]+[\w]+)$/i;
+export const UNIX_EXEC_PATH = /(\/[-\w]+|\/[-\w]+[\.]+[\w]+)$/i;
+
+export const validateFilePathInput = ({
+ os,
+ value = '',
+}: {
+ os: OperatingSystem;
+ value?: string;
+}): string | undefined => {
+ const textInput = value.trim();
+ const isValidFilePath = isPathValid({
+ os,
+ field: 'file.path.text',
+ type: 'wildcard',
+ value: textInput,
+ });
+ const hasSimpleFileName = hasSimpleExecutableName({
+ os,
+ type: 'wildcard',
+ value: textInput,
+ });
+
+ if (!textInput.length) {
+ return FILEPATH_WARNING;
+ }
+
+ if (isValidFilePath) {
+ if (!hasSimpleFileName) {
+ return FILENAME_WILDCARD_WARNING;
+ }
+ } else {
+ return FILEPATH_WARNING;
+ }
+};
+
+export const hasSimpleExecutableName = ({
+ os,
+ type,
+ value,
+}: {
+ os: OperatingSystem;
+ type: TrustedAppEntryTypes;
+ value: string;
+}): boolean => {
+ if (type === 'wildcard') {
+ return os === OperatingSystem.WINDOWS ? WIN_EXEC_PATH.test(value) : UNIX_EXEC_PATH.test(value);
+ }
+ return true;
+};
+
+export const isPathValid = ({
+ os,
+ field,
+ type,
+ value,
+}: {
+ os: OperatingSystem;
+ field: ConditionEntryField | 'file.path.text';
+ type: TrustedAppEntryTypes;
+ value: string;
+}): boolean => {
+ if (field === ConditionEntryField.PATH || field === 'file.path.text') {
+ if (type === 'wildcard') {
+ return os === OperatingSystem.WINDOWS
+ ? isWindowsWildcardPathValid(value)
+ : isLinuxMacWildcardPathValid(value);
+ }
+ return doesPathMatchRegex({ value, os });
+ }
+ return true;
+};
+
+const doesPathMatchRegex = ({ os, value }: { os: OperatingSystem; value: string }): boolean => {
+ if (os === OperatingSystem.WINDOWS) {
+ const filePathRegex =
+ /^[a-z]:(?:|\\\\[^<>:"'/\\|?*]+\\[^<>:"'/\\|?*]+|%\w+%|)[\\](?:[^<>:"'/\\|?*]+[\\/])*([^<>:"'/\\|?*])+$/i;
+ return filePathRegex.test(value);
+ }
+ return /^(\/|(\/[\w\-]+)+|\/[\w\-]+\.[\w]+|(\/[\w-]+)+\/[\w\-]+\.[\w]+)$/i.test(value);
+};
+
+const isWindowsWildcardPathValid = (path: string): boolean => {
+ const firstCharacter = path[0];
+ const lastCharacter = path.slice(-1);
+ const trimmedValue = path.trim();
+ const hasSlash = /\//.test(trimmedValue);
+ if (path.length === 0) {
+ return false;
+ } else if (
+ hasSlash ||
+ trimmedValue.length !== path.length ||
+ firstCharacter === '^' ||
+ lastCharacter === '\\' ||
+ !hasWildcard({ path, isWindowsPath: true })
+ ) {
+ return false;
+ } else {
+ return true;
+ }
+};
+
+const isLinuxMacWildcardPathValid = (path: string): boolean => {
+ const firstCharacter = path[0];
+ const lastCharacter = path.slice(-1);
+ const trimmedValue = path.trim();
+ if (path.length === 0) {
+ return false;
+ } else if (
+ trimmedValue.length !== path.length ||
+ firstCharacter !== '/' ||
+ lastCharacter === '/' ||
+ path.length > 1024 === true ||
+ path.includes('//') === true ||
+ !hasWildcard({ path, isWindowsPath: false })
+ ) {
+ return false;
+ } else {
+ return true;
+ }
+};
+
+const hasWildcard = ({
+ path,
+ isWindowsPath,
+}: {
+ path: string;
+ isWindowsPath: boolean;
+}): boolean => {
+ for (const pathComponent of path.split(isWindowsPath ? '\\' : '/')) {
+ if (/[\*|\?]+/.test(pathComponent) === true) {
+ return true;
+ }
+ }
+ return false;
+};
diff --git a/packages/kbn-storybook/src/lib/decorators.tsx b/packages/kbn-storybook/src/lib/decorators.tsx
index 97ee5393b4ea..24af82875424 100644
--- a/packages/kbn-storybook/src/lib/decorators.tsx
+++ b/packages/kbn-storybook/src/lib/decorators.tsx
@@ -11,6 +11,8 @@ import { EuiProvider } from '@elastic/eui';
import createCache from '@emotion/cache';
import type { DecoratorFn } from '@storybook/react';
+import 'core_styles';
+
/**
* Storybook decorator using the EUI provider. Uses the value from
* `globals` provided by the Storybook theme switcher.
diff --git a/packages/kbn-storybook/src/lib/default_config.ts b/packages/kbn-storybook/src/lib/default_config.ts
index 6db6a6bd4643..3caf879c48cb 100644
--- a/packages/kbn-storybook/src/lib/default_config.ts
+++ b/packages/kbn-storybook/src/lib/default_config.ts
@@ -26,7 +26,16 @@ export const defaultConfig: StorybookConfig = {
// @ts-expect-error StorybookConfig type is incomplete
// https://storybook.js.org/docs/react/configure/babel#custom-configuration
babel: async (options) => {
- options.presets.push('@emotion/babel-preset-css-prop');
+ options.presets.push([
+ require.resolve('@emotion/babel-preset-css-prop'),
+ {
+ // There's an issue where emotion classnames may be duplicated,
+ // (e.g. `[hash]-[filename]--[local]_[filename]--[local]`)
+ // https://github.com/emotion-js/emotion/issues/2417
+ autoLabel: 'always',
+ labelFormat: '[filename]--[local]',
+ },
+ ]);
return options;
},
webpackFinal: (config, options) => {
diff --git a/packages/kbn-storybook/src/webpack.config.ts b/packages/kbn-storybook/src/webpack.config.ts
index 8d5818182b87..4da3c58688f7 100644
--- a/packages/kbn-storybook/src/webpack.config.ts
+++ b/packages/kbn-storybook/src/webpack.config.ts
@@ -121,6 +121,7 @@ export default ({ config: storybookConfig }: { config: Configuration }) => {
mainFields: ['browser', 'main'],
alias: {
core_app_image_assets: resolve(REPO_ROOT, 'src/core/public/core_app/images'),
+ core_styles: resolve(REPO_ROOT, 'src/core/public/index.scss'),
},
symlinks: false,
},
diff --git a/packages/kbn-storybook/templates/index.ejs b/packages/kbn-storybook/templates/index.ejs
index 8be0e58bf87d..53dc0f5e5575 100644
--- a/packages/kbn-storybook/templates/index.ejs
+++ b/packages/kbn-storybook/templates/index.ejs
@@ -38,7 +38,7 @@
-
+
<% if (typeof bodyHtmlSnippet !== 'undefined') { %>
diff --git a/packages/kbn-telemetry-tools/src/tools/check_collector__integrity.test.ts b/packages/kbn-telemetry-tools/src/tools/check_collector__integrity.test.ts
index 2485b04f4b10..4e7cff799ea7 100644
--- a/packages/kbn-telemetry-tools/src/tools/check_collector__integrity.test.ts
+++ b/packages/kbn-telemetry-tools/src/tools/check_collector__integrity.test.ts
@@ -78,7 +78,6 @@ describe('checkCompatibleTypeDescriptor', () => {
]);
expect(incompatibles).toHaveLength(1);
const { diff, message } = incompatibles[0];
- // eslint-disable-next-line @typescript-eslint/naming-convention
expect(diff).toEqual({ '@@INDEX@@.count_2.kind': 'number' });
expect(message).toHaveLength(1);
expect(message).toEqual([
diff --git a/packages/kbn-test-jest-helpers/src/enzyme_helpers.tsx b/packages/kbn-test-jest-helpers/src/enzyme_helpers.tsx
index 222689d621b5..8388ed55eb51 100644
--- a/packages/kbn-test-jest-helpers/src/enzyme_helpers.tsx
+++ b/packages/kbn-test-jest-helpers/src/enzyme_helpers.tsx
@@ -14,7 +14,6 @@
*/
import { I18nProvider, InjectedIntl, intlShape, __IntlProvider } from '@kbn/i18n-react';
-// eslint-disable-next-line import/no-extraneous-dependencies
import { mount, ReactWrapper, render, shallow } from 'enzyme';
import React, { ReactElement, ValidationMap } from 'react';
import { act as reactAct } from 'react-dom/test-utils';
diff --git a/packages/kbn-test-jest-helpers/src/find_test_subject.ts b/packages/kbn-test-jest-helpers/src/find_test_subject.ts
index 9d519f5197cd..ef3a744fbd99 100644
--- a/packages/kbn-test-jest-helpers/src/find_test_subject.ts
+++ b/packages/kbn-test-jest-helpers/src/find_test_subject.ts
@@ -6,7 +6,6 @@
* Side Public License, v 1.
*/
-// eslint-disable-next-line import/no-extraneous-dependencies
import { ReactWrapper } from 'enzyme';
type Matcher = '=' | '~=' | '|=' | '^=' | '$=' | '*=';
diff --git a/packages/kbn-test-jest-helpers/src/random.ts b/packages/kbn-test-jest-helpers/src/random.ts
index 9f4efccf810f..4aa8a30555e0 100644
--- a/packages/kbn-test-jest-helpers/src/random.ts
+++ b/packages/kbn-test-jest-helpers/src/random.ts
@@ -6,7 +6,6 @@
* Side Public License, v 1.
*/
-// eslint-disable-next-line import/no-extraneous-dependencies
import Chance from 'chance';
const chance = new Chance();
diff --git a/packages/kbn-test-jest-helpers/src/testbed/mount_component.tsx b/packages/kbn-test-jest-helpers/src/testbed/mount_component.tsx
index 5c5fd3f2237d..2ac482abc0fb 100644
--- a/packages/kbn-test-jest-helpers/src/testbed/mount_component.tsx
+++ b/packages/kbn-test-jest-helpers/src/testbed/mount_component.tsx
@@ -8,7 +8,6 @@
import React, { ComponentType } from 'react';
import { Store } from 'redux';
-// eslint-disable-next-line import/no-extraneous-dependencies
import { ReactWrapper } from 'enzyme';
import { act } from 'react-dom/test-utils';
diff --git a/packages/kbn-test-jest-helpers/src/testbed/testbed.ts b/packages/kbn-test-jest-helpers/src/testbed/testbed.ts
index 87efb9e61b34..ddd574ace64b 100644
--- a/packages/kbn-test-jest-helpers/src/testbed/testbed.ts
+++ b/packages/kbn-test-jest-helpers/src/testbed/testbed.ts
@@ -7,7 +7,6 @@
*/
import { Component as ReactComponent } from 'react';
-// eslint-disable-next-line import/no-extraneous-dependencies
import { ComponentType, HTMLAttributes, ReactWrapper } from 'enzyme';
import { findTestSubject } from '../find_test_subject';
diff --git a/packages/kbn-test-jest-helpers/src/testbed/types.ts b/packages/kbn-test-jest-helpers/src/testbed/types.ts
index ff548f3af5f5..11f8c802a975 100644
--- a/packages/kbn-test-jest-helpers/src/testbed/types.ts
+++ b/packages/kbn-test-jest-helpers/src/testbed/types.ts
@@ -7,7 +7,6 @@
*/
import { Store } from 'redux';
-// eslint-disable-next-line import/no-extraneous-dependencies
import { ReactWrapper as GenericReactWrapper } from 'enzyme';
import { LocationDescriptor } from 'history';
diff --git a/packages/kbn-test/BUILD.bazel b/packages/kbn-test/BUILD.bazel
index 6732b08d8bc7..4dc8d684941f 100644
--- a/packages/kbn-test/BUILD.bazel
+++ b/packages/kbn-test/BUILD.bazel
@@ -53,6 +53,7 @@ RUNTIME_DEPS = [
"@npm//execa",
"@npm//exit-hook",
"@npm//form-data",
+ "@npm//get-port",
"@npm//getopts",
"@npm//globby",
"@npm//he",
@@ -90,6 +91,7 @@ TYPES_DEPS = [
"@npm//del",
"@npm//exit-hook",
"@npm//form-data",
+ "@npm//get-port",
"@npm//getopts",
"@npm//jest",
"@npm//jest-cli",
diff --git a/packages/kbn-test/jest-preset.js b/packages/kbn-test/jest-preset.js
index 9dad901f5eb2..ba515865e532 100644
--- a/packages/kbn-test/jest-preset.js
+++ b/packages/kbn-test/jest-preset.js
@@ -9,6 +9,8 @@
// For a detailed explanation regarding each configuration property, visit:
// https://jestjs.io/docs/en/configuration.html
+/** @typedef {import("@jest/types").Config.InitialOptions} JestConfig */
+/** @type {JestConfig} */
module.exports = {
// The directory where Jest should output its coverage files
coverageDirectory: '/target/kibana-coverage/jest',
@@ -128,4 +130,6 @@ module.exports = {
// A custom resolver to preserve symlinks by default
resolver: '/node_modules/@kbn/test/target_node/jest/setup/preserve_symlinks_resolver.js',
+
+ watchPathIgnorePatterns: ['.*/__tmp__/.*'],
};
diff --git a/packages/kbn-test/src/es/es_client_for_testing.ts b/packages/kbn-test/src/es/es_client_for_testing.ts
index 084cb8d77eac..3eeccffcc218 100644
--- a/packages/kbn-test/src/es/es_client_for_testing.ts
+++ b/packages/kbn-test/src/es/es_client_for_testing.ts
@@ -27,6 +27,22 @@ export interface EsClientForTestingOptions extends Omit
+) {
+ const ccsConfig = config.get('esTestCluster.ccs');
+ if (!ccsConfig) {
+ throw new Error('FTR config is missing esTestCluster.ccs');
+ }
+
+ return createEsClientForTesting({
+ esUrl: ccsConfig.remoteClusterUrl,
+ requestTimeout: config.get('timeouts.esRequestTimeout'),
+ ...overrides,
+ });
+}
+
export function createEsClientForFtrConfig(
config: Config,
overrides?: Omit
diff --git a/packages/kbn-test/src/es/index.ts b/packages/kbn-test/src/es/index.ts
index 641253acc364..bdc338894582 100644
--- a/packages/kbn-test/src/es/index.ts
+++ b/packages/kbn-test/src/es/index.ts
@@ -9,5 +9,9 @@
export { createTestEsCluster } from './test_es_cluster';
export type { CreateTestEsClusterOptions, EsTestCluster, ICluster } from './test_es_cluster';
export { esTestConfig } from './es_test_config';
-export { createEsClientForTesting, createEsClientForFtrConfig } from './es_client_for_testing';
+export {
+ createEsClientForTesting,
+ createEsClientForFtrConfig,
+ createRemoteEsClientForFtrConfig,
+} from './es_client_for_testing';
export type { EsClientForTestingOptions } from './es_client_for_testing';
diff --git a/packages/kbn-test/src/es/test_es_cluster.ts b/packages/kbn-test/src/es/test_es_cluster.ts
index 6e4fc2fb1462..27f29ce6995a 100644
--- a/packages/kbn-test/src/es/test_es_cluster.ts
+++ b/packages/kbn-test/src/es/test_es_cluster.ts
@@ -136,7 +136,15 @@ export interface CreateTestEsClusterOptions {
* }
*/
port?: number;
+ /**
+ * Should this ES cluster use SSL?
+ */
ssl?: boolean;
+ /**
+ * Explicit transport port for a single node to run on, or a string port range to use eg. '9300-9400'
+ * defaults to the transport port from `packages/kbn-test/src/es/es_test_config.ts`
+ */
+ transportPort?: number | string;
}
export function createTestEsCluster<
@@ -155,13 +163,14 @@ export function createTestEsCluster<
esJavaOpts,
clusterName: customClusterName = 'es-test-cluster',
ssl,
+ transportPort,
} = options;
const clusterName = `${CI_PARALLEL_PROCESS_PREFIX}${customClusterName}`;
const defaultEsArgs = [
`cluster.name=${clusterName}`,
- `transport.port=${esTestConfig.getTransportPort()}`,
+ `transport.port=${transportPort ?? esTestConfig.getTransportPort()}`,
// For multi-node clusters, we make all nodes master-eligible by default.
...(nodes.length > 1
? ['discovery.type=zen', `cluster.initial_master_nodes=${nodes.map((n) => n.name).join(',')}`]
diff --git a/packages/kbn-test/src/functional_test_runner/fake_mocha_types.ts b/packages/kbn-test/src/functional_test_runner/fake_mocha_types.ts
index dec381fb04b5..96ebcd79c4e4 100644
--- a/packages/kbn-test/src/functional_test_runner/fake_mocha_types.ts
+++ b/packages/kbn-test/src/functional_test_runner/fake_mocha_types.ts
@@ -31,6 +31,7 @@ export interface Test {
file?: string;
parent?: Suite;
isPassed: () => boolean;
+ pending?: boolean;
}
export interface Runner extends EventEmitter {
diff --git a/packages/kbn-test/src/functional_test_runner/functional_test_runner.ts b/packages/kbn-test/src/functional_test_runner/functional_test_runner.ts
index 53ec36dfbe55..c8caad3049f1 100644
--- a/packages/kbn-test/src/functional_test_runner/functional_test_runner.ts
+++ b/packages/kbn-test/src/functional_test_runner/functional_test_runner.ts
@@ -6,7 +6,8 @@
* Side Public License, v 1.
*/
-import Path from 'path';
+import { writeFileSync, mkdirSync } from 'fs';
+import Path, { dirname } from 'path';
import { ToolingLog } from '@kbn/dev-utils';
import { REPO_ROOT } from '@kbn/utils';
@@ -98,6 +99,15 @@ export class FunctionalTestRunner {
reporterOptions
);
+ // there's a bug in mocha's dry run, see https://github.com/mochajs/mocha/issues/4838
+ // until we can update to a mocha version where this is fixed, we won't actually
+ // execute the mocha dry run but simulate it by reading the suites and tests of
+ // the mocha object and writing a report file with similar structure to the json report
+ // (just leave out some execution details like timing, retry and erros)
+ if (config.get('mochaOpts.dryRun')) {
+ return this.simulateMochaDryRun(mocha);
+ }
+
await this.lifecycle.beforeTests.trigger(mocha.suite);
this.log.info('Starting tests');
@@ -145,8 +155,9 @@ export class FunctionalTestRunner {
readProviderSpec(type, providers).map((p) => ({
...p,
fn: skip.includes(p.name)
- ? (...args: unknown[]) => {
- const result = p.fn(...args);
+ ? (ctx: any) => {
+ const result = ProviderCollection.callProviderFn(p.fn, ctx);
+
if ('then' in result) {
throw new Error(
`Provider [${p.name}] returns a promise so it can't loaded during test analysis`
@@ -244,4 +255,62 @@ export class FunctionalTestRunner {
this.closed = true;
await this.lifecycle.cleanup.trigger();
}
+
+ simulateMochaDryRun(mocha: any) {
+ interface TestEntry {
+ file: string;
+ title: string;
+ fullTitle: string;
+ }
+
+ const getFullTitle = (node: Test | Suite): string => {
+ const parentTitle = node.parent && getFullTitle(node.parent);
+ return parentTitle ? `${parentTitle} ${node.title}` : node.title;
+ };
+
+ let suiteCount = 0;
+ const passes: TestEntry[] = [];
+ const pending: TestEntry[] = [];
+
+ const collectTests = (suite: Suite) => {
+ for (const subSuite of suite.suites) {
+ suiteCount++;
+ for (const test of subSuite.tests) {
+ const testEntry = {
+ title: test.title,
+ fullTitle: getFullTitle(test),
+ file: test.file || '',
+ };
+ if (test.pending) {
+ pending.push(testEntry);
+ } else {
+ passes.push(testEntry);
+ }
+ }
+ collectTests(subSuite);
+ }
+ };
+
+ collectTests(mocha.suite);
+
+ const reportData = {
+ stats: {
+ suites: suiteCount,
+ tests: passes.length + pending.length,
+ passes: passes.length,
+ pending: pending.length,
+ failures: 0,
+ },
+ tests: [...passes, ...pending],
+ passes,
+ pending,
+ failures: [],
+ };
+
+ const reportPath = mocha.options.reporterOptions.output;
+ mkdirSync(dirname(reportPath), { recursive: true });
+ writeFileSync(reportPath, JSON.stringify(reportData, null, 2), 'utf8');
+
+ return 0;
+ }
}
diff --git a/packages/kbn-test/src/functional_test_runner/index.ts b/packages/kbn-test/src/functional_test_runner/index.ts
index e67e72fd5801..b5d55c28ee9b 100644
--- a/packages/kbn-test/src/functional_test_runner/index.ts
+++ b/packages/kbn-test/src/functional_test_runner/index.ts
@@ -7,7 +7,14 @@
*/
export { FunctionalTestRunner } from './functional_test_runner';
-export { readConfigFile, Config, EsVersion, Lifecycle, LifecyclePhase } from './lib';
+export {
+ readConfigFile,
+ Config,
+ createAsyncInstance,
+ EsVersion,
+ Lifecycle,
+ LifecyclePhase,
+} from './lib';
export type { ScreenshotRecord } from './lib';
export { runFtrCli } from './cli';
export * from './lib/docker_servers';
diff --git a/packages/kbn-test/src/functional_test_runner/integration_tests/__fixtures__/failure_hooks/config.js b/packages/kbn-test/src/functional_test_runner/integration_tests/__fixtures__/failure_hooks/config.js
index 6e25e4c073ab..417fc8e10aec 100644
--- a/packages/kbn-test/src/functional_test_runner/integration_tests/__fixtures__/failure_hooks/config.js
+++ b/packages/kbn-test/src/functional_test_runner/integration_tests/__fixtures__/failure_hooks/config.js
@@ -37,5 +37,10 @@ export default function () {
captureLogOutput: false,
sendToCiStats: false,
},
+ servers: {
+ elasticsearch: {
+ port: 1234,
+ },
+ },
};
}
diff --git a/packages/kbn-test/src/functional_test_runner/integration_tests/__fixtures__/simple_project/config.js b/packages/kbn-test/src/functional_test_runner/integration_tests/__fixtures__/simple_project/config.js
index 4c87b53b5753..067528c4ae12 100644
--- a/packages/kbn-test/src/functional_test_runner/integration_tests/__fixtures__/simple_project/config.js
+++ b/packages/kbn-test/src/functional_test_runner/integration_tests/__fixtures__/simple_project/config.js
@@ -13,4 +13,9 @@ export default () => ({
mochaReporter: {
sendToCiStats: false,
},
+ servers: {
+ elasticsearch: {
+ port: 1234,
+ },
+ },
});
diff --git a/packages/kbn-test/src/functional_test_runner/integration_tests/failure_hooks.test.js b/packages/kbn-test/src/functional_test_runner/integration_tests/failure_hooks.test.js
index 0d986a1602e1..47ae51ca62f1 100644
--- a/packages/kbn-test/src/functional_test_runner/integration_tests/failure_hooks.test.js
+++ b/packages/kbn-test/src/functional_test_runner/integration_tests/failure_hooks.test.js
@@ -61,7 +61,7 @@ describe('failure hooks', function () {
expect(tests).toHaveLength(0);
} catch (error) {
- console.error('full log output', linesCopy.join('\n'));
+ error.message += `\n\nfull log output:${linesCopy.join('\n')}`;
throw error;
}
});
diff --git a/packages/kbn-test/src/functional_test_runner/lib/config/__fixtures__/config.1.js b/packages/kbn-test/src/functional_test_runner/lib/config/__fixtures__/config.1.js
index 123bc8b9bc20..afcad01c4ab9 100644
--- a/packages/kbn-test/src/functional_test_runner/lib/config/__fixtures__/config.1.js
+++ b/packages/kbn-test/src/functional_test_runner/lib/config/__fixtures__/config.1.js
@@ -9,5 +9,10 @@
export default function () {
return {
testFiles: ['config.1'],
+ servers: {
+ elasticsearch: {
+ port: 1234,
+ },
+ },
};
}
diff --git a/packages/kbn-test/src/functional_test_runner/lib/config/__fixtures__/config.2.js b/packages/kbn-test/src/functional_test_runner/lib/config/__fixtures__/config.2.js
index 2dd4c96186fc..692a3de78672 100644
--- a/packages/kbn-test/src/functional_test_runner/lib/config/__fixtures__/config.2.js
+++ b/packages/kbn-test/src/functional_test_runner/lib/config/__fixtures__/config.2.js
@@ -11,5 +11,10 @@ export default async function ({ readConfigFile }) {
return {
testFiles: [...config1.get('testFiles'), 'config.2'],
+ servers: {
+ elasticsearch: {
+ port: 1234,
+ },
+ },
};
}
diff --git a/packages/kbn-test/src/functional_test_runner/lib/config/config.test.ts b/packages/kbn-test/src/functional_test_runner/lib/config/config.test.ts
index 88c1fd99f001..d551e7a884b4 100644
--- a/packages/kbn-test/src/functional_test_runner/lib/config/config.test.ts
+++ b/packages/kbn-test/src/functional_test_runner/lib/config/config.test.ts
@@ -15,6 +15,11 @@ describe('Config', () => {
services: {
foo: () => 42,
},
+ servers: {
+ elasticsearch: {
+ port: 1234,
+ },
+ },
},
primary: true,
path: process.cwd(),
diff --git a/packages/kbn-test/src/functional_test_runner/lib/config/schema.ts b/packages/kbn-test/src/functional_test_runner/lib/config/schema.ts
index f65cb3c41f42..cf1afbb810c7 100644
--- a/packages/kbn-test/src/functional_test_runner/lib/config/schema.ts
+++ b/packages/kbn-test/src/functional_test_runner/lib/config/schema.ts
@@ -17,19 +17,33 @@ const ID_PATTERN = /^[a-zA-Z0-9_]+$/;
// it will search both --inspect and --inspect-brk
const INSPECTING = !!process.execArgv.find((arg) => arg.includes('--inspect'));
-const urlPartsSchema = () =>
+const maybeRequireKeys = (keys: string[], schemas: Record) => {
+ if (!keys.length) {
+ return schemas;
+ }
+
+ const withRequires: Record = {};
+ for (const [key, schema] of Object.entries(schemas)) {
+ withRequires[key] = keys.includes(key) ? schema.required() : schema;
+ }
+ return withRequires;
+};
+
+const urlPartsSchema = ({ requiredKeys }: { requiredKeys?: string[] } = {}) =>
Joi.object()
- .keys({
- protocol: Joi.string().valid('http', 'https').default('http'),
- hostname: Joi.string().hostname().default('localhost'),
- port: Joi.number(),
- auth: Joi.string().regex(/^[^:]+:.+$/, 'username and password separated by a colon'),
- username: Joi.string(),
- password: Joi.string(),
- pathname: Joi.string().regex(/^\//, 'start with a /'),
- hash: Joi.string().regex(/^\//, 'start with a /'),
- certificateAuthorities: Joi.array().items(Joi.binary()).optional(),
- })
+ .keys(
+ maybeRequireKeys(requiredKeys ?? [], {
+ protocol: Joi.string().valid('http', 'https').default('http'),
+ hostname: Joi.string().hostname().default('localhost'),
+ port: Joi.number(),
+ auth: Joi.string().regex(/^[^:]+:.+$/, 'username and password separated by a colon'),
+ username: Joi.string(),
+ password: Joi.string(),
+ pathname: Joi.string().regex(/^\//, 'start with a /'),
+ hash: Joi.string().regex(/^\//, 'start with a /'),
+ certificateAuthorities: Joi.array().items(Joi.binary()).optional(),
+ })
+ )
.default();
const appUrlPartsSchema = () =>
@@ -170,18 +184,25 @@ export const schema = Joi.object()
servers: Joi.object()
.keys({
kibana: urlPartsSchema(),
- elasticsearch: urlPartsSchema(),
+ elasticsearch: urlPartsSchema({
+ requiredKeys: ['port'],
+ }),
})
.default(),
esTestCluster: Joi.object()
.keys({
- license: Joi.string().default('basic'),
+ license: Joi.valid('basic', 'trial', 'gold').default('basic'),
from: Joi.string().default('snapshot'),
- serverArgs: Joi.array(),
+ serverArgs: Joi.array().items(Joi.string()),
esJavaOpts: Joi.string(),
dataArchive: Joi.string(),
ssl: Joi.boolean().default(false),
+ ccs: Joi.object().keys({
+ remoteClusterUrl: Joi.string().uri({
+ scheme: /https?/,
+ }),
+ }),
})
.default(),
@@ -274,6 +295,7 @@ export const schema = Joi.object()
security: Joi.object()
.keys({
roles: Joi.object().default(),
+ remoteEsRoles: Joi.object(),
defaultRoles: Joi.array()
.items(Joi.string())
.when('$primary', {
diff --git a/packages/kbn-test/src/functional_test_runner/lib/index.ts b/packages/kbn-test/src/functional_test_runner/lib/index.ts
index e387fd156fe8..077a62e8e74e 100644
--- a/packages/kbn-test/src/functional_test_runner/lib/index.ts
+++ b/packages/kbn-test/src/functional_test_runner/lib/index.ts
@@ -9,7 +9,7 @@
export { Lifecycle } from './lifecycle';
export { LifecyclePhase } from './lifecycle_phase';
export { readConfigFile, Config } from './config';
-export { readProviderSpec, ProviderCollection } from './providers';
+export * from './providers';
// @internal
export { runTests, setupMocha } from './mocha';
export * from './test_metadata';
diff --git a/packages/kbn-test/src/functional_test_runner/lib/providers/index.ts b/packages/kbn-test/src/functional_test_runner/lib/providers/index.ts
index 10aeca19ba45..578e41ca8e82 100644
--- a/packages/kbn-test/src/functional_test_runner/lib/providers/index.ts
+++ b/packages/kbn-test/src/functional_test_runner/lib/providers/index.ts
@@ -8,4 +8,5 @@
export { ProviderCollection } from './provider_collection';
export { readProviderSpec } from './read_provider_spec';
+export { createAsyncInstance } from './async_instance';
export type { Provider } from './read_provider_spec';
diff --git a/packages/kbn-test/src/functional_test_runner/lib/providers/provider_collection.ts b/packages/kbn-test/src/functional_test_runner/lib/providers/provider_collection.ts
index 69a5973168f0..97d7d43417f9 100644
--- a/packages/kbn-test/src/functional_test_runner/lib/providers/provider_collection.ts
+++ b/packages/kbn-test/src/functional_test_runner/lib/providers/provider_collection.ts
@@ -15,6 +15,15 @@ import { createVerboseInstance } from './verbose_instance';
import { GenericFtrService } from '../../public_types';
export class ProviderCollection {
+ static callProviderFn(providerFn: any, ctx: any) {
+ if (providerFn.prototype instanceof GenericFtrService) {
+ const Constructor = providerFn as any as new (ctx: any) => any;
+ return new Constructor(ctx);
+ }
+
+ return providerFn(ctx);
+ }
+
private readonly instances = new Map();
constructor(private readonly log: ToolingLog, private readonly providers: Providers) {}
@@ -59,19 +68,12 @@ export class ProviderCollection {
}
public invokeProviderFn(provider: (args: any) => any) {
- const ctx = {
+ return ProviderCollection.callProviderFn(provider, {
getService: this.getService,
hasService: this.hasService,
getPageObject: this.getPageObject,
getPageObjects: this.getPageObjects,
- };
-
- if (provider.prototype instanceof GenericFtrService) {
- const Constructor = provider as any as new (ctx: any) => any;
- return new Constructor(ctx);
- }
-
- return provider(ctx);
+ });
}
private findProvider(type: string, name: string) {
diff --git a/packages/kbn-test/src/functional_tests/lib/run_elasticsearch.ts b/packages/kbn-test/src/functional_tests/lib/run_elasticsearch.ts
index 68e7a4992fcf..ba314e8325a6 100644
--- a/packages/kbn-test/src/functional_tests/lib/run_elasticsearch.ts
+++ b/packages/kbn-test/src/functional_tests/lib/run_elasticsearch.ts
@@ -8,6 +8,7 @@
import { resolve } from 'path';
import type { ToolingLog } from '@kbn/dev-utils';
+import getPort from 'get-port';
import { KIBANA_ROOT } from './paths';
import type { Config } from '../../functional_test_runner/';
import { createTestEsCluster } from '../../es';
@@ -15,32 +16,102 @@ import { createTestEsCluster } from '../../es';
interface RunElasticsearchOptions {
log: ToolingLog;
esFrom?: string;
+ config: Config;
+}
+
+interface CcsConfig {
+ remoteClusterUrl: string;
}
-export async function runElasticsearch({
+
+type EsConfig = ReturnType;
+
+function getEsConfig({
config,
- options,
-}: {
- config: Config;
- options: RunElasticsearchOptions;
-}) {
- const { log, esFrom } = options;
- const ssl = config.get('esTestCluster.ssl');
- const license = config.get('esTestCluster.license');
- const esArgs = config.get('esTestCluster.serverArgs');
- const esJavaOpts = config.get('esTestCluster.esJavaOpts');
+ esFrom = config.get('esTestCluster.from'),
+}: RunElasticsearchOptions) {
+ const ssl = !!config.get('esTestCluster.ssl');
+ const license: 'basic' | 'trial' | 'gold' = config.get('esTestCluster.license');
+ const esArgs: string[] = config.get('esTestCluster.serverArgs') ?? [];
+ const esJavaOpts: string | undefined = config.get('esTestCluster.esJavaOpts');
const isSecurityEnabled = esArgs.includes('xpack.security.enabled=true');
- const cluster = createTestEsCluster({
- port: config.get('servers.elasticsearch.port'),
- password: isSecurityEnabled ? 'changeme' : config.get('servers.elasticsearch.password'),
+ const port: number | undefined = config.get('servers.elasticsearch.port');
+ const ccsConfig: CcsConfig | undefined = config.get('esTestCluster.ccs');
+
+ const password: string | undefined = isSecurityEnabled
+ ? 'changeme'
+ : config.get('servers.elasticsearch.password');
+
+ const dataArchive: string | undefined = config.get('esTestCluster.dataArchive');
+
+ return {
+ ssl,
license,
- log,
- basePath: resolve(KIBANA_ROOT, '.es'),
- esFrom: esFrom || config.get('esTestCluster.from'),
- dataArchive: config.get('esTestCluster.dataArchive'),
esArgs,
esJavaOpts,
- ssl,
+ isSecurityEnabled,
+ esFrom,
+ port,
+ password,
+ dataArchive,
+ ccsConfig,
+ };
+}
+
+export async function runElasticsearch(
+ options: RunElasticsearchOptions
+): Promise<() => Promise> {
+ const { log } = options;
+ const config = getEsConfig(options);
+
+ if (!config.ccsConfig) {
+ const node = await startEsNode(log, 'ftr', config);
+ return async () => {
+ await node.cleanup();
+ };
+ }
+
+ const remotePort = await getPort();
+ const remoteNode = await startEsNode(log, 'ftr-remote', {
+ ...config,
+ port: parseInt(new URL(config.ccsConfig.remoteClusterUrl).port, 10),
+ transportPort: remotePort,
+ });
+
+ const localNode = await startEsNode(log, 'ftr-local', {
+ ...config,
+ esArgs: [...config.esArgs, `cluster.remote.ftr-remote.seeds=localhost:${remotePort}`],
+ });
+
+ return async () => {
+ await localNode.cleanup();
+ await remoteNode.cleanup();
+ };
+}
+
+async function startEsNode(
+ log: ToolingLog,
+ name: string,
+ config: EsConfig & { transportPort?: number }
+) {
+ const cluster = createTestEsCluster({
+ clusterName: `cluster-${name}`,
+ esArgs: config.esArgs,
+ esFrom: config.esFrom,
+ esJavaOpts: config.esJavaOpts,
+ license: config.license,
+ password: config.password,
+ port: config.port,
+ ssl: config.ssl,
+ log,
+ basePath: resolve(KIBANA_ROOT, '.es'),
+ nodes: [
+ {
+ name,
+ dataArchive: config.dataArchive,
+ },
+ ],
+ transportPort: config.transportPort,
});
await cluster.start();
diff --git a/packages/kbn-test/src/functional_tests/tasks.ts b/packages/kbn-test/src/functional_tests/tasks.ts
index 5906193ca145..b1213ceef290 100644
--- a/packages/kbn-test/src/functional_tests/tasks.ts
+++ b/packages/kbn-test/src/functional_tests/tasks.ts
@@ -108,10 +108,10 @@ export async function runTests(options: RunTestsParams) {
await withProcRunner(log, async (procs) => {
const config = await readConfigFile(log, options.esVersion, configPath);
- let es;
+ let shutdownEs;
try {
if (process.env.TEST_ES_DISABLE_STARTUP !== 'true') {
- es = await runElasticsearch({ config, options: { ...options, log } });
+ shutdownEs = await runElasticsearch({ ...options, log, config });
}
await runKibanaServer({ procs, config, options });
await runFtr({ configPath, options: { ...options, log } });
@@ -125,8 +125,8 @@ export async function runTests(options: RunTestsParams) {
await procs.stop('kibana');
} finally {
- if (es) {
- await es.cleanup();
+ if (shutdownEs) {
+ await shutdownEs();
}
}
}
@@ -166,7 +166,7 @@ export async function startServers({ ...options }: StartServerOptions) {
await withProcRunner(log, async (procs) => {
const config = await readConfigFile(log, options.esVersion, options.config);
- const es = await runElasticsearch({ config, options: opts });
+ const shutdownEs = await runElasticsearch({ ...opts, config });
await runKibanaServer({
procs,
config,
@@ -190,7 +190,7 @@ export async function startServers({ ...options }: StartServerOptions) {
log.success(makeSuccessMessage(options));
await procs.waitForAllToStop();
- await es.cleanup();
+ await shutdownEs();
});
}
diff --git a/packages/kbn-test/src/index.ts b/packages/kbn-test/src/index.ts
index 26d40f70edb7..c9f0e67c558f 100644
--- a/packages/kbn-test/src/index.ts
+++ b/packages/kbn-test/src/index.ts
@@ -36,6 +36,7 @@ export {
createTestEsCluster,
createEsClientForTesting,
createEsClientForFtrConfig,
+ createRemoteEsClientForFtrConfig,
} from './es';
export {
diff --git a/packages/kbn-test/src/jest/run.ts b/packages/kbn-test/src/jest/run.ts
index 26fa12497357..b8617317d6d9 100644
--- a/packages/kbn-test/src/jest/run.ts
+++ b/packages/kbn-test/src/jest/run.ts
@@ -22,6 +22,7 @@ import { existsSync } from 'fs';
import { run } from 'jest';
import { buildArgv } from 'jest-cli/build/cli';
import { ToolingLog, getTimeReporter } from '@kbn/dev-utils';
+import { REPO_ROOT } from '@kbn/utils';
import { map } from 'lodash';
// yarn test:jest src/core/server/saved_objects
@@ -67,23 +68,47 @@ export function runJest(configName = 'jest.config.js') {
log.verbose('commonTestFiles:', commonTestFiles);
let configPath;
- let devConfigPath;
// sets the working directory to the cwd or the common
// base directory of the provided test files
let wd = testFilesProvided ? commonTestFiles : cwd;
-
- devConfigPath = resolve(wd, devConfigName);
- configPath = resolve(wd, configName);
-
- while (!existsSync(configPath) && !existsSync(devConfigPath)) {
- wd = resolve(wd, '..');
- devConfigPath = resolve(wd, devConfigName);
- configPath = resolve(wd, configName);
+ while (true) {
+ const dev = resolve(wd, devConfigName);
+ if (existsSync(dev)) {
+ configPath = dev;
+ break;
+ }
+
+ const actual = resolve(wd, configName);
+ if (existsSync(actual)) {
+ configPath = actual;
+ break;
+ }
+
+ if (wd === REPO_ROOT) {
+ break;
+ }
+
+ const parent = resolve(wd, '..');
+ if (parent === wd) {
+ break;
+ }
+
+ wd = parent;
}
- if (existsSync(devConfigPath)) {
- configPath = devConfigPath;
+ if (!configPath) {
+ if (testFilesProvided) {
+ log.error(
+ `unable to find a ${configName} file in ${commonTestFiles} or any parent directory up to the root of the repo. This CLI can only run Jest tests which resolve to a single ${configName} file, and that file must exist in a parent directory of all the paths you pass.`
+ );
+ } else {
+ log.error(
+ `we no longer ship a root config file so you either need to pass a path to a test file, a folder where tests can be found, or a --config argument pointing to one of the many ${configName} files in the repository`
+ );
+ }
+
+ process.exit(1);
}
log.verbose(`no config provided, found ${configPath}`);
diff --git a/packages/kbn-test/src/kbn_client/kbn_client_saved_objects.ts b/packages/kbn-test/src/kbn_client/kbn_client_saved_objects.ts
index 717f214211d9..02861fcb27fd 100644
--- a/packages/kbn-test/src/kbn_client/kbn_client_saved_objects.ts
+++ b/packages/kbn-test/src/kbn_client/kbn_client_saved_objects.ts
@@ -219,6 +219,25 @@ export class KbnClientSavedObjects {
this.log.success('deleted', deleted, 'objects');
}
+ public async cleanStandardList(options?: { space?: string }) {
+ // add types here
+ const types = [
+ 'search',
+ 'index-pattern',
+ 'visualization',
+ 'dashboard',
+ 'lens',
+ 'map',
+ 'graph-workspace',
+ 'query',
+ 'tag',
+ 'url',
+ 'canvas-workpad',
+ ];
+ const newOptions = { types, space: options?.space };
+ await this.clean(newOptions);
+ }
+
public async bulkDelete(options: DeleteObjectsOptions) {
let deleted = 0;
let missing = 0;
diff --git a/packages/kbn-type-summarizer/BUILD.bazel b/packages/kbn-type-summarizer/BUILD.bazel
new file mode 100644
index 000000000000..ec0df11bc376
--- /dev/null
+++ b/packages/kbn-type-summarizer/BUILD.bazel
@@ -0,0 +1,134 @@
+load("@npm//@bazel/typescript:index.bzl", "ts_config")
+load("@build_bazel_rules_nodejs//:index.bzl", "js_library")
+load("//src/dev/bazel:index.bzl", "jsts_transpiler", "pkg_npm", "pkg_npm_types", "ts_project")
+load("@build_bazel_rules_nodejs//internal/node:node.bzl", "nodejs_binary")
+load("@build_bazel_rules_nodejs//:index.bzl", "directory_file_path")
+
+PKG_BASE_NAME = "kbn-type-summarizer"
+PKG_REQUIRE_NAME = "@kbn/type-summarizer"
+
+SOURCE_FILES = glob(
+ [
+ "src/**/*.ts",
+ ]
+)
+
+SRCS = SOURCE_FILES
+
+filegroup(
+ name = "srcs",
+ srcs = SRCS,
+)
+
+NPM_MODULE_EXTRA_FILES = [
+ "package.json",
+ "README.md",
+]
+
+RUNTIME_DEPS = [
+ "@npm//@babel/runtime",
+ "@npm//@microsoft/api-extractor",
+ "@npm//source-map-support",
+ "@npm//chalk",
+ "@npm//getopts",
+ "@npm//is-path-inside",
+ "@npm//normalize-path",
+ "@npm//source-map",
+ "@npm//tslib",
+]
+
+TYPES_DEPS = [
+ "@npm//@microsoft/api-extractor",
+ "@npm//@types/jest",
+ "@npm//@types/node",
+ "@npm//@types/normalize-path",
+ "@npm//getopts",
+ "@npm//is-path-inside",
+ "@npm//normalize-path",
+ "@npm//source-map",
+ "@npm//strip-ansi",
+ "@npm//tslib",
+]
+
+ts_config(
+ name = "tsconfig",
+ src = "tsconfig.json",
+ deps = [
+ "//:tsconfig.base.json",
+ "//:tsconfig.bazel.json",
+ ],
+)
+
+ts_project(
+ name = "tsc_types",
+ args = ['--pretty'],
+ srcs = SRCS,
+ deps = TYPES_DEPS,
+ declaration = True,
+ declaration_map = True,
+ emit_declaration_only = True,
+ out_dir = "target_types",
+ root_dir = "src",
+ tsconfig = ":tsconfig",
+)
+
+jsts_transpiler(
+ name = "target_node",
+ srcs = SRCS,
+ build_pkg_name = package_name(),
+)
+
+js_library(
+ name = PKG_BASE_NAME,
+ srcs = NPM_MODULE_EXTRA_FILES,
+ deps = RUNTIME_DEPS + [":target_node"],
+ package_name = PKG_REQUIRE_NAME,
+ visibility = ["//visibility:public"],
+)
+
+directory_file_path(
+ name = "bazel-cli-path",
+ directory = ":target_node",
+ path = "bazel_cli.js",
+)
+
+nodejs_binary(
+ name = "bazel-cli",
+ data = [
+ ":%s" % PKG_BASE_NAME
+ ],
+ entry_point = ":bazel-cli-path",
+ visibility = ["//visibility:public"],
+)
+
+pkg_npm(
+ name = "npm_module",
+ deps = [
+ ":%s" % PKG_BASE_NAME,
+ ],
+)
+
+filegroup(
+ name = "build",
+ srcs = [
+ ":npm_module",
+ ],
+ visibility = ["//visibility:public"],
+)
+
+pkg_npm_types(
+ name = "npm_module_types",
+ srcs = SRCS,
+ deps = [":tsc_types"],
+ package_name = PKG_REQUIRE_NAME,
+ tsconfig = ":tsconfig",
+ visibility = ["//visibility:public"],
+)
+
+filegroup(
+ name = "build_types",
+ srcs = [
+ ":npm_module_types",
+ ],
+ visibility = ["//visibility:public"],
+)
diff --git a/packages/kbn-type-summarizer/README.md b/packages/kbn-type-summarizer/README.md
new file mode 100644
index 000000000000..fdd58886a0a6
--- /dev/null
+++ b/packages/kbn-type-summarizer/README.md
@@ -0,0 +1,17 @@
+# @kbn/type-summarizer
+
+Consume the .d.ts files for a package, produced by `tsc`, and generate a single `.d.ts` file of the public types along with a source map that points back to the original source.
+
+## You mean like API Extractor?
+
+Yeah, except with source map support and without all the legacy features and other features we disable to generate our current type summaries.
+
+I first attempted to implement this in api-extractor but I (@spalger) hit a wall when dealing with the `Span` class. This class handles all the text output which ends up becoming source code, and I wasn't able to find a way to associate specific spans with source locations without getting 12 headaches. Instead I decided to try implementing this from scratch, reducing our reliance on the api-extractor project and putting us in control of how we generate type summaries.
+
+This package is missing some critical features for wider adoption, but rather than build the entire product in a branch I decided to implement support for a small number of TS features and put this to use in the `@kbn/crypto` module ASAP.
+
+The plan is to expand to other packages in the Kibana repo, adding support for language features as we go.
+
+## Something isn't working and I'm blocked!
+
+If there's a problem with the implmentation blocking another team at any point we can move the package back to using api-extractor by removing the package from the `TYPE_SUMMARIZER_PACKAGES` list at the top of [packages/kbn-type-summarizer/src/lib/bazel_cli_config.ts](./src/lib/bazel_cli_config.ts).
\ No newline at end of file
diff --git a/packages/kbn-type-summarizer/jest.config.js b/packages/kbn-type-summarizer/jest.config.js
new file mode 100644
index 000000000000..84b10626e82c
--- /dev/null
+++ b/packages/kbn-type-summarizer/jest.config.js
@@ -0,0 +1,15 @@
+/*
+ * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
+ * or more contributor license agreements. Licensed under the Elastic License
+ * 2.0 and the Server Side Public License, v 1; you may not use this file except
+ * in compliance with, at your election, the Elastic License 2.0 or the Server
+ * Side Public License, v 1.
+ */
+
+/** @typedef {import("@jest/types").Config.InitialOptions} JestConfig */
+/** @type {JestConfig} */
+module.exports = {
+ preset: '@kbn/test/jest_node',
+ rootDir: '../..',
+ roots: ['/packages/kbn-type-summarizer'],
+};
diff --git a/packages/kbn-type-summarizer/jest.integration.config.js b/packages/kbn-type-summarizer/jest.integration.config.js
new file mode 100644
index 000000000000..ae7b80073b93
--- /dev/null
+++ b/packages/kbn-type-summarizer/jest.integration.config.js
@@ -0,0 +1,15 @@
+/*
+ * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
+ * or more contributor license agreements. Licensed under the Elastic License
+ * 2.0 and the Server Side Public License, v 1; you may not use this file except
+ * in compliance with, at your election, the Elastic License 2.0 or the Server
+ * Side Public License, v 1.
+ */
+
+/** @typedef {import("@jest/types").Config.InitialOptions} JestConfig */
+/** @type {JestConfig} */
+module.exports = {
+ preset: '@kbn/test/jest_integration_node',
+ rootDir: '../..',
+ roots: ['/packages/kbn-type-summarizer'],
+};
diff --git a/packages/kbn-type-summarizer/package.json b/packages/kbn-type-summarizer/package.json
new file mode 100644
index 000000000000..df9c5564d561
--- /dev/null
+++ b/packages/kbn-type-summarizer/package.json
@@ -0,0 +1,10 @@
+{
+ "name": "@kbn/type-summarizer",
+ "version": "1.0.0",
+ "license": "SSPL-1.0 OR Elastic License 2.0",
+ "main": "./target_node/index.js",
+ "private": true,
+ "kibana": {
+ "devOnly": true
+ }
+}
diff --git a/packages/kbn-type-summarizer/src/bazel_cli.ts b/packages/kbn-type-summarizer/src/bazel_cli.ts
new file mode 100644
index 000000000000..af6b13ebfc09
--- /dev/null
+++ b/packages/kbn-type-summarizer/src/bazel_cli.ts
@@ -0,0 +1,73 @@
+/*
+ * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
+ * or more contributor license agreements. Licensed under the Elastic License
+ * 2.0 and the Server Side Public License, v 1; you may not use this file except
+ * in compliance with, at your election, the Elastic License 2.0 or the Server
+ * Side Public License, v 1.
+ */
+
+import Fsp from 'fs/promises';
+import Path from 'path';
+
+import { run } from './lib/run';
+import { parseBazelCliConfig } from './lib/bazel_cli_config';
+
+import { summarizePackage } from './summarize_package';
+import { runApiExtractor } from './run_api_extractor';
+
+const HELP = `
+Script called from bazel to create the summarized version of a package. When called by Bazel
+config is passed as a JSON encoded object.
+
+When called via "node scripts/build_type_summarizer_output" pass a path to a package and that
+package's types will be read from node_modules and written to data/type-summarizer-output.
+
+`;
+
+run(
+ async ({ argv, log }) => {
+ log.debug('cwd:', process.cwd());
+ log.debug('argv', process.argv);
+
+ const config = parseBazelCliConfig(argv);
+ await Fsp.mkdir(config.outputDir, { recursive: true });
+
+ // generate pkg json output
+ await Fsp.writeFile(
+ Path.resolve(config.outputDir, 'package.json'),
+ JSON.stringify(
+ {
+ name: `@types/${config.packageName.replaceAll('@', '').replaceAll('/', '__')}`,
+ description: 'Generated by @kbn/type-summarizer',
+ types: './index.d.ts',
+ private: true,
+ license: 'MIT',
+ version: '1.1.0',
+ },
+ null,
+ 2
+ )
+ );
+
+ if (config.use === 'type-summarizer') {
+ await summarizePackage(log, {
+ dtsDir: Path.dirname(config.inputPath),
+ inputPaths: [config.inputPath],
+ outputDir: config.outputDir,
+ tsconfigPath: config.tsconfigPath,
+ repoRelativePackageDir: config.repoRelativePackageDir,
+ });
+ log.success('type summary created for', config.repoRelativePackageDir);
+ } else {
+ await runApiExtractor(
+ config.tsconfigPath,
+ config.inputPath,
+ Path.resolve(config.outputDir, 'index.d.ts')
+ );
+ }
+ },
+ {
+ helpText: HELP,
+ defaultLogLevel: 'quiet',
+ }
+);
diff --git a/packages/kbn-type-summarizer/src/index.ts b/packages/kbn-type-summarizer/src/index.ts
new file mode 100644
index 000000000000..1667ab5cd8d2
--- /dev/null
+++ b/packages/kbn-type-summarizer/src/index.ts
@@ -0,0 +1,11 @@
+/*
+ * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
+ * or more contributor license agreements. Licensed under the Elastic License
+ * 2.0 and the Server Side Public License, v 1; you may not use this file except
+ * in compliance with, at your election, the Elastic License 2.0 or the Server
+ * Side Public License, v 1.
+ */
+
+export type { Logger } from './lib/log';
+export type { SummarizePacakgeOptions } from './summarize_package';
+export { summarizePackage } from './summarize_package';
diff --git a/packages/kbn-type-summarizer/src/lib/bazel_cli_config.ts b/packages/kbn-type-summarizer/src/lib/bazel_cli_config.ts
new file mode 100644
index 000000000000..da82aef8f7d7
--- /dev/null
+++ b/packages/kbn-type-summarizer/src/lib/bazel_cli_config.ts
@@ -0,0 +1,186 @@
+/*
+ * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
+ * or more contributor license agreements. Licensed under the Elastic License
+ * 2.0 and the Server Side Public License, v 1; you may not use this file except
+ * in compliance with, at your election, the Elastic License 2.0 or the Server
+ * Side Public License, v 1.
+ */
+
+import Fs from 'fs';
+
+import { CliError } from './cli_error';
+import { parseCliFlags } from './cli_flags';
+import * as Path from './path';
+
+const TYPE_SUMMARIZER_PACKAGES = ['@kbn/type-summarizer', '@kbn/crypto', '@kbn/generate'];
+
+const isString = (i: any): i is string => typeof i === 'string' && i.length > 0;
+
+interface BazelCliConfig {
+ packageName: string;
+ outputDir: string;
+ tsconfigPath: string;
+ inputPath: string;
+ repoRelativePackageDir: string;
+ use: 'api-extractor' | 'type-summarizer';
+}
+
+function isKibanaRepo(dir: string) {
+ try {
+ const json = Fs.readFileSync(Path.join(dir, 'package.json'), 'utf8');
+ const parsed = JSON.parse(json);
+ return parsed.name === 'kibana';
+ } catch {
+ return false;
+ }
+}
+
+function findRepoRoot() {
+ const start = Path.resolve(__dirname);
+ let dir = start;
+ while (true) {
+ if (isKibanaRepo(dir)) {
+ return dir;
+ }
+
+ // this is not the kibana directory, try moving up a directory
+ const parent = Path.join(dir, '..');
+ if (parent === dir) {
+ throw new Error(
+ `unable to find Kibana's package.json file when traversing up from [${start}]`
+ );
+ }
+
+ dir = parent;
+ }
+}
+
+export function parseBazelCliFlags(argv: string[]): BazelCliConfig {
+ const { rawFlags, unknownFlags } = parseCliFlags(argv, {
+ string: ['use'],
+ default: {
+ use: 'api-extractor',
+ },
+ });
+
+ if (unknownFlags.length) {
+ throw new CliError(`Unknown flags: ${unknownFlags.join(', ')}`, {
+ showHelp: true,
+ });
+ }
+
+ const repoRoot = findRepoRoot();
+
+ const [relativePackagePath, ...extraPositional] = rawFlags._;
+ if (typeof relativePackagePath !== 'string') {
+ throw new CliError(`missing path to package as first positional argument`, { showHelp: true });
+ }
+ if (extraPositional.length) {
+ throw new CliError(`extra positional arguments`, { showHelp: true });
+ }
+
+ const use = rawFlags.use;
+ if (use !== 'api-extractor' && use !== 'type-summarizer') {
+ throw new CliError(`invalid --use flag, expected "api-extractor" or "type-summarizer"`);
+ }
+
+ const packageDir = Path.resolve(relativePackagePath);
+ const packageName: string = JSON.parse(
+ Fs.readFileSync(Path.join(packageDir, 'package.json'), 'utf8')
+ ).name;
+ const repoRelativePackageDir = Path.relative(repoRoot, packageDir);
+
+ return {
+ use,
+ packageName,
+ tsconfigPath: Path.join(repoRoot, repoRelativePackageDir, 'tsconfig.json'),
+ inputPath: Path.join(repoRoot, 'node_modules', packageName, 'target_types/index.d.ts'),
+ repoRelativePackageDir,
+ outputDir: Path.join(repoRoot, 'data/type-summarizer-output', use),
+ };
+}
+
+function parseJsonFromCli(json: string) {
+ try {
+ return JSON.parse(json);
+ } catch (error) {
+ // TODO: This is to handle a bug in Bazel which escapes `"` in .bat arguments incorrectly, replacing them with `\`
+ if (
+ error.message === 'Unexpected token \\ in JSON at position 1' &&
+ process.platform === 'win32'
+ ) {
+ const unescapedJson = json.replaceAll('\\', '"');
+ try {
+ return JSON.parse(unescapedJson);
+ } catch (e) {
+ throw new CliError(
+ `unable to parse first positional argument as JSON: "${e.message}"\n unescaped value: ${unescapedJson}\n raw value: ${json}`
+ );
+ }
+ }
+
+ throw new CliError(
+ `unable to parse first positional argument as JSON: "${error.message}"\n value: ${json}`
+ );
+ }
+}
+
+export function parseBazelCliJson(json: string): BazelCliConfig {
+ const config = parseJsonFromCli(json);
+ if (typeof config !== 'object' || config === null) {
+ throw new CliError('config JSON must be an object');
+ }
+
+ const packageName = config.packageName;
+ if (!isString(packageName)) {
+ throw new CliError('packageName config must be a non-empty string');
+ }
+
+ const outputDir = config.outputDir;
+ if (!isString(outputDir)) {
+ throw new CliError('outputDir config must be a non-empty string');
+ }
+ if (Path.isAbsolute(outputDir)) {
+ throw new CliError(`outputDir [${outputDir}] must be a relative path`);
+ }
+
+ const tsconfigPath = config.tsconfigPath;
+ if (!isString(tsconfigPath)) {
+ throw new CliError('tsconfigPath config must be a non-empty string');
+ }
+ if (Path.isAbsolute(tsconfigPath)) {
+ throw new CliError(`tsconfigPath [${tsconfigPath}] must be a relative path`);
+ }
+
+ const inputPath = config.inputPath;
+ if (!isString(inputPath)) {
+ throw new CliError('inputPath config must be a non-empty string');
+ }
+ if (Path.isAbsolute(inputPath)) {
+ throw new CliError(`inputPath [${inputPath}] must be a relative path`);
+ }
+
+ const buildFilePath = config.buildFilePath;
+ if (!isString(buildFilePath)) {
+ throw new CliError('buildFilePath config must be a non-empty string');
+ }
+ if (Path.isAbsolute(buildFilePath)) {
+ throw new CliError(`buildFilePath [${buildFilePath}] must be a relative path`);
+ }
+
+ return {
+ packageName,
+ outputDir: Path.resolve(outputDir),
+ tsconfigPath: Path.resolve(tsconfigPath),
+ inputPath: Path.resolve(inputPath),
+ repoRelativePackageDir: Path.dirname(buildFilePath),
+ use: TYPE_SUMMARIZER_PACKAGES.includes(packageName) ? 'type-summarizer' : 'api-extractor',
+ };
+}
+
+export function parseBazelCliConfig(argv: string[]) {
+ if (typeof argv[0] === 'string' && argv[0].startsWith('{')) {
+ return parseBazelCliJson(argv[0]);
+ }
+ return parseBazelCliFlags(argv);
+}
diff --git a/packages/kbn-type-summarizer/src/lib/cli_error.ts b/packages/kbn-type-summarizer/src/lib/cli_error.ts
new file mode 100644
index 000000000000..143d790612f6
--- /dev/null
+++ b/packages/kbn-type-summarizer/src/lib/cli_error.ts
@@ -0,0 +1,24 @@
+/*
+ * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
+ * or more contributor license agreements. Licensed under the Elastic License
+ * 2.0 and the Server Side Public License, v 1; you may not use this file except
+ * in compliance with, at your election, the Elastic License 2.0 or the Server
+ * Side Public License, v 1.
+ */
+
+export interface CliErrorOptions {
+ exitCode?: number;
+ showHelp?: boolean;
+}
+
+export class CliError extends Error {
+ public readonly exitCode: number;
+ public readonly showHelp: boolean;
+
+ constructor(message: string, options: CliErrorOptions = {}) {
+ super(message);
+
+ this.exitCode = options.exitCode ?? 1;
+ this.showHelp = options.showHelp ?? false;
+ }
+}
diff --git a/packages/kbn-type-summarizer/src/lib/cli_flags.ts b/packages/kbn-type-summarizer/src/lib/cli_flags.ts
new file mode 100644
index 000000000000..0f616dca873b
--- /dev/null
+++ b/packages/kbn-type-summarizer/src/lib/cli_flags.ts
@@ -0,0 +1,45 @@
+/*
+ * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
+ * or more contributor license agreements. Licensed under the Elastic License
+ * 2.0 and the Server Side Public License, v 1; you may not use this file except
+ * in compliance with, at your election, the Elastic License 2.0 or the Server
+ * Side Public License, v 1.
+ */
+
+import getopts from 'getopts';
+
+interface ParseCliFlagsOptions {
+ alias?: Record;
+ boolean?: string[];
+ string?: string[];
+ default?: Record;
+}
+
+export function parseCliFlags(argv = process.argv.slice(2), options: ParseCliFlagsOptions = {}) {
+ const unknownFlags: string[] = [];
+
+ const string = options.string ?? [];
+ const boolean = ['help', 'verbose', 'debug', 'quiet', 'silent', ...(options.boolean ?? [])];
+ const alias = {
+ v: 'verbose',
+ d: 'debug',
+ h: 'help',
+ ...options.alias,
+ };
+
+ const rawFlags = getopts(argv, {
+ alias,
+ boolean,
+ string,
+ default: options.default,
+ unknown(name) {
+ unknownFlags.push(name);
+ return false;
+ },
+ });
+
+ return {
+ rawFlags,
+ unknownFlags,
+ };
+}
diff --git a/packages/kbn-type-summarizer/src/lib/export_collector/collector_results.ts b/packages/kbn-type-summarizer/src/lib/export_collector/collector_results.ts
new file mode 100644
index 000000000000..f8f4e131f838
--- /dev/null
+++ b/packages/kbn-type-summarizer/src/lib/export_collector/collector_results.ts
@@ -0,0 +1,93 @@
+/*
+ * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
+ * or more contributor license agreements. Licensed under the Elastic License
+ * 2.0 and the Server Side Public License, v 1; you may not use this file except
+ * in compliance with, at your election, the Elastic License 2.0 or the Server
+ * Side Public License, v 1.
+ */
+
+import * as ts from 'typescript';
+import { ValueNode, ExportFromDeclaration } from '../ts_nodes';
+import { ResultValue } from './result_value';
+import { ImportedSymbols } from './imported_symbols';
+import { Reference, ReferenceKey } from './reference';
+import { SourceMapper } from '../source_mapper';
+
+export type CollectorResult = Reference | ImportedSymbols | ResultValue;
+
+export class CollectorResults {
+ imports: ImportedSymbols[] = [];
+ importsByPath = new Map();
+
+ nodes: ResultValue[] = [];
+ nodesByAst = new Map();
+
+ constructor(private readonly sourceMapper: SourceMapper) {}
+
+ addNode(exported: boolean, node: ValueNode) {
+ const existing = this.nodesByAst.get(node);
+ if (existing) {
+ existing.exported = existing.exported || exported;
+ return;
+ }
+
+ const result = new ResultValue(exported, node);
+ this.nodesByAst.set(node, result);
+ this.nodes.push(result);
+ }
+
+ ensureExported(node: ValueNode) {
+ this.addNode(true, node);
+ }
+
+ addImport(
+ exported: boolean,
+ node: ts.ImportDeclaration | ExportFromDeclaration,
+ symbol: ts.Symbol
+ ) {
+ const literal = node.moduleSpecifier;
+ if (!ts.isStringLiteral(literal)) {
+ throw new Error('import statement with non string literal module identifier');
+ }
+
+ const existing = this.importsByPath.get(literal.text);
+ if (existing) {
+ existing.symbols.push(symbol);
+ return;
+ }
+
+ const result = new ImportedSymbols(exported, node, [symbol]);
+ this.importsByPath.set(literal.text, result);
+ this.imports.push(result);
+ }
+
+ private getReferencesFromNodes() {
+ // collect the references from all the sourcefiles of all the resulting nodes
+ const sourceFiles = new Set();
+ for (const { node } of this.nodes) {
+ sourceFiles.add(this.sourceMapper.getSourceFile(node));
+ }
+
+ const references: Record> = {
+ lib: new Set(),
+ types: new Set(),
+ };
+ for (const sourceFile of sourceFiles) {
+ for (const ref of sourceFile.libReferenceDirectives) {
+ references.lib.add(ref.fileName);
+ }
+ for (const ref of sourceFile.typeReferenceDirectives) {
+ references.types.add(ref.fileName);
+ }
+ }
+
+ return [
+ ...Array.from(references.lib).map((name) => new Reference('lib', name)),
+ ...Array.from(references.types).map((name) => new Reference('types', name)),
+ ];
+ }
+
+ getAll(): CollectorResult[] {
+ return [...this.getReferencesFromNodes(), ...this.imports, ...this.nodes];
+ }
+}
diff --git a/packages/kbn-type-summarizer/src/lib/export_collector/exports_collector.ts b/packages/kbn-type-summarizer/src/lib/export_collector/exports_collector.ts
new file mode 100644
index 000000000000..3f46ceda70e1
--- /dev/null
+++ b/packages/kbn-type-summarizer/src/lib/export_collector/exports_collector.ts
@@ -0,0 +1,209 @@
+/*
+ * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
+ * or more contributor license agreements. Licensed under the Elastic License
+ * 2.0 and the Server Side Public License, v 1; you may not use this file except
+ * in compliance with, at your election, the Elastic License 2.0 or the Server
+ * Side Public License, v 1.
+ */
+
+import * as ts from 'typescript';
+
+import { Logger } from '../log';
+import {
+ assertExportedValueNode,
+ isExportedValueNode,
+ DecSymbol,
+ assertDecSymbol,
+ toDecSymbol,
+ ExportFromDeclaration,
+ isExportFromDeclaration,
+ isAliasSymbol,
+} from '../ts_nodes';
+
+import { ExportInfo } from '../export_info';
+import { CollectorResults } from './collector_results';
+import { SourceMapper } from '../source_mapper';
+import { isNodeModule } from '../is_node_module';
+
+interface ResolvedNmImport {
+ type: 'import';
+ node: ts.ImportDeclaration | ExportFromDeclaration;
+ targetPath: string;
+}
+interface ResolvedSymbol {
+ type: 'symbol';
+ symbol: DecSymbol;
+}
+
+export class ExportCollector {
+ constructor(
+ private readonly log: Logger,
+ private readonly typeChecker: ts.TypeChecker,
+ private readonly sourceFile: ts.SourceFile,
+ private readonly dtsDir: string,
+ private readonly sourceMapper: SourceMapper
+ ) {}
+
+ private getParentImport(
+ symbol: DecSymbol
+ ): ts.ImportDeclaration | ExportFromDeclaration | undefined {
+ for (const node of symbol.declarations) {
+ let cursor: ts.Node = node;
+ while (true) {
+ if (ts.isImportDeclaration(cursor) || isExportFromDeclaration(cursor)) {
+ return cursor;
+ }
+
+ if (ts.isSourceFile(cursor)) {
+ break;
+ }
+
+ cursor = cursor.parent;
+ }
+ }
+ }
+
+ private getAllChildSymbols(
+ node: ts.Node,
+ results = new Set(),
+ seen = new Set()
+ ) {
+ node.forEachChild((child) => {
+ const childSymbol = this.typeChecker.getSymbolAtLocation(child);
+ if (childSymbol) {
+ results.add(toDecSymbol(childSymbol));
+ }
+ if (!seen.has(child)) {
+ seen.add(child);
+ this.getAllChildSymbols(child, results, seen);
+ }
+ });
+ return results;
+ }
+
+ private resolveAliasSymbolStep(alias: ts.Symbol): DecSymbol {
+ // get the symbol this symbol references
+ const aliased = this.typeChecker.getImmediateAliasedSymbol(alias);
+ if (!aliased) {
+ throw new Error(`symbol [${alias.escapedName}] is an alias without aliased symbol`);
+ }
+ assertDecSymbol(aliased);
+ return aliased;
+ }
+
+ private getImportFromNodeModules(symbol: DecSymbol): undefined | ResolvedNmImport {
+ const parentImport = this.getParentImport(symbol);
+ if (parentImport) {
+ // this symbol is within an import statement, is it an import from a node_module?
+ const aliased = this.resolveAliasSymbolStep(symbol);
+
+ // symbol is in an import or export-from statement, make sure we want to traverse to that file
+ const targetPaths = [
+ ...new Set(aliased.declarations.map((d) => this.sourceMapper.getSourceFile(d).fileName)),
+ ];
+
+ if (targetPaths.length > 1) {
+ throw new Error('importing a symbol from multiple locations is unsupported at this time');
+ }
+
+ const targetPath = targetPaths[0];
+ if (isNodeModule(this.dtsDir, targetPath)) {
+ return {
+ type: 'import',
+ node: parentImport,
+ targetPath,
+ };
+ }
+ }
+ }
+
+ private resolveAliasSymbol(alias: DecSymbol): ResolvedNmImport | ResolvedSymbol {
+ let symbol = alias;
+
+ while (isAliasSymbol(symbol)) {
+ const nmImport = this.getImportFromNodeModules(symbol);
+ if (nmImport) {
+ return nmImport;
+ }
+
+ symbol = this.resolveAliasSymbolStep(symbol);
+ }
+
+ return {
+ type: 'symbol',
+ symbol,
+ };
+ }
+
+ private traversedSymbols = new Set();
+ private collectResults(
+ results: CollectorResults,
+ exportInfo: ExportInfo | undefined,
+ symbol: DecSymbol
+ ): void {
+ const seen = this.traversedSymbols.has(symbol);
+ if (seen && !exportInfo) {
+ return;
+ }
+ this.traversedSymbols.add(symbol);
+
+ const source = this.resolveAliasSymbol(symbol);
+ if (source.type === 'import') {
+ results.addImport(!!exportInfo, source.node, symbol);
+ return;
+ }
+
+ symbol = source.symbol;
+ if (seen) {
+ for (const node of symbol.declarations) {
+ assertExportedValueNode(node);
+ results.ensureExported(node);
+ }
+ return;
+ }
+
+ const globalDecs: ts.Declaration[] = [];
+ const localDecs: ts.Declaration[] = [];
+ for (const node of symbol.declarations) {
+ const sourceFile = this.sourceMapper.getSourceFile(node);
+ (isNodeModule(this.dtsDir, sourceFile.fileName) ? globalDecs : localDecs).push(node);
+ }
+
+ if (globalDecs.length) {
+ this.log.debug(
+ `Ignoring ${globalDecs.length} global declarations for "${source.symbol.escapedName}"`
+ );
+ }
+
+ for (const node of localDecs) {
+ // iterate through the child nodes to find nodes we need to export to make this useful
+ const childSymbols = this.getAllChildSymbols(node);
+ childSymbols.delete(symbol);
+
+ for (const childSymbol of childSymbols) {
+ this.collectResults(results, undefined, childSymbol);
+ }
+
+ if (isExportedValueNode(node)) {
+ results.addNode(!!exportInfo, node);
+ }
+ }
+ }
+
+ run(): CollectorResults {
+ const results = new CollectorResults(this.sourceMapper);
+
+ const moduleSymbol = this.typeChecker.getSymbolAtLocation(this.sourceFile);
+ if (!moduleSymbol) {
+ this.log.warn('Source file has no symbol in the type checker, is it empty?');
+ return results;
+ }
+
+ for (const symbol of this.typeChecker.getExportsOfModule(moduleSymbol)) {
+ assertDecSymbol(symbol);
+ this.collectResults(results, new ExportInfo(`${symbol.escapedName}`), symbol);
+ }
+
+ return results;
+ }
+}
diff --git a/packages/kbn-type-summarizer/src/lib/export_collector/imported_symbols.ts b/packages/kbn-type-summarizer/src/lib/export_collector/imported_symbols.ts
new file mode 100644
index 000000000000..1c9fa800baaa
--- /dev/null
+++ b/packages/kbn-type-summarizer/src/lib/export_collector/imported_symbols.ts
@@ -0,0 +1,21 @@
+/*
+ * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
+ * or more contributor license agreements. Licensed under the Elastic License
+ * 2.0 and the Server Side Public License, v 1; you may not use this file except
+ * in compliance with, at your election, the Elastic License 2.0 or the Server
+ * Side Public License, v 1.
+ */
+
+import * as ts from 'typescript';
+import { ExportFromDeclaration } from '../ts_nodes';
+
+export class ImportedSymbols {
+ type = 'import' as const;
+
+ constructor(
+ public readonly exported: boolean,
+ public readonly importNode: ts.ImportDeclaration | ExportFromDeclaration,
+ // TODO: I'm going to need to keep track of local names for these... unless that's embedded in the symbols
+ public readonly symbols: ts.Symbol[]
+ ) {}
+}
diff --git a/packages/kbn-type-summarizer/src/lib/export_collector/index.ts b/packages/kbn-type-summarizer/src/lib/export_collector/index.ts
new file mode 100644
index 000000000000..87f6630d2fcf
--- /dev/null
+++ b/packages/kbn-type-summarizer/src/lib/export_collector/index.ts
@@ -0,0 +1,10 @@
+/*
+ * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
+ * or more contributor license agreements. Licensed under the Elastic License
+ * 2.0 and the Server Side Public License, v 1; you may not use this file except
+ * in compliance with, at your election, the Elastic License 2.0 or the Server
+ * Side Public License, v 1.
+ */
+
+export * from './exports_collector';
+export * from './collector_results';
diff --git a/packages/kbn-type-summarizer/src/lib/export_collector/reference.ts b/packages/kbn-type-summarizer/src/lib/export_collector/reference.ts
new file mode 100644
index 000000000000..b664a457a24a
--- /dev/null
+++ b/packages/kbn-type-summarizer/src/lib/export_collector/reference.ts
@@ -0,0 +1,14 @@
+/*
+ * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
+ * or more contributor license agreements. Licensed under the Elastic License
+ * 2.0 and the Server Side Public License, v 1; you may not use this file except
+ * in compliance with, at your election, the Elastic License 2.0 or the Server
+ * Side Public License, v 1.
+ */
+
+export type ReferenceKey = 'types' | 'lib';
+
+export class Reference {
+ type = 'reference' as const;
+ constructor(public readonly key: ReferenceKey, public readonly name: string) {}
+}
diff --git a/packages/elastic-apm-synthtrace/src/lib/apm/defaults/get_observer_defaults.ts b/packages/kbn-type-summarizer/src/lib/export_collector/result_value.ts
similarity index 66%
rename from packages/elastic-apm-synthtrace/src/lib/apm/defaults/get_observer_defaults.ts
rename to packages/kbn-type-summarizer/src/lib/export_collector/result_value.ts
index 882029a50e47..91249eea68e1 100644
--- a/packages/elastic-apm-synthtrace/src/lib/apm/defaults/get_observer_defaults.ts
+++ b/packages/kbn-type-summarizer/src/lib/export_collector/result_value.ts
@@ -6,11 +6,10 @@
* Side Public License, v 1.
*/
-import { ApmFields } from '../apm_fields';
+import { ValueNode } from '../ts_nodes';
-export function getObserverDefaults(): ApmFields {
- return {
- 'observer.version': '7.16.0',
- 'observer.version_major': 7,
- };
+export class ResultValue {
+ type = 'value' as const;
+
+ constructor(public exported: boolean, public readonly node: ValueNode) {}
}
diff --git a/packages/kbn-test/src/functional_test_runner/lib/config/__fixtures__/config.4.js b/packages/kbn-type-summarizer/src/lib/export_info.ts
similarity index 78%
rename from packages/kbn-test/src/functional_test_runner/lib/config/__fixtures__/config.4.js
rename to packages/kbn-type-summarizer/src/lib/export_info.ts
index 6dc8aa803613..3dee04121d32 100644
--- a/packages/kbn-test/src/functional_test_runner/lib/config/__fixtures__/config.4.js
+++ b/packages/kbn-type-summarizer/src/lib/export_info.ts
@@ -6,10 +6,6 @@
* Side Public License, v 1.
*/
-export default function () {
- return {
- screenshots: {
- directory: 'bar',
- },
- };
+export class ExportInfo {
+ constructor(public readonly name: string) {}
}
diff --git a/packages/kbn-type-summarizer/src/lib/helpers/error.ts b/packages/kbn-type-summarizer/src/lib/helpers/error.ts
new file mode 100644
index 000000000000..f78eb29083b0
--- /dev/null
+++ b/packages/kbn-type-summarizer/src/lib/helpers/error.ts
@@ -0,0 +1,19 @@
+/*
+ * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
+ * or more contributor license agreements. Licensed under the Elastic License
+ * 2.0 and the Server Side Public License, v 1; you may not use this file except
+ * in compliance with, at your election, the Elastic License 2.0 or the Server
+ * Side Public License, v 1.
+ */
+
+export function toError(thrown: unknown) {
+ if (thrown instanceof Error) {
+ return thrown;
+ }
+
+ return new Error(`${thrown} thrown`);
+}
+
+export function isSystemError(error: Error): error is NodeJS.ErrnoException {
+ return typeof (error as any).code === 'string';
+}
diff --git a/packages/kbn-type-summarizer/src/lib/helpers/fs.ts b/packages/kbn-type-summarizer/src/lib/helpers/fs.ts
new file mode 100644
index 000000000000..092310c1e5db
--- /dev/null
+++ b/packages/kbn-type-summarizer/src/lib/helpers/fs.ts
@@ -0,0 +1,26 @@
+/*
+ * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
+ * or more contributor license agreements. Licensed under the Elastic License
+ * 2.0 and the Server Side Public License, v 1; you may not use this file except
+ * in compliance with, at your election, the Elastic License 2.0 or the Server
+ * Side Public License, v 1.
+ */
+
+import Fsp from 'fs/promises';
+import { toError, isSystemError } from './error';
+
+export async function tryReadFile(
+ path: string,
+ encoding: 'utf-8' | 'utf8'
+): Promise;
+export async function tryReadFile(path: string, encoding?: BufferEncoding) {
+ try {
+ return await Fsp.readFile(path, encoding);
+ } catch (_) {
+ const error = toError(_);
+ if (isSystemError(error) && error.code === 'ENOENT') {
+ return undefined;
+ }
+ throw error;
+ }
+}
diff --git a/packages/kbn-type-summarizer/src/lib/helpers/json.test.ts b/packages/kbn-type-summarizer/src/lib/helpers/json.test.ts
new file mode 100644
index 000000000000..4bb86652221d
--- /dev/null
+++ b/packages/kbn-type-summarizer/src/lib/helpers/json.test.ts
@@ -0,0 +1,23 @@
+/*
+ * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
+ * or more contributor license agreements. Licensed under the Elastic License
+ * 2.0 and the Server Side Public License, v 1; you may not use this file except
+ * in compliance with, at your election, the Elastic License 2.0 or the Server
+ * Side Public License, v 1.
+ */
+
+import { parseJson } from './json';
+
+it('parses JSON', () => {
+ expect(parseJson('{"foo": "bar"}')).toMatchInlineSnapshot(`
+ Object {
+ "foo": "bar",
+ }
+ `);
+});
+
+it('throws more helpful errors', () => {
+ expect(() => parseJson('{"foo": bar}')).toThrowErrorMatchingInlineSnapshot(
+ `"Failed to parse JSON: Unexpected token b in JSON at position 8"`
+ );
+});
diff --git a/packages/kbn-type-summarizer/src/lib/helpers/json.ts b/packages/kbn-type-summarizer/src/lib/helpers/json.ts
new file mode 100644
index 000000000000..ee2403bd9422
--- /dev/null
+++ b/packages/kbn-type-summarizer/src/lib/helpers/json.ts
@@ -0,0 +1,18 @@
+/*
+ * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
+ * or more contributor license agreements. Licensed under the Elastic License
+ * 2.0 and the Server Side Public License, v 1; you may not use this file except
+ * in compliance with, at your election, the Elastic License 2.0 or the Server
+ * Side Public License, v 1.
+ */
+
+import { toError } from './error';
+
+export function parseJson(json: string, from?: string) {
+ try {
+ return JSON.parse(json);
+ } catch (_) {
+ const error = toError(_);
+ throw new Error(`Failed to parse JSON${from ? ` from ${from}` : ''}: ${error.message}`);
+ }
+}
diff --git a/packages/kbn-type-summarizer/src/lib/is_node_module.ts b/packages/kbn-type-summarizer/src/lib/is_node_module.ts
new file mode 100644
index 000000000000..ba4d607ccb86
--- /dev/null
+++ b/packages/kbn-type-summarizer/src/lib/is_node_module.ts
@@ -0,0 +1,17 @@
+/*
+ * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
+ * or more contributor license agreements. Licensed under the Elastic License
+ * 2.0 and the Server Side Public License, v 1; you may not use this file except
+ * in compliance with, at your election, the Elastic License 2.0 or the Server
+ * Side Public License, v 1.
+ */
+
+import isPathInside from 'is-path-inside';
+
+import * as Path from './path';
+
+export function isNodeModule(dtsDir: string, path: string) {
+ return (isPathInside(path, dtsDir) ? Path.relative(dtsDir, path) : path)
+ .split('/')
+ .includes('node_modules');
+}
diff --git a/packages/kbn-type-summarizer/src/lib/log/cli_log.ts b/packages/kbn-type-summarizer/src/lib/log/cli_log.ts
new file mode 100644
index 000000000000..1121dfae3606
--- /dev/null
+++ b/packages/kbn-type-summarizer/src/lib/log/cli_log.ts
@@ -0,0 +1,99 @@
+/*
+ * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
+ * or more contributor license agreements. Licensed under the Elastic License
+ * 2.0 and the Server Side Public License, v 1; you may not use this file except
+ * in compliance with, at your election, the Elastic License 2.0 or the Server
+ * Side Public License, v 1.
+ */
+
+import { format } from 'util';
+import { dim, blueBright, yellowBright, redBright, gray } from 'chalk';
+import getopts from 'getopts';
+
+import { Logger } from './logger';
+
+const LOG_LEVEL_RANKS = {
+ silent: 0,
+ quiet: 1,
+ info: 2,
+ debug: 3,
+ verbose: 4,
+};
+export type LogLevel = keyof typeof LOG_LEVEL_RANKS;
+const LOG_LEVELS = (Object.keys(LOG_LEVEL_RANKS) as LogLevel[]).sort(
+ (a, b) => LOG_LEVEL_RANKS[a] - LOG_LEVEL_RANKS[b]
+);
+const LOG_LEVELS_DESC = LOG_LEVELS.slice().reverse();
+
+type LogLevelMap = { [k in LogLevel]: boolean };
+
+export interface LogWriter {
+ write(chunk: string): void;
+}
+
+export class CliLog implements Logger {
+ static parseLogLevel(level: LogLevel) {
+ if (!LOG_LEVELS.includes(level)) {
+ throw new Error('invalid log level');
+ }
+
+ const rank = LOG_LEVEL_RANKS[level];
+ return Object.fromEntries(
+ LOG_LEVELS.map((l) => [l, LOG_LEVEL_RANKS[l] <= rank])
+ ) as LogLevelMap;
+ }
+
+ static pickLogLevelFromFlags(
+ flags: getopts.ParsedOptions,
+ defaultLogLevl: LogLevel = 'info'
+ ): LogLevel {
+ for (const level of LOG_LEVELS_DESC) {
+ if (Object.prototype.hasOwnProperty.call(flags, level) && flags[level] === true) {
+ return level;
+ }
+ }
+
+ return defaultLogLevl;
+ }
+
+ private readonly map: LogLevelMap;
+ constructor(public readonly level: LogLevel, private readonly writeTo: LogWriter) {
+ this.map = CliLog.parseLogLevel(level);
+ }
+
+ info(msg: string, ...args: any[]) {
+ if (this.map.info) {
+ this.writeTo.write(`${blueBright('info')} ${format(msg, ...args)}\n`);
+ }
+ }
+
+ warn(msg: string, ...args: any[]) {
+ if (this.map.quiet) {
+ this.writeTo.write(`${yellowBright('warning')} ${format(msg, ...args)}\n`);
+ }
+ }
+
+ error(msg: string, ...args: any[]) {
+ if (this.map.quiet) {
+ this.writeTo.write(`${redBright('error')} ${format(msg, ...args)}\n`);
+ }
+ }
+
+ debug(msg: string, ...args: any[]) {
+ if (this.map.debug) {
+ this.writeTo.write(`${gray('debug')} ${format(msg, ...args)}\n`);
+ }
+ }
+
+ verbose(msg: string, ...args: any[]) {
+ if (this.map.verbose) {
+ this.writeTo.write(`${dim('verbose')}: ${format(msg, ...args)}\n`);
+ }
+ }
+
+ success(msg: string, ...args: any[]): void {
+ if (this.map.quiet) {
+ this.writeTo.write(`✅ ${format(msg, ...args)}\n`);
+ }
+ }
+}
diff --git a/packages/kbn-type-summarizer/src/lib/log/index.ts b/packages/kbn-type-summarizer/src/lib/log/index.ts
new file mode 100644
index 000000000000..68a37528d497
--- /dev/null
+++ b/packages/kbn-type-summarizer/src/lib/log/index.ts
@@ -0,0 +1,11 @@
+/*
+ * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
+ * or more contributor license agreements. Licensed under the Elastic License
+ * 2.0 and the Server Side Public License, v 1; you may not use this file except
+ * in compliance with, at your election, the Elastic License 2.0 or the Server
+ * Side Public License, v 1.
+ */
+
+export * from './logger';
+export * from './cli_log';
+export * from './test_log';
diff --git a/packages/kbn-type-summarizer/src/lib/log/logger.ts b/packages/kbn-type-summarizer/src/lib/log/logger.ts
new file mode 100644
index 000000000000..76cb7fe525f6
--- /dev/null
+++ b/packages/kbn-type-summarizer/src/lib/log/logger.ts
@@ -0,0 +1,49 @@
+/*
+ * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
+ * or more contributor license agreements. Licensed under the Elastic License
+ * 2.0 and the Server Side Public License, v 1; you may not use this file except
+ * in compliance with, at your election, the Elastic License 2.0 or the Server
+ * Side Public License, v 1.
+ */
+
+/**
+ * Logger interface used by @kbn/type-summarizer
+ */
+export interface Logger {
+ /**
+ * Write a message to the log with the level "info"
+ * @param msg any message
+ * @param args any serializeable values you would like to be appended to the log message
+ */
+ info(msg: string, ...args: any[]): void;
+ /**
+ * Write a message to the log with the level "warn"
+ * @param msg any message
+ * @param args any serializeable values you would like to be appended to the log message
+ */
+ warn(msg: string, ...args: any[]): void;
+ /**
+ * Write a message to the log with the level "error"
+ * @param msg any message
+ * @param args any serializeable values you would like to be appended to the log message
+ */
+ error(msg: string, ...args: any[]): void;
+ /**
+ * Write a message to the log with the level "debug"
+ * @param msg any message
+ * @param args any serializeable values you would like to be appended to the log message
+ */
+ debug(msg: string, ...args: any[]): void;
+ /**
+ * Write a message to the log with the level "verbose"
+ * @param msg any message
+ * @param args any serializeable values you would like to be appended to the log message
+ */
+ verbose(msg: string, ...args: any[]): void;
+ /**
+ * Write a message to the log, only excluded in silent mode
+ * @param msg any message
+ * @param args any serializeable values you would like to be appended to the log message
+ */
+ success(msg: string, ...args: any[]): void;
+}
diff --git a/packages/kbn-type-summarizer/src/lib/log/test_log.ts b/packages/kbn-type-summarizer/src/lib/log/test_log.ts
new file mode 100644
index 000000000000..5062a8cbae84
--- /dev/null
+++ b/packages/kbn-type-summarizer/src/lib/log/test_log.ts
@@ -0,0 +1,20 @@
+/*
+ * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
+ * or more contributor license agreements. Licensed under the Elastic License
+ * 2.0 and the Server Side Public License, v 1; you may not use this file except
+ * in compliance with, at your election, the Elastic License 2.0 or the Server
+ * Side Public License, v 1.
+ */
+
+import { CliLog, LogLevel } from './cli_log';
+
+export class TestLog extends CliLog {
+ messages: string[] = [];
+ constructor(level: LogLevel = 'verbose') {
+ super(level, {
+ write: (chunk) => {
+ this.messages.push(chunk);
+ },
+ });
+ }
+}
diff --git a/packages/kbn-type-summarizer/src/lib/path.ts b/packages/kbn-type-summarizer/src/lib/path.ts
new file mode 100644
index 000000000000..79d56aa58fab
--- /dev/null
+++ b/packages/kbn-type-summarizer/src/lib/path.ts
@@ -0,0 +1,36 @@
+/*
+ * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
+ * or more contributor license agreements. Licensed under the Elastic License
+ * 2.0 and the Server Side Public License, v 1; you may not use this file except
+ * in compliance with, at your election, the Elastic License 2.0 or the Server
+ * Side Public License, v 1.
+ */
+
+import Path from 'path';
+
+import normalizePath from 'normalize-path';
+const cwd = normalizePath(process.cwd());
+
+export function cwdRelative(path: string) {
+ return relative(cwd, path);
+}
+
+export function relative(from: string, to: string) {
+ return normalizePath(Path.relative(from, to));
+}
+
+export function join(...segments: string[]) {
+ return Path.join(...segments);
+}
+
+export function dirname(path: string) {
+ return Path.dirname(path);
+}
+
+export function resolve(path: string) {
+ return Path.isAbsolute(path) ? normalizePath(path) : join(cwd, path);
+}
+
+export function isAbsolute(path: string) {
+ return Path.isAbsolute(path);
+}
diff --git a/packages/kbn-type-summarizer/src/lib/printer.ts b/packages/kbn-type-summarizer/src/lib/printer.ts
new file mode 100644
index 000000000000..8ecc4356ea4a
--- /dev/null
+++ b/packages/kbn-type-summarizer/src/lib/printer.ts
@@ -0,0 +1,361 @@
+/*
+ * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
+ * or more contributor license agreements. Licensed under the Elastic License
+ * 2.0 and the Server Side Public License, v 1; you may not use this file except
+ * in compliance with, at your election, the Elastic License 2.0 or the Server
+ * Side Public License, v 1.
+ */
+
+import * as ts from 'typescript';
+import { SourceNode, CodeWithSourceMap } from 'source-map';
+
+import * as Path from './path';
+import { findKind } from './ts_nodes';
+import { SourceMapper } from './source_mapper';
+import { CollectorResult } from './export_collector';
+
+type SourceNodes = Array;
+const COMMENT_TRIM = /^(\s+)(\/\*|\*|\/\/)/;
+
+export class Printer {
+ private readonly tsPrint = ts.createPrinter({
+ newLine: ts.NewLineKind.LineFeed,
+ noEmitHelpers: true,
+ omitTrailingSemicolon: false,
+ removeComments: true,
+ });
+
+ constructor(
+ private readonly sourceMapper: SourceMapper,
+ private readonly results: CollectorResult[],
+ private readonly outputPath: string,
+ private readonly mapOutputPath: string,
+ private readonly sourceRoot: string,
+ private readonly strict: boolean
+ ) {}
+
+ async print(): Promise {
+ const file = new SourceNode(
+ null,
+ null,
+ null,
+ this.results.flatMap((r) => {
+ if (r.type === 'reference') {
+ return `/// \n`;
+ }
+
+ if (r.type === 'import') {
+ // TODO: handle default imports, imports with alternate names, etc
+ return `import { ${r.symbols
+ .map((s) => s.escapedName)
+ .join(', ')} } from ${r.importNode.moduleSpecifier.getText()};\n`;
+ }
+
+ return this.toSourceNodes(r.node, r.exported);
+ })
+ );
+
+ const outputDir = Path.dirname(this.outputPath);
+ const mapOutputDir = Path.dirname(this.mapOutputPath);
+
+ const output = file.toStringWithSourceMap({
+ file: Path.relative(mapOutputDir, this.outputPath),
+ sourceRoot: this.sourceRoot,
+ });
+
+ const nl = output.code.endsWith('\n') ? '' : '\n';
+ const sourceMapPathRel = Path.relative(outputDir, this.mapOutputPath);
+ output.code += `${nl}//# sourceMappingURL=${sourceMapPathRel}`;
+
+ return output;
+ }
+
+ private getDeclarationKeyword(node: ts.Declaration) {
+ if (node.kind === ts.SyntaxKind.FunctionDeclaration) {
+ return 'function';
+ }
+
+ if (node.kind === ts.SyntaxKind.TypeAliasDeclaration) {
+ return 'type';
+ }
+
+ if (node.kind === ts.SyntaxKind.ClassDeclaration) {
+ return 'class';
+ }
+
+ if (node.kind === ts.SyntaxKind.InterfaceDeclaration) {
+ return 'interface';
+ }
+
+ if (ts.isVariableDeclaration(node)) {
+ return this.getVariableDeclarationType(node);
+ }
+ }
+
+ private printModifiers(exported: boolean, node: ts.Declaration) {
+ const flags = ts.getCombinedModifierFlags(node);
+ const modifiers: string[] = [];
+ if (exported) {
+ modifiers.push('export');
+ }
+ if (flags & ts.ModifierFlags.Default) {
+ modifiers.push('default');
+ }
+ if (flags & ts.ModifierFlags.Abstract) {
+ modifiers.push('abstract');
+ }
+ if (flags & ts.ModifierFlags.Private) {
+ modifiers.push('private');
+ }
+ if (flags & ts.ModifierFlags.Public) {
+ modifiers.push('public');
+ }
+ if (flags & ts.ModifierFlags.Static) {
+ modifiers.push('static');
+ }
+ if (flags & ts.ModifierFlags.Readonly) {
+ modifiers.push('readonly');
+ }
+ if (flags & ts.ModifierFlags.Const) {
+ modifiers.push('const');
+ }
+ if (flags & ts.ModifierFlags.Async) {
+ modifiers.push('async');
+ }
+
+ const keyword = this.getDeclarationKeyword(node);
+ if (keyword) {
+ modifiers.push(keyword);
+ }
+
+ return `${modifiers.join(' ')} `;
+ }
+
+ private printNode(node: ts.Node) {
+ return this.tsPrint.printNode(
+ ts.EmitHint.Unspecified,
+ node,
+ this.sourceMapper.getSourceFile(node)
+ );
+ }
+
+ private ensureNewline(string: string): string;
+ private ensureNewline(string: SourceNodes): SourceNodes;
+ private ensureNewline(string: string | SourceNodes): string | SourceNodes {
+ if (typeof string === 'string') {
+ return string.endsWith('\n') ? string : `${string}\n`;
+ }
+
+ const end = string.at(-1);
+ if (end === undefined) {
+ return [];
+ }
+
+ const valid = (typeof end === 'string' ? end : end.toString()).endsWith('\n');
+ return valid ? string : [...string, '\n'];
+ }
+
+ private getMappedSourceNode(node: ts.Node, code?: string) {
+ return this.sourceMapper.getSourceNode(node, code ?? node.getText());
+ }
+
+ private getVariableDeclarationList(node: ts.VariableDeclaration) {
+ const list = node.parent;
+ if (!ts.isVariableDeclarationList(list)) {
+ const kind = findKind(list);
+ throw new Error(
+ `expected parent of variable declaration to be a VariableDeclarationList, got [${kind}]`
+ );
+ }
+ return list;
+ }
+
+ private getVariableDeclarationType(node: ts.VariableDeclaration) {
+ const flags = ts.getCombinedNodeFlags(this.getVariableDeclarationList(node));
+ if (flags & ts.NodeFlags.Const) {
+ return 'const';
+ }
+ if (flags & ts.NodeFlags.Let) {
+ return 'let';
+ }
+ return 'var';
+ }
+
+ private getSourceWithLeadingComments(node: ts.Node) {
+ // variable declarations regularly have leading comments but they're two-parents up, so we have to handle them separately
+ if (!ts.isVariableDeclaration(node)) {
+ return node.getFullText();
+ }
+
+ const list = this.getVariableDeclarationList(node);
+ if (list.declarations.length > 1) {
+ return node.getFullText();
+ }
+
+ const statement = list.parent;
+ if (!ts.isVariableStatement(statement)) {
+ throw new Error('expected parent of VariableDeclarationList to be a VariableStatement');
+ }
+
+ return statement.getFullText();
+ }
+
+ private getLeadingComments(node: ts.Node, indentWidth = 0): string[] {
+ const fullText = this.getSourceWithLeadingComments(node);
+ const ranges = ts.getLeadingCommentRanges(fullText, 0);
+ if (!ranges) {
+ return [];
+ }
+ const indent = ' '.repeat(indentWidth);
+
+ return ranges.flatMap((range) => {
+ const comment = fullText
+ .slice(range.pos, range.end)
+ .split('\n')
+ .map((line) => {
+ const match = line.match(COMMENT_TRIM);
+ if (!match) {
+ return line;
+ }
+
+ const [, spaces, type] = match;
+ return line.slice(type === '*' ? spaces.length - 1 : spaces.length);
+ })
+ .map((line) => `${indent}${line}`)
+ .join('\n');
+
+ if (comment.startsWith('/// this.printNode(p)).join(', ')}>`;
+ }
+
+ private toSourceNodes(node: ts.Node, exported = false): SourceNodes {
+ switch (node.kind) {
+ case ts.SyntaxKind.LiteralType:
+ case ts.SyntaxKind.StringLiteral:
+ case ts.SyntaxKind.BigIntLiteral:
+ case ts.SyntaxKind.NumericLiteral:
+ case ts.SyntaxKind.StringKeyword:
+ return [this.printNode(node)];
+ }
+
+ if (ts.isFunctionDeclaration(node)) {
+ // we are just trying to replace the name with a sourceMapped node, so if there
+ // is no name just return the source
+ if (!node.name) {
+ return [node.getFullText()];
+ }
+
+ return [
+ this.getLeadingComments(node),
+ this.printModifiers(exported, node),
+ this.getMappedSourceNode(node.name),
+ this.printTypeParameters(node),
+ `(${node.parameters.map((p) => p.getFullText()).join(', ')})`,
+ node.type ? [': ', this.printNode(node.type), ';'] : ';',
+ ].flat();
+ }
+
+ if (ts.isInterfaceDeclaration(node)) {
+ const text = node.getText();
+ const name = node.name.getText();
+ const nameI = text.indexOf(name);
+ if (nameI === -1) {
+ throw new Error(`printed version of interface does not include name [${name}]: ${text}`);
+ }
+ return [
+ ...this.getLeadingComments(node),
+ text.slice(0, nameI),
+ this.getMappedSourceNode(node.name, name),
+ text.slice(nameI + name.length),
+ '\n',
+ ];
+ }
+
+ if (ts.isVariableDeclaration(node)) {
+ return [
+ ...this.getLeadingComments(node),
+ this.printModifiers(exported, node),
+ this.getMappedSourceNode(node.name),
+ ...(node.type ? [': ', this.printNode(node.type)] : []),
+ ';\n',
+ ];
+ }
+
+ if (ts.isUnionTypeNode(node)) {
+ return node.types.flatMap((type, i) =>
+ i > 0 ? [' | ', ...this.toSourceNodes(type)] : this.toSourceNodes(type)
+ );
+ }
+
+ if (ts.isTypeAliasDeclaration(node)) {
+ return [
+ ...this.getLeadingComments(node),
+ this.printModifiers(exported, node),
+ this.getMappedSourceNode(node.name),
+ this.printTypeParameters(node),
+ ' = ',
+ this.ensureNewline(this.toSourceNodes(node.type)),
+ ].flat();
+ }
+
+ if (ts.isClassDeclaration(node)) {
+ return [
+ ...this.getLeadingComments(node),
+ this.printModifiers(exported, node),
+ node.name ? this.getMappedSourceNode(node.name) : [],
+ this.printTypeParameters(node),
+ ' {\n',
+ node.members.flatMap((m) => {
+ const memberText = m.getText();
+
+ if (ts.isConstructorDeclaration(m)) {
+ return ` ${memberText}\n`;
+ }
+
+ if (!m.name) {
+ return ` ${memberText}\n`;
+ }
+
+ const nameText = m.name.getText();
+ const pos = memberText.indexOf(nameText);
+ if (pos === -1) {
+ return ` ${memberText}\n`;
+ }
+
+ const left = memberText.slice(0, pos);
+ const right = memberText.slice(pos + nameText.length);
+ const nameNode = this.getMappedSourceNode(m.name, nameText);
+
+ return [...this.getLeadingComments(m, 2), ` `, left, nameNode, right, `\n`];
+ }),
+ '}\n',
+ ].flat();
+ }
+
+ if (!this.strict) {
+ return [this.ensureNewline(this.printNode(node))];
+ } else {
+ throw new Error(`unable to print export type of kind [${findKind(node)}]`);
+ }
+ }
+}
diff --git a/packages/kbn-type-summarizer/src/lib/run.ts b/packages/kbn-type-summarizer/src/lib/run.ts
new file mode 100644
index 000000000000..4834c4d8aae9
--- /dev/null
+++ b/packages/kbn-type-summarizer/src/lib/run.ts
@@ -0,0 +1,49 @@
+/*
+ * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
+ * or more contributor license agreements. Licensed under the Elastic License
+ * 2.0 and the Server Side Public License, v 1; you may not use this file except
+ * in compliance with, at your election, the Elastic License 2.0 or the Server
+ * Side Public License, v 1.
+ */
+
+import getopts from 'getopts';
+
+import { CliLog, LogLevel } from './log';
+import { toError } from './helpers/error';
+import { CliError } from './cli_error';
+
+export interface RunContext {
+ argv: string[];
+ log: CliLog;
+}
+
+export interface RunOptions {
+ helpText: string;
+ defaultLogLevel?: LogLevel;
+}
+
+export async function run(main: (ctx: RunContext) => Promise, options: RunOptions) {
+ const argv = process.argv.slice(2);
+ const rawFlags = getopts(argv);
+
+ const log = new CliLog(
+ CliLog.pickLogLevelFromFlags(rawFlags, options.defaultLogLevel),
+ process.stdout
+ );
+
+ try {
+ await main({ argv, log });
+ } catch (_) {
+ const error = toError(_);
+ if (error instanceof CliError) {
+ process.exitCode = error.exitCode;
+ log.error(error.message);
+ if (error.showHelp) {
+ process.stdout.write(options.helpText);
+ }
+ } else {
+ log.error('UNHANDLED ERROR', error.stack);
+ process.exitCode = 1;
+ }
+ }
+}
diff --git a/packages/kbn-type-summarizer/src/lib/source_mapper.ts b/packages/kbn-type-summarizer/src/lib/source_mapper.ts
new file mode 100644
index 000000000000..1f03119e8e3f
--- /dev/null
+++ b/packages/kbn-type-summarizer/src/lib/source_mapper.ts
@@ -0,0 +1,143 @@
+/*
+ * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
+ * or more contributor license agreements. Licensed under the Elastic License
+ * 2.0 and the Server Side Public License, v 1; you may not use this file except
+ * in compliance with, at your election, the Elastic License 2.0 or the Server
+ * Side Public License, v 1.
+ */
+
+import * as ts from 'typescript';
+import { SourceNode, SourceMapConsumer, BasicSourceMapConsumer } from 'source-map';
+
+import { Logger } from './log';
+import { tryReadFile } from './helpers/fs';
+import { parseJson } from './helpers/json';
+import { isNodeModule } from './is_node_module';
+import * as Path from './path';
+
+type SourceMapConsumerEntry = [ts.SourceFile, BasicSourceMapConsumer | undefined];
+
+export class SourceMapper {
+ static async forSourceFiles(
+ log: Logger,
+ dtsDir: string,
+ repoRelativePackageDir: string,
+ sourceFiles: readonly ts.SourceFile[]
+ ) {
+ const entries = await Promise.all(
+ sourceFiles.map(async (sourceFile): Promise => {
+ if (isNodeModule(dtsDir, sourceFile.fileName)) {
+ return;
+ }
+
+ const text = sourceFile.getText();
+ const match = text.match(/^\/\/#\s*sourceMappingURL=(.*)/im);
+ if (!match) {
+ return [sourceFile, undefined];
+ }
+
+ const relSourceFile = Path.cwdRelative(sourceFile.fileName);
+ const sourceMapPath = Path.join(Path.dirname(sourceFile.fileName), match[1]);
+ const relSourceMapPath = Path.cwdRelative(sourceMapPath);
+ const sourceJson = await tryReadFile(sourceMapPath, 'utf8');
+ if (!sourceJson) {
+ throw new Error(
+ `unable to find source map for [${relSourceFile}] expected at [${match[1]}]`
+ );
+ }
+
+ const json = parseJson(sourceJson, `source map at [${relSourceMapPath}]`);
+ return [sourceFile, await new SourceMapConsumer(json)];
+ })
+ );
+
+ const consumers = new Map(entries.filter((e): e is SourceMapConsumerEntry => !!e));
+ log.debug(
+ 'loaded sourcemaps for',
+ Array.from(consumers.keys()).map((s) => Path.relative(process.cwd(), s.fileName))
+ );
+
+ return new SourceMapper(consumers, repoRelativePackageDir);
+ }
+
+ private readonly sourceFixDir: string;
+ constructor(
+ private readonly consumers: Map,
+ repoRelativePackageDir: string
+ ) {
+ this.sourceFixDir = Path.join('/', repoRelativePackageDir);
+ }
+
+ /**
+ * We ensure that `sourceRoot` is not defined in the tsconfig files, and we assume that the `source` value
+ * for each file in the source map will be a relative path out of the bazel-out dir and to the `repoRelativePackageDir`
+ * or some path outside of the package in rare situations. Our goal is to convert each of these source paths
+ * to new path that is relative to the `repoRelativePackageDir` path. To do this we resolve the `repoRelativePackageDir`
+ * as if it was at the root of the filesystem, then do the same for the `source`, so both paths should be
+ * absolute, but only include the path segments from the root of the repo. We then get the relative path from
+ * the absolute version of the `repoRelativePackageDir` to the absolute version of the `source`, which should give
+ * us the path to the source, relative to the `repoRelativePackageDir`.
+ */
+ fixSourcePath(source: string) {
+ return Path.relative(this.sourceFixDir, Path.join('/', source));
+ }
+
+ getSourceNode(generatedNode: ts.Node, code: string) {
+ const pos = this.findOriginalPosition(generatedNode);
+
+ if (pos) {
+ return new SourceNode(pos.line, pos.column, pos.source, code, pos.name ?? undefined);
+ }
+
+ return new SourceNode(null, null, null, code);
+ }
+
+ sourceFileCache = new WeakMap();
+ // abstracted so we can cache this
+ getSourceFile(node: ts.Node): ts.SourceFile {
+ if (ts.isSourceFile(node)) {
+ return node;
+ }
+
+ const cached = this.sourceFileCache.get(node);
+ if (cached) {
+ return cached;
+ }
+
+ const sourceFile = this.getSourceFile(node.parent);
+ this.sourceFileCache.set(node, sourceFile);
+ return sourceFile;
+ }
+
+ findOriginalPosition(node: ts.Node) {
+ const dtsSource = this.getSourceFile(node);
+
+ if (!this.consumers.has(dtsSource)) {
+ throw new Error(`sourceFile for [${dtsSource.fileName}] didn't have sourcemaps loaded`);
+ }
+
+ const consumer = this.consumers.get(dtsSource);
+ if (!consumer) {
+ return;
+ }
+
+ const posInDts = dtsSource.getLineAndCharacterOfPosition(node.getStart());
+ const pos = consumer.originalPositionFor({
+ /* ts line column numbers are 0 based, source map column numbers are also 0 based */
+ column: posInDts.character,
+ /* ts line numbers are 0 based, source map line numbers are 1 based */
+ line: posInDts.line + 1,
+ });
+
+ return {
+ ...pos,
+ source: pos.source ? this.fixSourcePath(pos.source) : null,
+ };
+ }
+
+ close() {
+ for (const consumer of this.consumers.values()) {
+ consumer?.destroy();
+ }
+ }
+}
diff --git a/packages/kbn-type-summarizer/src/lib/ts_nodes.ts b/packages/kbn-type-summarizer/src/lib/ts_nodes.ts
new file mode 100644
index 000000000000..b5c03ee8c4c1
--- /dev/null
+++ b/packages/kbn-type-summarizer/src/lib/ts_nodes.ts
@@ -0,0 +1,73 @@
+/*
+ * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
+ * or more contributor license agreements. Licensed under the Elastic License
+ * 2.0 and the Server Side Public License, v 1; you may not use this file except
+ * in compliance with, at your election, the Elastic License 2.0 or the Server
+ * Side Public License, v 1.
+ */
+
+import * as ts from 'typescript';
+
+export type ValueNode =
+ | ts.ClassDeclaration
+ | ts.FunctionDeclaration
+ | ts.TypeAliasDeclaration
+ | ts.VariableDeclaration
+ | ts.InterfaceDeclaration;
+
+export function isExportedValueNode(node: ts.Node): node is ValueNode {
+ return (
+ node.kind === ts.SyntaxKind.ClassDeclaration ||
+ node.kind === ts.SyntaxKind.FunctionDeclaration ||
+ node.kind === ts.SyntaxKind.TypeAliasDeclaration ||
+ node.kind === ts.SyntaxKind.VariableDeclaration ||
+ node.kind === ts.SyntaxKind.InterfaceDeclaration
+ );
+}
+export function assertExportedValueNode(node: ts.Node): asserts node is ValueNode {
+ if (!isExportedValueNode(node)) {
+ const kind = findKind(node);
+ throw new Error(`not a valid ExportedValueNode [kind=${kind}]`);
+ }
+}
+export function toExportedNodeValue(node: ts.Node): ValueNode {
+ assertExportedValueNode(node);
+ return node;
+}
+
+export function findKind(node: ts.Node) {
+ for (const [name, value] of Object.entries(ts.SyntaxKind)) {
+ if (node.kind === value) {
+ return name;
+ }
+ }
+
+ throw new Error('node.kind is not in the SyntaxKind map');
+}
+
+export type DecSymbol = ts.Symbol & {
+ declarations: NonNullable;
+};
+export function isDecSymbol(symbol: ts.Symbol): symbol is DecSymbol {
+ return !!symbol.declarations;
+}
+export function assertDecSymbol(symbol: ts.Symbol): asserts symbol is DecSymbol {
+ if (!isDecSymbol(symbol)) {
+ throw new Error('symbol has no declarations');
+ }
+}
+export function toDecSymbol(symbol: ts.Symbol): DecSymbol {
+ assertDecSymbol(symbol);
+ return symbol;
+}
+
+export type ExportFromDeclaration = ts.ExportDeclaration & {
+ moduleSpecifier: NonNullable;
+};
+export function isExportFromDeclaration(node: ts.Node): node is ExportFromDeclaration {
+ return ts.isExportDeclaration(node) && !!node.moduleSpecifier;
+}
+
+export function isAliasSymbol(symbol: ts.Symbol) {
+ return symbol.flags & ts.SymbolFlags.Alias;
+}
diff --git a/packages/kbn-type-summarizer/src/lib/ts_project.ts b/packages/kbn-type-summarizer/src/lib/ts_project.ts
new file mode 100644
index 000000000000..92946e329044
--- /dev/null
+++ b/packages/kbn-type-summarizer/src/lib/ts_project.ts
@@ -0,0 +1,20 @@
+/*
+ * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
+ * or more contributor license agreements. Licensed under the Elastic License
+ * 2.0 and the Server Side Public License, v 1; you may not use this file except
+ * in compliance with, at your election, the Elastic License 2.0 or the Server
+ * Side Public License, v 1.
+ */
+
+import * as ts from 'typescript';
+
+export function createTsProject(tsConfig: ts.ParsedCommandLine, inputPaths: string[]) {
+ return ts.createProgram({
+ rootNames: inputPaths,
+ options: {
+ ...tsConfig.options,
+ skipLibCheck: false,
+ },
+ projectReferences: tsConfig.projectReferences,
+ });
+}
diff --git a/packages/kbn-type-summarizer/src/lib/tsconfig_file.ts b/packages/kbn-type-summarizer/src/lib/tsconfig_file.ts
new file mode 100644
index 000000000000..f3d491c93abc
--- /dev/null
+++ b/packages/kbn-type-summarizer/src/lib/tsconfig_file.ts
@@ -0,0 +1,26 @@
+/*
+ * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
+ * or more contributor license agreements. Licensed under the Elastic License
+ * 2.0 and the Server Side Public License, v 1; you may not use this file except
+ * in compliance with, at your election, the Elastic License 2.0 or the Server
+ * Side Public License, v 1.
+ */
+
+import * as ts from 'typescript';
+
+import * as Path from './path';
+import { CliError } from './cli_error';
+
+export function readTsConfigFile(path: string) {
+ const json = ts.readConfigFile(path, ts.sys.readFile);
+
+ if (json.error) {
+ throw new CliError(`Unable to load tsconfig file: ${json.error.messageText}`);
+ }
+
+ return json.config;
+}
+
+export function loadTsConfigFile(path: string) {
+ return ts.parseJsonConfigFileContent(readTsConfigFile(path) ?? {}, ts.sys, Path.dirname(path));
+}
diff --git a/packages/kbn-type-summarizer/src/run_api_extractor.ts b/packages/kbn-type-summarizer/src/run_api_extractor.ts
new file mode 100644
index 000000000000..0e7bae5165a4
--- /dev/null
+++ b/packages/kbn-type-summarizer/src/run_api_extractor.ts
@@ -0,0 +1,86 @@
+/* eslint-disable @kbn/eslint/require-license-header */
+
+/**
+ * @license
+ * Copyright Google LLC All Rights Reserved.
+ *
+ * Use of this source code is governed by an MIT-style license that can be
+ * found in the LICENSE file at https://angular.io/license
+ */
+
+import Fsp from 'fs/promises';
+import Path from 'path';
+
+import { Extractor, ExtractorConfig } from '@microsoft/api-extractor';
+
+import { readTsConfigFile } from './lib/tsconfig_file';
+import { CliError } from './lib/cli_error';
+
+export async function runApiExtractor(
+ tsconfigPath: string,
+ entryPath: string,
+ dtsBundleOutDir: string
+) {
+ const pkgJson = Path.resolve(Path.dirname(entryPath), 'package.json');
+ try {
+ await Fsp.writeFile(
+ pkgJson,
+ JSON.stringify({
+ name: 'GENERATED-BY-BAZEL',
+ description: 'This is a dummy package.json as API Extractor always requires one.',
+ types: './index.d.ts',
+ private: true,
+ license: 'SSPL-1.0 OR Elastic License 2.0',
+ version: '1.0.0',
+ }),
+ {
+ flag: 'wx',
+ }
+ );
+ } catch (error) {
+ if (!error.code || error.code !== 'EEXIST') {
+ throw error;
+ }
+ }
+
+ // API extractor doesn't always support the version of TypeScript used in the repo
+ // example: at the moment it is not compatable with 3.2
+ // to use the internal TypeScript we shall not create a program but rather pass a parsed tsConfig.
+ const extractorOptions = {
+ localBuild: false,
+ };
+
+ const extractorConfig = ExtractorConfig.prepare({
+ configObject: {
+ compiler: {
+ overrideTsconfig: readTsConfigFile(tsconfigPath),
+ },
+ projectFolder: Path.dirname(tsconfigPath),
+ mainEntryPointFilePath: entryPath,
+ apiReport: {
+ enabled: false,
+ // TODO(alan-agius4): remove this folder name when the below issue is solved upstream
+ // See: https://github.com/microsoft/web-build-tools/issues/1470
+ reportFileName: 'invalid',
+ },
+ docModel: {
+ enabled: false,
+ },
+ dtsRollup: {
+ enabled: !!dtsBundleOutDir,
+ untrimmedFilePath: dtsBundleOutDir,
+ },
+ tsdocMetadata: {
+ enabled: false,
+ },
+ },
+ packageJson: undefined,
+ packageJsonFullPath: pkgJson,
+ configObjectFullPath: undefined,
+ });
+ const { succeeded } = Extractor.invoke(extractorConfig, extractorOptions);
+
+ if (!succeeded) {
+ throw new CliError('api-extractor failed');
+ }
+}
diff --git a/packages/kbn-type-summarizer/src/summarize_package.ts b/packages/kbn-type-summarizer/src/summarize_package.ts
new file mode 100644
index 000000000000..d3aac96af177
--- /dev/null
+++ b/packages/kbn-type-summarizer/src/summarize_package.ts
@@ -0,0 +1,123 @@
+/*
+ * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
+ * or more contributor license agreements. Licensed under the Elastic License
+ * 2.0 and the Server Side Public License, v 1; you may not use this file except
+ * in compliance with, at your election, the Elastic License 2.0 or the Server
+ * Side Public License, v 1.
+ */
+
+import Fsp from 'fs/promises';
+import Path from 'path';
+
+import normalizePath from 'normalize-path';
+
+import { SourceMapper } from './lib/source_mapper';
+import { createTsProject } from './lib/ts_project';
+import { loadTsConfigFile } from './lib/tsconfig_file';
+import { ExportCollector } from './lib/export_collector';
+import { isNodeModule } from './lib/is_node_module';
+import { Printer } from './lib/printer';
+import { Logger } from './lib/log';
+
+/**
+ * Options used to customize the summarizePackage function
+ */
+export interface SummarizePacakgeOptions {
+ /**
+ * Absolute path to the directory containing the .d.ts files produced by `tsc`. Maps to the
+ * `declarationDir` compiler option.
+ */
+ dtsDir: string;
+ /**
+ * Absolute path to the tsconfig.json file for the project we are summarizing
+ */
+ tsconfigPath: string;
+ /**
+ * Array of absolute paths to the .d.ts files which will be summarized. Each file in this
+ * array will cause an output .d.ts summary file to be created containing all the AST nodes
+ * which are exported or referenced by those exports.
+ */
+ inputPaths: string[];
+ /**
+ * Absolute path to the output directory where the summary .d.ts files should be written
+ */
+ outputDir: string;
+ /**
+ * Repo-relative path to the package source, for example `packages/kbn-type-summarizer` for
+ * this package. This is used to provide the correct `sourceRoot` path in the resulting source
+ * map files.
+ */
+ repoRelativePackageDir: string;
+ /**
+ * Should the printer throw an error if it doesn't know how to print an AST node? Primarily
+ * used for testing
+ */
+ strictPrinting?: boolean;
+}
+
+/**
+ * Produce summary .d.ts files for a package
+ */
+export async function summarizePackage(log: Logger, options: SummarizePacakgeOptions) {
+ const tsConfig = loadTsConfigFile(options.tsconfigPath);
+ log.verbose('Created tsconfig', tsConfig);
+
+ if (tsConfig.options.sourceRoot) {
+ throw new Error(`${options.tsconfigPath} must not define "compilerOptions.sourceRoot"`);
+ }
+
+ const program = createTsProject(tsConfig, options.inputPaths);
+ log.verbose('Loaded typescript program');
+
+ const typeChecker = program.getTypeChecker();
+ log.verbose('Typechecker loaded');
+
+ const sourceFiles = program
+ .getSourceFiles()
+ .filter((f) => !isNodeModule(options.dtsDir, f.fileName))
+ .sort((a, b) => a.fileName.localeCompare(b.fileName));
+
+ const sourceMapper = await SourceMapper.forSourceFiles(
+ log,
+ options.dtsDir,
+ options.repoRelativePackageDir,
+ sourceFiles
+ );
+
+ // value that will end up as the `sourceRoot` in the final sourceMaps
+ const sourceRoot = `../../../${normalizePath(options.repoRelativePackageDir)}`;
+
+ for (const input of options.inputPaths) {
+ const outputPath = Path.resolve(options.outputDir, Path.basename(input));
+ const mapOutputPath = `${outputPath}.map`;
+ const sourceFile = program.getSourceFile(input);
+ if (!sourceFile) {
+ throw new Error(`input file wasn't included in the program`);
+ }
+
+ const results = new ExportCollector(
+ log,
+ typeChecker,
+ sourceFile,
+ options.dtsDir,
+ sourceMapper
+ ).run();
+
+ const printer = new Printer(
+ sourceMapper,
+ results.getAll(),
+ outputPath,
+ mapOutputPath,
+ sourceRoot,
+ !!options.strictPrinting
+ );
+
+ const summary = await printer.print();
+
+ await Fsp.mkdir(options.outputDir, { recursive: true });
+ await Fsp.writeFile(outputPath, summary.code);
+ await Fsp.writeFile(mapOutputPath, JSON.stringify(summary.map));
+
+ sourceMapper.close();
+ }
+}
diff --git a/packages/kbn-type-summarizer/src/tests/integration_helpers.ts b/packages/kbn-type-summarizer/src/tests/integration_helpers.ts
new file mode 100644
index 000000000000..c64e58c4e33f
--- /dev/null
+++ b/packages/kbn-type-summarizer/src/tests/integration_helpers.ts
@@ -0,0 +1,177 @@
+/*
+ * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
+ * or more contributor license agreements. Licensed under the Elastic License
+ * 2.0 and the Server Side Public License, v 1; you may not use this file except
+ * in compliance with, at your election, the Elastic License 2.0 or the Server
+ * Side Public License, v 1.
+ */
+
+/* eslint-disable no-console */
+
+import Path from 'path';
+import Fsp from 'fs/promises';
+
+import * as ts from 'typescript';
+import stripAnsi from 'strip-ansi';
+import normalizePath from 'normalize-path';
+
+import { loadTsConfigFile } from '../lib/tsconfig_file';
+import { createTsProject } from '../lib/ts_project';
+import { TestLog } from '../lib/log';
+import { summarizePackage } from '../summarize_package';
+
+const TMP_DIR = Path.resolve(__dirname, '../../__tmp__');
+
+const DIAGNOSTIC_HOST = {
+ getCanonicalFileName: (p: string) => p,
+ getCurrentDirectory: () => process.cwd(),
+ getNewLine: () => '\n',
+};
+
+function dedent(string: string) {
+ const lines = string.split('\n');
+ while (lines.length && lines[0].trim() === '') {
+ lines.shift();
+ }
+ if (lines.length === 0) {
+ return '';
+ }
+ const indent = lines[0].split('').findIndex((c) => c !== ' ');
+ return lines.map((l) => l.slice(indent)).join('\n');
+}
+
+function ensureDts(path: string) {
+ if (path.endsWith('.d.ts')) {
+ throw new Error('path should end with .ts, not .d.ts');
+ }
+ return `${path.slice(0, -3)}.d.ts`;
+}
+
+interface Options {
+ /* Other files which should be available to the test execution */
+ otherFiles?: Record;
+}
+
+class MockCli {
+ /* file contents which will be fed into TypeScript for this test */
+ public readonly mockFiles: Record;
+
+ /* directory where mockFiles pretend to be from */
+ public readonly sourceDir = Path.resolve(TMP_DIR, 'src');
+ /* directory where we will write .d.ts versions of mockFiles */
+ public readonly dtsOutputDir = Path.resolve(TMP_DIR, 'dist_dts');
+ /* directory where output will be written */
+ public readonly outputDir = Path.resolve(TMP_DIR, 'dts');
+ /* path where the tsconfig.json file will be written */
+ public readonly tsconfigPath = Path.resolve(this.sourceDir, 'tsconfig.json');
+
+ /* .d.ts file which we will read to discover the types we need to summarize */
+ public readonly inputPath = ensureDts(Path.resolve(this.dtsOutputDir, 'index.ts'));
+ /* the location we will write the summarized .d.ts file */
+ public readonly outputPath = Path.resolve(this.outputDir, Path.basename(this.inputPath));
+ /* the location we will write the sourcemaps for the summaried .d.ts file */
+ public readonly mapOutputPath = `${this.outputPath}.map`;
+
+ constructor(tsContent: string, options?: Options) {
+ this.mockFiles = {
+ ...options?.otherFiles,
+ 'index.ts': tsContent,
+ };
+ }
+
+ private buildDts() {
+ const program = createTsProject(
+ loadTsConfigFile(this.tsconfigPath),
+ Object.keys(this.mockFiles).map((n) => Path.resolve(this.sourceDir, n))
+ );
+
+ this.printDiagnostics(`dts/config`, program.getConfigFileParsingDiagnostics());
+ this.printDiagnostics(`dts/global`, program.getGlobalDiagnostics());
+ this.printDiagnostics(`dts/options`, program.getOptionsDiagnostics());
+ this.printDiagnostics(`dts/semantic`, program.getSemanticDiagnostics());
+ this.printDiagnostics(`dts/syntactic`, program.getSyntacticDiagnostics());
+ this.printDiagnostics(`dts/declaration`, program.getDeclarationDiagnostics());
+
+ const result = program.emit(undefined, undefined, undefined, true);
+ this.printDiagnostics('dts/results', result.diagnostics);
+ }
+
+ private printDiagnostics(type: string, diagnostics: readonly ts.Diagnostic[]) {
+ const errors = diagnostics.filter((d) => d.category === ts.DiagnosticCategory.Error);
+ if (!errors.length) {
+ return;
+ }
+
+ const message = ts.formatDiagnosticsWithColorAndContext(errors, DIAGNOSTIC_HOST);
+
+ console.error(
+ `TS Errors (${type}):\n${message
+ .split('\n')
+ .map((l) => ` ${l}`)
+ .join('\n')}`
+ );
+ }
+
+ async run() {
+ const log = new TestLog('debug');
+
+ // wipe out the tmp dir
+ await Fsp.rm(TMP_DIR, { recursive: true, force: true });
+
+ // write mock files to the filesystem
+ await Promise.all(
+ Object.entries(this.mockFiles).map(async ([rel, content]) => {
+ const path = Path.resolve(this.sourceDir, rel);
+ await Fsp.mkdir(Path.dirname(path), { recursive: true });
+ await Fsp.writeFile(path, dedent(content));
+ })
+ );
+
+ // write tsconfig.json to the filesystem
+ await Fsp.writeFile(
+ this.tsconfigPath,
+ JSON.stringify({
+ include: [`**/*.ts`, `**/*.tsx`],
+ compilerOptions: {
+ moduleResolution: 'node',
+ target: 'es2021',
+ module: 'CommonJS',
+ strict: true,
+ esModuleInterop: true,
+ allowSyntheticDefaultImports: true,
+ declaration: true,
+ emitDeclarationOnly: true,
+ declarationDir: '../dist_dts',
+ declarationMap: true,
+ // prevent loading all @types packages
+ typeRoots: [],
+ },
+ })
+ );
+
+ // convert the source files to .d.ts files
+ this.buildDts();
+
+ // summarize the .d.ts files into the output dir
+ await summarizePackage(log, {
+ dtsDir: normalizePath(this.dtsOutputDir),
+ inputPaths: [normalizePath(this.inputPath)],
+ outputDir: normalizePath(this.outputDir),
+ repoRelativePackageDir: 'src',
+ tsconfigPath: normalizePath(this.tsconfigPath),
+ strictPrinting: false,
+ });
+
+ // return the results
+ return {
+ code: await Fsp.readFile(this.outputPath, 'utf8'),
+ map: JSON.parse(await Fsp.readFile(this.mapOutputPath, 'utf8')),
+ logs: stripAnsi(log.messages.join('')),
+ };
+ }
+}
+
+export async function run(tsContent: string, options?: Options) {
+ const project = new MockCli(tsContent, options);
+ return await project.run();
+}
diff --git a/packages/kbn-type-summarizer/src/tests/integration_tests/class.test.ts b/packages/kbn-type-summarizer/src/tests/integration_tests/class.test.ts
new file mode 100644
index 000000000000..eaf87cda8521
--- /dev/null
+++ b/packages/kbn-type-summarizer/src/tests/integration_tests/class.test.ts
@@ -0,0 +1,77 @@
+/*
+ * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
+ * or more contributor license agreements. Licensed under the Elastic License
+ * 2.0 and the Server Side Public License, v 1; you may not use this file except
+ * in compliance with, at your election, the Elastic License 2.0 or the Server
+ * Side Public License, v 1.
+ */
+
+import { run } from '../integration_helpers';
+
+it('prints basic class correctly', async () => {
+ const output = await run(`
+ /**
+ * Interface for writin records to a database
+ */
+ interface Db {
+ write(record: Record): Promise
+ }
+
+ export class Foo {
+ /**
+ * The name of the Foo
+ */
+ public readonly name: string
+ constructor(name: string) {
+ this.name = name.toLowerCase()
+ }
+
+ speak() {
+ alert('hi, my name is ' + this.name)
+ }
+
+ async save(db: Db) {
+ await db.write({
+ name: this.name
+ })
+ }
+ }
+ `);
+
+ expect(output.code).toMatchInlineSnapshot(`
+ "/**
+ * Interface for writin records to a database
+ */
+ interface Db {
+ write(record: Record): Promise;
+ }
+ export class Foo {
+ /**
+ * The name of the Foo
+ */
+ readonly name: string;
+ constructor(name: string);
+ speak(): void;
+ save(db: Db): Promise;
+ }
+ //# sourceMappingURL=index.d.ts.map"
+ `);
+ expect(output.map).toMatchInlineSnapshot(`
+ Object {
+ "file": "index.d.ts",
+ "mappings": ";;;UAGU,E;;;aAIG,G;;;;WAIK,I;;EAKhB,K;EAIM,I",
+ "names": Array [],
+ "sourceRoot": "../../../src",
+ "sources": Array [
+ "index.ts",
+ ],
+ "version": 3,
+ }
+ `);
+ expect(output.logs).toMatchInlineSnapshot(`
+ "debug loaded sourcemaps for [ 'packages/kbn-type-summarizer/__tmp__/dist_dts/index.d.ts' ]
+ debug Ignoring 1 global declarations for \\"Record\\"
+ debug Ignoring 5 global declarations for \\"Promise\\"
+ "
+ `);
+});
diff --git a/packages/kbn-type-summarizer/src/tests/integration_tests/function.test.ts b/packages/kbn-type-summarizer/src/tests/integration_tests/function.test.ts
new file mode 100644
index 000000000000..de0f1bb4c6d4
--- /dev/null
+++ b/packages/kbn-type-summarizer/src/tests/integration_tests/function.test.ts
@@ -0,0 +1,83 @@
+/*
+ * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
+ * or more contributor license agreements. Licensed under the Elastic License
+ * 2.0 and the Server Side Public License, v 1; you may not use this file except
+ * in compliance with, at your election, the Elastic License 2.0 or the Server
+ * Side Public License, v 1.
+ */
+
+import { run } from '../integration_helpers';
+
+it('prints the function declaration, including comments', async () => {
+ const result = await run(
+ `
+ import { Bar } from './bar';
+
+ /**
+ * Convert a Bar to a string
+ */
+ export function foo(
+ /**
+ * Important comment
+ */
+ name: Bar
+ ) {
+ return name.toString();
+ }
+ `,
+ {
+ otherFiles: {
+ 'bar.ts': `
+ export class Bar {
+ constructor(
+ private value: T
+ ){}
+
+ toString() {
+ return this.value.toString()
+ }
+ }
+ `,
+ },
+ }
+ );
+
+ expect(result.code).toMatchInlineSnapshot(`
+ "class Bar {
+ private value;
+ constructor(value: T);
+ toString(): string;
+ }
+ /**
+ * Convert a Bar to a string
+ */
+ export function foo(
+ /**
+ * Important comment
+ */
+ name: Bar): string;
+ //# sourceMappingURL=index.d.ts.map"
+ `);
+ expect(result.map).toMatchInlineSnapshot(`
+ Object {
+ "file": "index.d.ts",
+ "mappings": "MAAa,G;;;UAED,K;;EAGV,Q;;;;;gBCAc,G",
+ "names": Array [],
+ "sourceRoot": "../../../src",
+ "sources": Array [
+ "bar.ts",
+ "index.ts",
+ ],
+ "version": 3,
+ }
+ `);
+ expect(result.logs).toMatchInlineSnapshot(`
+ "debug loaded sourcemaps for [
+ 'packages/kbn-type-summarizer/__tmp__/dist_dts/bar.d.ts',
+ 'packages/kbn-type-summarizer/__tmp__/dist_dts/index.d.ts'
+ ]
+ "
+ `);
+});
diff --git a/packages/kbn-type-summarizer/src/tests/integration_tests/import_boundary.test.ts b/packages/kbn-type-summarizer/src/tests/integration_tests/import_boundary.test.ts
new file mode 100644
index 000000000000..f1e3279bb57b
--- /dev/null
+++ b/packages/kbn-type-summarizer/src/tests/integration_tests/import_boundary.test.ts
@@ -0,0 +1,90 @@
+/*
+ * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
+ * or more contributor license agreements. Licensed under the Elastic License
+ * 2.0 and the Server Side Public License, v 1; you may not use this file except
+ * in compliance with, at your election, the Elastic License 2.0 or the Server
+ * Side Public License, v 1.
+ */
+
+import { run } from '../integration_helpers';
+
+const nodeModules = {
+ 'node_modules/foo/index.ts': `
+ export class Foo {
+ render() {
+ return 'hello'
+ }
+ }
+ `,
+ 'node_modules/bar/index.ts': `
+ export default class Bar {
+ render() {
+ return 'hello'
+ }
+ }
+ `,
+};
+
+it('output type links to named import from node modules', async () => {
+ const output = await run(
+ `
+ import { Foo } from 'foo'
+ export type ValidName = string | Foo
+ `,
+ { otherFiles: nodeModules }
+ );
+
+ expect(output.code).toMatchInlineSnapshot(`
+ "import { Foo } from 'foo';
+ export type ValidName = string | Foo
+ //# sourceMappingURL=index.d.ts.map"
+ `);
+ expect(output.map).toMatchInlineSnapshot(`
+ Object {
+ "file": "index.d.ts",
+ "mappings": ";YACY,S",
+ "names": Array [],
+ "sourceRoot": "../../../src",
+ "sources": Array [
+ "index.ts",
+ ],
+ "version": 3,
+ }
+ `);
+ expect(output.logs).toMatchInlineSnapshot(`
+ "debug loaded sourcemaps for [ 'packages/kbn-type-summarizer/__tmp__/dist_dts/index.d.ts' ]
+ "
+ `);
+});
+
+it('output type links to default import from node modules', async () => {
+ const output = await run(
+ `
+ import Bar from 'bar'
+ export type ValidName = string | Bar
+ `,
+ { otherFiles: nodeModules }
+ );
+
+ expect(output.code).toMatchInlineSnapshot(`
+ "import { Bar } from 'bar';
+ export type ValidName = string | Bar
+ //# sourceMappingURL=index.d.ts.map"
+ `);
+ expect(output.map).toMatchInlineSnapshot(`
+ Object {
+ "file": "index.d.ts",
+ "mappings": ";YACY,S",
+ "names": Array [],
+ "sourceRoot": "../../../src",
+ "sources": Array [
+ "index.ts",
+ ],
+ "version": 3,
+ }
+ `);
+ expect(output.logs).toMatchInlineSnapshot(`
+ "debug loaded sourcemaps for [ 'packages/kbn-type-summarizer/__tmp__/dist_dts/index.d.ts' ]
+ "
+ `);
+});
diff --git a/packages/kbn-type-summarizer/src/tests/integration_tests/interface.test.ts b/packages/kbn-type-summarizer/src/tests/integration_tests/interface.test.ts
new file mode 100644
index 000000000000..cbccbfb1d77d
--- /dev/null
+++ b/packages/kbn-type-summarizer/src/tests/integration_tests/interface.test.ts
@@ -0,0 +1,62 @@
+/*
+ * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
+ * or more contributor license agreements. Licensed under the Elastic License
+ * 2.0 and the Server Side Public License, v 1; you may not use this file except
+ * in compliance with, at your election, the Elastic License 2.0 or the Server
+ * Side Public License, v 1.
+ */
+
+import { run } from '../integration_helpers';
+
+it('prints the whole interface, including comments', async () => {
+ const result = await run(`
+ /**
+ * This is an interface
+ */
+ export interface Foo {
+ /**
+ * method
+ */
+ name(): string
+
+ /**
+ * hello
+ */
+ close(): Promise
+ }
+ `);
+
+ expect(result.code).toMatchInlineSnapshot(`
+ "/**
+ * This is an interface
+ */
+ export interface Foo {
+ /**
+ * method
+ */
+ name(): string;
+ /**
+ * hello
+ */
+ close(): Promise;
+ }
+ //# sourceMappingURL=index.d.ts.map"
+ `);
+ expect(result.map).toMatchInlineSnapshot(`
+ Object {
+ "file": "index.d.ts",
+ "mappings": ";;;iBAGiB,G",
+ "names": Array [],
+ "sourceRoot": "../../../src",
+ "sources": Array [
+ "index.ts",
+ ],
+ "version": 3,
+ }
+ `);
+ expect(result.logs).toMatchInlineSnapshot(`
+ "debug loaded sourcemaps for [ 'packages/kbn-type-summarizer/__tmp__/dist_dts/index.d.ts' ]
+ debug Ignoring 5 global declarations for \\"Promise\\"
+ "
+ `);
+});
diff --git a/packages/kbn-type-summarizer/src/tests/integration_tests/references.test.ts b/packages/kbn-type-summarizer/src/tests/integration_tests/references.test.ts
new file mode 100644
index 000000000000..0a2cc9aaf585
--- /dev/null
+++ b/packages/kbn-type-summarizer/src/tests/integration_tests/references.test.ts
@@ -0,0 +1,73 @@
+/*
+ * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
+ * or more contributor license agreements. Licensed under the Elastic License
+ * 2.0 and the Server Side Public License, v 1; you may not use this file except
+ * in compliance with, at your election, the Elastic License 2.0 or the Server
+ * Side Public License, v 1.
+ */
+
+import { run } from '../integration_helpers';
+
+it('collects references from source files which contribute to result', async () => {
+ const result = await run(
+ `
+ ///
+ export type PromiseOfString = Promise<'string'>
+ export * from './files'
+ `,
+ {
+ otherFiles: {
+ 'files/index.ts': `
+ ///
+ export type MySymbol = Symbol & { __tag: 'MySymbol' }
+ export * from './foo'
+ `,
+ 'files/foo.ts': `
+ ///
+ interface Props {}
+ export type MyComponent = React.Component
+ `,
+ },
+ }
+ );
+
+ expect(result.code).toMatchInlineSnapshot(`
+ "///
+ ///
+ ///
+ export type PromiseOfString = Promise<'string'>
+ export type MySymbol = Symbol & {
+ __tag: 'MySymbol';
+ }
+ interface Props {
+ }
+ export type MyComponent = React.Component
+ //# sourceMappingURL=index.d.ts.map"
+ `);
+ expect(result.map).toMatchInlineSnapshot(`
+ Object {
+ "file": "index.d.ts",
+ "mappings": ";;;YACY,e;YCAA,Q;;;UCAF,K;;YACE,W",
+ "names": Array [],
+ "sourceRoot": "../../../src",
+ "sources": Array [
+ "index.ts",
+ "files/index.ts",
+ "files/foo.ts",
+ ],
+ "version": 3,
+ }
+ `);
+ expect(result.logs).toMatchInlineSnapshot(`
+ "debug loaded sourcemaps for [
+ 'packages/kbn-type-summarizer/__tmp__/dist_dts/files/foo.d.ts',
+ 'packages/kbn-type-summarizer/__tmp__/dist_dts/files/index.d.ts',
+ 'packages/kbn-type-summarizer/__tmp__/dist_dts/index.d.ts'
+ ]
+ debug Ignoring 5 global declarations for \\"Promise\\"
+ debug Ignoring 4 global declarations for \\"Symbol\\"
+ debug Ignoring 2 global declarations for \\"Component\\"
+ debug Ignoring 1 global declarations for \\"React\\"
+ "
+ `);
+});
diff --git a/packages/kbn-type-summarizer/src/tests/integration_tests/type_alias.test.ts b/packages/kbn-type-summarizer/src/tests/integration_tests/type_alias.test.ts
new file mode 100644
index 000000000000..cbe99c54ca04
--- /dev/null
+++ b/packages/kbn-type-summarizer/src/tests/integration_tests/type_alias.test.ts
@@ -0,0 +1,42 @@
+/*
+ * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
+ * or more contributor license agreements. Licensed under the Elastic License
+ * 2.0 and the Server Side Public License, v 1; you may not use this file except
+ * in compliance with, at your election, the Elastic License 2.0 or the Server
+ * Side Public License, v 1.
+ */
+
+import { run } from '../integration_helpers';
+
+it('prints basic type alias', async () => {
+ const output = await run(`
+ export type Name = 'foo' | string
+
+ function hello(name: Name) {
+ console.log('hello', name)
+ }
+
+ hello('john')
+ `);
+
+ expect(output.code).toMatchInlineSnapshot(`
+ "export type Name = 'foo' | string
+ //# sourceMappingURL=index.d.ts.map"
+ `);
+ expect(output.map).toMatchInlineSnapshot(`
+ Object {
+ "file": "index.d.ts",
+ "mappings": "YAAY,I",
+ "names": Array [],
+ "sourceRoot": "../../../src",
+ "sources": Array [
+ "index.ts",
+ ],
+ "version": 3,
+ }
+ `);
+ expect(output.logs).toMatchInlineSnapshot(`
+ "debug loaded sourcemaps for [ 'packages/kbn-type-summarizer/__tmp__/dist_dts/index.d.ts' ]
+ "
+ `);
+});
diff --git a/packages/kbn-type-summarizer/src/tests/integration_tests/variables.test.ts b/packages/kbn-type-summarizer/src/tests/integration_tests/variables.test.ts
new file mode 100644
index 000000000000..a2b47d647102
--- /dev/null
+++ b/packages/kbn-type-summarizer/src/tests/integration_tests/variables.test.ts
@@ -0,0 +1,68 @@
+/*
+ * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
+ * or more contributor license agreements. Licensed under the Elastic License
+ * 2.0 and the Server Side Public License, v 1; you may not use this file except
+ * in compliance with, at your election, the Elastic License 2.0 or the Server
+ * Side Public License, v 1.
+ */
+
+import { run } from '../integration_helpers';
+
+it('prints basic variable exports with sourcemaps', async () => {
+ const output = await run(`
+ /**
+ * What is a type
+ */
+ type Type = 'bar' | 'baz'
+
+ /** some comment */
+ export const bar: Type = 'bar'
+
+ export var
+ /**
+ * checkout bar
+ */
+ baz: Type = 'baz',
+ /**
+ * this is foo
+ */
+ foo: Type = 'bar'
+
+ export let types = [bar, baz, foo]
+ `);
+
+ expect(output.code).toMatchInlineSnapshot(`
+ "/**
+ * What is a type
+ */
+ type Type = 'bar' | 'baz'
+ /** some comment */
+ export const bar: Type;
+ /**
+ * checkout bar
+ */
+ export var baz: Type;
+ /**
+ * this is foo
+ */
+ export var foo: Type;
+ export let types: (\\"bar\\" | \\"baz\\")[];
+ //# sourceMappingURL=index.d.ts.map"
+ `);
+ expect(output.map).toMatchInlineSnapshot(`
+ Object {
+ "file": "index.d.ts",
+ "mappings": ";;;KAGK,I;;aAGQ,G;;;;WAMX,G;;;;WAIA,G;WAES,K",
+ "names": Array [],
+ "sourceRoot": "../../../src",
+ "sources": Array [
+ "index.ts",
+ ],
+ "version": 3,
+ }
+ `);
+ expect(output.logs).toMatchInlineSnapshot(`
+ "debug loaded sourcemaps for [ 'packages/kbn-type-summarizer/__tmp__/dist_dts/index.d.ts' ]
+ "
+ `);
+});
diff --git a/packages/kbn-type-summarizer/tsconfig.json b/packages/kbn-type-summarizer/tsconfig.json
new file mode 100644
index 000000000000..b3779bdd686e
--- /dev/null
+++ b/packages/kbn-type-summarizer/tsconfig.json
@@ -0,0 +1,16 @@
+{
+ "extends": "../../tsconfig.bazel.json",
+ "compilerOptions": {
+ "declaration": true,
+ "declarationMap": true,
+ "emitDeclarationOnly": false,
+ "outDir": "target_types",
+ "types": [
+ "jest",
+ "node"
+ ]
+ },
+ "include": [
+ "src/**/*"
+ ]
+}
diff --git a/packages/kbn-utility-types/src/tsd_tests/test_d/method_keys_of.ts b/packages/kbn-utility-types/src/tsd_tests/test_d/method_keys_of.ts
index 8438fd1a41da..816a504b816e 100644
--- a/packages/kbn-utility-types/src/tsd_tests/test_d/method_keys_of.ts
+++ b/packages/kbn-utility-types/src/tsd_tests/test_d/method_keys_of.ts
@@ -6,7 +6,6 @@
* Side Public License, v 1.
*/
-// eslint-disable-next-line import/no-extraneous-dependencies
import { expectType } from 'tsd';
import { MethodKeysOf } from '../..';
diff --git a/packages/kbn-utility-types/src/tsd_tests/test_d/public_contract.ts b/packages/kbn-utility-types/src/tsd_tests/test_d/public_contract.ts
index f0b5507a6f63..b37814255099 100644
--- a/packages/kbn-utility-types/src/tsd_tests/test_d/public_contract.ts
+++ b/packages/kbn-utility-types/src/tsd_tests/test_d/public_contract.ts
@@ -6,7 +6,6 @@
* Side Public License, v 1.
*/
-// eslint-disable-next-line import/no-extraneous-dependencies
import { expectType } from 'tsd';
import { PublicContract } from '../..';
diff --git a/packages/kbn-utility-types/src/tsd_tests/test_d/public_keys.ts b/packages/kbn-utility-types/src/tsd_tests/test_d/public_keys.ts
index 1916c7c0b7a0..7f05b30f4c55 100644
--- a/packages/kbn-utility-types/src/tsd_tests/test_d/public_keys.ts
+++ b/packages/kbn-utility-types/src/tsd_tests/test_d/public_keys.ts
@@ -6,7 +6,6 @@
* Side Public License, v 1.
*/
-// eslint-disable-next-line import/no-extraneous-dependencies
import { expectType } from 'tsd';
import { PublicKeys } from '../..';
diff --git a/packages/kbn-utility-types/src/tsd_tests/test_d/public_methods_of.ts b/packages/kbn-utility-types/src/tsd_tests/test_d/public_methods_of.ts
index fc2626179e7c..d265b86ece78 100644
--- a/packages/kbn-utility-types/src/tsd_tests/test_d/public_methods_of.ts
+++ b/packages/kbn-utility-types/src/tsd_tests/test_d/public_methods_of.ts
@@ -6,7 +6,6 @@
* Side Public License, v 1.
*/
-// eslint-disable-next-line import/no-extraneous-dependencies
import { expectAssignable, expectNotAssignable } from 'tsd';
import { PublicMethodsOf } from '../..';
diff --git a/packages/kbn-utility-types/src/tsd_tests/test_d/shallow_promise.ts b/packages/kbn-utility-types/src/tsd_tests/test_d/shallow_promise.ts
index 4bfd5b1826fb..a77558ae6ce9 100644
--- a/packages/kbn-utility-types/src/tsd_tests/test_d/shallow_promise.ts
+++ b/packages/kbn-utility-types/src/tsd_tests/test_d/shallow_promise.ts
@@ -6,7 +6,6 @@
* Side Public License, v 1.
*/
-// eslint-disable-next-line import/no-extraneous-dependencies
import { expectType } from 'tsd';
import { ShallowPromise } from '../..';
diff --git a/packages/kbn-utility-types/src/tsd_tests/test_d/union_to_intersection.ts b/packages/kbn-utility-types/src/tsd_tests/test_d/union_to_intersection.ts
index 776da8838ef5..057a2d5e3136 100644
--- a/packages/kbn-utility-types/src/tsd_tests/test_d/union_to_intersection.ts
+++ b/packages/kbn-utility-types/src/tsd_tests/test_d/union_to_intersection.ts
@@ -6,7 +6,6 @@
* Side Public License, v 1.
*/
-// eslint-disable-next-line import/no-extraneous-dependencies
import { expectAssignable } from 'tsd';
import { UnionToIntersection } from '../..';
diff --git a/packages/kbn-utility-types/src/tsd_tests/test_d/unwrap_observable.ts b/packages/kbn-utility-types/src/tsd_tests/test_d/unwrap_observable.ts
index 6f76fc7cf40f..5cde15f2ab21 100644
--- a/packages/kbn-utility-types/src/tsd_tests/test_d/unwrap_observable.ts
+++ b/packages/kbn-utility-types/src/tsd_tests/test_d/unwrap_observable.ts
@@ -6,7 +6,6 @@
* Side Public License, v 1.
*/
-// eslint-disable-next-line import/no-extraneous-dependencies
import { expectAssignable } from 'tsd';
import { UnwrapObservable, ObservableLike } from '../..';
diff --git a/packages/kbn-utility-types/src/tsd_tests/test_d/values.ts b/packages/kbn-utility-types/src/tsd_tests/test_d/values.ts
index 5e9e0d73f5b9..4033c22ea73a 100644
--- a/packages/kbn-utility-types/src/tsd_tests/test_d/values.ts
+++ b/packages/kbn-utility-types/src/tsd_tests/test_d/values.ts
@@ -6,7 +6,6 @@
* Side Public License, v 1.
*/
-// eslint-disable-next-line import/no-extraneous-dependencies
import { expectAssignable } from 'tsd';
import { Values } from '../..';
diff --git a/packages/kbn-utility-types/src/tsd_tests/test_d/writable.ts b/packages/kbn-utility-types/src/tsd_tests/test_d/writable.ts
index db3f6460d1b3..8cfb010d0087 100644
--- a/packages/kbn-utility-types/src/tsd_tests/test_d/writable.ts
+++ b/packages/kbn-utility-types/src/tsd_tests/test_d/writable.ts
@@ -6,7 +6,6 @@
* Side Public License, v 1.
*/
-// eslint-disable-next-line import/no-extraneous-dependencies
import { expectAssignable } from 'tsd';
import { Writable } from '../..';
diff --git a/renovate.json b/renovate.json
index 9b673a5a9ccf..0b6ca59edefe 100644
--- a/renovate.json
+++ b/renovate.json
@@ -1,6 +1,6 @@
{
"$schema": "https://docs.renovatebot.com/renovate-schema.json",
- "extends": ["config:base", ":disableDependencyDashboard"],
+ "extends": ["config:base"],
"ignorePaths": ["**/__fixtures__/**", "**/fixtures/**"],
"enabledManagers": ["npm"],
"baseBranches": ["main", "7.16", "7.15"],
diff --git a/scripts/build_type_summarizer_output.js b/scripts/build_type_summarizer_output.js
new file mode 100644
index 000000000000..619c8db5d2d0
--- /dev/null
+++ b/scripts/build_type_summarizer_output.js
@@ -0,0 +1,11 @@
+/*
+ * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
+ * or more contributor license agreements. Licensed under the Elastic License
+ * 2.0 and the Server Side Public License, v 1; you may not use this file except
+ * in compliance with, at your election, the Elastic License 2.0 or the Server
+ * Side Public License, v 1.
+ */
+
+require('../src/setup_node_env/ensure_node_preserve_symlinks');
+require('source-map-support/register');
+require('@kbn/type-summarizer/target_node/bazel_cli');
diff --git a/scripts/functional_tests.js b/scripts/functional_tests.js
index 972c682ab0d9..b185bcb0ea5d 100644
--- a/scripts/functional_tests.js
+++ b/scripts/functional_tests.js
@@ -9,7 +9,7 @@
require('../src/setup_node_env');
require('@kbn/test').runTestsCli([
require.resolve('../test/functional/config.js'),
- require.resolve('../test/functional_ccs/config.js'),
+ require.resolve('../test/functional_ccs/config.ts'),
require.resolve('../test/plugin_functional/config.ts'),
require.resolve('../test/ui_capabilities/newsfeed_err/config.ts'),
require.resolve('../test/new_visualize_flow/config.ts'),
diff --git a/scripts/generate.js b/scripts/generate.js
new file mode 100644
index 000000000000..29774e8088d6
--- /dev/null
+++ b/scripts/generate.js
@@ -0,0 +1,11 @@
+/*
+ * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
+ * or more contributor license agreements. Licensed under the Elastic License
+ * 2.0 and the Server Side Public License, v 1; you may not use this file except
+ * in compliance with, at your election, the Elastic License 2.0 or the Server
+ * Side Public License, v 1.
+ */
+
+require('../src/setup_node_env/ensure_node_preserve_symlinks');
+require('source-map-support/register');
+require('@kbn/generate').runGenerateCli();
diff --git a/scripts/update_vscode_config.js b/scripts/update_vscode_config.js
index 10ed9fa200b7..d39e4ce757ce 100644
--- a/scripts/update_vscode_config.js
+++ b/scripts/update_vscode_config.js
@@ -6,5 +6,5 @@
* Side Public License, v 1.
*/
-require('../src/setup_node_env');
+require('../src/setup_node_env/no_transpilation');
require('@kbn/dev-utils').runUpdateVscodeConfigCli();
diff --git a/src/core/public/apm_system.test.ts b/src/core/public/apm_system.test.ts
index 842d5de7e5af..0a3a1dee63e5 100644
--- a/src/core/public/apm_system.test.ts
+++ b/src/core/public/apm_system.test.ts
@@ -13,6 +13,7 @@ import type { Transaction } from '@elastic/apm-rum';
import { ApmSystem } from './apm_system';
import { Subject } from 'rxjs';
import { InternalApplicationStart } from './application/types';
+import { executionContextServiceMock } from './execution_context/execution_context_service.mock';
const initMock = init as jest.Mocked;
const apmMock = apm as DeeplyMockedKeys;
@@ -96,6 +97,7 @@ describe('ApmSystem', () => {
application: {
currentAppId$,
} as any as InternalApplicationStart,
+ executionContext: executionContextServiceMock.createInternalStartContract(),
});
expect(mark).toHaveBeenCalledWith('apm-start');
@@ -118,6 +120,7 @@ describe('ApmSystem', () => {
application: {
currentAppId$,
} as any as InternalApplicationStart,
+ executionContext: executionContextServiceMock.createInternalStartContract(),
});
currentAppId$.next('myapp');
@@ -145,6 +148,7 @@ describe('ApmSystem', () => {
application: {
currentAppId$,
} as any as InternalApplicationStart,
+ executionContext: executionContextServiceMock.createInternalStartContract(),
});
currentAppId$.next('myapp');
diff --git a/src/core/public/apm_system.ts b/src/core/public/apm_system.ts
index 2231f394381f..4e116c0a0182 100644
--- a/src/core/public/apm_system.ts
+++ b/src/core/public/apm_system.ts
@@ -10,6 +10,7 @@ import type { ApmBase, AgentConfigOptions, Transaction } from '@elastic/apm-rum'
import { modifyUrl } from '@kbn/std';
import { CachedResourceObserver } from './apm_resource_counter';
import type { InternalApplicationStart } from './application';
+import { ExecutionContextStart } from './execution_context';
/** "GET protocol://hostname:port/pathname" */
const HTTP_REQUEST_TRANSACTION_NAME_REGEX =
@@ -27,6 +28,7 @@ interface ApmConfig extends AgentConfigOptions {
interface StartDeps {
application: InternalApplicationStart;
+ executionContext: ExecutionContextStart;
}
export class ApmSystem {
@@ -34,6 +36,7 @@ export class ApmSystem {
private pageLoadTransaction?: Transaction;
private resourceObserver: CachedResourceObserver;
private apm?: ApmBase;
+
/**
* `apmConfig` would be populated with relevant APM RUM agent
* configuration if server is started with elastic.apm.* config.
@@ -64,6 +67,15 @@ export class ApmSystem {
this.markPageLoadStart();
+ start.executionContext.context$.subscribe((c) => {
+ // We're using labels because we want the context to be indexed
+ // https://www.elastic.co/guide/en/apm/get-started/current/metadata.html
+ const apmContext = start.executionContext.getAsLabels();
+ this.apm?.addLabels(apmContext);
+ });
+
+ // TODO: Start a new transaction every page change instead of every app change.
+
/**
* Register listeners for navigation changes and capture them as
* route-change transactions after Kibana app is bootstrapped
diff --git a/src/core/public/core_system.ts b/src/core/public/core_system.ts
index 3d3331d54792..1aa01c13dd37 100644
--- a/src/core/public/core_system.ts
+++ b/src/core/public/core_system.ts
@@ -31,6 +31,7 @@ import { DeprecationsService } from './deprecations';
import { ThemeService } from './theme';
import { CoreApp } from './core_app';
import type { InternalApplicationSetup, InternalApplicationStart } from './application/types';
+import { ExecutionContextService } from './execution_context';
interface Params {
rootDomElement: HTMLElement;
@@ -87,6 +88,7 @@ export class CoreSystem {
private readonly theme: ThemeService;
private readonly rootDomElement: HTMLElement;
private readonly coreContext: CoreContext;
+ private readonly executionContext: ExecutionContextService;
private fatalErrorsSetup: FatalErrorsSetup | null = null;
constructor(params: Params) {
@@ -121,6 +123,7 @@ export class CoreSystem {
this.application = new ApplicationService();
this.integrations = new IntegrationsService();
this.deprecations = new DeprecationsService();
+ this.executionContext = new ExecutionContextService();
this.plugins = new PluginsService(this.coreContext, injectedMetadata.uiPlugins);
this.coreApp = new CoreApp(this.coreContext);
@@ -137,7 +140,13 @@ export class CoreSystem {
});
await this.integrations.setup();
this.docLinks.setup();
- const http = this.http.setup({ injectedMetadata, fatalErrors: this.fatalErrorsSetup });
+
+ const executionContext = this.executionContext.setup();
+ const http = this.http.setup({
+ injectedMetadata,
+ fatalErrors: this.fatalErrorsSetup,
+ executionContext,
+ });
const uiSettings = this.uiSettings.setup({ http, injectedMetadata });
const notifications = this.notifications.setup({ uiSettings });
const theme = this.theme.setup({ injectedMetadata });
@@ -153,6 +162,7 @@ export class CoreSystem {
notifications,
theme,
uiSettings,
+ executionContext,
};
// Services that do not expose contracts at setup
@@ -201,6 +211,11 @@ export class CoreSystem {
targetDomElement: notificationsTargetDomElement,
});
const application = await this.application.start({ http, theme, overlays });
+
+ const executionContext = this.executionContext.start({
+ curApp$: application.currentAppId$,
+ });
+
const chrome = await this.chrome.start({
application,
docLinks,
@@ -216,6 +231,7 @@ export class CoreSystem {
application,
chrome,
docLinks,
+ executionContext,
http,
theme,
savedObjects,
@@ -248,6 +264,7 @@ export class CoreSystem {
return {
application,
+ executionContext,
};
} catch (error) {
if (this.fatalErrorsSetup) {
diff --git a/src/core/public/execution_context/execution_context_service.mock.ts b/src/core/public/execution_context/execution_context_service.mock.ts
new file mode 100644
index 000000000000..3941aa333cfa
--- /dev/null
+++ b/src/core/public/execution_context/execution_context_service.mock.ts
@@ -0,0 +1,35 @@
+/*
+ * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
+ * or more contributor license agreements. Licensed under the Elastic License
+ * 2.0 and the Server Side Public License, v 1; you may not use this file except
+ * in compliance with, at your election, the Elastic License 2.0 or the Server
+ * Side Public License, v 1.
+ */
+
+import { PublicMethodsOf } from '@kbn/utility-types';
+import { BehaviorSubject } from 'rxjs';
+
+import { ExecutionContextService, ExecutionContextSetup } from './execution_context_service';
+
+const createContractMock = (): jest.Mocked => ({
+ context$: new BehaviorSubject({}),
+ clear: jest.fn(),
+ set: jest.fn(),
+ get: jest.fn(),
+ getAsLabels: jest.fn(),
+ withGlobalContext: jest.fn(),
+});
+
+const createMock = (): jest.Mocked> => ({
+ setup: jest.fn().mockReturnValue(createContractMock()),
+ start: jest.fn().mockReturnValue(createContractMock()),
+ stop: jest.fn(),
+});
+
+export const executionContextServiceMock = {
+ create: createMock,
+ createSetupContract: createContractMock,
+ createStartContract: createContractMock,
+ createInternalSetupContract: createContractMock,
+ createInternalStartContract: createContractMock,
+};
diff --git a/src/core/public/execution_context/execution_context_service.test.ts b/src/core/public/execution_context/execution_context_service.test.ts
new file mode 100644
index 000000000000..70e57b8993bb
--- /dev/null
+++ b/src/core/public/execution_context/execution_context_service.test.ts
@@ -0,0 +1,205 @@
+/*
+ * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
+ * or more contributor license agreements. Licensed under the Elastic License
+ * 2.0 and the Server Side Public License, v 1; you may not use this file except
+ * in compliance with, at your election, the Elastic License 2.0 or the Server
+ * Side Public License, v 1.
+ */
+import { BehaviorSubject } from 'rxjs';
+import { ExecutionContextService, ExecutionContextSetup } from './execution_context_service';
+
+describe('ExecutionContextService', () => {
+ let execContext: ExecutionContextSetup;
+ let curApp$: BehaviorSubject;
+ let execService: ExecutionContextService;
+
+ beforeEach(() => {
+ execService = new ExecutionContextService();
+ execContext = execService.setup();
+ curApp$ = new BehaviorSubject('app1');
+ execContext = execService.start({
+ curApp$,
+ });
+ });
+
+ it('app name updates automatically and clears everything else', () => {
+ execContext.set({
+ type: 'ghf',
+ description: 'first set',
+ });
+
+ expect(execContext.get()).toStrictEqual({
+ name: 'app1',
+ description: 'first set',
+ type: 'ghf',
+ url: '/',
+ });
+
+ curApp$.next('app2');
+
+ expect(execContext.get()).toStrictEqual({
+ name: 'app2',
+ url: '/',
+ });
+ });
+
+ it('sets context and adds current url and appid when getting it', () => {
+ execContext.set({
+ type: 'ghf',
+ description: 'first set',
+ });
+
+ expect(execContext.get()).toStrictEqual({
+ name: 'app1',
+ description: 'first set',
+ type: 'ghf',
+ url: '/',
+ });
+ });
+
+ it('merges context between calls and gets it', () => {
+ execContext.set({
+ type: 'ghf',
+ description: 'first set',
+ });
+
+ execContext.set({
+ type: 'ghf',
+ description: 'second set',
+ });
+
+ expect(execContext.get()).toStrictEqual({
+ name: 'app1',
+ type: 'ghf',
+ description: 'second set',
+ url: '/',
+ });
+ });
+
+ it('context observable fires the context each time it changes', () => {
+ const sub = jest.fn();
+
+ execContext.set({
+ type: 'ghf',
+ description: 'first set',
+ });
+
+ execContext.context$.subscribe(sub);
+
+ expect(sub).toHaveBeenCalledWith({
+ name: 'app1',
+ type: 'ghf',
+ description: 'first set',
+ url: '/',
+ });
+
+ execContext.set({
+ type: 'str',
+ description: 'first set',
+ });
+
+ expect(sub).toHaveBeenCalledWith({
+ name: 'app1',
+ type: 'str',
+ description: 'first set',
+ url: '/',
+ });
+
+ expect(sub).toHaveBeenCalledTimes(2);
+ });
+
+ it('context observable doesnt fires if the context did not change', () => {
+ const sub = jest.fn();
+
+ execContext.set({
+ type: 'ghf',
+ description: 'first set',
+ });
+
+ execContext.context$.subscribe(sub);
+
+ execContext.set({
+ type: 'ghf',
+ });
+
+ expect(sub).toHaveBeenCalledWith({
+ name: 'app1',
+ type: 'ghf',
+ description: 'first set',
+ url: '/',
+ });
+
+ expect(sub).toHaveBeenCalledTimes(1);
+ });
+
+ it('clear resets context and triggers context observable', () => {
+ const sub = jest.fn();
+
+ execContext.set({
+ type: 'ghf',
+ description: 'first set',
+ });
+ execContext.context$.subscribe(sub);
+
+ execContext.clear();
+ expect(sub).toHaveBeenCalledWith({
+ name: 'app1',
+ url: '/',
+ });
+
+ // Clear triggers the observable
+ expect(sub).toHaveBeenCalledTimes(2);
+ });
+
+ it('getAsLabels return relevant values', () => {
+ execContext.set({
+ type: 'ghf',
+ description: 'first set',
+ page: 'mypage',
+ child: {
+ description: 'inner',
+ },
+ id: '123',
+ });
+
+ expect(execContext.getAsLabels()).toStrictEqual({
+ name: 'app1',
+ page: 'mypage',
+ id: '123',
+ });
+ });
+
+ it('getAsLabels removes undefined values', () => {
+ execContext.set({
+ type: 'ghf',
+ description: 'first set',
+ page: 'mypage',
+ id: undefined,
+ });
+
+ expect(execContext.get()).toStrictEqual({
+ name: 'app1',
+ type: 'ghf',
+ page: 'mypage',
+ url: '/',
+ description: 'first set',
+ id: undefined,
+ });
+
+ expect(execContext.getAsLabels()).toStrictEqual({
+ name: 'app1',
+ page: 'mypage',
+ });
+ });
+
+ it('stop clears subscriptions', () => {
+ const sub = jest.fn();
+ execContext.context$.subscribe(sub);
+ sub.mockReset();
+
+ execService.stop();
+ curApp$.next('abc');
+
+ expect(sub).not.toHaveBeenCalled();
+ });
+});
diff --git a/src/core/public/execution_context/execution_context_service.ts b/src/core/public/execution_context/execution_context_service.ts
new file mode 100644
index 000000000000..a14d876c9643
--- /dev/null
+++ b/src/core/public/execution_context/execution_context_service.ts
@@ -0,0 +1,137 @@
+/*
+ * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
+ * or more contributor license agreements. Licensed under the Elastic License
+ * 2.0 and the Server Side Public License, v 1; you may not use this file except
+ * in compliance with, at your election, the Elastic License 2.0 or the Server
+ * Side Public License, v 1.
+ */
+
+import { isEqual, isUndefined, omitBy } from 'lodash';
+import { BehaviorSubject, Observable, Subscription } from 'rxjs';
+import { CoreService, KibanaExecutionContext } from '../../types';
+
+// Should be exported from elastic/apm-rum
+export type LabelValue = string | number | boolean;
+
+export interface Labels {
+ [key: string]: LabelValue;
+}
+
+/**
+ * Kibana execution context.
+ * Used to provide execution context to Elasticsearch, reporting, performance monitoring, etc.
+ * @public
+ **/
+export interface ExecutionContextSetup {
+ /**
+ * The current context observable
+ **/
+ context$: Observable;
+ /**
+ * Set the current top level context
+ **/
+ set(c$: KibanaExecutionContext): void;
+ /**
+ * Get the current top level context
+ **/
+ get(): KibanaExecutionContext;
+ /**
+ * clears the context
+ **/
+ clear(): void;
+ /**
+ * returns apm labels
+ **/
+ getAsLabels(): Labels;
+ /**
+ * merges the current top level context with the specific event context
+ **/
+ withGlobalContext(context?: KibanaExecutionContext): KibanaExecutionContext;
+}
+
+/**
+ * See {@link ExecutionContextSetup}.
+ * @public
+ */
+export type ExecutionContextStart = ExecutionContextSetup;
+
+export interface StartDeps {
+ curApp$: Observable;
+}
+
+/** @internal */
+export class ExecutionContextService
+ implements CoreService
+{
+ private context$: BehaviorSubject = new BehaviorSubject({});
+ private appId?: string;
+ private subscription: Subscription = new Subscription();
+ private contract?: ExecutionContextSetup;
+
+ public setup() {
+ this.contract = {
+ context$: this.context$.asObservable(),
+ clear: () => {
+ this.context$.next(this.getDefaultContext());
+ },
+ set: (c: KibanaExecutionContext) => {
+ const newVal = this.mergeContext(c);
+ if (!isEqual(newVal, this.context$.value)) {
+ this.context$.next(newVal);
+ }
+ },
+ get: () => {
+ return this.mergeContext();
+ },
+ getAsLabels: () => {
+ return this.removeUndefined({
+ name: this.appId,
+ id: this.context$.value?.id,
+ page: this.context$.value?.page,
+ }) as Labels;
+ },
+ withGlobalContext: (context: KibanaExecutionContext) => {
+ return this.mergeContext(context);
+ },
+ };
+
+ return this.contract;
+ }
+
+ public start({ curApp$ }: StartDeps) {
+ const start = this.contract!;
+
+ // Track app id changes and clear context on app change
+ this.subscription.add(
+ curApp$.subscribe((appId) => {
+ this.appId = appId;
+ start.clear();
+ })
+ );
+
+ return start;
+ }
+
+ public stop() {
+ this.subscription.unsubscribe();
+ }
+
+ private removeUndefined(context: KibanaExecutionContext = {}) {
+ return omitBy(context, isUndefined);
+ }
+
+ private getDefaultContext() {
+ return {
+ name: this.appId,
+ url: window.location.pathname,
+ };
+ }
+
+ private mergeContext(context: KibanaExecutionContext = {}): KibanaExecutionContext {
+ return {
+ ...this.getDefaultContext(),
+ ...this.context$.value,
+ ...context,
+ };
+ }
+}
diff --git a/src/core/public/execution_context/index.ts b/src/core/public/execution_context/index.ts
index b15a967ac714..f160b0ecea67 100644
--- a/src/core/public/execution_context/index.ts
+++ b/src/core/public/execution_context/index.ts
@@ -8,3 +8,5 @@
export type { KibanaExecutionContext } from '../../types';
export { ExecutionContextContainer } from './execution_context_container';
+export { ExecutionContextService } from './execution_context_service';
+export type { ExecutionContextSetup, ExecutionContextStart } from './execution_context_service';
diff --git a/src/core/public/http/fetch.test.ts b/src/core/public/http/fetch.test.ts
index e897d69057e0..0691e2443c17 100644
--- a/src/core/public/http/fetch.test.ts
+++ b/src/core/public/http/fetch.test.ts
@@ -15,6 +15,7 @@ import { first } from 'rxjs/operators';
import { Fetch } from './fetch';
import { BasePath } from './base_path';
import { HttpResponse, HttpFetchOptionsWithPath } from './types';
+import { executionContextServiceMock } from '../execution_context/execution_context_service.mock';
function delay(duration: number) {
return new Promise((r) => setTimeout(r, duration));
@@ -23,9 +24,11 @@ function delay(duration: number) {
const BASE_PATH = 'http://localhost/myBase';
describe('Fetch', () => {
+ const executionContextMock = executionContextServiceMock.createSetupContract();
const fetchInstance = new Fetch({
basePath: new BasePath(BASE_PATH),
kibanaVersion: 'VERSION',
+ executionContext: executionContextMock,
});
afterEach(() => {
fetchMock.restore();
@@ -230,13 +233,15 @@ describe('Fetch', () => {
it('should inject context headers if provided', async () => {
fetchMock.get('*', {});
+ const context = {
+ type: 'test-type',
+ name: 'test-name',
+ description: 'test-description',
+ id: '42',
+ };
+ executionContextMock.withGlobalContext.mockReturnValue(context);
await fetchInstance.fetch('/my/path', {
- context: {
- type: 'test-type',
- name: 'test-name',
- description: 'test-description',
- id: '42',
- },
+ context,
});
expect(fetchMock.lastOptions()!.headers).toMatchObject({
@@ -245,6 +250,29 @@ describe('Fetch', () => {
});
});
+ it('should include top level context context headers if provided', async () => {
+ fetchMock.get('*', {});
+
+ const context = {
+ type: 'test-type',
+ name: 'test-name',
+ description: 'test-description',
+ id: '42',
+ };
+ executionContextMock.withGlobalContext.mockReturnValue({
+ ...context,
+ name: 'banana',
+ });
+ await fetchInstance.fetch('/my/path', {
+ context,
+ });
+
+ expect(fetchMock.lastOptions()!.headers).toMatchObject({
+ 'x-kbn-context':
+ '%7B%22type%22%3A%22test-type%22%2C%22name%22%3A%22banana%22%2C%22description%22%3A%22test-description%22%2C%22id%22%3A%2242%22%7D',
+ });
+ });
+
it('should return response', async () => {
fetchMock.get('*', { foo: 'bar' });
const json = await fetchInstance.fetch('/my/path');
diff --git a/src/core/public/http/fetch.ts b/src/core/public/http/fetch.ts
index 4ee81f4b47aa..9a333161e1b7 100644
--- a/src/core/public/http/fetch.ts
+++ b/src/core/public/http/fetch.ts
@@ -6,7 +6,7 @@
* Side Public License, v 1.
*/
-import { omitBy } from 'lodash';
+import { isEmpty, omitBy } from 'lodash';
import { format } from 'url';
import { BehaviorSubject } from 'rxjs';
@@ -22,11 +22,12 @@ import { HttpFetchError } from './http_fetch_error';
import { HttpInterceptController } from './http_intercept_controller';
import { interceptRequest, interceptResponse } from './intercept';
import { HttpInterceptHaltError } from './http_intercept_halt_error';
-import { ExecutionContextContainer } from '../execution_context';
+import { ExecutionContextContainer, ExecutionContextSetup } from '../execution_context';
interface Params {
basePath: IBasePath;
kibanaVersion: string;
+ executionContext: ExecutionContextSetup;
}
const JSON_CONTENT = /^(application\/(json|x-javascript)|text\/(x-)?javascript|x-json)(;.*)?$/;
@@ -107,6 +108,7 @@ export class Fetch {
};
private createRequest(options: HttpFetchOptionsWithPath): Request {
+ const context = this.params.executionContext.withGlobalContext(options.context);
// Merge and destructure options out that are not applicable to the Fetch API.
const {
query,
@@ -125,7 +127,7 @@ export class Fetch {
'Content-Type': 'application/json',
...options.headers,
'kbn-version': this.params.kibanaVersion,
- ...(options.context ? new ExecutionContextContainer(options.context).toHeader() : {}),
+ ...(!isEmpty(context) ? new ExecutionContextContainer(context).toHeader() : {}),
}),
};
diff --git a/src/core/public/http/http_service.test.ts b/src/core/public/http/http_service.test.ts
index 2b41991904d9..698fa876433d 100644
--- a/src/core/public/http/http_service.test.ts
+++ b/src/core/public/http/http_service.test.ts
@@ -14,6 +14,7 @@ import { fatalErrorsServiceMock } from '../fatal_errors/fatal_errors_service.moc
import { injectedMetadataServiceMock } from '../injected_metadata/injected_metadata_service.mock';
import { HttpService } from './http_service';
import { Observable } from 'rxjs';
+import { executionContextServiceMock } from '../execution_context/execution_context_service.mock';
describe('interceptors', () => {
afterEach(() => fetchMock.restore());
@@ -22,9 +23,10 @@ describe('interceptors', () => {
fetchMock.get('*', {});
const injectedMetadata = injectedMetadataServiceMock.createSetupContract();
const fatalErrors = fatalErrorsServiceMock.createSetupContract();
+ const executionContext = executionContextServiceMock.createSetupContract();
const httpService = new HttpService();
- const setup = httpService.setup({ fatalErrors, injectedMetadata });
+ const setup = httpService.setup({ fatalErrors, injectedMetadata, executionContext });
const setupInterceptor = jest.fn();
setup.intercept({ request: setupInterceptor });
@@ -47,7 +49,8 @@ describe('#setup()', () => {
const injectedMetadata = injectedMetadataServiceMock.createSetupContract();
const fatalErrors = fatalErrorsServiceMock.createSetupContract();
const httpService = new HttpService();
- httpService.setup({ fatalErrors, injectedMetadata });
+ const executionContext = executionContextServiceMock.createSetupContract();
+ httpService.setup({ fatalErrors, injectedMetadata, executionContext });
const loadingServiceSetup = loadingServiceMock.setup.mock.results[0].value;
// We don't verify that this Observable comes from Fetch#getLoadingCount$() to avoid complex mocking
expect(loadingServiceSetup.addLoadingCountSource).toHaveBeenCalledWith(expect.any(Observable));
@@ -59,7 +62,8 @@ describe('#stop()', () => {
const injectedMetadata = injectedMetadataServiceMock.createSetupContract();
const fatalErrors = fatalErrorsServiceMock.createSetupContract();
const httpService = new HttpService();
- httpService.setup({ fatalErrors, injectedMetadata });
+ const executionContext = executionContextServiceMock.createSetupContract();
+ httpService.setup({ fatalErrors, injectedMetadata, executionContext });
httpService.start();
httpService.stop();
expect(loadingServiceMock.stop).toHaveBeenCalled();
diff --git a/src/core/public/http/http_service.ts b/src/core/public/http/http_service.ts
index a9719cfce67a..390130da4e07 100644
--- a/src/core/public/http/http_service.ts
+++ b/src/core/public/http/http_service.ts
@@ -15,10 +15,12 @@ import { LoadingCountService } from './loading_count_service';
import { Fetch } from './fetch';
import { CoreService } from '../../types';
import { ExternalUrlService } from './external_url_service';
+import { ExecutionContextSetup } from '../execution_context';
interface HttpDeps {
injectedMetadata: InjectedMetadataSetup;
fatalErrors: FatalErrorsSetup;
+ executionContext: ExecutionContextSetup;
}
/** @internal */
@@ -27,14 +29,15 @@ export class HttpService implements CoreService {
private readonly loadingCount = new LoadingCountService();
private service?: HttpSetup;
- public setup({ injectedMetadata, fatalErrors }: HttpDeps): HttpSetup {
+ public setup({ injectedMetadata, fatalErrors, executionContext }: HttpDeps): HttpSetup {
const kibanaVersion = injectedMetadata.getKibanaVersion();
const basePath = new BasePath(
injectedMetadata.getBasePath(),
injectedMetadata.getServerBasePath(),
injectedMetadata.getPublicBaseUrl()
);
- const fetchService = new Fetch({ basePath, kibanaVersion });
+
+ const fetchService = new Fetch({ basePath, kibanaVersion, executionContext });
const loadingCount = this.loadingCount.setup({ fatalErrors });
loadingCount.addLoadingCountSource(fetchService.getRequestCount$());
diff --git a/src/core/public/index.ts b/src/core/public/index.ts
index ded7db9c6f89..902f93d108aa 100644
--- a/src/core/public/index.ts
+++ b/src/core/public/index.ts
@@ -52,19 +52,14 @@ import { HttpSetup, HttpStart } from './http';
import { I18nStart } from './i18n';
import { NotificationsSetup, NotificationsStart } from './notifications';
import { OverlayStart } from './overlays';
-import {
- Plugin,
- AsyncPlugin,
- PluginInitializer,
- PluginInitializerContext,
- PluginOpaqueId,
-} from './plugins';
+import { Plugin, PluginInitializer, PluginInitializerContext, PluginOpaqueId } from './plugins';
import { UiSettingsState, IUiSettingsClient } from './ui_settings';
import { ApplicationSetup, Capabilities, ApplicationStart } from './application';
import { DocLinksStart } from './doc_links';
import { SavedObjectsStart } from './saved_objects';
import { DeprecationsServiceStart } from './deprecations';
import type { ThemeServiceSetup, ThemeServiceStart } from './theme';
+import { ExecutionContextSetup, ExecutionContextStart } from './execution_context';
export type {
PackageInfo,
@@ -194,7 +189,11 @@ export type { MountPoint, UnmountCallback, PublicUiSettingsParams } from './type
export { URL_MAX_LENGTH } from './core_app';
-export type { KibanaExecutionContext } from './execution_context';
+export type {
+ KibanaExecutionContext,
+ ExecutionContextSetup,
+ ExecutionContextStart,
+} from './execution_context';
/**
* Core services exposed to the `Plugin` setup lifecycle
@@ -221,6 +220,8 @@ export interface CoreSetup, any, any]>, []>(() =>
Promise.resolve([createCoreStartMock({ basePath }), pluginStartDeps, pluginStartContract])
@@ -76,6 +78,7 @@ function createCoreStartMock({ basePath = '' } = {}) {
application: applicationServiceMock.createStartContract(),
chrome: chromeServiceMock.createStartContract(),
docLinks: docLinksServiceMock.createStartContract(),
+ executionContext: executionContextServiceMock.createStartContract(),
http: httpServiceMock.createStartContract({ basePath }),
i18n: i18nServiceMock.createStartContract(),
notifications: notificationServiceMock.createStartContract(),
diff --git a/src/core/public/plugins/index.ts b/src/core/public/plugins/index.ts
index 9d7a61ef47a0..976ec660ac9b 100644
--- a/src/core/public/plugins/index.ts
+++ b/src/core/public/plugins/index.ts
@@ -7,6 +7,6 @@
*/
export { PluginsService } from './plugins_service';
-export type { Plugin, AsyncPlugin, PluginInitializer } from './plugin';
+export type { Plugin, PluginInitializer } from './plugin';
export type { PluginInitializerContext } from './plugin_context';
export type { PluginOpaqueId } from '../../server/types';
diff --git a/src/core/public/plugins/plugin.test.ts b/src/core/public/plugins/plugin.test.ts
index 8deef6ac9f72..2c3bfc6961fb 100644
--- a/src/core/public/plugins/plugin.test.ts
+++ b/src/core/public/plugins/plugin.test.ts
@@ -94,9 +94,7 @@ describe('PluginWrapper', () => {
mockPluginReader.mockReturnValueOnce(
jest.fn(() => ({
setup: jest.fn(),
- start: jest.fn(async () => {
- // Add small delay to ensure startDependencies is not resolved until after the plugin instance's start resolves.
- await new Promise((resolve) => setTimeout(resolve, 10));
+ start: jest.fn(() => {
expect(startDependenciesResolved).toBe(false);
return pluginStartContract;
}),
diff --git a/src/core/public/plugins/plugin.ts b/src/core/public/plugins/plugin.ts
index a08a6cf0b431..a43cc2046b82 100644
--- a/src/core/public/plugins/plugin.ts
+++ b/src/core/public/plugins/plugin.ts
@@ -8,7 +8,6 @@
import { Subject } from 'rxjs';
import { first } from 'rxjs/operators';
-import { isPromise } from '@kbn/std';
import { DiscoveredPlugin, PluginOpaqueId } from '../../server';
import { PluginInitializerContext } from './plugin_context';
import { read } from './plugin_reader';
@@ -30,23 +29,6 @@ export interface Plugin<
stop?(): void;
}
-/**
- * A plugin with asynchronous lifecycle methods.
- *
- * @deprecated Asynchronous lifecycles are deprecated, and should be migrated to sync {@link Plugin | plugin}
- * @public
- */
-export interface AsyncPlugin<
- TSetup = void,
- TStart = void,
- TPluginsSetup extends object = object,
- TPluginsStart extends object = object
-> {
- setup(core: CoreSetup, plugins: TPluginsSetup): TSetup | Promise;
- start(core: CoreStart, plugins: TPluginsStart): TStart | Promise;
- stop?(): void;
-}
-
/**
* The `plugin` export at the root of a plugin's `public` directory should conform
* to this interface.
@@ -58,11 +40,7 @@ export type PluginInitializer<
TStart,
TPluginsSetup extends object = object,
TPluginsStart extends object = object
-> = (
- core: PluginInitializerContext
-) =>
- | Plugin
- | AsyncPlugin;
+> = (core: PluginInitializerContext) => Plugin;
/**
* Lightweight wrapper around discovered plugin that is responsible for instantiating
@@ -80,9 +58,7 @@ export class PluginWrapper<
public readonly configPath: DiscoveredPlugin['configPath'];
public readonly requiredPlugins: DiscoveredPlugin['requiredPlugins'];
public readonly optionalPlugins: DiscoveredPlugin['optionalPlugins'];
- private instance?:
- | Plugin
- | AsyncPlugin;
+ private instance?: Plugin;
private readonly startDependencies$ = new Subject<[CoreStart, TPluginsStart, TStart]>();
public readonly startDependencies = this.startDependencies$.pipe(first()).toPromise();
@@ -105,10 +81,7 @@ export class PluginWrapper<
* @param plugins The dictionary where the key is the dependency name and the value
* is the contract returned by the dependency's `setup` function.
*/
- public setup(
- setupContext: CoreSetup,
- plugins: TPluginsSetup
- ): TSetup | Promise {
+ public setup(setupContext: CoreSetup, plugins: TPluginsSetup): TSetup {
this.instance = this.createPluginInstance();
return this.instance.setup(setupContext, plugins);
}
@@ -126,15 +99,8 @@ export class PluginWrapper<
}
const startContract = this.instance.start(startContext, plugins);
- if (isPromise(startContract)) {
- return startContract.then((resolvedContract) => {
- this.startDependencies$.next([startContext, plugins, resolvedContract]);
- return resolvedContract;
- });
- } else {
- this.startDependencies$.next([startContext, plugins, startContract]);
- return startContract;
- }
+ this.startDependencies$.next([startContext, plugins, startContract]);
+ return startContract;
}
/**
diff --git a/src/core/public/plugins/plugin_context.ts b/src/core/public/plugins/plugin_context.ts
index 345aea4b6cac..8c085d3de236 100644
--- a/src/core/public/plugins/plugin_context.ts
+++ b/src/core/public/plugins/plugin_context.ts
@@ -88,6 +88,7 @@ export function createPluginSetupContext<
registerAppUpdater: (statusUpdater$) => deps.application.registerAppUpdater(statusUpdater$),
},
fatalErrors: deps.fatalErrors,
+ executionContext: deps.executionContext,
http: deps.http,
notifications: deps.notifications,
uiSettings: deps.uiSettings,
@@ -129,6 +130,7 @@ export function createPluginStartContext<
getUrlForApp: deps.application.getUrlForApp,
},
docLinks: deps.docLinks,
+ executionContext: deps.executionContext,
http: deps.http,
chrome: omit(deps.chrome, 'getComponent'),
i18n: deps.i18n,
diff --git a/src/core/public/plugins/plugins_service.test.mocks.ts b/src/core/public/plugins/plugins_service.test.mocks.ts
index 1858008e2801..801ea20015f2 100644
--- a/src/core/public/plugins/plugins_service.test.mocks.ts
+++ b/src/core/public/plugins/plugins_service.test.mocks.ts
@@ -7,12 +7,9 @@
*/
import { PluginName } from 'kibana/server';
-import { Plugin, AsyncPlugin } from './plugin';
+import { Plugin } from './plugin';
-export type MockedPluginInitializer = jest.Mock<
- Plugin | AsyncPlugin,
- any
->;
+export type MockedPluginInitializer = jest.Mock>;
export const mockPluginInitializerProvider: jest.Mock = jest
.fn()
diff --git a/src/core/public/plugins/plugins_service.test.ts b/src/core/public/plugins/plugins_service.test.ts
index c4e3b7990ba3..390cba409257 100644
--- a/src/core/public/plugins/plugins_service.test.ts
+++ b/src/core/public/plugins/plugins_service.test.ts
@@ -36,6 +36,7 @@ import { docLinksServiceMock } from '../doc_links/doc_links_service.mock';
import { savedObjectsServiceMock } from '../saved_objects/saved_objects_service.mock';
import { deprecationsServiceMock } from '../deprecations/deprecations_service.mock';
import { themeServiceMock } from '../theme/theme_service.mock';
+import { executionContextServiceMock } from '../execution_context/execution_context_service.mock';
export let mockPluginInitializers: Map;
@@ -85,6 +86,7 @@ describe('PluginsService', () => {
mockSetupDeps = {
application: applicationServiceMock.createInternalSetupContract(),
fatalErrors: fatalErrorsServiceMock.createSetupContract(),
+ executionContext: executionContextServiceMock.createSetupContract(),
http: httpServiceMock.createSetupContract(),
injectedMetadata: injectedMetadataServiceMock.createStartContract(),
notifications: notificationServiceMock.createSetupContract(),
@@ -100,6 +102,7 @@ describe('PluginsService', () => {
mockStartDeps = {
application: applicationServiceMock.createInternalStartContract(),
docLinks: docLinksServiceMock.createStartContract(),
+ executionContext: executionContextServiceMock.createStartContract(),
http: httpServiceMock.createStartContract(),
chrome: chromeServiceMock.createStartContract(),
i18n: i18nServiceMock.createStartContract(),
@@ -248,36 +251,6 @@ describe('PluginsService', () => {
expect((contracts.get('pluginA')! as any).setupValue).toEqual(1);
expect((contracts.get('pluginB')! as any).pluginAPlusB).toEqual(2);
});
-
- describe('timeout', () => {
- const flushPromises = () => new Promise((resolve) => setImmediate(resolve));
- beforeAll(() => {
- jest.useFakeTimers();
- });
- afterAll(() => {
- jest.useRealTimers();
- });
-
- it('throws timeout error if "setup" was not completed in 30 sec.', async () => {
- mockPluginInitializers.set(
- 'pluginA',
- jest.fn(() => ({
- setup: jest.fn(() => new Promise((i) => i)),
- start: jest.fn(() => ({ value: 1 })),
- stop: jest.fn(),
- }))
- );
- const pluginsService = new PluginsService(mockCoreContext, plugins);
- const promise = pluginsService.setup(mockSetupDeps);
-
- await flushPromises();
- jest.runAllTimers(); // setup plugins
-
- await expect(promise).rejects.toMatchInlineSnapshot(
- `[Error: Setup lifecycle of "pluginA" plugin wasn't completed in 10sec. Consider disabling the plugin and re-start.]`
- );
- });
- });
});
describe('#start()', () => {
@@ -330,34 +303,6 @@ describe('PluginsService', () => {
expect((contracts.get('pluginA')! as any).startValue).toEqual(2);
expect((contracts.get('pluginB')! as any).pluginAPlusB).toEqual(3);
});
- describe('timeout', () => {
- beforeAll(() => {
- jest.useFakeTimers();
- });
- afterAll(() => {
- jest.useRealTimers();
- });
-
- it('throws timeout error if "start" was not completed in 30 sec.', async () => {
- mockPluginInitializers.set(
- 'pluginA',
- jest.fn(() => ({
- setup: jest.fn(() => ({ value: 1 })),
- start: jest.fn(() => new Promise((i) => i)),
- stop: jest.fn(),
- }))
- );
- const pluginsService = new PluginsService(mockCoreContext, plugins);
- await pluginsService.setup(mockSetupDeps);
-
- const promise = pluginsService.start(mockStartDeps);
- jest.runAllTimers();
-
- await expect(promise).rejects.toMatchInlineSnapshot(
- `[Error: Start lifecycle of "pluginA" plugin wasn't completed in 10sec. Consider disabling the plugin and re-start.]`
- );
- });
- });
});
describe('#stop()', () => {
@@ -376,124 +321,4 @@ describe('PluginsService', () => {
expect(pluginCInstance.stop).toHaveBeenCalled();
});
});
-
- describe('asynchronous plugins', () => {
- let consoleSpy: jest.SpyInstance;
-
- beforeEach(() => {
- consoleSpy = jest.spyOn(console, 'log').mockImplementation(() => undefined);
- });
-
- afterEach(() => {
- consoleSpy.mockRestore();
- });
-
- const runScenario = async ({
- production,
- asyncSetup,
- asyncStart,
- }: {
- production: boolean;
- asyncSetup: boolean;
- asyncStart: boolean;
- }) => {
- const coreContext = coreMock.createCoreContext({ production });
-
- const syncPlugin = { id: 'sync-plugin', plugin: createManifest('sync-plugin') };
- mockPluginInitializers.set(
- 'sync-plugin',
- jest.fn(() => ({
- setup: jest.fn(() => 'setup-sync'),
- start: jest.fn(() => 'start-sync'),
- stop: jest.fn(),
- }))
- );
-
- const asyncPlugin = { id: 'async-plugin', plugin: createManifest('async-plugin') };
- mockPluginInitializers.set(
- 'async-plugin',
- jest.fn(() => ({
- setup: jest.fn(() => (asyncSetup ? Promise.resolve('setup-async') : 'setup-sync')),
- start: jest.fn(() => (asyncStart ? Promise.resolve('start-async') : 'start-sync')),
- stop: jest.fn(),
- }))
- );
-
- const pluginsService = new PluginsService(coreContext, [syncPlugin, asyncPlugin]);
-
- await pluginsService.setup(mockSetupDeps);
- await pluginsService.start(mockStartDeps);
- };
-
- it('logs a warning if a plugin returns a promise from its setup contract in dev mode', async () => {
- await runScenario({
- production: false,
- asyncSetup: true,
- asyncStart: false,
- });
-
- expect(consoleSpy.mock.calls).toMatchInlineSnapshot(`
- Array [
- Array [
- "Plugin async-plugin is using asynchronous setup lifecycle. Asynchronous plugins support will be removed in a later version.",
- ],
- ]
- `);
- });
-
- it('does not log warnings if a plugin returns a promise from its setup contract in prod mode', async () => {
- await runScenario({
- production: true,
- asyncSetup: true,
- asyncStart: false,
- });
-
- expect(consoleSpy).not.toHaveBeenCalled();
- });
-
- it('logs a warning if a plugin returns a promise from its start contract in dev mode', async () => {
- await runScenario({
- production: false,
- asyncSetup: false,
- asyncStart: true,
- });
-
- expect(consoleSpy.mock.calls).toMatchInlineSnapshot(`
- Array [
- Array [
- "Plugin async-plugin is using asynchronous start lifecycle. Asynchronous plugins support will be removed in a later version.",
- ],
- ]
- `);
- });
-
- it('does not log warnings if a plugin returns a promise from its start contract in prod mode', async () => {
- await runScenario({
- production: true,
- asyncSetup: false,
- asyncStart: true,
- });
-
- expect(consoleSpy).not.toHaveBeenCalled();
- });
-
- it('logs multiple warnings if both `setup` and `start` return promises', async () => {
- await runScenario({
- production: false,
- asyncSetup: true,
- asyncStart: true,
- });
-
- expect(consoleSpy.mock.calls).toMatchInlineSnapshot(`
- Array [
- Array [
- "Plugin async-plugin is using asynchronous setup lifecycle. Asynchronous plugins support will be removed in a later version.",
- ],
- Array [
- "Plugin async-plugin is using asynchronous start lifecycle. Asynchronous plugins support will be removed in a later version.",
- ],
- ]
- `);
- });
- });
});
diff --git a/src/core/public/plugins/plugins_service.ts b/src/core/public/plugins/plugins_service.ts
index 230a675b4cda..51af5a831d44 100644
--- a/src/core/public/plugins/plugins_service.ts
+++ b/src/core/public/plugins/plugins_service.ts
@@ -6,7 +6,6 @@
* Side Public License, v 1.
*/
-import { withTimeout, isPromise } from '@kbn/std';
import { PluginName, PluginOpaqueId } from '../../server';
import { CoreService } from '../../types';
import { CoreContext } from '../core_system';
@@ -19,7 +18,6 @@ import {
import { InternalCoreSetup, InternalCoreStart } from '../core_system';
import { InjectedPluginMetadata } from '../injected_metadata';
-const Sec = 1000;
/** @internal */
export type PluginsServiceSetupDeps = InternalCoreSetup;
/** @internal */
@@ -98,34 +96,10 @@ export class PluginsService implements CoreService
);
- let contract: unknown;
- const contractOrPromise = plugin.setup(
+ const contract = plugin.setup(
createPluginSetupContext(this.coreContext, deps, plugin),
pluginDepContracts
);
- if (isPromise(contractOrPromise)) {
- if (this.coreContext.env.mode.dev) {
- // eslint-disable-next-line no-console
- console.log(
- `Plugin ${pluginName} is using asynchronous setup lifecycle. Asynchronous plugins support will be removed in a later version.`
- );
- }
-
- const contractMaybe = await withTimeout({
- promise: contractOrPromise,
- timeoutMs: 10 * Sec,
- });
-
- if (contractMaybe.timedout) {
- throw new Error(
- `Setup lifecycle of "${pluginName}" plugin wasn't completed in 10sec. Consider disabling the plugin and re-start.`
- );
- } else {
- contract = contractMaybe.value;
- }
- } else {
- contract = contractOrPromise;
- }
contracts.set(pluginName, contract);
this.satupPlugins.push(pluginName);
@@ -152,34 +126,10 @@ export class PluginsService implements CoreService
);
- let contract: unknown;
- const contractOrPromise = plugin.start(
+ const contract = plugin.start(
createPluginStartContext(this.coreContext, deps, plugin),
pluginDepContracts
);
- if (isPromise(contractOrPromise)) {
- if (this.coreContext.env.mode.dev) {
- // eslint-disable-next-line no-console
- console.log(
- `Plugin ${pluginName} is using asynchronous start lifecycle. Asynchronous plugins support will be removed in a later version.`
- );
- }
-
- const contractMaybe = await withTimeout({
- promise: contractOrPromise,
- timeoutMs: 10 * Sec,
- });
-
- if (contractMaybe.timedout) {
- throw new Error(
- `Start lifecycle of "${pluginName}" plugin wasn't completed in 10sec. Consider disabling the plugin and re-start.`
- );
- } else {
- contract = contractMaybe.value;
- }
- } else {
- contract = contractOrPromise;
- }
contracts.set(pluginName, contract);
}
diff --git a/src/core/public/public.api.md b/src/core/public/public.api.md
index 4cf845de4617..6145cce3912f 100644
--- a/src/core/public/public.api.md
+++ b/src/core/public/public.api.md
@@ -209,16 +209,6 @@ export type AppUpdatableFields = Pick Partial | undefined;
-// @public @deprecated
-export interface AsyncPlugin {
- // (undocumented)
- setup(core: CoreSetup, plugins: TPluginsSetup): TSetup | Promise;
- // (undocumented)
- start(core: CoreStart, plugins: TPluginsStart): TStart | Promise;
- // (undocumented)
- stop?(): void;
-}
-
// @public
export interface Capabilities {
[key: string]: Record>;
@@ -401,6 +391,8 @@ export interface CoreSetup;
@@ -429,6 +421,8 @@ export interface CoreStart {
// (undocumented)
docLinks: DocLinksStart;
// (undocumented)
+ executionContext: ExecutionContextStart;
+ // (undocumented)
fatalErrors: FatalErrorsStart;
// (undocumented)
http: HttpStart;
@@ -461,6 +455,7 @@ export class CoreSystem {
// (undocumented)
start(): Promise<{
application: InternalApplicationStart;
+ executionContext: ExecutionContextSetup;
} | undefined>;
// (undocumented)
stop(): void;
@@ -511,6 +506,20 @@ export interface ErrorToastOptions extends ToastOptions {
toastMessage?: string;
}
+// @public
+export interface ExecutionContextSetup {
+ clear(): void;
+ context$: Observable;
+ get(): KibanaExecutionContext;
+ // Warning: (ae-forgotten-export) The symbol "Labels" needs to be exported by the entry point index.d.ts
+ getAsLabels(): Labels_2;
+ set(c$: KibanaExecutionContext): void;
+ withGlobalContext(context?: KibanaExecutionContext): KibanaExecutionContext;
+}
+
+// @public
+export type ExecutionContextStart = ExecutionContextSetup;
+
// @public
export interface FatalErrorInfo {
// (undocumented)
@@ -751,9 +760,10 @@ export interface IUiSettingsClient {
// @public
export type KibanaExecutionContext = {
- readonly type: string;
- readonly name: string;
- readonly id: string;
+ readonly type?: string;
+ readonly name?: string;
+ readonly page?: string;
+ readonly id?: string;
readonly description?: string;
readonly url?: string;
child?: KibanaExecutionContext;
@@ -900,7 +910,7 @@ interface Plugin_2 = (core: PluginInitializerContext) => Plugin_2 | AsyncPlugin;
+export type PluginInitializer = (core: PluginInitializerContext) => Plugin_2;
// @public
export interface PluginInitializerContext {
@@ -1108,7 +1118,7 @@ export class SavedObjectsClient {
}>) => Promise<{
resolved_objects: ResolvedSimpleSavedObject[];
}>;
- bulkUpdate(objects?: SavedObjectsBulkUpdateObject[]): Promise>;
+ bulkUpdate(objects?: SavedObjectsBulkUpdateObject[]): Promise>;
create: