diff --git a/.ci/.jenkins_nightly_nodejs.yml b/.ci/.jenkins_nightly_nodejs.yml index e4999e1deac..6ab8f935c13 100644 --- a/.ci/.jenkins_nightly_nodejs.yml +++ b/.ci/.jenkins_nightly_nodejs.yml @@ -9,4 +9,4 @@ # made, these will stop and there will be no value in testing v17 nightlies. # NODEJS_VERSION: - - "19" + - "20" diff --git a/.ci/.jenkins_nodejs.yml b/.ci/.jenkins_nodejs.yml index 8e585cb3ef5..8b736125804 100644 --- a/.ci/.jenkins_nodejs.yml +++ b/.ci/.jenkins_nodejs.yml @@ -1,7 +1,7 @@ NODEJS_VERSION: - # - "19" # Uncomment this when there are v19.x releases at https://nodejs.org/download/release/ + - "19" - "18" - # - "18.0" # Uncomment this when "18" is 18.1 or greater. + - "18.0" - "16" - "16.0" - "14" diff --git a/.ci/.jenkins_rc_nodejs.yml b/.ci/.jenkins_rc_nodejs.yml index 6c15769a2ff..e2caf072696 100644 --- a/.ci/.jenkins_rc_nodejs.yml +++ b/.ci/.jenkins_rc_nodejs.yml @@ -4,7 +4,7 @@ # The node.js project *sometimes* produces "rc" builds leading up to a new # release. They get uploaded to: https://nodejs.org/download/rc/ NODEJS_VERSION: + - "19" - "18" - "16" - "14" - - "12" diff --git a/.ci/.jenkins_tav.yml b/.ci/.jenkins_tav.yml index 07fc3c4e62c..db86aff93b5 100644 --- a/.ci/.jenkins_tav.yml +++ b/.ci/.jenkins_tav.yml @@ -26,9 +26,11 @@ TAV: - mongodb-core - mysql - mysql2 + - next - pg - pug - redis - restify - tedious + - undici - ws diff --git a/.ci/.jenkins_tav_nodejs.yml b/.ci/.jenkins_tav_nodejs.yml index f04ab8da441..a677d335cc5 100644 --- a/.ci/.jenkins_tav_nodejs.yml +++ b/.ci/.jenkins_tav_nodejs.yml @@ -1,5 +1,5 @@ NODEJS_VERSION: - # - "19" # Uncomment this when there are v19.x releases at https://nodejs.org/en/about/releases/ + - "19" - "18" - "16" - "14" diff --git a/.ci/Jenkinsfile b/.ci/Jenkinsfile index c3a478c3871..e4cc6259da3 100644 --- a/.ci/Jenkinsfile +++ b/.ci/Jenkinsfile @@ -8,15 +8,13 @@ pipeline { BASE_DIR = "src/github.com/elastic/${env.REPO}" PIPELINE_LOG_LEVEL='INFO' JOB_GCS_BUCKET = credentials('gcs-bucket') - GITHUB_CHECK_ITS_NAME = 'Integration Tests' - ITS_PIPELINE = 'apm-integration-tests-selector-mbp/main' GITHUB_CHECK = 'true' RELEASE_URL_MESSAGE = "()" SLACK_CHANNEL = '#apm-agent-node' NOTIFY_TO = 'build-apm+apm-agent-nodejs@elastic.co' NPMRC_SECRET = 'secret/jenkins-ci/npmjs/elasticmachine' TOTP_SECRET = 'totp/code/npmjs-elasticmachine' - BUILD_NODE_VERSION = 'v16.15.0' + BUILD_NODE_VERSION = 'v16.15.1' DOCKER_REGISTRY = 'docker.elastic.co' DOCKER_SECRET = 'secret/apm-team/ci/docker-registry/prod' } @@ -92,7 +90,7 @@ pipeline { def parallelTasks = [:] node['NODEJS_VERSION'].each{ version -> parallelTasks["Node.js-${version}"] = generateStep(version: version) - parallelTasks["Node.js-${version}-async-hooks-false"] = generateStep(version: version, disableAsyncHooks: true) + parallelTasks["Node.js-${version}-noasynchooks"] = generateStep(version: version, disableAsyncHooks: true) // TODO: to be enabled if required. // parallelTasks["Windows-Node.js-${version}"] = generateStepForWindows(version: version) } @@ -193,10 +191,10 @@ pipeline { } } } - stage('Nightly Test - No async hooks') { + stage('Nightly Test - noasynchooks') { agent { label 'linux && immutable' } steps { - withGithubNotify(context: 'Nightly No Async Hooks Test', tab: 'tests') { + withGithubNotify(context: 'Nightly noasynchooks Test', tab: 'tests') { deleteDir() unstash 'source' dir("${BASE_DIR}"){ @@ -204,7 +202,7 @@ pipeline { def node = readYaml(file: '.ci/.jenkins_nightly_nodejs.yml') def parallelTasks = [:] node['NODEJS_VERSION'].each { version -> - parallelTasks["Node.js-${version}-nightly-no-async-hooks"] = generateStep(version: version, buildType: 'nightly', disableAsyncHooks: true) + parallelTasks["Node.js-${version}-nightly-noasynchooks"] = generateStep(version: version, buildType: 'nightly', disableAsyncHooks: true) } parallel(parallelTasks) } @@ -231,10 +229,10 @@ pipeline { } } } - stage('RC Test - No async hooks') { + stage('RC Test - noasynchooks') { agent { label 'linux && immutable' } steps { - withGithubNotify(context: 'RC No Async Hooks Test', tab: 'tests') { + withGithubNotify(context: 'RC noasynchooks Test', tab: 'tests') { deleteDir() unstash 'source' dir("${BASE_DIR}"){ @@ -242,7 +240,7 @@ pipeline { def node = readYaml(file: '.ci/.jenkins_rc_nodejs.yml') def parallelTasks = [:] node['NODEJS_VERSION'].each { version -> - parallelTasks["Node.js-${version}-rc-no-async-hooks"] = generateStep(version: version, buildType: 'rc', disableAsyncHooks: true) + parallelTasks["Node.js-${version}-rc-noasynchooks"] = generateStep(version: version, buildType: 'rc', disableAsyncHooks: true) } parallel(parallelTasks) } @@ -252,29 +250,39 @@ pipeline { } } } - stage('Integration Tests') { - agent none - when { - beforeAgent true - allOf { - not { tag pattern: 'v\\d+\\.\\d+\\.\\d+', comparator: 'REGEXP' } - expression { return env.ONLY_DOCS == "false" } - anyOf { - changeRequest() - expression { return !params.Run_As_Main_Branch } - } - } + + /** + Publish a snapshot. A "snapshot" is a packaging of the latest *unreleased* APM agent, + published to a known GCS bucket for use in edge demo/test environments. + */ + stage('Publish snapshot') { + options { skipDefaultCheckout() } + environment { + BUCKET_NAME = 'oblt-artifacts' + DOCKER_REGISTRY = 'docker.elastic.co' + DOCKER_REGISTRY_SECRET = 'secret/observability-team/ci/docker-registry/prod' + GCS_ACCOUNT_SECRET = 'secret/observability-team/ci/snapshoty' } + when { branch 'main' } steps { - build(job: env.ITS_PIPELINE, propagate: false, wait: false, - parameters: [string(name: 'INTEGRATION_TEST', value: 'Node.js'), - string(name: 'BUILD_OPTS', value: "--nodejs-agent-package ${env.CHANGE_FORK?.trim() ?: 'elastic' }/${env.REPO}#${env.GIT_BASE_COMMIT} --opbeans-node-agent-branch ${env.GIT_BASE_COMMIT}"), - string(name: 'GITHUB_CHECK_NAME', value: env.GITHUB_CHECK_ITS_NAME), - string(name: 'GITHUB_CHECK_REPO', value: env.REPO), - string(name: 'GITHUB_CHECK_SHA1', value: env.GIT_BASE_COMMIT)]) - githubNotify(context: "${env.GITHUB_CHECK_ITS_NAME}", description: "${env.GITHUB_CHECK_ITS_NAME} ...", status: 'PENDING', targetUrl: "${env.JENKINS_URL}search/?q=${env.ITS_PIPELINE.replaceAll('/','+')}") + withGithubNotify(context: 'Publish snapshot packages') { + deleteDir() + unstash name: 'source' + withNodeJSEnv(version: env.BUILD_NODE_VERSION) { + dir(env.BASE_DIR) { + sh(label: 'package snapshot', script: 'npm run package:snapshot') + snapshoty( + bucket: env.BUCKET_NAME, + gcsAccountSecret: env.GCS_ACCOUNT_SECRET, + dockerRegistry: env.DOCKER_REGISTRY, + dockerSecret: env.DOCKER_REGISTRY_SECRET + ) + } + } + } } } + stage('Release') { options { skipDefaultCheckout() } when { @@ -371,7 +379,7 @@ pipeline { The result JSON files are also archive into Jenkins. */ stage('Benchmarks') { - agent { label 'metal' } + agent { label 'microbenchmarks-pool' } options { skipDefaultCheckout() } environment { HOME = "${env.WORKSPACE}" @@ -424,22 +432,23 @@ def generateStep(Map params = [:]){ def version = params?.version def tav = params.containsKey('tav') ? params.tav : '' def buildType = params.containsKey('buildType') ? params.buildType : 'release' - def ELASTIC_APM_ASYNC_HOOKS = String.valueOf(!params.get('disableAsyncHooks', false)) + def contextManager = params.get('disableAsyncHooks', false) ? 'patch' : '' return { withNode(labels: 'linux && immutable', forceWorkspace: true, forceWorker: true) { - withEnv(["VERSION=${version}", "ELASTIC_APM_ASYNC_HOOKS=${ELASTIC_APM_ASYNC_HOOKS}"]) { + withEnv(["VERSION=${version}", "ELASTIC_APM_CONTEXT_MANAGER=${contextManager}"]) { deleteDir() unstash 'source' - dir("${BASE_DIR}"){ - try { - retryWithSleep(retries: 2, seconds: 5, backoff: true) { - sh(label: "Run Tests", script: """.ci/scripts/test.sh -b "${buildType}" -t "${tav}" "${version}" """) + // Grab the current docker context for helping to troubleshoot the docker containers using filebeat and metricbeat + dockerContext(filebeatOutput: "docker-${version}-${buildType}.log", metricbeatOutput: "docker-${version}-${buildType}-metricbeat.log", archiveOnlyOnFail: true){ + dir("${BASE_DIR}"){ + try { + retryWithSleep(retries: 2, seconds: 5, backoff: true) { + sh(label: "Run Tests", script: """.ci/scripts/test.sh -b "${buildType}" -t "${tav}" "${version}" """) + } + } finally { + junit(testResults: "test_output/*.junit.xml", allowEmptyResults: true, keepLongStdio: true) + archiveArtifacts(artifacts: "test_output/*.tap", allowEmptyArchive: true) } - } catch(e){ - error(e.toString()) - } finally { - junit(testResults: "test_output/*.junit.xml", allowEmptyResults: true, keepLongStdio: true) - archiveArtifacts(artifacts: "test_output/*.tap", allowEmptyArchive: true) } } } @@ -516,7 +525,7 @@ def getSmartTAVContext() { def generateStepForWindows(Map params = [:]){ def version = params?.version - def ELASTIC_APM_ASYNC_HOOKS = String.valueOf(!params.get('disableAsyncHooks', false)) + def contextManager = params.get('disableAsyncHooks', false) ? 'patch' : '' return { sh label: 'Prepare services', script: ".ci/scripts/windows/prepare-test.sh ${version}" def linuxIp = grabWorkerIP() @@ -524,7 +533,7 @@ def generateStepForWindows(Map params = [:]){ // When installing with choco the PATH might not be updated within the already connected worker. withEnv(["PATH=${PATH};C:\\Program Files\\nodejs", "VERSION=${version}", - "ELASTIC_APM_ASYNC_HOOKS=${ELASTIC_APM_ASYNC_HOOKS}", + "ELASTIC_APM_CONTEXT_MANAGER=${contextManager}", "CASSANDRA_HOST=${linuxIp}", "ES_HOST=${linuxIp}", "LOCALSTACK_HOST=${linuxIp}", diff --git a/.ci/Makefile b/.ci/Makefile index c8368713458..c6e9ffc1699 100644 --- a/.ci/Makefile +++ b/.ci/Makefile @@ -58,7 +58,7 @@ publish: validate-layer-name validate-aws-default-region --layer-name "$(ELASTIC_LAYER_NAME)" \ --description "AWS Lambda Extension Layer for the Elastic APM Node.js Agent" \ --license "Apache-2.0" \ - --compatible-runtimes nodejs16.x nodejs14.x nodejs12.x nodejs10.x \ + --compatible-runtimes nodejs18.x nodejs16.x nodejs14.x nodejs12.x nodejs10.x \ --zip-file "fileb://./$(AWS_FOLDER)/elastic-apm-node-lambda-layer-$(BRANCH_NAME).zip" # Grant public access to the given LAYER in the given AWS region diff --git a/.ci/docker/docker-compose-node-edge-test.yml b/.ci/docker/docker-compose-node-edge-test.yml index 0f72f2e8370..ca90e8ed8e3 100644 --- a/.ci/docker/docker-compose-node-edge-test.yml +++ b/.ci/docker/docker-compose-node-edge-test.yml @@ -9,7 +9,7 @@ services: - NODE_VERSION=${NODE_VERSION} - NODE_FULL_VERSION=${NODE_FULL_VERSION} - NVM_NODEJS_ORG_MIRROR=${NVM_NODEJS_ORG_MIRROR} - - ELASTIC_APM_ASYNC_HOOKS=${ELASTIC_APM_ASYNC_HOOKS} + - ELASTIC_APM_CONTEXT_MANAGER=${ELASTIC_APM_CONTEXT_MANAGER} working_dir: /app command: > /bin/bash -c ".ci/scripts/docker-test.sh" @@ -27,7 +27,7 @@ services: NODE_VERSION: ${NODE_VERSION} NODE_FULL_VERSION: ${NODE_FULL_VERSION} NVM_NODEJS_ORG_MIRROR: ${NVM_NODEJS_ORG_MIRROR} - ELASTIC_APM_ASYNC_HOOKS: ${ELASTIC_APM_ASYNC_HOOKS} + ELASTIC_APM_CONTEXT_MANAGER: ${ELASTIC_APM_CONTEXT_MANAGER} TAV: ${TAV_MODULE} HOME: /tmp volumes: diff --git a/.ci/docker/docker-compose-node-test.yml b/.ci/docker/docker-compose-node-test.yml index a2e5403fca7..c272f2f7a3d 100644 --- a/.ci/docker/docker-compose-node-test.yml +++ b/.ci/docker/docker-compose-node-test.yml @@ -23,7 +23,7 @@ services: LOCALSTACK_HOST: 'localstack' NODE_VERSION: ${NODE_VERSION} TAV: ${TAV_MODULE} - ELASTIC_APM_ASYNC_HOOKS: ${ELASTIC_APM_ASYNC_HOOKS} + ELASTIC_APM_CONTEXT_MANAGER: ${ELASTIC_APM_CONTEXT_MANAGER} HOME: /tmp PATH: /app/node_modules/.bin:./node_modules/.bin:/app/node_modules:/bin:/sbin:/usr/bin:/usr/sbin:/usr/local/bin:/usr/local/sbin volumes: diff --git a/.ci/docker/docker-compose.yml b/.ci/docker/docker-compose.yml index c72d39cb5e1..388ad1291b0 100644 --- a/.ci/docker/docker-compose.yml +++ b/.ci/docker/docker-compose.yml @@ -19,7 +19,7 @@ services: retries: 30 mongodb: - image: mongo + image: mongo:5 ports: - "27017:27017" volumes: diff --git a/.ci/docker/node-edge-container/Dockerfile b/.ci/docker/node-edge-container/Dockerfile index 18eb6b52cbc..b7362339a0b 100644 --- a/.ci/docker/node-edge-container/Dockerfile +++ b/.ci/docker/node-edge-container/Dockerfile @@ -14,11 +14,11 @@ RUN apt-get -qq update \ ARG NODE_VERSION ARG NODE_FULL_VERSION ARG NVM_NODEJS_ORG_MIRROR -ARG ELASTIC_APM_ASYNC_HOOKS +ARG ELASTIC_APM_CONTEXT_MANAGER ENV NODE_VERSION=${NODE_VERSION} ENV NODE_FULL_VERSION=${NODE_FULL_VERSION} ENV NVM_NODEJS_ORG_MIRROR=${NVM_NODEJS_ORG_MIRROR} -ENV ELASTIC_APM_ASYNC_HOOKS=${ELASTIC_APM_ASYNC_HOOKS} +ENV ELASTIC_APM_CONTEXT_MANAGER=${ELASTIC_APM_CONTEXT_MANAGER} # nvm environment variables ENV NVM_VERSION v0.34.0 diff --git a/.ci/scripts/docker-test.sh b/.ci/scripts/docker-test.sh index 6ada34036ca..a6b7a67fab5 100755 --- a/.ci/scripts/docker-test.sh +++ b/.ci/scripts/docker-test.sh @@ -31,7 +31,7 @@ npm_install() { local retries=2 local count=0 - until npm install; do + until npm install --no-save; do exit=$? wait=$((2 ** $count)) count=$(($count + 1)) diff --git a/.ci/scripts/test.sh b/.ci/scripts/test.sh index 93f217e41c5..b22952cc405 100755 --- a/.ci/scripts/test.sh +++ b/.ci/scripts/test.sh @@ -226,11 +226,9 @@ else DOCKER_COMPOSE_FILE=docker-compose-all.yml fi -ELASTIC_APM_ASYNC_HOOKS=${ELASTIC_APM_ASYNC_HOOKS:-true} - set +e NVM_NODEJS_ORG_MIRROR=${NVM_NODEJS_ORG_MIRROR} \ -ELASTIC_APM_ASYNC_HOOKS=${ELASTIC_APM_ASYNC_HOOKS} \ +ELASTIC_APM_CONTEXT_MANAGER=${ELASTIC_APM_CONTEXT_MANAGER} \ NODE_VERSION=${NODE_VERSION} \ NODE_FULL_VERSION=${NODE_FULL_VERSION} \ TAV_MODULE=${TAV_MODULE} \ @@ -250,7 +248,7 @@ fi set -e NVM_NODEJS_ORG_MIRROR=${NVM_NODEJS_ORG_MIRROR} \ -ELASTIC_APM_ASYNC_HOOKS=${ELASTIC_APM_ASYNC_HOOKS} \ +ELASTIC_APM_CONTEXT_MANAGER=${ELASTIC_APM_CONTEXT_MANAGER} \ NODE_VERSION=${NODE_VERSION} \ NODE_FULL_VERSION=${NODE_FULL_VERSION} \ TAV_MODULE=${TAV_MODULE} \ diff --git a/.ci/snapshoty.yml b/.ci/snapshoty.yml new file mode 100644 index 00000000000..5183397d610 --- /dev/null +++ b/.ci/snapshoty.yml @@ -0,0 +1,36 @@ +--- + +# Version of configuration to use +version: '1.0' + +# You can define a Google Cloud Account to use +account: + # Project id of the service account + project: '${GCS_PROJECT}' + # Private key id of the service account + private_key_id: '${GCS_PRIVATE_KEY_ID}' + # Private key of the service account + private_key: '${GCS_PRIVATE_KEY}' + # Email of the service account + client_email: '${GCS_CLIENT_EMAIL}' + # URI token + token_uri: 'https://oauth2.googleapis.com/token' + +# List of artifacts +artifacts: + # Path to use for artifacts discovery + - path: './build/snapshot' + # Files pattern to match + files_pattern: 'elastic-apm-node-(?P\d+\.\d+\.\d+)\.tgz' + # File layout on GCS bucket + output_pattern: '{project}/{jenkins_branch_name}/elastic-apm-node-{app_version}-{jenkins_git_commit_short}.tgz' + # List of metadata processors to use. + metadata: + # Define static custom metadata + - name: 'custom' + data: + project: 'apm-agent-nodejs' + # Add git metadata + - name: 'git' + # Add jenkins metadata + - name: 'jenkins' diff --git a/.eslintrc.json b/.eslintrc.json index 35f800e4b3d..a4a2847bb48 100644 --- a/.eslintrc.json +++ b/.eslintrc.json @@ -11,12 +11,18 @@ "license-header/header": [ "error", "./dev-utils/license-header.js" ] }, "ignorePatterns": [ + "/*.example.js", // a pattern for uncommited local dev files to avoid linting "/.nyc_output", "/build", "node_modules", + "/examples/esbuild/dist", + "/examples/typescript/dist", + "/examples/nextjs", "/lib/opentelemetry-bridge/opentelemetry-core-mini", "/test/babel/out.js", "/test/lambda/fixtures/esbuild-bundled-handler/hello.js", + "/test/instrumentation/modules/next/a-nextjs-app/pages", + "/test/instrumentation/modules/next/a-nextjs-app/components", "/test/sourcemaps/fixtures/lib", "/test/sourcemaps/fixtures/src", "/test/stacktraces/fixtures/dist", diff --git a/.github/ISSUE_TEMPLATE/Bug_report.md b/.github/ISSUE_TEMPLATE/Bug_report.md index 997d3185415..43e2596c5de 100644 --- a/.github/ISSUE_TEMPLATE/Bug_report.md +++ b/.github/ISSUE_TEMPLATE/Bug_report.md @@ -1,55 +1,56 @@ ---- -name: Bug report -about: Create a report to help us improve - ---- - -**Describe the bug** - - - -**To Reproduce** - -Steps to reproduce the behavior: -1. Use this config '...' -2. Then call '....' -3. Then do '....' -4. See error - -**Expected behavior** - - - -**Environment (please complete the following information)** - -- OS: [e.g. Linux] -- Node.js version: -- APM Server version: -- Agent version: - -**How are you starting the agent? (please tick one of the boxes)** - -- [ ] Calling `agent.start()` directly (e.g. `require('elastic-apm-node').start(...)`) -- [ ] Requiring `elastic-apm-node/start` from within the source code -- [ ] Starting node with `-r elastic-apm-node/start` - -**Additional context** - - - -- Agent config options -
- Click to expand - - ``` - replace this line with your agent config options - ``` -
-- `package.json` dependencies: -
- Click to expand - - ``` - replace this line with your dependencies section from package.json - ``` -
+--- +name: Bug report +about: Create a report to help us improve + +--- + +**Describe the bug** + + + +**To Reproduce** + +Steps to reproduce the behavior: +1. Use this config '...' +2. Then call '....' +3. Then do '....' +4. See error + +**Expected behavior** + + + +**Environment (please complete the following information)** + +- OS: [e.g. Linux] +- Node.js version: +- APM Server version: +- Agent version: + +**How are you starting the agent? (please tick one of the boxes)** + +- [ ] Calling `agent.start()` directly (e.g. `require('elastic-apm-node').start(...)`) +- [ ] Requiring `elastic-apm-node/start` from within the source code +- [ ] Starting node with `-r elastic-apm-node/start` + +**Additional context** + + + +Agent config options: +
+ Click to expand + +``` +replace this line with your agent config options +``` +
+ +`package.json` dependencies: +
+ Click to expand + +``` +replace this line with your dependencies section from package.json +``` +
diff --git a/.github/ISSUE_TEMPLATE/Feature_request.md b/.github/ISSUE_TEMPLATE/Feature_request.md index 5384295126e..066b2d920a2 100644 --- a/.github/ISSUE_TEMPLATE/Feature_request.md +++ b/.github/ISSUE_TEMPLATE/Feature_request.md @@ -1,17 +1,17 @@ ---- -name: Feature request -about: Suggest an idea for this project - ---- - -**Is your feature request related to a problem? Please describe.** -A clear and concise description of what the problem is. Ex. I'm always frustrated when [...] - -**Describe the solution you'd like** -A clear and concise description of what you want to happen. - -**Describe alternatives you've considered** -A clear and concise description of any alternative solutions or features you've considered. - -**Additional context** -Add any other context or screenshots about the feature request here. +--- +name: Feature request +about: Suggest an idea for this project + +--- + +**Is your feature request related to a problem? Please describe.** +A clear and concise description of what the problem is. Ex. I'm always frustrated when [...] + +**Describe the solution you'd like** +A clear and concise description of what you want to happen. + +**Describe alternatives you've considered** +A clear and concise description of any alternative solutions or features you've considered. + +**Additional context** +Add any other context or screenshots about the feature request here. diff --git a/.github/dependabot.yml b/.github/dependabot.yml index 653368afb3f..aaaa0476a4f 100644 --- a/.github/dependabot.yml +++ b/.github/dependabot.yml @@ -4,5 +4,14 @@ updates: directory: "/" schedule: interval: "weekly" + open-pull-requests-limit: 10 + reviewers: + - "elastic/apm-agent-node-js" + + - package-ecosystem: "npm" + directory: "/test/instrumentation/modules/next/a-nextjs-app" + schedule: + interval: "weekly" + open-pull-requests-limit: 5 reviewers: - "elastic/apm-agent-node-js" diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index a4c49fe5ebb..3f9ff300310 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -6,7 +6,7 @@ # - the "TAV" tests that run against all supported versions of instrumented # modules # - the integration tests that run with an apm-server -# - testing with ELASTIC_APM_ASYNC_HOOKS=false +# - testing with ELASTIC_APM_CONTEXT_MANAGER=patch (i.e. without using async_hooks) # - code coverage (npm run coverage) name: Test @@ -68,7 +68,7 @@ jobs: POSTGRES_HOST_AUTH_METHOD: 'trust' mongodb: - image: mongo + image: mongo:5 ports: - 27017:27017 volumes: @@ -120,7 +120,9 @@ jobs: strategy: matrix: node: + - '19' - '18' + - '18.0' - '16' - '16.0' - '14' diff --git a/.gitignore b/.gitignore index fdebb0363b3..e58f59c9e45 100644 --- a/.gitignore +++ b/.gitignore @@ -13,3 +13,5 @@ node_modules /test/benchmarks/.tmp /tmp +/examples/*/dist +.next diff --git a/.nvmrc b/.nvmrc index 99cdd8009c3..431076a9486 100644 --- a/.nvmrc +++ b/.nvmrc @@ -1 +1 @@ -16.15.0 +16.16.0 diff --git a/.tav.yml b/.tav.yml index 89732ea6b9f..ec4b49c4802 100644 --- a/.tav.yml +++ b/.tav.yml @@ -55,9 +55,17 @@ mysql2-new: - node test/instrumentation/modules/mysql2/mysql.test.js - node test/instrumentation/modules/mysql2/pool-release-1.test.js -redis: +redis-v2-v4: + name: redis versions: '>=2.0.0 <4.0.0' - commands: node test/instrumentation/modules/redis.test.js + commands: node test/instrumentation/modules/redis-2-3.test.js + +redis: + name: redis + versions: '>=4.0.0 <5.0.0' + commands: + - node test/instrumentation/modules/redis.test.js + - node test/instrumentation/modules/redis4-legacy.test.js # We want these version ranges: # # v3.1.3 is broken in older versions of Node because of https://github.com/luin/ioredis/commit/d5867f7c7f03a770a8c0ca5680fdcbfcaf8488e7 @@ -159,10 +167,12 @@ ws-new: commands: node test/instrumentation/modules/ws.test.js graphql-v0.7-v16: + name: graphql preinstall: npm uninstall express-graphql versions: '>=0.7.0 <0.11.0 || >=0.11.1 <16' commands: node test/instrumentation/modules/graphql.test.js graphql: + name: graphql preinstall: npm uninstall express-graphql node: '>=12' versions: '>=16.0.0 <17' @@ -176,92 +186,6 @@ express: - node test/instrumentation/modules/express/capture-exceptions-on.test.js - node test/instrumentation/modules/express/set-framework.test.js -express-graphql-0.6.1_graphql-0.8: - name: express-graphql - preinstall: npm uninstall apollo-server-express - peerDependencies: graphql@^0.8.2 - versions: '0.6.1' - commands: node test/instrumentation/modules/express-graphql.test.js - -express-graphql-0.6.2_graphql-0.9: - name: express-graphql - preinstall: npm uninstall apollo-server-express - peerDependencies: graphql@^0.9.0 - versions: '>=0.6.2 <0.6.6' - commands: node test/instrumentation/modules/express-graphql.test.js - -express-graphql-0.6.6_graphql-0.10: - name: express-graphql - preinstall: npm uninstall apollo-server-express - peerDependencies: graphql@^0.10.0 - versions: '>=0.6.6 <0.6.8' - commands: node test/instrumentation/modules/express-graphql.test.js - -express-graphql-0.6.11_graphql-0.10: - name: express-graphql - preinstall: npm uninstall apollo-server-express - peerDependencies: graphql@^0.10.0 - versions: '0.6.11' - commands: node test/instrumentation/modules/express-graphql.test.js -express-graphql-0.6.11_graphql-0.11: - name: express-graphql - preinstall: npm uninstall apollo-server-express - peerDependencies: graphql@^0.11.0 - versions: '0.6.11' - commands: node test/instrumentation/modules/express-graphql.test.js - -express-graphql-0.6.12_graphql-0.10: - name: express-graphql - preinstall: npm uninstall apollo-server-express - peerDependencies: graphql@^0.10.0 - versions: '^0.6.12' - commands: node test/instrumentation/modules/express-graphql.test.js -express-graphql-0.6.12_graphql-0.11: - name: express-graphql - preinstall: npm uninstall apollo-server-express - peerDependencies: graphql@^0.11.0 - versions: '^0.6.12' - commands: node test/instrumentation/modules/express-graphql.test.js -express-graphql-0.6.12_graphql-0.12: - name: express-graphql - preinstall: npm uninstall apollo-server-express - peerDependencies: graphql@^0.12.0 - versions: '^0.6.12' - commands: node test/instrumentation/modules/express-graphql.test.js -express-graphql-0.6.12_graphql-0.13: - name: express-graphql - preinstall: npm uninstall apollo-server-express - peerDependencies: graphql@^0.13.0 - versions: '^0.6.12' - commands: node test/instrumentation/modules/express-graphql.test.js - -express-graphql-0.7.1_graphql-0.12: - name: express-graphql - preinstall: npm uninstall apollo-server-express - peerDependencies: graphql@^0.12.0 - versions: '>=0.7.1 <0.9.0' - commands: node test/instrumentation/modules/express-graphql.test.js -express-graphql-0.7.1_graphql-0.13: - name: express-graphql - preinstall: npm uninstall apollo-server-express - peerDependencies: graphql@^0.13.0 - versions: '>=0.7.1 <0.9.0' - commands: node test/instrumentation/modules/express-graphql.test.js -express-graphql-0.7.1_graphql-14: - name: express-graphql - preinstall: npm uninstall apollo-server-express - peerDependencies: graphql@^14.0.0 - versions: '>=0.7.1 <0.9.0' - commands: node test/instrumentation/modules/express-graphql.test.js - -express-graphql-0.9.0_graphql-14: - name: express-graphql - preinstall: npm uninstall apollo-server-express - peerDependencies: graphql@^14.4.1 - versions: '>=0.9.0 <0.10.0' - node: '>=7.6.0' - commands: node test/instrumentation/modules/express-graphql.test.js - # - Skip express-graphql@0.10.0 because it briefly, accidentally introduced # syntax that required ES2020 (node v14). # - Limit to node >=10.4 because of a known issue. @@ -296,31 +220,7 @@ express-graphql-0.11.0_graphql-15: node: '>=10.4' commands: node test/instrumentation/modules/express-graphql.test.js -apollo-server-express-2_12: - name: apollo-server-express - preinstall: npm uninstall express-graphql - peerDependencies: graphql@^0.12.0 - # We want this version range: - # versions: '>=2.9.16 <2.2 || >= 2.3.2 <3' - # but only the latest MAJOR.MINOR.x to reduce the test matrix. - # - # Maintenance note: This should be updated for newer MAJOR.MINOR releases. - versions: '2.9.16 || 2.10.1 || 2.11.0 || 2.12.0 || 2.13.1 || 2.14.5 || 2.15.1 || 2.16.1 || 2.17.0 || 2.18.2 || 2.19.2 || 2.20.0 || 2.21.2 || 2.22.2 || 2.23.0 || 2.24.1 || 2.25.0 || >2.25.x <3' - node: '>=6' - commands: node test/instrumentation/modules/apollo-server-express.test.js -apollo-server-express-2_13: - name: apollo-server-express - preinstall: npm uninstall express-graphql - peerDependencies: graphql@^0.13.0 - # We want this version range: - # versions: '>=2.9.16 <2.2 || >= 2.3.2 <3' - # but only the latest MAJOR.MINOR.x to reduce the test matrix. - # - # Maintenance note: This should be updated for newer MAJOR.MINOR releases. - versions: '2.9.16 || 2.10.1 || 2.11.0 || 2.12.0 || 2.13.1 || 2.14.5 || 2.15.1 || 2.16.1 || 2.17.0 || 2.18.2 || 2.19.2 || 2.20.0 || 2.21.2 || 2.22.2 || 2.23.0 || 2.24.1 || 2.25.0 || >2.25.x <3' - node: '>=6' - commands: node test/instrumentation/modules/apollo-server-express.test.js -apollo-server-express-2_14: +apollo-server-express-2_graphql-14: name: apollo-server-express preinstall: npm uninstall express-graphql peerDependencies: graphql@^14.0.0 @@ -332,7 +232,7 @@ apollo-server-express-2_14: versions: '2.9.16 || 2.10.1 || 2.11.0 || 2.12.0 || 2.13.1 || 2.14.5 || 2.15.1 || 2.16.1 || 2.17.0 || 2.18.2 || 2.19.2 || 2.20.0 || 2.21.2 || 2.22.2 || 2.23.0 || 2.24.1 || 2.25.0 || >2.25.x <3' node: '>=6' commands: node test/instrumentation/modules/apollo-server-express.test.js -apollo-server-express-2_15: +apollo-server-express-2_graphql-15: name: apollo-server-express preinstall: npm uninstall express-graphql peerDependencies: graphql@^15.0.0 @@ -347,28 +247,46 @@ apollo-server-express-2_15: # graphql v15 supports node v8 as a minimum. node: '>=8' commands: node test/instrumentation/modules/apollo-server-express.test.js - -apollo-server-express-3_15: +apollo-server-express-3_graphql-15: name: apollo-server-express preinstall: npm uninstall express-graphql peerDependencies: graphql@^15.0.0 - versions: '^3.0.0' - node: '>=12' + # We want this version range: + # versions: '^3.0.0' + # but only test the latest MAJOR.MINOR.x to reduce the test matrix. + # + # Maintenance note: This should be updated for newer MAJOR.MINOR releases. + versions: '3.0.2 || 3.1.2 || 3.2.0 || 3.3.0 || 3.4.1 || 3.5.0 || 3.6.8 || 3.7.0 || 3.8.2 || 3.9.0 || ^3.10.2' commands: node test/instrumentation/modules/apollo-server-express.test.js express-queue: versions: '>=0.0.11' commands: node test/instrumentation/modules/express-queue.test.js -koa-router: +koa-router-v5-v11: + name: koa-router + versions: '>=5.2.0 <11' node: '>=6.0.0' peerDependencies: koa@2 - versions: '>=5.2.0 <11' commands: node test/instrumentation/modules/koa-router/old-name.test.js -'@koa/router': - node: '>=8.0.0' +koa-router: + name: koa-router + versions: '>=11 <13' + node: '>=12.0.0' peerDependencies: koa@2 + commands: node test/instrumentation/modules/koa-router/old-name.test.js + +'@koa/router-v8-v11': + name: '@koa/router' versions: '>=8 <11' + node: '>=8.0.0' + peerDependencies: koa@2 + commands: node test/instrumentation/modules/koa-router/new-name.test.js +'@koa/router': + name: '@koa/router' + versions: '>=11 <13' + node: '>=12.0.0' + peerDependencies: koa@2 commands: node test/instrumentation/modules/koa-router/new-name.test.js elasticsearch: @@ -417,9 +335,11 @@ handlebars: commands: node test/instrumentation/modules/handlebars.test.js # Pug v3 dropped node v8 support (https://github.com/pugjs/pug/releases/tag/pug%403.0.0). pug-v2: + name: 'pug' versions: '0.1.0 || >2.0.0 <3.0.0' commands: node test/instrumentation/modules/pug.test.js pug: + name: 'pug' versions: '>=3.0.0' node: '>8' commands: node test/instrumentation/modules/pug.test.js @@ -431,6 +351,8 @@ pug: # - Node version compat: # - @hapi/hapi@19: supports node >=v12 (judging from commit 50d8d7d) # - @hapi/hapi@20: appears (from travis template refs) to support node >=v12 +# - @hapi/hapi@21: dropped support for node v12, and requires v14.10.0 +# for 'performance.eventLoopUtilization' '@hapi/hapi-v17-v18': name: '@hapi/hapi' versions: '>=17.0.0 <19.0.0' @@ -438,13 +360,20 @@ pug: commands: - node test/instrumentation/modules/hapi/basic.test.js - node test/instrumentation/modules/hapi/set-framework-hapihapi.test.js -'@hapi/hapi': +'@hapi/hapi-v19-v20': name: '@hapi/hapi' - versions: '>=19.0.0' + versions: '>=19.0.0 <21.0.0' node: '>=12' commands: - node test/instrumentation/modules/hapi/basic.test.js - node test/instrumentation/modules/hapi/set-framework-hapihapi.test.js +'@hapi/hapi': + name: '@hapi/hapi' + versions: '>=21.0.0' + node: '>=14.10.0' + commands: + - node test/instrumentation/modules/hapi/basic.test.js + - node test/instrumentation/modules/hapi/set-framework-hapihapi.test.js tedious-v1-v11: name: tedious @@ -459,27 +388,52 @@ tedious-v11-v12: versions: '11.x' commands: node test/instrumentation/modules/tedious.test.js -tedious: +tedious-v12-v15: name: tedious node: '>=12.3.0' versions: '12.x || 13.x || 14.x' commands: node test/instrumentation/modules/tedious.test.js +tedious: + name: tedious + node: '>=14' + versions: '15.x' + commands: node test/instrumentation/modules/tedious.test.js + cassandra-driver: # 3.1.0 is broken versions: '>=3 <3.1.0 || >3.1.0 <5' commands: node test/instrumentation/modules/cassandra-driver/index.test.js -restify-old: +# Restify +# - restify v14.18.0 +# (https://nodejs.org/api/modules.html#core-modules) +restify-v5-v8: name: restify versions: '>=5.2.0 <8.0.0' + node: '<18.0.0' commands: - node test/instrumentation/modules/restify/basic.test.js - node test/instrumentation/modules/restify/set-framework.test.js -restify-new: +restify-v8-v9: name: restify - node: '>=8.6.0' - versions: '>=8.0.0' + versions: '>=8.0.0 <9.0.0' + node: '>=8.6.0 <18.0.0' + commands: + - node test/instrumentation/modules/restify/basic.test.js + - node test/instrumentation/modules/restify/set-framework.test.js +restify-v9-v10: + name: restify + versions: '>=9.0.0' + node: '>=14.18.0 <18.0.0' + commands: + - node test/instrumentation/modules/restify/basic.test.js + - node test/instrumentation/modules/restify/set-framework.test.js +restify: + name: restify + versions: '>=10.0.0' + node: '>=14.18.0' commands: - node test/instrumentation/modules/restify/basic.test.js - node test/instrumentation/modules/restify/set-framework.test.js @@ -543,11 +497,19 @@ aws-sdk: # Maintenance note: This should be updated periodically using: # ./dev-utils/aws-sdk-tav-versions.sh # - # Test v2.858.0, every N=54 of 275 releases, and current latest. - versions: '2.858.0 || 2.912.0 || 2.966.0 || 2.1020.0 || 2.1074.0 || 2.1128.0 || 2.1132.0 || >2.1132.0 <3' + # Test v2.858.0, every N=72 of 365 releases, and current latest. + versions: '2.858.0 || 2.930.0 || 2.1002.0 || 2.1074.0 || 2.1146.0 || 2.1218.0 || 2.1222.0 || >2.1222.0 <3' commands: - node test/instrumentation/modules/aws-sdk/aws4-retries.test.js - node test/instrumentation/modules/aws-sdk/s3.test.js - node test/instrumentation/modules/aws-sdk/sns.test.js - node test/instrumentation/modules/aws-sdk/sqs.test.js - node test/instrumentation/modules/aws-sdk/dynamodb.test.js + +# - undici@4.7.0 added its diagnostics_channel support. +# - In undici@4.7.1 the `request.origin` property was added, which we need +# in the 'undici:request:create' diagnostic message. +undici: + versions: '>=4.7.1 <6' + commands: node test/instrumentation/modules/undici/undici.test.js + node: '>=12.18' diff --git a/CHANGELOG.asciidoc b/CHANGELOG.asciidoc index cd523245e69..2aa4d7a5b05 100644 --- a/CHANGELOG.asciidoc +++ b/CHANGELOG.asciidoc @@ -32,6 +32,244 @@ Notes: === Node.js Agent version 3.x +[[release-notes-3.41.1]] +==== 3.41.1 2022/12/21 + +[float] +===== Bug fixes + +* Fix a bug in span compression with sending spans that were buffered for + possible compression. Before this fix, in some cases a compressible span could + be sent *twice* or not sent at all. ({pull}3076[#3076]) + + +[[release-notes-3.41.0]] +==== 3.41.0 2022/12/12 + +[float] +===== Features + +* Capture HTTP context (status code, headers, etc.) on transactions (and + captured errors) for Lambda functions triggered by API Gateway. + ({issues}2419[#2419]) + +* Support instrumentation for restify@10. + +[float] +===== Bug fixes + +* Change default `serverUrl` from `http://localhost:8200` to `http://127.0.0.1:8200` + to avoid ambiguity between possible IPv4 and IPv6 DNS-resolved values for "localhost". + APM server only listens on IPv4 by default, so this avoids a possible surprising + mismatch. ({issues}3045[#3045]) + +* Add `tracestate` to the `TransactionOptions` TypeScript type for + `apm.startTransaction(..., options)`. ({issues}3061[#3061]) + +[float] +===== Chores + +* Mark the published Lambda layer as supporting the recently released + "nodejs18.x" Lambda Runtime (`--compatible-runtimes`). + + +[[release-notes-3.40.1]] +==== 3.40.1 2022/11/15 + +[float] +===== Bug fixes + +* Prevent a possible tight loop in central config fetching. ({issues}3029[#3029]) + + +[[release-notes-3.40.0]] +==== 3.40.0 2022/10/31 + +[float] +===== Features + +* Enable support for redis v4 ({pull}2945[#2945]) + +* preview:[] Next.js server-side instrumentation. See the <> document. ++ +This adds instrumentation of the Next.js dev server (`next dev`) and prod +server (`next start`). The APM transactions for incoming HTTP requests to the +server will be named appropriately based on Next.js's routing -- both for +user page routes (e.g. `GET /a-dynamic-page/[id]`) and for internal Next.js +routes (e.g. `Next.js _next/data route my-page`, +`Next.js Rewrite route /foo -> /bar`). As well, exceptions in server-side code +(e.g. `getServerSideProps`, server-side run page handlers, API handlers) will +be reported. ({pull}2959[#2959]) ++ +This is a technical preview to get feedback from Next.js users. The details on +how exactly the instrumentation works may change in future versions. + +* Improve container-info gathering to support AWS ECS/Fargate environments. + ({issues}2914[#2914]) + +[float] +===== Bug fixes + +* Source lines of context in stacktraces is *no longer reported* for "*.min.js" + files that do not have source-map information. These files are assumed to + be minimized files, for which source line context won't be useful. This + change is to guard against excessively large stacktrace data. + +[float] +===== Chores + +* Add guards to ensure that a crazy `Cache-Control: max-age=...` response + header cannot accidentally result in inappropriate intervals for fetching + central config. The re-fetch delay is clamped to `[5 seconds, 1 day]`. + ({issues}2941[#2941]) + + +[[release-notes-3.39.0]] +==== 3.39.0 2022/10/17 + +[float] +===== Features + +* Improve the granularity of data captured about downstream services, e.g. + databases, for spans that represent an external call (known as "exit spans"). + This data is used for + https://www.elastic.co/guide/en/kibana/current/service-maps.html[Service Maps] + and + https://www.elastic.co/guide/en/kibana/current/dependencies.html[Dependencies] + in the Kibana APM app. ++ +This is handled via the new span `service.target.*` fields that replace the +deprecated `destination.service.resource` field (https://github.com/elastic/apm/blob/main/specs/agents/tracing-spans-service-target.md[spec]). All instrumentations have +been updated to set appropriate service target values. If necessary, e.g. for manual +instrumentation, a new public <> API has been added to specify these values. +({pull}2882[#2882]) ++ +The never-public-but-available `span.setDestinationContext()` has been marked +for removal (using it will `process.emitWarning()`). Users of this internal +method should switch to the public <>. ++ +As part of this change, improvements have been made to some module instrumentations: ++ + ** `redis` and `ioredis`: `span.type` has changed from "cache" to "db" per https://github.com/elastic/apm/blob/main/specs/agents/tracing-instrumentation-db.md#redis[spec] + ** `mongodb`: `span.action` used to be "query", now it will be the mongodb command name, e.g. "find", "insert". + ** `mongodb` and `mongodb-core`: `span.db.instance` is now set to the database name ({issues}1494[#1494]) + ** `mysql` and `mysql2`: `span.db.{instance,user}` are now populated. + ** `@elastic/elasticsearch`: The cluster name is heuristically determined for Elastic Cloud deployments and used for the service target name. + ** `sqs`: `span.destination.{address,port}` are now populated. + ** `pg`: `span.db.{instance,user}` are now populated. + ** `cassandra-driver`: the Cassandra keyspace is captured for service target data, if available. + ** OpenTelemetry Bridge: OTel spans with kind PRODUCER and CLIENT are now handled as exit spans (e.g. span compression could apply). + +* Support instrumentation of `@koa/router` (and `koa-router`) versions 11 and 12. + Contributed by @sibelius. ({issues}2811[#2811]) + +* Support instrumentation of tedious@15. ({pull}2897[#2897]) + +* Improve the captured information for Elasticsearch client instrumentation. + For all outgoing Elasticsearch client requests, the full HTTP url is + now captured (stored in the "url.original" field). For Elasticsearch requests + that do a search, the outgoing request body is captured (to the + "span.db.statement" field) as before, but the format has changed to only + hold the request body. Before this change the "span.db.statement" would + also hold any HTTP query parameters. These are now more naturally captured + in "url.original". ({issues}2019[#2019]) ++ +This change also introduces the <> +configuration option to enable controlling which Elasticsearch REST API +paths are considered for request body capture. ({pull}2873[#2873]) + +* Support instrumenting core modules when require'd with the optional + https://nodejs.org/api/modules.html#core-modules['node:'-prefix]. + For example `require('node:http')` will now be instrumented. + ({issues}2816[#2816]) + +* Agent will delay loading of the `error-callsites` module until agent start time, + and will not load the module if the agent is disabled/inactive. This prevents the + setting of an `Error.prepareStackTrace` handler until necessary for stacktrace + collection. ({issues}2833[#2833] {pull}2906[#2906]) + +* Add `*principal*` pattern to default value for `sanitizeFieldNames` config + var, so that it is more likely to redact authentication-related HTTP headers, + e.g. on Azure. ({issues}2938[#2938]) + +[float] +===== Bug fixes + +* Avoid a possible `RangeError: Maximum call stack size exceeded` in + Span timer handler for exceedingly deep Span trees. ({pull}2939[#2939]) + +* Fix instrumentation of (very old) 'graphql' module versions <=0.9.6. + Instrumentation of these older graphql versions was broken in v3.36.0. + ({pull}2927[#2927]) + +[float] +===== Chores + +* Disable knex instrumentation when not collecting span stack traces + (because there is no point). This is a performance improvement for + Knex usage in the default configuration. ({pull}2879[#2879]) + +* Document and add types for `parent` option to + <>. ({issues}2977[#2977]) + + +[[release-notes-3.38.0]] +==== 3.38.0 2022/08/11 + +[float] +===== Features + +- Add instrumentation for the https://undici.nodejs.org[undici] HTTP client + library. This also adds instrumentation of Node.js v18's + https://nodejs.org/api/all.html#all_globals_fetch[`fetch()`], which uses + undici under the hood. For the instrumentation to work one must be using + node v14.17.0 or later, or have installed the + https://www.npmjs.com/package/diagnostics_channel['diagnostics_channel' polyfill]. + ({issues}2383[#2383]) + +- Added `exitSpanMinDuration` configuration field, allowing end users to + set a time threshold for dropping exit spans. ({pull}2843[#2843]) + +[float] +===== Bug fixes + +- Capturing an error would fail if the Error instance had an attribute that + was an invalid date. ({issues}2030[#2030]) + +- Fix the span for an instrumented S3 ListBuckets API call to not be invalid + for APM server intake. ({pull}2866[#2866]) + +- Fix an issue where the transaction `name` for a trace of a Lambda function + implementing a GraphQL server (e.g. via https://www.apollographql.com/docs/apollo-server/deployment/lambda/[apollo-server-lambda]) + would not get the GraphQL-specific naming. ({issues}2832[#2832]) + + +[[release-notes-3.37.0]] +==== 3.37.0 2022/07/18 + +[float] +===== Features + +- The agent will now use https://nodejs.org/api/async_context.html#class-asynclocalstorage[`AsyncLocalStorage`] + for run-context tracking in new enough versions of Node.js (versions >=14.5 + and >=12.19). This can reduce overhead from using the APM agent, especially in + Promise-heavy applications. ({pull}2786[#2786]) ++ +This also adds a new <> configuration option +to control which mechanism the agent uses for run-context tracking. It replaces +the, now deprecated, <> configuration option. If +you experience problems with the new AsyncLocalStorage-based tracking, you can +restore the older behavior with `contextManager: "asynchooks"`. + +[float] +===== Chores + +- The old "patch" mechanism that the APM agent uses for run-context tracking + (enabled via <>, or previously + enabled via `asyncHooks: false`) is now *deprecated*. It will be removed in a + future major version (after an 18 month deprecation period). + + [[release-notes-3.36.0]] ==== 3.36.0 2022/06/15 @@ -77,7 +315,9 @@ Notes: [float] ===== Features -- Add support for 'knex' version v0.21 to v1 ({issues}2699[#2699]) +- Add support for 'knex' version v0.21 to v1 ({issues}2699[#2699]). + Note that instrumentation of knex >=0.95.0 is not support when using the + deprecated <> configuration option. - Change the instrumentation of SQS- and SNS-triggered AWS Lambda invocations: The special-casing of triggers with a *single* message/record has been @@ -172,10 +412,6 @@ specifying links during span creation (with the limitation that span link [float] ===== Features -- Pulled the `traceparent` NPM module into a local module and replaced the - `random-poly-fill` module with the built in `require('crypto').randomFillSync` - function call ({pull}2669[#2669]) - - Add a `parent` option to `agent.captureError(err[, options][, cb])` to allow passing in a Transaction or Span to use as the parent for the error. Before this change the *current* span or transaction, if any, was always used. diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index d8200c0d8af..b2335321771 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -182,8 +182,6 @@ If you have access to make releases, the process is as follows: [[release-notes-x.y.z]] ==== x.y.z - YYYY/MM/DD ``` - - the EOL table in `docs/upgrading.asciidoc`, if this is a major or minor - release. EOL is 18 months after release date. 1. Ensure PR checks pass, then merge to main. 1. Working on the elastic repo now (not a fork), tag the merged-to-main commit with `git tag vx.y.x && git push origin vx.y.z`. For example: `git tag @@ -192,6 +190,7 @@ If you have access to make releases, the process is as follows: package version. See the appropriate [apm-ci tag build for this repo](https://apm-ci.elastic.co/job/apm-agent-nodejs/job/apm-agent-nodejs-mbp/view/tags/).) 1. Reset the latest major branch (currently `3.x`) to point to the current main, e.g. `git branch -f 3.x main && git push origin 3.x` +1. For major releases, [create an issue](https://github.com/elastic/website-requests/issues/new) to request an update of the [EOL table](https://www.elastic.co/support/eol). ### Past major diff --git a/DEVELOPMENT.md b/DEVELOPMENT.md index d7795c88167..82aad076eab 100644 --- a/DEVELOPMENT.md +++ b/DEVELOPMENT.md @@ -61,68 +61,6 @@ index 94376188..571539aa 100644 # Testing tips -## Integration tests fail - -If the "Integration Tests" check fails for your PR, here are some notes on -debugging that. (The actual ".ci/Jenkinsfile" and apm-integration-testing.git -are the authority. See also the [APM integration test troubleshooting guide](https://github.com/elastic/observability-dev/blob/main/docs/apm/apm-integration-test-troubleshooting-guide.md).) - -The Node.js integration tests are ["test\_nodejs.py" in apm-integration-testing](https://github.com/elastic/apm-integration-testing/blob/main/tests/agent/test_nodejs.py). Roughly speaking, the integration tests: - -- use that repo's scripts to start ES, kibana, apm-server and an [express test app](https://github.com/elastic/apm-integration-testing/blob/main/docker/nodejs/express/app.js) in Docker; -- run apm-integration-testing.git itself in a [Docker](https://github.com/elastic/apm-integration-testing/blob/main/Dockerfile) container and call `make test-agent-nodejs`; -- which runs [`pytest tests/agent/test_nodejs.py ...`](https://github.com/elastic/apm-integration-testing/blob/db7d9a26458832b812577a294e14c365c85001b9/Makefile#L102) - -To reproduce the integration test failure on your dev machine mainly involves -getting the correct settings for that "express test app", in particular -using your PR commit sha. The following boilerplate *should* get you going. -Note that it might likely get out of date: - -1. Create and active a Python virtual env for the Python bits that are used: - - python3 -m venv ./venv - source ./venv/bin/activate - -2. Set the apm-agent-nodejs.git commit you want to use: - - export MYCOMMIT=... # e.g. 3554f05fad6798f229f75eebc07bb66cee918385 - -3. Start the docker containers: - - export BUILD_OPTS="--nodejs-agent-package elastic/apm-agent-nodejs#$MYCOMMIT --opbeans-node-agent-branch $MYCOMMIT --build-parallel" - export ELASTIC_STACK_VERSION=8.0.0 - export COMPOSE_ARGS="${ELASTIC_STACK_VERSION} ${BUILD_OPTS} \ - --with-agent-nodejs-express \ - --no-apm-server-dashboards \ - --no-apm-server-self-instrument \ - --force-build --no-xpack-secure \ - --apm-log-level=trace" - make start-env - - # OR: replace all this with a suitable call to - # 'python3 scripts/compose.py start ...' - - Note: There is an easier way with "ELASTIC_STACK_VERSION=... - APM_AGENT_NODEJS_VERSION=... make start-env" I believe. See the README. - -4. Run the test suite: - - pytest tests/agent/test_nodejs.py -v - -5. (Optional) In a separate terminal, watch the log output from Node.js agent: - - docker logs -f expressapp | ecslog - -6. When done, stop the docker containers via: - - make stop-env - # OR: python3 scripts/compose.py stop - - Also, optionally, turn off the Python virtual env: - - deactivate - - ## How to show the slowest TAV tests from a Jenkins build Jenkins builds of the agent produce a "steps-info.json" artifact that gives @@ -153,6 +91,116 @@ For example: 6626799 FINISHED SUCCESS .ci/scripts/test.sh "8" "apollo-server-express" "false" ``` +## How to troubleshoot `Container "$containerId" is unhealthy.` errors + +Each "Test" step of a Jenkins CI build uses `docker-compose` to start services +for testing, and then runs tests in a `node_tests` container. Starting those +services can fail with the following unhelpful message in the logs: + +``` +[2022-09-19T05:55:43.897Z] .ci/scripts/test.sh:250: main(): docker-compose --no-ansi --log-level ERROR -f .ci/docker/docker-compose-all.yml up --exit-code-from node_tests --remove-orphans --abort-on-container-exit node_tests +... +[2022-09-19T05:56:23.776Z] ERROR: for node_tests Container "2d979b0c797d" is unhealthy. +``` + +That container ID does not identify *which* of the many service containers is +the one to fail. Two ways to troubleshoot this are as follows. + +First, the Jenkins build will include log files of both Docker container logs +and Docker events as Jenkins build artifacts, if the "Test" step failed. These +are collected by filebeat and metricbeat (as configured by the `dockerContext()` +block in ".ci/Jenkinsfile"). Here is an example querying the metricbeat log of +docker events for containers that are failing their healthcheck. This uses +[ecslog](https://github.com/trentm/go-ecslog) to filter and format the log file. + +``` +$ ecslog -k 'docker.healthcheck.failingstreak > 0' -i container.image.name,docker.healthcheck docker-16-release-metricbeat.log-20220927.ndjson +... +[2022-09-27T14:55:53.857Z] (on apm-ci-immutable-ubuntu-1804-1664290081867003348): + container: { + "image": { + "name": "mongo:6" + } + } + docker: { + "healthcheck": { + "status": "unhealthy", + "failingstreak": 49, + "event": { + "start_date": "2022-09-27T14:55:53.012Z", + "end_date": "2022-09-27T14:55:53.153Z", + "exit_code": -1, + "output": "OCI runtime exec failed: exec failed: unable to start container process: exec: \"mongo\": executable file not found in $PATH: unknown" + } + } + } +``` + +Second, most of the time you should be able to reproduce a "Test" step failure +locally. Sometimes this requires forcing an update to the latest Docker image +for some services. + +``` +$ docker system prune --all --force --volumes # heavy-handed purge of all local Docker data +... + +$ .ci/scripts/test.sh -b "release" -t "" "16" # or a different value for "16" depending which stage failed +... +``` + +Once the failure is reproduced, you should be able to use `docker ps -a`, +`docker inspect $containerId` and other regular Docker commands and tooling to +dig into the issue. + + +# Maintenance tips + +## How to check for outdated instrumentation modules + +The APM agent instruments a number of npm modules. Typically, each such +instrumentation supports an explicit version range of the module. This supported +version range is expressed in three places: + +1. Version guard code at the top of the instrumentation module. For example this + at the top of "lib/instrumentation/modules/redis.js" for the `redis` npm + package: + + ```js + if (!semver.satisfies(version, '>=2.0.0 <4.0.0')) { + agent.logger.debug('redis version %s not supported - aborting...', version) + return redis + } + ``` + +2. One or more config blocks in ".tav.yml" that are used to define all versions + of the module that are tested regularly in CI. For example, + + ```yaml + redis: + versions: '>=2.0.0 <4.0.0' + commands: node test/instrumentation/modules/redis.test.js + ``` + +3. The "docs/supported-technologies.asciidoc" document. For example, + + ``` + |https://www.npmjs.com/package/redis[redis] |>=2.0.0 <4.0.0 |Will instrument all queries + ``` + +Two maintenance tasks are (a) to keep these three places in sync and (b) to +know when support for newer versions of module needs to be added. The latter +is partially handled by automated dependabot PRs (see ".github/dependabot.yml"). +Both tasks are also partially supported by the **`./dev-utils/bitrot.js`** tool. +It will list inconsistences between ".tav.yaml" and +"supported-technologies.asciidoc", and will note newer releases of a module +that isn't covered. For example, redis@5 is not covered by the ranges above, +so the tool looks like this: + +``` +% ./dev-utils/bitrot.js +redis bitrot: latest redis@4.3.1 (released 2022-09-06): is not in .tav.yml ranges (>=2.0.0 <4.0.0), is not in supported-technologies.asciidoc ranges (>=2.0.0 <4.0.0) +``` + # Other tips diff --git a/dev-utils/bitrot.js b/dev-utils/bitrot.js new file mode 100755 index 00000000000..e5d20886c85 --- /dev/null +++ b/dev-utils/bitrot.js @@ -0,0 +1,405 @@ +#!/usr/bin/env node + +/* + * Copyright Elasticsearch B.V. and other contributors where applicable. + * Licensed under the BSD 2-Clause License; you may not use this file except in + * compliance with the BSD 2-Clause License. + */ + +'use strict' + +// Compare .tav.yml, docs/supported-technologies.asciidoc, and the current +// releases of modules instrumented by the Elastic Node.js APM agent to: +// - list inconsistencies between TAV-tested and "supported", and +// - list new releases of modules that the agent doesn't yet support +// +// Usage: +// node dev-utils/bitrot.js [MODULE-NAME...] + +const { execSync } = require('child_process') +const fs = require('fs') + +const dashdash = require('dashdash') +const ecsFormat = require('@elastic/ecs-pino-format') +const pino = require('pino') +const semver = require('semver') +const yaml = require('js-yaml') + +let log = null +let rotCount = 0 + +const EXCUSE_FROM_SUPPORTED_TECHNOLOGIES_DOC = { + '@elastic/elasticsearch-canary': true, // we test this for advance warning for '@elastic/elasticsearch', but don't explicitly support the canary versions + 'body-parser': true, // instrumented to support express + finalhandler: true, // instrumented to support express + got: true, // got@12 is pure ESM so we state support up to got@11 only + 'mimic-response': true, // we instrument a single old version to indirectly support an old version of 'got' + mongojs: true, // last release was in 2019, we aren't going to add effort to this module now + '': null +} +const EXCUSE_FROM_TAV = { + '@elastic/elasticsearch-canary': true, + got: true, // got@12 is pure ESM so we state support up to got@11 only + hapi: true, // we deprecated 'hapi' (in favour of '@hapi/hapi') + jade: true, // we deprecated 'jade' (in favour of 'pug') + 'mimic-response': true, // we instrument a single old version to indirectly support an old version of 'got' + mongojs: true, // last release was in 2019, we aren't going to add effort to this module now + '': null +} + +// ---- caching + +const gCachePath = '/tmp/apm-agent-nodejs-bitrot.cache.json' +let gCache = null + +function ensureCacheLoaded (ns) { + if (gCache === null) { + try { + gCache = JSON.parse(fs.readFileSync(gCachePath)) + } catch (loadErr) { + log.debug(loadErr, 'could not load cache') + gCache = {} + } + } + if (!(ns in gCache)) { + gCache[ns] = {} + } + return gCache[ns] +} + +function saveCache () { + if (gCache !== null) { + fs.writeFileSync(gCachePath, JSON.stringify(gCache, null, 2)) + } +} + +// ---- minimal ANSI styling support (from bunyan) + +// http://en.wikipedia.org/wiki/ANSI_escape_code#graphics +// Suggested colors (some are unreadable in common cases): +// - Good: cyan, yellow (limited use, poor visibility on white background), +// bold, green, magenta, red +// - Bad: blue (not visible on cmd.exe), grey (same color as background on +// Solarized Dark theme from , see +// issue #160) +var colors = { + bold: [1, 22], + italic: [3, 23], + underline: [4, 24], + inverse: [7, 27], + white: [37, 39], + grey: [90, 39], + black: [30, 39], + blue: [34, 39], + cyan: [36, 39], + green: [32, 39], + magenta: [35, 39], + red: [31, 39], + yellow: [33, 39] +} + +function stylizeWithColor (str, color) { + if (!str) { return '' } + var codes = colors[color] + if (codes) { + return '\x1B[' + codes[0] + 'm' + str + '\x1B[' + codes[1] + 'm' + } else { + return str + } +} + +function stylizeWithoutColor (str, color) { + return str +} + +let stylize = stylizeWithColor + +// ---- support functions + +function rot (moduleName, s) { + rotCount++ + console.log(`${stylize(moduleName, 'bold')} bitrot: ${s}`) +} + +// Process docs/supported-technologies.asciidoc into an array of: +// {name: '', versions: ''} +// +// Note that the tables in this file don't seem to follow the AsciiDoc table +// syntax described here: +// https://docs.asciidoctor.org/asciidoc/latest/tables/build-a-basic-table/ +// I don't know why the difference. This parsing supports just the limited form +// I see in supported-technologies.asciidoc. +function loadSupportedDoc () { + const docPath = 'docs/supported-technologies.asciidoc' + var html = fs.readFileSync(docPath, 'utf8') + var rows = [] + var state = null // null | 'thead' | 'tbody' + html.split(/\n/g).forEach(function (line) { + if (!line.startsWith('|')) { + + } else if (state === null) { + if (line.startsWith('|===')) { + state = 'thead' + } + } else if (state === 'thead') { + state = 'tbody' + } else if (state === 'tbody') { + if (line.startsWith('|===')) { + state = null + } else { + // Examples: + // |https://www.npmjs.com/package/generic-pool[generic-pool] | ^2.0.0 \|\| ^3.1.0 |Used by a lot of ... + // |https://www.npmjs.com/package/bluebird[bluebird] |>=2.0.0 <4.0.0 | + var escapePlaceholder = '6B1EC7E1-B273-40E9-94C4-197A59B55E24' + var cells = line + .trim() + .slice(1) // remove leading '|' + .replace(/\\\|/g, escapePlaceholder) + .split(/\s*\|\s*/g) + .map(c => c.replace(new RegExp(escapePlaceholder, 'g'), '|')) + .filter(c => c.length > 0) + rows.push(cells) + } + } + }) + // log.trace({rows}, `${docPath} table rows`) + + // The tables in supported-technologies.asciidoc have the module + // name in the first column, and version range in the second. There + // are two forms of the first cell to parse: + // [ '<>', '>=9.0.0 <19.0.0' ], + // [ '<>', '>=17.9.0 <20.0.0' ], + // [ '<> via koa-router or @koa/router', '>=5.2.0 <10.0.0' ], + // [ '<>', '>=5.2.0' ], + // [ '<>', 'N/A' ], + // ['https://www.npmjs.com/package/jade[jade]', '>=0.5.6'] + // + // The entries in the "Frameworks" table use the names of internal links in + // these docs. The anchor name is *sometimes* the same name as the npm + // module, but sometimes not. + var results = [] + let match + rows.forEach(function (row) { + if (row[1] === 'N/A') { + + } else if (row[0].includes('<<')) { + match = /^\s*<<(\w+),(.*?)>>/.exec(row[0]) + if (!match) { + throw new Error(`could not parse this table cell text from docs/supported-technologies.asciidoc: ${JSON.stringify(row[0])}`) + } + var moduleNames + if (match[1] === 'nextjs') { + moduleNames = ['next'] + } else if (match[2] === '@hapi/hapi') { + moduleNames = [match[2]] + } else if (match[1] === 'koa') { + moduleNames = ['koa-router', '@koa/router'] + } else { + moduleNames = [match[1]] + } + moduleNames.forEach(n => { + results.push({ name: n, versions: row[1] }) + }) + } else { + match = /^https:\/\/.*\[(.*)\]$/.exec(row[0]) + if (!match) { + throw new Error(`could not parse this table cell text from docs/supported-technologies.asciidoc: ${JSON.stringify(row[0])}`) + } + results.push({ name: match[1], versions: row[1] }) + } + }) + return results +} + +function getNpmInfo (name) { + const CACHE_TIMEOUT_MS = 30 * 60 * 1000 // 30 minutes + const cache = ensureCacheLoaded('npmInfo') + const cacheEntry = cache[name] + if (cacheEntry) { + if (cacheEntry.timestamp + CACHE_TIMEOUT_MS > Date.now()) { + return cacheEntry.value + } else { + delete cache[name] + } + } + + // Limited security guard on exec'ing given `name`. + const PKG_NAME_RE = /^(@[\w_.-]+\/)?([\w_.-]+)$/ + if (!PKG_NAME_RE.test(name)) { + throw new Error(`${JSON.stringify(name)} does not look like a valid npm package name`) + } + + const stdout = execSync(`npm info -j "${name}"`) + const npmInfo = JSON.parse(stdout) + + cache[name] = { + timestamp: Date.now(), + value: npmInfo + } + saveCache() + return npmInfo +} + +function bitrot (moduleNames) { + log.debug({ moduleNames }, 'bitrot') + var tavYmls = [ + yaml.load(fs.readFileSync('.tav.yml', 'utf8')), + yaml.load(fs.readFileSync('test/instrumentation/modules/next/a-nextjs-app/.tav.yml', 'utf8')) + ] + var supported = loadSupportedDoc() + + // Merge into one data structure we can iterate through. + var rangesFromName = {} + var ensureKey = (name) => { + if (!(name in rangesFromName)) { + rangesFromName[name] = { tavRanges: [], supRanges: [] } + } + } + tavYmls.forEach(tavYml => { + for (const [label, tavInfo] of Object.entries(tavYml)) { + var name = tavInfo.name || label + ensureKey(name) + rangesFromName[name].tavRanges.push(tavInfo.versions) + } + }) + for (const supInfo of supported) { + ensureKey(supInfo.name) + rangesFromName[supInfo.name].supRanges.push(supInfo.versions) + } + + // Reduce to `moduleNames` if given. + if (moduleNames && moduleNames.length > 0) { + var allNames = Object.keys(rangesFromName) + moduleNames.forEach(name => { + if (!(name in rangesFromName)) { + throw new Error(`unknown module name: ${name} (known module names: ${allNames.join(', ')})`) + } + }) + allNames.forEach(name => { + if (!moduleNames.includes(name)) { + delete rangesFromName[name] + } + }) + } + log.debug({ rangesFromName }, 'rangesFromName') + + // Check each module name. + var namesToCheck = Object.keys(rangesFromName).sort() + namesToCheck.forEach(name => { + var npmInfo = getNpmInfo(name) + log.trace({ name, 'dist-tags': npmInfo['dist-tags'], time: npmInfo.time }, 'npmInfo') + + // If the current latest version is in the supported and + // tav ranges, then all is good. + var latest = npmInfo['dist-tags'].latest + var tavGood = false + if (EXCUSE_FROM_TAV[name]) { + tavGood = true + } else { + for (const range of rangesFromName[name].tavRanges) { + if (semver.satisfies(latest, range, { includePrerelease: true })) { + tavGood = true + break + } + } + } + var supGood = false + if (EXCUSE_FROM_SUPPORTED_TECHNOLOGIES_DOC[name]) { + supGood = true + } else { + for (const range of rangesFromName[name].supRanges) { + if (semver.satisfies(latest, range, { includePrerelease: true })) { + supGood = true + break + } + } + } + if (tavGood && supGood) { + log.debug(`latest ${name}@${latest} is in tav and supported ranges (a good thing)`) + return + } + var issues = [] + if (!tavGood) { + issues.push(`is not in .tav.yml ranges (${rangesFromName[name].tavRanges.join(', ')})`) + } + if (!supGood) { + issues.push(`is not in supported-technologies.asciidoc ranges (${rangesFromName[name].supRanges.join(', ')})`) + } + rot(name, `latest ${name}@${latest} (released ${npmInfo.time[latest].split('T')[0]}): ${issues.join(', ')}`) + }) +} + +// ---- mainline + +const options = [ + { + names: ['verbose', 'v'], + type: 'bool', + help: 'Verbose log output. (Pipe to `ecslog` to format.)' + }, + { + names: ['help', 'h'], + type: 'bool', + help: 'Print this help and exit.' + } +] + +function main (argv) { + var parser = dashdash.createParser({ options: options }) + try { + var opts = parser.parse(argv) + } catch (e) { + console.error('help: error: %s', e.message) + process.exit(1) + } + if (opts.help) { + var help = parser.help().trimRight() + process.stdout.write(`Synopsis: + dev-utils/bitrot.js [OPTIONS] + +Description: + Compare ".tav.yml", "docs/supported-technologies.asciidoc" + and the current releases of instrumented modules to list + new releases that are not (yet) supported by the APM agent. + +Options: +${help} + +Exit status: + 0 No bitrot was found. + 1 There was an unexpected error. + 3 Bitrot was found. +`) + process.exit(0) + } + + stylize = process.stdout.isTTY ? stylizeWithColor : stylizeWithoutColor + log = pino({ + name: 'bitrot', + base: {}, // Don't want pid and hostname fields. + level: opts.verbose ? 'trace' : 'warn', + serializers: { + err: pino.stdSerializers.err, + req: pino.stdSerializers.req, + res: pino.stdSerializers.res + }, + ...ecsFormat({ apmIntegration: false }) + }, pino.destination(1)) + + const moduleNames = opts._args + try { + bitrot(moduleNames) + } catch (err) { + log.debug(err) + console.error(`bitrot: error: ${err.message}`) + process.exit(1) + } + + if (rotCount > 0) { + process.exit(3) + } +} + +if (require.main === module) { + main(process.argv) +} diff --git a/dev-utils/gen-notice.sh b/dev-utils/gen-notice.sh index ef209f45895..62f8447cf0d 100755 --- a/dev-utils/gen-notice.sh +++ b/dev-utils/gen-notice.sh @@ -53,13 +53,16 @@ DIST_DIR="$1" [[ -n "$DIST_DIR" ]] || fatal "missing DIST_DIR argument" [[ -f "$DIST_DIR/package.json" ]] || fatal "invalid DIST_DIR: $DIST_DIR/package.json does not exist" -# Guard against accidentally using this script with a too-old npm. -if [[ $(npm --version | cut -d. -f1) -lt 8 ]]; then +# Guard against accidentally using this script with a too-old npm (&2 +} + +# ---- mainline + +# Guard against accidentally using this script with a node that is too old +# for 'js-yaml' (<10). +nodeVer=$(node --version) +nodeMajorVer=$(echo "$nodeVer" | cut -d. -f1 | cut -c2-) +if [[ $nodeMajorVer -lt 10 ]]; then + warn "node version is too old for 'js-yaml': $nodeVer" + exit 0 +fi + +cd $(dirname $0)/../ >/dev/null # Run from repo top dir. +git ls-files | grep '\.yml$' | xargs -n1 ./node_modules/.bin/js-yaml >/dev/null diff --git a/docs/agent-api.asciidoc b/docs/agent-api.asciidoc index 098813bc90b..2f676cb5c19 100644 --- a/docs/agent-api.asciidoc +++ b/docs/agent-api.asciidoc @@ -7,22 +7,7 @@ endif::[] === `Agent` API -NOTE: This is the API documentation for the Elastic APM Node.js Agent. -For getting started, -we recommend that you take a look at our framework specific documentation for either <>, -<>, -<>, -<>, -<>, -or <>. - -The Elastic APM agent for Node.js is a singleton. -You get the agent instance by either requiring `elastic-apm-node` or `elastic-apm-node/start`. -For details on the two approaches, -see the <> guide. - -The agent is also returned by the `start()` function, -which allows you to require and start the agent on the same line: +The Elastic APM Node.js agent is a singleton. You get the agent instance by requiring either `elastic-apm-node` or `elastic-apm-node/start`. The agent is also returned by the <> method, which allows you to require and start the agent on the same line: [source,js] ---- @@ -33,6 +18,7 @@ If you need to access the `Agent` in any part of your codebase, you can simply require `elastic-apm-node` to access the already started singleton. You therefore don't need to manage or pass around the started `Agent` yourself. + [[apm-start]] ==== `apm.start([options])` @@ -40,13 +26,7 @@ Starts the Elastic APM agent for Node.js and returns itself. [IMPORTANT] ==== -Put the call to this function at the very top of your main app file - before requiring any other modules. - -If you are using Babel calling this function will not have the desired effect. -See the <> for details. - -If you are using Typescript the import statement may be removed if it is not used. -It is recommended to use `-r elastic-apm-node/start` when starting the app to avoid this. +For the APM agent to automatically instrument Node.js modules, it must be started before those modules are loaded. See <> for details and possible surprises with compilers/transpilers/bundlers. ==== See the <> for available options. @@ -355,6 +335,8 @@ See the <> method for details about the format ** `skipOutcome` +{type-boolean}+ Whether to skip setting the outcome value for the current span to `failure`. See <> for more information. *Default:* `false`. +** `parent` <> | <> | `null` - A Transaction or Span instance to make the parent of this error. If not given (or `undefined`), then the current span or transaction will be used. If `null` is given, then no span or transaction will be used. [small]#(Added in v3.33.0.)# + * `callback` - Will be called after the error has been sent to the APM Server. It will receive an `Error` instance if the agent failed to send the error, and the id of the captured error. @@ -535,7 +517,9 @@ Sub-millisecond precision can be achieved using decimals. If not provided, the current time will be used -** `childOf` +{type-string}+ The traceparent header received from a remote service. +** `childOf` +{type-string}+ A W3C trace-context "traceparent" string, typically received from a remote service call. + +** `tracestate` +{type-string}+ A W3C trace-context "tracestate" string. ** `links` +{type-array}+ Span links. A transaction can refer to zero or more other transactions or spans (separate diff --git a/docs/configuration.asciidoc b/docs/configuration.asciidoc index c5b57113a0d..fd6b92e6344 100644 --- a/docs/configuration.asciidoc +++ b/docs/configuration.asciidoc @@ -33,7 +33,6 @@ will be normalized to the allowed characters. If the name cannot be inferred from package.json, then a fallback value of "unknown-nodejs-service" is used. -[float] [[service-node-name]] ==== `serviceNodeName` @@ -73,7 +72,7 @@ WARNING: The API key is sent as plain-text in every request to the server, so yo ==== `serverUrl` * *Type:* String -* *Default:* `http://localhost:8200` +* *Default:* `http://127.0.0.1:8200` * *Env:* `ELASTIC_APM_SERVER_URL` The URL to where the APM Server is deployed. @@ -226,20 +225,53 @@ If set to `true`, the client will poll the APM Server regularly for new agent co NOTE: This feature requires APM Server v7.3 or later and that the APM Server is configured with `kibana.enabled: true`. More information is available in {kibana-ref}/agent-configuration.html[APM Agent configuration]. +[[context-manager]] +==== `contextManager` + +[small]#Added in: v3.37.0# + +* *Type:* String +* *Env:* `ELASTIC_APM_CONTEXT_MANAGER` + +This configuration option provides a way to override the APM agent's default +technique for tracking Node.js asynchronous tasks; sometimes referred to as "run +context", "async context", or just "context". Most users should not need to +change this setting. This setting replaces the older +<> configuration option. + +To effectively trace an application, the APM agent needs to track the logical +thread of control through asynchronous tasks. The preferred mechanism for this +is https://nodejs.org/api/async_context.html#class-asynclocalstorage[`AsyncLocalStorage`], +usable in Node.js versions >=14.5 and >=12.19. In older versions of Node, the APM +agent will fallback to using +https://nodejs.org/api/async_hooks.html[`async_hooks`], which can have a higher +performance overhead, especially in Promise-heavy applications. Finally, the APM +agent supports a limited tracking mechanism (named "patch") that monkey-patches +much of the core Node.js API to attempt to follow asynchronous calls. The +"patch" mechanism is limited in usage and coverage (for example, it cannot +track `async/await` usage), is *deprecated* and will be removed in a future +major version. + +Supported values for `contextManager` are: + +- `"asynclocalstorage"` - Use the `AsyncLocalStorage` mechanism, if able. Otherwise it will fallback to using `async_hooks`. +- `"asynchooks"` - Use the `async_hooks` mechanism. (Using this value will restore the agent behavior from before v3.37.0.) +- `"patch"` - Use the limited monkey-patching mechanism. Note that this mechanism is now *deprecated*. (Using this value is the equivalent of using `asyncHooks: false` in agent versions before v3.37.0.) + + [[async-hooks]] ==== `asyncHooks` +[small]#Deprecated in: v3.37.0, use <># + * *Type:* Boolean -* *Default:* `true` * *Env:* `ELASTIC_APM_ASYNC_HOOKS` -A boolean specifying if the agent should use the experimental https://nodejs.org/api/async_hooks.html[Async Hooks] API found in Node.js version 8.2.0 and above. -This setting has no effect when running a Node.js version older than 8.2.0. +This option is *deprecated* -- use <> instead. -If you experience any issues related to using Async Hooks, -please https://github.com/elastic/apm-agent-nodejs/issues[open an issue]. +The equivalent to `asyncHooks: false` is `contextManager: 'patch'`. +The equivalent to `asyncHooks: true` is to leave both `asyncHooks` and `contextManager` empty, for the default behavior. -Note that not all core Node.js API's can be instrumented without the use of Async Hooks if running Node.js 8 or above. [[transaction-ignore-urls]] ==== `transactionIgnoreUrls` @@ -606,7 +638,7 @@ A capture location stack trace is never generated for uncaught exceptions. * *Type:* Duration * *Default:* `'-1s'` (never capture span stack traces) -* *Env:* `ELASTIC_APM_STACK_TRACE_MIN_DURATION` +* *Env:* `ELASTIC_APM_SPAN_STACK_TRACE_MIN_DURATION` * <> *Central config name:* `span_stack_trace_min_duration` Use this option to control if stack traces are never captured for spans (the @@ -925,7 +957,7 @@ The value should include a time suffix ('m' for minutes, 's' for seconds, or [[sanitize-field-names]] ==== `sanitizeFieldNames` * *Type:* Array -* *Default:* `['password', 'passwd', 'pwd', 'secret', '*key', '*token*', '*session*', '*credit*', '*card*', '*auth*', 'set-cookie', 'pw', 'pass', 'connect.sid']` +* *Default:* `['password', 'passwd', 'pwd', 'secret', '*key', '*token*', '*session*', '*credit*', '*card*', '*auth*', 'set-cookie', '*principal*', 'pw', 'pass', 'connect.sid']` * *Env:* `ELASTIC_APM_SANITIZE_FIELD_NAMES` * <> *Central config name:* `sanitize_field_names` @@ -1114,7 +1146,7 @@ module.exports = { // Use if APM Server requires a token secretToken: '', - // Set custom APM Server URL (default: http://localhost:8200) + // Set custom APM Server URL (default: http://127.0.0.1:8200) serverUrl: '' } ---- @@ -1227,7 +1259,7 @@ views. * *Default:* `true` * *Env:* `ELASTIC_APM_SPAN_COMPRESSION_ENABLED` -Setting this option to false will disable the span compression feature. Span compression reduces the collection, processing, and storage overhead, and removes clutter from the UI. The tradeoff is that some information, such as DB statements of all the compressed spans, will not be collected. +Setting this option to false will disable the https://www.elastic.co/guide/en/apm/guide/current/span-compression.html[Span compression] feature. Span compression reduces the collection, processing, and storage overhead, and removes clutter from the UI. The tradeoff is that some information, such as DB statements of all the compressed spans, will not be collected. Example usage: @@ -1298,3 +1330,41 @@ require('elastic-apm-node').start({ opentelemetryBridgeEnabled: true }) ---- + +[[exit-span-min-duration]] +==== `exitSpanMinDuration` +* *Type:* String +* *Default:* `0ms` +* *Env:* `ELASTIC_APM_EXIT_SPAN_MIN_DURATION` +* <> *Central config name:* `exit_span_min_duration` + +Sets the minimum duration of exit spans. If an exit span's duration is less than +this threshold the agent will attempt to drop the span and not send it. + +In some cases exit spans will not be discarded. Spans that propagate the trace +context to downstream services, such as outgoing HTTP requests, will not be +discarded. However, external calls that don't propagate context, such as calls +to a database, can be discarded using this threshold. + +Additionally, spans that lead to an error will not be discarded. + +Example usage: + +[source,js] +---- +require('elastic-apm-node').start({ + exitSpanMinDuration: '10ms' +}) +---- + +[[elasticsearch-capture-body-urls]] +==== `elasticsearchCaptureBodyUrls` + +* *Type:* Array of wildcard patterns +* *Default:* `['*/_search', '*/_search/template', '*/_msearch', '*/_msearch/template', '*/_async_search', '*/_count', '*/_sql', '*/_eql/search' ]` +* *Env:* `ELASTIC_APM_ELASTICSEARCH_CAPTURE_BODY_URLS` +// Spec name: elasticsearch_capture_body_urls + +The URL path patterns for which the APM agent will capture the request body of outgoing requests to Elasticsearch made with the `@elastic/elasticsearch` module (or the legacy `elasticsearch` module). The default setting captures the body for https://www.elastic.co/guide/en/elasticsearch/reference/current/rest-apis.html[Elasticsearch REST APIs] making a search. + +The captured request body (if any) is stored on the `span.db.statement` field. Captured request bodies are truncated to a maximum length defined by <>. diff --git a/docs/custom-stack.asciidoc b/docs/custom-stack.asciidoc index d8b1d0c783e..52f97fd6a37 100644 --- a/docs/custom-stack.asciidoc +++ b/docs/custom-stack.asciidoc @@ -51,7 +51,7 @@ var apm = require('elastic-apm-node').start({ // Use if APM Server uses API keys for authentication apiKey: '', - // Set custom APM Server URL (default: http://localhost:8200) + // Set custom APM Server URL (default: http://127.0.0.1:8200) serverUrl: '', }) ---- diff --git a/docs/express.asciidoc b/docs/express.asciidoc index 564853e5481..a4693529c8f 100644 --- a/docs/express.asciidoc +++ b/docs/express.asciidoc @@ -49,7 +49,7 @@ const apm = require('elastic-apm-node').start({ // Use if APM Server uses API keys for authentication apiKey: '', - // Set custom APM Server URL (default: http://localhost:8200) + // Set custom APM Server URL (default: http://127.0.0.1:8200) serverUrl: '', }) diff --git a/docs/fastify.asciidoc b/docs/fastify.asciidoc index 0e5e9f26df7..fd322a49e55 100644 --- a/docs/fastify.asciidoc +++ b/docs/fastify.asciidoc @@ -50,7 +50,7 @@ var apm = require('elastic-apm-node').start({ // Use if APM Server uses API keys for authentication apiKey: '', - // Set custom APM Server URL (default: http://localhost:8200) + // Set custom APM Server URL (default: http://127.0.0.1:8200) serverUrl: '', }) diff --git a/docs/hapi.asciidoc b/docs/hapi.asciidoc index fc263fbb9db..06b70ce7ec8 100644 --- a/docs/hapi.asciidoc +++ b/docs/hapi.asciidoc @@ -46,7 +46,7 @@ const apm = require('elastic-apm-node').start({ // Use if APM Server uses API keys for authentication apiKey: '', - // Set custom APM Server URL (default: http://localhost:8200) + // Set custom APM Server URL (default: http://127.0.0.1:8200) serverUrl: '', }) diff --git a/docs/images/nextjs-my-app-screenshot.png b/docs/images/nextjs-my-app-screenshot.png new file mode 100644 index 00000000000..f2bdc6eb183 Binary files /dev/null and b/docs/images/nextjs-my-app-screenshot.png differ diff --git a/docs/images/node_release_schedule.svg b/docs/images/node_release_schedule.svg index 8cd3cc71cff..c33ada9a3cb 100644 --- a/docs/images/node_release_schedule.svg +++ b/docs/images/node_release_schedule.svg @@ -1,184 +1 @@ - - - - - - - - - -Apr 2019 - - - -Jul 2019 - - - -Oct 2019 - - - -Jan 2020 - - - -Apr 2020 - - - -Jul 2020 - - - -Oct 2020 - - - -Jan 2021 - - - -Apr 2021 - - - - - -Master - - - -Node.js 6 - - - -Node.js 8 - - - -Node.js 10 - - - -Node.js 11 - - - -Node.js 12 - - - -Node.js 13 - - - -Node.js 14 - - - - - - -unstable - - - - -maintenance - - - - -maintenance - - - - -maintenance - - - - -active - - - - -maintenance - - - - -current - - - - -maintenance - - - - -active - - - - -current - - - - -maintenance - - - - -current - - - - -active - - - - -current - - - +Jul 2022Oct 2022Jan 2023Apr 2023Jul 2023Oct 2023Jan 2024Apr 2024Jul 2024Oct 2024Jan 2025Apr 2025MasterNode.js 14Node.js 16Node.js 18Node.js 19Node.js 20unstablemaintenancemaintenanceactivemaintenanceactivecurrentcurrentmaintenanceactivecurrent \ No newline at end of file diff --git a/docs/index.asciidoc b/docs/index.asciidoc index 4869b24fb42..812bed368bb 100644 --- a/docs/index.asciidoc +++ b/docs/index.asciidoc @@ -2,14 +2,14 @@ include::{asciidoc-dir}/../../shared/versions/stack/current.asciidoc[] include::{asciidoc-dir}/../../shared/attributes.asciidoc[] :type-string: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Data_structures#String_type[] -:type-string-array: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Data_structures#String_type[] +:type-string-array: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Data_structures#String_type[] :type-array: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array[] :type-boolean: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Data_structures#Boolean_type[] :type-object: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object[] :type-number: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Data_structures#Number_type[] :type-function: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Function[] :type-error: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Error[] -:type-undefined: https://developer.mozilla.org/en-US/docs/Glossary/Undefined[] +:type-undefined: https://developer.mozilla.org/en-US/docs/Glossary/Undefined[] :type-incomingmessage: https://nodejs.org/api/http.html#http_class_http_incomingmessage[] :type-serverresponse: https://nodejs.org/api/http.html#http_class_http_serverresponse[] diff --git a/docs/koa.asciidoc b/docs/koa.asciidoc index b345a6c376b..6153c4b4847 100644 --- a/docs/koa.asciidoc +++ b/docs/koa.asciidoc @@ -13,7 +13,7 @@ include::./shared-set-up.asciidoc[tag=introduction] Koa doesn't have a built-in router, so we can't support Koa directly since we rely on router information for full support. -We currently support the most popular Koa router called https://github.com/alexmingoia/koa-router[koa-router]. +We currently support the most popular Koa router called https://github.com/koajs/koa-router[koa-router]. If you use another router with your Koa application, please https://github.com/elastic/apm-agent-nodejs/issues[open an issue] so we can make sure to support your stack. @@ -54,7 +54,7 @@ const apm = require('elastic-apm-node').start({ // Use if APM Server uses API keys for authentication apiKey: '', - // Set custom APM Server URL (default: http://localhost:8200) + // Set custom APM Server URL (default: http://127.0.0.1:8200) serverUrl: '', }) diff --git a/docs/lambda.asciidoc b/docs/lambda.asciidoc index f506e41a29b..b4033509964 100644 --- a/docs/lambda.asciidoc +++ b/docs/lambda.asciidoc @@ -33,23 +33,24 @@ include::{apm-aws-lambda-root}/docs/lambda-selector/lambda-attributes-selector.a include::{apm-aws-lambda-root}/docs/lambda-selector/extension-arn-replacement.asciidoc[] include::./lambda/nodejs-arn-replacement.asciidoc[] -Both the {apm-guide-ref}/aws-lambda-arch.html[APM Lambda Extension] and the Node.js APM Agent are added to your Lambda function as https://docs.aws.amazon.com/lambda/latest/dg/invocation-layers.html[AWS Lambda Layers]. Therefore, you need to add the corresponding Layer ARNs (identifiers) to your Lambda function. +Both the {apm-lambda-ref}/aws-lambda-arch.html[{apm-lambda-ext}] and the Node.js APM Agent are added to your Lambda function as https://docs.aws.amazon.com/lambda/latest/dg/invocation-layers.html[AWS Lambda Layers]. Therefore, you need to add the corresponding Layer ARNs (identifiers) to your Lambda function. include::{apm-aws-lambda-root}/docs/add-extension/add-extension-layer-widget.asciidoc[] [float] ==== Step 3: Configure APM on AWS Lambda -The APM Lambda Extension and the APM Node.js agent are configured through environment variables on the AWS Lambda function. +The {apm-lambda-ext} and the APM Node.js agent are configured through environment variables on the AWS Lambda function. For the minimal configuration, you will need the _APM Server URL_ to set the destination for APM data and an _{apm-guide-ref}/secret-token.html[APM Secret Token]_. If you prefer to use an {apm-guide-ref}/api-key.html[APM API key] instead of the APM secret token, use the `ELASTIC_APM_API_KEY` environment variable instead of `ELASTIC_APM_SECRET_TOKEN` in the following configuration. -For production environments, we recommend {apm-guide-ref}/aws-lambda-secrets-manager.html[using the AWS Secrets Manager to store your APM authentication key] instead of providing the secret value as plaintext in the environment variables. +For production environments, we recommend {apm-lambda-ref}/aws-lambda-secrets-manager.html[using the AWS Secrets Manager to store your APM authentication key] instead of providing the secret value as plaintext in the environment variables. include::./lambda/configure-lambda-widget.asciidoc[] +<1> The {apm-lambda-ref}/aws-lambda-config-options.html#_elastic_apm_send_strategy[`ELASTIC_APM_SEND_STRATEGY`] defines when APM data is sent to your Elastic APM backend. To reduce the execution time of your lambda functions, we recommend to use the `background` strategy in production environments with steady load scenarios. -You can optionally <> or the {apm-guide-ref}/aws-lambda-config-options.html[configuration of the APM Lambda Extension]. +You can optionally <> or the {apm-lambda-ref}/aws-lambda-config-options.html[configuration of the {apm-lambda-ext}]. That's it. After following the steps above, you're ready to go! Your Lambda function invocations should be traced from now on. @@ -89,4 +90,3 @@ include::./shared-set-up.asciidoc[tag=error-logging] * System and custom metrics are not collected for Lambda functions. This is both because most of those are irrelevant and because the interval-based event sending model is not suitable for FaaS environments. - diff --git a/docs/lambda/configure-lambda.asciidoc b/docs/lambda/configure-lambda.asciidoc index 589229ba89b..af4755248a5 100644 --- a/docs/lambda/configure-lambda.asciidoc +++ b/docs/lambda/configure-lambda.asciidoc @@ -12,6 +12,7 @@ To configure APM through the AWS Management Console: NODE_OPTIONS = -r elastic-apm-node/start # use this exact fixed value ELASTIC_APM_LAMBDA_APM_SERVER = # this is your APM Server URL ELASTIC_APM_SECRET_TOKEN = # this is your APM secret token +ELASTIC_APM_SEND_STRATEGY = background <1> ---- -- @@ -27,7 +28,7 @@ To configure APM through the AWS command line interface execute the following co [source,bash] ---- aws lambda update-function-configuration --function-name yourLambdaFunctionName \ - --environment "Variables={NODE_OPTIONS=-r elastic-apm-node/start,ELASTIC_APM_LAMBDA_APM_SERVER=,ELASTIC_APM_SECRET_TOKEN=}" + --environment "Variables={NODE_OPTIONS=-r elastic-apm-node/start,ELASTIC_APM_LAMBDA_APM_SERVER=,ELASTIC_APM_SECRET_TOKEN=,ELASTIC_APM_SEND_STRATEGY=background}" <1> ---- // end::cli-with-agent[] @@ -49,6 +50,7 @@ Resources: NODE_OPTIONS: -r elastic-apm-node/start ELASTIC_APM_LAMBDA_APM_SERVER: ELASTIC_APM_SECRET_TOKEN: + ELASTIC_APM_SEND_STRATEGY: background <1> ... ---- @@ -68,6 +70,7 @@ functions: NODE_OPTIONS: -r elastic-apm-node/start ELASTIC_APM_LAMBDA_APM_SERVER: ELASTIC_APM_SECRET_TOKEN: + ELASTIC_APM_SEND_STRATEGY: background <1> ... ---- @@ -86,6 +89,7 @@ resource "aws_lambda_function" "your_lambda_function" { NODE_OPTIONS = "-r elastic-apm-node/start" ELASTIC_APM_LAMBDA_APM_SERVER = "" ELASTIC_APM_SECRET_TOKEN = "" + ELASTIC_APM_SEND_STRATEGY = "background" <1> } } } @@ -103,6 +107,7 @@ You can use one of the other options (through AWS Web Console, AWS CLI, etc.) to NODE_OPTIONS = -r elastic-apm-node/start # use this exact fixed value ELASTIC_APM_LAMBDA_APM_SERVER = # this is your APM Server URL ELASTIC_APM_SECRET_TOKEN = # this is your APM secret token +ELASTIC_APM_SEND_STRATEGY = background <1> ---- // end::container-with-agent[] diff --git a/docs/nextjs.asciidoc b/docs/nextjs.asciidoc new file mode 100644 index 00000000000..3b8c83cdc65 --- /dev/null +++ b/docs/nextjs.asciidoc @@ -0,0 +1,208 @@ +:framework: Next.js + +[[nextjs]] + +ifdef::env-github[] +NOTE: For the best reading experience, +please view this documentation at https://www.elastic.co/guide/en/apm/agent/nodejs/current/nextjs.html[elastic.co] +endif::[] + +=== Get started with Next.js + +The Elastic APM Node.js agent can be used to trace the Next.js server (`next +start` or `next dev`) that runs your application without the need for code +changes to your app. The APM transactions for incoming HTTP requests to the +server will be named for the https://nextjs.org/docs/routing/introduction[pages] +and https://nextjs.org/docs/api-routes/introduction[API endpoints] in your +application, as well as for internal routes used by Next.js. Errors in code run +on the server will be reported for viewing in the Kibana APM app. + +Note that the Node.js APM agent can only instrument _server-side_ code. To +monitor the client-side parts of a Next.js application, see the +{apm-rum-ref}/intro.html[Elastic RUM agent]. + +NOTE: preview:[] This Next.js instrumentation is a _technical preview_ while we +solicit feedback from Next.js users. If you are a Next.js user, please help us +provide a better Next.js observability experience with your feedback on our +https://discuss.elastic.co/tags/c/apm/nodejs[Discuss forum]. + + +[float] +[[nextjs-prerequisites]] +==== Prerequisites + +You need an APM Server to send APM data to. Follow the +{apm-guide-ref}/apm-quick-start.html[APM Quick start] if you have not set one up +yet. You will need your *APM server URL* and an APM server *secret token* (or +*API key*) for configuring the APM agent below. + +You will also need a Next.js application to monitor. If you do not have an +existing one to use, you can use the following to create a starter app (see +https://nextjs.org/docs/getting-started[Next.js Getting Started docs] for more): + +[source,bash] +---- +npx create-next-app@latest # use the defaults +cd my-app +---- + +You can also take a look at and use this https://github.com/elastic/apm-agent-nodejs/tree/main/examples/nextjs/[Next.js + Elastic APM example app]. + +[float] +[[nextjs-setup]] +==== Step 1: Add the APM agent dependency + +Add the `elastic-apm-node` module as a dependency to your application: + +[source,bash] +---- +npm install elastic-apm-node --save # or 'yarn add elastic-apm-node' +---- + + +[float] +==== Step 2: Start the APM agent + +For the APM agent to instrument the Next.js server, it needs to be started +before the Next.js server code is loaded. The best way to do so is by using +Node's https://nodejs.org/api/cli.html#-r---require-module[`--require`] option +to load the "elastic-apm-node/start-next.js" module -- this will start the agent +(plus a little more for Next.js integration). + +Edit the "dev" and "start" scripts in your "package.json" as follows: + +[source,json] +---- +{ + // ... + "scripts": { + "dev": "NODE_OPTIONS=--require=elastic-apm-node/start-next.js next dev", + "build": "next build", + "start": "NODE_OPTIONS=--require=elastic-apm-node/start-next.js next start", + "lint": "next lint" + }, + // ... +} +---- + + +[float] +==== Step 3: Configure the APM agent + +The APM agent can be +<> +with environment variables or with an "elastic-apm-node.js" module in the +current working directory. Note that because the APM agent is being loaded +before the Next.js server, the +https://nextjs.org/docs/basic-features/environment-variables[Next.js-supported +".env" files] *cannot* be used to configure the APM agent. We will use an +"elastic-apm-node.js" file here. + +Create an "elastic-apm-node.js" file in the application root with the APM server +URL and secret token values from the <> section above: + +[source,javascript] +---- +// elastic-apm-node.js +module.exports = { + serverUrl: 'https://...', // E.g. https://my-deployment-name.apm.us-west2.gcp.elastic-cloud.com + secretToken: '...' +} +---- + +The equivalent using environment variables is: + +[source,bash] +---- +export ELASTIC_APM_SERVER_URL='https://...' +export ELASTIC_APM_SECRET_TOKEN='...' +---- + +See the <> for full details on supported configuration variables. + + +[float] +==== Step 4: Start your Next.js app + +[source,bash] +---- +npm run dev # or 'npm run build && npm start' for the production server +---- + +Open in your browser to load your Next.js app. If you +used the `create-next-app` tool above, it defines an +http://localhost:3000/api/hello[/api/hello] API endpoint. You can provide some +artificial load by running the following in a separate terminal: + +[source,bash] +---- +while true; do sleep 1; curl -i http://localhost:3000/api/hello; done +---- + +Visit your Kibana APM app and, after a few seconds, you should see a service +entry for your Next.js app. The service name will be pulled from the "name" +field in "package.json". It can be overriden with +<>. Here is an example: + +image::./images/nextjs-my-app-screenshot.png[Kibana APM app showing Next.js my-app] + + +[float] +[[nextjs-limitations]] +==== Limitations and future work + +This Next.js instrumentation has some limitations to be aware of. + +Next.js build tooling bundles dependencies (using Webpack) for both client _and_ +server-side code execution. The Node.js APM agent does not work when bundled. +See <> for details. The implication for Next.js instrumentation +is that you cannot directly import and use the APM agent in your code. That +means that using the <> for manual instrumentation is not currently +possible. + +This instrumentation supports naming APM transactions for many internal Next.js +routes. For example, for +https://nextjs.org/docs/basic-features/data-fetching/get-server-side-props[server-side +rendering (SSR)] Next.js client code will make requests of the form `GET +/next/_data/$buildId/$page.json`, for which the APM agent names the transaction +`Next.js _next/data route $page`. However, there is a limitation with the +Next.js "public folder catchall" route. HTTP requests that resolve to files in +your "public/" directory, for example `GET /favicon.ico`, will result in a +transaction named `GET unknown route`. See <> below. + +If you notice other limitations or have any suggestions, please give us feedback +on our https://discuss.elastic.co/tags/c/apm/nodejs[Discuss forum]. + + +[float] +[[nextjs-performance-monitoring]] +==== Performance monitoring + +Elastic APM automatically measures the performance of your Next.js application. +It records spans for database queries, external HTTP requests, and other slow +operations that happen during requests to your Next.js app. Spans are grouped in +transactions -- by default one for each incoming HTTP request. + +[float] +[[nextjs-unknown-routes]] +==== Unknown routes + +include::./shared-set-up.asciidoc[tag=unknown-roots] + +[float] +[[nextjs-filter-sensitive-information]] +==== Filter sensitive information + +include::./shared-set-up.asciidoc[tag=filter-sensitive-info] + +[float] +[[nextjs-compatibility]] +==== Compatibility + +include::./shared-set-up.asciidoc[tag=compatibility-link] + +[float] +[[nextjs-troubleshooting]] +==== Troubleshooting + +include::./shared-set-up.asciidoc[tag=troubleshooting-link] diff --git a/docs/opentracing.asciidoc b/docs/opentracing.asciidoc index 3972b0e9e9d..a59c06b9725 100644 --- a/docs/opentracing.asciidoc +++ b/docs/opentracing.asciidoc @@ -75,7 +75,7 @@ const agent = require('elastic-apm-node').start({ // Use if APM Server uses API keys for authentication apiKey: '', - // Set custom APM Server URL (default: http://localhost:8200) + // Set custom APM Server URL (default: http://127.0.0.1:8200) serverUrl: '', }) diff --git a/docs/performance-tuning.asciidoc b/docs/performance-tuning.asciidoc index 0a66bb9edb4..7a588db4c3d 100644 --- a/docs/performance-tuning.asciidoc +++ b/docs/performance-tuning.asciidoc @@ -30,7 +30,7 @@ Applications with a high request rate and/or many spans per incoming request may want to lower the the sampling rate. For example, see the example below to trace 20% of incoming requests. Note that incoming HTTP requests that are part of a <> already have the sampling -decision made -- the `tracestate` header includes a +decision made -- the `traceparent` header includes a https://w3c.github.io/trace-context/#sampled-flag[sampled flag]. In these cases the `transactionSampleRate` setting will not apply. diff --git a/docs/redirects.asciidoc b/docs/redirects.asciidoc index 1740e7c6e58..00a1b74a54d 100644 --- a/docs/redirects.asciidoc +++ b/docs/redirects.asciidoc @@ -41,4 +41,12 @@ This endpoint has moved. Please see <>. [role="exclude",id="get-started"] === Get started -This page has moved. Please see <>. \ No newline at end of file +This page has moved. Please see <>. + +[role="exclude",id="es-modules"] +=== ES Modules support + +This page has moved. + +- For details on ES Modules (ESM) support, see <>. +- For information on using the APM agent with TypeScript, see <>. diff --git a/docs/restify.asciidoc b/docs/restify.asciidoc index 341b80abcc2..bbc7b4b8456 100644 --- a/docs/restify.asciidoc +++ b/docs/restify.asciidoc @@ -46,7 +46,7 @@ const apm = require('elastic-apm-node').start({ // Use if APM Server uses API keys for authentication apiKey: '', - // Set custom APM Server URL (default: http://localhost:8200) + // Set custom APM Server URL (default: http://127.0.0.1:8200) serverUrl: '', }) diff --git a/docs/set-up.asciidoc b/docs/set-up.asciidoc index 4a294edfda3..4f3a377cff8 100644 --- a/docs/set-up.asciidoc +++ b/docs/set-up.asciidoc @@ -1,17 +1,20 @@ [[set-up]] == Set up the Agent -To get you off the ground, we've prepared guides for setting up the Agent with a few different popular web frameworks: +To get you off the ground, we've prepared guides for setting up the Agent with a few different popular web frameworks and technologies: // This tagged region is used throughout the documentation to link to the framework guides // Updates made here will be applied elsewhere as well. // tag::web-frameworks-list[] +* <> * <> +* <> * <> * <> +* <> * <> -* <> -* <> +* <> +* <> // end::web-frameworks-list[] Alternatively, you can <>. @@ -25,46 +28,297 @@ Other useful documentation includes: * <> * <> +include::./lambda.asciidoc[] + include::./express.asciidoc[] +include::./fastify.asciidoc[] + include::./hapi.asciidoc[] include::./koa.asciidoc[] +include::./nextjs.asciidoc[] + include::./restify.asciidoc[] -include::./fastify.asciidoc[] +include::./typescript.asciidoc[] include::./custom-stack.asciidoc[] -include::./lambda.asciidoc[] [[starting-the-agent]] === Starting the agent -IMPORTANT: The Elastic APM agent for Node.js needs to be started as the first thing in your application - *before any other module is required/imported*. -This means that you should probably require and start it in your applications main file (usually `index.js`, `server.js`, or `app.js`). +There are a few ways to start the Node.js APM agent. Choose the one that works best for you. The most important considerations for selecting a method are: + +- ensuring the APM agent starts early enough, and +- having a convenient way to configure the agent. + +For the Node.js APM agent to be able to fully function, it *must be started before `require(...)` statements for other modules*. The APM agent automatically instruments modules by interposing itself in the import process. If a given module is imported before the APM agent has started, then it won't be able to instrument that module. + + +==== Start methods + +[[start-option-require-and-start]] +===== `require('elastic-apm-node').start(...)` + +The most common way to start the APM agent is to require the `elastic-apm-node` module and call the <> method at the top of your main module. This allows you to use any of the methods to <>. + +[source,js] +---- +const apm = require('elastic-apm-node').start({ + // Add configuration options here. +}); + +// Application main code goes here. +---- -There are two ways to start the Elastic APM agent for Node.js: -* Require the `elastic-apm-node` module and call the <> function on the returned agent: -+ +[[start-option-require-start-module]] +===== `require('elastic-apm-node/start')` + +Another way to start the agent is with the `elastic-apm-node/start` module that imports and _starts_ the agent. + [source,js] ---- -var apm = require('elastic-apm-node').start({ - // add configuration options here +const apm = require('elastic-apm-node/start'); + +// Application main code goes here. +---- + +This start method exists for those that use a tool like Babel or esbuild to translate/transpile from code using ES modules (as in the following example) to code using CommonJS. It ensures that the APM agent is started before other imports in the same file. See <> below for details. + +[source,js] +---- +import 'elastic-apm-node/start'; + +// Application main code goes here. +---- + +A limitation of this approach is that you cannot configure the agent with an options object, but instead have to rely on <>, such as setting `ELASTIC_APM_...` environment variables. + + +[[start-option-node-require-opt]] +===== `node -r elastic-apm-node/start ...` + +Another way to start the agent is with the `-r elastic-apm-node/start` https://nodejs.org/api/cli.html#-r---require-module[command line option to `node`]. This will import and start the APM agent before your application code starts. This method allows you to enable the agent _without touching any code_. This is the recommended start method for <> and for tracing <>. + +[source,bash] +---- +node -r elastic-apm-node/start app.js +---- + +The `-r, --require` option can also be specified via the https://nodejs.org/api/cli.html#node_optionsoptions[`NODE_OPTIONS` environment variable]: + +[source,bash] +---- +# export ELASTIC_APM_... # Configure the agent with envvars. +export NODE_OPTIONS='-r elastic-apm-node/start' +node app.js +---- + + +[[start-option-separate-init-module]] +===== Separate APM init module + +If you want to avoid <> but still want the flexibility of passing a config object to the <>, then a good option is to write a separate JavaScript or TypeScript module that starts the agent, and import *that* init module at the top of your main file. For example: + +[source,ts] +---- +// initapm.ts +import apm from 'elastic-apm-node'; +apm.start({ + serverUrl: 'https://...', + secretToken: '...', + // ... }) ---- -* Require the `elastic-apm-node/start` script: -+ + +[source,ts] +---- +// main.ts +import 'initapm' + +// Application code starts here. +---- + + +[[start-gotchas]] +==== Start gotchas + +This section shows some sometimes subtle surprises starting the APM agent with some technologies. A general troubleshooting tip for using the agent with any build tool/system that produces compiled JavaScript is to look at the compiled JavaScript to see what is actually being executed by `node`. + +[[start-esm-imports]] +===== Hoisted ES module imports + +When using a tool like Babel or esbuild to translate/transpile from code using ES modules (i.e. `import ...` statements) to code using CommonJS (i.e. `require(...)`), all imports are "hoisted" to the top of a module, properly following ECMAScript module (ESM) semantics. This means the `apm.start()` method is called too late—*after* the `http` module has been imported. + +For example, running Babel on the following code does not initiate APM early enough: + [source,js] ---- -var apm = require('elastic-apm-node/start') +import apm from 'elastic-apm-node'; +apm.start() // This does not work. + +import http from 'http'; +// ... +---- + +Babel translates this to the equivalent of: + +[source,js] +---- +var apm = require('elastic-apm-node'); +var http = require('http'); +apm.start() // This is started too late. +// ... +---- + +The <> fixes this problem. The following will work: + +[source,js] +---- +import 'elastic-apm-node/start'; // This works. +import http from 'http'; +// ... +---- + +A more complete example using Babel is https://github.com/elastic/apm-agent-nodejs/tree/main/test/babel[here]. + +The same is true for ES module usage translated by esbuild (as explained well in https://esbuild.github.io/content-types/#real-esm-imports[the esbuild docs here]). Notably, TypeScript does _not_ following ECMAScript module semantics in this regard. + +Another good option is <> and import that first. + + +[[start-typescript]] +===== TypeScript gotcha + +TypeScript is a language that compiles to JavaScript, via the `tsc` TypeScript compiler, and is then executed via `node` (or some other JavaScript interpreter). Sometimes the produced JavaScript has a gotcha for using this APM agent. TypeScript assumes that module imports do not have side-effects, so it will https://github.com/Microsoft/TypeScript/wiki/FAQ#why-are-imports-being-elided-in-my-emit[elide the following import] if the `apm` variable is not used: + +[source,js] +---- +import apm from 'elastic-apm-node/start'; // Be careful +---- + +One can avoid that elision with: + +[source,js] +---- +import 'elastic-apm-node/start'; +---- + +Or with something like this: + +[source,js] +---- +import apm from 'elastic-apm-node/start'; apm; // Ensure import is kept for its side-effect. +---- + + +[[start-bundlers]] +===== Bundlers and APM + +JavaScript Bundlers are tools that bundle up a number of JavaScript files into one, or a few, JavaScript files to be executed. Often they also include other features such as compilation (from newer to older JavaScript syntax, from TypeScript), tree-shaking (removing sections of code that are unused), minifying, bundling of CSS/images, etc. There are many bundler tools, including: https://webpack.js.org/[Webpack], https://esbuild.github.io/[esbuild], https://rollupjs.org/[Rollup], https://parceljs.org/[Parcel]. + +The main use case for bundlers is for improving performance in _browser apps_, where reducing the size and number of separate files helps with network and CPU overhead. The use case is typically less strong for server-side JavaScript code executed with `node`. However, some tooling will use bundlers for server-side JavaScript, not necessarily for the _bundling_ but for some of the other features. + +Unfortunately, *using a bundler typically breaks the APM agent*. Bundling multiple modules into a single file necessarily means replacing `require(...)` calls with custom bundler code that handles returning the module object. But the APM agent relies on those `require(...)` calls to instrument a module. There is no automatic fix for this. The workaround is to: + +1. exclude the `elastic-apm-node` APM agent module from the bundle; and +2. optionally exclude other modules from the bundle that you would like the APM agent to instrument. + +"Excluding" a module 'foo' from the bundle (Webpack calls these "externals") means that a `require('foo')` expects "node_modules/foo/..." to exist at runtime. This means that you need to deploy both your bundle file(s) _and_ the excluded modules. This may or may not defeat your reasons for using a bundler. + +The rest of this section shows how to configure externals with various bundlers. If you know of a mechanism for a bundler that we haven't documented, please https://github.com/elastic/apm-agent-nodejs/blob/main/CONTRIBUTING.md#contributing-to-the-apm-agent[let us know.] + +[[start-webpack]] +===== Webpack + +Webpack supports https://webpack.js.org/configuration/externals/["externals"] configuration options to exclude specific modules from its bundle. At a minimum, the 'elastic-apm-agent' module must be made external. In addition, any modules that you want the APM agent to instrument (e.g. a database client) must also be made external. The easiest way to do this is to *use the https://github.com/liady/webpack-node-externals['webpack-node-externals'] module to make all of "node_modules/..." external*. + +For webpack@5 ensure your "webpack.config.js" has the following: + +[source,js] +---- +const nodeExternals = require('webpack-node-externals'); + +module.exports = { + // ... + + // Set these so Webpack emits code using Node's CommonJS + // require functions and knows to use Node's core modules. + target: 'node', + externalsPresets: { + node: true + }, + + // This tells Webpack to make everything under + // "node_modules/" external. + externals: [nodeExternals()], +}; +---- + +For webpack@4, the `externalsPresets` config var does not exist, so use: + +[source,js] +---- +const nodeExternals = require('webpack-node-externals'); + +module.exports = { + // ... + + target: 'node', + externals: [nodeExternals()], +}; +---- + + +[[start-esbuild]] +===== esbuild + +Esbuild supports marking modules/files as https://esbuild.github.io/api/#external["external"] to the bundle. At a minimum, the 'elastic-apm-agent' module must be made external for the APM agent to work. In addition, any modules that you want the APM agent to instrument (e.g. a database client) must also be made external. + +Here is an example build script for "package.json" to bundle a Node.js application (with "src/index.js" as the entry point, targetting node v14.x, and ensuring that the `pg` PostgreSQL module is instrumented): + +[source,json] +---- +{ + "scripts": { + "build": "esbuild src/index.js --outdir=dist --bundle --sourcemap --minify --platform=node --target=node14 --external:elastic-apm-node --external:pg" + } +} +---- + +This can be invoked via: + +[source,bash] +---- +npm run build +---- + +Or the esbuild configuration can be put into a build script and invoked via `node esbuild.build.js`. + +[source,js] +---- +// esbuild.build.js +require('esbuild').build({ + entryPoints: ['./src/index.js'], + outdir: 'dist', + bundle: true, + platform: 'node', + target: 'node14', + sourcemap: true, + minify: true, + external: ['elastic-apm-node', 'pg'] +}).catch(() => process.exit(1)) +---- + +An alternative to manually listing specific dependencies as "external" is to use the following esbuild option to exclude *all* dependencies: + +[source,bash] +---- +esbuild ... --external:'./node_modules/*' ---- -+ -If using this approach, -you can't configure the agent by passing in an options object, -but instead have to rely on <>. -NOTE: If you are using Babel, you need to use the `elastic-apm-node/start` approach. -<>. +A more complete example using esbuild and the APM agent is https://github.com/elastic/apm-agent-nodejs/tree/main/examples/esbuild/[here]. diff --git a/docs/setup.asciidoc b/docs/setup.asciidoc index b14f2a088c6..e595ebb2b47 100644 --- a/docs/setup.asciidoc +++ b/docs/setup.asciidoc @@ -12,7 +12,6 @@ Use the following pages to configure the APM Agent. * <> ** <> ** <> -* <> * <> [[configuring-the-agent]] @@ -71,7 +70,7 @@ require('elastic-apm-node').start({ // Use if APM Server uses API keys for authentication apiKey: '', - // Set custom APM Server URL (default: http://localhost:8200) + // Set custom APM Server URL (default: http://127.0.0.1:8200) serverUrl: '', // Only activate the agent if it's running in production @@ -86,51 +85,6 @@ require('elastic-apm-node').start({ The Node.js agent looks for a file named `elastic-apm-node.js` in the current working directory. You can specify a custom path for this file with the <> configuration option. -[[es-modules]] -=== ES Modules support - -If you are using ES Modules, -for instance with the help of Babel, -TypeScript, -or the `--experimental-modules` flag for Node.js, -all import statements are evaluated prior to calling any functions. -**In this case, you can't configure the agent by passing a configuration object to the `start` function, -as this call will happen after all of the modules have been loaded.** -Instead you need to import the `elastic-apm-node/start` module: - -[source,js] ----- -import apm from 'elastic-apm-node/start' ----- - -Now, configure the agent using the environment variables associated with each <>, -or use the optional <>. - -To explicitly start the agent, import `elastic-apm-node` and call the `apm.start()` method with the -<>. - -[float] -[[esm-typescript]] -==== TypeScript - -If you're using TypeScript, -the default import will not work unless you use the `esModuleInterop` https://www.typescriptlang.org/docs/handbook/compiler-options.html[compiler option]. -If you don't want to switch on `esModuleInterop`, -you instead have to import the agent like so: - -[source,js] ----- -import * as apm from 'elastic-apm-node/start' ----- - - -If your "tsconfig.json" sets https://www.typescriptlang.org/tsconfig#skipLibCheck[`skipLibCheck`] false (or excludes it), then you will need to install `@types/node` to avoid compile errors: - -[source,bash] ----- -npm install --save-dev @types/node ----- - include::./configuration.asciidoc[] diff --git a/docs/span-api.asciidoc b/docs/span-api.asciidoc index 0e813d013d5..e42a7876e21 100644 --- a/docs/span-api.asciidoc +++ b/docs/span-api.asciidoc @@ -215,3 +215,19 @@ However, for exit spans that represent an HTTP request, the `outcome` is based o * `outcome` +{type-string}+ The `setOutcome` method allows an end user to override the Node.js agent's default setting of a span's `outcome` property. The `setOutcome` method accepts a string of either `success`, `failure`, or `unknown`, and will force the agent to report this value for a specific span. + +[[span-setservicetarget]] +==== `span.setServiceTarget(type, name)` + +[small]#Added in: v3.39.0# + +* `type` +{type-string}+ | null The target service type, usually the same value as `span.subtype`, e.g. "mysql". +* `name` +{type-string}+ | null The target service name, an optional scoping of the service. For databases it is typically the database name. + +Manually set the `service.target.type` and `service.target.name` fields that identify a downstream service. They are used for https://www.elastic.co/guide/en/kibana/current/service-maps.html[Service Maps] and https://www.elastic.co/guide/en/kibana/current/dependencies.html[Dependencies] in the Kibana APM app. The values are only used for "exit" spans -- spans representing outgoing communication, marked with `exitSpan: true` at span creation. + +If false-y values (e.g. `null`) are given for both `type` and `name`, then `service.target` will explicitly be excluded from this span. This may impact Service Maps and other Kibana APM app reporting for this service. + +If this method is not called, the service target values are inferred from other span fields (https://github.com/elastic/apm/blob/main/specs/agents/tracing-spans-service-target.md#field-values[spec]). + +`service.target.*` fields are ignored for APM Server before v8.3. diff --git a/docs/supported-technologies.asciidoc b/docs/supported-technologies.asciidoc index 6a76f877818..26c846f5088 100644 --- a/docs/supported-technologies.asciidoc +++ b/docs/supported-technologies.asciidoc @@ -7,24 +7,74 @@ endif::[] == Supported technologies -Support for the Elastic APM Node.js agent follows the support schedule of Node.js itself to the end-of-life period of each version after its maintenance term. +The Elastic APM Node.js Agent automatically instruments various APIs in Node.js core and third-party frameworks and packages. This page lists all supported technologies and version ranges. + + +[float] +[[compatibility-node]] +=== Node.js versions + +Support for the Elastic APM Node.js agent follows the https://nodejs.org/en/about/releases/[support schedule of Node.js itself] +to the end-of-life period of each version after its maintenance term. Versions of Node.js past their end-of-life date are not supported. image::./images/node_release_schedule.svg[Node.js release schedule] -NOTE: The agent makes use of the experimental Node.js core API https://nodejs.org/api/async_hooks.html[Async Hooks]. -If you experience any issues related to using Async Hooks, -you can always disable the use of this API by setting the <> config option to `false`. -Note however, -that not all core Node.js API's can be instrumented without the use of Async Hooks. +The current APM agent version (3.x) works with Node.js versions back to v8.6. We will only break support for older Node.js versions with a major version release of the APM agent. + +[float] +[[compatibility-esm]] +=== ES Modules + +The Elastic APM Node.js agent does _not yet support automatically instrumenting +https://nodejs.org/api/esm.html#modules-ecmascript-modules[ECMAScript module imports (ESM)]_, i.e. modules that are loaded via `import ...` statements. It currently only instruments https://nodejs.org/api/modules.html#modules-commonjs-modules[CommonJS module imports], i.e. modules loaded via `require(...)`. + +For example, in the following code the `http` module *is* instrumented: + +[source,js] +---- +require('elastic-apm-node').start(/* ... */); + +const http = require('http'); // CommonJS require +const server = http.createServer((req, res) => { + res.statusCode = 200; + res.end('pong'); +}); +server.listen(3000); +---- + +But in the following code the `http` module *is not* instrumented: + +[source,js] +---- +import apm from 'elastic-apm-node/start'; + +import http from 'http'; // ESM import +const server = http.createServer((req, res) => { + res.statusCode = 200; + res.end('pong'); +}); +server.listen(3000); +---- + +However, if you are using TypeScript or JavaScript that is _compiled/translated/transpiled to CommonJS-using JavaScript_ via tools like Babel, Webpack, esbuild, etc., then using `import ...` in your source code is fine. To ensure your compiler is generating JS that uses CommonJS imports, use the following settings: + +- For TypeScript, use https://www.typescriptlang.org/tsconfig#module[`"module": "commonjs"` in your "tsconfig.json"] (a https://github.com/tsconfig/bases/blob/main/bases/node16.json[complete tsconfig.json example]). +- For Babel, use https://babeljs.io/docs/en/babel-preset-env#modules[`"modules": "commonjs"` in your Babel config] (https://github.com/elastic/apm-agent-nodejs/blob/main/test/babel/.babelrc[for example]). +- For Webpack, use `target: 'node', externalsPresets: { node: true }` in your "webpack.config.js". +- For esbuild, use `--platform=node --target=node...` options to `esbuild` (https://github.com/elastic/apm-agent-nodejs/blob/main/examples/esbuild/package.json#L7[for example]). + +The ESM limitation only affects the agent's automatic instrumentation. Other functionality -- such as metrics collection, manual instrumentation and error capture -- still works when using ES modules. Support for ES modules is planned for a future version of the APM agent. + [float] [[elastic-stack-compatibility]] === Elastic Stack Compatibility -This agent is compatible with {apm-guide-ref}[APM Server] v6.5 and above. -For support for previous releases of the APM Server, -use version {apm-node-ref-1x}[1.x] of the agent. +// See the APM agent compatibility table: https://www.elastic.co/guide/en/apm/guide/current/agent-server-compatibility.html + +This agent is compatible with {apm-guide-ref}[APM Server] v6.6 and above. + [float] [[compatibility-frameworks]] @@ -32,22 +82,19 @@ use version {apm-node-ref-1x}[1.x] of the agent. Though you can use Elastic APM <>, we automate a few things for the most popular Node.js modules. - These are the frameworks that we officially support: [options="header"] |======================================================================= -|Framework |Version -|<> |^4.0.0 -|<> |>=9.0.0 <19.0.0; Deprecated. No longer tested. -|<> |>=17.9.0 <21.0.0 -|<> via koa-router or @koa/router |>=5.2.0 <10.0.0 -2+|Koa doesn't have a built in router, so we can't support Koa directly since we rely on -router information for full support. We currently support the most popular Koa router called -https://github.com/alexmingoia/koa-router[koa-router]. -|<> |>=5.2.0 -|<> |>=1.0.0; see also https://www.fastify.io/docs/latest/Reference/LTS/[Fastify's own LTS documentation] -|<> |N/A +| Framework | Version | Note +| <> | N/A | +| <> | ^4.0.0 | +| <> | >=1.0.0 | See also https://www.fastify.io/docs/latest/Reference/LTS/[Fastify's own LTS documentation] +| <> | >=17.9.0 <22.0.0 | +| <> | >=9.0.0 <19.0.0 | Deprecated. No longer tested. +| <> via koa-router or @koa/router | >=5.2.0 <13.0.0 | Koa doesn't have a built in router, so we can't support Koa directly since we rely on router information for full support. We currently support the most popular Koa router called https://github.com/koajs/koa-router[koa-router]. +| <> | >=11.1.0 <14.0.0 | (Technical Preview) This instruments Next.js routing to name transactions for incoming HTTP transactions; and reports errors in user pages. It supports the Next.js production server (`next start`) and development server (`next dev`). See the <>. +| <> | >=5.2.0 <11.0.0 | |======================================================================= [float] @@ -60,8 +107,8 @@ These modules override that behavior to give better insights into specialized HT [options="header"] |======================================================================= |Module |Version |Note -|https://www.npmjs.com/package/express-graphql[express-graphql] |>=0.6.1 <0.13.0 |Will name all transactions by the GraphQL query name. (There is https://github.com/elastic/apm-agent-nodejs/issues/2516[known issue with node <10.4].) -|https://www.npmjs.com/package/apollo-server-express[apollo-server-express] |^2.0.4 <4|Will name all transactions by the GraphQL query name +|https://www.npmjs.com/package/express-graphql[express-graphql] |>=0.6.1 <0.13.0 |Will name all transactions by the GraphQL query name. There is a https://github.com/elastic/apm-agent-nodejs/issues/2516[known issue with node <10.4]. Versions before 0.10.0 are no longer tested. +|https://www.npmjs.com/package/apollo-server-express[apollo-server-express] |>=2.0.4 <4|Will name all transactions by the GraphQL query name. Versions before 2.9.6 are no longer tested. |======================================================================= [float] @@ -80,49 +127,49 @@ The Node.js agent will automatically instrument the following modules to give yo |https://www.npmjs.com/package/graphql[graphql] |>=0.7.0 <17 |Will instrument all queries |https://www.npmjs.com/package/handlebars[handlebars] |* |Will instrument compile and render calls |https://www.npmjs.com/package/jade[jade] |>=0.5.6 |Will instrument compile and render calls; Deprecated. No longer tested. Use pug. -|https://www.npmjs.com/package/pug[pug] |'>=0.1.0' |Will instrument compile and render calls -|https://www.npmjs.com/package/ioredis[ioredis] |>=2.0.0 <6.0.0 |Will instrument all queries -|https://www.npmjs.com/package/memcached[memcached] |>=2.2.0  |Will instrument all commands. -|https://www.npmjs.com/package/mongodb-core[mongodb-core] |>=1.2.19 <4 |Will instrument all queries. +|https://www.npmjs.com/package/pug[pug] |>=0.1.0 |Will instrument compile and render calls +|https://www.npmjs.com/package/ioredis[ioredis] |>=2.0.0 <6.0.0 |Will instrument all queries +|https://www.npmjs.com/package/memcached[memcached] |>=2.2.0 |Will instrument all commands. +|https://www.npmjs.com/package/mongodb-core[mongodb-core] |>=1.2.19 <4 |Will instrument all queries. A lot of higher level MongoDB modules use mongodb-core, so those should be supported as well. |https://www.npmjs.com/package/mongodb[mongodb] |>=2.0.0 <3.3.0 |Supported via mongodb-core -|https://www.npmjs.com/package/mongodb[mongodb] |^3.3.0 <5 |Will instrument all queries +|https://www.npmjs.com/package/mongodb[mongodb] |>=3.3.0 <5 |Will instrument all queries |https://www.npmjs.com/package/mongojs[mongojs] |>=1.0.0 <2.7.0 |Supported via mongodb-core |https://www.npmjs.com/package/mongoose[mongoose] |>=4.0.0 <5.7.0 |Supported via mongodb-core |https://www.npmjs.com/package/mysql[mysql] |^2.0.0 |Will instrument all queries |https://www.npmjs.com/package/mysql2[mysql2] |>=1.0.0 <3.0.0 |Will instrument all queries -|https://www.npmjs.com/package/pg[pg] |>=4.0.0 <9.0.0 |Will instrument all queries -|https://www.npmjs.com/package/redis[redis] |>=2.0.0 <4.0.0 |Will instrument all queries -|https://www.npmjs.com/package/tedious[tedious] |>=1.9 <15.0.0 | (Excluding v4.0.0.) Will instrument all queries -|https://www.npmjs.com/package/ws[ws] |>=1.0.0 <8.0.0 |Will instrument outgoing WebSocket messages +|https://www.npmjs.com/package/pg[pg] |>=4.0.0 <9.0.0 |Will instrument all queries +|https://www.npmjs.com/package/redis[redis] |>=2.0.0 <5.0.0 |Will instrument all queries +|https://www.npmjs.com/package/tedious[tedious] |>=1.9 <16.0.0 | (Excluding v4.0.0.) Will instrument all queries +|https://www.npmjs.com/package/undici[undici] | >=4.7.1 <6 | Will instrument undici HTTP requests, except HTTP CONNECT. Requires node v14.17.0 or later, or the user to have installed the https://www.npmjs.com/package/diagnostics_channel['diagnostics_channel' polyfill]. +|https://www.npmjs.com/package/ws[ws] |>=1.0.0 <8.0.0 |Will instrument outgoing WebSocket messages |======================================================================= [float] [[compatibility-better-stack-traces]] ==== Better Stack Traces -When viewing a span in Elastic APM, -you'll see where in your code you initiated the span (e.g. a database query). +The APM agent <> to capture +span stack traces, to show where in your code a span (e.g. for a database query) +was initiated. -Given the async nature of Node.js, -it's not possible for us to see further back than the last async boundary. -We therefore make sure to monitor as close to your code as possible. -But some modules will interfere with this monitoring by injecting an async call between your code and the actual monitored function. +Given the async nature of Node.js, it's not possible for the APM agent to see +further back than the last async boundary. Modules that happen to have an async +boundary between a call from your application code and the action that leads +to an APM span will limit the utility of these span stack traces. -We monitor these "offending" modules directly to give you a better experience. - -The modules and versions listed below are the ones we support. -If you use an unsupported version you might not be able to see your own code in the spans. -This does not impact the stability of your application in any way - only the collected metrics. +The modules listed below are those that the APM agent instruments to provide +more useful span stack traces -- ones that point to your application code -- +when enabled. If you don't see your own code in spans, please create a new topic in the https://discuss.elastic.co/c/apm[Elastic APM discuss forum] and include information about your dependencies. [options="header"] |================================================= -|Module |Version -|https://www.npmjs.com/package/knex[knex] |>=0.9.0 <1.0.0 +|Module |Version |Note +|https://www.npmjs.com/package/knex[knex] |>=0.9.0 <1.0.0 | Provides better span stack traces for 'pg' and 'mysql' spans. Instrumentation of Knex >=0.95.0 is not supported when using the deprecated <> configuration option. |================================================= [float] @@ -143,8 +190,8 @@ please create a new topic in the https://discuss.elastic.co/c/apm[Elastic APM di [options="header"] |======================================================================= |Module |Version |Note -|https://www.npmjs.com/package/bluebird[bluebird] |>=2.0.0 <4.0.0 | +|https://www.npmjs.com/package/bluebird[bluebird] |>=2.0.0 <4.0.0 | |https://www.npmjs.com/package/generic-pool[generic-pool] | ^2.0.0 \|\| ^3.1.0 |Used by a lot of database modules like for instance "pg" -|https://www.npmjs.com/package/express-queue[express-queue] |>=0.0.11 <1.0.0 | +|https://www.npmjs.com/package/express-queue[express-queue] |>=0.0.11 <1.0.0 | |======================================================================= diff --git a/docs/troubleshooting.asciidoc b/docs/troubleshooting.asciidoc index a771bce0a2a..892f7946926 100644 --- a/docs/troubleshooting.asciidoc +++ b/docs/troubleshooting.asciidoc @@ -106,7 +106,7 @@ Elastic APM is incorrectly configured: serverUrl "..." contains an invalid port! [float] [[missing-performance-metrics]] -==== No performance metrics sent to APM Server +==== No metrics or trace data is sent to APM Server Errors get tracked just fine, but you don't see any performance metrics or trace data. @@ -115,9 +115,7 @@ Make sure that the agent is *both required and started at the very top of your m It's important that the agent is started before any other modules are `require`d. If not, the agent will not be able to hook into any modules and will not be able to measure the performance of your application. - -IMPORTANT: If you are using Babel / ES modules in your application, -make sure you have read about the <>. +See <> for a number of possible surprises in correctly starting the APM agent when used with some compilers or bundlers. [float] diff --git a/docs/typescript.asciidoc b/docs/typescript.asciidoc new file mode 100644 index 00000000000..83cf19ba50f --- /dev/null +++ b/docs/typescript.asciidoc @@ -0,0 +1,85 @@ +[[typescript]] + +ifdef::env-github[] +NOTE: For the best reading experience, +please view this documentation at https://www.elastic.co/guide/en/apm/agent/nodejs/current/typescript.html[elastic.co] +endif::[] + +=== Get started with TypeScript + +The Elastic APM Node.js agent is implemented in vanilla JavaScript, but includes TypeScript types. This document shows how to integrate the APM agent with your TypeScript project. + +A small, complete example project can be found https://github.com/elastic/apm-agent-nodejs/tree/main/examples/typescript[here]. + + +[float] +[[typescript-installation]] +==== Installation + +Add `elastic-apm-node` as a dependency to your application, and possibly `@types/node` as a dev-dependency for type checking: + +[source,bash] +---- +npm install --save elastic-apm-node +npm install --save-dev @types/node <1> +---- +<1> Installing `@types/node` can be skipped if you use https://www.typescriptlang.org/tsconfig#skipLibCheck[`skipLibCheck: true`] in your "tsconfig.json". + + +[float] +[[typescript-tsconfig]] +==== tsconfig compiler options + +The TypeScript authors strongly recommend that you use the https://www.typescriptlang.org/tsconfig/#esModuleInterop[`"esModuleInterop": true`] option in your "tsconfig.json". In case you do not, then the "default" import of the agent will not work, so instead of using `import apm from 'elastic-apm-node/start'` or similar, you will have to use: + +[source,js] +---- +import * as apm from 'elastic-apm-node/start' // if using esModuleInterop:false +---- + +Currently the Elastic APM Node.js agent <>, so for full APM support you will need to tell TypeScript to generate JavaScript using CommonJS modules via the https://www.typescriptlang.org/tsconfig/#module[`"module": "commonjs"`] compiler option. + +[source,json] +---- +// tsconfig.json +{ + "compilerOptions": { + "module": "commonjs", + "esModuleInterop": true, + "moduleResolution": "node" + // ... + } +} +---- + +The current TypeScript https://github.com/tsconfig/bases#node-10-tsconfigjson[recommended tsconfigs for node] use options that work with the APM agent. + + +[float] +[[typescript-start]] +==== Starting the agent + +For the APM agent to be able to automatically instrument modules it *must be started before you import other modules*. This means that you should probably import and start the agent in your application's main file (usually `index.js`, `server.js` or `app.js`). One way to do this is as follows. + +[source,typescript] +---- +import 'elastic-apm-node/start' <1> + +// Application code starts here. +// ... +---- +<1> This start method requires you to use environment variables to configure the agent. See <> for all the ways to start the agent. + +Pay special attention to <> where the TypeScript compiler can throw away your import in the generated JavaScript. + + +[float] +[[typescript-next-steps]] +==== Next steps + +The APM agent will now trace your application, monitor performance, and record any uncaught exceptions. Refer to the following documentation to configure and use the APM agent. + +* <> +* <> + +include::./shared-set-up.asciidoc[tag=troubleshooting-link] diff --git a/docs/upgrading.asciidoc b/docs/upgrading.asciidoc index bbc2dcb1eab..d125b5314a1 100644 --- a/docs/upgrading.asciidoc +++ b/docs/upgrading.asciidoc @@ -31,51 +31,6 @@ We love all our products, but sometimes we must say goodbye to a release so that forward on future development and innovation. Our https://www.elastic.co/support/eol[End of life policy] defines how long a given release is considered supported, as well as how long a release is considered still in active development or maintenance. -The table below is a simplified description of this policy. - -[options="header"] -|==== -|Agent version |EOL Date |Maintained until -|3.36.x |2023-12-15 |3.37.0 -|3.35.x |2023-12-01 |3.36.0 -|3.34.x |2023-11-26 |3.35.0 -|3.33.x |2023-11-05 |3.34.0 -|3.32.x |2023-10-27 |3.33.0 -|3.31.x |2023-09-23 |3.32.0 -|3.30.x |2023-09-10 |3.31.0 -|3.29.x |2023-08-10 |3.30.0 -|3.28.x |2023-08-08 |3.29.0 -|3.27.x |2023-07-17 |3.28.0 -|3.26.x |2023-06-07 |3.27.0 -|3.25.x |2023-05-24 |3.26.0 -|3.24.x |2023-05-09 |3.25.0 -|3.23.x |2023-04-25 |3.24.0 -|3.22.x |2023-04-21 |3.23.0 -|3.21.x |2023-03-15 |3.22.0 -|3.20.x |2023-02-12 |3.21.0 -|3.19.x |2023-02-05 |3.20.0 -|3.18.x |2023-01-20 |3.19.0 -|3.17.x |2023-01-05 |3.18.0 -|3.16.x |2022-12-14 |3.17.0 -|3.15.x |2022-11-19 |3.16.0 -|3.14.x |2022-10-19 |3.15.0 -|3.13.x |2022-10-06 |3.14.0 -|3.12.x |2022-08-22 |3.13.0 -|3.11.x |2022-08-08 |3.12.0 -|3.10.x |2022-07-11 |3.11.0 -|3.9.x |2022-05-30 |3.10.0 -|3.8.x |2022-05-09 |3.9.0 -|3.7.x |2022-02-10 |3.8.0 -|3.6.x |2021-11-18 |3.7.0 -|3.5.x |2021-09-09 |3.6.0 -|3.4.x |2021-08-21 |3.5.0 -|3.3.x |2021-06-12 |3.4.0 -|3.2.x |2021-05-18 |3.3.0 -|3.1.x |2021-04-16 |3.2.0 -|3.0.x |2021-03-30 |3.1.0 -|2.17.x |2021-03-19 |(now EOL) -|1.14.x |2020-05-06 |(now EOL) -|==== include::./upgrade-to-v1.asciidoc[Upgrade to v1.x] diff --git a/examples/esbuild/.npmrc b/examples/esbuild/.npmrc new file mode 100644 index 00000000000..43c97e719a5 --- /dev/null +++ b/examples/esbuild/.npmrc @@ -0,0 +1 @@ +package-lock=false diff --git a/examples/esbuild/README.md b/examples/esbuild/README.md new file mode 100644 index 00000000000..1a083d1e921 --- /dev/null +++ b/examples/esbuild/README.md @@ -0,0 +1,47 @@ +This directory includes an example showing how the esbuild bundler +(https://esbuild.github.io) can be configured to be used with the Elastic +Node.js APM agent. + +For the APM agent to work with esbuild you must: + +- mark 'elastic-apm-node' as external so it is *not* included in the bundle; and +- any modules that you would like the APM agent to instrument (e.g. a database + client) must also be marked as external + +This can be done by passing this to the `esbuild` command: + + --external:elastic-apm-node --external: + +or if you are using an esbuild build script: + + require('esbuild').build({ + ... + external: ['elastic-apm-node', ''] + }).catch(() => process.exit(1)) + + +# Example + +This example implements an HTTP server that uses the [pug template +library](https://pugjs.org/api/getting-started.html) in its request handler. +Then a single request is made to the HTTP server. When tracing this we +expect a trace like this: + + transaction "GET unknown route" + `- span "pug" + +Setup dependencies and build the bundle. The bundle file is written to +"dist/index.js". + + npm install + npm run build + +Configure the APM agent to point to [your Elastic APM setup](https://www.elastic.co/guide/en/apm/guide/current/apm-quick-start.html) + + export ELASTIC_APM_SERVER_URL=... + export ELASTIC_APM_SECRET_TOKEN=... + +Run the script: + + node dist/index.js + diff --git a/examples/esbuild/package.json b/examples/esbuild/package.json new file mode 100644 index 00000000000..eab3527e240 --- /dev/null +++ b/examples/esbuild/package.json @@ -0,0 +1,17 @@ +{ + "name": "elastic-apm-node-esbuild-example", + "version": "1.0.0", + "private": true, + "main": "src/index.js", + "scripts": { + "build": "esbuild ./src/index* --outdir=dist --bundle --platform=node --target=node8.6 --external:elastic-apm-node --external:pug --sourcemap", + "clean": "rm -rf dist" + }, + "dependencies": { + "elastic-apm-node": "^3.37.0", + "pug": "^3.0.2" + }, + "devDependencies": { + "esbuild": "^0.14.49" + } +} diff --git a/examples/esbuild/src/handler.js b/examples/esbuild/src/handler.js new file mode 100644 index 00000000000..7ac92381888 --- /dev/null +++ b/examples/esbuild/src/handler.js @@ -0,0 +1,25 @@ +/* + * Copyright Elasticsearch B.V. and other contributors where applicable. + * Licensed under the BSD 2-Clause License; you may not use this file except in + * compliance with the BSD 2-Clause License. + */ + +// Implement the HTTP request handler in a separate file to make the +// case for bundling slightly more interesting. + +const apm = require('elastic-apm-node') +const pug = require('pug') + +const resTemplate = pug.compile('p The time is #{time}.') + +function handleRequest (req, res) { + console.log('SERVER: apm.currentTransaction: %s', apm.currentTransaction) + req.resume() + res.statusCode = 200 + res.setHeader('content-type', 'text/html') + res.end(resTemplate({ time: new Date().toISOString() })) +} + +module.exports = { + handleRequest +} diff --git a/examples/esbuild/src/index.js b/examples/esbuild/src/index.js new file mode 100644 index 00000000000..15e5f4a3078 --- /dev/null +++ b/examples/esbuild/src/index.js @@ -0,0 +1,26 @@ +/* + * Copyright Elasticsearch B.V. and other contributors where applicable. + * Licensed under the BSD 2-Clause License; you may not use this file except in + * compliance with the BSD 2-Clause License. + */ + +require('elastic-apm-node').start() + +const http = require('http') +const { handleRequest } = require('./handler') + +// Start a simple HTTP server. +const server = http.createServer(handleRequest) +server.listen(3000, () => { + // Make a single request and then stop. + http.get('http://localhost:3000', res => { + console.log('CLIENT: res.headers:', res.headers) + res.on('data', chunk => { + console.log('CLIENT: res "data": %s', chunk) + }) + res.on('end', () => { + console.log('CLIENT: res "end"') + server.close() + }) + }) +}) diff --git a/examples/nextjs/.eslintrc.json b/examples/nextjs/.eslintrc.json new file mode 100644 index 00000000000..bffb357a712 --- /dev/null +++ b/examples/nextjs/.eslintrc.json @@ -0,0 +1,3 @@ +{ + "extends": "next/core-web-vitals" +} diff --git a/examples/nextjs/.gitignore b/examples/nextjs/.gitignore new file mode 100644 index 00000000000..a248576abdc --- /dev/null +++ b/examples/nextjs/.gitignore @@ -0,0 +1,38 @@ +# See https://help.github.com/articles/ignoring-files/ for more about ignoring files. + +/elastic-apm-node.js + +# dependencies +/node_modules +/.pnp +.pnp.js + +# testing +/coverage + +# next.js +/.next/ +/out/ + +# production +/build + +# misc +.DS_Store +*.pem + +# debug +npm-debug.log* +yarn-debug.log* +yarn-error.log* +.pnpm-debug.log* + +# local env files +.env*.local + +# vercel +.vercel + +# typescript +*.tsbuildinfo +next-env.d.ts diff --git a/examples/nextjs/.npmrc b/examples/nextjs/.npmrc new file mode 100644 index 00000000000..43c97e719a5 --- /dev/null +++ b/examples/nextjs/.npmrc @@ -0,0 +1 @@ +package-lock=false diff --git a/examples/nextjs/README.md b/examples/nextjs/README.md new file mode 100644 index 00000000000..b58c18bee64 --- /dev/null +++ b/examples/nextjs/README.md @@ -0,0 +1,30 @@ +This is a [Next.js](https://nextjs.org/) application +1. bootstrapped with [`create-next-app`](https://github.com/vercel/next.js/tree/canary/packages/create-next-app), and then +2. modified to use the Elastic APM Node.js agent to monitor the Next server. + +## Getting Started + +1. `npm install` + +2. Configure an APM server URL and token for the APM agent. See the [APM Quick start](https://www.elastic.co/guide/en/apm/guide/current/apm-quick-start.html) for help setting up the Elastic Stack. + + ```bash + cp elastic-apm-node.js.template elastic-apm-node.js + vi elastic-apm-node.js + ``` + +3. Run the Next.js server: + + ```bash + npm run dev # the development server + npm run build && npm start # or the production server + ``` + +Open [http://localhost:3000](http://localhost:3000) in your browser to see the result. +An [API route](https://nextjs.org/docs/api-routes/introduction) can be accessed at . + +## Learn More + +- [Get started with Next.js and Elastic APM](https://www.elastic.co/guide/en/apm/agent/nodejs/master/nextjs.html) - official Elastic documentation. +- [Next.js Documentation](https://nextjs.org/docs) - learn about Next.js features and API. +- [Learn Next.js](https://nextjs.org/learn) - an interactive Next.js tutorial. diff --git a/examples/nextjs/elastic-apm-node.js.template b/examples/nextjs/elastic-apm-node.js.template new file mode 100644 index 00000000000..c973ab37dc3 --- /dev/null +++ b/examples/nextjs/elastic-apm-node.js.template @@ -0,0 +1,5 @@ +module.exports = { + // Configure the APM server URL and token that the APM agent should use. + // serverUrl: 'https://...', // e.g.: http://my-deployment-name.apm.us-west2.gcp.elastic-cloud.com', + // secretToken: '...' +} diff --git a/examples/nextjs/next.config.js b/examples/nextjs/next.config.js new file mode 100644 index 00000000000..ae887958d3c --- /dev/null +++ b/examples/nextjs/next.config.js @@ -0,0 +1,7 @@ +/** @type {import('next').NextConfig} */ +const nextConfig = { + reactStrictMode: true, + swcMinify: true, +} + +module.exports = nextConfig diff --git a/examples/nextjs/package.json b/examples/nextjs/package.json new file mode 100644 index 00000000000..45168c859eb --- /dev/null +++ b/examples/nextjs/package.json @@ -0,0 +1,21 @@ +{ + "name": "my-app", + "version": "0.1.0", + "private": true, + "scripts": { + "dev": "NODE_OPTIONS=--require=elastic-apm-node/start-next.js next dev", + "build": "next build", + "start": "NODE_OPTIONS=--require=elastic-apm-node/start-next.js next start", + "lint": "next lint" + }, + "dependencies": { + "elastic-apm-node": "elastic/apm-agent-nodejs#main", + "next": "12.3.1", + "react": "18.2.0", + "react-dom": "18.2.0" + }, + "devDependencies": { + "eslint": "8.25.0", + "eslint-config-next": "12.3.1" + } +} diff --git a/examples/nextjs/pages/_app.js b/examples/nextjs/pages/_app.js new file mode 100644 index 00000000000..1e1cec92425 --- /dev/null +++ b/examples/nextjs/pages/_app.js @@ -0,0 +1,7 @@ +import '../styles/globals.css' + +function MyApp({ Component, pageProps }) { + return +} + +export default MyApp diff --git a/examples/nextjs/pages/api/hello.js b/examples/nextjs/pages/api/hello.js new file mode 100644 index 00000000000..df63de88fa6 --- /dev/null +++ b/examples/nextjs/pages/api/hello.js @@ -0,0 +1,5 @@ +// Next.js API route support: https://nextjs.org/docs/api-routes/introduction + +export default function handler(req, res) { + res.status(200).json({ name: 'John Doe' }) +} diff --git a/examples/nextjs/pages/index.js b/examples/nextjs/pages/index.js new file mode 100644 index 00000000000..dc4b6403521 --- /dev/null +++ b/examples/nextjs/pages/index.js @@ -0,0 +1,69 @@ +import Head from 'next/head' +import Image from 'next/image' +import styles from '../styles/Home.module.css' + +export default function Home() { + return ( + + ) +} diff --git a/examples/nextjs/public/favicon.ico b/examples/nextjs/public/favicon.ico new file mode 100644 index 00000000000..718d6fea483 Binary files /dev/null and b/examples/nextjs/public/favicon.ico differ diff --git a/examples/nextjs/public/vercel.svg b/examples/nextjs/public/vercel.svg new file mode 100644 index 00000000000..fbf0e25a651 --- /dev/null +++ b/examples/nextjs/public/vercel.svg @@ -0,0 +1,4 @@ + + + \ No newline at end of file diff --git a/examples/nextjs/styles/Home.module.css b/examples/nextjs/styles/Home.module.css new file mode 100644 index 00000000000..bd50f42ffe6 --- /dev/null +++ b/examples/nextjs/styles/Home.module.css @@ -0,0 +1,129 @@ +.container { + padding: 0 2rem; +} + +.main { + min-height: 100vh; + padding: 4rem 0; + flex: 1; + display: flex; + flex-direction: column; + justify-content: center; + align-items: center; +} + +.footer { + display: flex; + flex: 1; + padding: 2rem 0; + border-top: 1px solid #eaeaea; + justify-content: center; + align-items: center; +} + +.footer a { + display: flex; + justify-content: center; + align-items: center; + flex-grow: 1; +} + +.title a { + color: #0070f3; + text-decoration: none; +} + +.title a:hover, +.title a:focus, +.title a:active { + text-decoration: underline; +} + +.title { + margin: 0; + line-height: 1.15; + font-size: 4rem; +} + +.title, +.description { + text-align: center; +} + +.description { + margin: 4rem 0; + line-height: 1.5; + font-size: 1.5rem; +} + +.code { + background: #fafafa; + border-radius: 5px; + padding: 0.75rem; + font-size: 1.1rem; + font-family: Menlo, Monaco, Lucida Console, Liberation Mono, DejaVu Sans Mono, + Bitstream Vera Sans Mono, Courier New, monospace; +} + +.grid { + display: flex; + align-items: center; + justify-content: center; + flex-wrap: wrap; + max-width: 800px; +} + +.card { + margin: 1rem; + padding: 1.5rem; + text-align: left; + color: inherit; + text-decoration: none; + border: 1px solid #eaeaea; + border-radius: 10px; + transition: color 0.15s ease, border-color 0.15s ease; + max-width: 300px; +} + +.card:hover, +.card:focus, +.card:active { + color: #0070f3; + border-color: #0070f3; +} + +.card h2 { + margin: 0 0 1rem 0; + font-size: 1.5rem; +} + +.card p { + margin: 0; + font-size: 1.25rem; + line-height: 1.5; +} + +.logo { + height: 1em; + margin-left: 0.5rem; +} + +@media (max-width: 600px) { + .grid { + width: 100%; + flex-direction: column; + } +} + +@media (prefers-color-scheme: dark) { + .card, + .footer { + border-color: #222; + } + .code { + background: #111; + } + .logo img { + filter: invert(1); + } +} diff --git a/examples/nextjs/styles/globals.css b/examples/nextjs/styles/globals.css new file mode 100644 index 00000000000..4f1842163d2 --- /dev/null +++ b/examples/nextjs/styles/globals.css @@ -0,0 +1,26 @@ +html, +body { + padding: 0; + margin: 0; + font-family: -apple-system, BlinkMacSystemFont, Segoe UI, Roboto, Oxygen, + Ubuntu, Cantarell, Fira Sans, Droid Sans, Helvetica Neue, sans-serif; +} + +a { + color: inherit; + text-decoration: none; +} + +* { + box-sizing: border-box; +} + +@media (prefers-color-scheme: dark) { + html { + color-scheme: dark; + } + body { + color: white; + background: black; + } +} diff --git a/examples/trace-apollo-server-express.js b/examples/trace-apollo-server-express.js new file mode 100644 index 00000000000..c5ccda6b752 --- /dev/null +++ b/examples/trace-apollo-server-express.js @@ -0,0 +1,67 @@ +/* + * Copyright Elasticsearch B.V. and other contributors where applicable. + * Licensed under the BSD 2-Clause License; you may not use this file except in + * compliance with the BSD 2-Clause License. + */ + +// A small example showing Elastic APM tracing of a GraphQL server implemented +// using 'apollo-server-express'. +// https://www.apollographql.com/docs/apollo-server/integrations/middleware#apollo-server-express +// +// Usage: +// - Set `ELASTIC_APM_SERVER_URL` and `ELASTIC_APM_SECRET_TOKEN` environment +// variables to configure a target APM server. +// (See https://www.elastic.co/guide/en/apm/guide/current/apm-quick-start.html) +// export ELASTIC_APM_SERVER_URL=... +// export ELASTIC_APM_SECRET_TOKEN=... +// - Start the small GraphQL server: +// node examples/trace-express-graphql.js +// - Make a GraphQL client request. E.g.: +// curl -i localhost:3000/graphql -X POST -H content-type:application/json -d'{"query":"query HelloQuery { hello }"}' +// +// In the Elastic APM app you should expect to see a transaction and span +// something like: +// +// transaction "HelloQuery hello (/graphql)" +// `- span "GraphQL: HelloQuery hello" + +require('../').start({ // elastic-apm-node + serviceName: 'example-trace-apollo-server-express', + logUncaughtExceptions: true +}) + +const http = require('http') +const { ApolloServer, gql } = require('apollo-server-express') +const express = require('express') + +const typeDefs = gql` +type Query { + "A simple type for getting started!" + hello: String +} +` +const resolvers = { + Query: { + hello: () => 'world' + } +} + +async function startServer () { + const app = express() + app.set('env', 'production') + app.get('/ping', (req, res, next) => { + req.resume() + res.end('pong') + }) + const httpServer = http.createServer(app) + + const server = new ApolloServer({ typeDefs, resolvers }) + await server.start() + server.applyMiddleware({ app }) + + httpServer.listen(3000, () => { + console.log(`Apollo GraphQL server listening at http://localhost:3000${server.graphqlPath}`) + }) +} + +startServer() diff --git a/examples/trace-elasticsearch7.js b/examples/trace-elasticsearch7.js index 84deddc10a5..ffd247164e0 100755 --- a/examples/trace-elasticsearch7.js +++ b/examples/trace-elasticsearch7.js @@ -18,10 +18,16 @@ const apm = require('../').start({ // elastic-apm-node logUncaughtExceptions: true }) +// Note that version 7 is *not* installed by default. To use v7 you'll need to: +// npm install @elastic/elasticsearch@7 const { Client } = require('@elastic/elasticsearch') const client = new Client({ - node: `http://${process.env.ES_HOST || 'localhost'}:9200` + node: process.env.ES_URL || 'http://localhost:9200', + auth: { + username: process.env.ES_USERNAME || undefined, + password: process.env.ES_PASSWORD || undefined + } }) async function run () { diff --git a/examples/trace-elasticsearch8.js b/examples/trace-elasticsearch8.js index 59051b0a4ae..b31705080c7 100755 --- a/examples/trace-elasticsearch8.js +++ b/examples/trace-elasticsearch8.js @@ -18,15 +18,20 @@ const apm = require('../').start({ // elastic-apm-node logUncaughtExceptions: true }) -// Currently, pre-releases of v8 are published as the "...-canary" package name. // eslint-disable-next-line no-unused-vars -const { Client, HttpConnection } = require('@elastic/elasticsearch-canary') +const { Client, HttpConnection } = require('@elastic/elasticsearch') const client = new Client({ - // With version 8 of the client, you can use `HttpConnection` to use the old - // HTTP client: + // By default version 8 uses the new undici HTTP client lib. You can specify + // `HttpConnection` to use the older HTTP client. // Connection: HttpConnection, - node: `http://${process.env.ES_HOST || 'localhost'}:9200` + + node: process.env.ES_URL || 'http://localhost:9200', + auth: { + username: process.env.ES_USERNAME || undefined, + password: process.env.ES_PASSWORD || undefined + }, + maxRetries: 1 }) async function run () { diff --git a/examples/trace-fetch.js b/examples/trace-fetch.js new file mode 100755 index 00000000000..b01d95a4bc1 --- /dev/null +++ b/examples/trace-fetch.js @@ -0,0 +1,41 @@ +#!/usr/bin/env node --no-warnings + +/* + * Copyright Elasticsearch B.V. and other contributors where applicable. + * Licensed under the BSD 2-Clause License; you may not use this file except in + * compliance with the BSD 2-Clause License. + */ + +// This example shows use of Node v18's core `fetch()`. The Node.js APM agent +// will automatically instrument it. + +/* global fetch */ // for eslint + +const apm = require('../').start({ + serviceName: 'example-trace-fetch' +}) + +const url = process.argv[2] || 'https://httpstat.us/200' + +async function main () { + // For tracing spans to be created, there must be an active transaction. + // Typically, a transaction is automatically started for incoming HTTP + // requests to a Node.js server. However, because this script is not running + // an HTTP server, we manually start a transaction. More details at: + // https://www.elastic.co/guide/en/apm/agent/nodejs/current/custom-transactions.html + const trans = apm.startTransaction('trans') + try { + const res = await fetch(url) + for (const [k, v] of res.headers) { + console.log(`${k}: ${v}`) + } + const body = await res.text() + console.log('\n' + body) + } catch (err) { + console.error('fetch error:', err) + } finally { + if (trans) trans.end() + } +} + +main() diff --git a/examples/trace-redis.js b/examples/trace-redis.js index df36631802b..4624779e641 100755 --- a/examples/trace-redis.js +++ b/examples/trace-redis.js @@ -14,33 +14,71 @@ // testing of this project). Then `npm run docker:stop` to stop them. const apm = require('../').start({ // elastic-apm-node - serviceName: 'example-trace-redis' + serviceName: 'example-trace-redis4', + spanCompressionEnabled: false }) const redis = require('redis') -const client = redis.createClient() +async function useRedis () { + let res -// For tracing spans to be created, there must be an active transaction. -// Typically, a transaction is automatically started for incoming HTTP -// requests to a Node.js server. However, because this script is not running -// an HTTP server, we manually start a transaction. More details at: -// https://www.elastic.co/guide/en/apm/agent/nodejs/current/custom-transactions.html -const t1 = apm.startTransaction('t1') + const client = redis.createClient({ + name: 'example-trace-redis4', // This results in early `CLIENT SETNAME` sent in RedisClient.#initiateSocket() + database: 1 // This results in early `SELECT` sent in RedisClient.#initiateSocket() + }) -client.set('key1', 'val1') -client.get('key1', function (err, reply) { - console.log('GET key1: %s', err ? `${err.name}: ${err.message}` : reply) - t1.end() - client.quit() -}) + await client.connect() -// Simulate a redis client error with `enable_offline_queue: false` and a -// quick `.set()` before the client connection ready. -const clientSimErr = redis.createClient({ enable_offline_queue: false }) -const t2 = apm.startTransaction('t2') -clientSimErr.set('key2', 'val2', function (err, reply) { - console.log('SET key2: %s', err ? `${err.name}: ${err.message}` : reply) - t2.end() - clientSimErr.quit() -}) + try { + res = await client.ping() + console.log('PING res: ', res) + } catch (err) { + console.log('PING err: ', err) + } + + try { + res = await client.set('foo', 'bar') + console.log('SET res: ', res) + } catch (err) { + console.log('SET err: ', err) + } + + try { + res = await client.get('foo') + console.log('GET res: ', res) + } catch (err) { + console.log('GET err: ', err) + } + + try { + res = await client.multi() + .set('spam', 'eggs') + .get('spam') + .exec() + console.log('MULTI res: ', res) + } catch (err) { + console.log('MULTI err: ', err) + } + + await client.quit() +} + +async function main () { + // For tracing spans to be created, there must be an active transaction. + // Typically, a transaction is automatically started for incoming HTTP + // requests to a Node.js server. However, because this script is not running + // an HTTP server, we manually start a transaction. More details at: + // https://www.elastic.co/guide/en/apm/agent/nodejs/current/custom-transactions.html + const trans = apm.startTransaction('trans') + + Promise + .all([ + useRedis() + ]) + .then(() => { + trans.end() + }) +} + +main() diff --git a/examples/trace-undici.js b/examples/trace-undici.js new file mode 100755 index 00000000000..885151c8f7c --- /dev/null +++ b/examples/trace-undici.js @@ -0,0 +1,66 @@ +#!/usr/bin/env node --no-warnings + +/* + * Copyright Elasticsearch B.V. and other contributors where applicable. + * Licensed under the BSD 2-Clause License; you may not use this file except in + * compliance with the BSD 2-Clause License. + */ + +// This example shows the Node.js APM agent's instrumentation of the 'undici' +// HTTP client library. +// +// Set `ELASTIC_APM_SERVER_URL` and `ELASTIC_APM_SECRET_TOKEN` environment +// variables to configure the APM agent, then run this script. + +const apm = require('../').start({ + serviceName: 'example-trace-undici', + usePathAsTransactionName: true // for our simple HTTP server +}) + +const http = require('http') +const undici = require('undici') + +// Start a simple HTTP server that we will call with undici. +const server = http.createServer((req, res) => { + console.log('incoming request: %s %s %s', req.method, req.url, req.headers) + req.resume() + req.on('end', function () { + const resBody = JSON.stringify({ ping: 'pong' }) + setTimeout(() => { + res.writeHead(200, { + 'content-type': 'application/json', + 'content-length': Buffer.byteLength(resBody) + }) + res.end(resBody) + }, 100) // Take ~100ms to respond. + }) +}) +server.listen(3000, async () => { + // For tracing spans to be created, there must be an active transaction. + // Typically, a transaction is automatically started for incoming HTTP + // requests to a Node.js server. However, because the undici calls are not + // in the context of an incoming HTTP request we manually start a transaction. + // More details at: + // https://www.elastic.co/guide/en/apm/agent/nodejs/current/custom-transactions.html + const trans = apm.startTransaction('trans', 'manual') + + // Make a handful of requests and use Undici's pipelining + // (https://undici.nodejs.org/#/?id=pipelining) to show concurrent requests. + const client = new undici.Client('http://localhost:3000', { + pipelining: 2 + }) + let lastReq + for (let i = 0; i < 4; i++) { + lastReq = client.request({ method: 'GET', path: '/ping-' + i }) + } + const { statusCode, headers, body } = await lastReq + console.log('last ping statusCode:', statusCode) + console.log('last ping headers:', headers) + for await (const data of body) { + console.log('last ping data:', data.toString()) + } + + trans.end() + client.close() + server.close() +}) diff --git a/examples/typescript/.npmrc b/examples/typescript/.npmrc new file mode 100644 index 00000000000..43c97e719a5 --- /dev/null +++ b/examples/typescript/.npmrc @@ -0,0 +1 @@ +package-lock=false diff --git a/examples/typescript/README.md b/examples/typescript/README.md new file mode 100644 index 00000000000..a5eb5f0ab6c --- /dev/null +++ b/examples/typescript/README.md @@ -0,0 +1,33 @@ +This directory includes an example TypeScript project using the Elastic +Node.js APM agent. It uses a tsconfig as recommended at +https://github.com/tsconfig/bases#node-14-tsconfigjson + +Install dependencies: + + npm install + +Compile the TypeScript ("index.ts") to JavaScript ("dist/index.js"): + + npm run build + +In this example we are importing and starting the agent with the following at +the top of "index.ts". (See [the docs](https://www.elastic.co/guide/en/apm/agent/nodejs/current/starting-the-agent.html) +for other ways of starting the APM agent.) + +```ts +import 'elastic-apm-node/start' +``` + +This start methods means that we need to use environment variables (or an +"elastic-apm-node.js" config file) for [configuration](https://www.elastic.co/guide/en/apm/agent/nodejs/current/configuring-the-agent.html). + +Configure the APM agent with values from [your Elastic Stack](https://www.elastic.co/guide/en/apm/guide/8.3/apm-quick-start.html) and execute the script: + + export ELASTIC_APM_SERVER_URL='https://...apm...cloud.es.io:443' + export ELASTIC_APM_SECRET_TOKEN='...' + export ELASTIC_APM_USE_PATH_AS_TRANSACTION_NAME=true + node dist/index.js + +This simple script creates an HTTP server and makes a single request to it. +If things work properly, you should see a trace with a single HTTP transaction +named "GET /ping". diff --git a/examples/typescript/index.ts b/examples/typescript/index.ts new file mode 100755 index 00000000000..ff096bdc692 --- /dev/null +++ b/examples/typescript/index.ts @@ -0,0 +1,43 @@ +/* + * Copyright Elasticsearch B.V. and other contributors where applicable. + * Licensed under the BSD 2-Clause License; you may not use this file except in + * compliance with the BSD 2-Clause License. + */ + +// Be sure to import and *start* the agent before other imports. +import 'elastic-apm-node/start' + +import http from 'http' + +// Create an HTTP server listening at port 3000. +const server = http.createServer((req, res) => { + console.log('incoming request: %s %s %s', req.method, req.url, req.headers) + req.resume() + req.on('end', function () { + const resBody = 'pong' + res.writeHead(200, { + server: 'example-trace-http', + 'content-type': 'text/plain', + 'content-length': Buffer.byteLength(resBody) + }) + res.end(resBody) + }) +}) +server.listen(3000, function () { + + // Make a single HTTP request, then stop the server. + const clientReq = http.request('http://localhost:3000/ping', clientRes => { + console.log('client response: %s %s', clientRes.statusCode, clientRes.headers) + const chunks: Array = [] + clientRes.on('data', function (chunk) { + chunks.push(chunk) + }) + clientRes.on('end', function () { + const body = chunks.join('') + console.log('client response body: %j', body) + server.close() + }) + }) + clientReq.end() + +}) diff --git a/examples/typescript/package.json b/examples/typescript/package.json new file mode 100644 index 00000000000..ec305c87060 --- /dev/null +++ b/examples/typescript/package.json @@ -0,0 +1,16 @@ +{ + "name": "elastic-apm-node-typescript-example", + "version": "1.0.0", + "private": true, + "main": "index.ts", + "scripts": { + "build": "tsc" + }, + "dependencies": { + "elastic-apm-node": "^3.37.0" + }, + "devDependencies": { + "@tsconfig/node14": "^1.0.3", + "typescript": "^4.7.4" + } +} diff --git a/examples/typescript/tsconfig.json b/examples/typescript/tsconfig.json new file mode 100644 index 00000000000..440bbffea04 --- /dev/null +++ b/examples/typescript/tsconfig.json @@ -0,0 +1,6 @@ +{ + "extends": "@tsconfig/node14/tsconfig.json", + "compilerOptions": { + "outDir": "dist" + } +} diff --git a/index.d.ts b/index.d.ts index 032c53fb748..799f0b58047 100644 --- a/index.d.ts +++ b/index.d.ts @@ -222,6 +222,7 @@ declare namespace apm { setLabel (name: string, value: LabelValue, stringify?: boolean): boolean; addLabels (labels: Labels, stringify?: boolean): boolean; setOutcome(outcome: Outcome): void; + setServiceTarget(type?: string | null, name?: string | null): void; end (endTime?: number): void; } @@ -249,9 +250,11 @@ declare namespace apm { contextPropagationOnly?: boolean; disableInstrumentations?: string | string[]; disableSend?: boolean; + elasticsearchCaptureBodyUrls?: Array; environment?: string; errorMessageMaxLength?: string; // DEPRECATED: use `longFieldMaxLength`. errorOnAbortedRequests?: boolean; + exitSpanMinDuration?: string; filterHttpHeaders?: boolean; frameworkName?: string; frameworkVersion?: string; @@ -317,6 +320,12 @@ declare namespace apm { message?: string; captureAttributes?: boolean; skipOutcome?: boolean; + /** + * A Transaction or Span instance to make the parent of this error. If not + * given (undefined), then the current span or transaction will be used. If + * `null` is given, then no span or transaction will be used. + */ + parent?: Transaction | Span | null; } interface Labels { @@ -366,7 +375,10 @@ declare namespace apm { export interface TransactionOptions { startTime?: number; + // `childOf` is a W3C trace-context 'traceparent' string. Passing a + // Transaction or Span is deprecated. childOf?: Transaction | Span | string; + tracestate?: string; // A W3C trace-context 'tracestate' string. links?: Link[]; } diff --git a/lib/agent.js b/lib/agent.js index fb515067a45..c7cf72512b4 100644 --- a/lib/agent.js +++ b/lib/agent.js @@ -22,7 +22,7 @@ var { elasticApmAwsLambda } = require('./lambda') var Metrics = require('./metrics') var parsers = require('./parsers') var symbols = require('./symbols') -const { frameCacheStats } = require('./stacktraces') +const { frameCacheStats, initStackTraceCollection } = require('./stacktraces') const Span = require('./instrumentation/span') const Transaction = require('./instrumentation/transaction') @@ -93,9 +93,9 @@ Object.defineProperty(Agent.prototype, 'currentTraceIds', { // - There may be in-flight tasks (in ins.addEndedSpan() and // agent.captureError() for example) that will complete after this destroy // completes. They should have no impact other than CPU/resource use. -// - The patching of core node functions when `asyncHooks=false` is *not* -// undone. This means run context tracking for `asyncHooks=false` is broken -// with in-process multiple-Agent use. +// - The patching of core node functions when `contextManager="patch"` is *not* +// undone. This means run context tracking for `contextManager="patch"` is +// broken with in-process multiple-Agent use. Agent.prototype.destroy = function () { if (this._transport && this._transport.destroy) { this._transport.destroy() @@ -198,15 +198,6 @@ Agent.prototype.setSpanOutcome = function (outcome) { Agent.prototype._config = function (opts) { this._conf = config.createConfig(opts, this.logger) this.logger = this._conf.logger - - const { host, port, protocol } = this._conf.serverUrl - ? parsers.parseUrl(this._conf.serverUrl) - : { host: 'localhost:8200', port: '8200' } - - this._conf.serverHost = host - this._conf.serverPort = port === '' - ? (protocol === 'https:' ? 443 : 80) - : parseInt(port, 10) } Agent.prototype.isStarted = function () { @@ -225,6 +216,7 @@ Agent.prototype.start = function (opts) { this.addFilter(require('./filters/http-headers')) } + // Check cases where we do *not* start. if (!this._conf.active) { this.logger.debug('Elastic APM agent disabled (`active` is false)') return this @@ -232,11 +224,19 @@ Agent.prototype.start = function (opts) { this.logger.error('Elastic APM is incorrectly configured: Missing serviceName (APM will be disabled)') this._conf.active = false return this - } else if (!(this._conf.serverPort >= 1 && this._conf.serverPort <= 65535)) { + } + // Sanity check the port from `serverUrl`. + const parsedUrl = parsers.parseUrl(this._conf.serverUrl) + const serverPort = (parsedUrl.port + ? Number(parsedUrl.port) + : (parsedUrl.protocol === 'https:' ? 443 : 80)) + if (!(serverPort >= 1 && serverPort <= 65535)) { this.logger.error('Elastic APM is incorrectly configured: serverUrl "%s" contains an invalid port! (allowed: 1-65535)', this._conf.serverUrl) this._conf.active = false return this - } else if (this._conf.logLevel === 'trace') { + } + + if (this._conf.logLevel === 'trace') { var stackObj = {} Error.captureStackTrace(stackObj) @@ -261,6 +261,7 @@ Agent.prototype.start = function (opts) { }, 'agent configured correctly') } + initStackTraceCollection() this._transport = this._conf.transport(this._conf, this) let runContextClass diff --git a/lib/cloud-metadata/callback-coordination.js b/lib/cloud-metadata/callback-coordination.js index 43fb5223798..17b9fac579a 100644 --- a/lib/cloud-metadata/callback-coordination.js +++ b/lib/cloud-metadata/callback-coordination.js @@ -40,7 +40,7 @@ class CallbackCoordination extends EventEmitter { this.timeout = setTimeout(() => { if (!this.done) { this.complete() - this.logger.error('metadata requests did not finish, possible deadlock') + this.logger.warn('cloud metadata requests timed out, using default values instead') const error = new CallbackCoordinationError( 'callback coordination reached timeout', this.errors diff --git a/lib/config.js b/lib/config.js index e56edf698cf..d2423230218 100644 --- a/lib/config.js +++ b/lib/config.js @@ -27,6 +27,9 @@ const INTAKE_STRING_MAX_SIZE = 1024 const CAPTURE_ERROR_LOG_STACK_TRACES_NEVER = 'never' const CAPTURE_ERROR_LOG_STACK_TRACES_MESSAGES = 'messages' const CAPTURE_ERROR_LOG_STACK_TRACES_ALWAYS = 'always' +const CONTEXT_MANAGER_PATCH = 'patch' +const CONTEXT_MANAGER_ASYNCHOOKS = 'asynchooks' +const CONTEXT_MANAGER_ASYNCLOCALSTORAGE = 'asynclocalstorage' const TRACE_CONTINUATION_STRATEGY_CONTINUE = 'continue' const TRACE_CONTINUATION_STRATEGY_RESTART = 'restart' const TRACE_CONTINUATION_STRATEGY_RESTART_EXTERNAL = 'restart_external' @@ -37,7 +40,6 @@ var DEFAULTS = { addPatch: undefined, apiRequestSize: '768kb', apiRequestTime: '10s', - asyncHooks: true, breakdownMetrics: true, captureBody: 'off', captureErrorLogStackTraces: CAPTURE_ERROR_LOG_STACK_TRACES_MESSAGES, @@ -46,11 +48,19 @@ var DEFAULTS = { centralConfig: true, cloudProvider: 'auto', containerId: undefined, + // 'contextManager' and 'asyncHooks' are explicitly *not* included in DEFAULTS + // because normalizeContextManager() needs to know if a value was provided by + // the user. contextPropagationOnly: false, disableInstrumentations: [], disableSend: false, + elasticsearchCaptureBodyUrls: [ + '*/_search', '*/_search/template', '*/_msearch', '*/_msearch/template', + '*/_async_search', '*/_count', '*/_sql', '*/_eql/search' + ], environment: process.env.NODE_ENV || 'development', errorOnAbortedRequests: false, + exitSpanMinDuration: '0ms', filterHttpHeaders: true, globalLabels: undefined, ignoreMessageQueues: [], @@ -62,19 +72,25 @@ var DEFAULTS = { kubernetesPodUID: undefined, logLevel: 'info', logUncaughtExceptions: false, // TODO: Change to `true` in the v4.0.0 + longFieldMaxLength: 10000, // Rough equivalent of the Java Agent's max_queue_size: // https://www.elastic.co/guide/en/apm/agent/java/current/config-reporter.html#config-max-queue-size - longFieldMaxLength: 10000, maxQueueSize: 1024, metricsInterval: '30s', metricsLimit: 1000, opentelemetryBridgeEnabled: false, - sanitizeFieldNames: ['password', 'passwd', 'pwd', 'secret', '*key', '*token*', - '*session*', '*credit*', '*card*', '*auth*', 'set-cookie', + sanitizeFieldNames: [ + // These patterns are specified in the shared APM specs: + // https://github.com/elastic/apm/blob/main/specs/agents/sanitization.md + 'password', 'passwd', 'pwd', 'secret', '*key', '*token*', + '*session*', '*credit*', '*card*', '*auth*', 'set-cookie', '*principal*', + // These are default patterns only in the Node.js APM agent, historically + // from when the "is-secret" dependency was used. 'pw', 'pass', 'connect.sid' ], serviceNodeName: undefined, serverTimeout: '30s', + serverUrl: 'http://127.0.0.1:8200', sourceLinesErrorAppFrames: 5, sourceLinesErrorLibraryFrames: 5, sourceLinesSpanAppFrames: 0, @@ -112,11 +128,14 @@ var ENV_TABLE = { centralConfig: 'ELASTIC_APM_CENTRAL_CONFIG', cloudProvider: 'ELASTIC_APM_CLOUD_PROVIDER', containerId: 'ELASTIC_APM_CONTAINER_ID', + contextManager: 'ELASTIC_APM_CONTEXT_MANAGER', contextPropagationOnly: 'ELASTIC_APM_CONTEXT_PROPAGATION_ONLY', disableInstrumentations: 'ELASTIC_APM_DISABLE_INSTRUMENTATIONS', disableSend: 'ELASTIC_APM_DISABLE_SEND', environment: 'ELASTIC_APM_ENVIRONMENT', + exitSpanMinDuration: 'ELASTIC_APM_EXIT_SPAN_MIN_DURATION', ignoreMessageQueues: ['ELASTIC_IGNORE_MESSAGE_QUEUES', 'ELASTIC_APM_IGNORE_MESSAGE_QUEUES'], + elasticsearchCaptureBodyUrls: 'ELASTIC_APM_ELASTICSEARCH_CAPTURE_BODY_URLS', errorMessageMaxLength: 'ELASTIC_APM_ERROR_MESSAGE_MAX_LENGTH', errorOnAbortedRequests: 'ELASTIC_APM_ERROR_ON_ABORTED_REQUESTS', filterHttpHeaders: 'ELASTIC_APM_FILTER_HTTP_HEADERS', @@ -174,7 +193,8 @@ var CENTRAL_CONFIG = { sanitize_field_names: 'sanitizeFieldNames', ignore_message_queues: 'ignoreMessageQueues', span_stack_trace_min_duration: 'spanStackTraceMinDuration', - trace_continuation_strategy: 'traceContinuationStrategy' + trace_continuation_strategy: 'traceContinuationStrategy', + exit_span_min_duration: 'exitSpanMinDuration' } var BOOL_OPTS = [ @@ -224,6 +244,12 @@ var DURATION_OPTS = [ allowedUnits: ['ms', 's', 'm'], allowNegative: false }, + { + name: 'exitSpanMinDuration', + defaultUnit: 'ms', + allowedUnits: ['us', 'ms', 's', 'm'], + allowNegative: false + }, { name: 'metricsInterval', defaultUnit: 's', @@ -274,6 +300,7 @@ var MINUS_ONE_EQUAL_INFINITY = [ var ARRAY_OPTS = [ 'disableInstrumentations', + 'elasticsearchCaptureBodyUrls', 'sanitizeFieldNames', 'transactionIgnoreUrls', 'ignoreMessageQueues' @@ -321,6 +348,7 @@ function initialConfig (logger) { cfg.ignoreUrlRegExp = [] cfg.ignoreUserAgentStr = [] cfg.ignoreUserAgentRegExp = [] + cfg.elasticsearchCaptureBodyUrlsRegExp = [] cfg.transactionIgnoreUrlRegExp = [] cfg.sanitizeFieldNamesRegExp = [] cfg.ignoreMessageQueuesRegExp = [] @@ -341,6 +369,7 @@ class Config { this.ignoreUrlRegExp = [] this.ignoreUserAgentStr = [] this.ignoreUserAgentRegExp = [] + this.elasticsearchCaptureBodyUrlsRegExp = [] this.transactionIgnoreUrlRegExp = [] this.sanitizeFieldNamesRegExp = [] this.ignoreMessageQueuesRegExp = [] @@ -513,8 +542,7 @@ class Config { const REDACT_FIELDS = { apiKey: true, secretToken: true, - serverUrl: true, - serverHost: true + serverUrl: true } const NICE_REGEXPS_FIELDS = { ignoreUrlRegExp: true, @@ -685,7 +713,9 @@ function normalize (opts, logger) { normalizeDurationOptions(opts, logger) normalizeBools(opts, logger) normalizeIgnoreOptions(opts) + normalizeElasticsearchCaptureBodyUrls(opts) normalizeSanitizeFieldNames(opts) + normalizeContextManager(opts, logger) // Must be after normalizeBools(). normalizeCloudProvider(opts, logger) normalizeTransactionSampleRate(opts, logger) normalizeTraceContinuationStrategy(opts, logger) @@ -766,6 +796,63 @@ function normalizeSpanStackTraceMinDuration (opts, logger) { } } +const ALLOWED_CONTEXT_MANAGER = { + [CONTEXT_MANAGER_PATCH]: true, + [CONTEXT_MANAGER_ASYNCHOOKS]: true, + [CONTEXT_MANAGER_ASYNCLOCALSTORAGE]: true +} + +/** + * Normalize and validate the given values for `contextManager`, and the + * deprecated `asyncHooks` that it replaces. + * + * - `contextManager=patch` means use the "patch-async" technique. I.e., do + * limited monkey patching of Node.js core async methods to do limited context + * tracking). + * - `contextManager=asynchooks` means use the "async_hooks.createHook()" + * technique. This works in all supported versions of node, but can have + * significant performance overhead for Promise-heavy apps. + * - `contextManager=asynclocalstorage` means use the "AsyncLocalStorage" + * technique *if supported in the version of node* (>=14.5 || ^12.19.0). + * Otherwise, this will warn and fallback to "asynchooks". + * - The `asyncHooks` config var is now deprecated. It is translated to the + * equivalent `contextManager` value. + * - `asyncHooks=false` -> `contextManager=patch` + * - `asyncHooks=true` -> leaves the `contextManager` value empty to get + * the default behavior: the best async technique. + * - No specified option means use the best async technique. + */ +function normalizeContextManager (opts, logger) { + // Treat the empty string, e.g. `ELASTIC_APM_CONTEXT_MANAGER=`, as if it had + // not been specified. + if (opts.contextManager === '') { + delete opts.contextManager + } + + if ('contextManager' in opts && !(opts.contextManager in ALLOWED_CONTEXT_MANAGER)) { + logger.warn('Invalid "contextManager" config value %j, falling back to default behavior', + opts.contextManager) + delete opts.contextManager + } + + if ('asyncHooks' in opts) { + if ('contextManager' in opts) { + logger.warn({ asyncHooks: opts.asyncHooks, contextManager: opts.contextManager }, + 'both `asyncHooks` and `contextManager` config options were specified: the `asyncHooks` value will be ignored') + delete opts.asyncHooks + } else if (opts.asyncHooks === false) { + logger.warn('the `asyncHooks` config option is deprecated; instead of `asyncHooks: false` option, use `contextManager: "patch"`') + opts.contextManager = 'patch' + delete opts.asyncHooks + } else if (opts.asyncHooks === true) { + logger.warn('the `asyncHooks` config option is deprecated; `asyncHooks: true` is the default behavior') + delete opts.asyncHooks + } else { + delete opts.asyncHooks // Some bogus value. + } + } +} + // transactionSampleRate is specified to be: // - in the range [0,1] // - rounded to 4 decimal places of precision (e.g. 0.0001, 0.5678, 0.9999) @@ -853,6 +940,16 @@ function normalizeIgnoreOptions (opts) { } } +function normalizeElasticsearchCaptureBodyUrls (opts) { + if (opts.elasticsearchCaptureBodyUrls) { + const wildcard = new WildcardMatcher() + for (const ptn of opts.elasticsearchCaptureBodyUrls) { + const re = wildcard.compile(ptn) + opts.elasticsearchCaptureBodyUrlsRegExp.push(re) + } + } +} + function normalizeNumbers (opts) { for (const key of NUM_OPTS) { if (key in opts) opts[key] = Number(opts[key]) @@ -1217,6 +1314,9 @@ module.exports = { CAPTURE_ERROR_LOG_STACK_TRACES_NEVER, CAPTURE_ERROR_LOG_STACK_TRACES_MESSAGES, CAPTURE_ERROR_LOG_STACK_TRACES_ALWAYS, + CONTEXT_MANAGER_PATCH, + CONTEXT_MANAGER_ASYNCHOOKS, + CONTEXT_MANAGER_ASYNCLOCALSTORAGE, TRACE_CONTINUATION_STRATEGY_CONTINUE, TRACE_CONTINUATION_STRATEGY_RESTART, TRACE_CONTINUATION_STRATEGY_RESTART_EXTERNAL, diff --git a/lib/constants.js b/lib/constants.js index e5fb37b0bed..8010d9804a5 100644 --- a/lib/constants.js +++ b/lib/constants.js @@ -9,6 +9,9 @@ */ module.exports = { + // The default span or transaction `type`. + DEFAULT_SPAN_TYPE: 'custom', + REDACTED: '[REDACTED]', OUTCOME_FAILURE: 'failure', OUTCOME_SUCCESS: 'success', diff --git a/lib/errors.js b/lib/errors.js index e0d825a0142..1ca950ab8c6 100644 --- a/lib/errors.js +++ b/lib/errors.js @@ -91,10 +91,13 @@ function attributesFromErr (err) { continue case 'object': // Ignore all objects except Dates. - if (typeof val.toISOString !== 'function') { + if (typeof val.toISOString !== 'function' || typeof val.getTime !== 'function') { continue + } else if (Number.isNaN(val.getTime())) { + val = 'Invalid Date' // calling toISOString() on invalid dates throws + } else { + val = val.toISOString() } - val = val.toISOString() } attrs[key] = val n++ @@ -280,5 +283,6 @@ module.exports = { createAPMError, // Exported for testing. + attributesFromErr, _moduleNameFromFrames } diff --git a/lib/instrumentation/context.js b/lib/instrumentation/context.js index 00a1be0a170..147adad65f6 100644 --- a/lib/instrumentation/context.js +++ b/lib/instrumentation/context.js @@ -16,8 +16,8 @@ function getPortNumber (port, protocol) { return port } -exports.getHTTPDestination = function (url, spantype) { - const { port, protocol, hostname, origin } = parseUrl(url) +exports.getHTTPDestination = function (url) { + const { port, protocol, hostname } = parseUrl(url) const portNumber = getPortNumber(port, protocol) // If hostname begins with [ and ends with ], assume that it's an IPv6 address. @@ -30,33 +30,28 @@ exports.getHTTPDestination = function (url, spantype) { const address = ipv6Hostname ? hostname.slice(1, -1) : hostname return { - service: { - name: origin, - resource: hostname + ':' + portNumber, - type: spantype - }, address, port: Number(portNumber) } } -exports.getDBDestination = function (span, host, port) { - const { type, subtype } = span - const destination = { - service: { - name: subtype, - resource: subtype, - type - } - } +exports.getDBDestination = function (host, port) { + const destination = {} + let haveValues = false if (host) { destination.address = host + haveValues = true } port = Number(port) if (port) { destination.port = port + haveValues = true } - return destination + if (haveValues) { + return destination + } else { + return null + } } diff --git a/lib/instrumentation/dropped-span-stats.js b/lib/instrumentation/dropped-span-stats.js index 7c6a52cab17..7dc85b8b89c 100644 --- a/lib/instrumentation/dropped-span-stats.js +++ b/lib/instrumentation/dropped-span-stats.js @@ -5,37 +5,53 @@ */ 'use strict' -const LIMIT_STATS = 128 + +const MAX_DROPPED_SPAN_STATS = 128 + class DroppedSpanStats { constructor () { this.statsMap = new Map() } + /** + * Record this span in dropped span stats. + * + * @param {Span} span + * @returns {boolean} True iff this span was added to stats. This return value + * is only used for testing. + */ captureDroppedSpan (span) { - const resource = span && span._destination && span._destination.service && span._destination.service.resource - if (!resource || !span._exitSpan) { - return + if (!span) { + return false + } + + const serviceTargetType = span._serviceTarget && span._serviceTarget.type + const serviceTargetName = span._serviceTarget && span._serviceTarget.name + const resource = span._destination && span._destination.service && span._destination.service.resource + if (!span._exitSpan || !(serviceTargetType || serviceTargetName) || !resource) { + return false } - const stats = this.getOrCreateStats(resource, span.outcome) + const stats = this._getOrCreateStats(serviceTargetType, serviceTargetName, resource, span.outcome) if (!stats) { - return + return false } stats.duration.count++ stats.duration.sum.us += (span._duration * 1000) return true } - getOrCreateStats (resource, outcome) { - const key = [resource, outcome].join('') + _getOrCreateStats (serviceTargetType, serviceTargetName, resource, outcome) { + const key = [serviceTargetType, serviceTargetName, resource, outcome].join('') let stats = this.statsMap.get(key) if (stats) { return stats } - if (this.statsMap.size >= LIMIT_STATS) { + if (this.statsMap.size >= MAX_DROPPED_SPAN_STATS) { return } + stats = { duration: { count: 0, @@ -46,6 +62,12 @@ class DroppedSpanStats { destination_service_resource: resource, outcome: outcome } + if (serviceTargetType) { + stats.service_target_type = serviceTargetType + } + if (serviceTargetName) { + stats.service_target_name = serviceTargetName + } this.statsMap.set(key, stats) return stats } @@ -60,5 +82,8 @@ class DroppedSpanStats { } module.exports = { - DroppedSpanStats + DroppedSpanStats, + + // Exported for testing-only. + MAX_DROPPED_SPAN_STATS } diff --git a/lib/instrumentation/elasticsearch-shared.js b/lib/instrumentation/elasticsearch-shared.js index ab56c14dd1d..75734b001fa 100644 --- a/lib/instrumentation/elasticsearch-shared.js +++ b/lib/instrumentation/elasticsearch-shared.js @@ -10,64 +10,50 @@ // - elasticsearch - the legacy Elasticsearch JS client // - @elastic/elasticsearch - the new Elasticsearch JS client -const querystring = require('querystring') - -// URL paths matching the following pattern will have their query params and -// request body captured in the span (as `context.db.statement`). We match -// a complete URL path component to attempt to avoid accidental matches of -// user data, like `GET /my_index_search/...`. -const pathIsAQuery = /\/(_search|_msearch|_count|_async_search|_sql|_eql)(\/|$)/ - -// (This is exported for testing.) -exports.pathIsAQuery = pathIsAQuery - -// Set the span's `context.db` from the Elasticsearch request querystring and -// body, if the request path looks like it is a query API. -// -// Some ES endpoints, e.g. '_search', support both query params and a body. -// We encode both into 'span.context.db.statement', separated by '\n\n' -// if both are present. E.g. for a possible msearch: -// -// search_type=query_then_fetch&typed_keys=false -// -// {} -// {"query":{"query_string":{"query":"pants"}}} -// -// `path`, `query`, and `body` can all be null or undefined. -exports.setElasticsearchDbContext = function (span, path, query, body) { - if (path && pathIsAQuery.test(path)) { - const parts = [] - if (query) { - if (typeof (query) === 'string') { - parts.push(query) - } else if (typeof (query) === 'object') { - const encodedQuery = querystring.encode(query) - if (encodedQuery) { - parts.push(encodedQuery) - } - } - } - if (body) { - if (typeof (body) === 'string') { - parts.push(body) - } else if (Buffer.isBuffer(body) || typeof body.pipe === 'function') { - // Never serialize a Buffer or a Readable. These guards mirror - // `shouldSerialize()` in the ES client, e.g.: - // https://github.com/elastic/elastic-transport-js/blob/069172506d1fcd544b23747d8c2d497bab053038/src/Transport.ts#L614-L618 - } else if (Array.isArray(body)) { - try { - parts.push(body.map(JSON.stringify).join('\n') + '\n') // ndjson - } catch (_ignoredErr) {} - } else if (typeof (body) === 'object') { - try { - parts.push(JSON.stringify(body)) - } catch (_ignoredErr) {} - } +// Only capture the ES request body if the request path matches the +// `elasticsearchCaptureBodyUrls` config. +function shouldCaptureBody (path, elasticsearchCaptureBodyUrlsRegExp) { + if (!path) { + return false + } + for (var i = 0; i < elasticsearchCaptureBodyUrlsRegExp.length; i++) { + const re = elasticsearchCaptureBodyUrlsRegExp[i] + if (re.test(path)) { + return true } + } + return false +} - span.setDbContext({ - type: 'elasticsearch', - statement: parts.join('\n\n') - }) +/** + * Get an appropriate `span.context.db.statement` for this ES client request, if any. + * https://github.com/elastic/apm/blob/main/specs/agents/tracing-instrumentation-db.md#elasticsearch_capture_body_urls-configuration + * + * @param {string | null} path + * @param {string | null} body + * @param {RegExp[]} elasticsearchCaptureBodyUrlsRegExp + * @return {string | undefined} + */ +function getElasticsearchDbStatement (path, body, elasticsearchCaptureBodyUrlsRegExp) { + if (body && shouldCaptureBody(path, elasticsearchCaptureBodyUrlsRegExp)) { + if (typeof (body) === 'string') { + return body + } else if (Buffer.isBuffer(body) || typeof body.pipe === 'function') { + // Never serialize a Buffer or a Readable. These guards mirror + // `shouldSerialize()` in the ES client, e.g.: + // https://github.com/elastic/elastic-transport-js/blob/069172506d1fcd544b23747d8c2d497bab053038/src/Transport.ts#L614-L618 + } else if (Array.isArray(body)) { + try { + return body.map(JSON.stringify).join('\n') + '\n' // ndjson + } catch (_ignoredErr) {} + } else if (typeof (body) === 'object') { + try { + return JSON.stringify(body) + } catch (_ignoredErr) {} + } } } + +module.exports = { + getElasticsearchDbStatement +} diff --git a/lib/instrumentation/generic-span.js b/lib/instrumentation/generic-span.js index cf93d08a504..f1ffd46cbf7 100644 --- a/lib/instrumentation/generic-span.js +++ b/lib/instrumentation/generic-span.js @@ -179,7 +179,7 @@ GenericSpan.prototype._addLinks = function (links) { } GenericSpan.prototype.setType = function (type = null, subtype = null, action = null) { - this.type = type + this.type = type || constants.DEFAULT_SPAN_TYPE this.subtype = subtype this.action = action } @@ -222,6 +222,10 @@ GenericSpan.prototype.isComposite = function () { return this._compression.isComposite() } +GenericSpan.prototype.getCompositeSum = function () { + return this._compression.composite.sum +} + // https://github.com/elastic/apm/blob/main/specs/agents/tracing-api-otel.md#span-kind // @param {String} kind GenericSpan.prototype._setOTelKind = function (kind) { diff --git a/lib/instrumentation/http-shared.js b/lib/instrumentation/http-shared.js index 32cbb53a250..4e4994140a9 100644 --- a/lib/instrumentation/http-shared.js +++ b/lib/instrumentation/http-shared.js @@ -137,7 +137,7 @@ exports.traceOutgoingRequest = function (agent, moduleName, method) { return function (orig) { return function (...args) { const parentRunContext = ins.currRunContext() - var span = ins.createSpan(null, 'external', 'http') + var span = ins.createSpan(null, 'external', 'http', { exitSpan: true }) var id = span && span.transaction.id agent.logger.debug('intercepted call to %s.%s %o', moduleName, method, { id: id }) @@ -223,7 +223,7 @@ exports.traceOutgoingRequest = function (agent, moduleName, method) { // For details, see: // https://github.com/elastic/apm-agent-nodejs/issues/1769 try { - span.setDestinationContext(getHTTPDestination(url, span.type)) + span._setDestinationContext(getHTTPDestination(url)) } catch (e) { agent.logger.error('Could not set destination context: %s', e.message) } diff --git a/lib/instrumentation/index.js b/lib/instrumentation/index.js index 316ea58d192..c3c871b7b76 100644 --- a/lib/instrumentation/index.js +++ b/lib/instrumentation/index.js @@ -10,20 +10,31 @@ var fs = require('fs') var path = require('path') var hook = require('require-in-the-middle') +const semver = require('semver') +const config = require('../config') var { Ids } = require('./ids') var NamedArray = require('./named-array') var Transaction = require('./transaction') const { BasicRunContextManager, - AsyncHooksRunContextManager + AsyncHooksRunContextManager, + AsyncLocalStorageRunContextManager } = require('./run-context') -const { - getLambdaHandlerInfo -} = require('../lambda') +const { getLambdaHandlerInfo } = require('../lambda') +const undiciInstr = require('./modules/undici') + +const nodeSupportsAsyncLocalStorage = semver.satisfies(process.versions.node, '>=14.5 || ^12.19.0') +// Node v16.5.0 added fetch support (behind `--experimental-fetch` until +// v18.0.0) based on undici@5.0.0. We can instrument undici >=v4.7.1. +const nodeHasInstrumentableFetch = typeof (global.fetch) === 'function' var MODULES = [ ['@elastic/elasticsearch', '@elastic/elasticsearch-canary'], + '@node-redis/client/dist/lib/client', + '@node-redis/client/dist/lib/client/commands-queue', + '@redis/client/dist/lib/client', + '@redis/client/dist/lib/client/commands-queue', 'apollo-server-core', 'aws-sdk', 'bluebird', @@ -52,11 +63,16 @@ var MODULES = [ 'mongodb', 'mysql', 'mysql2', + 'next/dist/server/api-utils/node', + 'next/dist/server/dev/next-dev-server', + 'next/dist/server/next', + 'next/dist/server/next-server', 'pg', 'pug', 'redis', 'restify', 'tedious', + 'undici', 'ws' ] @@ -64,6 +80,7 @@ module.exports = Instrumentation function Instrumentation (agent) { this._agent = agent + this._disableInstrumentationsSet = null this._hook = null // this._hook is only exposed for testing purposes this._started = false this._runCtxMgr = null @@ -179,11 +196,20 @@ Instrumentation.prototype.start = function (runContextClass) { // Could have changed in Agent.start(). this._log = this._agent.logger - if (this._agent._conf.asyncHooks) { - this._runCtxMgr = new AsyncHooksRunContextManager(this._log, runContextClass) - } else { + // Select the appropriate run-context manager. + const confContextManager = this._agent._conf.contextManager + if (confContextManager === config.CONTEXT_MANAGER_PATCH) { this._runCtxMgr = new BasicRunContextManager(this._log, runContextClass) require('./patch-async')(this) + } else if (confContextManager === config.CONTEXT_MANAGER_ASYNCHOOKS) { + this._runCtxMgr = new AsyncHooksRunContextManager(this._log, runContextClass) + } else if (nodeSupportsAsyncLocalStorage) { + this._runCtxMgr = new AsyncLocalStorageRunContextManager(this._log, runContextClass) + } else { + if (confContextManager === config.CONTEXT_MANAGER_ASYNCLOCALSTORAGE) { + this._log.warn(`config includes 'contextManager="${confContextManager}"', but node ${process.version} does not support AsyncLocalStorage for run-context management: falling back to using async_hooks`) + } + this._runCtxMgr = new AsyncHooksRunContextManager(this._log, runContextClass) } const patches = this._agent._conf.addPatch @@ -195,6 +221,11 @@ Instrumentation.prototype.start = function (runContextClass) { this._runCtxMgr.enable() this._startHook() + + if (nodeHasInstrumentableFetch && this._isModuleEnabled('undici')) { + this._log.debug('instrumenting fetch') + undiciInstr.instrumentUndici(this._agent) + } } // Stop active instrumentation and reset global state *as much as possible*. @@ -216,6 +247,10 @@ Instrumentation.prototype.stop = function () { this._hook.unhook() this._hook = null } + + if (nodeHasInstrumentableFetch) { + undiciInstr.uninstrumentUndici() + } } // Reset internal state for (relatively) clean re-use of this Instrumentation. @@ -229,6 +264,13 @@ Instrumentation.prototype.testReset = function () { } } +Instrumentation.prototype._isModuleEnabled = function (modName) { + if (!this._disableInstrumentationsSet) { + this._disableInstrumentationsSet = new Set(this._agent._conf.disableInstrumentations) + } + return this._agent._conf.instrument && !this._disableInstrumentationsSet.has(modName) +} + Instrumentation.prototype._startHook = function () { if (!this._started) return if (this._hook) { @@ -237,12 +279,11 @@ Instrumentation.prototype._startHook = function () { } var self = this - var disabled = new Set(this._agent._conf.disableInstrumentations) this._agent.logger.debug('adding hook to Node.js module loader') this._hook = hook(this._patches.keys, function (exports, name, basedir) { - var enabled = self._agent._conf.instrument && !disabled.has(name) + const enabled = self._isModuleEnabled(name) var pkg, version const isHandlingLambda = self._lambdaHandlerInfo && self._lambdaHandlerInfo.module === name @@ -373,29 +414,37 @@ Instrumentation.prototype.addEndedSpan = function (span) { // if I have ended and I have something buffered, send that buffered thing if (span.getBufferedSpan()) { this._encodeAndSendSpan(span.getBufferedSpan()) + span.setBufferedSpan(null) } - if (!span.isCompressionEligible() || span.getParentSpan().ended) { - const buffered = span.getBufferedSpan() + const parentSpan = span.getParentSpan() + if ((parentSpan && parentSpan.ended) || !span.isCompressionEligible()) { + const buffered = parentSpan && parentSpan.getBufferedSpan() if (buffered) { this._encodeAndSendSpan(buffered) - span.setBufferedSpan(null) + parentSpan.setBufferedSpan(null) } this._encodeAndSendSpan(span) - } else if (!span.getParentSpan().getBufferedSpan()) { + } else if (!parentSpan.getBufferedSpan()) { // span is compressible and there's nothing buffered // add to buffer, move on - span.getParentSpan().setBufferedSpan(span) - } else if (!span.getParentSpan().getBufferedSpan().tryToCompress(span)) { + parentSpan.setBufferedSpan(span) + } else if (!parentSpan.getBufferedSpan().tryToCompress(span)) { // we could not compress span so SEND bufferend span // and buffer the span we could not compress - this._encodeAndSendSpan(span.getParentSpan().getBufferedSpan()) - span.getParentSpan().setBufferedSpan(span) + this._encodeAndSendSpan(parentSpan.getBufferedSpan()) + parentSpan.setBufferedSpan(span) } } } Instrumentation.prototype._encodeAndSendSpan = function (span) { + const duration = span.isComposite() ? span.getCompositeSum() : span.duration() + if (span.discardable && duration / 1000 < this._agent._conf.exitSpanMinDuration) { + span.transaction.captureDroppedSpan(span) + return + } + const agent = this._agent // Note this error as an "inflight" event. See Agent#flush(). const inflightEvents = agent._inflightEvents diff --git a/lib/instrumentation/modules/@elastic/elasticsearch.js b/lib/instrumentation/modules/@elastic/elasticsearch.js index 2c89e8e8e39..722667c565b 100644 --- a/lib/instrumentation/modules/@elastic/elasticsearch.js +++ b/lib/instrumentation/modules/@elastic/elasticsearch.js @@ -26,7 +26,7 @@ // client diagnostic event for these queued ES requests will be wrong. // Currently the APM agent is not patching for this. // -// - When using the non-default `asyncHooks=false` APM Agent option with +// - When using the non-default `contextManager="patch"` APM Agent option with // @elastic/elasticsearch >=8 instrumentation, the diagnostic events do not // have the async run context of the current span. There are two impacts: // 1. Elasticsearch tracing spans will not have additional "http" context @@ -34,11 +34,30 @@ // 2. Users cannot access `apm.currentSpan` inside a diagnostic event handler. const semver = require('semver') +const { URL, URLSearchParams } = require('url') const { getDBDestination } = require('../../context') -const { setElasticsearchDbContext } = require('../../elasticsearch-shared') +const { getElasticsearchDbStatement } = require('../../elasticsearch-shared') const shimmer = require('../../shimmer') +/** + * Get the Elasticsearch cluster name, if possible. + * + * This is currently a partial implementation of: + * https://github.com/elastic/apm/blob/main/specs/agents/tracing-instrumentation-db.md#cluster-name + * + * @param {import("@elastic/elasticsearch").DiagnosticResult || null} + * @returns { string || null } + */ +function getESClusterName (diagResult) { + if (diagResult && diagResult.headers) { + const clusterNameFromHeader = diagResult.headers['x-found-handling-cluster'] + if (clusterNameFromHeader) { + return clusterNameFromHeader + } + } +} + module.exports = function (elasticsearch, agent, { version, enabled }) { if (!enabled) { return elasticsearch @@ -53,6 +72,7 @@ module.exports = function (elasticsearch, agent, { version, enabled }) { const doubleCallsRequestIfNoCb = semver.lt(version, '7.7.0') const ins = agent._instrumentation const isGteV8 = semver.satisfies(version, '>=8', { includePrerelease: true }) + const elasticsearchCaptureBodyUrlsRegExp = agent._conf.elasticsearchCaptureBodyUrlsRegExp agent.logger.debug('shimming elasticsearch.Transport.prototype.{request,getConnection}') shimmer.wrap(elasticsearch.Transport && elasticsearch.Transport.prototype, 'request', wrapRequest) @@ -126,17 +146,6 @@ module.exports = function (elasticsearch, agent, { version, enabled }) { const parentRunContext = ins.currRunContext() const spanRunContext = parentRunContext.enterSpan(span) const finish = ins.bindFunctionToRunContext(spanRunContext, (err, result) => { - // Set DB context. - // In @elastic/elasticsearch@7, `Transport#request` encodes - // `params.{querystring,body}` in-place; use it. In >=8 this encoding is - // no longer in-place. A better eventual solution would be to wrap - // `Connection.request` to capture the serialized params. - setElasticsearchDbContext( - span, - params && params.path, - params && params.querystring, - params && (params.body || params.bulkBody)) - // Set destination context. // Use the connection from wrappedGetConnection() above, if that worked. // Otherwise, fallback to using the first connection on @@ -149,10 +158,10 @@ module.exports = function (elasticsearch, agent, { version, enabled }) { conn = this.connectionPool.connections[0] } const connUrl = conn && conn.url - span.setDestinationContext(getDBDestination(span, + span._setDestinationContext(getDBDestination( connUrl && connUrl.hostname, connUrl && connUrl.port)) - // Gather some HTTP context from the "DiagnosticResult" object. + // Gather some HTTP context. // We are *not* including the response headers b/c they are boring: // // X-elastic-product: Elasticsearch @@ -170,6 +179,8 @@ module.exports = function (elasticsearch, agent, { version, enabled }) { // The result is that with Promise usage of v7, ES client requests that // are queued behind the "product-check" and that reject, won't have a // `diagResult`. + const httpContext = {} + let haveHttpContext = false let diagResult = isGteV8 ? null : result if (!diagResult) { diagResult = diagResultFromSpan.get(span) @@ -178,13 +189,11 @@ module.exports = function (elasticsearch, agent, { version, enabled }) { } } if (diagResult) { - const httpContext = {} - let haveHttpContext = false if (diagResult.statusCode) { haveHttpContext = true httpContext.status_code = diagResult.statusCode } - // *Not* currently adding headers because + if (diagResult.headers && 'content-length' in diagResult.headers) { const contentLength = Number(diagResult.headers['content-length']) if (!isNaN(contentLength)) { @@ -192,10 +201,48 @@ module.exports = function (elasticsearch, agent, { version, enabled }) { httpContext.response = { encoded_body_size: contentLength } } } - if (haveHttpContext) { - span.setHttpContext(httpContext) + } + + // Reconstruct the full URL (including query params). + let origin + if (connUrl) { + origin = connUrl.origin + } else if (diagResult && diagResult.meta && diagResult.meta.connection && diagResult.meta.connection.url) { + try { + origin = new URL(diagResult.meta.connection.url).origin + } catch (_ignoredErr) {} + } + if (origin && params && params.path) { + const fullUrl = new URL(origin) + fullUrl.pathname = params.path + fullUrl.search = new URLSearchParams(params.querystring).toString() + httpContext.url = fullUrl.toString() + haveHttpContext = true + } + + if (haveHttpContext) { + span.setHttpContext(httpContext) + } + + // Set DB context. + const dbContext = { + type: 'elasticsearch' + } + if (params) { + const statement = getElasticsearchDbStatement( + params.path, + params.body || params.bulkBody, + elasticsearchCaptureBodyUrlsRegExp + ) + if (statement) { + dbContext.statement = statement } } + const clusterName = getESClusterName(diagResult) + if (clusterName) { + dbContext.instance = clusterName + } + span.setDbContext(dbContext) if (err) { // Error properties are specified here: diff --git a/lib/instrumentation/modules/@node-redis/client/dist/lib/client.js b/lib/instrumentation/modules/@node-redis/client/dist/lib/client.js new file mode 100644 index 00000000000..524d02f8720 --- /dev/null +++ b/lib/instrumentation/modules/@node-redis/client/dist/lib/client.js @@ -0,0 +1,12 @@ +/* + * Copyright Elasticsearch B.V. and other contributors where applicable. + * Licensed under the BSD 2-Clause License; you may not use this file except in + * compliance with the BSD 2-Clause License. + */ + +// early versions of redis@4 were released under +// the @node-redis namespace. This ensures our +// instrumentation works whether it's required with +// the `@node-redis/client` name or the +// `@redis/client` name +module.exports = require('../../../../@redis/client/dist/lib/client') diff --git a/lib/instrumentation/modules/@node-redis/client/dist/lib/client/commands-queue.js b/lib/instrumentation/modules/@node-redis/client/dist/lib/client/commands-queue.js new file mode 100644 index 00000000000..2a54c94f1f7 --- /dev/null +++ b/lib/instrumentation/modules/@node-redis/client/dist/lib/client/commands-queue.js @@ -0,0 +1,12 @@ +/* + * Copyright Elasticsearch B.V. and other contributors where applicable. + * Licensed under the BSD 2-Clause License; you may not use this file except in + * compliance with the BSD 2-Clause License. + */ + +// early versions of redis@4 were released under +// the @node-redis namespace. This ensures our +// instrumentation works whether it's required with +// the `@node-redis/client` name or the +// `@redis/client` name +module.exports = require('../../../../../@redis/client/dist/lib/client/commands-queue') diff --git a/lib/instrumentation/modules/@redis/client/dist/lib/client.js b/lib/instrumentation/modules/@redis/client/dist/lib/client.js new file mode 100644 index 00000000000..1c630caf5cc --- /dev/null +++ b/lib/instrumentation/modules/@redis/client/dist/lib/client.js @@ -0,0 +1,46 @@ +/* + * Copyright Elasticsearch B.V. and other contributors where applicable. + * Licensed under the BSD 2-Clause License; you may not use this file except in + * compliance with the BSD 2-Clause License. + */ + +// Shim @redis/client's `RedisClient.create` to pass client options down to +// the `RedisCommandsQueue` instrumentation in ./client/commands-queue.js. +const semver = require('semver') +const shimmer = require('../../../../../shimmer') +const { redisClientOptions } = require('../../../../../../../lib/symbols') + +module.exports = function (mod, agent, { version, enabled }) { + if (!enabled) { + return mod + } + if (!semver.satisfies(version, '>=1 <2')) { + agent.logger.debug('@redis/client/dist/lib/client version %s not supported - aborting...', version) + return mod + } + + const RedisClient = mod.default + if (!(RedisClient && typeof RedisClient.create === 'function')) { + agent.logger.debug('cannot instrument @redis/client RedisClient') + return mod + } + + const ins = agent._instrumentation + + agent.logger.debug('shimming @redis/client RedisClient.create') + shimmer.wrap(RedisClient, 'create', function wrap (origCreate) { + return function wrappedCreate (options) { + // Capture the RedisClient options for just the synchronous run of the + // create function. We are relying on the RedisClient constructor + // synchronously creating its RedisCommandsQueue, which we've wrapped + // to pick up these options. This allows the queue instance to determine + // the appropriate destination context for spans it creates. + ins[redisClientOptions] = options + const rv = origCreate.apply(this, arguments) + delete ins[redisClientOptions] + return rv + } + }) + + return mod +} diff --git a/lib/instrumentation/modules/@redis/client/dist/lib/client/commands-queue.js b/lib/instrumentation/modules/@redis/client/dist/lib/client/commands-queue.js new file mode 100644 index 00000000000..8ea55cd6874 --- /dev/null +++ b/lib/instrumentation/modules/@redis/client/dist/lib/client/commands-queue.js @@ -0,0 +1,157 @@ +/* + * Copyright Elasticsearch B.V. and other contributors where applicable. + * Licensed under the BSD 2-Clause License; you may not use this file except in + * compliance with the BSD 2-Clause License. + */ + +const semver = require('semver') +const { getDBDestination } = require('../../../../../../context') +const { redisClientOptions } = require('../../../../../../../../lib/symbols') +const destinationContext = Symbol('destinationContext') + +const TYPE = 'db' +const SUBTYPE = 'redis' +const ACTION = 'query' + +// From https://redis.io/commands/ this is the set of redis commands that have +// *two* tokens for the full command name. +const IS_COMMAND_PREFIX = new Set([ + 'ACL', + 'CLIENT', + 'CLUSTER', + 'COMMAND', + 'CONFIG', + 'FUNCTION', // e.g. FUNCTION LOAD + 'LATENCY', + 'MEMORY', + 'MODULE', + 'OBJECT', + 'PUBSUB', + 'SCRIPT', + 'SLOWLOG', + 'XGROUP', + 'XINFO' +]) + +/** + * Return the redis command name from the given `RedisCommandArguments`. + * + * export type RedisCommandArgument = string | Buffer; + * export type RedisCommandArguments = Array & { preserve?: unknown }; + * + * Examples: + * > commandNameFromArgs(['PING']) + * 'PING' + * > commandNameFromArgs(['SET', 'foo', 'bar']) + * 'SET' + * > commandNameFromArgs(['ACL', 'SETUSER', 'karin', 'on', '+@all', '-@dangerous']) + * 'ACL SETUSER' + */ +function commandNameFromArgs (args) { + if (IS_COMMAND_PREFIX.has(args[0]) && args.length >= 2) { + return args.slice(0, 2).join(' ') + } else { + return args[0] + } +} + +module.exports = function (mod, agent, { version, enabled }) { + if (!enabled) { + return mod + } + if (!semver.satisfies(version, '>=1 <2')) { + agent.logger.debug('@redis/client/dist/lib/client version %s not supported - aborting...', version) + return mod + } + + const RedisCommandsQueue = mod.default + if (!(RedisCommandsQueue && + RedisCommandsQueue.name === 'RedisCommandsQueue' && + RedisCommandsQueue.prototype && + typeof RedisCommandsQueue.prototype.addCommand === 'function')) { + agent.logger.debug('cannot instrument @redis/client') + return mod + } + + const ins = agent._instrumentation + + agent.logger.debug('shimming @redis/client RedisCommandsQueue.prototype.addCommand') + + class RedisCommandsQueueTraced extends RedisCommandsQueue { + constructor () { + super(arguments) + + // Determine destination context to use for Redis spans, using the + // RedisClient `options` passed down from RedisClient.create instrumentation. + if (ins[redisClientOptions]) { + // https://github.com/redis/node-redis/blob/master/docs/client-configuration.md + // Reproducing determination of 'address' and 'port' per + // `RedisClient.#initializeOptions()` + let address = 'localhost' + let port = 6379 + if (ins[redisClientOptions].url) { + const parsed = new URL(ins[redisClientOptions].url) + address = parsed.hostname + if (parsed.port) { + port = parsed.port + } + } + if (ins[redisClientOptions].socket) { + if (ins[redisClientOptions].socket.host) { + address = ins[redisClientOptions].socket.host + } + if (ins[redisClientOptions].socket.port && !isNaN(Number(ins[redisClientOptions].socket.port))) { + port = Number(ins[redisClientOptions].socket.port) + } + } + + this[destinationContext] = getDBDestination(address, port) + } + } + + addCommand (args) { + const commandName = commandNameFromArgs(args) + agent.logger.debug({ commandName }, 'intercepted call to @redis/client RedisCommandsQueue.prototype.addCommand') + const span = ins.createSpan(commandName.toUpperCase(), TYPE, SUBTYPE, ACTION, { exitSpan: true }) + if (!span) { + return super.addCommand.apply(this, arguments) + } + + span.setDbContext({ type: 'redis' }) + + if (this[destinationContext]) { + span._setDestinationContext(this[destinationContext]) + } + + const parentRunContext = ins.currRunContext() + const spanRunContext = parentRunContext.enterSpan(span) + const finish = ins.bindFunctionToRunContext(spanRunContext, err => { + if (err) { + agent.captureError(err) + } + span.end() + }) + + const promise = super.addCommand.apply(this, arguments) + if (promise.then) { + promise.then( + function onResolve (_result) { + finish(null) + }, + function onReject (err) { + finish(err) + } + ) + } else { + // didn't get back the expected promose -- just end the + // span now and accept that those spans will be bogus + // (sync, zero-ish elapsed time). + span.end() + } + return promise + } + } + mod.default = RedisCommandsQueueTraced + + return mod +} diff --git a/lib/instrumentation/modules/aws-sdk/dynamodb.js b/lib/instrumentation/modules/aws-sdk/dynamodb.js index e8b239e5852..e13a13452fc 100644 --- a/lib/instrumentation/modules/aws-sdk/dynamodb.js +++ b/lib/instrumentation/modules/aws-sdk/dynamodb.js @@ -76,21 +76,21 @@ function instrumentationDynamoDb (orig, origArguments, request, AWS, agent, { ve return orig.apply(request, origArguments) } - span.setDbContext({ - instance: getRegionFromRequest(request), - statement: getStatementFromRequest(request), - type: SUBTYPE - }) - span.setDestinationContext({ + const region = getRegionFromRequest(request) + const dbContext = { + type: SUBTYPE, + instance: region + } + const dbStatement = getStatementFromRequest(request) + if (dbStatement) { + dbContext.statement = dbStatement + } + span.setDbContext(dbContext) + span._setDestinationContext({ address: getAddressFromRequest(request), port: getPortFromRequest(request), - service: { - name: SUBTYPE, - type: 'db', - resource: SUBTYPE - }, cloud: { - region: getRegionFromRequest(request) + region } }) diff --git a/lib/instrumentation/modules/aws-sdk/s3.js b/lib/instrumentation/modules/aws-sdk/s3.js index 0f22ec5855d..b6e85488612 100644 --- a/lib/instrumentation/modules/aws-sdk/s3.js +++ b/lib/instrumentation/modules/aws-sdk/s3.js @@ -78,27 +78,25 @@ function instrumentationS3 (orig, origArguments, request, AWS, agent, { version, const httpRequest = request.httpRequest const region = httpRequest && httpRequest.region - // Destination context. - // '.httpRequest.endpoint' might differ from '.service.endpoint' if - // the bucket is in a different region. - const endpoint = httpRequest && httpRequest.endpoint + span.setServiceTarget('s3', resource) const destContext = { + // Typically 'destination.service.resource' is calculated from + // 'service.target' in Span.end(), but S3 is a special case in the spec. service: { - name: SUBTYPE, - type: TYPE + resource } } + // '.httpRequest.endpoint' might differ from '.service.endpoint' if + // the bucket is in a different region. + const endpoint = httpRequest && httpRequest.endpoint if (endpoint) { destContext.address = endpoint.hostname destContext.port = endpoint.port } - if (resource) { - destContext.service.resource = resource - } if (region) { destContext.cloud = { region } } - span.setDestinationContext(destContext) + span._setDestinationContext(destContext) if (response) { // https://docs.aws.amazon.com/AWSJavaScriptSDK/latest/AWS/HttpResponse.html diff --git a/lib/instrumentation/modules/aws-sdk/sns.js b/lib/instrumentation/modules/aws-sdk/sns.js index bce4eba5647..3c870f10f80 100644 --- a/lib/instrumentation/modules/aws-sdk/sns.js +++ b/lib/instrumentation/modules/aws-sdk/sns.js @@ -54,11 +54,6 @@ function getMessageDestinationContextFromRequest (request) { return { address: getAddressFromRequest(request), port: getPortFromRequest(request), - service: { - resource: `${SUBTYPE}/${getDestinationNameFromRequest(request)}`, - type: TYPE, - name: SUBTYPE - }, cloud: { region: getRegionFromRequest(request) } @@ -122,7 +117,7 @@ function instrumentationSns (orig, origArguments, request, AWS, agent, { version return orig.apply(request, origArguments) } - span.setDestinationContext(getMessageDestinationContextFromRequest(request)) + span._setDestinationContext(getMessageDestinationContextFromRequest(request)) span.setMessageContext(getMessageContextFromRequest(request)) const onComplete = function (response) { diff --git a/lib/instrumentation/modules/aws-sdk/sqs.js b/lib/instrumentation/modules/aws-sdk/sqs.js index 63eccf9bf45..e2fe6563f27 100644 --- a/lib/instrumentation/modules/aws-sdk/sqs.js +++ b/lib/instrumentation/modules/aws-sdk/sqs.js @@ -64,14 +64,21 @@ function getRegionFromRequest (request) { return region || '' } +function getAddressFromRequest (request) { + return request && request.service && request.service.endpoint && + request.service.endpoint.hostname +} + +function getPortFromRequest (request) { + return request && request.service && request.service.endpoint && + request.service.endpoint.port +} + // Creates message destination context suitable for setDestinationContext function getMessageDestinationContextFromRequest (request) { const destination = { - service: { - name: SUBTYPE, - resource: `${SUBTYPE}/${getQueueNameFromRequest(request)}`, - type: TYPE - }, + address: getAddressFromRequest(request), + port: getPortFromRequest(request), cloud: { region: getRegionFromRequest(request) } @@ -201,7 +208,7 @@ function instrumentationSqs (orig, origArguments, request, AWS, agent, { version return orig.apply(request, origArguments) } - span.setDestinationContext(getMessageDestinationContextFromRequest(request)) + span._setDestinationContext(getMessageDestinationContextFromRequest(request)) span.setMessageContext(getMessageContextFromRequest(request)) const onComplete = function (response) { diff --git a/lib/instrumentation/modules/cassandra-driver.js b/lib/instrumentation/modules/cassandra-driver.js index b25c9fa903e..29e13e75345 100644 --- a/lib/instrumentation/modules/cassandra-driver.js +++ b/lib/instrumentation/modules/cassandra-driver.js @@ -40,10 +40,20 @@ module.exports = function (cassandra, agent, { version, enabled }) { function wrapAsyncConnect (original) { return async function wrappedAsyncConnect () { const span = ins.createSpan('Cassandra: Connect', 'db', 'cassandra', 'connect', { exitSpan: true }) + if (!span) { + return original.apply(this, arguments) + } + + const dbContext = { type: 'cassandra' } + if (this.keyspace) { + dbContext.instance = this.keyspace + } + span.setDbContext(dbContext) + try { return await original.apply(this, arguments) } finally { - if (span) span.end() + span.end() } } } @@ -55,6 +65,12 @@ module.exports = function (cassandra, agent, { version, enabled }) { return original.apply(this, arguments) } + const dbContext = { type: 'cassandra' } + if (this.keyspace) { + dbContext.instance = this.keyspace + } + span.setDbContext(dbContext) + function resolve () { span.end() } @@ -95,11 +111,12 @@ module.exports = function (cassandra, agent, { version, enabled }) { const queryStrings = queries.map(toQueryString) const query = queryStrings.join(';\n') - - span.setDbContext({ - statement: query, - type: 'cassandra' - }) + const dbContext = { type: 'cassandra', statement: query } + const keyspace = (options && typeof options === 'object' && options.keyspace) || this.keyspace + if (keyspace) { + dbContext.instance = keyspace + } + span.setDbContext(dbContext) function resolve () { span.end() @@ -137,8 +154,13 @@ module.exports = function (cassandra, agent, { version, enabled }) { return original.apply(this, arguments) } - span.setDbContext({ statement: query, type: 'cassandra' }) span.name = sqlSummary(query) + const dbContext = { type: 'cassandra', statement: query } + const keyspace = (options && typeof options === 'object' && options.keyspace) || this.keyspace + if (keyspace) { + dbContext.instance = keyspace + } + span.setDbContext(dbContext) function resolve () { span.end() @@ -176,8 +198,13 @@ module.exports = function (cassandra, agent, { version, enabled }) { return original.apply(this, arguments) } - span.setDbContext({ statement: query, type: 'cassandra' }) span.name = sqlSummary(query) + const dbContext = { type: 'cassandra', statement: query } + const keyspace = (options && typeof options === 'object' && options.keyspace) || this.keyspace + if (keyspace) { + dbContext.instance = keyspace + } + span.setDbContext(dbContext) // Wrap the callback const index = arguments.length - 1 diff --git a/lib/instrumentation/modules/elasticsearch.js b/lib/instrumentation/modules/elasticsearch.js index 0d8b07002fb..d5fae30b585 100644 --- a/lib/instrumentation/modules/elasticsearch.js +++ b/lib/instrumentation/modules/elasticsearch.js @@ -6,11 +6,11 @@ 'use strict' -const URL = require('url').URL +const { URL, URLSearchParams } = require('url') var shimmer = require('../shimmer') var { getDBDestination } = require('../context') -const { setElasticsearchDbContext } = require('../elasticsearch-shared') +const { getElasticsearchDbStatement } = require('../elasticsearch-shared') const startsWithProtocolRE = /^([a-z]+:)?\/\//i const DEFAULT_PORT = 9200 @@ -21,7 +21,8 @@ const DEFAULT_PORT_FROM_PROTO = { // This is an imperfect equivalent of the handling in the `Transport` // constructor and internal `Host` parsing function in the ES client. -function getHostAndPortFromTransportConfig (config) { +// This returns a `URL` object or null. +function getTargetUrlFromTransportConfig (config) { const transportHosts = config ? config.host || config.hosts : null if (!transportHosts) { return null @@ -39,21 +40,23 @@ function getHostAndPortFromTransportConfig (config) { if (!startsWithProtocolRE.test(firstTransportHost)) { firstTransportHost = 'http://' + firstTransportHost } - let u try { - u = new URL(firstTransportHost) + return new URL(firstTransportHost) } catch (_err) { return null } - if (!u.port) { - u.port = DEFAULT_PORT_FROM_PROTO[u.protocol] - } - return [u.hostname, u.port] } else if (typeof firstTransportHost === 'object') { - return [ - firstTransportHost.hostname || firstTransportHost.host, - firstTransportHost.port || DEFAULT_PORT - ] + let proto = firstTransportHost.protocol || 'http:' + if (!proto.endsWith(':')) { + proto += ':' + } + const hostname = firstTransportHost.hostname || firstTransportHost.host + const port = firstTransportHost.port || DEFAULT_PORT + try { + return new URL(proto + '//' + hostname + ':' + port) + } catch (_ignoredErr) { + return null + } } return null @@ -63,6 +66,7 @@ module.exports = function (elasticsearch, agent, { enabled }) { if (!enabled) return elasticsearch const ins = agent._instrumentation + const elasticsearchCaptureBodyUrlsRegExp = agent._conf.elasticsearchCaptureBodyUrlsRegExp agent.logger.debug('shimming elasticsearch.Transport.prototype.request') shimmer.wrap(elasticsearch.Transport && elasticsearch.Transport.prototype, 'request', wrapRequest) @@ -81,17 +85,34 @@ module.exports = function (elasticsearch, agent, { enabled }) { if (span && method && path) { span.name = `Elasticsearch: ${method} ${path}` - setElasticsearchDbContext(span, path, params && params.query, - params && params.body) + // Set DB context. + const dbContext = { + type: 'elasticsearch' + } + const statement = getElasticsearchDbStatement( + path, params && params.body, elasticsearchCaptureBodyUrlsRegExp) + if (statement) { + dbContext.statement = statement + } + span.setDbContext(dbContext) // Get the remote host information from elasticsearch Transport options. - let host, port - const hostAndPort = getHostAndPortFromTransportConfig(this._config) - if (hostAndPort) { - host = hostAndPort[0] - port = hostAndPort[1] + const targetUrl = getTargetUrlFromTransportConfig(this._config) + let port = targetUrl && targetUrl.port + if (!port && targetUrl) { + port = DEFAULT_PORT_FROM_PROTO[targetUrl.protocol] + } + span._setDestinationContext(getDBDestination( + targetUrl && targetUrl.hostname, + port + )) + if (targetUrl) { + targetUrl.pathname = path + targetUrl.search = new URLSearchParams(params.query).toString() + span.setHttpContext({ + url: targetUrl.toString() + }) } - span.setDestinationContext(getDBDestination(span, host, port)) const parentRunContext = ins.currRunContext() const spanRunContext = parentRunContext.enterSpan(span) diff --git a/lib/instrumentation/modules/graphql.js b/lib/instrumentation/modules/graphql.js index 7bc2ebf5ba1..b9ef4e78a56 100644 --- a/lib/instrumentation/modules/graphql.js +++ b/lib/instrumentation/modules/graphql.js @@ -23,6 +23,19 @@ module.exports = function (graphql, agent, { version, enabled }) { return graphql } + // Over the many versions the `graphql()` and `execute()` functions have + // changed in what arguments they accept: + // - Initially they only supported positional arguments: + // function graphql(schema, requestString, rootValue, contextValue, variableValues, operationName) + // - Starting in v0.10.0 (in #356), they started accepting a second form where + // all fields were passed in an object as the first argument: + // function graphql(argsOrSchema, source, rootValue, contextValue, variableValues, operationName, fieldResolver) + // and `arguments.length === 1` was used as the test to determine which. + // - Starting in v16 (in #2904), they dropped positional arguments: + // function graphql(args) + const onlySupportsPositionalArgs = semver.lt(version, '0.10.0') + const onlySupportsSingleArg = semver.gte(version, '16.0.0') + const ins = agent._instrumentation return clone({}, graphql, { @@ -57,13 +70,12 @@ module.exports = function (graphql, agent, { version, enabled }) { let schema let source let operationName - if (arguments.length === 1) { + const singleArgForm = onlySupportsSingleArg || (!onlySupportsPositionalArgs && arguments.length === 1) + if (singleArgForm) { schema = args.schema source = args.source operationName = args.operationName } else { - // graphql <=v15 supported positional arguments: - // function (schema, source, rootValue, contextValue, variableValues, operationName) schema = arguments[0] source = arguments[1] operationName = arguments[5] @@ -112,12 +124,11 @@ module.exports = function (graphql, agent, { version, enabled }) { let document let operationName - if (arguments.length === 1) { + const singleArgForm = onlySupportsSingleArg || (!onlySupportsPositionalArgs && arguments.length === 1) + if (singleArgForm) { document = args.document operationName = args.operationName } else { - // graphql <=v15 supported positional arguments: - // function (schema, document, rootValue, contextValue, variableValues, operationName) document = arguments[1] operationName = arguments[5] } diff --git a/lib/instrumentation/modules/http2.js b/lib/instrumentation/modules/http2.js index 9bb5b3cf24d..2a8106b1649 100644 --- a/lib/instrumentation/modules/http2.js +++ b/lib/instrumentation/modules/http2.js @@ -275,7 +275,7 @@ module.exports = function (http2, agent, { enabled }) { // For details, see: // https://github.com/elastic/apm-agent-nodejs/issues/1769 try { - span.setDestinationContext(getHTTPDestination(url, span.type)) + span._setDestinationContext(getHTTPDestination(url)) } catch (e) { agent.logger.error('Could not set destination context: %s', e.message) } diff --git a/lib/instrumentation/modules/ioredis.js b/lib/instrumentation/modules/ioredis.js index 4095610599d..d26712eb004 100644 --- a/lib/instrumentation/modules/ioredis.js +++ b/lib/instrumentation/modules/ioredis.js @@ -16,8 +16,9 @@ const constants = require('../../constants') const { getDBDestination } = require('../context') const shimmer = require('../shimmer') -const TYPE = 'cache' +const TYPE = 'db' const SUBTYPE = 'redis' +const ACTION = 'query' const hasIoredisSpanSym = Symbol('ElasticAPMHasIoredisSpan') module.exports = function (ioredis, agent, { version, enabled }) { @@ -48,7 +49,7 @@ module.exports = function (ioredis, agent, { version, enabled }) { } agent.logger.debug({ command: command.name }, 'intercepted call to ioredis.prototype.sendCommand') - const span = ins.createSpan(command.name.toUpperCase(), TYPE, SUBTYPE, { exitSpan: true }) + const span = ins.createSpan(command.name.toUpperCase(), TYPE, SUBTYPE, ACTION, { exitSpan: true }) if (!span) { return origSendCommand.apply(this, arguments) } @@ -56,7 +57,8 @@ module.exports = function (ioredis, agent, { version, enabled }) { command[hasIoredisSpanSym] = true const options = this.options || {} // `this` is the `Redis` client. - span.setDestinationContext(getDBDestination(span, options.host, options.port)) + span._setDestinationContext(getDBDestination(options.host, options.port)) + span.setDbContext({ type: 'redis' }) const spanRunContext = ins.currRunContext().enterSpan(span) command.promise.then( diff --git a/lib/instrumentation/modules/knex.js b/lib/instrumentation/modules/knex.js index 84c04b3fc7f..f2012940878 100644 --- a/lib/instrumentation/modules/knex.js +++ b/lib/instrumentation/modules/knex.js @@ -4,6 +4,10 @@ * compliance with the BSD 2-Clause License. */ +// Knex instrumentation exists to capture a more useful span stacktrace at +// the start of a Knex query, and use that stacktrace on the 'pg' or 'mysql' +// span. + 'use strict' var semver = require('semver') @@ -12,11 +16,23 @@ var shimmer = require('../shimmer') var symbols = require('../../symbols') module.exports = function (Knex, agent, { version, enabled }) { - if (!enabled) return Knex + if (!enabled) { + return Knex + } + if (agent._conf.spanStackTraceMinDuration < 0) { + agent.logger.trace('not instrumenting knex because not capturing span stack traces (spanStackTraceMinDuration=%s)', + agent._conf.spanStackTraceMinDuration) + return Knex + } if (semver.gte(version, '1.0.0')) { agent.logger.debug('knex version %s not supported - aborting...', version) return Knex } + if (semver.gte(version, '0.95.0') && agent._conf.contextManager === 'patch') { + agent.logger.debug('knex >=0.95.0 instrumentation is not supported with contextManager=patch config', version) + return Knex + } + if (Knex.Client && Knex.Client.prototype) { var QUERY_FNS = ['queryBuilder', 'raw'] agent.logger.debug('shimming Knex.Client.prototype.runner') diff --git a/lib/instrumentation/modules/koa-router.js b/lib/instrumentation/modules/koa-router.js index 94fc7f943f8..4a08e404bae 100644 --- a/lib/instrumentation/modules/koa-router.js +++ b/lib/instrumentation/modules/koa-router.js @@ -12,7 +12,7 @@ var shimmer = require('../shimmer') module.exports = function (Router, agent, { version, enabled }) { if (!enabled) return Router - if (!semver.satisfies(version, '>=5.2.0 <=10')) { + if (!semver.satisfies(version, '>=5.2.0 <=12')) { agent.logger.debug('koa-router version %s not supported - aborting...', version) return Router } diff --git a/lib/instrumentation/modules/memcached.js b/lib/instrumentation/modules/memcached.js index 1c7ce0a7a63..cb848178997 100644 --- a/lib/instrumentation/modules/memcached.js +++ b/lib/instrumentation/modules/memcached.js @@ -35,7 +35,7 @@ module.exports = function (memcached, agent, { version, enabled }) { if (currentSpan) { const [host, port = 11211] = server.split(':') - currentSpan.setDestinationContext(getDBDestination(currentSpan, host, port)) + currentSpan._setDestinationContext(getDBDestination(host, port)) } return original.apply(this, arguments) } diff --git a/lib/instrumentation/modules/mongodb-core.js b/lib/instrumentation/modules/mongodb-core.js index 7221e7072e1..ab08f7e671e 100644 --- a/lib/instrumentation/modules/mongodb-core.js +++ b/lib/instrumentation/modules/mongodb-core.js @@ -8,6 +8,7 @@ var semver = require('semver') +const { getDBDestination } = require('../context') var shimmer = require('../shimmer') var SERVER_FNS = ['insert', 'update', 'remove', 'auth'] @@ -59,6 +60,7 @@ module.exports = function (mongodb, agent, { version, enabled }) { span = ins.createSpan(ns + '.' + type, 'db', 'mongodb', 'query', { exitSpan: true }) if (span) { + span.setDbContext({ type: 'mongodb', instance: ns }) arguments[index] = ins.bindFunctionToRunContext(ins.currRunContext(), wrappedCallback) } } @@ -66,8 +68,12 @@ module.exports = function (mongodb, agent, { version, enabled }) { return orig.apply(this, arguments) - function wrappedCallback () { + function wrappedCallback (_err, commandResult) { agent.logger.debug('intercepted mongodb-core.Server.prototype.command callback %o', { id: id }) + if (commandResult && commandResult.connection) { + span._setDestinationContext(getDBDestination( + commandResult.connection.host, commandResult.connection.port)) + } span.end() return cb.apply(this, arguments) } @@ -88,6 +94,7 @@ module.exports = function (mongodb, agent, { version, enabled }) { if (typeof cb === 'function') { span = ins.createSpan(ns + '.' + name, 'db', 'mongodb', 'query', { exitSpan: true }) if (span) { + span.setDbContext({ type: 'mongodb', instance: ns }) arguments[index] = ins.bindFunctionToRunContext(ins.currRunContext(), wrappedCallback) } } @@ -95,8 +102,12 @@ module.exports = function (mongodb, agent, { version, enabled }) { return orig.apply(this, arguments) - function wrappedCallback () { + function wrappedCallback (_err, commandResult) { agent.logger.debug('intercepted mongodb-core.Server.prototype.%s callback %o', name, { id: id }) + if (commandResult && commandResult.connection) { + span._setDestinationContext(getDBDestination( + commandResult.connection.host, commandResult.connection.port)) + } span.end() return cb.apply(this, arguments) } @@ -118,6 +129,9 @@ module.exports = function (mongodb, agent, { version, enabled }) { span = ins.createSpan(spanName, 'db', 'mongodb', 'query', { exitSpan: true }) } if (span) { + span.setDbContext({ type: 'mongodb', instance: this.ns }) + // Limitation: Currently not getting destination address/port for + // cursor calls. arguments[0] = ins.bindFunctionToRunContext(ins.currRunContext(), wrappedCallback) if (name === 'next') { this[firstSpan] = true diff --git a/lib/instrumentation/modules/mongodb.js b/lib/instrumentation/modules/mongodb.js index 35821652134..5fd892291ba 100644 --- a/lib/instrumentation/modules/mongodb.js +++ b/lib/instrumentation/modules/mongodb.js @@ -123,10 +123,11 @@ module.exports = (mongodb, agent, { version, enabled }) => { event.commandName ].join('.') - const span = ins.createSpan(name, 'db', 'mongodb', 'query', { exitSpan: true }) + const span = ins.createSpan(name, 'db', 'mongodb', event.commandName, { exitSpan: true }) if (span) { activeSpans.set(event.requestId, span) + // Destination context. // Per the following code it looks like ":" should be // available via the `address` or `connectionId` field. // https://github.com/mongodb/node-mongodb-native/blob/dd356f0ede/lib/core/connection/apm.js#L155-L169 @@ -134,11 +135,13 @@ module.exports = (mongodb, agent, { version, enabled }) => { let match if (address && typeof (address) === 'string' && (match = HOSTNAME_PORT_RE.exec(address))) { - span.setDestinationContext( - getDBDestination(span, match[1], match[2])) + span._setDestinationContext(getDBDestination(match[1], match[2])) } else { agent.logger.trace('could not set destination context on mongodb span from address=%j', address) } + + const dbContext = { type: 'mongodb', instance: event.databaseName } + span.setDbContext(dbContext) } } diff --git a/lib/instrumentation/modules/mysql.js b/lib/instrumentation/modules/mysql.js index 6294cac370a..750394b1fed 100644 --- a/lib/instrumentation/modules/mysql.js +++ b/lib/instrumentation/modules/mysql.js @@ -98,9 +98,9 @@ function wrapQueryable (connection, objType, agent) { agent.logger.debug('shimming mysql %s.query', objType) shimmer.wrap(connection, 'query', wrapQuery) - let host, port + let host, port, user, database if (typeof connection.config === 'object') { - ({ host, port } = connection.config) + ({ host, port, user, database } = connection.config) } function wrapQuery (original) { @@ -145,10 +145,10 @@ function wrapQueryable (connection, objType, agent) { if (sqlStr) { agent.logger.debug({ sql: sqlStr }, 'extracted sql from mysql query') - span.setDbContext({ statement: sqlStr, type: 'sql' }) + span.setDbContext({ statement: sqlStr, type: 'sql', user, instance: database }) span.name = sqlSummary(sqlStr) } - span.setDestinationContext(getDBDestination(span, host, port)) + span._setDestinationContext(getDBDestination(host, port)) if (typeof values === 'function') { arguments[1] = wrapCallback(values) diff --git a/lib/instrumentation/modules/mysql2.js b/lib/instrumentation/modules/mysql2.js index 6088cdb4449..fd02d8f32d0 100644 --- a/lib/instrumentation/modules/mysql2.js +++ b/lib/instrumentation/modules/mysql2.js @@ -52,6 +52,12 @@ module.exports = function (mysql2, agent, { version, enabled }) { }) } + let host, port, user, database + if (typeof this.config === 'object') { + ({ host, port, user, database } = this.config) + } + span._setDestinationContext(getDBDestination(host, port)) + let sqlStr switch (typeof sql) { case 'string': @@ -70,17 +76,11 @@ module.exports = function (mysql2, agent, { version, enabled }) { break } if (sqlStr) { - span.setDbContext({ statement: sqlStr, type: 'sql' }) + span.setDbContext({ type: 'sql', instance: database, user, statement: sqlStr }) span.name = sqlSummary(sqlStr) } else { - span.setDbContext({ type: 'sql' }) - } - - let host, port - if (typeof this.config === 'object') { - ({ host, port } = this.config) + span.setDbContext({ type: 'sql', instance: database, user }) } - span.setDestinationContext(getDBDestination(span, host, port)) if (typeof values === 'function') { arguments[1] = wrapCallback(values) diff --git a/lib/instrumentation/modules/next/README.md b/lib/instrumentation/modules/next/README.md new file mode 100644 index 00000000000..165ba137022 --- /dev/null +++ b/lib/instrumentation/modules/next/README.md @@ -0,0 +1,84 @@ +# Next.js instrumentation dev notes + +Instrumenting the Next.js servers (the dev and prod servers) involves shimming +a number of files. An overview of the instrumentation is provided here. +Some of the complexity here is that I found the Next.js server internals not +always ammenable to instrumentation. There isn't a clean separation between +"determine the route", "run the handler for that route", "expose an error +or the result". + +There are a number of ways to deploy (https://nextjs.org/docs/deployment) a +Next.js app. This instrumentation works with "Self-Hosting", and using Next.js's +built-in server. + +Here is the Next.js "server" class hierarchy: + + class Server (in base-server.ts) + class NextNodeServer (in next-server.ts, used for `next start`) + class DevServer (in dev/next-dev-server.js, used for `next dev`) + + +## dist/server/next.js + +This is the first module imported for `require('next')`. It is used solely +to `agent.setFramework(...)`. Doing so in "next-server.js" can be too late +because it is lazily imported when creating the Next server -- by which point +metadata may have already been sent on the first APM agent intake request. + + +## dist/server/next-server.js + +This file in the "next" package implements the `NextNodeServer`, the Next.js +"production" server used by `next start`. Most instrumentation is on this class. + +The Next.js server is a vanilla Node.js `http.createServer` (http-only, https +termination isn't supported) using `NextNodeServer.handleRequest` as the request +handler, so every request to the server is a call to that method. + +User routes are defined by files under "pages/". Generally, an incoming request path: + GET /a-page +is resolved to one of those pages: + ./pages/a-page.js +The user files under "./pages/" are loaded by `NextNodeServer.findPageComponents`. +**We instrument `findPageComponents` to capture the resolved page name to use +for the transaction name.** + +There are also other built-in routes to handle redirects, rewrites, static-file +serving (e.g. `GET /favicon.ico -> ./public/favicon.ico`), and various internal +`/_next/...` routes used by the Next.js client code for bundle loading, +server-side generated page data, etc. At server start, a call to +`.generateRoutes()` is called which returns a somewhat regular data structure +with routing data. **We instrument *most* of these routes to set +`transaction.name` appropriately for most of these internal routes.** A notable +limitation is the `public folder catchall` route that could not be cleanly +instrumented. + +An error in rendering a page results in `renderErrorToResponse(err)` being +called to handle that error. **We instrument `renderErrorToResponse` to +`apm.captureError()` those errors.** (Limitation: There are some edge cases +where this method is not used to handle an exception. This instrumentation isn't +capturing those.) + +*API* routes ("pages/api/...") are handled differently from other pages. +The `catchAllRoute` route handler calls `handleApiRequest`, which resolves +the URL path to a possibly dynamic route name (e.g. `/api/widgets/[id]`, +**we instrument `ensureApiPage` to get that resolve route name**), loads the +webpack-compiled user module for that route, and calls `apiResolver` in +"api-utils/node.ts" to execute. **We instrument that `apiResolve()` function +to capture any errors in the user's handler.** + + +## dist/server/dev/next-dev-server.js + +This file defines the `DevServer` used by `next dev`. It subclasses +`NextNodeServer`. The instrumentation in this file is **very** similar to that +in "next-server.js". However, some of it needs to be repeated on the `DevServer` +class to capture results specific to the dev-server. For example +`DevServer.generateRoutes()` includes some additional routes. + + +## dist/server/api-utils/node.js + +See the `apiResolve()` mention above. + + diff --git a/lib/instrumentation/modules/next/dist/server/api-utils/node.js b/lib/instrumentation/modules/next/dist/server/api-utils/node.js new file mode 100644 index 00000000000..59a4b007107 --- /dev/null +++ b/lib/instrumentation/modules/next/dist/server/api-utils/node.js @@ -0,0 +1,88 @@ +/* + * Copyright Elasticsearch B.V. and other contributors where applicable. + * Licensed under the BSD 2-Clause License; you may not use this file except in + * compliance with the BSD 2-Clause License. + */ + +'use strict' + +// See "lib/instrumentation/modules/next/README.md". + +const semver = require('semver') + +const shimmer = require('../../../../../shimmer') + +const kErrIsCaptured = Symbol.for('ElasticAPMNextJsErrIsCaptured') + +module.exports = function (mod, agent, { version, enabled }) { + if (!enabled) { + return mod + } + if (!semver.satisfies(version, '>=11.1.0 <14.0.0', { includePrerelease: true })) { + agent.logger.debug('next/dist/server/api-utils/node.js version %s not supported, skipping', version) + return mod + } + + const wrappedModFromMod = new WeakMap() + + shimmer.wrap(mod, 'apiResolver', wrapApiResolver) + + return mod + + function wrapApiResolver (orig) { + return function wrappedApiResolver (_req, _res, _query, resolverModule, _apiContext, _propagateError, _dev, _page) { + // The user module that we are wrapping is a webpack-wrapped build that + // exposes fields only as getters. We therefore need to fully replace + // the module to be able to wrap the single `.default` field. + // + // Cache `wrappedMod` so we only need to create it once per API endpoint, + // rather than every time each API endpoint is called. + let wrappedMod = wrappedModFromMod.get(resolverModule) + if (!wrappedMod) { + wrappedMod = {} + const names = Object.getOwnPropertyNames(resolverModule) + for (let i = 0; i < names.length; i++) { + const name = names[i] + if (name !== 'default') { + // Proxy other module fields. + Object.defineProperty(wrappedMod, name, { enumerable: true, get: function () { return resolverModule[name] } }) + } + } + wrappedMod.default = wrapApiHandler(resolverModule.default || resolverModule) + wrappedModFromMod.set(resolverModule, wrappedMod) + } + arguments[3] = wrappedMod + + return orig.apply(this, arguments) + } + } + + function wrapApiHandler (orig) { + // This wraps a user's API handler in order to capture an error if there + // is one. For example: + // // pages/api/some-endpoint-path.js + // export default function handler(req, res) { + // // ... + // throw new Error('boom') + // } + // That handler might also be async, in which case it returns a promise + // that we want to watch for a possible rejection. + return function wrappedApiHandler () { + let promise + try { + promise = orig.apply(this, arguments) + } catch (syncErr) { + agent.captureError(syncErr) + syncErr[kErrIsCaptured] = true + throw syncErr + } + if (promise) { + promise.catch(rejectErr => { + agent.captureError(rejectErr) + rejectErr[kErrIsCaptured] = true + }) + } + return promise + } + } +} diff --git a/lib/instrumentation/modules/next/dist/server/dev/next-dev-server.js b/lib/instrumentation/modules/next/dist/server/dev/next-dev-server.js new file mode 100644 index 00000000000..ab1e70523ca --- /dev/null +++ b/lib/instrumentation/modules/next/dist/server/dev/next-dev-server.js @@ -0,0 +1,199 @@ +/* + * Copyright Elasticsearch B.V. and other contributors where applicable. + * Licensed under the BSD 2-Clause License; you may not use this file except in + * compliance with the BSD 2-Clause License. + */ + +'use strict' + +// See "lib/instrumentation/modules/next/README.md". + +const semver = require('semver') + +const shimmer = require('../../../../../shimmer') + +const kSetTransNameFn = Symbol.for('ElasticAPMNextJsSetTransNameFn') + +const noopFn = () => {} + +module.exports = function (mod, agent, { version, enabled }) { + if (!enabled) { + return mod + } + if (!semver.satisfies(version, '>=11.1.0 <14.0.0', { includePrerelease: true })) { + agent.logger.debug('next version %s not supported, skipping', version) + return mod + } + + const ins = agent._instrumentation + const log = agent.logger + + const DevServer = mod.default + shimmer.wrap(DevServer.prototype, 'generateRoutes', wrapGenerateRoutes) + shimmer.wrap(DevServer.prototype, 'ensureApiPage', wrapEnsureApiPage) + shimmer.wrap(DevServer.prototype, 'findPageComponents', wrapFindPageComponents) + // Instrumenting the DevServer also uses the wrapping of + // 'NextNodeServer.renderErrorToResponse' in "next-server.js". + + return mod + + // The `route` objects being wrapped here have this type: + // https://github.com/vercel/next.js/blob/v12.3.0/packages/next/server/router.ts#L26-L45 + function wrapGenerateRoutes (orig) { + return function wrappedGenerateRoutes () { + if (this.constructor !== DevServer) { + return orig.apply(this, arguments) + } + const routes = orig.apply(this, arguments) + log.debug('wrap Next.js DevServer routes') + routes.redirects.forEach(wrapRedirectRoute) + routes.rewrites.beforeFiles.forEach(wrapRewriteRoute) + routes.rewrites.afterFiles.forEach(wrapRewriteRoute) + routes.rewrites.fallback.forEach(wrapRewriteRoute) + routes.fsRoutes.forEach(wrapFsRoute) + wrapCatchAllRoute(routes.catchAllRoute) + return routes + } + } + + function wrapRedirectRoute (route) { + if (typeof route.fn !== 'function') { + return + } + const origRouteFn = route.fn + route.fn = function () { + const trans = ins.currTransaction() + if (trans) { + trans.setDefaultName('Next.js ' + route.name) + trans[kSetTransNameFn] = noopFn + } + return origRouteFn.apply(this, arguments) + } + } + + function wrapRewriteRoute (route) { + if (typeof route.fn !== 'function') { + return + } + const origRouteFn = route.fn + route.fn = function () { + const trans = ins.currTransaction() + if (trans) { + trans.setDefaultName(`Next.js ${route.name} -> ${route.destination}`) + trans[kSetTransNameFn] = noopFn + } + return origRouteFn.apply(this, arguments) + } + } + + // "FS" routes are those that go looking for matching paths on the filesystem + // to fulfill the request. + function wrapFsRoute (route) { + if (typeof route.fn !== 'function') { + return + } + const origRouteFn = route.fn + // We explicitly handle only the `fsRoute`s that we know by name in the + // Next.js code. We cannot set `trans.name` for all of them because of the + // true catch-all-routes that match any path and only sometimes handle them + // (e.g. 'public folder catchall'). + switch (route.name) { + case '_next/data catchall': + // This handles "/_next/data/..." paths that are used by Next.js + // client-side code to call `getServerSideProps()` for user pages. + route.fn = function () { + const trans = ins.currTransaction() + if (trans) { + trans.setDefaultName(`Next.js ${route.name}`) + if (!trans[kSetTransNameFn]) { + trans[kSetTransNameFn] = (_req, pathname) => { + trans.setDefaultName(`Next.js _next/data route ${pathname}`) + trans[kSetTransNameFn] = noopFn + } + } + } + return origRouteFn.apply(this, arguments) + } + break + case '_next/static/development/_devMiddlewareManifest.json': + case '_next/static/development/_devPagesManifest.json': + case '_next/development catchall': + case '_next/static catchall': + case '_next/image catchall': + case '_next catchall': + route.fn = function () { + const trans = ins.currTransaction() + if (trans) { + trans.setDefaultName(`Next.js ${route.name}`) + } + return origRouteFn.apply(this, arguments) + } + break + } + } + + function wrapCatchAllRoute (route) { + if (typeof route.fn !== 'function') { + return + } + const origRouteFn = route.fn + route.fn = function () { + const trans = ins.currTransaction() + // This is a catchall route, so only set a kSetTransNameFn if a more + // specific route wrapper hasn't already done so. + if (trans && !trans[kSetTransNameFn]) { + trans[kSetTransNameFn] = (req, pathname) => { + trans.setDefaultName(`${req.method} ${pathname}`) + // Ensure only the first `findPageComponents` result sets the trans + // name, otherwise a loaded `/_error` for page error handling could + // incorrectly override. + trans[kSetTransNameFn] = noopFn + } + } + return origRouteFn.apply(this, arguments) + } + } + + function wrapEnsureApiPage (orig) { + return function wrappedEnsureApiPage (pathname) { + if (this.constructor !== DevServer) { + return orig.apply(this, arguments) + } + const trans = ins.currTransaction() + if (trans && trans.req) { + log.trace({ pathname }, 'set transaction name from ensureApiPage') + trans.setDefaultName(`${trans.req.method} ${pathname}`) + trans[kSetTransNameFn] = noopFn + } + return orig.apply(this, arguments) + } + } + + // `findPageComponents` is used to load any "./pages/..." files. It provides + // the resolved path appropriate for the transaction name. + function wrapFindPageComponents (orig) { + return function wrappedFindPageComponents (pathnameOrArgs) { + if (this.constructor !== DevServer) { + return orig.apply(this, arguments) + } + + // In next <=12.2.6-canary.10 the function signature is: + // async findPageComponents(pathname, query, params, isAppPath) + // after that version it is: + // async findPageComponents({ pathname, query, params, isAppPath }) + const pathname = typeof pathnameOrArgs === 'string' ? pathnameOrArgs : pathnameOrArgs.pathname + + const promise = orig.apply(this, arguments) + promise.then(findComponentsResult => { + if (findComponentsResult) { + const trans = ins.currTransaction() + if (trans && trans.req && trans[kSetTransNameFn]) { + log.trace({ pathname }, 'set transaction name from findPageComponents') + trans[kSetTransNameFn](trans.req, pathname) + } + } + }) + return promise + } + } +} diff --git a/lib/instrumentation/modules/next/dist/server/next-server.js b/lib/instrumentation/modules/next/dist/server/next-server.js new file mode 100644 index 00000000000..0431e260d07 --- /dev/null +++ b/lib/instrumentation/modules/next/dist/server/next-server.js @@ -0,0 +1,224 @@ +/* + * Copyright Elasticsearch B.V. and other contributors where applicable. + * Licensed under the BSD 2-Clause License; you may not use this file except in + * compliance with the BSD 2-Clause License. + */ + +'use strict' + +// See "lib/instrumentation/modules/next/README.md". + +const semver = require('semver') + +const shimmer = require('../../../../shimmer') + +const kSetTransNameFn = Symbol.for('ElasticAPMNextJsSetTransNameFn') +const kErrIsCaptured = Symbol.for('ElasticAPMNextJsErrIsCaptured') + +const noopFn = () => {} + +module.exports = function (mod, agent, { version, enabled }) { + if (!enabled) { + return mod + } + if (!semver.satisfies(version, '>=11.1.0 <14.0.0', { includePrerelease: true })) { + agent.logger.debug('next version %s not supported, skipping', version) + return mod + } + + const ins = agent._instrumentation + const log = agent.logger + + const NextNodeServer = mod.default + shimmer.wrap(NextNodeServer.prototype, 'generateRoutes', wrapGenerateRoutes) + shimmer.wrap(NextNodeServer.prototype, 'ensureApiPage', wrapEnsureApiPage) + shimmer.wrap(NextNodeServer.prototype, 'findPageComponents', wrapFindPageComponents) + shimmer.wrap(NextNodeServer.prototype, 'renderErrorToResponse', wrapRenderErrorToResponse) + + return mod + + // The `route` objects being wrapped here have this type: + // https://github.com/vercel/next.js/blob/v12.3.0/packages/next/server/router.ts#L26-L45 + function wrapGenerateRoutes (orig) { + return function wrappedGenerateRoutes () { + if (this.constructor !== NextNodeServer) { + return orig.apply(this, arguments) + } + const routes = orig.apply(this, arguments) + log.debug('wrap Next.js NodeNextServer routes') + routes.redirects.forEach(wrapRedirectRoute) + routes.rewrites.beforeFiles.forEach(wrapRewriteRoute) + routes.rewrites.afterFiles.forEach(wrapRewriteRoute) + routes.rewrites.fallback.forEach(wrapRewriteRoute) + routes.fsRoutes.forEach(wrapFsRoute) + wrapCatchAllRoute(routes.catchAllRoute) + return routes + } + } + + function wrapRedirectRoute (route) { + if (typeof route.fn !== 'function') { + return + } + const origRouteFn = route.fn + route.fn = function () { + const trans = ins.currTransaction() + if (trans) { + trans.setDefaultName('Next.js ' + route.name) + trans[kSetTransNameFn] = noopFn + } + return origRouteFn.apply(this, arguments) + } + } + + function wrapRewriteRoute (route) { + if (typeof route.fn !== 'function') { + return + } + const origRouteFn = route.fn + route.fn = function () { + const trans = ins.currTransaction() + if (trans) { + trans.setDefaultName(`Next.js ${route.name} -> ${route.destination}`) + trans[kSetTransNameFn] = noopFn + } + return origRouteFn.apply(this, arguments) + } + } + + // "FS" routes are those that go looking for matching paths on the filesystem + // to fulfill the request. + function wrapFsRoute (route) { + if (typeof route.fn !== 'function') { + return + } + const origRouteFn = route.fn + // We explicitly handle only the `fsRoute`s that we know by name in the + // Next.js code. We cannot set `trans.name` for all of them because of the + // true catch-all-routes that match any path and only sometimes handle them + // (e.g. 'public folder catchall'). + switch (route.name) { + case '_next/data catchall': + // This handles "/_next/data/..." paths that are used by Next.js + // client-side code to call `getServerSideProps()` for user pages. + route.fn = function () { + const trans = ins.currTransaction() + if (trans) { + trans.setDefaultName(`Next.js ${route.name}`) + if (!trans[kSetTransNameFn]) { + trans[kSetTransNameFn] = (_req, pathname) => { + trans.setDefaultName(`Next.js _next/data route ${pathname}`) + trans[kSetTransNameFn] = noopFn + } + } + } + return origRouteFn.apply(this, arguments) + } + break + case '_next/static catchall': + case '_next/image catchall': + case '_next catchall': + route.fn = function () { + const trans = ins.currTransaction() + if (trans) { + trans.setDefaultName(`Next.js ${route.name}`) + } + return origRouteFn.apply(this, arguments) + } + break + } + } + + function wrapCatchAllRoute (route) { + if (typeof route.fn !== 'function') { + return + } + const origRouteFn = route.fn + route.fn = function () { + const trans = ins.currTransaction() + // This is a catchall route, so only set a kSetTransNameFn if a more + // specific route wrapper hasn't already done so. + if (trans && !trans[kSetTransNameFn]) { + trans[kSetTransNameFn] = (req, pathname) => { + trans.setDefaultName(`${req.method} ${pathname}`) + // Ensure only the first `findPageComponents` result sets the trans + // name, otherwise a loaded `/_error` for page error handling could + // incorrectly override. + trans[kSetTransNameFn] = noopFn + } + } + return origRouteFn.apply(this, arguments) + } + } + + function wrapEnsureApiPage (orig) { + return function wrappedEnsureApiPage (pathname) { + if (this.constructor !== NextNodeServer) { + return orig.apply(this, arguments) + } + const trans = ins.currTransaction() + if (trans && trans.req) { + log.trace({ pathname }, 'set transaction name from ensureApiPage') + trans.setDefaultName(`${trans.req.method} ${pathname}`) + trans[kSetTransNameFn] = noopFn + } + return orig.apply(this, arguments) + } + } + + // `findPageComponents` is used to load any "./pages/..." files. It provides + // the resolved path appropriate for the transaction name. + function wrapFindPageComponents (orig) { + return function wrappedFindPageComponents (pathnameOrArgs) { + if (this.constructor !== NextNodeServer) { + return orig.apply(this, arguments) + } + + // In next <=12.2.6-canary.10 the function signature is: + // async findPageComponents(pathname, query, params, isAppPath) + // after that version it is: + // async findPageComponents({ pathname, query, params, isAppPath }) + const pathname = typeof pathnameOrArgs === 'string' ? pathnameOrArgs : pathnameOrArgs.pathname + + const promise = orig.apply(this, arguments) + promise.then(findComponentsResult => { + if (findComponentsResult) { + const trans = ins.currTransaction() + if (trans && trans.req && trans[kSetTransNameFn]) { + log.trace({ pathname }, 'set transaction name from findPageComponents') + trans[kSetTransNameFn](trans.req, pathname) + } + } + }) + return promise + } + } + + function wrapRenderErrorToResponse (orig) { + return function wrappedRenderErrorToResponse (ctx, err) { + // The wrapped `NodeNextServer.renderErrorToResponse` is used for both + // this and the "next-dev-sever.js" instrumentation, so it doesn't have + // the `this.constructor !== ...` guard that the above wrappers do. + + const trans = ins.currTransaction() + if (trans) { + // Next.js is now doing error handling for this request, which typically + // means loading the "_error.js" page component. We don't want + // that `findPageComponents` call to set the transaction name. + trans[kSetTransNameFn] = noopFn + } + + // - Next.js uses `err=null` to handle a 404. + // - To capture errors in API handlers we have shimmed `apiResolver` (see + // "api-utils/node.js"). In the dev server only, `renderErrorToResponse` + // is *also* called for the error -- and in v12.2.6 and below it is + // called *twice*. The `kErrIsCaptured` guard prevents capturing + // the same error twice. + if (err && !err[kErrIsCaptured]) { + agent.captureError(err) + err[kErrIsCaptured] = true + } + return orig.apply(this, arguments) + } + } +} diff --git a/lib/instrumentation/modules/next/dist/server/next.js b/lib/instrumentation/modules/next/dist/server/next.js new file mode 100644 index 00000000000..ff930a25547 --- /dev/null +++ b/lib/instrumentation/modules/next/dist/server/next.js @@ -0,0 +1,29 @@ +/* + * Copyright Elasticsearch B.V. and other contributors where applicable. + * Licensed under the BSD 2-Clause License; you may not use this file except in + * compliance with the BSD 2-Clause License. + */ + +'use strict' + +// See "lib/instrumentation/modules/next/README.md". + +const semver = require('semver') + +module.exports = function (mod, agent, { version, enabled }) { + if (!enabled) { + return mod + } + if (!semver.satisfies(version, '>=11.1.0 <14.0.0', { includePrerelease: true })) { + agent.logger.debug('next version %s not supported, skipping', version) + return mod + } + + // This isn't perfect. Which framework the agent will report with a + // custom Next.js server using another framework, e.g. + // https://github.com/vercel/next.js/blob/canary/examples/custom-server-fastify/server.js + // depends on which is *imported* first. + agent.setFramework({ name: 'Next.js', version, overwrite: false }) + + return mod +} diff --git a/lib/instrumentation/modules/pg.js b/lib/instrumentation/modules/pg.js index e7774ec6395..dca971b3794 100644 --- a/lib/instrumentation/modules/pg.js +++ b/lib/instrumentation/modules/pg.js @@ -60,23 +60,31 @@ function patchClient (Client, klass, agent) { return orig.apply(this, arguments) } + // Get connection parameters from Client. + let host, port, database, user + if (typeof this.connectionParameters === 'object') { + ({ host, port, database, user } = this.connectionParameters) + } + span._setDestinationContext(getDBDestination(host, port)) + + const dbContext = { type: 'sql' } let sqlText = sql if (sql && typeof sql.text === 'string') { sqlText = sql.text } if (typeof sqlText === 'string') { - span.setDbContext({ statement: sqlText, type: 'sql' }) span.name = sqlSummary(sqlText) + dbContext.statement = sqlText } else { agent.logger.debug('unable to parse sql form pg module (type: %s)', typeof sqlText) } - - // Get connection parameters from Client. - let host, port - if (typeof this.connectionParameters === 'object') { - ({ host, port } = this.connectionParameters) + if (database) { + dbContext.instance = database + } + if (user) { + dbContext.user = user } - span.setDestinationContext(getDBDestination(span, host, port)) + span.setDbContext(dbContext) if (this[symbols.knexStackObj]) { span.customStackTrace(this[symbols.knexStackObj]) diff --git a/lib/instrumentation/modules/redis.js b/lib/instrumentation/modules/redis.js index a0c1ae1b7e6..b8a4b507ba0 100644 --- a/lib/instrumentation/modules/redis.js +++ b/lib/instrumentation/modules/redis.js @@ -14,8 +14,9 @@ var { getDBDestination } = require('../context') const isWrappedRedisCbSym = Symbol('ElasticAPMIsWrappedRedisCb') -const TYPE = 'cache' +const TYPE = 'db' const SUBTYPE = 'redis' +const ACTION = 'query' module.exports = function (redis, agent, { version, enabled }) { if (!enabled) { @@ -79,13 +80,14 @@ module.exports = function (redis, agent, { version, enabled }) { const command = commandObj.command agent.logger.debug({ command: command }, 'intercepted call to RedisClient.prototype.internal_send_command') - const span = ins.createSpan(command.toUpperCase(), TYPE, SUBTYPE, { exitSpan: true }) + const span = ins.createSpan(command.toUpperCase(), TYPE, SUBTYPE, ACTION, { exitSpan: true }) if (!span) { return original.apply(this, arguments) } const connOpts = connOptsFromRedisClient(this) - span.setDestinationContext(getDBDestination(span, connOpts.host, connOpts.port)) + span._setDestinationContext(getDBDestination(connOpts.host, connOpts.port)) + span.setDbContext({ type: 'redis' }) const spanRunContext = ins.currRunContext().enterSpan(span) commandObj.callback = makeWrappedCallback(spanRunContext, span, commandObj.callback) @@ -111,13 +113,14 @@ module.exports = function (redis, agent, { version, enabled }) { } agent.logger.debug({ command: command }, 'intercepted call to RedisClient.prototype.send_command') - var span = ins.createSpan(command.toUpperCase(), TYPE, SUBTYPE, { exitSpan: true }) + var span = ins.createSpan(command.toUpperCase(), TYPE, SUBTYPE, ACTION, { exitSpan: true }) if (!span) { return original.apply(this, arguments) } const connOpts = connOptsFromRedisClient(this) - span.setDestinationContext(getDBDestination(span, connOpts.host, connOpts.port)) + span._setDestinationContext(getDBDestination(connOpts.host, connOpts.port)) + span.setDbContext({ type: 'redis' }) const spanRunContext = ins.currRunContext().enterSpan(span) const wrappedCb = makeWrappedCallback(spanRunContext, span, origCb) diff --git a/lib/instrumentation/modules/restify.js b/lib/instrumentation/modules/restify.js index a851030427c..be93a096e8d 100644 --- a/lib/instrumentation/modules/restify.js +++ b/lib/instrumentation/modules/restify.js @@ -11,7 +11,13 @@ const semver = require('semver') const shimmer = require('../shimmer') module.exports = function (restify, agent, { version, enabled }) { - if (!enabled) return restify + if (!enabled) { + return restify + } + if (!semver.satisfies(version, '>=5.2.0 <11.0.0')) { + agent.logger.debug('restify version %s not supported, skipping', version) + return restify + } agent.setFramework({ name: 'restify', version, overwrite: false }) diff --git a/lib/instrumentation/modules/tedious.js b/lib/instrumentation/modules/tedious.js index 585b97cec99..5304bd6fad2 100644 --- a/lib/instrumentation/modules/tedious.js +++ b/lib/instrumentation/modules/tedious.js @@ -14,7 +14,7 @@ var { getDBDestination } = require('../context') module.exports = function (tedious, agent, { version, enabled }) { if (!enabled) return tedious - if (!semver.satisfies(version, '^1.9.0 || 2.x || 3.x || ^4.0.1 || 5.x || 6.x || 7.x || 8.x || 9.x || 10.x || 11.x || 12.x || 13.x || 14.x')) { + if (!semver.satisfies(version, '^1.9.0 || 2.x || 3.x || ^4.0.1 || 5.x || 6.x || 7.x || 8.x || 9.x || 10.x || 11.x || 12.x || 13.x || 14.x || 15.x')) { agent.logger.debug('tedious version %s not supported - aborting...', version) return tedious } @@ -80,6 +80,17 @@ module.exports = function (tedious, agent, { version, enabled }) { return super.makeRequest(...arguments) } + let host, port, instanceName + if (typeof this.config === 'object') { + // http://tediousjs.github.io/tedious/api-connection.html#function_newConnection + host = this.config.server + if (this.config.options) { + port = this.config.options.port + instanceName = this.config.options.instanceName + } + } + span._setDestinationContext(getDBDestination(host, port)) + let sql let preparing if (payload.parameters !== undefined) { @@ -96,17 +107,15 @@ module.exports = function (tedious, agent, { version, enabled }) { sql = (params.statement || params.stmt || {}).value } span.name = sqlSummary(sql) + (preparing ? ' (prepare)' : '') - span.setDbContext({ statement: sql, type: 'sql' }) - // extract hostname and port from connection config - let host, port - if (typeof this.config === 'object') { - host = this.config.server - port = this.config.options && this.config.options.port + const dbContext = { type: 'sql', statement: sql } + if (instanceName) { + dbContext.instance = instanceName } - span.setDestinationContext(getDBDestination(span, host, port)) + span.setDbContext(dbContext) const origCallback = request.userCallback request.userCallback = ins.bindFunction(function tracedCallback () { + // TODO: captureError and setOutcome on err first arg here span.end() if (origCallback) { return origCallback.apply(this, arguments) diff --git a/lib/instrumentation/modules/undici.js b/lib/instrumentation/modules/undici.js new file mode 100644 index 00000000000..8218e10bf0f --- /dev/null +++ b/lib/instrumentation/modules/undici.js @@ -0,0 +1,223 @@ +/* + * Copyright Elasticsearch B.V. and other contributors where applicable. + * Licensed under the BSD 2-Clause License; you may not use this file except in + * compliance with the BSD 2-Clause License. + */ + +'use strict' + +// Instrument the undici module. +// +// This uses undici's diagnostics_channel support for instrumentation. +// https://github.com/nodejs/undici/blob/main/docs/api/DiagnosticsChannel.md +// Undici is also used for Node >=v18.0.0's `fetch()` implementation, via +// an esbuild bundle. This instrumentation is enabled if either `global.fetch` +// is present or `require('undici')`. +// +// Limitations: +// - Currently this isn't subscribing to 'undici:client:...' messages. +// With typical undici usage a connection will only be initiated for a +// request. However, if a user manually does `client.connect(...)` then it is +// possible for this instrumentation to miss a connection error from +// 'undici:client:connectError'. It would eventually be nice to heuristically +// add 'connect' spans as children of request spans. +// - This doesn't instrument HTTP CONNECT, as exposed by `undici.connect(...)`. +// I don't think the current undici diagnostics_channel messages provide a +// way to watch the completion of the CONNECT request. +// - This hasn't been tested with `undici.upgrade()`. +// +// Some notes on if/when we want to collect some HTTP client metrics: +// - The time between 'undici:client:connected' and 'undici:client:sendHeaders' +// could be a measure of client-side latency. I'm not sure if client-side +// queueing of requests would show a time gap here. +// - The time between 'undici:client:sendHeaders' and 'undici:client:bodySent' +// might be interesting for large bodies, or perhaps for streaming requests. +// - The time between 'undici:client:bodySent' and 'undici:request:headers' +// could be a measure of response TTFB latency. + +let diagch = null +try { + diagch = require('diagnostics_channel') +} catch (_importErr) { + // pass +} + +const semver = require('semver') + +let isInstrumented = false +let spanFromReq = null +let chans = null + +// Get the content-length from undici response headers. +// `headers` is an Array of buffers: [k, v, k, v, ...]. +// If the header is not present, or has an invalid value, this returns null. +function contentLengthFromResponseHeaders (headers) { + const name = 'content-length' + for (let i = 0; i < headers.length; i += 2) { + const k = headers[i] + if (k.length === name.length && k.toString().toLowerCase() === name) { + const v = Number(headers[i + 1]) + if (!isNaN(v)) { + return v + } else { + return null + } + } + } + return null +} + +function uninstrumentUndici () { + if (!isInstrumented) { + return + } + isInstrumented = false + + spanFromReq = null + chans.forEach(({ chan, onMessage }) => { + chan.unsubscribe(onMessage) + }) + chans = null +} + +/** + * Setup instrumentation for undici. The instrumentation is based entirely on + * diagnostics_channel usage, so no reference to the loaded undici module is + * required. + */ +function instrumentUndici (agent) { + if (isInstrumented) { + return + } + isInstrumented = true + + const ins = agent._instrumentation + spanFromReq = new WeakMap() + + // Keep ref to avoid https://github.com/nodejs/node/issues/42170 bug and for + // unsubscribing. + chans = [] + function diagchSub (name, onMessage) { + const chan = diagch.channel(name) + chan.subscribe(onMessage) + chans.push({ + name, + chan, + onMessage + }) + } + + diagchSub('undici:request:create', ({ request }) => { + // We do not handle instrumenting HTTP CONNECT. See limitation notes above. + if (request.method === 'CONNECT') { + return + } + + const url = new URL(request.origin) + const span = ins.createSpan(`${request.method} ${url.host}`, 'external', 'http', request.method, { exitSpan: true }) + + // W3C trace-context propagation. + // If the span is null (e.g. hit `transactionMaxSpans`, unsampled + // transaction), then fallback to the current run context's span or + // transaction, if any. + const parentRunContext = ins.currRunContext() + const propSpan = span || parentRunContext.currSpan() || parentRunContext.currTransaction() + if (propSpan) { + propSpan.propagateTraceContextHeaders(request, function (req, name, value) { + req.addHeader(name, value) + }) + } + + if (span) { + spanFromReq.set(request, span) + + // Set some initial HTTP context, in case the request errors out before a response. + span.setHttpContext({ + method: request.method, + url: request.origin + request.path + }) + + const destContext = { + address: url.hostname + } + const port = Number(url.port) || (url.protocol === 'https:' && 443) || (url.protocol === 'http:' && 80) + if (port) { + destContext.port = port + } + span._setDestinationContext(destContext) + } + }) + + diagchSub('undici:request:headers', ({ request, response }) => { + const span = spanFromReq.get(request) + if (span !== undefined) { + // We are currently *not* capturing response headers, even though the + // intake API does allow it, because none of the other `setHttpContext` + // uses currently do. + + const httpContext = { + method: request.method, + status_code: response.statusCode, + url: request.origin + request.path + } + const cLen = contentLengthFromResponseHeaders(response.headers) + if (cLen !== null) { + httpContext.response = { encoded_body_size: cLen } + } + span.setHttpContext(httpContext) + + span._setOutcomeFromHttpStatusCode(response.statusCode) + } + }) + + diagchSub('undici:request:trailers', ({ request }) => { + const span = spanFromReq.get(request) + if (span !== undefined) { + span.end() + spanFromReq.delete(request) + } + }) + + diagchSub('undici:request:error', ({ request, error }) => { + const span = spanFromReq.get(request) + const errOpts = {} + if (span !== undefined) { + errOpts.parent = span + // Cases where we won't have an undici parent span: + // - We've hit transactionMaxSpans. + // - The undici HTTP span was suppressed because it is a child of an + // exit span (e.g. when used as the transport for the Elasticsearch + // client). + // It might be debatable whether we want to capture the error in the + // latter case. This could be revisited later. + } + agent.captureError(error, errOpts) + if (span !== undefined) { + span.end() + spanFromReq.delete(request) + } + }) +} + +function shimUndici (undici, agent, { version, enabled }) { + if (!enabled) { + return undici + } + if (semver.lt(version, '4.7.1')) { + // Undici added its diagnostics_channel messages in v4.7.0. In v4.7.1 the + // `request.origin` property, that we need, was added. + agent.logger.debug('cannot instrument undici: undici version %s is not supported', version) + return undici + } + if (!diagch) { + agent.logger.debug('cannot instrument undici: there is no "diagnostics_channel" module', process.version) + return undici + } + + instrumentUndici(agent) + return undici +} + +module.exports = shimUndici +module.exports.instrumentUndici = instrumentUndici +module.exports.uninstrumentUndici = uninstrumentUndici diff --git a/lib/instrumentation/run-context/AbstractRunContextManager.js b/lib/instrumentation/run-context/AbstractRunContextManager.js index f79b360fb54..42d317dff8c 100644 --- a/lib/instrumentation/run-context/AbstractRunContextManager.js +++ b/lib/instrumentation/run-context/AbstractRunContextManager.js @@ -6,6 +6,8 @@ 'use strict' +const { RunContext } = require('./RunContext') + const ADD_LISTENER_METHODS = [ 'addListener', 'on', @@ -16,9 +18,10 @@ const ADD_LISTENER_METHODS = [ // An abstract base RunContextManager class that implements the following // methods that all run context manager implementations can share: -// bindFn -// bindEE -// isEEBound +// root() +// bindFn(runContext, target) +// bindEE(runContext, eventEmitter) +// isEEBound(eventEmitter) // and stubs out the remaining public methods of the RunContextManager // interface. // @@ -26,9 +29,19 @@ const ADD_LISTENER_METHODS = [ // The implementation is adapted from // https://github.com/open-telemetry/opentelemetry-js/blob/main/packages/opentelemetry-context-async-hooks/src/AbstractAsyncHooksContextManager.ts) class AbstractRunContextManager { - constructor (log) { + constructor (log, runContextClass = RunContext) { this._log = log this._kListeners = Symbol('ElasticListeners') + this._root = new runContextClass() // eslint-disable-line new-cap + } + + // Get the root run context. This is always empty (no current trans or span). + // + // This is the equivalent of OTel JS API's `ROOT_CONTEXT` constant. Ours + // is not a top-level constant, because the RunContext class can be + // overriden. + root () { + return this._root } enable () { diff --git a/lib/instrumentation/run-context/AsyncLocalStorageRunContextManager.js b/lib/instrumentation/run-context/AsyncLocalStorageRunContextManager.js new file mode 100644 index 00000000000..77901620039 --- /dev/null +++ b/lib/instrumentation/run-context/AsyncLocalStorageRunContextManager.js @@ -0,0 +1,73 @@ +/* + * Copyright Elasticsearch B.V. and other contributors where applicable. + * Licensed under the BSD 2-Clause License; you may not use this file except in + * compliance with the BSD 2-Clause License. + */ + +'use strict' + +const { AsyncLocalStorage } = require('async_hooks') + +const { AbstractRunContextManager } = require('./AbstractRunContextManager') + +/** + * A RunContextManager that uses core node `AsyncLocalStorage` as the mechanism + * for run-context tracking. + * + * (Adapted from https://github.com/open-telemetry/opentelemetry-js/blob/main/packages/opentelemetry-context-async-hooks/src/AsyncLocalStorageContextManager.ts) + */ +class AsyncLocalStorageRunContextManager extends AbstractRunContextManager { + constructor (log, runContextClass) { + super(log, runContextClass) + this._asyncLocalStorage = new AsyncLocalStorage() + } + + // A string representation useful for debug logging. For example, + // AsyncLocalStorageRunContextManager( RC(Trans(685ead, manual), [Span(9dd31c, GET httpstat.us, ended)]) ) + toString () { + return `${this.constructor.name}( ${this.active().toString()} )` + } + + enable () { + return this + } + + disable () { + this._asyncLocalStorage.disable() + return this + } + + // Reset state for re-use of this context manager by tests in the same process. + testReset () { + this.disable() + this.enable() + } + + active () { + const store = this._asyncLocalStorage.getStore() + if (store == null) { + return this.root() + } else { + return store + } + } + + with (runContext, fn, thisArg, ...args) { + const cb = thisArg == null ? fn : fn.bind(thisArg) + return this._asyncLocalStorage.run(runContext, cb, ...args) + } + + // This public method is needed to support the semantics of + // apm.startTransaction() and apm.startSpan() that impact the current run + // context. + // + // Otherwise, all run context changes are via `.with()` -- scoped to a + // function call -- or via the "before" async hook -- scoped to an async task. + supersedeRunContext (runContext) { + this._asyncLocalStorage.enterWith(runContext) + } +} + +module.exports = { + AsyncLocalStorageRunContextManager +} diff --git a/lib/instrumentation/run-context/BasicRunContextManager.js b/lib/instrumentation/run-context/BasicRunContextManager.js index ddb8f9debb1..606d0a61b63 100644 --- a/lib/instrumentation/run-context/BasicRunContextManager.js +++ b/lib/instrumentation/run-context/BasicRunContextManager.js @@ -7,31 +7,19 @@ 'use strict' const { AbstractRunContextManager } = require('./AbstractRunContextManager') -const { RunContext } = require('./RunContext') // A basic manager for run context. It handles a stack of run contexts, but does // no automatic tracking (via async_hooks or otherwise). In combination with -// "patch-async.js" it does an adequate job of context tracking for much of the +// "patch-async.js" it does a limited job of context tracking for much of the // core Node.js API. // // (Adapted from https://github.com/open-telemetry/opentelemetry-js/blob/main/packages/opentelemetry-context-async-hooks/src/AsyncHooksContextManager.ts) class BasicRunContextManager extends AbstractRunContextManager { - constructor (log, runContextClass = RunContext) { - super(log) - this._runContextClass = runContextClass - this._root = new this._runContextClass() + constructor (log, runContextClass) { + super(log, runContextClass) this._stack = [] // Top of stack is the current run context. } - // Get the root run context. This is always empty (no current trans or span). - // - // This is the equivalent of OTel JS API's `ROOT_CONTEXT` constant. Ours - // is not a top-level constant, because the RunContext class can be - // overriden. - root () { - return this._root - } - // A string representation useful for debug logging. For example, // BasicRunContextManager( // RC(Trans(685ead, manual), [Span(9dd31c, GET httpstat.us, ended)]), @@ -56,7 +44,7 @@ class BasicRunContextManager extends AbstractRunContextManager { } active () { - return this._stack[this._stack.length - 1] || this._root + return this._stack[this._stack.length - 1] || this.root() } with (runContext, fn, thisArg, ...args) { diff --git a/lib/instrumentation/run-context/index.js b/lib/instrumentation/run-context/index.js index b73aa6428dc..017c2fcc72b 100644 --- a/lib/instrumentation/run-context/index.js +++ b/lib/instrumentation/run-context/index.js @@ -7,11 +7,13 @@ 'use strict' const { AsyncHooksRunContextManager } = require('./AsyncHooksRunContextManager') +const { AsyncLocalStorageRunContextManager } = require('./AsyncLocalStorageRunContextManager') const { BasicRunContextManager } = require('./BasicRunContextManager') const { RunContext } = require('./RunContext') module.exports = { AsyncHooksRunContextManager, + AsyncLocalStorageRunContextManager, BasicRunContextManager, RunContext } diff --git a/lib/instrumentation/span-compression.js b/lib/instrumentation/span-compression.js index a5a7bd74c3b..80dc24f00ab 100644 --- a/lib/instrumentation/span-compression.js +++ b/lib/instrumentation/span-compression.js @@ -37,7 +37,7 @@ class SpanCompression { // @param Span toCompressSpan // @returns boolean|String _getCompressionStrategy (compositeSpan, toCompressSpan) { - if (!this._isEnabled() || !compositeSpan._destination || !toCompressSpan._destination) { + if (!this._isEnabled() || !compositeSpan._serviceTarget || !toCompressSpan._serviceTarget) { return false } @@ -57,8 +57,9 @@ class SpanCompression { isSameKind (compositeSpan, toCompressSpan) { return compositeSpan.type === toCompressSpan.type && - compositeSpan.subtype === toCompressSpan.subtype && - compositeSpan._destination.service.resource === toCompressSpan._destination.service.resource + compositeSpan.subtype === toCompressSpan.subtype && + compositeSpan._serviceTarget.type === toCompressSpan._serviceTarget.type && + compositeSpan._serviceTarget.name === toCompressSpan._serviceTarget.name } // Sets initial composite values or confirms strategy matches @@ -146,7 +147,7 @@ class SpanCompression { if (this.duration <= (this._agent._conf.spanCompressionSameKindMaxDuration * 1000) && spanToCompress._duration <= (this._agent._conf.spanCompressionSameKindMaxDuration * 1000)) { this.composite.compression_strategy = STRATEGY_SAME_KIND - compositeSpan.name = 'Calls to ' + compositeSpan._destination.service.resource + compositeSpan.name = this._spanNameFromCompositeSpan(compositeSpan) return true } @@ -165,6 +166,22 @@ class SpanCompression { } } + _spanNameFromCompositeSpan (compositeSpan) { + const prefix = 'Calls to ' + const serviceTarget = compositeSpan._serviceTarget + if (!serviceTarget.type) { + if (!serviceTarget.name) { + return prefix + 'unknown' + } else { + return prefix + serviceTarget.name + } + } else if (!serviceTarget.name) { + return prefix + serviceTarget.type + } else { + return prefix + serviceTarget.type + '/' + serviceTarget.name + } + } + _isEnabled () { return this._agent._conf.spanCompressionEnabled } diff --git a/lib/instrumentation/span.js b/lib/instrumentation/span.js index 41cf80f271a..bb1586380b5 100644 --- a/lib/instrumentation/span.js +++ b/lib/instrumentation/span.js @@ -7,6 +7,7 @@ 'use strict' const { executionAsyncId } = require('async_hooks') +const { URL } = require('url') var util = require('util') var Value = require('async-value-promise') @@ -33,6 +34,13 @@ function Span (transaction, ...args) { : {} const [name, ...tsaArgs] = args // "tsa" === Type, Subtype, Action + if (opts.timer) { + process.emitWarning( + 'specifying the `timer` option to `new Span()` was never a public API and will be removed', + 'DeprecationWarning', + 'ELASTIC_APM_SPAN_TIMER_OPTION' + ) + } if (!opts.childOf) { const defaultChildOf = transaction._agent._instrumentation.currSpan() || transaction opts.childOf = defaultChildOf @@ -42,6 +50,8 @@ function Span (transaction, ...args) { } this._exitSpan = !!opts.exitSpan + this.discardable = this._exitSpan + delete opts.exitSpan GenericSpan.call(this, transaction._agent, ...tsaArgs, opts) @@ -49,6 +59,8 @@ function Span (transaction, ...args) { this._db = null this._http = null this._destination = null + this._serviceTarget = null + this._excludeServiceTarget = false this._message = null this._stackObj = null this._capturedStackTrace = null @@ -97,6 +109,8 @@ Span.prototype.end = function (endTime) { this._setOutcomeFromSpanEnd() + this._inferServiceTargetAndDestinationService() + this.ended = true this._agent.logger.debug('ended span %o', { span: this.id, parent: this.parentId, trace: this.traceId, name: this.name, type: this.type, subtype: this.subtype, action: this.action }) @@ -125,6 +139,80 @@ Span.prototype.end = function (endTime) { this.transaction._captureBreakdown(this) } +Span.prototype._inferServiceTargetAndDestinationService = function () { + // `context.service.target.*` must be set for exit spans. There is a public + // `span.setServiceTarget(...)` for users to manually set this, but typically + // it is inferred from other span fields here. + // https://github.com/elastic/apm/blob/main/specs/agents/tracing-spans-service-target.md#field-values + if (this._excludeServiceTarget || !this._exitSpan) { + this._serviceTarget = null + } else { + if (!this._serviceTarget) { + this._serviceTarget = {} + } + if (!('type' in this._serviceTarget)) { + this._serviceTarget.type = this.subtype || this.type || constants.DEFAULT_SPAN_TYPE + } + if (!('name' in this._serviceTarget)) { + if (this._db) { + if (this._db.instance) { + this._serviceTarget.name = this._db.instance + } + } else if (this._message) { + if (this._message.queue && this._message.queue.name) { + this._serviceTarget.name = this._message.queue.name + } + } else if (this._http && this._http.url) { + try { + this._serviceTarget.name = new URL(this._http.url).host + } catch (invalidUrlErr) { + this._agent.logger.debug('cannot set "service.target.name": %s (ignoring)', invalidUrlErr) + } + } + } + + // `destination.service.*` is deprecated, but still required for older + // APM servers. + if (!this._destination) { this._destination = {} } + if (!this._destination.service) { this._destination.service = {} } + // - `destination.service.{type,name}` could be skipped if the upstream APM server is known to be >=7.14. + this._destination.service.type = '' + this._destination.service.name = '' + // - Infer the now deprecated `context.destination.service.resource` value. + // https://github.com/elastic/apm/blob/main/specs/agents/tracing-spans-destination.md#destination-resource + if (!this._destination.service.resource) { + if (!this._serviceTarget.name) { + // If we only have `.type`, then use that. + this._destination.service.resource = this._serviceTarget.type + } else if (!this._serviceTarget.type) { + // If we only have `.name`, then use that. + this._destination.service.resource = this._serviceTarget.name + } else if (this.type === 'external') { + // Typically the "resource" value would now be "$type/$name", e.g. + // "mysql/customers". However, we want a special case for some spans (to + // have the same value as historically?) where we do NOT use the + // "$type/" prefix. One example is HTTP spans. Another is gRPC spans + // and, I infer from otel_bridge.feature, any OTel "rpc.system"-usage + // spans as well + // (https://opentelemetry.io/docs/reference/specification/trace/semantic_conventions/rpc/). + // Options to infer this from other span data: + // - Use the presence of "http" context, but without "db" and "message" + // context. This is a little brittle, and requires more complete OTel + // bridge compatibility mapping of OTel attributes than is currently + // being done. + // } else if (!this._db && !this._message && this._http && this._http.url) { + // - Use `span.subtype`: "http", "grpc", ... add others if/when they are + // used. + // - Use `span.type === "external"`. This, at least currently corresponds. + // Let's use this one. + this._destination.service.resource = this._serviceTarget.name + } else { + this._destination.service.resource = `${this._serviceTarget.type}/${this._serviceTarget.name}` + } + } + } +} + Span.prototype.setDbContext = function (context) { if (!context) return this._db = Object.assign(this._db || {}, context) @@ -135,8 +223,86 @@ Span.prototype.setHttpContext = function (context) { this._http = Object.assign(this._http || {}, context) } -Span.prototype.setDestinationContext = function (context) { - this._destination = Object.assign(this._destination || {}, context) +/** + * This is deprecated and will be dropped in a future version. This was always + * an internal method, but possibly used by enterprising users of manual + * instrumentation. + * + * @deprecated Users should use the public `setServiceTarget()`. + * Internal APM agent code should use `_setDestinationContext()`. + */ +Span.prototype.setDestinationContext = function (destCtx) { + process.emitWarning( + '.setDestinationContext() was never a public API and will be removed, use .setServiceTarget().', + 'DeprecationWarning', + 'ELASTIC_APM_SET_DESTINATION_CONTEXT' + ) + + if (destCtx.service && destCtx.service.resource) { + this.setServiceTarget('', destCtx.service.resource) + } + const destCtxWithoutService = Object.assign({}, destCtx) + delete destCtxWithoutService.service + this._setDestinationContext(destCtxWithoutService) +} + +/** + * The internal method for setting "destination" context. + * + * "destination.service.resource" should only ever be included for special + * cases. It is typically inferred from other fields via a general algorithm. + */ +Span.prototype._setDestinationContext = function (destCtx) { + this._destination = Object.assign(this._destination || {}, destCtx) +} + +/** + * Manually set the `service.target.type` and `service.target.name` fields that + * are used for service maps and the identification of downstream services. The + * values are only used for "exit" spans -- spans representing outgoing + * communication, marked with `exitSpan: true` at span creation. + * + * If false-y values (e.g. `null`) are given for both `type` and `name`, then + * `service.target` will explicitly be excluded from this span. This may impact + * Service Maps and other Kibana APM app reporting for this service. + * + * If this method is not called, values are inferred from other span fields per + * https://github.com/elastic/apm/blob/main/specs/agents/tracing-spans-service-target.md#field-values + * + * `service.target.*` fields are ignored for APM Server before v8.3. + * + * @param {string | null} type - service target type, usually same value as + * `span.subtype` + * @param {string | null} name - service target name: value depends on type, + * for databases it's usually the database name + */ +Span.prototype.setServiceTarget = function (type, name) { + if (!type && !name) { + this._excludeServiceTarget = true + this._serviceTarget = null + return + } + + if (typeof type === 'string') { + this._excludeServiceTarget = false + if (this._serviceTarget === null) { + this._serviceTarget = { type } + } else { + this._serviceTarget.type = type + } + } else { + this._agent.logger.warn('"type" argument to Span#setServiceTarget must be of type "string", got type "%s": ignoring', typeof type) + } + if (typeof name === 'string') { + this._excludeServiceTarget = false + if (this._serviceTarget === null) { + this._serviceTarget = { name } + } else { + this._serviceTarget.name = name + } + } else { + this._agent.logger.warn('"name" argument to Span#setServiceTarget must be of type "string", got type "%s": ignoring', typeof name) + } } Span.prototype.setMessageContext = function (context) { @@ -160,14 +326,14 @@ Span.prototype.setOutcome = function (outcome) { return } this._freezeOutcome() - this.outcome = outcome + this._setOutcome(outcome) } Span.prototype._setOutcomeFromErrorCapture = function (outcome) { if (this._isOutcomeFrozen) { return } - this.outcome = outcome + this._setOutcome(outcome) } Span.prototype._setOutcomeFromHttpStatusCode = function (statusCode) { @@ -181,9 +347,9 @@ Span.prototype._setOutcomeFromHttpStatusCode = function (statusCode) { */ if (typeof statusCode !== 'undefined') { if (statusCode >= 400) { - this.outcome = constants.OUTCOME_FAILURE + this._setOutcome(constants.OUTCOME_FAILURE) } else { - this.outcome = constants.OUTCOME_SUCCESS + this._setOutcome(constants.OUTCOME_SUCCESS) } } @@ -192,7 +358,19 @@ Span.prototype._setOutcomeFromHttpStatusCode = function (statusCode) { Span.prototype._setOutcomeFromSpanEnd = function () { if (this.outcome === constants.OUTCOME_UNKNOWN && !this._isOutcomeFrozen) { - this.outcome = constants.OUTCOME_SUCCESS + this._setOutcome(constants.OUTCOME_SUCCESS) + } +} + +/** + * Central setting for outcome + * + * Enables "when outcome does X, Y should also happen" behaviors + */ +Span.prototype._setOutcome = function (outcome) { + this.outcome = outcome + if (outcome !== constants.OUTCOME_SUCCESS) { + this.discardable = false } } @@ -207,7 +385,9 @@ Span.prototype._recordStackTrace = function (obj) { Span.prototype._encode = function (cb) { var self = this - if (!this.ended) return cb(new Error('cannot encode un-ended span')) + if (!this.ended) { + return cb(new Error('cannot encode un-ended span')) + } const payload = { id: self.id, @@ -215,7 +395,7 @@ Span.prototype._encode = function (cb) { parent_id: self.parentId, trace_id: self.traceId, name: self.name, - type: self.type || 'custom', + type: self.type || constants.DEFAULT_SPAN_TYPE, subtype: self.subtype, action: self.action, timestamp: self.timestamp, @@ -232,14 +412,34 @@ Span.prototype._encode = function (cb) { payload.sample_rate = sampleRate } - if (self._db || self._http || self._labels || self._destination || self._message) { - payload.context = { - db: self._db || undefined, - http: self._http || undefined, - tags: self._labels || undefined, - destination: self._destination || undefined, - message: self._message || undefined - } + let haveContext = false + const context = {} + if (self._serviceTarget) { + context.service = { target: self._serviceTarget } + haveContext = true + } + if (self._destination) { + context.destination = self._destination + haveContext = true + } + if (self._db) { + context.db = self._db + haveContext = true + } + if (self._message) { + context.message = self._message + haveContext = true + } + if (self._http) { + context.http = self._http + haveContext = true + } + if (self._labels) { + context.tags = self._labels + haveContext = true + } + if (haveContext) { + payload.context = context } if (self.isComposite()) { @@ -321,6 +521,11 @@ Span.prototype.setRecorded = function (value) { return this._context.setRecorded(value) } +Span.prototype.propagateTraceContextHeaders = function (carrier, setter) { + this.discardable = false + return GenericSpan.prototype.propagateTraceContextHeaders.call(this, carrier, setter) +} + function filterCallSite (callsite) { var filename = callsite.getFileName() return filename ? filename.indexOf('/node_modules/elastic-apm-node/') === -1 : true diff --git a/lib/instrumentation/timer.js b/lib/instrumentation/timer.js index 8e134d6f875..be72293591d 100644 --- a/lib/instrumentation/timer.js +++ b/lib/instrumentation/timer.js @@ -8,17 +8,29 @@ var microtime = require('relative-microtime') +/** + * Return `time`, if given and valid, or the current time (calculated using + * the given `timer`). + * + * @param {Timer} timer + * @param {Number} [time] - An optional float number of milliseconds since + * the epoch (i.e. the same as provided by `Date.now()`). + * @returns {Number} A time in *microseconds* since the Epoch. + */ function maybeTime (timer, time) { - if (timer._parent) return maybeTime(timer._parent, time) - return time >= 0 ? time * 1000 : timer._timer() + if (time >= 0) { + return time * 1000 + } else { + return timer._timer() + } } module.exports = class Timer { // `startTime`: millisecond float - constructor (timer, startTime) { - this._parent = timer - this._timer = timer ? timer._timer : microtime() - this.start = maybeTime(this, startTime) // microsecond integer + constructor (parentTimer, startTime) { + this._parent = parentTimer + this._timer = parentTimer ? parentTimer._timer : microtime() + this.start = maybeTime(this, startTime) // microsecond integer (note: might not be an integer) this.endTimestamp = null this.duration = null // millisecond float this.selfTime = null // millisecond float diff --git a/lib/instrumentation/transaction.js b/lib/instrumentation/transaction.js index b498e1fdd26..f66e8b31707 100644 --- a/lib/instrumentation/transaction.js +++ b/lib/instrumentation/transaction.js @@ -53,6 +53,13 @@ function Transaction (agent, name, ...args) { ? (args.pop() || {}) : {} + if (opts.timer) { + process.emitWarning( + 'specifying the `timer` option to `new Transaction()` was never a public API and will be removed', + 'DeprecationWarning', + 'ELASTIC_APM_SPAN_TIMER_OPTION' + ) + } if (opts.tracestate) { opts.tracestate = TraceState.fromStringFormatString(opts.tracestate) } @@ -229,7 +236,7 @@ Transaction.prototype.toJSON = function () { trace_id: this.traceId, parent_id: this.parentId, name: this.name, - type: this.type || 'custom', + type: this.type || constants.DEFAULT_SPAN_TYPE, duration: this._duration, timestamp: this.timestamp, result: String(this.result), diff --git a/lib/lambda.js b/lib/lambda.js index 8a443af185d..087e47947ed 100644 --- a/lib/lambda.js +++ b/lib/lambda.js @@ -10,6 +10,7 @@ const constants = require('./constants') const shimmer = require('./instrumentation/shimmer') const fs = require('fs') const path = require('path') +const querystring = require('querystring') const { MAX_MESSAGES_PROCESSED_FOR_TRACE_CONTEXT } = require('./constants') @@ -93,7 +94,7 @@ function getFaasData (context, faasId, isColdStart, faasTriggerType, requestId) function setGenericData (trans, event, context, faasId, isColdStart) { trans.type = 'request' - trans.name = context.functionName + trans.setDefaultName(context.functionName) trans.setFaas(getFaasData(context, faasId, isColdStart, 'other')) @@ -113,6 +114,7 @@ function setApiGatewayData (agent, trans, event, context, faasId, isColdStart) { const requestContext = event.requestContext let name + let pseudoReq if (requestContext.http) { // 2.0 if (agent._conf.usePathAsTransactionName) { name = `${requestContext.http.method} ${requestContext.http.path}` @@ -130,15 +132,41 @@ function setApiGatewayData (agent, trans, event, context, faasId, isColdStart) { } name = `${requestContext.http.method} /${requestContext.stage}${routeKeyPath}` } - } else { // 1.0 + pseudoReq = { + httpVersion: (requestContext.http.protocol + ? requestContext.http.protocol.split('/')[1] // 'HTTP/1.1' -> '1.1' + : undefined), + method: requestContext.http.method, + url: event.rawPath + (event.rawQueryString ? '?' + event.rawQueryString : ''), + headers: event.normedHeaders, + socket: { remoteAddress: requestContext.http.sourceIp }, + body: event.body + } + } else { // payload version format 1.0 if (agent._conf.usePathAsTransactionName) { name = `${requestContext.httpMethod} ${requestContext.path}` } else { name = `${requestContext.httpMethod} /${requestContext.stage}${requestContext.resourcePath}` } + pseudoReq = { + httpVersion: (requestContext.protocol + ? requestContext.protocol.split('/')[1] // 'HTTP/1.1' -> '1.1' + : undefined), + method: requestContext.httpMethod, + url: requestContext.path + (event.queryStringParameters + ? '?' + querystring.encode(event.queryStringParameters) + : ''), + headers: event.normedHeaders, + socket: { remoteAddress: requestContext.identity && requestContext.identity.sourceIp }, + // Limitation: Note that `getContextFromRequest` does *not* use this body, + // because API Gateway payload format 1.0 does not include the + // Content-Length header from the original request. + body: event.body + } } trans.type = 'request' - trans.name = name + trans.setDefaultName(name) + trans.req = pseudoReq // Used by parsers.getContextFromRequest() for adding context to transaction and errors. trans.setFaas(getFaasData(context, faasId, isColdStart, 'http', requestContext.requestId)) @@ -166,6 +194,48 @@ function setApiGatewayData (agent, trans, event, context, faasId, isColdStart) { trans.setCloudContext(cloudContext) } +/** + * Set transaction data for HTTP-y triggers -- API Gateway -- from the + * Lambda function result. + */ +function setTransDataFromHttpyResult (err, result, trans, event, triggerType) { + if (err) { + trans.result = 'HTTP 5xx' + } else if (result && result.statusCode) { + trans.result = 'HTTP ' + result.statusCode.toString()[0] + 'xx' + } else { + trans.result = constants.RESULT_SUCCESS + } + + // This doc defines the format of API Gateway-triggered responses, from which + // we can infer `transaction.context.response` values. + // https://docs.aws.amazon.com/apigateway/latest/developerguide/http-api-develop-integrations-lambda.html#http-api-develop-integrations-lambda.response + if (err) { + trans.res = { + statusCode: 500 + } + } else if (event.requestContext.http) { // payload format version 2.0 + if (result && result.statusCode) { + trans.res = { + statusCode: result.statusCode, + headers: result.headers + } + } else { + trans.res = { + statusCode: 200, + headers: { 'content-type': 'application/json' } + } + } + } else { // payload format version 1.0 + if (result && result.statusCode) { + trans.res = { + statusCode: result.statusCode, + headers: result.headers + } + } + } +} + function setSqsData (agent, trans, event, context, faasId, isColdStart) { const record = event && event.Records && event.Records[0] const eventSourceARN = record.eventSourceARN ? record.eventSourceARN : '' @@ -176,7 +246,7 @@ function setSqsData (agent, trans, event, context, faasId, isColdStart) { const queueName = arnParts[5] const accountId = arnParts[4] - trans.name = `RECEIVE ${queueName}` + trans.setDefaultName(`RECEIVE ${queueName}`) trans.type = 'messaging' const serviceContext = { @@ -217,7 +287,7 @@ function setSnsData (agent, trans, event, context, faasId, isColdStart) { const accountId = arnParts[4] const region = arnParts[3] - trans.name = `RECEIVE ${topicName}` + trans.setDefaultName(`RECEIVE ${topicName}`) trans.type = 'messaging' const serviceContext = { @@ -252,7 +322,7 @@ function setS3SingleData (trans, event, context, faasId, isColdStart) { trans.setFaas(getFaasData(context, faasId, isColdStart, 'datasource', record.responseElements && record.responseElements['x-amz-request-id'])) - trans.name = `${record && record.eventName} ${record && record.s3 && record.s3.bucket && record.s3.bucket.name}` + trans.setDefaultName(`${record && record.eventName} ${record && record.s3 && record.s3.bucket && record.s3.bucket.name}`) trans.type = 'request' const serviceContext = { @@ -282,6 +352,14 @@ function elasticApmAwsLambda (agent) { function endAndFlushTransaction (err, result, trans, event, context, triggerType, cb) { log.trace({ awsRequestId: context && context.awsRequestId }, 'lambda: fn end') + if (triggerType === TRIGGER_API_GATEWAY) { + setTransDataFromHttpyResult(err, result, trans, event, triggerType) + } else if (err) { + trans.result = constants.RESULT_FAILURE + } else { + trans.result = constants.RESULT_SUCCESS + } + if (err) { // Capture the error before trans.end() so it associates with the // current trans. `skipOutcome` to avoid setting outcome on a possible @@ -289,18 +367,8 @@ function elasticApmAwsLambda (agent) { // sub-span. agent.captureError(err, { skipOutcome: true }) trans.setOutcome(constants.OUTCOME_FAILURE) - if (triggerType === TRIGGER_API_GATEWAY) { - trans.result = 'HTTP 5xx' - } else { - trans.result = constants.RESULT_FAILURE - } } else { trans.setOutcome(constants.OUTCOME_SUCCESS) - if (triggerType === TRIGGER_API_GATEWAY && result && result.statusCode) { - trans.result = 'HTTP ' + result.statusCode.toString()[0] + 'xx' - } else { - trans.result = constants.RESULT_SUCCESS - } } trans.end() @@ -386,11 +454,17 @@ function elasticApmAwsLambda (agent) { // Look for trace-context info in headers or messageAttributes. let traceparent let tracestate - let normedHeaders if (triggerType === TRIGGER_API_GATEWAY && event.headers) { - normedHeaders = lowerCaseObjectKeys(event.headers) - traceparent = normedHeaders.traceparent || normedHeaders['elastic-apm-traceparent'] - tracestate = normedHeaders.tracestate + // https://docs.aws.amazon.com/apigateway/latest/developerguide/http-api-develop-integrations-lambda.html + // says "Header names are lowercased." However, that isn't the case for + // payload format version 1.0. We need lowercased headers for processing. + if (!event.requestContext.http) { // 1.0 + event.normedHeaders = lowerCaseObjectKeys(event.headers) + } else { + event.normedHeaders = event.headers + } + traceparent = event.normedHeaders.traceparent || event.normedHeaders['elastic-apm-traceparent'] + tracestate = event.normedHeaders.tracestate } // Start the transaction and set some possibly trigger-specific data. diff --git a/lib/opentelemetry-bridge/OTelSpan.js b/lib/opentelemetry-bridge/OTelSpan.js index 2bf63c51f71..f9341e465d2 100644 --- a/lib/opentelemetry-bridge/OTelSpan.js +++ b/lib/opentelemetry-bridge/OTelSpan.js @@ -206,7 +206,8 @@ class OTelSpan { let type let subtype - let resource + let serviceTargetType = null + let serviceTargetName = null const httpPortFromScheme = function (scheme) { if (scheme === 'http') { @@ -243,39 +244,33 @@ class OTelSpan { if (attrs['db.system']) { type = 'db' subtype = attrs['db.system'] - resource = netName || subtype - if (attrs['db.name']) { - resource += '/' - resource += attrs['db.name'] - } + serviceTargetType = subtype + serviceTargetName = attrs['db.name'] || null } else if (attrs['messaging.system']) { type = 'messaging' subtype = attrs['messaging.system'] if (!netName && attrs['messaging.url']) { netName = parseNetName(attrs['messaging.url']) } - resource = netName || subtype - if (attrs['messaging.destination']) { - resource += '/' + attrs['messaging.destination'] - } + serviceTargetType = subtype + serviceTargetName = attrs['messaging.destination'] || null } else if (attrs['rpc.system']) { type = 'external' subtype = attrs['rpc.system'] - resource = netName || subtype - if (attrs['rpc.service']) { - resource += '/' + attrs['rpc.service'] - } + serviceTargetType = subtype + serviceTargetName = netName || attrs['rpc.service'] || null } else if (attrs['http.url'] || attrs['http.scheme']) { type = 'external' subtype = 'http' + serviceTargetType = 'http' const httpHost = attrs['http.host'] || netPeer if (httpHost) { if (netPort < 0) { netPort = httpPortFromScheme(attrs['http.scheme']) } - resource = netPort < 0 ? httpHost : httpHost + ':' + netPort + serviceTargetName = netPort < 0 ? httpHost : httpHost + ':' + netPort } else if (attrs['http.url']) { - resource = parseNetName(attrs['http.url']) + serviceTargetName = parseNetName(attrs['http.url']) } } @@ -292,15 +287,8 @@ class OTelSpan { if (subtype) { this._span.subtype = subtype } - if (resource) { - this._span.setDestinationContext({ - service: { - resource, - // Empty strings per https://github.com/elastic/apm/blob/main/specs/agents/tracing-spans-destination.md#contextdestinationservicenamecontextdestinationservicetype - name: '', - type: '' - } - }) + if (serviceTargetType || serviceTargetName) { + this._span.setServiceTarget(serviceTargetType, serviceTargetName) } } diff --git a/lib/opentelemetry-bridge/OTelTracer.js b/lib/opentelemetry-bridge/OTelTracer.js index 507a55350f6..71d1921b906 100644 --- a/lib/opentelemetry-bridge/OTelTracer.js +++ b/lib/opentelemetry-bridge/OTelTracer.js @@ -84,6 +84,9 @@ class OTelTracer { if (otelSpanOptions.startTime) { createOpts.startTime = epochMsFromOTelTimeInput(otelSpanOptions.startTime) } + if (otelSpanOptions.kind === otel.SpanKind.CLIENT || otelSpanOptions.kind === otel.SpanKind.PRODUCER) { + createOpts.exitSpan = true + } newTransOrSpan = trans.createSpan(name, createOpts) // There might be no span, e.g. if the span is a child of an exit span. We diff --git a/lib/opentelemetry-bridge/README.md b/lib/opentelemetry-bridge/README.md index 006f3703e58..0afbecdd07f 100644 --- a/lib/opentelemetry-bridge/README.md +++ b/lib/opentelemetry-bridge/README.md @@ -158,7 +158,7 @@ the top of `startSpan` in [`OTelTracer`](./OTelTracer.js) than is allowed for "tags" (aka labels) in the APM Server intake API, so some further filtering of attributes would be required. -- There is a known issue with the `asyncHooks: false` config option and +- There is a known issue with the `contextManager: "patch"` config option and `tracer.startActiveSpan(name, async function fn () { ... })` where run context is lost after the first `await ...` usage in that given `fn`. See https://github.com/elastic/apm-agent-nodejs/issues/2679. diff --git a/lib/propwrap.js b/lib/propwrap.js index 94c74fb1a4e..194edc7bb51 100644 --- a/lib/propwrap.js +++ b/lib/propwrap.js @@ -67,7 +67,7 @@ var __copyProps = (to, from, except, desc) => { * console.log(os.platform()) // => DARWIN * * The subpath can indicate a nested property. Each property in that subpath, - * except the last, much identify an *Object*. + * except the last, must identify an *Object*. * * Limitations: * - This doesn't handle possible Symbol properties on the copied object(s). diff --git a/lib/stacktraces.js b/lib/stacktraces.js index 5d8fede8846..b3ed19935e3 100644 --- a/lib/stacktraces.js +++ b/lib/stacktraces.js @@ -18,7 +18,14 @@ var path = require('path') const asyncCache = require('async-cache') const afterAllResults = require('after-all-results') -const errorCallsites = require('error-callsites') + +// avoid loading error-callsites until needed to avoid +// Error.prepareStackTrace side-effects +// https://github.com/elastic/apm-agent-nodejs/issues/2833 +let errorCallsites +function initStackTraceCollection () { + errorCallsites = require('error-callsites') +} const errorStackParser = require('error-stack-parser') const loadSourceMap = require('./load-source-map') const LRU = require('lru-cache') @@ -373,6 +380,15 @@ function frameFromCallSite (log, callsite, cwd, sourceLinesAppFrames, sourceLine } } + // If the file looks like it minimized (as we didn't have a source-map in + // the processing above), then skip adding source context because it + // is mostly useless and the typically 500-char lines result in over-large + // APM error objects. + if (filename.endsWith('.min.js')) { + cacheAndCb(frame) + return + } + // Otherwise load the file from disk, if available. fileCache.get(frame.abs_path, function onFileCacheGet (fileErr, lines) { if (fileErr) { @@ -408,7 +424,7 @@ function frameFromCallSite (log, callsite, cwd, sourceLinesAppFrames, sourceLine function gatherStackTrace (log, err, sourceLinesAppFrames, sourceLinesLibraryFrames, filterCallSite, cb) { // errorCallsites returns an array of v8 CallSite objects. // https://v8.dev/docs/stack-trace-api#customizing-stack-traces - let callsites = errorCallsites(err) + let callsites = errorCallsites ? errorCallsites(err) : null const next = afterAllResults(function finish (_err, stacktrace) { // _err is always null from frameFromCallSite. @@ -424,7 +440,7 @@ function gatherStackTrace (log, err, sourceLinesAppFrames, sourceLinesLibraryFra if (!isValidCallsites(callsites)) { // When can this happen? Another competing Error.prepareStackTrace breaking - // error-callsites? + // error-callsites? Also initStackTraceCollection not having been called. log.debug('could not get valid callsites from error "%s"', err) } else if (callsites) { if (filterCallSite) { @@ -447,6 +463,7 @@ function gatherStackTrace (log, err, sourceLinesAppFrames, sourceLinesLibraryFra module.exports = { gatherStackTrace, frameCacheStats, + initStackTraceCollection, // Exported for testing only. stackTraceFromErrStackString diff --git a/lib/symbols.js b/lib/symbols.js index cbfd01d5d2f..82a6a0188bc 100644 --- a/lib/symbols.js +++ b/lib/symbols.js @@ -12,3 +12,4 @@ exports.knexStackObj = Symbol('ElasticAPMKnexStackObj') exports.staticFile = Symbol('ElasticAPMStaticFile') exports.expressMountStack = Symbol('ElasticAPMExpressMountStack') exports.errorReportedSymbol = Symbol('ElasticAPMErrorReported') +exports.redisClientOptions = Symbol('ElasticAPMRedisClientOptions') diff --git a/package-lock.json b/package-lock.json index 93dcebaa5bf..cfd10442f5e 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "elastic-apm-node", - "version": "3.36.0", + "version": "3.41.1", "lockfileVersion": 2, "requires": true, "packages": { "": { "name": "elastic-apm-node", - "version": "3.36.0", + "version": "3.41.1", "license": "BSD-2-Clause", "dependencies": { "@elastic/ecs-pino-format": "^1.2.0", @@ -17,7 +17,7 @@ "basic-auth": "^2.0.1", "cookie": "^0.5.0", "core-util-is": "^1.0.2", - "elastic-apm-http-client": "11.0.1", + "elastic-apm-http-client": "11.0.4", "end-of-stream": "^1.4.4", "error-callsites": "^2.0.4", "error-stack-parser": "^2.0.6", @@ -33,7 +33,7 @@ "original-url": "^1.2.3", "pino": "^6.11.2", "relative-microtime": "^2.0.0", - "require-in-the-middle": "^5.0.3", + "require-in-the-middle": "^5.2.0", "semver": "^6.3.0", "set-cookie-serde": "^1.0.0", "shallow-clone-shim": "^2.0.0", @@ -46,14 +46,14 @@ "@babel/cli": "^7.8.4", "@babel/core": "^7.8.4", "@babel/preset-env": "^7.8.4", - "@elastic/elasticsearch": "^8.2.0-patch.1", + "@elastic/elasticsearch": "^8.2.1", "@elastic/elasticsearch-canary": "^8.2.0-canary.2", "@fastify/formbody": "^7.0.1", - "@hapi/hapi": "^20.1.2", - "@koa/router": "^9.0.1", - "@types/node": "^18.0.1", + "@hapi/hapi": "^21.0.0", + "@koa/router": "^12.0.0", + "@types/node": "^18.11.9", "@types/pino": "^6.3.8", - "ajv": "^6.12.6", + "ajv": "^7.2.4", "apollo-server-core": "^3.0.0", "apollo-server-express": "^3.0.0", "aws-sdk": "^2.622.0", @@ -65,14 +65,14 @@ "clone": "^2.0.0", "columnify": "^1.5.4", "connect": "^3.7.0", - "container-info": "^1.0.1", "dashdash": "^2.0.0", "dependency-check": "^4.1.0", + "diagnostics_channel": "^1.1.0", "elasticsearch": "^16.7.3", "eslint": "^6.8.0", "eslint-config-standard": "^14.1.1", "eslint-plugin-import": "^2.25.4", - "eslint-plugin-license-header": "^0.4.0", + "eslint-plugin-license-header": "^0.6.0", "eslint-plugin-node": "^11.1.0", "eslint-plugin-promise": "^4.3.1", "eslint-plugin-standard": "^4.1.0", @@ -88,10 +88,11 @@ "handlebars": "^4.7.3", "https-pem": "^3.0.0", "ioredis": "^5.1.0", - "knex": "^0.21.2", + "js-yaml": "^4.1.0", + "knex": "^0.95.15", "koa": "^2.11.0", "koa-bodyparser": "^4.3.0", - "koa-router": "^9.0.1", + "koa-router": "^12.0.0", "lambda-local": "^2.0.2", "memcached": "^2.2.2", "mimic-response": "^2.1.0", @@ -107,23 +108,23 @@ "once": "^1.4.0", "pg": "^8.7.1", "pug": "^3.0.1", - "redis": "^3.1.2", + "redis": "^4.3.0", "request": "^2.88.2", - "restify": "^8.5.1", + "restify": "^10.0.0", "rimraf": "^3.0.2", - "send": "^0.17.1", "tap-junit": "^5.0.1", "tape": "^5.0.0", - "tedious": "^14.5.0", + "tedious": "^15.1.0", "test-all-versions": "^4.1.1", "thunky": "^1.1.0", "typescript": "^4.7.4", + "undici": "^5.8.0", "vasync": "^2.2.0", - "wait-on": "^6.0.1", + "wait-on": "^7.0.1", "ws": "^7.2.1" }, "engines": { - "node": "^8.6.0 || 10 || 12 || 14 || 16 || 17 || 18" + "node": "^8.6.0 || 10 || 12 || 14 || 16 || 17 || 18 || 19" } }, "node_modules/@ampproject/remapping": { @@ -140,9 +141,9 @@ } }, "node_modules/@apollo/protobufjs": { - "version": "1.2.2", - "resolved": "https://registry.npmjs.org/@apollo/protobufjs/-/protobufjs-1.2.2.tgz", - "integrity": "sha512-vF+zxhPiLtkwxONs6YanSt1EpwpGilThpneExUN5K3tCymuxNnVq2yojTvnpRjv2QfsEIt/n7ozPIIzBLwGIDQ==", + "version": "1.2.6", + "resolved": "https://registry.npmjs.org/@apollo/protobufjs/-/protobufjs-1.2.6.tgz", + "integrity": "sha512-Wqo1oSHNUj/jxmsVp4iR3I480p6qdqHikn38lKrFhfzcDJ7lwd7Ck7cHRl4JE81tWNArl77xhnG/OkZhxKBYOw==", "dev": true, "hasInstallScript": true, "dependencies": { @@ -171,12 +172,114 @@ "integrity": "sha512-F0KIgDJfy2nA3zMLmWGKxcH2ZVEtCZXHHdOQs2gSaQ27+lNeEfGxzkIw90aXswATX7AZ33tahPbzy6KAfUreVw==", "dev": true }, + "node_modules/@apollo/utils.dropunuseddefinitions": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@apollo/utils.dropunuseddefinitions/-/utils.dropunuseddefinitions-1.1.0.tgz", + "integrity": "sha512-jU1XjMr6ec9pPoL+BFWzEPW7VHHulVdGKMkPAMiCigpVIT11VmCbnij0bWob8uS3ODJ65tZLYKAh/55vLw2rbg==", + "dev": true, + "engines": { + "node": ">=12.13.0" + }, + "peerDependencies": { + "graphql": "14.x || 15.x || 16.x" + } + }, + "node_modules/@apollo/utils.keyvaluecache": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@apollo/utils.keyvaluecache/-/utils.keyvaluecache-1.0.1.tgz", + "integrity": "sha512-nLgYLomqjVimEzQ4cdvVQkcryi970NDvcRVPfd0OPeXhBfda38WjBq+WhQFk+czSHrmrSp34YHBxpat0EtiowA==", + "dev": true, + "dependencies": { + "@apollo/utils.logger": "^1.0.0", + "lru-cache": "^7.10.1" + } + }, + "node_modules/@apollo/utils.keyvaluecache/node_modules/lru-cache": { + "version": "7.13.1", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-7.13.1.tgz", + "integrity": "sha512-CHqbAq7NFlW3RSnoWXLJBxCWaZVBrfa9UEHId2M3AW8iEBurbqduNexEUCGc3SHc6iCYXNJCDi903LajSVAEPQ==", + "dev": true, + "engines": { + "node": ">=12" + } + }, "node_modules/@apollo/utils.logger": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/@apollo/utils.logger/-/utils.logger-1.0.0.tgz", "integrity": "sha512-dx9XrjyisD2pOa+KsB5RcDbWIAdgC91gJfeyLCgy0ctJMjQe7yZK5kdWaWlaOoCeX0z6YI9iYlg7vMPyMpQF3Q==", "dev": true }, + "node_modules/@apollo/utils.printwithreducedwhitespace": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@apollo/utils.printwithreducedwhitespace/-/utils.printwithreducedwhitespace-1.1.0.tgz", + "integrity": "sha512-GfFSkAv3n1toDZ4V6u2d7L4xMwLA+lv+6hqXicMN9KELSJ9yy9RzuEXaX73c/Ry+GzRsBy/fdSUGayGqdHfT2Q==", + "dev": true, + "engines": { + "node": ">=12.13.0" + }, + "peerDependencies": { + "graphql": "14.x || 15.x || 16.x" + } + }, + "node_modules/@apollo/utils.removealiases": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/@apollo/utils.removealiases/-/utils.removealiases-1.0.0.tgz", + "integrity": "sha512-6cM8sEOJW2LaGjL/0vHV0GtRaSekrPQR4DiywaApQlL9EdROASZU5PsQibe2MWeZCOhNrPRuHh4wDMwPsWTn8A==", + "dev": true, + "engines": { + "node": ">=12.13.0" + }, + "peerDependencies": { + "graphql": "14.x || 15.x || 16.x" + } + }, + "node_modules/@apollo/utils.sortast": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@apollo/utils.sortast/-/utils.sortast-1.1.0.tgz", + "integrity": "sha512-VPlTsmUnOwzPK5yGZENN069y6uUHgeiSlpEhRnLFYwYNoJHsuJq2vXVwIaSmts015WTPa2fpz1inkLYByeuRQA==", + "dev": true, + "dependencies": { + "lodash.sortby": "^4.7.0" + }, + "engines": { + "node": ">=12.13.0" + }, + "peerDependencies": { + "graphql": "14.x || 15.x || 16.x" + } + }, + "node_modules/@apollo/utils.stripsensitiveliterals": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/@apollo/utils.stripsensitiveliterals/-/utils.stripsensitiveliterals-1.2.0.tgz", + "integrity": "sha512-E41rDUzkz/cdikM5147d8nfCFVKovXxKBcjvLEQ7bjZm/cg9zEcXvS6vFY8ugTubI3fn6zoqo0CyU8zT+BGP9w==", + "dev": true, + "engines": { + "node": ">=12.13.0" + }, + "peerDependencies": { + "graphql": "14.x || 15.x || 16.x" + } + }, + "node_modules/@apollo/utils.usagereporting": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/@apollo/utils.usagereporting/-/utils.usagereporting-1.0.0.tgz", + "integrity": "sha512-5PL7hJMkTPmdo3oxPtigRrIyPxDk/ddrUryHPDaezL1lSFExpNzsDd2f1j0XJoHOg350GRd3LyD64caLA2PU1w==", + "dev": true, + "dependencies": { + "@apollo/utils.dropunuseddefinitions": "^1.1.0", + "@apollo/utils.printwithreducedwhitespace": "^1.1.0", + "@apollo/utils.removealiases": "1.0.0", + "@apollo/utils.sortast": "^1.1.0", + "@apollo/utils.stripsensitiveliterals": "^1.2.0", + "apollo-reporting-protobuf": "^3.3.1" + }, + "engines": { + "node": ">=12.13.0" + }, + "peerDependencies": { + "graphql": "14.x || 15.x || 16.x" + } + }, "node_modules/@apollographql/apollo-tools": { "version": "0.5.4", "resolved": "https://registry.npmjs.org/@apollographql/apollo-tools/-/apollo-tools-0.5.4.tgz", @@ -506,15 +609,13 @@ } }, "node_modules/@azure/msal-node": { - "version": "1.9.0", - "resolved": "https://registry.npmjs.org/@azure/msal-node/-/msal-node-1.9.0.tgz", - "integrity": "sha512-lw6ejz1WPqcdjkwp91Gidte98+kfGxHk9eYSmmpUChzrUUrZMFGvrtrvG3Qnr6bp5d4WijVge9LMe+2QQUMhoA==", + "version": "1.14.6", + "resolved": "https://registry.npmjs.org/@azure/msal-node/-/msal-node-1.14.6.tgz", + "integrity": "sha512-em/qqFL5tLMxMPl9vormAs13OgZpmQoJbiQ/GlWr+BA77eCLoL+Ehr5xRHowYo+LFe5b+p+PJVkRvT+mLvOkwA==", "dev": true, "dependencies": { - "@azure/msal-common": "^6.3.0", - "axios": "^0.21.4", - "https-proxy-agent": "^5.0.0", - "jsonwebtoken": "^8.5.1", + "@azure/msal-common": "^9.0.2", + "jsonwebtoken": "^9.0.0", "uuid": "^8.3.0" }, "engines": { @@ -522,25 +623,25 @@ } }, "node_modules/@azure/msal-node/node_modules/@azure/msal-common": { - "version": "6.3.0", - "resolved": "https://registry.npmjs.org/@azure/msal-common/-/msal-common-6.3.0.tgz", - "integrity": "sha512-ZyLq9GdnLBi/83YpysE86TFKbA0TuvfNAN5Psqu20cdAjLo/4rw4ttiItdh1G//XeGErHk9qn57gi2AYU1b5/Q==", + "version": "9.0.2", + "resolved": "https://registry.npmjs.org/@azure/msal-common/-/msal-common-9.0.2.tgz", + "integrity": "sha512-qzwxuF8kZAp+rNUactMCgJh8fblq9D4lSqrrIxMDzLjgSZtjN32ix7r/HBe8QdOr76II9SVVPcMkX4sPzPfQ7w==", "dev": true, "engines": { "node": ">=0.8.0" } }, "node_modules/@babel/cli": { - "version": "7.17.10", - "resolved": "https://registry.npmjs.org/@babel/cli/-/cli-7.17.10.tgz", - "integrity": "sha512-OygVO1M2J4yPMNOW9pb+I6kFGpQK77HmG44Oz3hg8xQIl5L/2zq+ZohwAdSaqYgVwM0SfmPHZHphH4wR8qzVYw==", + "version": "7.19.3", + "resolved": "https://registry.npmjs.org/@babel/cli/-/cli-7.19.3.tgz", + "integrity": "sha512-643/TybmaCAe101m2tSVHi9UKpETXP9c/Ff4mD2tAwkdP6esKIfaauZFc67vGEM6r9fekbEGid+sZhbEnSe3dg==", "dev": true, "dependencies": { "@jridgewell/trace-mapping": "^0.3.8", "commander": "^4.0.1", "convert-source-map": "^1.1.0", "fs-readdir-recursive": "^1.1.0", - "glob": "^7.0.0", + "glob": "^7.2.0", "make-dir": "^2.1.0", "slash": "^2.0.0" }, @@ -572,30 +673,30 @@ } }, "node_modules/@babel/compat-data": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.18.6.tgz", - "integrity": "sha512-tzulrgDT0QD6U7BJ4TKVk2SDDg7wlP39P9yAx1RfLy7vP/7rsDRlWVfbWxElslu56+r7QOhB2NSDsabYYruoZQ==", + "version": "7.20.1", + "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.20.1.tgz", + "integrity": "sha512-EWZ4mE2diW3QALKvDMiXnbZpRvlj+nayZ112nK93SnhqOtpdsbVD4W+2tEoT3YNBAG9RBR0ISY758ZkOgsn6pQ==", "dev": true, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/core": { - "version": "7.18.2", - "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.18.2.tgz", - "integrity": "sha512-A8pri1YJiC5UnkdrWcmfZTJTV85b4UXTAfImGmCfYmax4TR9Cw8sDS0MOk++Gp2mE/BefVJ5nwy5yzqNJbP/DQ==", + "version": "7.20.2", + "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.20.2.tgz", + "integrity": "sha512-w7DbG8DtMrJcFOi4VrLm+8QM4az8Mo+PuLBKLp2zrYRCow8W/f9xiXm5sN53C8HksCyDQwCKha9JiDoIyPjT2g==", "dev": true, "dependencies": { "@ampproject/remapping": "^2.1.0", - "@babel/code-frame": "^7.16.7", - "@babel/generator": "^7.18.2", - "@babel/helper-compilation-targets": "^7.18.2", - "@babel/helper-module-transforms": "^7.18.0", - "@babel/helpers": "^7.18.2", - "@babel/parser": "^7.18.0", - "@babel/template": "^7.16.7", - "@babel/traverse": "^7.18.2", - "@babel/types": "^7.18.2", + "@babel/code-frame": "^7.18.6", + "@babel/generator": "^7.20.2", + "@babel/helper-compilation-targets": "^7.20.0", + "@babel/helper-module-transforms": "^7.20.2", + "@babel/helpers": "^7.20.1", + "@babel/parser": "^7.20.2", + "@babel/template": "^7.18.10", + "@babel/traverse": "^7.20.1", + "@babel/types": "^7.20.2", "convert-source-map": "^1.7.0", "debug": "^4.1.0", "gensync": "^1.0.0-beta.2", @@ -611,12 +712,12 @@ } }, "node_modules/@babel/generator": { - "version": "7.18.7", - "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.18.7.tgz", - "integrity": "sha512-shck+7VLlY72a2w9c3zYWuE1pwOKEiQHV7GTUbSnhyl5eu3i04t30tBY82ZRWrDfo3gkakCFtevExnxbkf2a3A==", + "version": "7.20.2", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.20.2.tgz", + "integrity": "sha512-SD75PMIK6i9H8G/tfGvB4KKl4Nw6Ssos9nGgYwxbgyTP0iX/Z55DveoH86rmUB/YHTQQ+ZC0F7xxaY8l2OF44Q==", "dev": true, "dependencies": { - "@babel/types": "^7.18.7", + "@babel/types": "^7.20.2", "@jridgewell/gen-mapping": "^0.3.2", "jsesc": "^2.5.1" }, @@ -664,14 +765,14 @@ } }, "node_modules/@babel/helper-compilation-targets": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.18.6.tgz", - "integrity": "sha512-vFjbfhNCzqdeAtZflUFrG5YIFqGTqsctrtkZ1D/NB0mDW9TwW3GmmUepYY4G9wCET5rY5ugz4OGTcLd614IzQg==", + "version": "7.20.0", + "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.20.0.tgz", + "integrity": "sha512-0jp//vDGp9e8hZzBc6N/KwA5ZK3Wsm/pfm4CrY7vzegkVxc65SgSn6wYOnwHe9Js9HRQ1YTCKLGPzDtaS3RoLQ==", "dev": true, "dependencies": { - "@babel/compat-data": "^7.18.6", + "@babel/compat-data": "^7.20.0", "@babel/helper-validator-option": "^7.18.6", - "browserslist": "^4.20.2", + "browserslist": "^4.21.3", "semver": "^6.3.0" }, "engines": { @@ -703,9 +804,9 @@ } }, "node_modules/@babel/helper-create-regexp-features-plugin": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/helper-create-regexp-features-plugin/-/helper-create-regexp-features-plugin-7.18.6.tgz", - "integrity": "sha512-7LcpH1wnQLGrI+4v+nPp+zUvIkF9x0ddv1Hkdue10tg3gmRnLy97DXh4STiOf1qeIInyD69Qv5kKSZzKD8B/7A==", + "version": "7.19.0", + "resolved": "https://registry.npmjs.org/@babel/helper-create-regexp-features-plugin/-/helper-create-regexp-features-plugin-7.19.0.tgz", + "integrity": "sha512-htnV+mHX32DF81amCDrwIDr8nrp1PTm+3wfBN9/v8QJOLEioOCOG7qNyq0nHeFiWbT3Eb7gsPwEmV64UCQ1jzw==", "dev": true, "dependencies": { "@babel/helper-annotate-as-pure": "^7.18.6", @@ -719,15 +820,13 @@ } }, "node_modules/@babel/helper-define-polyfill-provider": { - "version": "0.3.1", - "resolved": "https://registry.npmjs.org/@babel/helper-define-polyfill-provider/-/helper-define-polyfill-provider-0.3.1.tgz", - "integrity": "sha512-J9hGMpJQmtWmj46B3kBHmL38UhJGhYX7eqkcq+2gsstyYt341HmPeWspihX43yVRA0mS+8GGk2Gckc7bY/HCmA==", + "version": "0.3.3", + "resolved": "https://registry.npmjs.org/@babel/helper-define-polyfill-provider/-/helper-define-polyfill-provider-0.3.3.tgz", + "integrity": "sha512-z5aQKU4IzbqCC1XH0nAqfsFLMVSo22SBKUc0BxGrLkolTdPTructy0ToNnlO2zA4j9Q/7pjMZf0DSY+DSTYzww==", "dev": true, "dependencies": { - "@babel/helper-compilation-targets": "^7.13.0", - "@babel/helper-module-imports": "^7.12.13", - "@babel/helper-plugin-utils": "^7.13.0", - "@babel/traverse": "^7.13.0", + "@babel/helper-compilation-targets": "^7.17.7", + "@babel/helper-plugin-utils": "^7.16.7", "debug": "^4.1.1", "lodash.debounce": "^4.0.8", "resolve": "^1.14.2", @@ -738,9 +837,9 @@ } }, "node_modules/@babel/helper-environment-visitor": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/helper-environment-visitor/-/helper-environment-visitor-7.18.6.tgz", - "integrity": "sha512-8n6gSfn2baOY+qlp+VSzsosjCVGFqWKmDF0cCWOybh52Dw3SEyoWR1KrhMJASjLwIEkkAufZ0xvr+SxLHSpy2Q==", + "version": "7.18.9", + "resolved": "https://registry.npmjs.org/@babel/helper-environment-visitor/-/helper-environment-visitor-7.18.9.tgz", + "integrity": "sha512-3r/aACDJ3fhQ/EVgFy0hpj8oHyHpQc+LPtJoY9SzTThAsStm4Ptegq92vqKoE3vD706ZVFWITnMnxucw+S9Ipg==", "dev": true, "engines": { "node": ">=6.9.0" @@ -759,13 +858,13 @@ } }, "node_modules/@babel/helper-function-name": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.18.6.tgz", - "integrity": "sha512-0mWMxV1aC97dhjCah5U5Ua7668r5ZmSC2DLfH2EZnf9c3/dHZKiFa5pRLMH5tjSl471tY6496ZWk/kjNONBxhw==", + "version": "7.19.0", + "resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.19.0.tgz", + "integrity": "sha512-WAwHBINyrpqywkUH0nTnNgI5ina5TFn85HKS0pbPDfxFfhyR/aNQEn4hGi1P1JyT//I0t4OgXUlofzWILRvS5w==", "dev": true, "dependencies": { - "@babel/template": "^7.18.6", - "@babel/types": "^7.18.6" + "@babel/template": "^7.18.10", + "@babel/types": "^7.19.0" }, "engines": { "node": ">=6.9.0" @@ -784,12 +883,12 @@ } }, "node_modules/@babel/helper-member-expression-to-functions": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/helper-member-expression-to-functions/-/helper-member-expression-to-functions-7.18.6.tgz", - "integrity": "sha512-CeHxqwwipekotzPDUuJOfIMtcIHBuc7WAzLmTYWctVigqS5RktNMQ5bEwQSuGewzYnCtTWa3BARXeiLxDTv+Ng==", + "version": "7.18.9", + "resolved": "https://registry.npmjs.org/@babel/helper-member-expression-to-functions/-/helper-member-expression-to-functions-7.18.9.tgz", + "integrity": "sha512-RxifAh2ZoVU67PyKIO4AMi1wTenGfMR/O/ae0CCRqwgBAt5v7xjdtRw7UoSbsreKrQn5t7r89eruK/9JjYHuDg==", "dev": true, "dependencies": { - "@babel/types": "^7.18.6" + "@babel/types": "^7.18.9" }, "engines": { "node": ">=6.9.0" @@ -808,19 +907,19 @@ } }, "node_modules/@babel/helper-module-transforms": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.18.6.tgz", - "integrity": "sha512-L//phhB4al5uucwzlimruukHB3jRd5JGClwRMD/ROrVjXfLqovYnvQrK/JK36WYyVwGGO7OD3kMyVTjx+WVPhw==", + "version": "7.20.2", + "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.20.2.tgz", + "integrity": "sha512-zvBKyJXRbmK07XhMuujYoJ48B5yvvmM6+wcpv6Ivj4Yg6qO7NOZOSnvZN9CRl1zz1Z4cKf8YejmCMh8clOoOeA==", "dev": true, "dependencies": { - "@babel/helper-environment-visitor": "^7.18.6", + "@babel/helper-environment-visitor": "^7.18.9", "@babel/helper-module-imports": "^7.18.6", - "@babel/helper-simple-access": "^7.18.6", + "@babel/helper-simple-access": "^7.20.2", "@babel/helper-split-export-declaration": "^7.18.6", - "@babel/helper-validator-identifier": "^7.18.6", - "@babel/template": "^7.18.6", - "@babel/traverse": "^7.18.6", - "@babel/types": "^7.18.6" + "@babel/helper-validator-identifier": "^7.19.1", + "@babel/template": "^7.18.10", + "@babel/traverse": "^7.20.1", + "@babel/types": "^7.20.2" }, "engines": { "node": ">=6.9.0" @@ -839,24 +938,24 @@ } }, "node_modules/@babel/helper-plugin-utils": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.18.6.tgz", - "integrity": "sha512-gvZnm1YAAxh13eJdkb9EWHBnF3eAub3XTLCZEehHT2kWxiKVRL64+ae5Y6Ivne0mVHmMYKT+xWgZO+gQhuLUBg==", + "version": "7.20.2", + "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.20.2.tgz", + "integrity": "sha512-8RvlJG2mj4huQ4pZ+rU9lqKi9ZKiRmuvGuM2HlWmkmgOhbs6zEAw6IEiJ5cQqGbDzGZOhwuOQNtZMi/ENLjZoQ==", "dev": true, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/helper-remap-async-to-generator": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/helper-remap-async-to-generator/-/helper-remap-async-to-generator-7.18.6.tgz", - "integrity": "sha512-z5wbmV55TveUPZlCLZvxWHtrjuJd+8inFhk7DG0WW87/oJuGDcjDiu7HIvGcpf5464L6xKCg3vNkmlVVz9hwyQ==", + "version": "7.18.9", + "resolved": "https://registry.npmjs.org/@babel/helper-remap-async-to-generator/-/helper-remap-async-to-generator-7.18.9.tgz", + "integrity": "sha512-dI7q50YKd8BAv3VEfgg7PS7yD3Rtbi2J1XMXaalXO0W0164hYLnh8zpjRS0mte9MfVp/tltvr/cfdXPvJr1opA==", "dev": true, "dependencies": { "@babel/helper-annotate-as-pure": "^7.18.6", - "@babel/helper-environment-visitor": "^7.18.6", - "@babel/helper-wrap-function": "^7.18.6", - "@babel/types": "^7.18.6" + "@babel/helper-environment-visitor": "^7.18.9", + "@babel/helper-wrap-function": "^7.18.9", + "@babel/types": "^7.18.9" }, "engines": { "node": ">=6.9.0" @@ -866,40 +965,40 @@ } }, "node_modules/@babel/helper-replace-supers": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/helper-replace-supers/-/helper-replace-supers-7.18.6.tgz", - "integrity": "sha512-fTf7zoXnUGl9gF25fXCWE26t7Tvtyn6H4hkLSYhATwJvw2uYxd3aoXplMSe0g9XbwK7bmxNes7+FGO0rB/xC0g==", + "version": "7.19.1", + "resolved": "https://registry.npmjs.org/@babel/helper-replace-supers/-/helper-replace-supers-7.19.1.tgz", + "integrity": "sha512-T7ahH7wV0Hfs46SFh5Jz3s0B6+o8g3c+7TMxu7xKfmHikg7EAZ3I2Qk9LFhjxXq8sL7UkP5JflezNwoZa8WvWw==", "dev": true, "dependencies": { - "@babel/helper-environment-visitor": "^7.18.6", - "@babel/helper-member-expression-to-functions": "^7.18.6", + "@babel/helper-environment-visitor": "^7.18.9", + "@babel/helper-member-expression-to-functions": "^7.18.9", "@babel/helper-optimise-call-expression": "^7.18.6", - "@babel/traverse": "^7.18.6", - "@babel/types": "^7.18.6" + "@babel/traverse": "^7.19.1", + "@babel/types": "^7.19.0" }, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/helper-simple-access": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/helper-simple-access/-/helper-simple-access-7.18.6.tgz", - "integrity": "sha512-iNpIgTgyAvDQpDj76POqg+YEt8fPxx3yaNBg3S30dxNKm2SWfYhD0TGrK/Eu9wHpUW63VQU894TsTg+GLbUa1g==", + "version": "7.20.2", + "resolved": "https://registry.npmjs.org/@babel/helper-simple-access/-/helper-simple-access-7.20.2.tgz", + "integrity": "sha512-+0woI/WPq59IrqDYbVGfshjT5Dmk/nnbdpcF8SnMhhXObpTq2KNBdLFRFrkVdbDOyUmHBCxzm5FHV1rACIkIbA==", "dev": true, "dependencies": { - "@babel/types": "^7.18.6" + "@babel/types": "^7.20.2" }, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/helper-skip-transparent-expression-wrappers": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/helper-skip-transparent-expression-wrappers/-/helper-skip-transparent-expression-wrappers-7.18.6.tgz", - "integrity": "sha512-4KoLhwGS9vGethZpAhYnMejWkX64wsnHPDwvOsKWU6Fg4+AlK2Jz3TyjQLMEPvz+1zemi/WBdkYxCD0bAfIkiw==", + "version": "7.18.9", + "resolved": "https://registry.npmjs.org/@babel/helper-skip-transparent-expression-wrappers/-/helper-skip-transparent-expression-wrappers-7.18.9.tgz", + "integrity": "sha512-imytd2gHi3cJPsybLRbmFrF7u5BIEuI2cNheyKi3/iOBC63kNn3q8Crn2xVuESli0aM4KYsyEqKyS7lFL8YVtw==", "dev": true, "dependencies": { - "@babel/types": "^7.18.6" + "@babel/types": "^7.18.9" }, "engines": { "node": ">=6.9.0" @@ -917,10 +1016,19 @@ "node": ">=6.9.0" } }, + "node_modules/@babel/helper-string-parser": { + "version": "7.19.4", + "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.19.4.tgz", + "integrity": "sha512-nHtDoQcuqFmwYNYPz3Rah5ph2p8PFeFCsZk9A/48dPc/rGocJ5J3hAAZ7pb76VWX3fZKu+uEr/FhH5jLx7umrw==", + "dev": true, + "engines": { + "node": ">=6.9.0" + } + }, "node_modules/@babel/helper-validator-identifier": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.18.6.tgz", - "integrity": "sha512-MmetCkz9ej86nJQV+sFCxoGGrUbU3q02kgLciwkrt9QqEB7cP39oKEY0PakknEO0Gu20SskMRi+AYZ3b1TpN9g==", + "version": "7.19.1", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.19.1.tgz", + "integrity": "sha512-awrNfaMtnHUr653GgGEs++LlAvW6w+DcPrOliSMXWCKo597CwL5Acf/wWdNkf/tfEQE3mjkeD1YOVZOUV/od1w==", "dev": true, "engines": { "node": ">=6.9.0" @@ -936,29 +1044,29 @@ } }, "node_modules/@babel/helper-wrap-function": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/helper-wrap-function/-/helper-wrap-function-7.18.6.tgz", - "integrity": "sha512-I5/LZfozwMNbwr/b1vhhuYD+J/mU+gfGAj5td7l5Rv9WYmH6i3Om69WGKNmlIpsVW/mF6O5bvTKbvDQZVgjqOw==", + "version": "7.18.11", + "resolved": "https://registry.npmjs.org/@babel/helper-wrap-function/-/helper-wrap-function-7.18.11.tgz", + "integrity": "sha512-oBUlbv+rjZLh2Ks9SKi4aL7eKaAXBWleHzU89mP0G6BMUlRxSckk9tSIkgDGydhgFxHuGSlBQZfnaD47oBEB7w==", "dev": true, "dependencies": { - "@babel/helper-function-name": "^7.18.6", - "@babel/template": "^7.18.6", - "@babel/traverse": "^7.18.6", - "@babel/types": "^7.18.6" + "@babel/helper-function-name": "^7.18.9", + "@babel/template": "^7.18.10", + "@babel/traverse": "^7.18.11", + "@babel/types": "^7.18.10" }, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/helpers": { - "version": "7.18.2", - "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.18.2.tgz", - "integrity": "sha512-j+d+u5xT5utcQSzrh9p+PaJX94h++KN+ng9b9WEJq7pkUPAd61FGqhjuUEdfknb3E/uDBb7ruwEeKkIxNJPIrg==", + "version": "7.20.1", + "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.20.1.tgz", + "integrity": "sha512-J77mUVaDTUJFZ5BpP6mMn6OIl3rEWymk2ZxDBQJUG3P+PbmyMcF3bYWvz0ma69Af1oobDqT/iAsvzhB58xhQUg==", "dev": true, "dependencies": { - "@babel/template": "^7.16.7", - "@babel/traverse": "^7.18.2", - "@babel/types": "^7.18.2" + "@babel/template": "^7.18.10", + "@babel/traverse": "^7.20.1", + "@babel/types": "^7.20.0" }, "engines": { "node": ">=6.9.0" @@ -979,9 +1087,9 @@ } }, "node_modules/@babel/parser": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.18.6.tgz", - "integrity": "sha512-uQVSa9jJUe/G/304lXspfWVpKpK4euFLgGiMQFOCpM/bgcAdeoHwi/OQz23O9GK2osz26ZiXRRV9aV+Yl1O8tw==", + "version": "7.20.2", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.20.2.tgz", + "integrity": "sha512-afk318kh2uKbo7BEj2QtEi8HVCGrwHUffrYDy7dgVcSa2j9lY3LDjPzcyGdpX7xgm35aWqvciZJ4WKmdF/SxYg==", "dev": true, "bin": { "parser": "bin/babel-parser.js" @@ -1006,14 +1114,14 @@ } }, "node_modules/@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining/-/plugin-bugfix-v8-spread-parameters-in-optional-chaining-7.18.6.tgz", - "integrity": "sha512-Udgu8ZRgrBrttVz6A0EVL0SJ1z+RLbIeqsu632SA1hf0awEppD6TvdznoH+orIF8wtFFAV/Enmw9Y+9oV8TQcw==", + "version": "7.18.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining/-/plugin-bugfix-v8-spread-parameters-in-optional-chaining-7.18.9.tgz", + "integrity": "sha512-AHrP9jadvH7qlOj6PINbgSuphjQUAK7AOT7DPjBo9EHoLhQTnnK5u45e1Hd4DbSQEO9nqPWtQ89r+XEOWFScKg==", "dev": true, "dependencies": { - "@babel/helper-plugin-utils": "^7.18.6", - "@babel/helper-skip-transparent-expression-wrappers": "^7.18.6", - "@babel/plugin-proposal-optional-chaining": "^7.18.6" + "@babel/helper-plugin-utils": "^7.18.9", + "@babel/helper-skip-transparent-expression-wrappers": "^7.18.9", + "@babel/plugin-proposal-optional-chaining": "^7.18.9" }, "engines": { "node": ">=6.9.0" @@ -1023,14 +1131,14 @@ } }, "node_modules/@babel/plugin-proposal-async-generator-functions": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-async-generator-functions/-/plugin-proposal-async-generator-functions-7.18.6.tgz", - "integrity": "sha512-WAz4R9bvozx4qwf74M+sfqPMKfSqwM0phxPTR6iJIi8robgzXwkEgmeJG1gEKhm6sDqT/U9aV3lfcqybIpev8w==", + "version": "7.20.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-async-generator-functions/-/plugin-proposal-async-generator-functions-7.20.1.tgz", + "integrity": "sha512-Gh5rchzSwE4kC+o/6T8waD0WHEQIsDmjltY8WnWRXHUdH8axZhuH86Ov9M72YhJfDrZseQwuuWaaIT/TmePp3g==", "dev": true, "dependencies": { - "@babel/helper-environment-visitor": "^7.18.6", - "@babel/helper-plugin-utils": "^7.18.6", - "@babel/helper-remap-async-to-generator": "^7.18.6", + "@babel/helper-environment-visitor": "^7.18.9", + "@babel/helper-plugin-utils": "^7.19.0", + "@babel/helper-remap-async-to-generator": "^7.18.9", "@babel/plugin-syntax-async-generators": "^7.8.4" }, "engines": { @@ -1090,12 +1198,12 @@ } }, "node_modules/@babel/plugin-proposal-export-namespace-from": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-export-namespace-from/-/plugin-proposal-export-namespace-from-7.18.6.tgz", - "integrity": "sha512-zr/QcUlUo7GPo6+X1wC98NJADqmy5QTFWWhqeQWiki4XHafJtLl/YMGkmRB2szDD2IYJCCdBTd4ElwhId9T7Xw==", + "version": "7.18.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-export-namespace-from/-/plugin-proposal-export-namespace-from-7.18.9.tgz", + "integrity": "sha512-k1NtHyOMvlDDFeb9G5PhUXuGj8m/wiwojgQVEhJ/fsVsMCpLyOP4h0uGEjYJKrRI+EVPlb5Jk+Gt9P97lOGwtA==", "dev": true, "dependencies": { - "@babel/helper-plugin-utils": "^7.18.6", + "@babel/helper-plugin-utils": "^7.18.9", "@babel/plugin-syntax-export-namespace-from": "^7.8.3" }, "engines": { @@ -1122,12 +1230,12 @@ } }, "node_modules/@babel/plugin-proposal-logical-assignment-operators": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-logical-assignment-operators/-/plugin-proposal-logical-assignment-operators-7.18.6.tgz", - "integrity": "sha512-zMo66azZth/0tVd7gmkxOkOjs2rpHyhpcFo565PUP37hSp6hSd9uUKIfTDFMz58BwqgQKhJ9YxtM5XddjXVn+Q==", + "version": "7.18.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-logical-assignment-operators/-/plugin-proposal-logical-assignment-operators-7.18.9.tgz", + "integrity": "sha512-128YbMpjCrP35IOExw2Fq+x55LMP42DzhOhX2aNNIdI9avSWl2PI0yuBWarr3RYpZBSPtabfadkH2yeRiMD61Q==", "dev": true, "dependencies": { - "@babel/helper-plugin-utils": "^7.18.6", + "@babel/helper-plugin-utils": "^7.18.9", "@babel/plugin-syntax-logical-assignment-operators": "^7.10.4" }, "engines": { @@ -1170,16 +1278,16 @@ } }, "node_modules/@babel/plugin-proposal-object-rest-spread": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-object-rest-spread/-/plugin-proposal-object-rest-spread-7.18.6.tgz", - "integrity": "sha512-9yuM6wr4rIsKa1wlUAbZEazkCrgw2sMPEXCr4Rnwetu7cEW1NydkCWytLuYletbf8vFxdJxFhwEZqMpOx2eZyw==", + "version": "7.20.2", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-object-rest-spread/-/plugin-proposal-object-rest-spread-7.20.2.tgz", + "integrity": "sha512-Ks6uej9WFK+fvIMesSqbAto5dD8Dz4VuuFvGJFKgIGSkJuRGcrwGECPA1fDgQK3/DbExBJpEkTeYeB8geIFCSQ==", "dev": true, "dependencies": { - "@babel/compat-data": "^7.18.6", - "@babel/helper-compilation-targets": "^7.18.6", - "@babel/helper-plugin-utils": "^7.18.6", + "@babel/compat-data": "^7.20.1", + "@babel/helper-compilation-targets": "^7.20.0", + "@babel/helper-plugin-utils": "^7.20.2", "@babel/plugin-syntax-object-rest-spread": "^7.8.3", - "@babel/plugin-transform-parameters": "^7.18.6" + "@babel/plugin-transform-parameters": "^7.20.1" }, "engines": { "node": ">=6.9.0" @@ -1205,13 +1313,13 @@ } }, "node_modules/@babel/plugin-proposal-optional-chaining": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-optional-chaining/-/plugin-proposal-optional-chaining-7.18.6.tgz", - "integrity": "sha512-PatI6elL5eMzoypFAiYDpYQyMtXTn+iMhuxxQt5mAXD4fEmKorpSI3PHd+i3JXBJN3xyA6MvJv7at23HffFHwA==", + "version": "7.18.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-optional-chaining/-/plugin-proposal-optional-chaining-7.18.9.tgz", + "integrity": "sha512-v5nwt4IqBXihxGsW2QmCWMDS3B3bzGIk/EQVZz2ei7f3NJl8NzAJVvUmpDW5q1CRNY+Beb/k58UAH1Km1N411w==", "dev": true, "dependencies": { - "@babel/helper-plugin-utils": "^7.18.6", - "@babel/helper-skip-transparent-expression-wrappers": "^7.18.6", + "@babel/helper-plugin-utils": "^7.18.9", + "@babel/helper-skip-transparent-expression-wrappers": "^7.18.9", "@babel/plugin-syntax-optional-chaining": "^7.8.3" }, "engines": { @@ -1335,12 +1443,12 @@ } }, "node_modules/@babel/plugin-syntax-import-assertions": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-import-assertions/-/plugin-syntax-import-assertions-7.18.6.tgz", - "integrity": "sha512-/DU3RXad9+bZwrgWJQKbr39gYbJpLJHezqEzRzi/BHRlJ9zsQb4CK2CA/5apllXNomwA1qHwzvHl+AdEmC5krQ==", + "version": "7.20.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-import-assertions/-/plugin-syntax-import-assertions-7.20.0.tgz", + "integrity": "sha512-IUh1vakzNoWalR8ch/areW7qFopR2AEw03JlG7BbrDqmQ4X3q9uuipQwSGrUn7oGiemKjtSLDhNtQHzMHr1JdQ==", "dev": true, "dependencies": { - "@babel/helper-plugin-utils": "^7.18.6" + "@babel/helper-plugin-utils": "^7.19.0" }, "engines": { "node": ">=6.9.0" @@ -1511,12 +1619,12 @@ } }, "node_modules/@babel/plugin-transform-block-scoping": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-block-scoping/-/plugin-transform-block-scoping-7.18.6.tgz", - "integrity": "sha512-pRqwb91C42vs1ahSAWJkxOxU1RHWDn16XAa6ggQ72wjLlWyYeAcLvTtE0aM8ph3KNydy9CQF2nLYcjq1WysgxQ==", + "version": "7.20.2", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-block-scoping/-/plugin-transform-block-scoping-7.20.2.tgz", + "integrity": "sha512-y5V15+04ry69OV2wULmwhEA6jwSWXO1TwAtIwiPXcvHcoOQUqpyMVd2bDsQJMW8AurjulIyUV8kDqtjSwHy1uQ==", "dev": true, "dependencies": { - "@babel/helper-plugin-utils": "^7.18.6" + "@babel/helper-plugin-utils": "^7.20.2" }, "engines": { "node": ">=6.9.0" @@ -1526,17 +1634,18 @@ } }, "node_modules/@babel/plugin-transform-classes": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-classes/-/plugin-transform-classes-7.18.6.tgz", - "integrity": "sha512-XTg8XW/mKpzAF3actL554Jl/dOYoJtv3l8fxaEczpgz84IeeVf+T1u2CSvPHuZbt0w3JkIx4rdn/MRQI7mo0HQ==", + "version": "7.20.2", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-classes/-/plugin-transform-classes-7.20.2.tgz", + "integrity": "sha512-9rbPp0lCVVoagvtEyQKSo5L8oo0nQS/iif+lwlAz29MccX2642vWDlSZK+2T2buxbopotId2ld7zZAzRfz9j1g==", "dev": true, "dependencies": { "@babel/helper-annotate-as-pure": "^7.18.6", - "@babel/helper-environment-visitor": "^7.18.6", - "@babel/helper-function-name": "^7.18.6", + "@babel/helper-compilation-targets": "^7.20.0", + "@babel/helper-environment-visitor": "^7.18.9", + "@babel/helper-function-name": "^7.19.0", "@babel/helper-optimise-call-expression": "^7.18.6", - "@babel/helper-plugin-utils": "^7.18.6", - "@babel/helper-replace-supers": "^7.18.6", + "@babel/helper-plugin-utils": "^7.20.2", + "@babel/helper-replace-supers": "^7.19.1", "@babel/helper-split-export-declaration": "^7.18.6", "globals": "^11.1.0" }, @@ -1548,12 +1657,12 @@ } }, "node_modules/@babel/plugin-transform-computed-properties": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-computed-properties/-/plugin-transform-computed-properties-7.18.6.tgz", - "integrity": "sha512-9repI4BhNrR0KenoR9vm3/cIc1tSBIo+u1WVjKCAynahj25O8zfbiE6JtAtHPGQSs4yZ+bA8mRasRP+qc+2R5A==", + "version": "7.18.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-computed-properties/-/plugin-transform-computed-properties-7.18.9.tgz", + "integrity": "sha512-+i0ZU1bCDymKakLxn5srGHrsAPRELC2WIbzwjLhHW9SIE1cPYkLCL0NlnXMZaM1vhfgA2+M7hySk42VBvrkBRw==", "dev": true, "dependencies": { - "@babel/helper-plugin-utils": "^7.18.6" + "@babel/helper-plugin-utils": "^7.18.9" }, "engines": { "node": ">=6.9.0" @@ -1563,12 +1672,12 @@ } }, "node_modules/@babel/plugin-transform-destructuring": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-destructuring/-/plugin-transform-destructuring-7.18.6.tgz", - "integrity": "sha512-tgy3u6lRp17ilY8r1kP4i2+HDUwxlVqq3RTc943eAWSzGgpU1qhiKpqZ5CMyHReIYPHdo3Kg8v8edKtDqSVEyQ==", + "version": "7.20.2", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-destructuring/-/plugin-transform-destructuring-7.20.2.tgz", + "integrity": "sha512-mENM+ZHrvEgxLTBXUiQ621rRXZes3KWUv6NdQlrnr1TkWVw+hUjQBZuP2X32qKlrlG2BzgR95gkuCRSkJl8vIw==", "dev": true, "dependencies": { - "@babel/helper-plugin-utils": "^7.18.6" + "@babel/helper-plugin-utils": "^7.20.2" }, "engines": { "node": ">=6.9.0" @@ -1594,12 +1703,12 @@ } }, "node_modules/@babel/plugin-transform-duplicate-keys": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-duplicate-keys/-/plugin-transform-duplicate-keys-7.18.6.tgz", - "integrity": "sha512-NJU26U/208+sxYszf82nmGYqVF9QN8py2HFTblPT9hbawi8+1C5a9JubODLTGFuT0qlkqVinmkwOD13s0sZktg==", + "version": "7.18.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-duplicate-keys/-/plugin-transform-duplicate-keys-7.18.9.tgz", + "integrity": "sha512-d2bmXCtZXYc59/0SanQKbiWINadaJXqtvIQIzd4+hNwkWBgyCd5F/2t1kXoUdvPMrxzPvhK6EMQRROxsue+mfw==", "dev": true, "dependencies": { - "@babel/helper-plugin-utils": "^7.18.6" + "@babel/helper-plugin-utils": "^7.18.9" }, "engines": { "node": ">=6.9.0" @@ -1625,9 +1734,9 @@ } }, "node_modules/@babel/plugin-transform-for-of": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-for-of/-/plugin-transform-for-of-7.18.6.tgz", - "integrity": "sha512-WAjoMf4wIiSsy88KmG7tgj2nFdEK7E46tArVtcgED7Bkj6Fg/tG5SbvNIOKxbFS2VFgNh6+iaPswBeQZm4ox8w==", + "version": "7.18.8", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-for-of/-/plugin-transform-for-of-7.18.8.tgz", + "integrity": "sha512-yEfTRnjuskWYo0k1mHUqrVWaZwrdq8AYbfrpqULOJOaucGSp4mNMVps+YtA8byoevxS/urwU75vyhQIxcCgiBQ==", "dev": true, "dependencies": { "@babel/helper-plugin-utils": "^7.18.6" @@ -1640,14 +1749,14 @@ } }, "node_modules/@babel/plugin-transform-function-name": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-function-name/-/plugin-transform-function-name-7.18.6.tgz", - "integrity": "sha512-kJha/Gbs5RjzIu0CxZwf5e3aTTSlhZnHMT8zPWnJMjNpLOUgqevg+PN5oMH68nMCXnfiMo4Bhgxqj59KHTlAnA==", + "version": "7.18.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-function-name/-/plugin-transform-function-name-7.18.9.tgz", + "integrity": "sha512-WvIBoRPaJQ5yVHzcnJFor7oS5Ls0PYixlTYE63lCj2RtdQEl15M68FXQlxnG6wdraJIXRdR7KI+hQ7q/9QjrCQ==", "dev": true, "dependencies": { - "@babel/helper-compilation-targets": "^7.18.6", - "@babel/helper-function-name": "^7.18.6", - "@babel/helper-plugin-utils": "^7.18.6" + "@babel/helper-compilation-targets": "^7.18.9", + "@babel/helper-function-name": "^7.18.9", + "@babel/helper-plugin-utils": "^7.18.9" }, "engines": { "node": ">=6.9.0" @@ -1657,12 +1766,12 @@ } }, "node_modules/@babel/plugin-transform-literals": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-literals/-/plugin-transform-literals-7.18.6.tgz", - "integrity": "sha512-x3HEw0cJZVDoENXOp20HlypIHfl0zMIhMVZEBVTfmqbObIpsMxMbmU5nOEO8R7LYT+z5RORKPlTI5Hj4OsO9/Q==", + "version": "7.18.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-literals/-/plugin-transform-literals-7.18.9.tgz", + "integrity": "sha512-IFQDSRoTPnrAIrI5zoZv73IFeZu2dhu6irxQjY9rNjTT53VmKg9fenjvoiOWOkJ6mm4jKVPtdMzBY98Fp4Z4cg==", "dev": true, "dependencies": { - "@babel/helper-plugin-utils": "^7.18.6" + "@babel/helper-plugin-utils": "^7.18.9" }, "engines": { "node": ">=6.9.0" @@ -1687,14 +1796,13 @@ } }, "node_modules/@babel/plugin-transform-modules-amd": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-amd/-/plugin-transform-modules-amd-7.18.6.tgz", - "integrity": "sha512-Pra5aXsmTsOnjM3IajS8rTaLCy++nGM4v3YR4esk5PCsyg9z8NA5oQLwxzMUtDBd8F+UmVza3VxoAaWCbzH1rg==", + "version": "7.19.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-amd/-/plugin-transform-modules-amd-7.19.6.tgz", + "integrity": "sha512-uG3od2mXvAtIFQIh0xrpLH6r5fpSQN04gIVovl+ODLdUMANokxQLZnPBHcjmv3GxRjnqwLuHvppjjcelqUFZvg==", "dev": true, "dependencies": { - "@babel/helper-module-transforms": "^7.18.6", - "@babel/helper-plugin-utils": "^7.18.6", - "babel-plugin-dynamic-import-node": "^2.3.3" + "@babel/helper-module-transforms": "^7.19.6", + "@babel/helper-plugin-utils": "^7.19.0" }, "engines": { "node": ">=6.9.0" @@ -1704,15 +1812,14 @@ } }, "node_modules/@babel/plugin-transform-modules-commonjs": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-commonjs/-/plugin-transform-modules-commonjs-7.18.6.tgz", - "integrity": "sha512-Qfv2ZOWikpvmedXQJDSbxNqy7Xr/j2Y8/KfijM0iJyKkBTmWuvCA1yeH1yDM7NJhBW/2aXxeucLj6i80/LAJ/Q==", + "version": "7.19.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-commonjs/-/plugin-transform-modules-commonjs-7.19.6.tgz", + "integrity": "sha512-8PIa1ym4XRTKuSsOUXqDG0YaOlEuTVvHMe5JCfgBMOtHvJKw/4NGovEGN33viISshG/rZNVrACiBmPQLvWN8xQ==", "dev": true, "dependencies": { - "@babel/helper-module-transforms": "^7.18.6", - "@babel/helper-plugin-utils": "^7.18.6", - "@babel/helper-simple-access": "^7.18.6", - "babel-plugin-dynamic-import-node": "^2.3.3" + "@babel/helper-module-transforms": "^7.19.6", + "@babel/helper-plugin-utils": "^7.19.0", + "@babel/helper-simple-access": "^7.19.4" }, "engines": { "node": ">=6.9.0" @@ -1722,16 +1829,15 @@ } }, "node_modules/@babel/plugin-transform-modules-systemjs": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-systemjs/-/plugin-transform-modules-systemjs-7.18.6.tgz", - "integrity": "sha512-UbPYpXxLjTw6w6yXX2BYNxF3p6QY225wcTkfQCy3OMnSlS/C3xGtwUjEzGkldb/sy6PWLiCQ3NbYfjWUTI3t4g==", + "version": "7.19.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-systemjs/-/plugin-transform-modules-systemjs-7.19.6.tgz", + "integrity": "sha512-fqGLBepcc3kErfR9R3DnVpURmckXP7gj7bAlrTQyBxrigFqszZCkFkcoxzCp2v32XmwXLvbw+8Yq9/b+QqksjQ==", "dev": true, "dependencies": { "@babel/helper-hoist-variables": "^7.18.6", - "@babel/helper-module-transforms": "^7.18.6", - "@babel/helper-plugin-utils": "^7.18.6", - "@babel/helper-validator-identifier": "^7.18.6", - "babel-plugin-dynamic-import-node": "^2.3.3" + "@babel/helper-module-transforms": "^7.19.6", + "@babel/helper-plugin-utils": "^7.19.0", + "@babel/helper-validator-identifier": "^7.19.1" }, "engines": { "node": ">=6.9.0" @@ -1757,13 +1863,13 @@ } }, "node_modules/@babel/plugin-transform-named-capturing-groups-regex": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-named-capturing-groups-regex/-/plugin-transform-named-capturing-groups-regex-7.18.6.tgz", - "integrity": "sha512-UmEOGF8XgaIqD74bC8g7iV3RYj8lMf0Bw7NJzvnS9qQhM4mg+1WHKotUIdjxgD2RGrgFLZZPCFPFj3P/kVDYhg==", + "version": "7.19.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-named-capturing-groups-regex/-/plugin-transform-named-capturing-groups-regex-7.19.1.tgz", + "integrity": "sha512-oWk9l9WItWBQYS4FgXD4Uyy5kq898lvkXpXQxoJEY1RnvPk4R/Dvu2ebXU9q8lP+rlMwUQTFf2Ok6d78ODa0kw==", "dev": true, "dependencies": { - "@babel/helper-create-regexp-features-plugin": "^7.18.6", - "@babel/helper-plugin-utils": "^7.18.6" + "@babel/helper-create-regexp-features-plugin": "^7.19.0", + "@babel/helper-plugin-utils": "^7.19.0" }, "engines": { "node": ">=6.9.0" @@ -1804,12 +1910,12 @@ } }, "node_modules/@babel/plugin-transform-parameters": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-parameters/-/plugin-transform-parameters-7.18.6.tgz", - "integrity": "sha512-FjdqgMv37yVl/gwvzkcB+wfjRI8HQmc5EgOG9iGNvUY1ok+TjsoaMP7IqCDZBhkFcM5f3OPVMs6Dmp03C5k4/A==", + "version": "7.20.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-parameters/-/plugin-transform-parameters-7.20.1.tgz", + "integrity": "sha512-nDvKLrAvl+kf6BOy1UJ3MGwzzfTMgppxwiD2Jb4LO3xjYyZq30oQzDNJbCQpMdG9+j2IXHoiMrw5Cm/L6ZoxXQ==", "dev": true, "dependencies": { - "@babel/helper-plugin-utils": "^7.18.6" + "@babel/helper-plugin-utils": "^7.19.0" }, "engines": { "node": ">=6.9.0" @@ -1880,13 +1986,13 @@ } }, "node_modules/@babel/plugin-transform-spread": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-spread/-/plugin-transform-spread-7.18.6.tgz", - "integrity": "sha512-ayT53rT/ENF8WWexIRg9AiV9h0aIteyWn5ptfZTZQrjk/+f3WdrJGCY4c9wcgl2+MKkKPhzbYp97FTsquZpDCw==", + "version": "7.19.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-spread/-/plugin-transform-spread-7.19.0.tgz", + "integrity": "sha512-RsuMk7j6n+r752EtzyScnWkQyuJdli6LdO5Klv8Yx0OfPVTcQkIUfS8clx5e9yHXzlnhOZF3CbQ8C2uP5j074w==", "dev": true, "dependencies": { - "@babel/helper-plugin-utils": "^7.18.6", - "@babel/helper-skip-transparent-expression-wrappers": "^7.18.6" + "@babel/helper-plugin-utils": "^7.19.0", + "@babel/helper-skip-transparent-expression-wrappers": "^7.18.9" }, "engines": { "node": ">=6.9.0" @@ -1911,12 +2017,12 @@ } }, "node_modules/@babel/plugin-transform-template-literals": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-template-literals/-/plugin-transform-template-literals-7.18.6.tgz", - "integrity": "sha512-UuqlRrQmT2SWRvahW46cGSany0uTlcj8NYOS5sRGYi8FxPYPoLd5DDmMd32ZXEj2Jq+06uGVQKHxa/hJx2EzKw==", + "version": "7.18.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-template-literals/-/plugin-transform-template-literals-7.18.9.tgz", + "integrity": "sha512-S8cOWfT82gTezpYOiVaGHrCbhlHgKhQt8XH5ES46P2XWmX92yisoZywf5km75wv5sYcXDUCLMmMxOLCtthDgMA==", "dev": true, "dependencies": { - "@babel/helper-plugin-utils": "^7.18.6" + "@babel/helper-plugin-utils": "^7.18.9" }, "engines": { "node": ">=6.9.0" @@ -1926,12 +2032,12 @@ } }, "node_modules/@babel/plugin-transform-typeof-symbol": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-typeof-symbol/-/plugin-transform-typeof-symbol-7.18.6.tgz", - "integrity": "sha512-7m71iS/QhsPk85xSjFPovHPcH3H9qeyzsujhTc+vcdnsXavoWYJ74zx0lP5RhpC5+iDnVLO+PPMHzC11qels1g==", + "version": "7.18.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-typeof-symbol/-/plugin-transform-typeof-symbol-7.18.9.tgz", + "integrity": "sha512-SRfwTtF11G2aemAZWivL7PD+C9z52v9EvMqH9BuYbabyPuKUvSWks3oCg6041pT925L4zVFqaVBeECwsmlguEw==", "dev": true, "dependencies": { - "@babel/helper-plugin-utils": "^7.18.6" + "@babel/helper-plugin-utils": "^7.18.9" }, "engines": { "node": ">=6.9.0" @@ -1941,12 +2047,12 @@ } }, "node_modules/@babel/plugin-transform-unicode-escapes": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-escapes/-/plugin-transform-unicode-escapes-7.18.6.tgz", - "integrity": "sha512-XNRwQUXYMP7VLuy54cr/KS/WeL3AZeORhrmeZ7iewgu+X2eBqmpaLI/hzqr9ZxCeUoq0ASK4GUzSM0BDhZkLFw==", + "version": "7.18.10", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-escapes/-/plugin-transform-unicode-escapes-7.18.10.tgz", + "integrity": "sha512-kKAdAI+YzPgGY/ftStBFXTI1LZFju38rYThnfMykS+IXy8BVx+res7s2fxf1l8I35DV2T97ezo6+SGrXz6B3iQ==", "dev": true, "dependencies": { - "@babel/helper-plugin-utils": "^7.18.6" + "@babel/helper-plugin-utils": "^7.18.9" }, "engines": { "node": ">=6.9.0" @@ -1972,29 +2078,29 @@ } }, "node_modules/@babel/preset-env": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/preset-env/-/preset-env-7.18.6.tgz", - "integrity": "sha512-WrthhuIIYKrEFAwttYzgRNQ5hULGmwTj+D6l7Zdfsv5M7IWV/OZbUfbeL++Qrzx1nVJwWROIFhCHRYQV4xbPNw==", + "version": "7.20.2", + "resolved": "https://registry.npmjs.org/@babel/preset-env/-/preset-env-7.20.2.tgz", + "integrity": "sha512-1G0efQEWR1EHkKvKHqbG+IN/QdgwfByUpM5V5QroDzGV2t3S/WXNQd693cHiHTlCFMpr9B6FkPFXDA2lQcKoDg==", "dev": true, "dependencies": { - "@babel/compat-data": "^7.18.6", - "@babel/helper-compilation-targets": "^7.18.6", - "@babel/helper-plugin-utils": "^7.18.6", + "@babel/compat-data": "^7.20.1", + "@babel/helper-compilation-targets": "^7.20.0", + "@babel/helper-plugin-utils": "^7.20.2", "@babel/helper-validator-option": "^7.18.6", "@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression": "^7.18.6", - "@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining": "^7.18.6", - "@babel/plugin-proposal-async-generator-functions": "^7.18.6", + "@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining": "^7.18.9", + "@babel/plugin-proposal-async-generator-functions": "^7.20.1", "@babel/plugin-proposal-class-properties": "^7.18.6", "@babel/plugin-proposal-class-static-block": "^7.18.6", "@babel/plugin-proposal-dynamic-import": "^7.18.6", - "@babel/plugin-proposal-export-namespace-from": "^7.18.6", + "@babel/plugin-proposal-export-namespace-from": "^7.18.9", "@babel/plugin-proposal-json-strings": "^7.18.6", - "@babel/plugin-proposal-logical-assignment-operators": "^7.18.6", + "@babel/plugin-proposal-logical-assignment-operators": "^7.18.9", "@babel/plugin-proposal-nullish-coalescing-operator": "^7.18.6", "@babel/plugin-proposal-numeric-separator": "^7.18.6", - "@babel/plugin-proposal-object-rest-spread": "^7.18.6", + "@babel/plugin-proposal-object-rest-spread": "^7.20.2", "@babel/plugin-proposal-optional-catch-binding": "^7.18.6", - "@babel/plugin-proposal-optional-chaining": "^7.18.6", + "@babel/plugin-proposal-optional-chaining": "^7.18.9", "@babel/plugin-proposal-private-methods": "^7.18.6", "@babel/plugin-proposal-private-property-in-object": "^7.18.6", "@babel/plugin-proposal-unicode-property-regex": "^7.18.6", @@ -2003,7 +2109,7 @@ "@babel/plugin-syntax-class-static-block": "^7.14.5", "@babel/plugin-syntax-dynamic-import": "^7.8.3", "@babel/plugin-syntax-export-namespace-from": "^7.8.3", - "@babel/plugin-syntax-import-assertions": "^7.18.6", + "@babel/plugin-syntax-import-assertions": "^7.20.0", "@babel/plugin-syntax-json-strings": "^7.8.3", "@babel/plugin-syntax-logical-assignment-operators": "^7.10.4", "@babel/plugin-syntax-nullish-coalescing-operator": "^7.8.3", @@ -2016,41 +2122,41 @@ "@babel/plugin-transform-arrow-functions": "^7.18.6", "@babel/plugin-transform-async-to-generator": "^7.18.6", "@babel/plugin-transform-block-scoped-functions": "^7.18.6", - "@babel/plugin-transform-block-scoping": "^7.18.6", - "@babel/plugin-transform-classes": "^7.18.6", - "@babel/plugin-transform-computed-properties": "^7.18.6", - "@babel/plugin-transform-destructuring": "^7.18.6", + "@babel/plugin-transform-block-scoping": "^7.20.2", + "@babel/plugin-transform-classes": "^7.20.2", + "@babel/plugin-transform-computed-properties": "^7.18.9", + "@babel/plugin-transform-destructuring": "^7.20.2", "@babel/plugin-transform-dotall-regex": "^7.18.6", - "@babel/plugin-transform-duplicate-keys": "^7.18.6", + "@babel/plugin-transform-duplicate-keys": "^7.18.9", "@babel/plugin-transform-exponentiation-operator": "^7.18.6", - "@babel/plugin-transform-for-of": "^7.18.6", - "@babel/plugin-transform-function-name": "^7.18.6", - "@babel/plugin-transform-literals": "^7.18.6", + "@babel/plugin-transform-for-of": "^7.18.8", + "@babel/plugin-transform-function-name": "^7.18.9", + "@babel/plugin-transform-literals": "^7.18.9", "@babel/plugin-transform-member-expression-literals": "^7.18.6", - "@babel/plugin-transform-modules-amd": "^7.18.6", - "@babel/plugin-transform-modules-commonjs": "^7.18.6", - "@babel/plugin-transform-modules-systemjs": "^7.18.6", + "@babel/plugin-transform-modules-amd": "^7.19.6", + "@babel/plugin-transform-modules-commonjs": "^7.19.6", + "@babel/plugin-transform-modules-systemjs": "^7.19.6", "@babel/plugin-transform-modules-umd": "^7.18.6", - "@babel/plugin-transform-named-capturing-groups-regex": "^7.18.6", + "@babel/plugin-transform-named-capturing-groups-regex": "^7.19.1", "@babel/plugin-transform-new-target": "^7.18.6", "@babel/plugin-transform-object-super": "^7.18.6", - "@babel/plugin-transform-parameters": "^7.18.6", + "@babel/plugin-transform-parameters": "^7.20.1", "@babel/plugin-transform-property-literals": "^7.18.6", "@babel/plugin-transform-regenerator": "^7.18.6", "@babel/plugin-transform-reserved-words": "^7.18.6", "@babel/plugin-transform-shorthand-properties": "^7.18.6", - "@babel/plugin-transform-spread": "^7.18.6", + "@babel/plugin-transform-spread": "^7.19.0", "@babel/plugin-transform-sticky-regex": "^7.18.6", - "@babel/plugin-transform-template-literals": "^7.18.6", - "@babel/plugin-transform-typeof-symbol": "^7.18.6", - "@babel/plugin-transform-unicode-escapes": "^7.18.6", + "@babel/plugin-transform-template-literals": "^7.18.9", + "@babel/plugin-transform-typeof-symbol": "^7.18.9", + "@babel/plugin-transform-unicode-escapes": "^7.18.10", "@babel/plugin-transform-unicode-regex": "^7.18.6", "@babel/preset-modules": "^0.1.5", - "@babel/types": "^7.18.6", - "babel-plugin-polyfill-corejs2": "^0.3.1", - "babel-plugin-polyfill-corejs3": "^0.5.2", - "babel-plugin-polyfill-regenerator": "^0.3.1", - "core-js-compat": "^3.22.1", + "@babel/types": "^7.20.2", + "babel-plugin-polyfill-corejs2": "^0.3.3", + "babel-plugin-polyfill-corejs3": "^0.6.0", + "babel-plugin-polyfill-regenerator": "^0.4.1", + "core-js-compat": "^3.25.1", "semver": "^6.3.0" }, "engines": { @@ -2089,33 +2195,33 @@ } }, "node_modules/@babel/template": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.18.6.tgz", - "integrity": "sha512-JoDWzPe+wgBsTTgdnIma3iHNFC7YVJoPssVBDjiHfNlyt4YcunDtcDOUmfVDfCK5MfdsaIoX9PkijPhjH3nYUw==", + "version": "7.18.10", + "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.18.10.tgz", + "integrity": "sha512-TI+rCtooWHr3QJ27kJxfjutghu44DLnasDMwpDqCXVTal9RLp3RSYNh4NdBrRP2cQAoG9A8juOQl6P6oZG4JxA==", "dev": true, "dependencies": { "@babel/code-frame": "^7.18.6", - "@babel/parser": "^7.18.6", - "@babel/types": "^7.18.6" + "@babel/parser": "^7.18.10", + "@babel/types": "^7.18.10" }, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/traverse": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.18.6.tgz", - "integrity": "sha512-zS/OKyqmD7lslOtFqbscH6gMLFYOfG1YPqCKfAW5KrTeolKqvB8UelR49Fpr6y93kYkW2Ik00mT1LOGiAGvizw==", + "version": "7.20.1", + "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.20.1.tgz", + "integrity": "sha512-d3tN8fkVJwFLkHkBN479SOsw4DMZnz8cdbL/gvuDuzy3TS6Nfw80HuQqhw1pITbIruHyh7d1fMA47kWzmcUEGA==", "dev": true, "dependencies": { "@babel/code-frame": "^7.18.6", - "@babel/generator": "^7.18.6", - "@babel/helper-environment-visitor": "^7.18.6", - "@babel/helper-function-name": "^7.18.6", + "@babel/generator": "^7.20.1", + "@babel/helper-environment-visitor": "^7.18.9", + "@babel/helper-function-name": "^7.19.0", "@babel/helper-hoist-variables": "^7.18.6", "@babel/helper-split-export-declaration": "^7.18.6", - "@babel/parser": "^7.18.6", - "@babel/types": "^7.18.6", + "@babel/parser": "^7.20.1", + "@babel/types": "^7.20.0", "debug": "^4.1.0", "globals": "^11.1.0" }, @@ -2124,12 +2230,13 @@ } }, "node_modules/@babel/types": { - "version": "7.18.7", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.18.7.tgz", - "integrity": "sha512-QG3yxTcTIBoAcQmkCs+wAPYZhu7Dk9rXKacINfNbdJDNERTbLQbHGyVG8q/YGMPeCJRIhSY0+fTc5+xuh6WPSQ==", + "version": "7.20.2", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.20.2.tgz", + "integrity": "sha512-FnnvsNWgZCr232sqtXggapvlkk/tuwR/qhGzcmxI0GXLCjmPYQPzio2FbdlWuY6y1sHFfQKk+rRbUZ9VStQMog==", "dev": true, "dependencies": { - "@babel/helper-validator-identifier": "^7.18.6", + "@babel/helper-string-parser": "^7.19.4", + "@babel/helper-validator-identifier": "^7.19.1", "to-fast-properties": "^2.0.0" }, "engines": { @@ -2179,9 +2286,9 @@ } }, "node_modules/@elastic/elasticsearch": { - "version": "8.2.1", - "resolved": "https://registry.npmjs.org/@elastic/elasticsearch/-/elasticsearch-8.2.1.tgz", - "integrity": "sha512-Kwerd8DfNZdBGgl7fkn+20kXkw1QePB3goTv5QwW9poo2d4VbPE0EChmh6irpXWAGsVSYiKr8x6bh8dH5YdylA==", + "version": "8.5.0", + "resolved": "https://registry.npmjs.org/@elastic/elasticsearch/-/elasticsearch-8.5.0.tgz", + "integrity": "sha512-iOgr/3zQi84WmPhAplnK2W13R89VXD2oc6WhlQmH3bARQwmI+De23ZJKBEn7bvuG/AHMAqasPXX7uJIiJa2MqQ==", "dev": true, "dependencies": { "@elastic/transport": "^8.2.0", @@ -2237,14 +2344,14 @@ "dev": true }, "node_modules/@fastify/ajv-compiler": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/@fastify/ajv-compiler/-/ajv-compiler-3.1.0.tgz", - "integrity": "sha512-+hRMMxcUmdqtnCGPwrI2yczFdlgp3IBR88WlPLimXlgRb8vHBTXz38I17R/9ui+hIt9jx0uOdZKOis77VooHfA==", + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/@fastify/ajv-compiler/-/ajv-compiler-3.3.1.tgz", + "integrity": "sha512-IRnids8lblQ8e1i8h4JLyfJmebXE+ohcj8x8X/+Ew6ZB4H0Ui05z5YL6q5FOcl0zItVpu4adRzeyVNNUwmduIg==", "dev": true, "dependencies": { - "ajv": "^8.10.0", + "ajv": "^8.11.0", "ajv-formats": "^2.1.1", - "fast-uri": "^1.0.1" + "fast-uri": "^2.0.0" } }, "node_modules/@fastify/ajv-compiler/node_modules/ajv": { @@ -2263,10 +2370,10 @@ "url": "https://github.com/sponsors/epoberezkin" } }, - "node_modules/@fastify/ajv-compiler/node_modules/json-schema-traverse": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", - "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==", + "node_modules/@fastify/deepmerge": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@fastify/deepmerge/-/deepmerge-1.1.0.tgz", + "integrity": "sha512-E8Hfdvs1bG6u0N4vN5Nty6JONUfTdOciyD5rn8KnEsLKIenvOVcr210BQR9t34PRkNyjqnMLGk3e0BsaxRdL+g==", "dev": true }, "node_modules/@fastify/error": { @@ -2276,9 +2383,9 @@ "dev": true }, "node_modules/@fastify/fast-json-stringify-compiler": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/@fastify/fast-json-stringify-compiler/-/fast-json-stringify-compiler-4.0.0.tgz", - "integrity": "sha512-9pCi6c6tmGt/qfuf2koZQuSIG6ckP9q3mz+JoMmAq9eQ4EtA92sWoK7E0LJUn2FFTS/hp5kag+4+dWsV5ZfcXg==", + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/@fastify/fast-json-stringify-compiler/-/fast-json-stringify-compiler-4.1.0.tgz", + "integrity": "sha512-cTKBV2J9+u6VaKDhX7HepSfPSzw+F+TSd+k0wzifj4rG+4E5PjSFJCk19P8R6tr/72cuzgGd+mbB3jFT6lvAgw==", "dev": true, "dependencies": { "fast-json-stringify": "^5.0.0" @@ -2301,37 +2408,27 @@ } }, "node_modules/@fastify/fast-json-stringify-compiler/node_modules/fast-json-stringify": { - "version": "5.0.5", - "resolved": "https://registry.npmjs.org/fast-json-stringify/-/fast-json-stringify-5.0.5.tgz", - "integrity": "sha512-NGXE7I6dBcSTM1pprcLEIQ6nHp424mDn8ABleM17Sp7XkyPLlbIDed41/VhUiqnLICX7XiOoFsNHx/nnJ8qhig==", + "version": "5.4.0", + "resolved": "https://registry.npmjs.org/fast-json-stringify/-/fast-json-stringify-5.4.0.tgz", + "integrity": "sha512-PIzon53oX/zEGLrGbu4DpfNcYiV4K4rk+JsVrawRPO/G8cNBEMZ3KlIk2BCGqN+m1KCCA4zt5E7Hh3GG9ojRVA==", "dev": true, "dependencies": { + "@fastify/deepmerge": "^1.0.0", "ajv": "^8.10.0", "ajv-formats": "^2.1.1", - "deepmerge": "^4.2.2", + "fast-deep-equal": "^3.1.3", "fast-uri": "^2.1.0", "rfdc": "^1.2.0" } }, - "node_modules/@fastify/fast-json-stringify-compiler/node_modules/fast-uri": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/fast-uri/-/fast-uri-2.1.0.tgz", - "integrity": "sha512-qKRta6N7BWEFVlyonVY/V+BMLgFqktCUV0QjT259ekAIlbVrMaFnFLxJ4s/JPl4tou56S1BzPufI60bLe29fHA==", - "dev": true - }, - "node_modules/@fastify/fast-json-stringify-compiler/node_modules/json-schema-traverse": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", - "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==", - "dev": true - }, "node_modules/@fastify/formbody": { - "version": "7.0.1", - "resolved": "https://registry.npmjs.org/@fastify/formbody/-/formbody-7.0.1.tgz", - "integrity": "sha512-CY6IfzdtidHbZezyyXv7u9dzmb2Lv92HyOZDqANuFb++5ojsqoqIb8bJz11bSgPK0MDoqww/dH6DxZDMM8N4ng==", + "version": "7.4.0", + "resolved": "https://registry.npmjs.org/@fastify/formbody/-/formbody-7.4.0.tgz", + "integrity": "sha512-H3C6h1GN56/SMrZS8N2vCT2cZr7mIHzBHzOBa5OPpjfB/D6FzP9mMpE02ZzrFX0ANeh0BAJdoXKOF2e7IbV+Og==", "dev": true, "dependencies": { - "fastify-plugin": "^3.0.0" + "fast-querystring": "^1.0.0", + "fastify-plugin": "^4.0.0" } }, "node_modules/@graphql-tools/merge": { @@ -2414,157 +2511,226 @@ "dev": true }, "node_modules/@hapi/accept": { - "version": "5.0.2", - "resolved": "https://registry.npmjs.org/@hapi/accept/-/accept-5.0.2.tgz", - "integrity": "sha512-CmzBx/bXUR8451fnZRuZAJRlzgm0Jgu5dltTX/bszmR2lheb9BpyN47Q1RbaGTsvFzn0PXAEs+lXDKfshccYZw==", + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/@hapi/accept/-/accept-6.0.0.tgz", + "integrity": "sha512-aG/Ml4kSBWCVmWvR8N8ULRuB385D8K/3OI7lquZQruH11eM7sHR5Nha30BbDzijJHtyV7Vwc6MlMwNfwb70ISg==", "dev": true, "dependencies": { - "@hapi/boom": "9.x.x", - "@hapi/hoek": "9.x.x" + "@hapi/boom": "^10.0.0", + "@hapi/hoek": "^10.0.0" } }, + "node_modules/@hapi/accept/node_modules/@hapi/hoek": { + "version": "10.0.1", + "resolved": "https://registry.npmjs.org/@hapi/hoek/-/hoek-10.0.1.tgz", + "integrity": "sha512-CvlW7jmOhWzuqOqiJQ3rQVLMcREh0eel4IBnxDx2FAcK8g7qoJRQK4L1CPBASoCY6y8e6zuCy3f2g+HWdkzcMw==", + "dev": true + }, "node_modules/@hapi/ammo": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/@hapi/ammo/-/ammo-5.0.1.tgz", - "integrity": "sha512-FbCNwcTbnQP4VYYhLNGZmA76xb2aHg9AMPiy18NZyWMG310P5KdFGyA9v2rm5ujrIny77dEEIkMOwl0Xv+fSSA==", + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/@hapi/ammo/-/ammo-6.0.0.tgz", + "integrity": "sha512-lhX7SYtWScQaeAIL5XnE54WzyDgS5RXVeEtFEovyZcTdVzTYbo0nem56Bwko1PBcRxRUIw1v2tMb6sjFs6vEwg==", "dev": true, "dependencies": { - "@hapi/hoek": "9.x.x" + "@hapi/hoek": "^10.0.0" } }, + "node_modules/@hapi/ammo/node_modules/@hapi/hoek": { + "version": "10.0.1", + "resolved": "https://registry.npmjs.org/@hapi/hoek/-/hoek-10.0.1.tgz", + "integrity": "sha512-CvlW7jmOhWzuqOqiJQ3rQVLMcREh0eel4IBnxDx2FAcK8g7qoJRQK4L1CPBASoCY6y8e6zuCy3f2g+HWdkzcMw==", + "dev": true + }, "node_modules/@hapi/b64": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/@hapi/b64/-/b64-5.0.0.tgz", - "integrity": "sha512-ngu0tSEmrezoiIaNGG6rRvKOUkUuDdf4XTPnONHGYfSGRmDqPZX5oJL6HAdKTo1UQHECbdB4OzhWrfgVppjHUw==", + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/@hapi/b64/-/b64-6.0.0.tgz", + "integrity": "sha512-Es6o4BtzvMmNF28KJGuwUzUtMjF6ToZ1hQt3UOjaXc6TNkRefel+NyQSjc9b5q3Re7xwv23r0xK3Vo3yreaJHQ==", "dev": true, "dependencies": { - "@hapi/hoek": "9.x.x" + "@hapi/hoek": "^10.0.0" } }, + "node_modules/@hapi/b64/node_modules/@hapi/hoek": { + "version": "10.0.1", + "resolved": "https://registry.npmjs.org/@hapi/hoek/-/hoek-10.0.1.tgz", + "integrity": "sha512-CvlW7jmOhWzuqOqiJQ3rQVLMcREh0eel4IBnxDx2FAcK8g7qoJRQK4L1CPBASoCY6y8e6zuCy3f2g+HWdkzcMw==", + "dev": true + }, "node_modules/@hapi/boom": { - "version": "9.1.4", - "resolved": "https://registry.npmjs.org/@hapi/boom/-/boom-9.1.4.tgz", - "integrity": "sha512-Ls1oH8jaN1vNsqcaHVYJrKmgMcKsC1wcp8bujvXrHaAqD2iDYq3HoOwsxwo09Cuda5R5nC0o0IxlrlTuvPuzSw==", + "version": "10.0.0", + "resolved": "https://registry.npmjs.org/@hapi/boom/-/boom-10.0.0.tgz", + "integrity": "sha512-1YVs9tLHhypBqqinKQRqh7FUERIolarQApO37OWkzD+z6y6USi871Sv746zBPKcIOBuI6g6y4FrwX87mmJ90Gg==", "dev": true, "dependencies": { - "@hapi/hoek": "9.x.x" + "@hapi/hoek": "10.x.x" } }, + "node_modules/@hapi/boom/node_modules/@hapi/hoek": { + "version": "10.0.1", + "resolved": "https://registry.npmjs.org/@hapi/hoek/-/hoek-10.0.1.tgz", + "integrity": "sha512-CvlW7jmOhWzuqOqiJQ3rQVLMcREh0eel4IBnxDx2FAcK8g7qoJRQK4L1CPBASoCY6y8e6zuCy3f2g+HWdkzcMw==", + "dev": true + }, "node_modules/@hapi/bounce": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/@hapi/bounce/-/bounce-2.0.0.tgz", - "integrity": "sha512-JesW92uyzOOyuzJKjoLHM1ThiOvHPOLDHw01YV8yh5nCso7sDwJho1h0Ad2N+E62bZyz46TG3xhAi/78Gsct6A==", + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@hapi/bounce/-/bounce-3.0.0.tgz", + "integrity": "sha512-L0G4NcwwOYRhpcXeL76hNrLTUcObqtZMB3z4kcRVUZcR/w3v6C5Q1cTElV4/V7og1fG+wOyDR55UMFA+tWfhtA==", "dev": true, "dependencies": { - "@hapi/boom": "9.x.x", - "@hapi/hoek": "9.x.x" + "@hapi/boom": "^10.0.0", + "@hapi/hoek": "^10.0.0" } }, + "node_modules/@hapi/bounce/node_modules/@hapi/hoek": { + "version": "10.0.1", + "resolved": "https://registry.npmjs.org/@hapi/hoek/-/hoek-10.0.1.tgz", + "integrity": "sha512-CvlW7jmOhWzuqOqiJQ3rQVLMcREh0eel4IBnxDx2FAcK8g7qoJRQK4L1CPBASoCY6y8e6zuCy3f2g+HWdkzcMw==", + "dev": true + }, "node_modules/@hapi/bourne": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/@hapi/bourne/-/bourne-2.1.0.tgz", - "integrity": "sha512-i1BpaNDVLJdRBEKeJWkVO6tYX6DMFBuwMhSuWqLsY4ufeTKGVuV5rBsUhxPayXqnnWHgXUAmWK16H/ykO5Wj4Q==", + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@hapi/bourne/-/bourne-3.0.0.tgz", + "integrity": "sha512-Waj1cwPXJDucOib4a3bAISsKJVb15MKi9IvmTI/7ssVEm6sywXGjVJDhl6/umt1pK1ZS7PacXU3A1PmFKHEZ2w==", "dev": true }, "node_modules/@hapi/call": { - "version": "8.0.1", - "resolved": "https://registry.npmjs.org/@hapi/call/-/call-8.0.1.tgz", - "integrity": "sha512-bOff6GTdOnoe5b8oXRV3lwkQSb/LAWylvDMae6RgEWWntd0SHtkYbQukDHKlfaYtVnSAgIavJ0kqszF/AIBb6g==", + "version": "9.0.0", + "resolved": "https://registry.npmjs.org/@hapi/call/-/call-9.0.0.tgz", + "integrity": "sha512-Z6byqbEtKF3RIH2kWG6cX64RwEqHBWYEVkNoEx6oKvkPaTrC6WTPRgr+ANo9Xa8G1GXyvs/NCMTnn3Mdj12TSA==", "dev": true, "dependencies": { - "@hapi/boom": "9.x.x", - "@hapi/hoek": "9.x.x" + "@hapi/boom": "^10.0.0", + "@hapi/hoek": "^10.0.0" } }, + "node_modules/@hapi/call/node_modules/@hapi/hoek": { + "version": "10.0.1", + "resolved": "https://registry.npmjs.org/@hapi/hoek/-/hoek-10.0.1.tgz", + "integrity": "sha512-CvlW7jmOhWzuqOqiJQ3rQVLMcREh0eel4IBnxDx2FAcK8g7qoJRQK4L1CPBASoCY6y8e6zuCy3f2g+HWdkzcMw==", + "dev": true + }, "node_modules/@hapi/catbox": { - "version": "11.1.1", - "resolved": "https://registry.npmjs.org/@hapi/catbox/-/catbox-11.1.1.tgz", - "integrity": "sha512-u/8HvB7dD/6X8hsZIpskSDo4yMKpHxFd7NluoylhGrL6cUfYxdQPnvUp9YU2C6F9hsyBVLGulBd9vBN1ebfXOQ==", + "version": "12.0.1", + "resolved": "https://registry.npmjs.org/@hapi/catbox/-/catbox-12.0.1.tgz", + "integrity": "sha512-EJnj0KJt9LZ/c+mo6NB7mesFhy+s+CDX3AT7de5VRCOHkzOm4ENxN/rgNd0HyI/AfT8FqyUKt1Gccd1DVg8tQA==", "dev": true, "dependencies": { - "@hapi/boom": "9.x.x", - "@hapi/hoek": "9.x.x", - "@hapi/podium": "4.x.x", - "@hapi/validate": "1.x.x" + "@hapi/boom": "^10.0.0", + "@hapi/hoek": "^10.0.0", + "@hapi/podium": "^5.0.0", + "@hapi/validate": "^2.0.0" } }, "node_modules/@hapi/catbox-memory": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/@hapi/catbox-memory/-/catbox-memory-5.0.1.tgz", - "integrity": "sha512-QWw9nOYJq5PlvChLWV8i6hQHJYfvdqiXdvTupJFh0eqLZ64Xir7mKNi96d5/ZMUAqXPursfNDIDxjFgoEDUqeQ==", + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/@hapi/catbox-memory/-/catbox-memory-6.0.0.tgz", + "integrity": "sha512-A1O30g8GdaODx/GinytF6jFm772pdTPVWJe0cF2RiTOfhgIAAagzCcpBqRgQ8olLui0F5bzUF/SAi4BmkZ4yxA==", "dev": true, "dependencies": { - "@hapi/boom": "9.x.x", - "@hapi/hoek": "9.x.x" + "@hapi/boom": "^10.0.0", + "@hapi/hoek": "^10.0.0" } }, + "node_modules/@hapi/catbox-memory/node_modules/@hapi/hoek": { + "version": "10.0.1", + "resolved": "https://registry.npmjs.org/@hapi/hoek/-/hoek-10.0.1.tgz", + "integrity": "sha512-CvlW7jmOhWzuqOqiJQ3rQVLMcREh0eel4IBnxDx2FAcK8g7qoJRQK4L1CPBASoCY6y8e6zuCy3f2g+HWdkzcMw==", + "dev": true + }, + "node_modules/@hapi/catbox/node_modules/@hapi/hoek": { + "version": "10.0.1", + "resolved": "https://registry.npmjs.org/@hapi/hoek/-/hoek-10.0.1.tgz", + "integrity": "sha512-CvlW7jmOhWzuqOqiJQ3rQVLMcREh0eel4IBnxDx2FAcK8g7qoJRQK4L1CPBASoCY6y8e6zuCy3f2g+HWdkzcMw==", + "dev": true + }, "node_modules/@hapi/content": { - "version": "5.0.2", - "resolved": "https://registry.npmjs.org/@hapi/content/-/content-5.0.2.tgz", - "integrity": "sha512-mre4dl1ygd4ZyOH3tiYBrOUBzV7Pu/EOs8VLGf58vtOEECWed8Uuw6B4iR9AN/8uQt42tB04qpVaMyoMQh0oMw==", + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/@hapi/content/-/content-6.0.0.tgz", + "integrity": "sha512-CEhs7j+H0iQffKfe5Htdak5LBOz/Qc8TRh51cF+BFv0qnuph3Em4pjGVzJMkI2gfTDdlJKWJISGWS1rK34POGA==", "dev": true, "dependencies": { - "@hapi/boom": "9.x.x" + "@hapi/boom": "^10.0.0" } }, "node_modules/@hapi/cryptiles": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/@hapi/cryptiles/-/cryptiles-5.1.0.tgz", - "integrity": "sha512-fo9+d1Ba5/FIoMySfMqPBR/7Pa29J2RsiPrl7bkwo5W5o+AN1dAYQRi4SPrPwwVxVGKjgLOEWrsvt1BonJSfLA==", + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/@hapi/cryptiles/-/cryptiles-6.0.0.tgz", + "integrity": "sha512-CUypQJI2F3HaKZjwlky3KyLu7p0O4WJXNJj+2AZ0czqwkwQIz8j+btOkzA3OMar8WTntnCrDx0f92PzxEK+JlA==", "dev": true, "dependencies": { - "@hapi/boom": "9.x.x" + "@hapi/boom": "^10.0.0" }, "engines": { - "node": ">=12.0.0" + "node": ">=14.0.0" } }, "node_modules/@hapi/file": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/@hapi/file/-/file-2.0.0.tgz", - "integrity": "sha512-WSrlgpvEqgPWkI18kkGELEZfXr0bYLtr16iIN4Krh9sRnzBZN6nnWxHFxtsnP684wueEySBbXPDg/WfA9xJdBQ==", + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@hapi/file/-/file-3.0.0.tgz", + "integrity": "sha512-w+lKW+yRrLhJu620jT3y+5g2mHqnKfepreykvdOcl9/6up8GrQQn+l3FRTsjHTKbkbfQFkuksHpdv2EcpKcJ4Q==", "dev": true }, "node_modules/@hapi/hapi": { - "version": "20.2.2", - "resolved": "https://registry.npmjs.org/@hapi/hapi/-/hapi-20.2.2.tgz", - "integrity": "sha512-crhU6TIKt7QsksWLYctDBAXogk9PYAm7UzdpETyuBHC2pCa6/+B5NykiOVLG/3FCIgHo/raPVtan8bYtByHORQ==", - "dev": true, - "dependencies": { - "@hapi/accept": "^5.0.1", - "@hapi/ammo": "^5.0.1", - "@hapi/boom": "^9.1.0", - "@hapi/bounce": "^2.0.0", - "@hapi/call": "^8.0.0", - "@hapi/catbox": "^11.1.1", - "@hapi/catbox-memory": "^5.0.0", - "@hapi/heavy": "^7.0.1", - "@hapi/hoek": "^9.0.4", - "@hapi/mimos": "^6.0.0", - "@hapi/podium": "^4.1.1", - "@hapi/shot": "^5.0.5", - "@hapi/somever": "^3.0.0", - "@hapi/statehood": "^7.0.4", - "@hapi/subtext": "^7.0.3", - "@hapi/teamwork": "^5.1.1", - "@hapi/topo": "^5.0.0", - "@hapi/validate": "^1.1.1" - }, - "engines": { - "node": ">=12.0.0" + "version": "21.1.0", + "resolved": "https://registry.npmjs.org/@hapi/hapi/-/hapi-21.1.0.tgz", + "integrity": "sha512-het7j9yLXZMVU1IvtN2JXkPkn/UcU1j8gsZxMS0Mu1q7791IQeyhT37tpRPUhqerOtL6L0E8Z8CvVVFOYxoN6w==", + "dev": true, + "dependencies": { + "@hapi/accept": "^6.0.0", + "@hapi/ammo": "^6.0.0", + "@hapi/boom": "^10.0.0", + "@hapi/bounce": "^3.0.0", + "@hapi/call": "^9.0.0", + "@hapi/catbox": "^12.0.0", + "@hapi/catbox-memory": "^6.0.0", + "@hapi/heavy": "^8.0.0", + "@hapi/hoek": "^10.0.0", + "@hapi/mimos": "^7.0.0", + "@hapi/podium": "^5.0.0", + "@hapi/shot": "^6.0.0", + "@hapi/somever": "^4.1.0", + "@hapi/statehood": "^8.0.0", + "@hapi/subtext": "^8.0.0", + "@hapi/teamwork": "^6.0.0", + "@hapi/topo": "^6.0.0", + "@hapi/validate": "^2.0.0" + }, + "engines": { + "node": ">=14.15.0" + } + }, + "node_modules/@hapi/hapi/node_modules/@hapi/hoek": { + "version": "10.0.1", + "resolved": "https://registry.npmjs.org/@hapi/hoek/-/hoek-10.0.1.tgz", + "integrity": "sha512-CvlW7jmOhWzuqOqiJQ3rQVLMcREh0eel4IBnxDx2FAcK8g7qoJRQK4L1CPBASoCY6y8e6zuCy3f2g+HWdkzcMw==", + "dev": true + }, + "node_modules/@hapi/hapi/node_modules/@hapi/topo": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/@hapi/topo/-/topo-6.0.0.tgz", + "integrity": "sha512-aorJvN1Q1n5xrZuA50Z4X6adI6VAM2NalIVm46ALL9LUvdoqhof3JPY69jdJH8asM3PsWr2SUVYzp57EqUP41A==", + "dev": true, + "dependencies": { + "@hapi/hoek": "^10.0.0" } }, "node_modules/@hapi/heavy": { - "version": "7.0.1", - "resolved": "https://registry.npmjs.org/@hapi/heavy/-/heavy-7.0.1.tgz", - "integrity": "sha512-vJ/vzRQ13MtRzz6Qd4zRHWS3FaUc/5uivV2TIuExGTM9Qk+7Zzqj0e2G7EpE6KztO9SalTbiIkTh7qFKj/33cA==", + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/@hapi/heavy/-/heavy-8.0.0.tgz", + "integrity": "sha512-NpKo74mF66GSwYu31IZwp11/6NmaUYxHeMTKSky09XBs8fVbzQDP83856+l+Ji6wxGmUeg75itCu1ujvEF6mdA==", "dev": true, "dependencies": { - "@hapi/boom": "9.x.x", - "@hapi/hoek": "9.x.x", - "@hapi/validate": "1.x.x" + "@hapi/boom": "^10.0.0", + "@hapi/hoek": "^10.0.0", + "@hapi/validate": "^2.0.0" } }, + "node_modules/@hapi/heavy/node_modules/@hapi/hoek": { + "version": "10.0.1", + "resolved": "https://registry.npmjs.org/@hapi/hoek/-/hoek-10.0.1.tgz", + "integrity": "sha512-CvlW7jmOhWzuqOqiJQ3rQVLMcREh0eel4IBnxDx2FAcK8g7qoJRQK4L1CPBASoCY6y8e6zuCy3f2g+HWdkzcMw==", + "dev": true + }, "node_modules/@hapi/hoek": { "version": "9.3.0", "resolved": "https://registry.npmjs.org/@hapi/hoek/-/hoek-9.3.0.tgz", @@ -2572,122 +2738,170 @@ "dev": true }, "node_modules/@hapi/iron": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/@hapi/iron/-/iron-6.0.0.tgz", - "integrity": "sha512-zvGvWDufiTGpTJPG1Y/McN8UqWBu0k/xs/7l++HVU535NLHXsHhy54cfEMdW7EjwKfbBfM9Xy25FmTiobb7Hvw==", + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/@hapi/iron/-/iron-7.0.0.tgz", + "integrity": "sha512-NNXJP5fpeiTCPj/4OJG2PWBjWC0/V5D8YggS9RZeuBbfUUuTYE6TbdGqLUsCzIpPI54I8W5dhwEGbRv1CnWQtw==", "dev": true, "dependencies": { - "@hapi/b64": "5.x.x", - "@hapi/boom": "9.x.x", - "@hapi/bourne": "2.x.x", - "@hapi/cryptiles": "5.x.x", - "@hapi/hoek": "9.x.x" + "@hapi/b64": "^6.0.0", + "@hapi/boom": "^10.0.0", + "@hapi/bourne": "^3.0.0", + "@hapi/cryptiles": "^6.0.0", + "@hapi/hoek": "^10.0.0" } }, + "node_modules/@hapi/iron/node_modules/@hapi/hoek": { + "version": "10.0.1", + "resolved": "https://registry.npmjs.org/@hapi/hoek/-/hoek-10.0.1.tgz", + "integrity": "sha512-CvlW7jmOhWzuqOqiJQ3rQVLMcREh0eel4IBnxDx2FAcK8g7qoJRQK4L1CPBASoCY6y8e6zuCy3f2g+HWdkzcMw==", + "dev": true + }, "node_modules/@hapi/mimos": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/@hapi/mimos/-/mimos-6.0.0.tgz", - "integrity": "sha512-Op/67tr1I+JafN3R3XN5DucVSxKRT/Tc+tUszDwENoNpolxeXkhrJ2Czt6B6AAqrespHoivhgZBWYSuANN9QXg==", + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/@hapi/mimos/-/mimos-7.0.0.tgz", + "integrity": "sha512-ALORTrZrrBPOUX05rW4htNajoekEjQtUi1PB+17/3xs/hkdQ+gSEFbs5GdJihA49qWf7td3v4PgnvOe8mcf/jQ==", "dev": true, "dependencies": { - "@hapi/hoek": "9.x.x", - "mime-db": "1.x.x" + "@hapi/hoek": "^10.0.0", + "mime-db": "^1.52.0" } }, + "node_modules/@hapi/mimos/node_modules/@hapi/hoek": { + "version": "10.0.1", + "resolved": "https://registry.npmjs.org/@hapi/hoek/-/hoek-10.0.1.tgz", + "integrity": "sha512-CvlW7jmOhWzuqOqiJQ3rQVLMcREh0eel4IBnxDx2FAcK8g7qoJRQK4L1CPBASoCY6y8e6zuCy3f2g+HWdkzcMw==", + "dev": true + }, "node_modules/@hapi/nigel": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/@hapi/nigel/-/nigel-4.0.2.tgz", - "integrity": "sha512-ht2KoEsDW22BxQOEkLEJaqfpoKPXxi7tvabXy7B/77eFtOyG5ZEstfZwxHQcqAiZhp58Ae5vkhEqI03kawkYNw==", + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/@hapi/nigel/-/nigel-5.0.0.tgz", + "integrity": "sha512-I9eq43BnSdz1BkvMpG7mFL7J+SIfn6DLNThuxFpIOAMUnkWbPgtcFP+HHrBAeoFkowfgQrr02vsIAkAPml4hvw==", "dev": true, "dependencies": { - "@hapi/hoek": "^9.0.4", - "@hapi/vise": "^4.0.0" + "@hapi/hoek": "^10.0.0", + "@hapi/vise": "^5.0.0" }, "engines": { - "node": ">=12.0.0" + "node": ">=14.0.0" } }, + "node_modules/@hapi/nigel/node_modules/@hapi/hoek": { + "version": "10.0.1", + "resolved": "https://registry.npmjs.org/@hapi/hoek/-/hoek-10.0.1.tgz", + "integrity": "sha512-CvlW7jmOhWzuqOqiJQ3rQVLMcREh0eel4IBnxDx2FAcK8g7qoJRQK4L1CPBASoCY6y8e6zuCy3f2g+HWdkzcMw==", + "dev": true + }, "node_modules/@hapi/pez": { - "version": "5.0.3", - "resolved": "https://registry.npmjs.org/@hapi/pez/-/pez-5.0.3.tgz", - "integrity": "sha512-mpikYRJjtrbJgdDHG/H9ySqYqwJ+QU/D7FXsYciS9P7NYBXE2ayKDAy3H0ou6CohOCaxPuTV4SZ0D936+VomHA==", + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/@hapi/pez/-/pez-6.0.0.tgz", + "integrity": "sha512-3bMmsvlqrVNqaNEe4JWLZVpJ40jXuQ3vDy1+fbhyJmuAdMCMCkWexsKc7fT+mu18pFIwJzlenjc4/VE3weTq7w==", "dev": true, "dependencies": { - "@hapi/b64": "5.x.x", - "@hapi/boom": "9.x.x", - "@hapi/content": "^5.0.2", - "@hapi/hoek": "9.x.x", - "@hapi/nigel": "4.x.x" + "@hapi/b64": "^6.0.0", + "@hapi/boom": "^10.0.0", + "@hapi/content": "^6.0.0", + "@hapi/hoek": "^10.0.0", + "@hapi/nigel": "^5.0.0" } }, + "node_modules/@hapi/pez/node_modules/@hapi/hoek": { + "version": "10.0.1", + "resolved": "https://registry.npmjs.org/@hapi/hoek/-/hoek-10.0.1.tgz", + "integrity": "sha512-CvlW7jmOhWzuqOqiJQ3rQVLMcREh0eel4IBnxDx2FAcK8g7qoJRQK4L1CPBASoCY6y8e6zuCy3f2g+HWdkzcMw==", + "dev": true + }, "node_modules/@hapi/podium": { - "version": "4.1.3", - "resolved": "https://registry.npmjs.org/@hapi/podium/-/podium-4.1.3.tgz", - "integrity": "sha512-ljsKGQzLkFqnQxE7qeanvgGj4dejnciErYd30dbrYzUOF/FyS/DOF97qcrT3bhoVwCYmxa6PEMhxfCPlnUcD2g==", + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/@hapi/podium/-/podium-5.0.0.tgz", + "integrity": "sha512-SbhFdu8LOIscMS82Zsoj9abcllAqbK4qBgznzJ9yr+vS2j1EomJTukkhxb76Lml0BHCd4Hn79F+3EQg06kcf8g==", "dev": true, "dependencies": { - "@hapi/hoek": "9.x.x", - "@hapi/teamwork": "5.x.x", - "@hapi/validate": "1.x.x" + "@hapi/hoek": "^10.0.0", + "@hapi/teamwork": "^6.0.0", + "@hapi/validate": "^2.0.0" } }, + "node_modules/@hapi/podium/node_modules/@hapi/hoek": { + "version": "10.0.1", + "resolved": "https://registry.npmjs.org/@hapi/hoek/-/hoek-10.0.1.tgz", + "integrity": "sha512-CvlW7jmOhWzuqOqiJQ3rQVLMcREh0eel4IBnxDx2FAcK8g7qoJRQK4L1CPBASoCY6y8e6zuCy3f2g+HWdkzcMw==", + "dev": true + }, "node_modules/@hapi/shot": { - "version": "5.0.5", - "resolved": "https://registry.npmjs.org/@hapi/shot/-/shot-5.0.5.tgz", - "integrity": "sha512-x5AMSZ5+j+Paa8KdfCoKh+klB78otxF+vcJR/IoN91Vo2e5ulXIW6HUsFTCU+4W6P/Etaip9nmdAx2zWDimB2A==", + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/@hapi/shot/-/shot-6.0.0.tgz", + "integrity": "sha512-RLGgzXy9GciJDunhY40NbVnLgYqp5gfBooZ2fOkAr4KbCEav/SJtYQS1N+knR7WFGzy8aooCR3XBUPI4ghHAkQ==", "dev": true, "dependencies": { - "@hapi/hoek": "9.x.x", - "@hapi/validate": "1.x.x" + "@hapi/hoek": "^10.0.0", + "@hapi/validate": "^2.0.0" } }, + "node_modules/@hapi/shot/node_modules/@hapi/hoek": { + "version": "10.0.1", + "resolved": "https://registry.npmjs.org/@hapi/hoek/-/hoek-10.0.1.tgz", + "integrity": "sha512-CvlW7jmOhWzuqOqiJQ3rQVLMcREh0eel4IBnxDx2FAcK8g7qoJRQK4L1CPBASoCY6y8e6zuCy3f2g+HWdkzcMw==", + "dev": true + }, "node_modules/@hapi/somever": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/@hapi/somever/-/somever-3.0.1.tgz", - "integrity": "sha512-4ZTSN3YAHtgpY/M4GOtHUXgi6uZtG9nEZfNI6QrArhK0XN/RDVgijlb9kOmXwCR5VclDSkBul9FBvhSuKXx9+w==", + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/@hapi/somever/-/somever-4.1.0.tgz", + "integrity": "sha512-koNBYu7Jdcb7gaC4VcnU78rFxSlsYwuElm6NMznE0EEeznzJtvLLmDZX0SPX8kXWC/E7ONlE29HF/yiSOgWG1Q==", "dev": true, "dependencies": { - "@hapi/bounce": "2.x.x", - "@hapi/hoek": "9.x.x" + "@hapi/bounce": "^3.0.0", + "@hapi/hoek": "^9.0.0" } }, "node_modules/@hapi/statehood": { - "version": "7.0.4", - "resolved": "https://registry.npmjs.org/@hapi/statehood/-/statehood-7.0.4.tgz", - "integrity": "sha512-Fia6atroOVmc5+2bNOxF6Zv9vpbNAjEXNcUbWXavDqhnJDlchwUUwKS5LCi5mGtCTxRhUKKHwuxuBZJkmLZ7fw==", + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/@hapi/statehood/-/statehood-8.0.0.tgz", + "integrity": "sha512-umQTPID7BwmqAv9Rx7yLtbTNzsYg4va96aLqKneb3mlBQG32uq4iOQZ6luwBVACDFhqU3C3ewhznhukN09ZkZQ==", "dev": true, "dependencies": { - "@hapi/boom": "9.x.x", - "@hapi/bounce": "2.x.x", - "@hapi/bourne": "2.x.x", - "@hapi/cryptiles": "5.x.x", - "@hapi/hoek": "9.x.x", - "@hapi/iron": "6.x.x", - "@hapi/validate": "1.x.x" + "@hapi/boom": "^10.0.0", + "@hapi/bounce": "^3.0.0", + "@hapi/bourne": "^3.0.0", + "@hapi/cryptiles": "^6.0.0", + "@hapi/hoek": "^10.0.0", + "@hapi/iron": "^7.0.0", + "@hapi/validate": "^2.0.0" } }, + "node_modules/@hapi/statehood/node_modules/@hapi/hoek": { + "version": "10.0.1", + "resolved": "https://registry.npmjs.org/@hapi/hoek/-/hoek-10.0.1.tgz", + "integrity": "sha512-CvlW7jmOhWzuqOqiJQ3rQVLMcREh0eel4IBnxDx2FAcK8g7qoJRQK4L1CPBASoCY6y8e6zuCy3f2g+HWdkzcMw==", + "dev": true + }, "node_modules/@hapi/subtext": { - "version": "7.0.3", - "resolved": "https://registry.npmjs.org/@hapi/subtext/-/subtext-7.0.3.tgz", - "integrity": "sha512-CekDizZkDGERJ01C0+TzHlKtqdXZxzSWTOaH6THBrbOHnsr3GY+yiMZC+AfNCypfE17RaIakGIAbpL2Tk1z2+A==", + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/@hapi/subtext/-/subtext-8.0.0.tgz", + "integrity": "sha512-fD+LY1U1SIUNHZJrNMIbuGl3CAd9JN8slljarFO4b8RrifkzjqbvdlZu/6iT6zlNM35GtDExf7hIepbUFUkT7A==", "dev": true, "dependencies": { - "@hapi/boom": "9.x.x", - "@hapi/bourne": "2.x.x", - "@hapi/content": "^5.0.2", - "@hapi/file": "2.x.x", - "@hapi/hoek": "9.x.x", - "@hapi/pez": "^5.0.1", - "@hapi/wreck": "17.x.x" + "@hapi/boom": "^10.0.0", + "@hapi/bourne": "^3.0.0", + "@hapi/content": "^6.0.0", + "@hapi/file": "^3.0.0", + "@hapi/hoek": "^10.0.0", + "@hapi/pez": "^6.0.0", + "@hapi/wreck": "^18.0.0" } }, + "node_modules/@hapi/subtext/node_modules/@hapi/hoek": { + "version": "10.0.1", + "resolved": "https://registry.npmjs.org/@hapi/hoek/-/hoek-10.0.1.tgz", + "integrity": "sha512-CvlW7jmOhWzuqOqiJQ3rQVLMcREh0eel4IBnxDx2FAcK8g7qoJRQK4L1CPBASoCY6y8e6zuCy3f2g+HWdkzcMw==", + "dev": true + }, "node_modules/@hapi/teamwork": { - "version": "5.1.1", - "resolved": "https://registry.npmjs.org/@hapi/teamwork/-/teamwork-5.1.1.tgz", - "integrity": "sha512-1oPx9AE5TIv+V6Ih54RP9lTZBso3rP8j4Xhb6iSVwPXtAM+sDopl5TFMv5Paw73UnpZJ9gjcrTE1BXrWt9eQrg==", + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/@hapi/teamwork/-/teamwork-6.0.0.tgz", + "integrity": "sha512-05HumSy3LWfXpmJ9cr6HzwhAavrHkJ1ZRCmNE2qJMihdM5YcWreWPfyN0yKT2ZjCM92au3ZkuodjBxOibxM67A==", "dev": true, "engines": { - "node": ">=12.0.0" + "node": ">=14.0.0" } }, "node_modules/@hapi/topo": { @@ -2700,35 +2914,62 @@ } }, "node_modules/@hapi/validate": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/@hapi/validate/-/validate-1.1.3.tgz", - "integrity": "sha512-/XMR0N0wjw0Twzq2pQOzPBZlDzkekGcoCtzO314BpIEsbXdYGthQUbxgkGDf4nhk1+IPDAsXqWjMohRQYO06UA==", + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/@hapi/validate/-/validate-2.0.0.tgz", + "integrity": "sha512-w5m8MvBgqGndbMIB+AWmXTb8CLtF1DlIxbnbAHNAo7aFuNQuI1Ywc2e0zDLK5fbFXDoqRzNrHnC7JjNJ+hDigw==", "dev": true, "dependencies": { - "@hapi/hoek": "^9.0.0", - "@hapi/topo": "^5.0.0" + "@hapi/hoek": "^10.0.0", + "@hapi/topo": "^6.0.0" + } + }, + "node_modules/@hapi/validate/node_modules/@hapi/hoek": { + "version": "10.0.1", + "resolved": "https://registry.npmjs.org/@hapi/hoek/-/hoek-10.0.1.tgz", + "integrity": "sha512-CvlW7jmOhWzuqOqiJQ3rQVLMcREh0eel4IBnxDx2FAcK8g7qoJRQK4L1CPBASoCY6y8e6zuCy3f2g+HWdkzcMw==", + "dev": true + }, + "node_modules/@hapi/validate/node_modules/@hapi/topo": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/@hapi/topo/-/topo-6.0.0.tgz", + "integrity": "sha512-aorJvN1Q1n5xrZuA50Z4X6adI6VAM2NalIVm46ALL9LUvdoqhof3JPY69jdJH8asM3PsWr2SUVYzp57EqUP41A==", + "dev": true, + "dependencies": { + "@hapi/hoek": "^10.0.0" } }, "node_modules/@hapi/vise": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/@hapi/vise/-/vise-4.0.0.tgz", - "integrity": "sha512-eYyLkuUiFZTer59h+SGy7hUm+qE9p+UemePTHLlIWppEd+wExn3Df5jO04bFQTm7nleF5V8CtuYQYb+VFpZ6Sg==", + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/@hapi/vise/-/vise-5.0.0.tgz", + "integrity": "sha512-bz/PA7DHIvsd/2eoW7t9WpU8+k9pofZHppYEn1mCTOVnC/cGN3hCEYaoAe6BpoeJM72iJDKZEOWvQvfgCrmzxA==", "dev": true, "dependencies": { - "@hapi/hoek": "9.x.x" + "@hapi/hoek": "^10.0.0" } }, + "node_modules/@hapi/vise/node_modules/@hapi/hoek": { + "version": "10.0.1", + "resolved": "https://registry.npmjs.org/@hapi/hoek/-/hoek-10.0.1.tgz", + "integrity": "sha512-CvlW7jmOhWzuqOqiJQ3rQVLMcREh0eel4IBnxDx2FAcK8g7qoJRQK4L1CPBASoCY6y8e6zuCy3f2g+HWdkzcMw==", + "dev": true + }, "node_modules/@hapi/wreck": { - "version": "17.2.0", - "resolved": "https://registry.npmjs.org/@hapi/wreck/-/wreck-17.2.0.tgz", - "integrity": "sha512-pJ5kjYoRPYDv+eIuiLQqhGon341fr2bNIYZjuotuPJG/3Ilzr/XtI+JAp0A86E2bYfsS3zBPABuS2ICkaXFT8g==", + "version": "18.0.0", + "resolved": "https://registry.npmjs.org/@hapi/wreck/-/wreck-18.0.0.tgz", + "integrity": "sha512-Yk9STxoM06Hjjq58cH0KFG91u9F2h9eVE72o8vUr3AfK80qt7I2POG5+cDGTEntbnvvzm0ERow2sjG3QsqCWUA==", "dev": true, "dependencies": { - "@hapi/boom": "9.x.x", - "@hapi/bourne": "2.x.x", - "@hapi/hoek": "9.x.x" + "@hapi/boom": "^10.0.0", + "@hapi/bourne": "^3.0.0", + "@hapi/hoek": "^10.0.0" } }, + "node_modules/@hapi/wreck/node_modules/@hapi/hoek": { + "version": "10.0.1", + "resolved": "https://registry.npmjs.org/@hapi/hoek/-/hoek-10.0.1.tgz", + "integrity": "sha512-CvlW7jmOhWzuqOqiJQ3rQVLMcREh0eel4IBnxDx2FAcK8g7qoJRQK4L1CPBASoCY6y8e6zuCy3f2g+HWdkzcMw==", + "dev": true + }, "node_modules/@ioredis/commands": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/@ioredis/commands/-/commands-1.2.0.tgz", @@ -2760,6 +3001,19 @@ "node": ">=6" } }, + "node_modules/@istanbuljs/load-nyc-config/node_modules/js-yaml": { + "version": "3.14.1", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.14.1.tgz", + "integrity": "sha512-okMH7OXXJ7YrN9Ok3/SXrnu4iX9yOk+25nqX4imS2npuvTYDmo/QEZoqwZkYaIDk3jVvBOTOIEgEhaLOynBS9g==", + "dev": true, + "dependencies": { + "argparse": "^1.0.7", + "esprima": "^4.0.0" + }, + "bin": { + "js-yaml": "bin/js-yaml.js" + } + }, "node_modules/@istanbuljs/load-nyc-config/node_modules/resolve-from": { "version": "5.0.0", "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-5.0.0.tgz", @@ -2832,25 +3086,58 @@ } }, "node_modules/@js-joda/core": { - "version": "4.3.1", - "resolved": "https://registry.npmjs.org/@js-joda/core/-/core-4.3.1.tgz", - "integrity": "sha512-oeaetlodcqVsiZDxnEcqsbs+sXBkASxua0mXs5OXuPQXz3/wdPTMlxwfQ4z2HKcOik3S9voW3QJkp/KLWDhvRQ==", + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/@js-joda/core/-/core-5.2.0.tgz", + "integrity": "sha512-0OriPYIaMLB3XiLQMe0BXKVIqeriTn3H7JMOzTsHEtt7Zqq+TetCu97KnAhU3ckiQZKBxfZshft+H1OC4D1lXw==", "dev": true }, "node_modules/@koa/router": { - "version": "9.4.0", - "resolved": "https://registry.npmjs.org/@koa/router/-/router-9.4.0.tgz", - "integrity": "sha512-dOOXgzqaDoHu5qqMEPLKEgLz5CeIA7q8+1W62mCvFVCOqeC71UoTGJ4u1xUSOpIl2J1x2pqrNULkFteUeZW3/A==", + "version": "12.0.0", + "resolved": "https://registry.npmjs.org/@koa/router/-/router-12.0.0.tgz", + "integrity": "sha512-cnnxeKHXlt7XARJptflGURdJaO+ITpNkOHmQu7NHmCoRinPbyvFzce/EG/E8Zy81yQ1W9MoSdtklc3nyaDReUw==", "dev": true, "dependencies": { - "debug": "^4.1.1", - "http-errors": "^1.7.3", + "http-errors": "^2.0.0", "koa-compose": "^4.1.0", "methods": "^1.1.2", - "path-to-regexp": "^6.1.0" + "path-to-regexp": "^6.2.1" }, "engines": { - "node": ">= 8.0.0" + "node": ">= 12" + } + }, + "node_modules/@koa/router/node_modules/depd": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz", + "integrity": "sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==", + "dev": true, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/@koa/router/node_modules/http-errors": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-2.0.0.tgz", + "integrity": "sha512-FtwrG/euBzaEjYeRqOgly7G0qviiXoJWnvEH2Z1plBdXgbyjv34pHTSb9zoeHMyDy33+DWy5Wt9Wo+TURtOYSQ==", + "dev": true, + "dependencies": { + "depd": "2.0.0", + "inherits": "2.0.4", + "setprototypeof": "1.2.0", + "statuses": "2.0.1", + "toidentifier": "1.0.1" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/@koa/router/node_modules/statuses": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.1.tgz", + "integrity": "sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ==", + "dev": true, + "engines": { + "node": ">= 0.8" } }, "node_modules/@netflix/nerror": { @@ -3106,7 +3393,7 @@ "node_modules/@protobufjs/aspromise": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/@protobufjs/aspromise/-/aspromise-1.1.2.tgz", - "integrity": "sha1-m4sMxmPWaafY9vXQiToU00jzD78=", + "integrity": "sha512-j+gKExEuLmKwvz3OgROXtrJ2UG2x8Ch2YZUxahh+s1F2HZ+wAceUNLkvy6zKCPVRkU++ZWQrdxsUeQXmcg4uoQ==", "dev": true }, "node_modules/@protobufjs/base64": { @@ -3124,13 +3411,13 @@ "node_modules/@protobufjs/eventemitter": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/@protobufjs/eventemitter/-/eventemitter-1.1.0.tgz", - "integrity": "sha1-NVy8mLr61ZePntCV85diHx0Ga3A=", + "integrity": "sha512-j9ednRT81vYJ9OfVuXG6ERSTdEL1xVsNgqpkxMsbIabzSo3goCjDIveeGv5d03om39ML71RdmrGNjG5SReBP/Q==", "dev": true }, "node_modules/@protobufjs/fetch": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/@protobufjs/fetch/-/fetch-1.1.0.tgz", - "integrity": "sha1-upn7WYYUr2VwDBYZ/wbUVLDYTEU=", + "integrity": "sha512-lljVXpqXebpsijW71PZaCYeIcE5on1w5DlQy5WH6GLbFryLUrBD4932W/E2BSpfRJWseIL4v/KPgBFxDOIdKpQ==", "dev": true, "dependencies": { "@protobufjs/aspromise": "^1.1.1", @@ -3140,33 +3427,107 @@ "node_modules/@protobufjs/float": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/@protobufjs/float/-/float-1.0.2.tgz", - "integrity": "sha1-Xp4avctz/Ap8uLKR33jIy9l7h9E=", + "integrity": "sha512-Ddb+kVXlXst9d+R9PfTIxh1EdNkgoRe5tOX6t01f1lYWOvJnSPDBlG241QLzcyPdoNTsblLUdujGSE4RzrTZGQ==", "dev": true }, "node_modules/@protobufjs/inquire": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/@protobufjs/inquire/-/inquire-1.1.0.tgz", - "integrity": "sha1-/yAOPnzyQp4tyvwRQIKOjMY48Ik=", + "integrity": "sha512-kdSefcPdruJiFMVSbn801t4vFK7KB/5gd2fYvrxhuJYg8ILrmn9SKSX2tZdV6V+ksulWqS7aXjBcRXl3wHoD9Q==", "dev": true }, "node_modules/@protobufjs/path": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/@protobufjs/path/-/path-1.1.2.tgz", - "integrity": "sha1-bMKyDFya1q0NzP0hynZz2Nf79o0=", + "integrity": "sha512-6JOcJ5Tm08dOHAbdR3GrvP+yUUfkjG5ePsHYczMFLq3ZmMkAD98cDgcT2iA1lJ9NVwFd4tH/iSSoe44YWkltEA==", "dev": true }, "node_modules/@protobufjs/pool": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/@protobufjs/pool/-/pool-1.1.0.tgz", - "integrity": "sha1-Cf0V8tbTq/qbZbw2ZQbWrXhG/1Q=", + "integrity": "sha512-0kELaGSIDBKvcgS4zkjz1PeddatrjYcmMWOlAuAPwAeccUrPHdUqo/J6LiymHHEiJT5NrF1UVwxY14f+fy4WQw==", "dev": true }, "node_modules/@protobufjs/utf8": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/@protobufjs/utf8/-/utf8-1.1.0.tgz", - "integrity": "sha1-p3c2C1s5oaLlEG+OhY8v0tBgxXA=", + "integrity": "sha512-Vvn3zZrhQZkkBE8LSuW3em98c0FwgO4nxzv6OdSxPKJIEKY2bGbHn+mhGIPerzI4twdxaP8/0+06HBpwf345Lw==", + "dev": true + }, + "node_modules/@redis/bloom": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/@redis/bloom/-/bloom-1.0.2.tgz", + "integrity": "sha512-EBw7Ag1hPgFzdznK2PBblc1kdlj5B5Cw3XwI9/oG7tSn85/HKy3X9xHy/8tm/eNXJYHLXHJL/pkwBpFMVVefkw==", + "dev": true, + "peerDependencies": { + "@redis/client": "^1.0.0" + } + }, + "node_modules/@redis/client": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/@redis/client/-/client-1.3.0.tgz", + "integrity": "sha512-XCFV60nloXAefDsPnYMjHGtvbtHR8fV5Om8cQ0JYqTNbWcQo/4AryzJ2luRj4blveWazRK/j40gES8M7Cp6cfQ==", + "dev": true, + "dependencies": { + "cluster-key-slot": "1.1.0", + "generic-pool": "3.8.2", + "yallist": "4.0.0" + }, + "engines": { + "node": ">=14" + } + }, + "node_modules/@redis/client/node_modules/generic-pool": { + "version": "3.8.2", + "resolved": "https://registry.npmjs.org/generic-pool/-/generic-pool-3.8.2.tgz", + "integrity": "sha512-nGToKy6p3PAbYQ7p1UlWl6vSPwfwU6TMSWK7TTu+WUY4ZjyZQGniGGt2oNVvyNSpyZYSB43zMXVLcBm08MTMkg==", + "dev": true, + "engines": { + "node": ">= 4" + } + }, + "node_modules/@redis/client/node_modules/yallist": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", "dev": true }, + "node_modules/@redis/graph": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@redis/graph/-/graph-1.0.1.tgz", + "integrity": "sha512-oDE4myMCJOCVKYMygEMWuriBgqlS5FqdWerikMoJxzmmTUErnTRRgmIDa2VcgytACZMFqpAOWDzops4DOlnkfQ==", + "dev": true, + "peerDependencies": { + "@redis/client": "^1.0.0" + } + }, + "node_modules/@redis/json": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/@redis/json/-/json-1.0.4.tgz", + "integrity": "sha512-LUZE2Gdrhg0Rx7AN+cZkb1e6HjoSKaeeW8rYnt89Tly13GBI5eP4CwDVr+MY8BAYfCg4/N15OUrtLoona9uSgw==", + "dev": true, + "peerDependencies": { + "@redis/client": "^1.0.0" + } + }, + "node_modules/@redis/search": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@redis/search/-/search-1.1.0.tgz", + "integrity": "sha512-NyFZEVnxIJEybpy+YskjgOJRNsfTYqaPbK/Buv6W2kmFNaRk85JiqjJZA5QkRmWvGbyQYwoO5QfDi2wHskKrQQ==", + "dev": true, + "peerDependencies": { + "@redis/client": "^1.0.0" + } + }, + "node_modules/@redis/time-series": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/@redis/time-series/-/time-series-1.0.3.tgz", + "integrity": "sha512-OFp0q4SGrTH0Mruf6oFsHGea58u8vS/iI5+NpYdicaM+7BgqBZH8FFvNZ8rYYLrUO/QRqMq72NpXmxLVNcdmjA==", + "dev": true, + "peerDependencies": { + "@redis/client": "^1.0.0" + } + }, "node_modules/@sideway/address": { "version": "4.1.4", "resolved": "https://registry.npmjs.org/@sideway/address/-/address-4.1.4.tgz", @@ -3177,9 +3538,9 @@ } }, "node_modules/@sideway/formula": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/@sideway/formula/-/formula-3.0.0.tgz", - "integrity": "sha512-vHe7wZ4NOXVfkoRb8T5otiENVlT7a3IAiw7H5M2+GO+9CDgcVUUsX1zalAztCmwyOr2RUTGJdgB+ZvSVqmdHmg==", + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/@sideway/formula/-/formula-3.0.1.tgz", + "integrity": "sha512-/poHZJJVjx3L+zVD6g9KgHfYnb443oi7wLu/XKojDviHy6HOEOA6z1Trk5aR1dGcmPenJEgb2sK2I80LeS3MIg==", "dev": true }, "node_modules/@sideway/pinpoint": { @@ -3277,9 +3638,9 @@ } }, "node_modules/@types/express": { - "version": "4.17.13", - "resolved": "https://registry.npmjs.org/@types/express/-/express-4.17.13.tgz", - "integrity": "sha512-6bSZTPaTIACxn48l50SR+axgrqm6qXFIxrdAKaG6PaJk3+zuUr35hBlgT7vOmJcum+OEaIBLtHV/qloEAFITeA==", + "version": "4.17.14", + "resolved": "https://registry.npmjs.org/@types/express/-/express-4.17.14.tgz", + "integrity": "sha512-TEbt+vaPFQ+xpxFLFssxUDXj5cWCxZJjIcB7Yg0k0GMHGtgtQgpvx/MUQUeAkNbA9AAGrwkAsoeItdTgS7FMyg==", "dev": true, "dependencies": { "@types/body-parser": "*", @@ -3289,9 +3650,9 @@ } }, "node_modules/@types/express-serve-static-core": { - "version": "4.17.28", - "resolved": "https://registry.npmjs.org/@types/express-serve-static-core/-/express-serve-static-core-4.17.28.tgz", - "integrity": "sha512-P1BJAEAW3E2DJUlkgq4tOL3RyMunoWXqbSCygWo5ZIWTjUgN1YnaXWW4VWl/oc8vs/XoYibEGBKP0uZyF4AHig==", + "version": "4.17.31", + "resolved": "https://registry.npmjs.org/@types/express-serve-static-core/-/express-serve-static-core-4.17.31.tgz", + "integrity": "sha512-DxMhY+NAsTwMMFHBTtJFNp5qiHKJ7TeqOo23zVEM9alT1Ml27Q3xcTH0xwxn7Q0BbMcVEJOs/7aQtUWupUQN3Q==", "dev": true, "dependencies": { "@types/node": "*", @@ -3367,9 +3728,9 @@ "dev": true }, "node_modules/@types/mime": { - "version": "1.3.2", - "resolved": "https://registry.npmjs.org/@types/mime/-/mime-1.3.2.tgz", - "integrity": "sha512-YATxVxgRqNH6nHEIsvg6k2Boc1JHI9ZbH5iWFFv/MTkchz3b1ieGDa5T0a9RznNdI0KhVbdbWSN+KWWrQZRxTw==", + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/@types/mime/-/mime-3.0.1.tgz", + "integrity": "sha512-Y4XFY5VJAuw0FgAqPNd6NNoV44jbq9Bz2L7Rh/J6jLTiHBSBJa9fxqQIvkIld4GsoDOcCbvzOUAbLPsSKKg+uA==", "dev": true }, "node_modules/@types/minimatch": { @@ -3379,9 +3740,9 @@ "dev": true }, "node_modules/@types/node": { - "version": "18.0.3", - "resolved": "https://registry.npmjs.org/@types/node/-/node-18.0.3.tgz", - "integrity": "sha512-HzNRZtp4eepNitP+BD6k2L6DROIDG4Q0fm4x+dwfsr6LGmROENnok75VGw40628xf+iR24WeMFcHuuBDUAzzsQ==", + "version": "18.11.9", + "resolved": "https://registry.npmjs.org/@types/node/-/node-18.11.9.tgz", + "integrity": "sha512-CRpX21/kGdzjOpFsZSkcrXMGIBWMGNIHXXBVFSH+ggkftxg+XYP20TESbh+zFvFj3EQOl5byk0HTRn1IL6hbqg==", "dev": true }, "node_modules/@types/node-fetch": { @@ -3470,12 +3831,12 @@ } }, "node_modules/@types/serve-static": { - "version": "1.13.10", - "resolved": "https://registry.npmjs.org/@types/serve-static/-/serve-static-1.13.10.tgz", - "integrity": "sha512-nCkHGI4w7ZgAdNkrEu0bv+4xNV/XDqW+DydknebMOQwkpDGx8G+HTlj7R7ABI8i8nKxVw0wtKPi1D+lPOkh4YQ==", + "version": "1.15.0", + "resolved": "https://registry.npmjs.org/@types/serve-static/-/serve-static-1.15.0.tgz", + "integrity": "sha512-z5xyF6uh8CbjAu9760KDKsH2FcDxZ2tFCsA4HIMWE6IkiYMXfVoa+4f9KX+FN0ZLsaMw1WNG2ETLA6N+/YA+cg==", "dev": true, "dependencies": { - "@types/mime": "^1", + "@types/mime": "*", "@types/node": "*" } }, @@ -3489,21 +3850,33 @@ } }, "node_modules/@types/webidl-conversions": { - "version": "6.1.1", - "resolved": "https://registry.npmjs.org/@types/webidl-conversions/-/webidl-conversions-6.1.1.tgz", - "integrity": "sha512-XAahCdThVuCFDQLT7R7Pk/vqeObFNL3YqRyFZg+AqAP/W1/w3xHaIxuW7WszQqTbIBOPRcItYJIou3i/mppu3Q==", + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/@types/webidl-conversions/-/webidl-conversions-7.0.0.tgz", + "integrity": "sha512-xTE1E+YF4aWPJJeUzaZI5DRntlkY3+BCVJi0axFptnjGmAoWxkyREIh/XMrfxVLejwQxMCfDXdICo0VLxThrog==", "dev": true }, "node_modules/@types/whatwg-url": { - "version": "8.2.1", - "resolved": "https://registry.npmjs.org/@types/whatwg-url/-/whatwg-url-8.2.1.tgz", - "integrity": "sha512-2YubE1sjj5ifxievI5Ge1sckb9k/Er66HyR2c+3+I6VDUUg1TLPdYYTEbQ+DjRkS4nTxMJhgWfSfMRD2sl2EYQ==", + "version": "8.2.2", + "resolved": "https://registry.npmjs.org/@types/whatwg-url/-/whatwg-url-8.2.2.tgz", + "integrity": "sha512-FtQu10RWgn3D9U4aazdwIE2yzphmTJREDqNdODHrbrZmmMqI0vMheC/6NE/J1Yveaj8H+ela+YwWTjq5PGmuhA==", "dev": true, "dependencies": { "@types/node": "*", "@types/webidl-conversions": "*" } }, + "node_modules/abort-controller": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/abort-controller/-/abort-controller-3.0.0.tgz", + "integrity": "sha512-h8lQ8tacZYnR3vNQTgibj+tODHI5/+l06Au2Pcriv/Gmet0eaj4TwWH41sO9wnHDiQsEj19q0drzdWdeAHtweg==", + "dev": true, + "dependencies": { + "event-target-shim": "^5.0.0" + }, + "engines": { + "node": ">=6.5" + } + }, "node_modules/abstract-logging": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/abstract-logging/-/abstract-logging-2.0.1.tgz", @@ -3617,13 +3990,14 @@ } }, "node_modules/ajv": { - "version": "6.12.6", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", - "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", + "version": "7.2.4", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-7.2.4.tgz", + "integrity": "sha512-nBeQgg/ZZA3u3SYxyaDvpvDtgZ/EZPF547ARgZBrG9Bhu1vKDwAIjtIf+sDtJUKa2zOcEbmRLBRSyMraS/Oy1A==", + "dev": true, "dependencies": { "fast-deep-equal": "^3.1.1", - "fast-json-stable-stringify": "^2.0.0", - "json-schema-traverse": "^0.4.1", + "json-schema-traverse": "^1.0.0", + "require-from-string": "^2.0.2", "uri-js": "^4.2.2" }, "funding": { @@ -3664,12 +4038,6 @@ "url": "https://github.com/sponsors/epoberezkin" } }, - "node_modules/ajv-formats/node_modules/json-schema-traverse": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", - "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==", - "dev": true - }, "node_modules/ansi-diff-stream": { "version": "1.2.1", "resolved": "https://registry.npmjs.org/ansi-diff-stream/-/ansi-diff-stream-1.2.1.tgz", @@ -3756,12 +4124,12 @@ } }, "node_modules/apollo-datasource": { - "version": "3.3.1", - "resolved": "https://registry.npmjs.org/apollo-datasource/-/apollo-datasource-3.3.1.tgz", - "integrity": "sha512-Z3a8rEUXVPIZ1p8xrFL8bcNhWmhOmovgDArvwIwmJOBnh093ZpRfO+ESJEDAN4KswmyzCLDAwjsW4zQOONdRUw==", + "version": "3.3.2", + "resolved": "https://registry.npmjs.org/apollo-datasource/-/apollo-datasource-3.3.2.tgz", + "integrity": "sha512-L5TiS8E2Hn/Yz7SSnWIVbZw0ZfEIXZCa5VUiVxD9P53JvSrf4aStvsFDlGWPvpIdCR+aly2CfoB79B9/JjKFqg==", "dev": true, "dependencies": { - "apollo-server-caching": "^3.3.0", + "@apollo/utils.keyvaluecache": "^1.0.1", "apollo-server-env": "^4.2.1" }, "engines": { @@ -3769,53 +4137,42 @@ } }, "node_modules/apollo-reporting-protobuf": { - "version": "3.3.1", - "resolved": "https://registry.npmjs.org/apollo-reporting-protobuf/-/apollo-reporting-protobuf-3.3.1.tgz", - "integrity": "sha512-tyvj3Vj71TCh6c8PtdHOLgHHBSJ05DF/A/Po3q8yfHTBkOPcOJZE/GGN/PT/pwKg7HHxKcAeHDw7+xciVvGx0w==", + "version": "3.3.3", + "resolved": "https://registry.npmjs.org/apollo-reporting-protobuf/-/apollo-reporting-protobuf-3.3.3.tgz", + "integrity": "sha512-L3+DdClhLMaRZWVmMbBcwl4Ic77CnEBPXLW53F7hkYhkaZD88ivbCVB1w/x5gunO6ZHrdzhjq0FHmTsBvPo7aQ==", "dev": true, "dependencies": { - "@apollo/protobufjs": "1.2.2" - } - }, - "node_modules/apollo-server-caching": { - "version": "3.3.0", - "resolved": "https://registry.npmjs.org/apollo-server-caching/-/apollo-server-caching-3.3.0.tgz", - "integrity": "sha512-Wgcb0ArjZ5DjQ7ID+tvxUcZ7Yxdbk5l1MxZL8D8gkyjooOkhPNzjRVQ7ubPoXqO54PrOMOTm1ejVhsF+AfIirQ==", - "dev": true, - "dependencies": { - "lru-cache": "^6.0.0" - }, - "engines": { - "node": ">=12.0" + "@apollo/protobufjs": "1.2.6" } }, "node_modules/apollo-server-core": { - "version": "3.7.0", - "resolved": "https://registry.npmjs.org/apollo-server-core/-/apollo-server-core-3.7.0.tgz", - "integrity": "sha512-xUCDjrBzPVbttbh/HenuQdivco/dcXE2oIDYwCU6FU2RBXqxWFmuCl2Xe7VPA/5Frw/4snJDLCyVte9PA5edww==", + "version": "3.11.1", + "resolved": "https://registry.npmjs.org/apollo-server-core/-/apollo-server-core-3.11.1.tgz", + "integrity": "sha512-t/eCKrRFK1lYZlc5pHD99iG7Np7CEm3SmbDiONA7fckR3EaB/pdsEdIkIwQ5QBBpT5JLp/nwvrZRVwhaWmaRvw==", "dev": true, "dependencies": { + "@apollo/utils.keyvaluecache": "^1.0.1", "@apollo/utils.logger": "^1.0.0", + "@apollo/utils.usagereporting": "^1.0.0", "@apollographql/apollo-tools": "^0.5.3", "@apollographql/graphql-playground-html": "1.6.29", "@graphql-tools/mock": "^8.1.2", "@graphql-tools/schema": "^8.0.0", "@josephg/resolvable": "^1.0.0", - "apollo-datasource": "^3.3.1", - "apollo-reporting-protobuf": "^3.3.1", - "apollo-server-caching": "^3.3.0", + "apollo-datasource": "^3.3.2", + "apollo-reporting-protobuf": "^3.3.3", "apollo-server-env": "^4.2.1", "apollo-server-errors": "^3.3.1", - "apollo-server-plugin-base": "^3.5.3", - "apollo-server-types": "^3.5.3", + "apollo-server-plugin-base": "^3.7.1", + "apollo-server-types": "^3.7.1", "async-retry": "^1.2.1", "fast-json-stable-stringify": "^2.1.0", "graphql-tag": "^2.11.0", - "lodash.sortby": "^4.7.0", "loglevel": "^1.6.8", "lru-cache": "^6.0.0", + "node-abort-controller": "^3.0.1", "sha.js": "^2.4.11", - "uuid": "^8.0.0", + "uuid": "^9.0.0", "whatwg-mimetype": "^3.0.0" }, "engines": { @@ -3825,6 +4182,15 @@ "graphql": "^15.3.0 || ^16.0.0" } }, + "node_modules/apollo-server-core/node_modules/uuid": { + "version": "9.0.0", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-9.0.0.tgz", + "integrity": "sha512-MXcSTerfPa4uqyzStbRoTgt5XIe3x5+42+q1sDuy3R5MDk66URdLMOZe5aPX/SQd+kuYAh0FdP/pO28IkQyTeg==", + "dev": true, + "bin": { + "uuid": "dist/bin/uuid" + } + }, "node_modules/apollo-server-env": { "version": "4.2.1", "resolved": "https://registry.npmjs.org/apollo-server-env/-/apollo-server-env-4.2.1.tgz", @@ -3850,19 +4216,19 @@ } }, "node_modules/apollo-server-express": { - "version": "3.7.0", - "resolved": "https://registry.npmjs.org/apollo-server-express/-/apollo-server-express-3.7.0.tgz", - "integrity": "sha512-176LSK7YBxwfleurtbfr5SYMheNNJSHrQa2h4QuosLqhfFJkfTpI2iBW56N737U47QfyueCOvkjNZVq86e3n2g==", + "version": "3.11.1", + "resolved": "https://registry.npmjs.org/apollo-server-express/-/apollo-server-express-3.11.1.tgz", + "integrity": "sha512-x9ngcpXbBlt4naCXTwNtBFb/mOd9OU0wtFXvJkObHF26NsRazu3DxDfEuekA6V1NFOocD+A9jmVMQeQWug5MgA==", "dev": true, "dependencies": { "@types/accepts": "^1.3.5", "@types/body-parser": "1.19.2", "@types/cors": "2.8.12", - "@types/express": "4.17.13", - "@types/express-serve-static-core": "4.17.28", + "@types/express": "4.17.14", + "@types/express-serve-static-core": "4.17.31", "accepts": "^1.3.5", - "apollo-server-core": "^3.7.0", - "apollo-server-types": "^3.5.3", + "apollo-server-core": "^3.11.1", + "apollo-server-types": "^3.7.1", "body-parser": "^1.19.0", "cors": "^2.8.5", "parseurl": "^1.3.3" @@ -3876,12 +4242,12 @@ } }, "node_modules/apollo-server-plugin-base": { - "version": "3.5.3", - "resolved": "https://registry.npmjs.org/apollo-server-plugin-base/-/apollo-server-plugin-base-3.5.3.tgz", - "integrity": "sha512-zojm3qiUGYtM5k1PPrCJnLZSDNqvWvmIDvqBjCu3wI3iNZqNm3MOA86eYGFfaBi/WNu3qYIj6QE3T7w0XjRV1A==", + "version": "3.7.1", + "resolved": "https://registry.npmjs.org/apollo-server-plugin-base/-/apollo-server-plugin-base-3.7.1.tgz", + "integrity": "sha512-g3vJStmQtQvjGI289UkLMfThmOEOddpVgHLHT2bNj0sCD/bbisj4xKbBHETqaURokteqSWyyd4RDTUe0wAUDNQ==", "dev": true, "dependencies": { - "apollo-server-types": "^3.5.3" + "apollo-server-types": "^3.7.1" }, "engines": { "node": ">=12.0" @@ -3891,13 +4257,14 @@ } }, "node_modules/apollo-server-types": { - "version": "3.5.3", - "resolved": "https://registry.npmjs.org/apollo-server-types/-/apollo-server-types-3.5.3.tgz", - "integrity": "sha512-Qf5mMVTDyABEeyjGecwMsk0y0km4KuW8/j/UwBDQkAAW1QRy+w8nqi+wvSoA5hNXiYCdJN4U4nxTxm9+2eiT4w==", + "version": "3.7.1", + "resolved": "https://registry.npmjs.org/apollo-server-types/-/apollo-server-types-3.7.1.tgz", + "integrity": "sha512-aE9RDVplmkaOj/OduNmGa+0a1B5RIWI0o3zC1zLvBTVWMKTpo0ifVf11TyMkLCY+T7cnZqVqwyShziOyC3FyUw==", "dev": true, "dependencies": { - "apollo-reporting-protobuf": "^3.3.1", - "apollo-server-caching": "^3.3.0", + "@apollo/utils.keyvaluecache": "^1.0.1", + "@apollo/utils.logger": "^1.0.0", + "apollo-reporting-protobuf": "^3.3.3", "apollo-server-env": "^4.2.1" }, "engines": { @@ -3934,42 +4301,6 @@ "sprintf-js": "~1.0.2" } }, - "node_modules/arr-diff": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/arr-diff/-/arr-diff-4.0.0.tgz", - "integrity": "sha1-1kYQdP6/7HHn4VI1dhoyml3HxSA=", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/arr-flatten": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/arr-flatten/-/arr-flatten-1.1.0.tgz", - "integrity": "sha512-L3hKV5R/p5o81R7O02IGnwpDmkp6E982XhtbuwSe3O4qOtMMMtodicASA1Cny2U+aCXcNpml+m4dPsvsJ3jatg==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/arr-union": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/arr-union/-/arr-union-3.1.0.tgz", - "integrity": "sha1-45sJrqne+Gao8gbiiK9jkZuuOcQ=", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/array-each": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/array-each/-/array-each-1.0.1.tgz", - "integrity": "sha1-p5SvDAWrF1KEbudTofIRoFugxE8=", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/array-flatten": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-1.1.1.tgz", @@ -3995,15 +4326,6 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/array-slice": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/array-slice/-/array-slice-1.1.0.tgz", - "integrity": "sha512-B1qMD3RBP7O8o0H2KbrXDyB0IccejMF15+87Lvlor12ONPRHP6gTjXMNkt/d3ZuOGbAe66hFmaCfECI24Ufp6w==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/array-union": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/array-union/-/array-union-2.1.0.tgz", @@ -4013,15 +4335,6 @@ "node": ">=8" } }, - "node_modules/array-unique": { - "version": "0.3.2", - "resolved": "https://registry.npmjs.org/array-unique/-/array-unique-0.3.2.tgz", - "integrity": "sha1-qJS3XUvE9s1nnvMkSp/Y9Gri1Cg=", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/array.prototype.every": { "version": "1.1.3", "resolved": "https://registry.npmjs.org/array.prototype.every/-/array.prototype.every-1.1.3.tgz", @@ -4082,15 +4395,6 @@ "node": ">=0.8" } }, - "node_modules/assign-symbols": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/assign-symbols/-/assign-symbols-1.0.0.tgz", - "integrity": "sha1-WWZ/QfrdTyDMvCu5a41Pf3jsA2c=", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/astral-regex": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/astral-regex/-/astral-regex-1.0.0.tgz", @@ -4152,18 +4456,6 @@ "integrity": "sha1-x57Zf380y48robyXkLzDZkdLS3k=", "dev": true }, - "node_modules/atob": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/atob/-/atob-2.1.2.tgz", - "integrity": "sha512-Wm6ukoaOGJi/73p/cl2GvLjTI5JM1k/O14isD73YML8StrH/7/lRFgmg8nICZgD3bZZvjwCGxtMOD3wWNAu8cg==", - "dev": true, - "bin": { - "atob": "bin/atob.js" - }, - "engines": { - "node": ">= 4.5.0" - } - }, "node_modules/atomic-sleep": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/atomic-sleep/-/atomic-sleep-1.0.0.tgz", @@ -4185,15 +4477,14 @@ } }, "node_modules/avvio": { - "version": "8.1.3", - "resolved": "https://registry.npmjs.org/avvio/-/avvio-8.1.3.tgz", - "integrity": "sha512-tl9TC0yDRKzP6gFLkrInqPyx8AkfBC/0QRnwkE9Jo31+OJjLrE/73GJuE0QgSB0Vpv38CTJJZGqU9hczowclWw==", + "version": "8.2.0", + "resolved": "https://registry.npmjs.org/avvio/-/avvio-8.2.0.tgz", + "integrity": "sha512-bbCQdg7bpEv6kGH41RO/3B2/GMMmJSo2iBK+X8AWN9mujtfUipMDfIjsgHCfpnKqoGEQrrmCDKSa5OQ19+fDmg==", "dev": true, "dependencies": { "archy": "^1.0.0", "debug": "^4.0.0", - "fastq": "^1.6.1", - "queue-microtask": "^1.1.2" + "fastq": "^1.6.1" } }, "node_modules/aws-sdk": { @@ -4250,23 +4541,14 @@ "follow-redirects": "^1.14.0" } }, - "node_modules/babel-plugin-dynamic-import-node": { - "version": "2.3.3", - "resolved": "https://registry.npmjs.org/babel-plugin-dynamic-import-node/-/babel-plugin-dynamic-import-node-2.3.3.tgz", - "integrity": "sha512-jZVI+s9Zg3IqA/kdi0i6UDCybUI3aSBLnglhYbSSjKlV7yF1F/5LWv8MakQmvYpnbJDS6fcBL2KzHSxNCMtWSQ==", - "dev": true, - "dependencies": { - "object.assign": "^4.1.0" - } - }, "node_modules/babel-plugin-polyfill-corejs2": { - "version": "0.3.1", - "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-corejs2/-/babel-plugin-polyfill-corejs2-0.3.1.tgz", - "integrity": "sha512-v7/T6EQcNfVLfcN2X8Lulb7DjprieyLWJK/zOWH5DUYcAgex9sP3h25Q+DLsX9TloXe3y1O8l2q2Jv9q8UVB9w==", + "version": "0.3.3", + "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-corejs2/-/babel-plugin-polyfill-corejs2-0.3.3.tgz", + "integrity": "sha512-8hOdmFYFSZhqg2C/JgLUQ+t52o5nirNwaWM2B9LWteozwIvM14VSwdsCAUET10qT+kmySAlseadmfeeSWFCy+Q==", "dev": true, "dependencies": { - "@babel/compat-data": "^7.13.11", - "@babel/helper-define-polyfill-provider": "^0.3.1", + "@babel/compat-data": "^7.17.7", + "@babel/helper-define-polyfill-provider": "^0.3.3", "semver": "^6.1.1" }, "peerDependencies": { @@ -4274,25 +4556,25 @@ } }, "node_modules/babel-plugin-polyfill-corejs3": { - "version": "0.5.2", - "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-corejs3/-/babel-plugin-polyfill-corejs3-0.5.2.tgz", - "integrity": "sha512-G3uJih0XWiID451fpeFaYGVuxHEjzKTHtc9uGFEjR6hHrvNzeS/PX+LLLcetJcytsB5m4j+K3o/EpXJNb/5IEQ==", + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-corejs3/-/babel-plugin-polyfill-corejs3-0.6.0.tgz", + "integrity": "sha512-+eHqR6OPcBhJOGgsIar7xoAB1GcSwVUA3XjAd7HJNzOXT4wv6/H7KIdA/Nc60cvUlDbKApmqNvD1B1bzOt4nyA==", "dev": true, "dependencies": { - "@babel/helper-define-polyfill-provider": "^0.3.1", - "core-js-compat": "^3.21.0" + "@babel/helper-define-polyfill-provider": "^0.3.3", + "core-js-compat": "^3.25.1" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "node_modules/babel-plugin-polyfill-regenerator": { - "version": "0.3.1", - "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-regenerator/-/babel-plugin-polyfill-regenerator-0.3.1.tgz", - "integrity": "sha512-Y2B06tvgHYt1x0yz17jGkGeeMr5FeKUu+ASJ+N6nB5lQ8Dapfg42i0OVrf8PNGJ3zKL4A23snMi1IRwrqqND7A==", + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-regenerator/-/babel-plugin-polyfill-regenerator-0.4.1.tgz", + "integrity": "sha512-NtQGmyQDXjQqQ+IzRkBVwEOz9lQ4zxAQZgoAYEtU9dJjnl1Oc98qnN7jcp+bE7O7aYzVpavXE3/VKXNzUbh7aw==", "dev": true, "dependencies": { - "@babel/helper-define-polyfill-provider": "^0.3.1" + "@babel/helper-define-polyfill-provider": "^0.3.3" }, "peerDependencies": { "@babel/core": "^7.0.0-0" @@ -4427,83 +4709,6 @@ "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", "dev": true }, - "node_modules/base": { - "version": "0.11.2", - "resolved": "https://registry.npmjs.org/base/-/base-0.11.2.tgz", - "integrity": "sha512-5T6P4xPgpp0YDFvSWwEZ4NoE3aM4QBQXDzmVbraCkFj8zHM+mba8SyqB5DbZWyR7mYHo6Y7BdQo3MoA4m0TeQg==", - "dev": true, - "dependencies": { - "cache-base": "^1.0.1", - "class-utils": "^0.3.5", - "component-emitter": "^1.2.1", - "define-property": "^1.0.0", - "isobject": "^3.0.1", - "mixin-deep": "^1.2.0", - "pascalcase": "^0.1.1" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/base/node_modules/define-property": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/define-property/-/define-property-1.0.0.tgz", - "integrity": "sha1-dp66rz9KY6rTr56NMEybvnm/sOY=", - "dev": true, - "dependencies": { - "is-descriptor": "^1.0.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/base/node_modules/is-accessor-descriptor": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz", - "integrity": "sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ==", - "dev": true, - "dependencies": { - "kind-of": "^6.0.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/base/node_modules/is-data-descriptor": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz", - "integrity": "sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ==", - "dev": true, - "dependencies": { - "kind-of": "^6.0.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/base/node_modules/is-descriptor": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.2.tgz", - "integrity": "sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg==", - "dev": true, - "dependencies": { - "is-accessor-descriptor": "^1.0.0", - "is-data-descriptor": "^1.0.0", - "kind-of": "^6.0.2" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/base/node_modules/kind-of": { - "version": "6.0.3", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.3.tgz", - "integrity": "sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/base64-js": { "version": "1.5.1", "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz", @@ -4626,9 +4831,9 @@ "dev": true }, "node_modules/body-parser": { - "version": "1.20.0", - "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.20.0.tgz", - "integrity": "sha512-DfJ+q6EPcGKZD1QWUjSpqp+Q7bDQTsQIF4zfUAtZ6qk+H/3/QRhg9CEp39ss+/T2vw0+HaidC0ecJj/DRLIaKg==", + "version": "1.20.1", + "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.20.1.tgz", + "integrity": "sha512-jWi7abTbYwajOytWCQc37VulmWiRae5RyTpaCyDcS5/lMdtwSz5lOpDE67srw/HYe35f1z3fDQw+3txg7gNtWw==", "dev": true, "dependencies": { "bytes": "3.1.2", @@ -4639,7 +4844,7 @@ "http-errors": "2.0.0", "iconv-lite": "0.4.24", "on-finished": "2.4.1", - "qs": "6.10.3", + "qs": "6.11.0", "raw-body": "2.5.1", "type-is": "~1.6.18", "unpipe": "1.0.0" @@ -4729,9 +4934,9 @@ } }, "node_modules/browserslist": { - "version": "4.20.3", - "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.20.3.tgz", - "integrity": "sha512-NBhymBQl1zM0Y5dQT/O+xiLP9/rzOIQdKM/eMJBAq7yBgaB6krIYLGejrwVYnSHZdqjscB1SPuAjHwxjvN6Wdg==", + "version": "4.21.4", + "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.21.4.tgz", + "integrity": "sha512-CBHJJdDmgjl3daYjN5Cp5kbTf1mUhZoS+beLklHIvkOWscs83YAhLlF3Wsh/lciQYAcbBJgTOD44VtG31ZM4Hw==", "dev": true, "funding": [ { @@ -4744,11 +4949,10 @@ } ], "dependencies": { - "caniuse-lite": "^1.0.30001332", - "electron-to-chromium": "^1.4.118", - "escalade": "^3.1.1", - "node-releases": "^2.0.3", - "picocolors": "^1.0.0" + "caniuse-lite": "^1.0.30001400", + "electron-to-chromium": "^1.4.251", + "node-releases": "^2.0.6", + "update-browserslist-db": "^1.0.9" }, "bin": { "browserslist": "cli.js" @@ -4758,9 +4962,9 @@ } }, "node_modules/bson": { - "version": "4.6.3", - "resolved": "https://registry.npmjs.org/bson/-/bson-4.6.3.tgz", - "integrity": "sha512-rAqP5hcUVJhXP2MCSNVsf0oM2OGU1So6A9pVRDYayvJ5+hygXHQApf87wd5NlhPM1J9RJnbqxIG/f8QTzRoQ4A==", + "version": "4.7.0", + "resolved": "https://registry.npmjs.org/bson/-/bson-4.7.0.tgz", + "integrity": "sha512-VrlEE4vuiO1WTpfof4VmaVolCVYkYTgB9iWgYNOrVlnifpME/06fhFRmONgBhClD5pFC1t9ZWqFUQEQAzY43bA==", "dev": true, "dependencies": { "buffer": "^5.6.0" @@ -4825,22 +5029,16 @@ "node": ">=4" } }, - "node_modules/bunyan": { - "version": "1.8.15", - "resolved": "https://registry.npmjs.org/bunyan/-/bunyan-1.8.15.tgz", - "integrity": "sha512-0tECWShh6wUysgucJcBAoYegf3JJoZWibxdqhTm7OHPeT42qdjkZ29QCMcKwbgU1kiH+auSIasNRXMLWXafXig==", + "node_modules/busboy": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/busboy/-/busboy-1.6.0.tgz", + "integrity": "sha512-8SFQbg/0hQ9xy3UNTB0YEnsNBbWfhf7RtnzpL7TkBiTBRfrQ9Fxcnz7VJsleJpyp6rVLvXiuORqjlHi5q+PYuA==", "dev": true, - "engines": [ - "node >=0.10.0" - ], - "bin": { - "bunyan": "bin/bunyan" + "dependencies": { + "streamsearch": "^1.1.0" }, - "optionalDependencies": { - "dtrace-provider": "~0.8", - "moment": "^2.19.3", - "mv": "~2", - "safe-json-stringify": "~1" + "engines": { + "node": ">=10.16.0" } }, "node_modules/bytes": { @@ -4852,26 +5050,6 @@ "node": ">= 0.8" } }, - "node_modules/cache-base": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/cache-base/-/cache-base-1.0.1.tgz", - "integrity": "sha512-AKcdTnFSWATd5/GCPRxr2ChwIJ85CeyrEyjRHlKxQ56d4XJMGym0uAiKn0xbLOGOl3+yRpOTi484dVCEc5AUzQ==", - "dev": true, - "dependencies": { - "collection-visit": "^1.0.0", - "component-emitter": "^1.2.1", - "get-value": "^2.0.6", - "has-value": "^1.0.0", - "isobject": "^3.0.1", - "set-value": "^2.0.0", - "to-object-path": "^0.3.0", - "union-value": "^1.0.0", - "unset-value": "^1.0.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/cache-content-type": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/cache-content-type/-/cache-content-type-1.0.1.tgz", @@ -4964,9 +5142,9 @@ } }, "node_modules/caniuse-lite": { - "version": "1.0.30001338", - "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001338.tgz", - "integrity": "sha512-1gLHWyfVoRDsHieO+CaeYe7jSo/MT7D7lhaXUiwwbuR5BwQxORs0f1tAwUSQr3YbxRXJvxHM/PA5FfPQRnsPeQ==", + "version": "1.0.30001406", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001406.tgz", + "integrity": "sha512-bWTlaXUy/rq0BBtYShc/jArYfBPjEV95euvZ8JVtO43oQExEN/WquoqpufFjNu4kSpi5cy5kMbNvzztWDfv1Jg==", "dev": true, "funding": [ { @@ -4986,9 +5164,9 @@ "dev": true }, "node_modules/cassandra-driver": { - "version": "4.6.3", - "resolved": "https://registry.npmjs.org/cassandra-driver/-/cassandra-driver-4.6.3.tgz", - "integrity": "sha512-npW670TXjTHrdb15LUFN01wssb9vvz6SuNYcppesoKcUXx3Q29nXVhRtnvsnkG0BaSnDGvCCR4udrzYLsbh+sg==", + "version": "4.6.4", + "resolved": "https://registry.npmjs.org/cassandra-driver/-/cassandra-driver-4.6.4.tgz", + "integrity": "sha512-SksbIK0cZ2QZRx8ti7w+PnLqldyY+6kU2gRWFChwXFTtrD/ce8cQICDEHxyPwx+DeILwRnMrPf9cjUGizYw9Vg==", "dev": true, "dependencies": { "@types/long": "^4.0.0", @@ -5072,33 +5250,6 @@ "integrity": "sha512-5tK7EtrZ0N+OLFMthtqOj4fI2Jeb88C4CAZPu25LDVUgXJ0A3Js4PMGqrn0JU1W0Mh1/Z8wZzYPxqUrXeBboCQ==", "dev": true }, - "node_modules/class-utils": { - "version": "0.3.6", - "resolved": "https://registry.npmjs.org/class-utils/-/class-utils-0.3.6.tgz", - "integrity": "sha512-qOhPa/Fj7s6TY8H8esGu5QNpMMQxz79h+urzrNYN6mn+9BnxlDGf5QZ+XeCDsxSjPqsSR56XOZOJmpeurnLMeg==", - "dev": true, - "dependencies": { - "arr-union": "^3.1.0", - "define-property": "^0.2.5", - "isobject": "^3.0.0", - "static-extend": "^0.1.1" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/class-utils/node_modules/define-property": { - "version": "0.2.5", - "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", - "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", - "dev": true, - "dependencies": { - "is-descriptor": "^0.1.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/clean-stack": { "version": "2.2.0", "resolved": "https://registry.npmjs.org/clean-stack/-/clean-stack-2.2.0.tgz", @@ -5210,19 +5361,6 @@ "type-is": "^1.6.16" } }, - "node_modules/collection-visit": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/collection-visit/-/collection-visit-1.0.0.tgz", - "integrity": "sha1-S8A3PBZLwykbTTaMgpzxqApZ3KA=", - "dev": true, - "dependencies": { - "map-visit": "^1.0.0", - "object-visit": "^1.0.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/color": { "version": "3.2.1", "resolved": "https://registry.npmjs.org/color/-/color-3.2.1.tgz", @@ -5259,9 +5397,9 @@ } }, "node_modules/colorette": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/colorette/-/colorette-1.2.1.tgz", - "integrity": "sha512-puCDz0CzydiSYOrnXpz/PKd69zRrribezjtE9yd4zvytoRc8+RY/KJPvtPFKZS3E3wP6neGyMe0vOTlHO5L3Pw==", + "version": "2.0.16", + "resolved": "https://registry.npmjs.org/colorette/-/colorette-2.0.16.tgz", + "integrity": "sha512-hUewv7oMjCp+wkBv5Rm0v87eJhq4woh5rSR+42YSQJKecCqgIqNkZ6lAlQms/BwHPJA5NKMRlpxPRv0n8HQW6g==", "dev": true }, "node_modules/colorspace": { @@ -5314,12 +5452,6 @@ "integrity": "sha1-3dgA2gxmEnOTzKWVDqloo6rxJTs=", "dev": true }, - "node_modules/component-emitter": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/component-emitter/-/component-emitter-1.3.0.tgz", - "integrity": "sha512-Rd3se6QB+sO1TwqZjscQrurpEPIfO0/yYnSin6Q/rD3mOutHvUrCAhJub3r90uNb+SESBuE0QYoB90YdfatsRg==", - "dev": true - }, "node_modules/compress-brotli": { "version": "1.3.8", "resolved": "https://registry.npmjs.org/compress-brotli/-/compress-brotli-1.3.8.tgz", @@ -5410,11 +5542,6 @@ "resolved": "https://registry.npmjs.org/console-log-level/-/console-log-level-1.4.1.tgz", "integrity": "sha512-VZzbIORbP+PPcN/gg3DXClTLPLg5Slwd5fL2MIc+o1qZ4BXBvWyc6QxPk6T/Mkr6IVjRpoAGf32XxP3ZWMVRcQ==" }, - "node_modules/container-info": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/container-info/-/container-info-1.1.0.tgz", - "integrity": "sha512-eD2zLAmxGS2kmL4f1jY8BdOqnmpL6X70kvzTBW/9FIQnxoxiBJ4htMsTmtPLPWRs7NHYFvqKQ1VtppV08mdsQA==" - }, "node_modules/content-disposition": { "version": "0.5.4", "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.4.tgz", @@ -5501,15 +5628,6 @@ "node": ">= 0.8" } }, - "node_modules/copy-descriptor": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/copy-descriptor/-/copy-descriptor-0.1.1.tgz", - "integrity": "sha1-Z29us8OZl8LuGsOpJP1hJHSPV40=", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/copy-to": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/copy-to/-/copy-to-2.0.1.tgz", @@ -5517,28 +5635,18 @@ "dev": true }, "node_modules/core-js-compat": { - "version": "3.22.4", - "resolved": "https://registry.npmjs.org/core-js-compat/-/core-js-compat-3.22.4.tgz", - "integrity": "sha512-dIWcsszDezkFZrfm1cnB4f/J85gyhiCpxbgBdohWCDtSVuAaChTSpPV7ldOQf/Xds2U5xCIJZOK82G4ZPAIswA==", + "version": "3.25.2", + "resolved": "https://registry.npmjs.org/core-js-compat/-/core-js-compat-3.25.2.tgz", + "integrity": "sha512-TxfyECD4smdn3/CjWxczVtJqVLEEC2up7/82t7vC0AzNogr+4nQ8vyF7abxAuTXWvjTClSbvGhU0RgqA4ToQaQ==", "dev": true, "dependencies": { - "browserslist": "^4.20.3", - "semver": "7.0.0" + "browserslist": "^4.21.4" }, "funding": { "type": "opencollective", "url": "https://opencollective.com/core-js" } }, - "node_modules/core-js-compat/node_modules/semver": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.0.0.tgz", - "integrity": "sha512-+GB6zVA9LWh6zovYQLALHwv5rb2PHGlJi3lfiqIHxR0uuwCgefcOJc59v9fv1w8GbStwxuuqqAjI9NMAOOgq1A==", - "dev": true, - "bin": { - "semver": "bin/semver.js" - } - }, "node_modules/core-util-is": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.3.tgz", @@ -5589,36 +5697,36 @@ "dev": true }, "node_modules/csv": { - "version": "5.5.3", - "resolved": "https://registry.npmjs.org/csv/-/csv-5.5.3.tgz", - "integrity": "sha512-QTaY0XjjhTQOdguARF0lGKm5/mEq9PD9/VhZZegHDIBq2tQwgNpHc3dneD4mGo2iJs+fTKv5Bp0fZ+BRuY3Z0g==", + "version": "6.2.5", + "resolved": "https://registry.npmjs.org/csv/-/csv-6.2.5.tgz", + "integrity": "sha512-T+K0H7MIrlrnP6KxYKo3lK+uLl6OC2Gmwdd81TG/VdkhKvpatl35sR7tyRSpDLGl22y2T+q9KvNHnVtn4OAscQ==", "dev": true, "dependencies": { - "csv-generate": "^3.4.3", - "csv-parse": "^4.16.3", - "csv-stringify": "^5.6.5", - "stream-transform": "^2.1.3" + "csv-generate": "^4.2.1", + "csv-parse": "^5.3.3", + "csv-stringify": "^6.2.3", + "stream-transform": "^3.2.1" }, "engines": { "node": ">= 0.1.90" } }, "node_modules/csv-generate": { - "version": "3.4.3", - "resolved": "https://registry.npmjs.org/csv-generate/-/csv-generate-3.4.3.tgz", - "integrity": "sha512-w/T+rqR0vwvHqWs/1ZyMDWtHHSJaN06klRqJXBEpDJaM/+dZkso0OKh1VcuuYvK3XM53KysVNq8Ko/epCK8wOw==", + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/csv-generate/-/csv-generate-4.2.1.tgz", + "integrity": "sha512-w6GFHjvApv6bcJ2xdi9JGsH6ZvUBfC+vUdfefnEzurXG6hMRwzkBLnhztU2H7v7+zfCk1I/knnQ+tGbgpxWrBw==", "dev": true }, "node_modules/csv-parse": { - "version": "4.16.3", - "resolved": "https://registry.npmjs.org/csv-parse/-/csv-parse-4.16.3.tgz", - "integrity": "sha512-cO1I/zmz4w2dcKHVvpCr7JVRu8/FymG5OEpmvsZYlccYolPBLoVGKUHgNoc4ZGkFeFlWGEDmMyBM+TTqRdW/wg==", + "version": "5.3.3", + "resolved": "https://registry.npmjs.org/csv-parse/-/csv-parse-5.3.3.tgz", + "integrity": "sha512-kEWkAPleNEdhFNkHQpFHu9RYPogsFj3dx6bCxL847fsiLgidzWg0z/O0B1kVWMJUc5ky64zGp18LX2T3DQrOfw==", "dev": true }, "node_modules/csv-stringify": { - "version": "5.6.5", - "resolved": "https://registry.npmjs.org/csv-stringify/-/csv-stringify-5.6.5.tgz", - "integrity": "sha512-PjiQ659aQ+fUTQqSrd1XEDnOr52jh30RBurfzkscaE2tPaFsDH5wOAHJiw8XAHphRknCwMUE9KRayc4K/NbO8A==", + "version": "6.2.3", + "resolved": "https://registry.npmjs.org/csv-stringify/-/csv-stringify-6.2.3.tgz", + "integrity": "sha512-4qGjUMwnlaRc00gc2jrIYh2w/h1fo25B0mTuY9K8fBiIgtmCX3LcgUbrEGViL98Ci4Se/F5LFEtu8k+dItJVZQ==", "dev": true }, "node_modules/dargs": { @@ -5670,15 +5778,6 @@ "node": ">=0.10.0" } }, - "node_modules/decode-uri-component": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/decode-uri-component/-/decode-uri-component-0.2.0.tgz", - "integrity": "sha1-6zkTMzRYd1y4TNGh+uBiEGu4dUU=", - "dev": true, - "engines": { - "node": ">=0.10" - } - }, "node_modules/decompress-response": { "version": "6.0.0", "resolved": "https://registry.npmjs.org/decompress-response/-/decompress-response-6.0.0.tgz", @@ -5804,66 +5903,6 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/define-property": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/define-property/-/define-property-2.0.2.tgz", - "integrity": "sha512-jwK2UV4cnPpbcG7+VRARKTZPUWowwXA8bzH5NP6ud0oeAxyYPuGZUAC7hMugpCdz4BeSZl2Dl9k66CHJ/46ZYQ==", - "dev": true, - "dependencies": { - "is-descriptor": "^1.0.2", - "isobject": "^3.0.1" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/define-property/node_modules/is-accessor-descriptor": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz", - "integrity": "sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ==", - "dev": true, - "dependencies": { - "kind-of": "^6.0.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/define-property/node_modules/is-data-descriptor": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz", - "integrity": "sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ==", - "dev": true, - "dependencies": { - "kind-of": "^6.0.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/define-property/node_modules/is-descriptor": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.2.tgz", - "integrity": "sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg==", - "dev": true, - "dependencies": { - "is-accessor-descriptor": "^1.0.0", - "is-data-descriptor": "^1.0.0", - "kind-of": "^6.0.2" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/define-property/node_modules/kind-of": { - "version": "6.0.3", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.3.tgz", - "integrity": "sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/defined": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/defined/-/defined-1.0.0.tgz", @@ -5916,15 +5955,6 @@ "integrity": "sha1-hMbhWbgZBP3KWaDvRM2HDTElD5o=", "dev": true }, - "node_modules/denque": { - "version": "1.5.1", - "resolved": "https://registry.npmjs.org/denque/-/denque-1.5.1.tgz", - "integrity": "sha512-XwE+iZ4D6ZUB7mfYRMb5wByE8L74HCn30FBN7sWnXksWc1LO1bPDl67pBR9o/kC4z/xSNAwkMYcGgqDV3BE3Hw==", - "dev": true, - "engines": { - "node": ">=0.10" - } - }, "node_modules/depd": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/depd/-/depd-1.1.2.tgz", @@ -6000,15 +6030,6 @@ "npm": "1.2.8000 || >= 1.4.16" } }, - "node_modules/detect-file": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/detect-file/-/detect-file-1.0.0.tgz", - "integrity": "sha1-8NZtA2cqglyxtzvbP+YjEMjlUrc=", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/detect-node": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/detect-node/-/detect-node-2.1.0.tgz", @@ -6032,6 +6053,15 @@ "node": ">=0.8.0" } }, + "node_modules/diagnostics_channel": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/diagnostics_channel/-/diagnostics_channel-1.1.0.tgz", + "integrity": "sha512-OE1ngLDjSBPG6Tx0YATELzYzy3RKHC+7veQ8gLa8yS7AAgw65mFbVdcsu3501abqOZCEZqZyAIemB0zXlqDSuw==", + "dev": true, + "engines": { + "node": ">=4" + } + }, "node_modules/dir-glob": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/dir-glob/-/dir-glob-3.0.1.tgz", @@ -6063,9 +6093,9 @@ "dev": true }, "node_modules/dotenv": { - "version": "16.0.1", - "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-16.0.1.tgz", - "integrity": "sha512-1K6hR6wtk2FviQ4kEiSjFiH5rpzEVi8WW0x96aztHVMhEspNpc4DVOUTEHtEva5VThQ8IaBX1Pe4gSzpVVUsKQ==", + "version": "16.0.3", + "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-16.0.3.tgz", + "integrity": "sha512-7GO6HghkA5fYG9TYnNxi14/7K9f5occMlp3zXAuSxn7CKCxt9xbNWG7yF8hTCSUchlfWSe3uLmlPfigevRItzQ==", "dev": true, "engines": { "node": ">=12" @@ -6097,18 +6127,6 @@ "node": ">=0.10" } }, - "node_modules/duplexify": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/duplexify/-/duplexify-4.1.2.tgz", - "integrity": "sha512-fz3OjcNCHmRP12MJoZMPglx8m4rrFP8rovnk4vT8Fs+aonZoCwGg10dSsQsfP/E62eZcPTMSMP6686fu9Qlqtw==", - "dev": true, - "dependencies": { - "end-of-stream": "^1.4.1", - "inherits": "^2.0.3", - "readable-stream": "^3.1.1", - "stream-shift": "^1.0.0" - } - }, "node_modules/ecc-jsbn": { "version": "0.1.2", "resolved": "https://registry.npmjs.org/ecc-jsbn/-/ecc-jsbn-0.1.2.tgz", @@ -6135,13 +6153,12 @@ "dev": true }, "node_modules/elastic-apm-http-client": { - "version": "11.0.1", - "resolved": "https://registry.npmjs.org/elastic-apm-http-client/-/elastic-apm-http-client-11.0.1.tgz", - "integrity": "sha512-5AOWlhs2WlZpI+DfgGqY/8Rk7KF8WeevaO8R961eBylavU6GWhLRNiJncohn5jsvrqhmeT19azBvy/oYRN7bJw==", + "version": "11.0.4", + "resolved": "https://registry.npmjs.org/elastic-apm-http-client/-/elastic-apm-http-client-11.0.4.tgz", + "integrity": "sha512-449Qj/STi9hgnIk2KQ7719E7lpM3/i4Afs7NUhSOX8wV3sxn/+ItIHx9kKJthzhDDezxIfQcH83v83AF67GspQ==", "dependencies": { "agentkeepalive": "^4.2.1", "breadth-filter": "^2.0.0", - "container-info": "^1.0.1", "end-of-stream": "^1.4.4", "fast-safe-stringify": "^2.0.7", "fast-stream-to-buffer": "^1.0.0", @@ -6246,9 +6263,9 @@ } }, "node_modules/electron-to-chromium": { - "version": "1.4.137", - "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.137.tgz", - "integrity": "sha512-0Rcpald12O11BUogJagX3HsCN3FE83DSqWjgXoHo5a72KUKMSfI39XBgJpgNNxS9fuGzytaFjE06kZkiVFy2qA==", + "version": "1.4.254", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.254.tgz", + "integrity": "sha512-Sh/7YsHqQYkA6ZHuHMy24e6TE4eX6KZVsZb9E/DvU1nQRIrH4BflO/4k+83tfdYvDl+MObvlqHPRICzEdC9c6Q==", "dev": true }, "node_modules/emoji-regex": { @@ -6717,9 +6734,9 @@ "dev": true }, "node_modules/eslint-plugin-license-header": { - "version": "0.4.0", - "resolved": "https://registry.npmjs.org/eslint-plugin-license-header/-/eslint-plugin-license-header-0.4.0.tgz", - "integrity": "sha512-KNpyxD+r8d9VoioyaHofUDsrYO+epVv/WjGZKugfO+qVN1KvHi/LwpXXY1618OCOYEaRNXZeRUtbOIb2YvJXTw==", + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/eslint-plugin-license-header/-/eslint-plugin-license-header-0.6.0.tgz", + "integrity": "sha512-IEywStBWaDBDMkogYoKUAdaOuomZ+YaQmdoSD2vHmXobekM+XuP6SWLlvwUUhIbdocn3MTlb5CUJ8E4VHz1c/w==", "dev": true, "dependencies": { "requireindex": "^1.2.0" @@ -6826,6 +6843,22 @@ "node": ">=4" } }, + "node_modules/eslint/node_modules/ajv": { + "version": "6.12.6", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", + "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", + "dev": true, + "dependencies": { + "fast-deep-equal": "^3.1.1", + "fast-json-stable-stringify": "^2.0.0", + "json-schema-traverse": "^0.4.1", + "uri-js": "^4.2.2" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, "node_modules/eslint/node_modules/ansi-regex": { "version": "4.1.1", "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.1.tgz", @@ -6859,6 +6892,25 @@ "node": ">= 4" } }, + "node_modules/eslint/node_modules/js-yaml": { + "version": "3.14.1", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.14.1.tgz", + "integrity": "sha512-okMH7OXXJ7YrN9Ok3/SXrnu4iX9yOk+25nqX4imS2npuvTYDmo/QEZoqwZkYaIDk3jVvBOTOIEgEhaLOynBS9g==", + "dev": true, + "dependencies": { + "argparse": "^1.0.7", + "esprima": "^4.0.0" + }, + "bin": { + "js-yaml": "bin/js-yaml.js" + } + }, + "node_modules/eslint/node_modules/json-schema-traverse": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", + "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", + "dev": true + }, "node_modules/eslint/node_modules/strip-ansi": { "version": "5.2.0", "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-5.2.0.tgz", @@ -6976,6 +7028,15 @@ "node": ">= 0.6" } }, + "node_modules/event-target-shim": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/event-target-shim/-/event-target-shim-5.0.1.tgz", + "integrity": "sha512-i/2XbnSz/uxRCU6+NdVJgKWDTM427+MqYbkQzD321DuCQJUqOuJKIA0IM2+W2xtYHdKOmZ4dR6fExsd4SXL+WQ==", + "dev": true, + "engines": { + "node": ">=6" + } + }, "node_modules/events": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/events/-/events-1.1.1.tgz", @@ -7000,121 +7061,52 @@ "assert-plus": "^1.0.0" } }, - "node_modules/expand-brackets": { - "version": "2.1.4", - "resolved": "https://registry.npmjs.org/expand-brackets/-/expand-brackets-2.1.4.tgz", - "integrity": "sha1-t3c14xXOMPa27/D4OwQVGiJEliI=", + "node_modules/express": { + "version": "4.18.2", + "resolved": "https://registry.npmjs.org/express/-/express-4.18.2.tgz", + "integrity": "sha512-5/PsL6iGPdfQ/lKM1UuielYgv3BUoJfz1aUwU9vHZ+J7gyvwdQXFEBIEIaxeGf0GIcreATNyBExtalisDbuMqQ==", "dev": true, "dependencies": { - "debug": "^2.3.3", - "define-property": "^0.2.5", - "extend-shallow": "^2.0.1", - "posix-character-classes": "^0.1.0", - "regex-not": "^1.0.0", - "snapdragon": "^0.8.1", - "to-regex": "^3.0.1" + "accepts": "~1.3.8", + "array-flatten": "1.1.1", + "body-parser": "1.20.1", + "content-disposition": "0.5.4", + "content-type": "~1.0.4", + "cookie": "0.5.0", + "cookie-signature": "1.0.6", + "debug": "2.6.9", + "depd": "2.0.0", + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "etag": "~1.8.1", + "finalhandler": "1.2.0", + "fresh": "0.5.2", + "http-errors": "2.0.0", + "merge-descriptors": "1.0.1", + "methods": "~1.1.2", + "on-finished": "2.4.1", + "parseurl": "~1.3.3", + "path-to-regexp": "0.1.7", + "proxy-addr": "~2.0.7", + "qs": "6.11.0", + "range-parser": "~1.2.1", + "safe-buffer": "5.2.1", + "send": "0.18.0", + "serve-static": "1.15.0", + "setprototypeof": "1.2.0", + "statuses": "2.0.1", + "type-is": "~1.6.18", + "utils-merge": "1.0.1", + "vary": "~1.1.2" }, "engines": { - "node": ">=0.10.0" + "node": ">= 0.10.0" } }, - "node_modules/expand-brackets/node_modules/debug": { - "version": "2.6.9", - "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", - "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", - "dev": true, - "dependencies": { - "ms": "2.0.0" - } - }, - "node_modules/expand-brackets/node_modules/define-property": { - "version": "0.2.5", - "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", - "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", - "dev": true, - "dependencies": { - "is-descriptor": "^0.1.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/expand-brackets/node_modules/extend-shallow": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", - "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", - "dev": true, - "dependencies": { - "is-extendable": "^0.1.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/expand-brackets/node_modules/ms": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", - "dev": true - }, - "node_modules/expand-tilde": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/expand-tilde/-/expand-tilde-2.0.2.tgz", - "integrity": "sha1-l+gBqgUt8CRU3kawK/YhZCzchQI=", - "dev": true, - "dependencies": { - "homedir-polyfill": "^1.0.1" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/express": { - "version": "4.18.1", - "resolved": "https://registry.npmjs.org/express/-/express-4.18.1.tgz", - "integrity": "sha512-zZBcOX9TfehHQhtupq57OF8lFZ3UZi08Y97dwFCkD8p9d/d2Y3M+ykKcwaMDEL+4qyUolgBDX6AblpR3fL212Q==", - "dev": true, - "dependencies": { - "accepts": "~1.3.8", - "array-flatten": "1.1.1", - "body-parser": "1.20.0", - "content-disposition": "0.5.4", - "content-type": "~1.0.4", - "cookie": "0.5.0", - "cookie-signature": "1.0.6", - "debug": "2.6.9", - "depd": "2.0.0", - "encodeurl": "~1.0.2", - "escape-html": "~1.0.3", - "etag": "~1.8.1", - "finalhandler": "1.2.0", - "fresh": "0.5.2", - "http-errors": "2.0.0", - "merge-descriptors": "1.0.1", - "methods": "~1.1.2", - "on-finished": "2.4.1", - "parseurl": "~1.3.3", - "path-to-regexp": "0.1.7", - "proxy-addr": "~2.0.7", - "qs": "6.10.3", - "range-parser": "~1.2.1", - "safe-buffer": "5.2.1", - "send": "0.18.0", - "serve-static": "1.15.0", - "setprototypeof": "1.2.0", - "statuses": "2.0.1", - "type-is": "~1.6.18", - "utils-merge": "1.0.1", - "vary": "~1.1.2" - }, - "engines": { - "node": ">= 0.10.0" - } - }, - "node_modules/express-end": { - "version": "0.0.8", - "resolved": "https://registry.npmjs.org/express-end/-/express-end-0.0.8.tgz", - "integrity": "sha1-DI/ZVCiTIVjytM+R9ARTRr8sUyM=", + "node_modules/express-end": { + "version": "0.0.8", + "resolved": "https://registry.npmjs.org/express-end/-/express-end-0.0.8.tgz", + "integrity": "sha1-DI/ZVCiTIVjytM+R9ARTRr8sUyM=", "dev": true, "dependencies": { "debug": "^2.2.0" @@ -7261,36 +7253,6 @@ } ] }, - "node_modules/express/node_modules/send": { - "version": "0.18.0", - "resolved": "https://registry.npmjs.org/send/-/send-0.18.0.tgz", - "integrity": "sha512-qqWzuOjSFOuqPjFe4NOsMLafToQQwBSOEpS+FwEt3A2V3vKubTquT3vmLTQpFgMXp8AlFWFuP1qKaJZOtPpVXg==", - "dev": true, - "dependencies": { - "debug": "2.6.9", - "depd": "2.0.0", - "destroy": "1.2.0", - "encodeurl": "~1.0.2", - "escape-html": "~1.0.3", - "etag": "~1.8.1", - "fresh": "0.5.2", - "http-errors": "2.0.0", - "mime": "1.6.0", - "ms": "2.1.3", - "on-finished": "2.4.1", - "range-parser": "~1.2.1", - "statuses": "2.0.1" - }, - "engines": { - "node": ">= 0.8.0" - } - }, - "node_modules/express/node_modules/send/node_modules/ms": { - "version": "2.1.3", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", - "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", - "dev": true - }, "node_modules/express/node_modules/statuses": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.1.tgz", @@ -7306,43 +7268,6 @@ "integrity": "sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==", "dev": true }, - "node_modules/extend-shallow": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-3.0.2.tgz", - "integrity": "sha1-Jqcarwc7OfshJxcnRhMcJwQCjbg=", - "dev": true, - "dependencies": { - "assign-symbols": "^1.0.0", - "is-extendable": "^1.0.1" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/extend-shallow/node_modules/is-extendable": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-1.0.1.tgz", - "integrity": "sha512-arnXMxT1hhoKo9k1LZdmlNyJdDDfy2v0fXjFlmok4+i8ul/6WlbVge9bhM74OpNPQPMGUToDtz+KXa1PneJxOA==", - "dev": true, - "dependencies": { - "is-plain-object": "^2.0.4" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/extend-shallow/node_modules/is-plain-object": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-2.0.4.tgz", - "integrity": "sha512-h5PpgXkWitc38BBMYawTYMWJHFZJVnBquFE57xFpjB8pJFiF6gZ+bU+WyI/yqXiFR5mdLsgYNaPe8uao6Uv9Og==", - "dev": true, - "dependencies": { - "isobject": "^3.0.1" - }, - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/external-editor": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/external-editor/-/external-editor-3.1.0.tgz", @@ -7357,96 +7282,6 @@ "node": ">=4" } }, - "node_modules/extglob": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/extglob/-/extglob-2.0.4.tgz", - "integrity": "sha512-Nmb6QXkELsuBr24CJSkilo6UHHgbekK5UiZgfE6UHD3Eb27YC6oD+bhcT+tJ6cl8dmsgdQxnWlcry8ksBIBLpw==", - "dev": true, - "dependencies": { - "array-unique": "^0.3.2", - "define-property": "^1.0.0", - "expand-brackets": "^2.1.4", - "extend-shallow": "^2.0.1", - "fragment-cache": "^0.2.1", - "regex-not": "^1.0.0", - "snapdragon": "^0.8.1", - "to-regex": "^3.0.1" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/extglob/node_modules/define-property": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/define-property/-/define-property-1.0.0.tgz", - "integrity": "sha1-dp66rz9KY6rTr56NMEybvnm/sOY=", - "dev": true, - "dependencies": { - "is-descriptor": "^1.0.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/extglob/node_modules/extend-shallow": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", - "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", - "dev": true, - "dependencies": { - "is-extendable": "^0.1.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/extglob/node_modules/is-accessor-descriptor": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz", - "integrity": "sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ==", - "dev": true, - "dependencies": { - "kind-of": "^6.0.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/extglob/node_modules/is-data-descriptor": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz", - "integrity": "sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ==", - "dev": true, - "dependencies": { - "kind-of": "^6.0.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/extglob/node_modules/is-descriptor": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.2.tgz", - "integrity": "sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg==", - "dev": true, - "dependencies": { - "is-accessor-descriptor": "^1.0.0", - "is-data-descriptor": "^1.0.0", - "kind-of": "^6.0.2" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/extglob/node_modules/kind-of": { - "version": "6.0.3", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.3.tgz", - "integrity": "sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/extsprintf": { "version": "1.3.0", "resolved": "https://registry.npmjs.org/extsprintf/-/extsprintf-1.3.0.tgz", @@ -7502,12 +7337,41 @@ "node": ">= 10.0.0" } }, + "node_modules/fast-json-stringify/node_modules/ajv": { + "version": "6.12.6", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", + "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", + "dependencies": { + "fast-deep-equal": "^3.1.1", + "fast-json-stable-stringify": "^2.0.0", + "json-schema-traverse": "^0.4.1", + "uri-js": "^4.2.2" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, + "node_modules/fast-json-stringify/node_modules/json-schema-traverse": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", + "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==" + }, "node_modules/fast-levenshtein": { "version": "2.0.6", "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz", "integrity": "sha1-PYpcZog6FqMMqGQ+hR8Zuqd5eRc=", "dev": true }, + "node_modules/fast-querystring": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/fast-querystring/-/fast-querystring-1.0.0.tgz", + "integrity": "sha512-3LQi62IhQoDlmt4ULCYmh17vRO2EtS7hTSsG4WwoKWgV7GLMKBOecEh+aiavASnLx8I2y89OD33AGLo0ccRhzA==", + "dev": true, + "dependencies": { + "fast-decode-uri-component": "^1.0.1" + } + }, "node_modules/fast-redact": { "version": "3.1.1", "resolved": "https://registry.npmjs.org/fast-redact/-/fast-redact-3.1.1.tgz", @@ -7530,78 +7394,66 @@ } }, "node_modules/fast-uri": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/fast-uri/-/fast-uri-1.0.1.tgz", - "integrity": "sha512-dbO/+ny6lX4tt7pvfPMTiHfQVR5igYKFa5BJ2a21TWuOgd2ySp5DYswsEGuMcJZLL3/eJ/MQJ5KNcXyNUvDt8w==", + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/fast-uri/-/fast-uri-2.1.0.tgz", + "integrity": "sha512-qKRta6N7BWEFVlyonVY/V+BMLgFqktCUV0QjT259ekAIlbVrMaFnFLxJ4s/JPl4tou56S1BzPufI60bLe29fHA==", "dev": true }, "node_modules/fastify": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/fastify/-/fastify-4.2.0.tgz", - "integrity": "sha512-0QXEp+8ceKc0fwVakeBLM/1Ss/+fc7a3auuygT+1GjbSAgHfwqxSucUuu0rYjziu32UgEZXfjItYN/a89HWKhw==", + "version": "4.11.0", + "resolved": "https://registry.npmjs.org/fastify/-/fastify-4.11.0.tgz", + "integrity": "sha512-JteZ8pjEqd+6n+azQnQfSJV8MUMxAmxbvC2Dx/Mybj039Lf/u3kda9Kq84uy/huCpqCzZoyHIZS5JFGF3wLztw==", "dev": true, "dependencies": { - "@fastify/ajv-compiler": "^3.1.0", + "@fastify/ajv-compiler": "^3.3.1", "@fastify/error": "^3.0.0", - "@fastify/fast-json-stringify-compiler": "^4.0.0", + "@fastify/fast-json-stringify-compiler": "^4.1.0", "abstract-logging": "^2.0.1", - "avvio": "^8.1.3", - "find-my-way": "^7.0.0", - "light-my-request": "^5.0.0", - "pino": "^8.0.0", + "avvio": "^8.2.0", + "content-type": "^1.0.4", + "find-my-way": "^7.3.0", + "light-my-request": "^5.6.1", + "pino": "^8.5.0", "process-warning": "^2.0.0", "proxy-addr": "^2.0.7", "rfdc": "^1.3.0", - "secure-json-parse": "^2.4.0", + "secure-json-parse": "^2.5.0", "semver": "^7.3.7", - "tiny-lru": "^8.0.2" + "tiny-lru": "^10.0.0" } }, "node_modules/fastify-plugin": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/fastify-plugin/-/fastify-plugin-3.0.1.tgz", - "integrity": "sha512-qKcDXmuZadJqdTm6vlCqioEbyewF60b/0LOFCcYN1B6BIZGlYJumWWOYs70SFYLDAH4YqdE1cxH/RKMG7rFxgA==", + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/fastify-plugin/-/fastify-plugin-4.2.1.tgz", + "integrity": "sha512-dlGKiwLzRBKkEf5J5ho0uAD/Jdv8GQVUbriB3tAX3ehRUXE4gTV3lRd5inEg9li1aLzb0EGj8y2K4/8g1TN06g==", "dev": true }, - "node_modules/fastify/node_modules/find-my-way": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/find-my-way/-/find-my-way-7.0.0.tgz", - "integrity": "sha512-NHVohYPYRXgj6jxXVRwm4iMQjA2ggJpyewHz7Nq7hvBnHoYJJIyHuxNzs8QLPTLQfoqxZzls2g6Zm79XMbhXjA==", - "dev": true, - "dependencies": { - "fast-deep-equal": "^3.1.3", - "safe-regex2": "^2.0.0" - }, - "engines": { - "node": ">=14" - } - }, "node_modules/fastify/node_modules/pino": { - "version": "8.0.0", - "resolved": "https://registry.npmjs.org/pino/-/pino-8.0.0.tgz", - "integrity": "sha512-EvZh9ZUoLGkrhqhoF9UBxw2/ZiAhXHUKlGrI4WUT/wLu0sfu8Wr3NJaZ6lxcy/S51W0PMSon5KE7ujPAhc/G6g==", + "version": "8.6.1", + "resolved": "https://registry.npmjs.org/pino/-/pino-8.6.1.tgz", + "integrity": "sha512-fi+V2K98eMZjQ/uEHHSiMALNrz7HaFdKNYuyA3ZUrbH0f1e8sPFDmeRGzg7ZH2q4QDxGnJPOswmqlEaTAZeDPA==", "dev": true, "dependencies": { "atomic-sleep": "^1.0.0", - "fast-redact": "^3.0.0", - "on-exit-leak-free": "^1.0.0", - "pino-abstract-transport": "v0.5.0", - "pino-std-serializers": "^5.0.0", + "fast-redact": "^3.1.1", + "on-exit-leak-free": "^2.1.0", + "pino-abstract-transport": "v1.0.0", + "pino-std-serializers": "^6.0.0", "process-warning": "^2.0.0", "quick-format-unescaped": "^4.0.3", - "real-require": "^0.1.0", - "safe-stable-stringify": "^2.1.0", - "sonic-boom": "^3.0.0", - "thread-stream": "^1.0.0" + "real-require": "^0.2.0", + "safe-stable-stringify": "^2.3.1", + "sonic-boom": "^3.1.0", + "thread-stream": "^2.0.0" }, "bin": { "pino": "bin.js" } }, "node_modules/fastify/node_modules/pino-std-serializers": { - "version": "5.3.0", - "resolved": "https://registry.npmjs.org/pino-std-serializers/-/pino-std-serializers-5.3.0.tgz", - "integrity": "sha512-Jm6EfiTTWUMxiyi07RUPpD9KLntgqc4P9lriWZG5TpabeJYxG/zkI5aUdTpUdgfS1mj3YD+0n3BINbQTz9r0Ig==", + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/pino-std-serializers/-/pino-std-serializers-6.0.0.tgz", + "integrity": "sha512-mMMOwSKrmyl+Y12Ri2xhH1lbzQxwwpuru9VjyJpgFIH4asSj88F2csdMwN6+M5g1Ll4rmsYghHLQJw81tgZ7LQ==", "dev": true }, "node_modules/fastify/node_modules/process-warning": { @@ -7626,9 +7478,9 @@ } }, "node_modules/fastify/node_modules/sonic-boom": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/sonic-boom/-/sonic-boom-3.0.0.tgz", - "integrity": "sha512-p5DiZOZHbJ2ZO5MADczp5qrfOd3W5Vr2vHxfCpe7G4AzPwVOweIjbfgku8wSQUuk+Y5Yuo8W7JqRe6XKmKistg==", + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/sonic-boom/-/sonic-boom-3.2.0.tgz", + "integrity": "sha512-SbbZ+Kqj/XIunvIAgUZRlqd6CGQYq71tRRbXR92Za8J/R3Yh4Av+TWENiSiEgnlwckYLyP0YZQWVfyNC0dzLaA==", "dev": true, "dependencies": { "atomic-sleep": "^1.0.0" @@ -7772,17 +7624,17 @@ } }, "node_modules/find-my-way": { - "version": "2.2.5", - "resolved": "https://registry.npmjs.org/find-my-way/-/find-my-way-2.2.5.tgz", - "integrity": "sha512-GjRZZlGcGmTh9t+6Xrj5K0YprpoAFCAiCPgmAH9Kb09O4oX6hYuckDfnDipYj+Q7B1GtYWSzDI5HEecNYscLQg==", + "version": "7.3.1", + "resolved": "https://registry.npmjs.org/find-my-way/-/find-my-way-7.3.1.tgz", + "integrity": "sha512-kGvM08SOkqvheLcuQ8GW9t/H901Qb9rZEbcNWbXopzy4jDRoaJpJoObPSKf4MnQLZ20ZTp7rL5MpF6rf+pqmyg==", "dev": true, "dependencies": { - "fast-decode-uri-component": "^1.0.0", - "safe-regex2": "^2.0.0", - "semver-store": "^0.3.0" + "fast-deep-equal": "^3.1.3", + "fast-querystring": "^1.0.0", + "safe-regex2": "^2.0.0" }, "engines": { - "node": ">=6" + "node": ">=14" } }, "node_modules/find-up": { @@ -7798,188 +7650,6 @@ "node": ">=8" } }, - "node_modules/findup-sync": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/findup-sync/-/findup-sync-3.0.0.tgz", - "integrity": "sha512-YbffarhcicEhOrm4CtrwdKBdCuz576RLdhJDsIfvNtxUuhdRet1qZcsMjqbePtAseKdAnDyM/IyXbu7PRPRLYg==", - "dev": true, - "dependencies": { - "detect-file": "^1.0.0", - "is-glob": "^4.0.0", - "micromatch": "^3.0.4", - "resolve-dir": "^1.0.1" - }, - "engines": { - "node": ">= 0.10" - } - }, - "node_modules/findup-sync/node_modules/braces": { - "version": "2.3.2", - "resolved": "https://registry.npmjs.org/braces/-/braces-2.3.2.tgz", - "integrity": "sha512-aNdbnj9P8PjdXU4ybaWLK2IF3jc/EoDYbC7AazW6to3TRsfXxscC9UXOB5iDiEQrkyIbWp2SLQda4+QAa7nc3w==", - "dev": true, - "dependencies": { - "arr-flatten": "^1.1.0", - "array-unique": "^0.3.2", - "extend-shallow": "^2.0.1", - "fill-range": "^4.0.0", - "isobject": "^3.0.1", - "repeat-element": "^1.1.2", - "snapdragon": "^0.8.1", - "snapdragon-node": "^2.0.1", - "split-string": "^3.0.2", - "to-regex": "^3.0.1" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/findup-sync/node_modules/braces/node_modules/extend-shallow": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", - "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", - "dev": true, - "dependencies": { - "is-extendable": "^0.1.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/findup-sync/node_modules/fill-range": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-4.0.0.tgz", - "integrity": "sha1-1USBHUKPmOsGpj3EAtJAPDKMOPc=", - "dev": true, - "dependencies": { - "extend-shallow": "^2.0.1", - "is-number": "^3.0.0", - "repeat-string": "^1.6.1", - "to-regex-range": "^2.1.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/findup-sync/node_modules/fill-range/node_modules/extend-shallow": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", - "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", - "dev": true, - "dependencies": { - "is-extendable": "^0.1.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/findup-sync/node_modules/is-number": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/is-number/-/is-number-3.0.0.tgz", - "integrity": "sha1-JP1iAaR4LPUFYcgQJ2r8fRLXEZU=", - "dev": true, - "dependencies": { - "kind-of": "^3.0.2" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/findup-sync/node_modules/is-number/node_modules/kind-of": { - "version": "3.2.2", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", - "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", - "dev": true, - "dependencies": { - "is-buffer": "^1.1.5" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/findup-sync/node_modules/kind-of": { - "version": "6.0.3", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.3.tgz", - "integrity": "sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/findup-sync/node_modules/micromatch": { - "version": "3.1.10", - "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-3.1.10.tgz", - "integrity": "sha512-MWikgl9n9M3w+bpsY3He8L+w9eF9338xRl8IAO5viDizwSzziFEyUzo2xrrloB64ADbTf8uA8vRqqttDTOmccg==", - "dev": true, - "dependencies": { - "arr-diff": "^4.0.0", - "array-unique": "^0.3.2", - "braces": "^2.3.1", - "define-property": "^2.0.2", - "extend-shallow": "^3.0.2", - "extglob": "^2.0.4", - "fragment-cache": "^0.2.1", - "kind-of": "^6.0.2", - "nanomatch": "^1.2.9", - "object.pick": "^1.3.0", - "regex-not": "^1.0.0", - "snapdragon": "^0.8.1", - "to-regex": "^3.0.2" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/findup-sync/node_modules/to-regex-range": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-2.1.1.tgz", - "integrity": "sha1-fIDBe53+vlmeJzZ+DU3VWQFB2zg=", - "dev": true, - "dependencies": { - "is-number": "^3.0.0", - "repeat-string": "^1.6.1" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/fined": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/fined/-/fined-1.2.0.tgz", - "integrity": "sha512-ZYDqPLGxDkDhDZBjZBb+oD1+j0rA4E0pXY50eplAAOPg2N/gUBSSk5IM1/QhPfyVo19lJ+CvXpqfvk+b2p/8Ng==", - "dev": true, - "dependencies": { - "expand-tilde": "^2.0.2", - "is-plain-object": "^2.0.3", - "object.defaults": "^1.1.0", - "object.pick": "^1.2.0", - "parse-filepath": "^1.0.1" - }, - "engines": { - "node": ">= 0.10" - } - }, - "node_modules/fined/node_modules/is-plain-object": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-2.0.4.tgz", - "integrity": "sha512-h5PpgXkWitc38BBMYawTYMWJHFZJVnBquFE57xFpjB8pJFiF6gZ+bU+WyI/yqXiFR5mdLsgYNaPe8uao6Uv9Og==", - "dev": true, - "dependencies": { - "isobject": "^3.0.1" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/flagged-respawn": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/flagged-respawn/-/flagged-respawn-1.0.1.tgz", - "integrity": "sha512-lNaHNVymajmk0OJMBn8fVUAU1BtDeKIqKoVhk4xAALB57aALg6b4W0MfJ/cUE0g9YBXy5XhSlPIpYIJ7HaY/3Q==", - "dev": true, - "engines": { - "node": ">= 0.10" - } - }, "node_modules/flat-cache": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-2.0.1.tgz", @@ -8052,27 +7722,6 @@ "is-callable": "^1.1.3" } }, - "node_modules/for-in": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/for-in/-/for-in-1.0.2.tgz", - "integrity": "sha1-gQaNKVqBQuwKxybG4iAMMPttXoA=", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/for-own": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/for-own/-/for-own-1.0.0.tgz", - "integrity": "sha1-xjMy9BXO3EsE2/5wz4NklMU8tEs=", - "dev": true, - "dependencies": { - "for-in": "^1.0.1" - }, - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/foreach": { "version": "2.0.5", "resolved": "https://registry.npmjs.org/foreach/-/foreach-2.0.5.tgz", @@ -8198,18 +7847,6 @@ "resolved": "https://registry.npmjs.org/forwarded-parse/-/forwarded-parse-2.1.2.tgz", "integrity": "sha512-alTFZZQDKMporBH77856pXgzhEzaUVmLCDk+egLgIgHst3Tpndzz8MnKe+GzRJRfvVdn69HhpW7cmXzvtLvJAw==" }, - "node_modules/fragment-cache": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/fragment-cache/-/fragment-cache-0.2.1.tgz", - "integrity": "sha1-QpD60n8T6Jvn8zeZxrxaCr//DRk=", - "dev": true, - "dependencies": { - "map-cache": "^0.2.2" - }, - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/fresh": { "version": "0.5.2", "resolved": "https://registry.npmjs.org/fresh/-/fresh-0.5.2.tgz", @@ -8311,9 +7948,9 @@ } }, "node_modules/generic-pool": { - "version": "3.8.2", - "resolved": "https://registry.npmjs.org/generic-pool/-/generic-pool-3.8.2.tgz", - "integrity": "sha512-nGToKy6p3PAbYQ7p1UlWl6vSPwfwU6TMSWK7TTu+WUY4ZjyZQGniGGt2oNVvyNSpyZYSB43zMXVLcBm08MTMkg==", + "version": "3.9.0", + "resolved": "https://registry.npmjs.org/generic-pool/-/generic-pool-3.9.0.tgz", + "integrity": "sha512-hymDOu5B53XvN4QT9dBmZxPX4CWhBPPLguTZ9MMFeFa/Kg0xWVfylOVNlJji/E7yTZWFd/q9GO5TxDLq156D7g==", "dev": true, "engines": { "node": ">= 4" @@ -8401,15 +8038,6 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/get-value": { - "version": "2.0.6", - "resolved": "https://registry.npmjs.org/get-value/-/get-value-2.0.6.tgz", - "integrity": "sha1-3BXKHGcjh8p2vTesCjlbogQqLCg=", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/getopts": { "version": "2.2.5", "resolved": "https://registry.npmjs.org/getopts/-/getopts-2.2.5.tgz", @@ -8426,15 +8054,15 @@ } }, "node_modules/glob": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.0.tgz", - "integrity": "sha512-lmLf6gtyrPq8tTjSmrO94wBeQbFR3HbLHbuyD69wuyQkImp2hWqMGB47OX65FBkPffO641IP9jWa1z4ivqG26Q==", + "version": "7.2.3", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", + "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", "dev": true, "dependencies": { "fs.realpath": "^1.0.0", "inflight": "^1.0.4", "inherits": "2", - "minimatch": "^3.0.4", + "minimatch": "^3.1.1", "once": "^1.3.0", "path-is-absolute": "^1.0.0" }, @@ -8457,36 +8085,6 @@ "node": ">= 6" } }, - "node_modules/global-modules": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/global-modules/-/global-modules-1.0.0.tgz", - "integrity": "sha512-sKzpEkf11GpOFuw0Zzjzmt4B4UZwjOcG757PPvrfhxcLFbq0wpsgpOqxpxtxFiCG4DtG93M6XRVbF2oGdev7bg==", - "dev": true, - "dependencies": { - "global-prefix": "^1.0.1", - "is-windows": "^1.0.1", - "resolve-dir": "^1.0.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/global-prefix": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/global-prefix/-/global-prefix-1.0.2.tgz", - "integrity": "sha1-2/dDxsFJklk8ZVVoy2btMsASLr4=", - "dev": true, - "dependencies": { - "expand-tilde": "^2.0.2", - "homedir-polyfill": "^1.0.1", - "ini": "^1.3.4", - "is-windows": "^1.0.1", - "which": "^1.2.14" - }, - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/globals": { "version": "11.12.0", "resolved": "https://registry.npmjs.org/globals/-/globals-11.12.0.tgz", @@ -8541,9 +8139,9 @@ } }, "node_modules/got": { - "version": "11.8.5", - "resolved": "https://registry.npmjs.org/got/-/got-11.8.5.tgz", - "integrity": "sha512-o0Je4NvQObAuZPHLFoRSkdG2lTgtcynqymzg2Vupdx6PorhaT5MCbIyXG6d4D94kk8ZG57QeosgdiqfJWhEhlQ==", + "version": "11.8.6", + "resolved": "https://registry.npmjs.org/got/-/got-11.8.6.tgz", + "integrity": "sha512-6tfZ91bOr7bOXnK7PRDCGBLa1H4U080YHNaAQ2KsMGlLEzRbk44nsZF2E1IeRc3vtJHPVbKCYgdFbaGO2ljd8g==", "dev": true, "dependencies": { "@sindresorhus/is": "^4.0.0", @@ -8654,6 +8252,28 @@ "node": ">=6" } }, + "node_modules/har-validator/node_modules/ajv": { + "version": "6.12.6", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", + "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", + "dev": true, + "dependencies": { + "fast-deep-equal": "^3.1.1", + "fast-json-stable-stringify": "^2.0.0", + "json-schema-traverse": "^0.4.1", + "uri-js": "^4.2.2" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, + "node_modules/har-validator/node_modules/json-schema-traverse": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", + "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", + "dev": true + }, "node_modules/has": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz", @@ -8752,69 +8372,6 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/has-value": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/has-value/-/has-value-1.0.0.tgz", - "integrity": "sha1-GLKB2lhbHFxR3vJMkw7SmgvmsXc=", - "dev": true, - "dependencies": { - "get-value": "^2.0.6", - "has-values": "^1.0.0", - "isobject": "^3.0.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/has-values": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/has-values/-/has-values-1.0.0.tgz", - "integrity": "sha1-lbC2P+whRmGab+V/51Yo1aOe/k8=", - "dev": true, - "dependencies": { - "is-number": "^3.0.0", - "kind-of": "^4.0.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/has-values/node_modules/is-number": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/is-number/-/is-number-3.0.0.tgz", - "integrity": "sha1-JP1iAaR4LPUFYcgQJ2r8fRLXEZU=", - "dev": true, - "dependencies": { - "kind-of": "^3.0.2" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/has-values/node_modules/is-number/node_modules/kind-of": { - "version": "3.2.2", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", - "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", - "dev": true, - "dependencies": { - "is-buffer": "^1.1.5" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/has-values/node_modules/kind-of": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-4.0.0.tgz", - "integrity": "sha1-IIE989cSkosgc3hpGkUGb65y3Vc=", - "dev": true, - "dependencies": { - "is-buffer": "^1.1.5" - }, - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/hasha": { "version": "5.2.2", "resolved": "https://registry.npmjs.org/hasha/-/hasha-5.2.2.tgz", @@ -8841,18 +8398,6 @@ "simple-lru-cache": "0.0.x" } }, - "node_modules/homedir-polyfill": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/homedir-polyfill/-/homedir-polyfill-1.0.3.tgz", - "integrity": "sha512-eSmmWE5bZTK2Nou4g0AI3zZ9rswp7GRKoKXS1BLUkvPviOqs4YTN1djQIqrXy9k5gEtdLPy86JjRwsNM9tnDcA==", - "dev": true, - "dependencies": { - "parse-passwd": "^1.0.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/hosted-git-info": { "version": "2.8.9", "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-2.8.9.tgz", @@ -9108,12 +8653,6 @@ "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==" }, - "node_modules/ini": { - "version": "1.3.8", - "resolved": "https://registry.npmjs.org/ini/-/ini-1.3.8.tgz", - "integrity": "sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew==", - "dev": true - }, "node_modules/inquirer": { "version": "7.3.3", "resolved": "https://registry.npmjs.org/inquirer/-/inquirer-7.3.3.tgz", @@ -9231,9 +8770,9 @@ } }, "node_modules/ioredis": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/ioredis/-/ioredis-5.1.0.tgz", - "integrity": "sha512-HYHnvwxFwefeUBj0hZFejLvd8Q/YNAfnZlZG/hSRxkRhXMs1H8soMEVccHd1WlLrKkynorXBsAtqDGskOdAfVQ==", + "version": "5.2.3", + "resolved": "https://registry.npmjs.org/ioredis/-/ioredis-5.2.3.tgz", + "integrity": "sha512-gQNcMF23/NpvjCaa1b5YycUyQJ9rBNH2xP94LWinNpodMWVUPP5Ai/xXANn/SM7gfIvI62B5CCvZxhg5pOgyMw==", "dev": true, "dependencies": { "@ioredis/commands": "^1.1.1", @@ -9264,43 +8803,18 @@ } }, "node_modules/ip": { - "version": "1.1.5", - "resolved": "https://registry.npmjs.org/ip/-/ip-1.1.5.tgz", - "integrity": "sha1-vd7XARQpCCjAoDnnLvJfWq7ENUo=", + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ip/-/ip-2.0.0.tgz", + "integrity": "sha512-WKa+XuLG1A1R0UWhl2+1XQSi+fZWMsYKffMZTTYsiZaUD8k2yDAj5atimTUD2TZkyCkNEeYE5NhFZmupOGtjYQ==", "dev": true }, "node_modules/ipaddr.js": { "version": "1.9.1", - "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.9.1.tgz", - "integrity": "sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g==", - "dev": true, - "engines": { - "node": ">= 0.10" - } - }, - "node_modules/is-absolute": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-absolute/-/is-absolute-1.0.0.tgz", - "integrity": "sha512-dOWoqflvcydARa360Gvv18DZ/gRuHKi2NU/wU5X1ZFzdYfH29nkiNZsF3mp4OJ3H4yo9Mx8A/uAGNzpzPN3yBA==", - "dev": true, - "dependencies": { - "is-relative": "^1.0.0", - "is-windows": "^1.0.1" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/is-accessor-descriptor": { - "version": "0.1.6", - "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-0.1.6.tgz", - "integrity": "sha1-qeEss66Nh2cn7u84Q/igiXtcmNY=", + "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.9.1.tgz", + "integrity": "sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g==", "dev": true, - "dependencies": { - "kind-of": "^3.0.2" - }, "engines": { - "node": ">=0.10.0" + "node": ">= 0.10" } }, "node_modules/is-arguments": { @@ -9358,12 +8872,6 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/is-buffer": { - "version": "1.1.6", - "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-1.1.6.tgz", - "integrity": "sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w==", - "dev": true - }, "node_modules/is-callable": { "version": "1.2.4", "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.2.4.tgz", @@ -9388,9 +8896,9 @@ } }, "node_modules/is-core-module": { - "version": "2.8.1", - "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.8.1.tgz", - "integrity": "sha512-SdNCUs284hr40hFTFP6l0IfZ/RSrMXF3qgoRHd3/79unUTvrFO/JoXwkGm+5J/Oe3E/b5GsnG330uUNgRpu1PA==", + "version": "2.10.0", + "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.10.0.tgz", + "integrity": "sha512-Erxj2n/LDAZ7H8WNJXd9tw38GYM3dv8rk8Zcs+jJuxYTW7sozH+SS8NtrSjVL1/vpLvWi1hxy96IzjJ3EHTJJg==", "dependencies": { "has": "^1.0.3" }, @@ -9398,18 +8906,6 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/is-data-descriptor": { - "version": "0.1.4", - "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-0.1.4.tgz", - "integrity": "sha1-C17mSDiOLIYCgueT8YVv7D8wG1Y=", - "dev": true, - "dependencies": { - "kind-of": "^3.0.2" - }, - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/is-date-object": { "version": "1.0.5", "resolved": "https://registry.npmjs.org/is-date-object/-/is-date-object-1.0.5.tgz", @@ -9424,29 +8920,6 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/is-descriptor": { - "version": "0.1.6", - "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-0.1.6.tgz", - "integrity": "sha512-avDYr0SB3DwO9zsMov0gKCESFYqCnE4hq/4z3TdUlukEy5t9C0YRq7HLrsN52NAcqXKaepeCD0n+B0arnVG3Hg==", - "dev": true, - "dependencies": { - "is-accessor-descriptor": "^0.1.6", - "is-data-descriptor": "^0.1.4", - "kind-of": "^5.0.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/is-descriptor/node_modules/kind-of": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-5.1.0.tgz", - "integrity": "sha512-NGEErnH6F2vUuXDh+OlbcKW7/wOcfdRHaZ7VWtqCztfHri/++YKmP51OdWeGPuqCOba6kk2OTe5d02VmTB80Pw==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/is-docker": { "version": "2.2.1", "resolved": "https://registry.npmjs.org/is-docker/-/is-docker-2.2.1.tgz", @@ -9472,15 +8945,6 @@ "object-assign": "^4.1.1" } }, - "node_modules/is-extendable": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-0.1.1.tgz", - "integrity": "sha1-YrEQ4omkcUGOPsNqYX1HLjAd/Ik=", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/is-extglob": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", @@ -9852,15 +9316,6 @@ "integrity": "sha1-6PvzdNxVb/iUehDcsFctYz8s+hA=", "dev": true }, - "node_modules/isobject": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz", - "integrity": "sha1-TkMekrEalzFjaqH5yNHMvP2reN8=", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/isstream": { "version": "0.1.2", "resolved": "https://registry.npmjs.org/isstream/-/isstream-0.1.2.tgz", @@ -10131,9 +9586,9 @@ } }, "node_modules/joi": { - "version": "17.6.0", - "resolved": "https://registry.npmjs.org/joi/-/joi-17.6.0.tgz", - "integrity": "sha512-OX5dG6DTbcr/kbMFj0KGYxuew69HPcAE3K/sZpEV2nP6e/j/C0HV+HNiBPCASxdx5T7DMoa0s8UeHWMnb6n2zw==", + "version": "17.7.0", + "resolved": "https://registry.npmjs.org/joi/-/joi-17.7.0.tgz", + "integrity": "sha512-1/ugc8djfn93rTE3WRKdCzGGt/EtiYKxITMO4Wiv6q5JL1gl9ePt4kBsl1S499nbosspfctIQTpYIhSmHA3WAg==", "dev": true, "dependencies": { "@hapi/hoek": "^9.0.0", @@ -10143,6 +9598,12 @@ "@sideway/pinpoint": "^2.0.0" } }, + "node_modules/js-md4": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/js-md4/-/js-md4-0.3.2.tgz", + "integrity": "sha512-/GDnfQYsltsjRswQhN9fhv3EMw2sCpUdrdxyWDOUK7eyD++r3gRhzgiQgc/x4MAv2i1iuQ4lxO5mvqM3vj4bwA==", + "dev": true + }, "node_modules/js-stringify": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/js-stringify/-/js-stringify-1.0.2.tgz", @@ -10156,22 +9617,27 @@ "dev": true }, "node_modules/js-yaml": { - "version": "3.14.1", - "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.14.1.tgz", - "integrity": "sha512-okMH7OXXJ7YrN9Ok3/SXrnu4iX9yOk+25nqX4imS2npuvTYDmo/QEZoqwZkYaIDk3jVvBOTOIEgEhaLOynBS9g==", + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", + "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==", "dev": true, "dependencies": { - "argparse": "^1.0.7", - "esprima": "^4.0.0" + "argparse": "^2.0.1" }, "bin": { "js-yaml": "bin/js-yaml.js" } }, + "node_modules/js-yaml/node_modules/argparse": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", + "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", + "dev": true + }, "node_modules/jsbi": { - "version": "3.2.5", - "resolved": "https://registry.npmjs.org/jsbi/-/jsbi-3.2.5.tgz", - "integrity": "sha512-aBE4n43IPvjaddScbvWRA2YlTzKEynHzu7MqOyTipdHucf/VxS63ViCjxYRg86M8Rxwbt/GfzHl1kKERkt45fQ==", + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/jsbi/-/jsbi-4.3.0.tgz", + "integrity": "sha512-SnZNcinB4RIcnEyZqFPdGPVgrg2AcnykiBy0sHVJQKHYeaLUvi3Exj+iaPpLnFVkDPZIV4U0yvgC9/R4uEAZ9g==", "dev": true }, "node_modules/jsbn": { @@ -10211,9 +9677,10 @@ "dev": true }, "node_modules/json-schema-traverse": { - "version": "0.4.1", - "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", - "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==" + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", + "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==", + "dev": true }, "node_modules/json-stable-stringify-without-jsonify": { "version": "1.0.1", @@ -10228,9 +9695,9 @@ "dev": true }, "node_modules/json5": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.1.tgz", - "integrity": "sha512-1hqLFMSrGHRHxav9q9gNjJ5EXznIxGVO09xQRrwplcS8qs28pZ8s8hupZAmqDwZUmVZ2Qb2jnyPOWcDH8m8dlA==", + "version": "2.2.3", + "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.3.tgz", + "integrity": "sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==", "dev": true, "bin": { "json5": "lib/cli.js" @@ -10240,25 +9707,19 @@ } }, "node_modules/jsonwebtoken": { - "version": "8.5.1", - "resolved": "https://registry.npmjs.org/jsonwebtoken/-/jsonwebtoken-8.5.1.tgz", - "integrity": "sha512-XjwVfRS6jTMsqYs0EsuJ4LGxXV14zQybNd4L2r0UvbVnSF9Af8x7p5MzbJ90Ioz/9TI41/hTCvznF/loiSzn8w==", + "version": "9.0.0", + "resolved": "https://registry.npmjs.org/jsonwebtoken/-/jsonwebtoken-9.0.0.tgz", + "integrity": "sha512-tuGfYXxkQGDPnLJ7SibiQgVgeDgfbPq2k2ICcbgqW8WxWLBAxKQM/ZCu/IT8SOSwmaYl4dpTFCW5xZv7YbbWUw==", "dev": true, "dependencies": { "jws": "^3.2.2", - "lodash.includes": "^4.3.0", - "lodash.isboolean": "^3.0.3", - "lodash.isinteger": "^4.0.4", - "lodash.isnumber": "^3.0.3", - "lodash.isplainobject": "^4.0.6", - "lodash.isstring": "^4.0.1", - "lodash.once": "^4.0.0", + "lodash": "^4.17.21", "ms": "^2.1.1", - "semver": "^5.6.0" + "semver": "^7.3.8" }, "engines": { - "node": ">=4", - "npm": ">=1.4.28" + "node": ">=12", + "npm": ">=6" } }, "node_modules/jsonwebtoken/node_modules/jwa": { @@ -10283,12 +9744,18 @@ } }, "node_modules/jsonwebtoken/node_modules/semver": { - "version": "5.7.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", - "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==", + "version": "7.3.8", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.8.tgz", + "integrity": "sha512-NB1ctGL5rlHrPJtFDVIVzTyQylMLu9N9VICA6HSFJo8MCGVTMW6gfpicwKmmK/dAjTOrqu5l63JJOpDSrAis3A==", "dev": true, + "dependencies": { + "lru-cache": "^6.0.0" + }, "bin": { - "semver": "bin/semver" + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" } }, "node_modules/jsprim": { @@ -10349,36 +9816,25 @@ "json-buffer": "3.0.1" } }, - "node_modules/kind-of": { - "version": "3.2.2", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", - "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", - "dev": true, - "dependencies": { - "is-buffer": "^1.1.5" - }, - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/knex": { - "version": "0.21.21", - "resolved": "https://registry.npmjs.org/knex/-/knex-0.21.21.tgz", - "integrity": "sha512-cjw5qO1EzVKjbywcVa61IQJMLt7PfYBRI/2NwCA/B9beXgbw652wDNLz+JM+UKKNsfwprq0ugYqBYc9q4JN36A==", + "version": "0.95.15", + "resolved": "https://registry.npmjs.org/knex/-/knex-0.95.15.tgz", + "integrity": "sha512-Loq6WgHaWlmL2bfZGWPsy4l8xw4pOE+tmLGkPG0auBppxpI0UcK+GYCycJcqz9W54f2LiGewkCVLBm3Wq4ur/w==", "dev": true, "dependencies": { - "colorette": "1.2.1", - "commander": "^6.2.0", - "debug": "4.3.1", + "colorette": "2.0.16", + "commander": "^7.1.0", + "debug": "4.3.2", + "escalade": "^3.1.1", "esm": "^3.2.25", "getopts": "2.2.5", "interpret": "^2.2.0", - "liftoff": "3.1.0", - "lodash": "^4.17.20", - "pg-connection-string": "2.4.0", + "lodash": "^4.17.21", + "pg-connection-string": "2.5.0", + "rechoir": "0.7.0", + "resolve-from": "^5.0.0", "tarn": "^3.0.1", - "tildify": "2.0.0", - "v8flags": "^3.2.0" + "tildify": "2.0.0" }, "bin": { "knex": "bin/cli.js" @@ -10386,17 +9842,7 @@ "engines": { "node": ">=10" }, - "peerDependencies": { - "mssql": "^6.2.1", - "mysql": "^2.18.1", - "mysql2": "^2.1.0", - "pg": "^8.3.0", - "sqlite3": "^5.0.0" - }, "peerDependenciesMeta": { - "mssql": { - "optional": true - }, "mysql": { "optional": true }, @@ -10406,24 +9852,30 @@ "pg": { "optional": true }, + "pg-native": { + "optional": true + }, "sqlite3": { "optional": true + }, + "tedious": { + "optional": true } } }, "node_modules/knex/node_modules/commander": { - "version": "6.2.1", - "resolved": "https://registry.npmjs.org/commander/-/commander-6.2.1.tgz", - "integrity": "sha512-U7VdrJFnJgo4xjrHpTzu0yrHPGImdsmD95ZlgYSEajAn2JKzDhDTPG9kBTefmObL2w/ngeZnilk+OV9CG3d7UA==", + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/commander/-/commander-7.2.0.tgz", + "integrity": "sha512-QrWXB+ZQSVPmIWIhtEO9H+gwHaMGYiF5ChvoJ+K9ZGHG/sVsa6yiesAD1GC/x46sET00Xlwo1u49RVVVzvcSkw==", "dev": true, "engines": { - "node": ">= 6" + "node": ">= 10" } }, "node_modules/knex/node_modules/debug": { - "version": "4.3.1", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.1.tgz", - "integrity": "sha512-doEwdvm4PCeK4K3RQN2ZC2BYUBaxwLARCqZmMjtF8a51J2Rb0xpVloFRnCODwqjpwnAoao4pelN8l3RJdv3gRQ==", + "version": "4.3.2", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.2.tgz", + "integrity": "sha512-mOp8wKcvj7XxC78zLgw/ZA+6TSgkoE2C/ienthhRD298T7UNwAg9diBpLRxC0mOezLl4B0xV7M0cCO6P/O0Xhw==", "dev": true, "dependencies": { "ms": "2.1.2" @@ -10437,10 +9889,19 @@ } } }, + "node_modules/knex/node_modules/resolve-from": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-5.0.0.tgz", + "integrity": "sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==", + "dev": true, + "engines": { + "node": ">=8" + } + }, "node_modules/koa": { - "version": "2.13.4", - "resolved": "https://registry.npmjs.org/koa/-/koa-2.13.4.tgz", - "integrity": "sha512-43zkIKubNbnrULWlHdN5h1g3SEKXOEzoAlRsHOTFpnlDu8JlAOZSMJBLULusuXRequboiwJcj5vtYXKB3k7+2g==", + "version": "2.14.1", + "resolved": "https://registry.npmjs.org/koa/-/koa-2.14.1.tgz", + "integrity": "sha512-USJFyZgi2l0wDgqkfD27gL4YGno7TfUkcmOe6UOLFOVuN+J7FwnNu4Dydl4CUQzraM1lBAiGed0M9OVJoT0Kqw==", "dev": true, "dependencies": { "accepts": "^1.3.5", @@ -10504,19 +9965,52 @@ } }, "node_modules/koa-router": { - "version": "9.4.0", - "resolved": "https://registry.npmjs.org/koa-router/-/koa-router-9.4.0.tgz", - "integrity": "sha512-RO/Y8XqSNM2J5vQeDaBI/7iRpL50C9QEudY4d3T4D1A2VMKLH0swmfjxDFPiIpVDLuNN6mVD9zBI1eFTHB6QaA==", + "version": "12.0.0", + "resolved": "https://registry.npmjs.org/koa-router/-/koa-router-12.0.0.tgz", + "integrity": "sha512-zGrdiXygGYW8WvrzeGsHZvKnHs4DzyGoqJ9a8iHlRkiwuEAOAPyI27//OlhoWdgFAEIM3qbUgr0KCuRaP/TCag==", "dev": true, "dependencies": { - "debug": "^4.1.1", - "http-errors": "^1.7.3", + "http-errors": "^2.0.0", "koa-compose": "^4.1.0", "methods": "^1.1.2", - "path-to-regexp": "^6.1.0" + "path-to-regexp": "^6.2.1" }, "engines": { - "node": ">= 8.0.0" + "node": ">= 12" + } + }, + "node_modules/koa-router/node_modules/depd": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz", + "integrity": "sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==", + "dev": true, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/koa-router/node_modules/http-errors": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-2.0.0.tgz", + "integrity": "sha512-FtwrG/euBzaEjYeRqOgly7G0qviiXoJWnvEH2Z1plBdXgbyjv34pHTSb9zoeHMyDy33+DWy5Wt9Wo+TURtOYSQ==", + "dev": true, + "dependencies": { + "depd": "2.0.0", + "inherits": "2.0.4", + "setprototypeof": "1.2.0", + "statuses": "2.0.1", + "toidentifier": "1.0.1" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/koa-router/node_modules/statuses": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.1.tgz", + "integrity": "sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ==", + "dev": true, + "engines": { + "node": ">= 0.8" } }, "node_modules/koa/node_modules/depd": { @@ -10535,14 +10029,14 @@ "dev": true }, "node_modules/lambda-local": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/lambda-local/-/lambda-local-2.0.2.tgz", - "integrity": "sha512-sCE0U645QdmQOx5y028kZnmvbfho4NkdAjmJuA8KdwPQS8tz9sByz281WHyEAfcBfXci/9eQxNURuL996Q8ybw==", + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/lambda-local/-/lambda-local-2.0.3.tgz", + "integrity": "sha512-Vs55gujwdjhPL2VpXEXAWWwxiOYdnVPDsMgwOr9BqC0O1EoSXs1S8TKBmD/ySEnPVRiQfFlABcQgcykF1mkE8Q==", "dev": true, "dependencies": { - "commander": "^9.0.0", - "dotenv": "^16.0.0", - "winston": "^3.6.0" + "commander": "^9.4.0", + "dotenv": "^16.0.2", + "winston": "^3.8.2" }, "bin": { "lambda-local": "build/cli.js" @@ -10552,9 +10046,9 @@ } }, "node_modules/lambda-local/node_modules/commander": { - "version": "9.3.0", - "resolved": "https://registry.npmjs.org/commander/-/commander-9.3.0.tgz", - "integrity": "sha512-hv95iU5uXPbK83mjrJKuZyFM/LBAoCV/XhVGkS5Je6tl7sxr6A0ITMw5WoRV46/UaJ46Nllm3Xt7IaJhXTIkzw==", + "version": "9.4.1", + "resolved": "https://registry.npmjs.org/commander/-/commander-9.4.1.tgz", + "integrity": "sha512-5EEkTNyHNGFPD2H+c/dXXfQZYa/scCKasxWcXJaWnNJ99pnQN9Vnmqow+p+PlFPE63Q6mThaZws1T+HxfpgtPw==", "dev": true, "engines": { "node": "^12.20.0 || >=14" @@ -10573,69 +10067,21 @@ "node": ">= 0.8.0" } }, - "node_modules/liftoff": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/liftoff/-/liftoff-3.1.0.tgz", - "integrity": "sha512-DlIPlJUkCV0Ips2zf2pJP0unEoT1kwYhiiPUGF3s/jtxTCjziNLoiVVh+jqWOWeFi6mmwQ5fNxvAUyPad4Dfog==", - "dev": true, - "dependencies": { - "extend": "^3.0.0", - "findup-sync": "^3.0.0", - "fined": "^1.0.1", - "flagged-respawn": "^1.0.0", - "is-plain-object": "^2.0.4", - "object.map": "^1.0.0", - "rechoir": "^0.6.2", - "resolve": "^1.1.7" - }, - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/liftoff/node_modules/is-plain-object": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-2.0.4.tgz", - "integrity": "sha512-h5PpgXkWitc38BBMYawTYMWJHFZJVnBquFE57xFpjB8pJFiF6gZ+bU+WyI/yqXiFR5mdLsgYNaPe8uao6Uv9Og==", - "dev": true, - "dependencies": { - "isobject": "^3.0.1" - }, - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/light-my-request": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/light-my-request/-/light-my-request-5.0.0.tgz", - "integrity": "sha512-0OPHKV+uHgBOnRokzL1LqeMCnSAo5l/rZS7kyB6G1I8qxGCvhXpq1M6WK565Y9A5CSn50l3DVaHnJ5FCdpguZQ==", + "version": "5.6.1", + "resolved": "https://registry.npmjs.org/light-my-request/-/light-my-request-5.6.1.tgz", + "integrity": "sha512-sbJnC1UBRivi9L1kICr3CESb82pNiPNB3TvtdIrZZqW0Qh8uDXvoywMmWKZlihDcmw952CMICCzM+54LDf+E+g==", "dev": true, "dependencies": { - "ajv": "^8.1.0", "cookie": "^0.5.0", - "process-warning": "^1.0.0", + "process-warning": "^2.0.0", "set-cookie-parser": "^2.4.1" } }, - "node_modules/light-my-request/node_modules/ajv": { - "version": "8.11.0", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.11.0.tgz", - "integrity": "sha512-wGgprdCvMalC0BztXvitD2hC04YffAvtsUn93JbGXYLAtCUO4xd17mCCZQxUOItiBwZvJScWo8NIvQMQ71rdpg==", - "dev": true, - "dependencies": { - "fast-deep-equal": "^3.1.1", - "json-schema-traverse": "^1.0.0", - "require-from-string": "^2.0.2", - "uri-js": "^4.2.2" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/epoberezkin" - } - }, - "node_modules/light-my-request/node_modules/json-schema-traverse": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", - "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==", + "node_modules/light-my-request/node_modules/process-warning": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/process-warning/-/process-warning-2.0.0.tgz", + "integrity": "sha512-+MmoAXoUX+VTHAlwns0h+kFUWFs/3FZy+ZuchkgjyOu3oioLAo2LB5aCfKPh2+P9O18i3m43tUEv3YqttSy0Ww==", "dev": true }, "node_modules/locate-path": { @@ -10659,7 +10105,7 @@ "node_modules/lodash.debounce": { "version": "4.0.8", "resolved": "https://registry.npmjs.org/lodash.debounce/-/lodash.debounce-4.0.8.tgz", - "integrity": "sha1-gteb/zCmfEAF/9XiUVMArZyk168=", + "integrity": "sha512-FT1yDzDYEoYWhnSGnpE/4Kj1fLZkDFyqRb7fNt6FdYOSxlUWAtp42Eh6Wb0rGIv/m9Bgo7x4GhQbm5Ys4SG5ow==", "dev": true }, "node_modules/lodash.defaults": { @@ -10686,12 +10132,6 @@ "integrity": "sha1-+wMJF/hqMTTlvJvsDWngAT3f7bI=", "dev": true }, - "node_modules/lodash.includes": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/lodash.includes/-/lodash.includes-4.3.0.tgz", - "integrity": "sha1-YLuYqHy5I8aMoeUTJUgzFISfVT8=", - "dev": true - }, "node_modules/lodash.intersection": { "version": "4.4.0", "resolved": "https://registry.npmjs.org/lodash.intersection/-/lodash.intersection-4.4.0.tgz", @@ -10704,48 +10144,18 @@ "integrity": "sha1-L1c9hcaiQon/AGY7SRwdM4/zRYo=", "dev": true }, - "node_modules/lodash.isboolean": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/lodash.isboolean/-/lodash.isboolean-3.0.3.tgz", - "integrity": "sha1-bC4XHbKiV82WgC/UOwGyDV9YcPY=", - "dev": true - }, "node_modules/lodash.isempty": { "version": "4.4.0", "resolved": "https://registry.npmjs.org/lodash.isempty/-/lodash.isempty-4.4.0.tgz", "integrity": "sha1-b4bL7di+TsmHvpqvM8loTbGzHn4=", "dev": true }, - "node_modules/lodash.isinteger": { - "version": "4.0.4", - "resolved": "https://registry.npmjs.org/lodash.isinteger/-/lodash.isinteger-4.0.4.tgz", - "integrity": "sha1-YZwK89A/iwTDH1iChAt3sRzWg0M=", - "dev": true - }, - "node_modules/lodash.isnumber": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/lodash.isnumber/-/lodash.isnumber-3.0.3.tgz", - "integrity": "sha1-POdoEMWSjQM1IwGsKHMX8RwLH/w=", - "dev": true - }, - "node_modules/lodash.isplainobject": { - "version": "4.0.6", - "resolved": "https://registry.npmjs.org/lodash.isplainobject/-/lodash.isplainobject-4.0.6.tgz", - "integrity": "sha1-fFJqUtibRcRcxpC4gWO+BJf1UMs=", - "dev": true - }, "node_modules/lodash.isstring": { "version": "4.0.1", "resolved": "https://registry.npmjs.org/lodash.isstring/-/lodash.isstring-4.0.1.tgz", "integrity": "sha1-1SfftUVuynzJu5XV2ur4i6VKVFE=", "dev": true }, - "node_modules/lodash.once": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/lodash.once/-/lodash.once-4.1.1.tgz", - "integrity": "sha1-DdOXEhPHxW34gJd9UEyI+0cal6w=", - "dev": true - }, "node_modules/lodash.sortby": { "version": "4.7.0", "resolved": "https://registry.npmjs.org/lodash.sortby/-/lodash.sortby-4.7.0.tgz", @@ -10897,71 +10307,29 @@ }, "node_modules/lru-cache/node_modules/yallist": { "version": "4.0.0", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", - "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==" - }, - "node_modules/make-dir": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-2.1.0.tgz", - "integrity": "sha512-LS9X+dc8KLxXCb8dni79fLIIUA5VyZoyjSMCwTluaXA0o27cCK0bhXkpgw+sTXVpPy/lSO57ilRixqk0vDmtRA==", - "dev": true, - "dependencies": { - "pify": "^4.0.1", - "semver": "^5.6.0" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/make-dir/node_modules/semver": { - "version": "5.7.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", - "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==", - "dev": true, - "bin": { - "semver": "bin/semver" - } - }, - "node_modules/make-iterator": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/make-iterator/-/make-iterator-1.0.1.tgz", - "integrity": "sha512-pxiuXh0iVEq7VM7KMIhs5gxsfxCux2URptUQaXo4iZZJxBAzTPOLE2BumO5dbfVYq/hBJFBR/a1mFDmOx5AGmw==", - "dev": true, - "dependencies": { - "kind-of": "^6.0.2" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/make-iterator/node_modules/kind-of": { - "version": "6.0.3", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.3.tgz", - "integrity": "sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/map-cache": { - "version": "0.2.2", - "resolved": "https://registry.npmjs.org/map-cache/-/map-cache-0.2.2.tgz", - "integrity": "sha1-wyq9C9ZSXZsFFkW7TyasXcmKDb8=", - "dev": true, - "engines": { - "node": ">=0.10.0" - } + "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==" }, - "node_modules/map-visit": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/map-visit/-/map-visit-1.0.0.tgz", - "integrity": "sha1-7Nyo8TFE5mDxtb1B8S80edmN+48=", + "node_modules/make-dir": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-2.1.0.tgz", + "integrity": "sha512-LS9X+dc8KLxXCb8dni79fLIIUA5VyZoyjSMCwTluaXA0o27cCK0bhXkpgw+sTXVpPy/lSO57ilRixqk0vDmtRA==", "dev": true, "dependencies": { - "object-visit": "^1.0.0" + "pify": "^4.0.1", + "semver": "^5.6.0" }, "engines": { - "node": ">=0.10.0" + "node": ">=6" + } + }, + "node_modules/make-dir/node_modules/semver": { + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", + "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==", + "dev": true, + "bin": { + "semver": "bin/semver" } }, "node_modules/mapcap": { @@ -11175,52 +10543,6 @@ "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", "dev": true }, - "node_modules/mixin-deep": { - "version": "1.3.2", - "resolved": "https://registry.npmjs.org/mixin-deep/-/mixin-deep-1.3.2.tgz", - "integrity": "sha512-WRoDn//mXBiJ1H40rqa3vH0toePwSsGb45iInWlTySa+Uu4k3tYUSxa2v1KqAiLtvlrSzaExqS1gtk96A9zvEA==", - "dev": true, - "dependencies": { - "for-in": "^1.0.2", - "is-extendable": "^1.0.1" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/mixin-deep/node_modules/is-extendable": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-1.0.1.tgz", - "integrity": "sha512-arnXMxT1hhoKo9k1LZdmlNyJdDDfy2v0fXjFlmok4+i8ul/6WlbVge9bhM74OpNPQPMGUToDtz+KXa1PneJxOA==", - "dev": true, - "dependencies": { - "is-plain-object": "^2.0.4" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/mixin-deep/node_modules/is-plain-object": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-2.0.4.tgz", - "integrity": "sha512-h5PpgXkWitc38BBMYawTYMWJHFZJVnBquFE57xFpjB8pJFiF6gZ+bU+WyI/yqXiFR5mdLsgYNaPe8uao6Uv9Og==", - "dev": true, - "dependencies": { - "isobject": "^3.0.1" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/mixme": { - "version": "0.5.4", - "resolved": "https://registry.npmjs.org/mixme/-/mixme-0.5.4.tgz", - "integrity": "sha512-3KYa4m4Vlqx98GPdOHghxSdNtTvcP8E0kkaJ5Dlh+h2DRzF7zpuVVcA8B0QpKd11YJeP9QQ7ASkKzOeu195Wzw==", - "dev": true, - "engines": { - "node": ">= 8.0.0" - } - }, "node_modules/mkdirp": { "version": "0.5.6", "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.6.tgz", @@ -11238,26 +10560,16 @@ "resolved": "https://registry.npmjs.org/module-details-from-path/-/module-details-from-path-1.0.3.tgz", "integrity": "sha1-EUyUlnPiqKNenTV4hSeqN7Z52is=" }, - "node_modules/moment": { - "version": "2.29.4", - "resolved": "https://registry.npmjs.org/moment/-/moment-2.29.4.tgz", - "integrity": "sha512-5LC9SOxjSc2HF6vO2CyuTDNivEdoz2IvyJJGj6X8DJ0eFyfszE0QiEd+iXmBvUP3WHxSjFH/vIsA0EN00cgr8w==", - "dev": true, - "optional": true, - "engines": { - "node": "*" - } - }, "node_modules/mongodb": { - "version": "4.6.0", - "resolved": "https://registry.npmjs.org/mongodb/-/mongodb-4.6.0.tgz", - "integrity": "sha512-1gsxVXmjFTPJ+CkMG9olE4bcVsyY8lBJN9m5B5vj+LZ7wkBqq3PO8RVmNX9GwCBOBz1KV0zM00vPviUearSv7A==", + "version": "4.10.0", + "resolved": "https://registry.npmjs.org/mongodb/-/mongodb-4.10.0.tgz", + "integrity": "sha512-My2QxLTw0Cc1O9gih0mz4mqo145Jq4rLAQx0Glk/Ha9iYBzYpt4I2QFNRIh35uNFNfe8KFQcdwY1/HKxXBkinw==", "dev": true, "dependencies": { - "bson": "^4.6.3", - "denque": "^2.0.1", - "mongodb-connection-string-url": "^2.5.2", - "socks": "^2.6.2" + "bson": "^4.7.0", + "denque": "^2.1.0", + "mongodb-connection-string-url": "^2.5.3", + "socks": "^2.7.0" }, "engines": { "node": ">=12.9.0" @@ -11267,9 +10579,9 @@ } }, "node_modules/mongodb-connection-string-url": { - "version": "2.5.2", - "resolved": "https://registry.npmjs.org/mongodb-connection-string-url/-/mongodb-connection-string-url-2.5.2.tgz", - "integrity": "sha512-tWDyIG8cQlI5k3skB6ywaEA5F9f5OntrKKsT/Lteub2zgwSUlhqEN2inGgBTm8bpYJf8QYBdA/5naz65XDpczA==", + "version": "2.5.3", + "resolved": "https://registry.npmjs.org/mongodb-connection-string-url/-/mongodb-connection-string-url-2.5.3.tgz", + "integrity": "sha512-f+/WsED+xF4B74l3k9V/XkTVj5/fxFH2o5ToKXd8Iyi5UhM+sO9u0Ape17Mvl/GkZaFtM0HQnzAG5OTmhKw+tQ==", "dev": true, "dependencies": { "@types/whatwg-url": "^8.2.1", @@ -11334,9 +10646,9 @@ } }, "node_modules/mongodb/node_modules/denque": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/denque/-/denque-2.0.1.tgz", - "integrity": "sha512-tfiWc6BQLXNLpNiR5iGd0Ocu3P3VpxfzFiqubLgMfhfOw9WyvgJBd46CClNn9k3qfbjvT//0cf7AlYRX/OslMQ==", + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/denque/-/denque-2.1.0.tgz", + "integrity": "sha512-HVQE3AAb/pxF8fQAoiqpvg9i3evqug3hoiwakOyZAwJm+6vZehbkYXZ0l4JxS+I3QxM97v5aaRNhj8v5oBhekw==", "dev": true, "engines": { "node": ">=0.10" @@ -11358,51 +10670,6 @@ "integrity": "sha512-nnbWWOkoWyUsTjKrhgD0dcz22mdkSnpYqbEjIm2nhwhuxlSkpywJmBo8h0ZqJdkp73mb90SssHkN4rsRaBAfAA==", "dev": true }, - "node_modules/mv": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/mv/-/mv-2.1.1.tgz", - "integrity": "sha1-rmzg1vbV4KT32JN5jQPB6pVZtqI=", - "dev": true, - "optional": true, - "dependencies": { - "mkdirp": "~0.5.1", - "ncp": "~2.0.0", - "rimraf": "~2.4.0" - }, - "engines": { - "node": ">=0.8.0" - } - }, - "node_modules/mv/node_modules/glob": { - "version": "6.0.4", - "resolved": "https://registry.npmjs.org/glob/-/glob-6.0.4.tgz", - "integrity": "sha1-DwiGD2oVUSey+t1PnOJLGqtuTSI=", - "dev": true, - "optional": true, - "dependencies": { - "inflight": "^1.0.4", - "inherits": "2", - "minimatch": "2 || 3", - "once": "^1.3.0", - "path-is-absolute": "^1.0.0" - }, - "engines": { - "node": "*" - } - }, - "node_modules/mv/node_modules/rimraf": { - "version": "2.4.5", - "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.4.5.tgz", - "integrity": "sha1-7nEM5dk6j9uFb7Xqj/Di11k0sto=", - "dev": true, - "optional": true, - "dependencies": { - "glob": "^6.0.1" - }, - "bin": { - "rimraf": "bin.js" - } - }, "node_modules/mysql": { "version": "2.18.1", "resolved": "https://registry.npmjs.org/mysql/-/mysql-2.18.1.tgz", @@ -11514,43 +10781,12 @@ } }, "node_modules/nan": { - "version": "2.15.0", - "resolved": "https://registry.npmjs.org/nan/-/nan-2.15.0.tgz", - "integrity": "sha512-8ZtvEnA2c5aYCZYd1cvgdnU6cqwixRoYg70xPLWUws5ORTa/lnw+u4amixRS/Ac5U5mQVgp9pnlSUnbNWFaWZQ==", + "version": "2.17.0", + "resolved": "https://registry.npmjs.org/nan/-/nan-2.17.0.tgz", + "integrity": "sha512-2ZTgtl0nJsO0KQCjEpxcIr5D+Yv90plTitZt9JBfQvVJDS5seMl3FOvsh3+9CoYWXf/1l5OaZzzF6nDm4cagaQ==", "dev": true, "optional": true }, - "node_modules/nanomatch": { - "version": "1.2.13", - "resolved": "https://registry.npmjs.org/nanomatch/-/nanomatch-1.2.13.tgz", - "integrity": "sha512-fpoe2T0RbHwBTBUOftAfBPaDEi06ufaUai0mE6Yn1kacc3SnTErfb/h+X94VXzI64rKFHYImXSvdwGGCmwOqCA==", - "dev": true, - "dependencies": { - "arr-diff": "^4.0.0", - "array-unique": "^0.3.2", - "define-property": "^2.0.2", - "extend-shallow": "^3.0.2", - "fragment-cache": "^0.2.1", - "is-windows": "^1.0.2", - "kind-of": "^6.0.2", - "object.pick": "^1.3.0", - "regex-not": "^1.0.0", - "snapdragon": "^0.8.1", - "to-regex": "^3.0.1" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/nanomatch/node_modules/kind-of": { - "version": "6.0.3", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.3.tgz", - "integrity": "sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/native-duplexpair": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/native-duplexpair/-/native-duplexpair-1.0.0.tgz", @@ -11563,16 +10799,6 @@ "integrity": "sha1-Sr6/7tdUHywnrPspvbvRXI1bpPc=", "dev": true }, - "node_modules/ncp": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ncp/-/ncp-2.0.0.tgz", - "integrity": "sha1-GVoh1sRuNh0vsSgbo4uR6d9727M=", - "dev": true, - "optional": true, - "bin": { - "ncp": "bin/ncp" - } - }, "node_modules/ndjson": { "version": "1.5.0", "resolved": "https://registry.npmjs.org/ndjson/-/ndjson-1.5.0.tgz", @@ -11684,9 +10910,9 @@ } }, "node_modules/node-releases": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.4.tgz", - "integrity": "sha512-gbMzqQtTtDz/00jQzZ21PQzdI9PyLYqUSvD0p3naOhX4odFji0ZxYdnVwPTxmSwkmxhcFImpozceidSG+AgoPQ==", + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.6.tgz", + "integrity": "sha512-PiVXnNuFm5+iYkLBNeq5211hvO38y63T0i2KKh2KnUs3RpzJ+JtODFjkD8yjLwnDkTYF1eKXheUwdssR+NRZdg==", "dev": true }, "node_modules/normalize-package-data": { @@ -11965,32 +11191,6 @@ "node": ">=0.10.0" } }, - "node_modules/object-copy": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/object-copy/-/object-copy-0.1.0.tgz", - "integrity": "sha1-fn2Fi3gb18mRpBupde04EnVOmYw=", - "dev": true, - "dependencies": { - "copy-descriptor": "^0.1.0", - "define-property": "^0.2.5", - "kind-of": "^3.0.3" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/object-copy/node_modules/define-property": { - "version": "0.2.5", - "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", - "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", - "dev": true, - "dependencies": { - "is-descriptor": "^0.1.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/object-filter-sequence": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/object-filter-sequence/-/object-filter-sequence-1.0.0.tgz", @@ -12005,9 +11205,9 @@ } }, "node_modules/object-inspect": { - "version": "1.12.0", - "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.12.0.tgz", - "integrity": "sha512-Ho2z80bVIvJloH+YzRmpZVQe87+qASmBUKZDWgx9cu+KDrX2ZDH/3tMy+gXbZETVGs2M8YdxObOh7XAtim9Y0g==", + "version": "1.12.2", + "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.12.2.tgz", + "integrity": "sha512-z+cPxW0QGUp0mcqcsgQyLVRDoXFQbXOwBaqyF7VIgI4TWNQsDHrBpUQslRmIfAoYWdYzs6UlKJtB2XJpTaNSpQ==", "funding": { "url": "https://github.com/sponsors/ljharb" } @@ -12036,26 +11236,14 @@ "node": ">= 0.4" } }, - "node_modules/object-visit": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/object-visit/-/object-visit-1.0.1.tgz", - "integrity": "sha1-95xEk68MU3e1n+OdOV5BBC3QRbs=", - "dev": true, - "dependencies": { - "isobject": "^3.0.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/object.assign": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/object.assign/-/object.assign-4.1.2.tgz", - "integrity": "sha512-ixT2L5THXsApyiUPYKmW+2EHpXXe5Ii3M+f4e+aJFAHao5amFRW6J0OO6c/LU8Be47utCx2GL89hxGB6XSmKuQ==", + "version": "4.1.4", + "resolved": "https://registry.npmjs.org/object.assign/-/object.assign-4.1.4.tgz", + "integrity": "sha512-1mxKf0e58bvyjSCtKYY4sRe9itRk3PJpquJOjeIkz885CczcI4IvJJDLPS72oowuSh+pBxUFROpX+TU++hxhZQ==", "dependencies": { - "call-bind": "^1.0.0", - "define-properties": "^1.1.3", - "has-symbols": "^1.0.1", + "call-bind": "^1.0.2", + "define-properties": "^1.1.4", + "has-symbols": "^1.0.3", "object-keys": "^1.1.1" }, "engines": { @@ -12065,21 +11253,6 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/object.defaults": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/object.defaults/-/object.defaults-1.1.0.tgz", - "integrity": "sha1-On+GgzS0B96gbaFtiNXNKeQ1/s8=", - "dev": true, - "dependencies": { - "array-each": "^1.0.1", - "array-slice": "^1.0.0", - "for-own": "^1.0.0", - "isobject": "^3.0.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/object.entries": { "version": "1.1.5", "resolved": "https://registry.npmjs.org/object.entries/-/object.entries-1.1.5.tgz", @@ -12093,31 +11266,6 @@ "node": ">= 0.4" } }, - "node_modules/object.map": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/object.map/-/object.map-1.0.1.tgz", - "integrity": "sha1-z4Plncj8wK1fQlDh94s7gb2AHTc=", - "dev": true, - "dependencies": { - "for-own": "^1.0.0", - "make-iterator": "^1.0.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/object.pick": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/object.pick/-/object.pick-1.3.0.tgz", - "integrity": "sha1-h6EKxMFpS9Lhy/U1kaZhQftd10c=", - "dev": true, - "dependencies": { - "isobject": "^3.0.1" - }, - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/object.values": { "version": "1.1.5", "resolved": "https://registry.npmjs.org/object.values/-/object.values-1.1.5.tgz", @@ -12142,9 +11290,9 @@ "dev": true }, "node_modules/on-exit-leak-free": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/on-exit-leak-free/-/on-exit-leak-free-1.0.0.tgz", - "integrity": "sha512-Ve8ubhrXRdnuCJ5bQSQpP3uaV43K1PMcOfSRC1pqHgRZommXCgsXwh08jVC5NpjwScE23BPDwDvVg4cov3mwjw==", + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/on-exit-leak-free/-/on-exit-leak-free-2.1.0.tgz", + "integrity": "sha512-VuCaZZAjReZ3vUwgOB8LxAosIurDiAW0s13rI1YwmaP++jvcxP77AWoQvenZebpCA2m8WC1/EosPYPMjnRAp/w==", "dev": true }, "node_modules/on-finished": { @@ -12439,29 +11587,6 @@ "node": ">=6" } }, - "node_modules/parse-filepath": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/parse-filepath/-/parse-filepath-1.0.2.tgz", - "integrity": "sha1-pjISf1Oq89FYdvWHLz/6x2PWyJE=", - "dev": true, - "dependencies": { - "is-absolute": "^1.0.0", - "map-cache": "^0.2.0", - "path-root": "^0.1.1" - }, - "engines": { - "node": ">=0.8" - } - }, - "node_modules/parse-passwd": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/parse-passwd/-/parse-passwd-1.0.0.tgz", - "integrity": "sha1-bVuTSkVpk7I9N/QKOC1vFmao5cY=", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/parseurl": { "version": "1.3.3", "resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.3.tgz", @@ -12471,15 +11596,6 @@ "node": ">= 0.8" } }, - "node_modules/pascalcase": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/pascalcase/-/pascalcase-0.1.1.tgz", - "integrity": "sha1-s2PlXoAGym/iF4TS2yK9FdeRfxQ=", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/path-exists": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", @@ -12512,27 +11628,6 @@ "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz", "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==" }, - "node_modules/path-root": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/path-root/-/path-root-0.1.1.tgz", - "integrity": "sha1-mkpoFMrBwM1zNgqV8yCDyOpHRbc=", - "dev": true, - "dependencies": { - "path-root-regex": "^0.1.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/path-root-regex": { - "version": "0.1.2", - "resolved": "https://registry.npmjs.org/path-root-regex/-/path-root-regex-0.1.2.tgz", - "integrity": "sha1-v8zcjfWxLcUsi0PsONGNcsBLqW0=", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/path-to-regexp": { "version": "6.2.1", "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-6.2.1.tgz", @@ -12555,15 +11650,15 @@ "dev": true }, "node_modules/pg": { - "version": "8.7.3", - "resolved": "https://registry.npmjs.org/pg/-/pg-8.7.3.tgz", - "integrity": "sha512-HPmH4GH4H3AOprDJOazoIcpI49XFsHCe8xlrjHkWiapdbHK+HLtbm/GQzXYAZwmPju/kzKhjaSfMACG+8cgJcw==", + "version": "8.8.0", + "resolved": "https://registry.npmjs.org/pg/-/pg-8.8.0.tgz", + "integrity": "sha512-UXYN0ziKj+AeNNP7VDMwrehpACThH7LUl/p8TDFpEUuSejCUIwGSfxpHsPvtM6/WXFy6SU4E5RG4IJV/TZAGjw==", "dev": true, "dependencies": { "buffer-writer": "2.0.0", "packet-reader": "1.0.0", "pg-connection-string": "^2.5.0", - "pg-pool": "^3.5.1", + "pg-pool": "^3.5.2", "pg-protocol": "^1.5.0", "pg-types": "^2.1.0", "pgpass": "1.x" @@ -12572,7 +11667,7 @@ "node": ">= 8.0.0" }, "peerDependencies": { - "pg-native": ">=2.0.0" + "pg-native": ">=3.0.1" }, "peerDependenciesMeta": { "pg-native": { @@ -12581,9 +11676,9 @@ } }, "node_modules/pg-connection-string": { - "version": "2.4.0", - "resolved": "https://registry.npmjs.org/pg-connection-string/-/pg-connection-string-2.4.0.tgz", - "integrity": "sha512-3iBXuv7XKvxeMrIgym7njT+HlZkwZqqGX4Bu9cci8xHZNT+Um1gWKqCsAzcC0d95rcKMU5WBg6YRUcHyV0HZKQ==", + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/pg-connection-string/-/pg-connection-string-2.5.0.tgz", + "integrity": "sha512-r5o/V/ORTA6TmUnyWZR9nCj1klXCO2CEKNRlVuJptZe85QuhFayC7WeMic7ndayT5IRIR0S0xFxFi2ousartlQ==", "dev": true }, "node_modules/pg-int8": { @@ -12596,9 +11691,9 @@ } }, "node_modules/pg-pool": { - "version": "3.5.1", - "resolved": "https://registry.npmjs.org/pg-pool/-/pg-pool-3.5.1.tgz", - "integrity": "sha512-6iCR0wVrro6OOHFsyavV+i6KYL4lVNyYAB9RD18w66xSzN+d8b66HiwuP30Gp1SH5O9T82fckkzsRjlrhD0ioQ==", + "version": "3.5.2", + "resolved": "https://registry.npmjs.org/pg-pool/-/pg-pool-3.5.2.tgz", + "integrity": "sha512-His3Fh17Z4eg7oANLob6ZvH8xIVen3phEZh2QuyrIl4dQSDVEabNducv6ysROKpDNPSD+12tONZVWfSgMvDD9w==", "dev": true, "peerDependencies": { "pg": ">=8.0" @@ -12626,12 +11721,6 @@ "node": ">=4" } }, - "node_modules/pg/node_modules/pg-connection-string": { - "version": "2.5.0", - "resolved": "https://registry.npmjs.org/pg-connection-string/-/pg-connection-string-2.5.0.tgz", - "integrity": "sha512-r5o/V/ORTA6TmUnyWZR9nCj1klXCO2CEKNRlVuJptZe85QuhFayC7WeMic7ndayT5IRIR0S0xFxFi2ousartlQ==", - "dev": true - }, "node_modules/pgpass": { "version": "1.0.5", "resolved": "https://registry.npmjs.org/pgpass/-/pgpass-1.0.5.tgz", @@ -12669,15 +11758,15 @@ } }, "node_modules/pidusage": { - "version": "2.0.21", - "resolved": "https://registry.npmjs.org/pidusage/-/pidusage-2.0.21.tgz", - "integrity": "sha512-cv3xAQos+pugVX+BfXpHsbyz/dLzX+lr44zNMsYiGxUw+kV5sgQCIcLd1z+0vq+KyC7dJ+/ts2PsfgWfSC3WXA==", + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/pidusage/-/pidusage-3.0.2.tgz", + "integrity": "sha512-g0VU+y08pKw5M8EZ2rIGiEBaB8wrQMjYGFfW2QVIfyT8V+fq8YFLkvlz4bz5ljvFDJYNFCWT3PWqcRr2FKO81w==", "dev": true, "dependencies": { "safe-buffer": "^5.2.1" }, "engines": { - "node": ">=8" + "node": ">=10" } }, "node_modules/pidusage/node_modules/safe-buffer": { @@ -12726,14 +11815,82 @@ "pino": "bin.js" } }, - "node_modules/pino-abstract-transport": { - "version": "0.5.0", - "resolved": "https://registry.npmjs.org/pino-abstract-transport/-/pino-abstract-transport-0.5.0.tgz", - "integrity": "sha512-+KAgmVeqXYbTtU2FScx1XS3kNyfZ5TrXY07V96QnUSFqo2gAqlvmaxH67Lj7SWazqsMabf+58ctdTcBgnOLUOQ==", + "node_modules/pino-abstract-transport": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/pino-abstract-transport/-/pino-abstract-transport-1.0.0.tgz", + "integrity": "sha512-c7vo5OpW4wIS42hUVcT5REsL8ZljsUfBjqV/e2sFxmFEFZiq1XLUp5EYLtuDH6PEHq9W1egWqRbnLUP5FuZmOA==", + "dev": true, + "dependencies": { + "readable-stream": "^4.0.0", + "split2": "^4.0.0" + } + }, + "node_modules/pino-abstract-transport/node_modules/buffer": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/buffer/-/buffer-6.0.3.tgz", + "integrity": "sha512-FTiCpNxtwiZZHEZbcbTIcZjERVICn9yq/pDFkTl95/AxzD1naBctN7YO68riM/gLSDY7sdrMby8hofADYuuqOA==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "dependencies": { + "base64-js": "^1.3.1", + "ieee754": "^1.2.1" + } + }, + "node_modules/pino-abstract-transport/node_modules/events": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/events/-/events-3.3.0.tgz", + "integrity": "sha512-mQw+2fkQbALzQ7V0MY0IqdnXNOeTtP4r0lN9z7AAawCXgqea7bDii20AYrIBrFd/Hx0M2Ocz6S111CaFkUcb0Q==", + "dev": true, + "engines": { + "node": ">=0.8.x" + } + }, + "node_modules/pino-abstract-transport/node_modules/ieee754": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.2.1.tgz", + "integrity": "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ] + }, + "node_modules/pino-abstract-transport/node_modules/readable-stream": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-4.2.0.tgz", + "integrity": "sha512-gJrBHsaI3lgBoGMW/jHZsQ/o/TIWiu5ENCJG1BB7fuCKzpFM8GaS2UoBVt9NO+oI+3FcrBNbUkl3ilDe09aY4A==", "dev": true, "dependencies": { - "duplexify": "^4.1.2", - "split2": "^4.0.0" + "abort-controller": "^3.0.0", + "buffer": "^6.0.3", + "events": "^3.3.0", + "process": "^0.11.10" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" } }, "node_modules/pino-abstract-transport/node_modules/split2": { @@ -12826,15 +11983,6 @@ "integrity": "sha512-fnWVljUchTro6RiCFvCXBbNhJc2NijN7oIQxbwsyL0buWJPG85v81ehlHI9fXrJsMNgTofEoWIQeClKpgxFLrg==", "dev": true }, - "node_modules/posix-character-classes": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/posix-character-classes/-/posix-character-classes-0.1.1.tgz", - "integrity": "sha1-AerA/jta9xoqbAL+q7jB/vfgDqs=", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/postgres-array": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/postgres-array/-/postgres-array-2.0.0.tgz", @@ -13179,9 +12327,9 @@ } }, "node_modules/qs": { - "version": "6.10.3", - "resolved": "https://registry.npmjs.org/qs/-/qs-6.10.3.tgz", - "integrity": "sha512-wr7M2E0OFRfIfJZjKGieI8lBKb7fRCH4Fv5KNPEs7gJ8jadvotdsS08PzOKR7opXhZ/Xkjtt3WF9g38drmyRqQ==", + "version": "6.11.0", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.11.0.tgz", + "integrity": "sha512-MvjoMCJwEarSbUYk5O+nmoSzSutSsTwF85zcHPQ9OrlFoZOYIjaqBAJIqIXjptyD5vThxGq52Xu/MaJzRkIk4Q==", "dev": true, "dependencies": { "side-channel": "^1.0.4" @@ -13337,51 +12485,40 @@ } }, "node_modules/real-require": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/real-require/-/real-require-0.1.0.tgz", - "integrity": "sha512-r/H9MzAWtrv8aSVjPCMFpDMl5q66GqtmmRkRjpHTsp4zBAa+snZyiQNlMONiUmEJcsnaw0wCauJ2GWODr/aFkg==", + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/real-require/-/real-require-0.2.0.tgz", + "integrity": "sha512-57frrGM/OCTLqLOAh0mhVA9VBMHd+9U7Zb2THMGdBUoZVOtGbJzjxsYGDJ3A9AYYCP4hn6y1TVbaOfzWtm5GFg==", "dev": true, "engines": { "node": ">= 12.13.0" } }, "node_modules/rechoir": { - "version": "0.6.2", - "resolved": "https://registry.npmjs.org/rechoir/-/rechoir-0.6.2.tgz", - "integrity": "sha1-hSBLVNuoLVdC4oyWdW70OvUOM4Q=", + "version": "0.7.0", + "resolved": "https://registry.npmjs.org/rechoir/-/rechoir-0.7.0.tgz", + "integrity": "sha512-ADsDEH2bvbjltXEP+hTIAmeFekTFK0V2BTxMkok6qILyAJEXV0AFfoWcAq4yfll5VdIMd/RVXq0lR+wQi5ZU3Q==", "dev": true, "dependencies": { - "resolve": "^1.1.6" + "resolve": "^1.9.0" }, "engines": { "node": ">= 0.10" } }, "node_modules/redis": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/redis/-/redis-3.1.2.tgz", - "integrity": "sha512-grn5KoZLr/qrRQVwoSkmzdbw6pwF+/rwODtrOr6vuBRiR/f3rjSTGupbF90Zpqm2oenix8Do6RV7pYEkGwlKkw==", + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/redis/-/redis-4.3.1.tgz", + "integrity": "sha512-cM7yFU5CA6zyCF7N/+SSTcSJQSRMEKN0k0Whhu6J7n9mmXRoXugfWDBo5iOzGwABmsWKSwGPTU5J4Bxbl+0mrA==", "dev": true, "dependencies": { - "denque": "^1.5.0", - "redis-commands": "^1.7.0", - "redis-errors": "^1.2.0", - "redis-parser": "^3.0.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/node-redis" + "@redis/bloom": "1.0.2", + "@redis/client": "1.3.0", + "@redis/graph": "1.0.1", + "@redis/json": "1.0.4", + "@redis/search": "1.1.0", + "@redis/time-series": "1.0.3" } }, - "node_modules/redis-commands": { - "version": "1.7.0", - "resolved": "https://registry.npmjs.org/redis-commands/-/redis-commands-1.7.0.tgz", - "integrity": "sha512-nJWqw3bTFy21hX/CPKHth6sfhZbdiHP6bTawSgQBlKOVRG7EZkfHbbHwQJnrE4vsQf0CMNE+3gJ4Fmm16vdVlQ==", - "dev": true - }, "node_modules/redis-errors": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/redis-errors/-/redis-errors-1.2.0.tgz", @@ -13436,19 +12573,6 @@ "@babel/runtime": "^7.8.4" } }, - "node_modules/regex-not": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/regex-not/-/regex-not-1.0.2.tgz", - "integrity": "sha512-J6SDjUgDxQj5NusnOtdFxDwN/+HWykR8GELwctJ7mdqhcyy1xEc4SRFHUXvxTp661YaVKAjfRLZ9cCqS6tn32A==", - "dev": true, - "dependencies": { - "extend-shallow": "^3.0.2", - "safe-regex": "^1.1.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/regexp.prototype.flags": { "version": "1.4.3", "resolved": "https://registry.npmjs.org/regexp.prototype.flags/-/regexp.prototype.flags-1.4.3.tgz", @@ -13535,24 +12659,6 @@ "node": ">=4" } }, - "node_modules/repeat-element": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/repeat-element/-/repeat-element-1.1.4.tgz", - "integrity": "sha512-LFiNfRcSu7KK3evMyYOuCzv3L10TW7yC1G2/+StMjK8Y6Vqd2MG7r/Qjw4ghtuCOjFvlnms/iMmLqpvW/ES/WQ==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/repeat-string": { - "version": "1.6.1", - "resolved": "https://registry.npmjs.org/repeat-string/-/repeat-string-1.6.1.tgz", - "integrity": "sha1-jcrkcOHIirwtYA//Sndihtp15jc=", - "dev": true, - "engines": { - "node": ">=0.10" - } - }, "node_modules/request": { "version": "2.88.2", "resolved": "https://registry.npmjs.org/request/-/request-2.88.2.tgz", @@ -13651,13 +12757,16 @@ } }, "node_modules/require-in-the-middle": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/require-in-the-middle/-/require-in-the-middle-5.1.0.tgz", - "integrity": "sha512-M2rLKVupQfJ5lf9OvqFGIT+9iVLnTmjgbOmpil12hiSQNn5zJTKGPoIisETNjfK+09vP3rpm1zJajmErpr2sEQ==", + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/require-in-the-middle/-/require-in-the-middle-5.2.0.tgz", + "integrity": "sha512-efCx3b+0Z69/LGJmm9Yvi4cqEdxnoGnxYxGxBghkkTTFeXRtTCmmhO0AnAfHz59k957uTSuy8WaHqOs8wbYUWg==", "dependencies": { "debug": "^4.1.1", "module-details-from-path": "^1.0.3", - "resolve": "^1.12.0" + "resolve": "^1.22.1" + }, + "engines": { + "node": ">=6" } }, "node_modules/require-main-filename": { @@ -13676,11 +12785,11 @@ } }, "node_modules/resolve": { - "version": "1.22.0", - "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.0.tgz", - "integrity": "sha512-Hhtrw0nLeSrFQ7phPp4OOcVjLPIeMnRlr5mcnVuMe7M/7eBn98A3hmFRLoFo3DLZkivSYwhRUJTyPyWAk56WLw==", + "version": "1.22.1", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.1.tgz", + "integrity": "sha512-nBpuuYuY5jFsli/JIs1oldw6fOQCBioohqWZg/2hiaOybXOft4lonv85uDOKXdf8rhyK159cxU5cDcK/NKk8zw==", "dependencies": { - "is-core-module": "^2.8.1", + "is-core-module": "^2.9.0", "path-parse": "^1.0.7", "supports-preserve-symlinks-flag": "^1.0.0" }, @@ -13697,19 +12806,6 @@ "integrity": "sha512-0a1F4l73/ZFZOakJnQ3FvkJ2+gSTQWz/r2KE5OdDY0TxPm5h4GkqkWWfM47T7HsbnOtcJVEF4epCVy6u7Q3K+g==", "dev": true }, - "node_modules/resolve-dir": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/resolve-dir/-/resolve-dir-1.0.1.tgz", - "integrity": "sha1-eaQGRMNivoLybv/nOcm7U4IEb0M=", - "dev": true, - "dependencies": { - "expand-tilde": "^2.0.0", - "global-modules": "^1.0.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/resolve-from": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz", @@ -13719,13 +12815,6 @@ "node": ">=4" } }, - "node_modules/resolve-url": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/resolve-url/-/resolve-url-0.2.1.tgz", - "integrity": "sha1-LGN/53yJOv0qZj/iGqkIAGjiBSo=", - "deprecated": "https://github.com/lydell/resolve-url#deprecated", - "dev": true - }, "node_modules/responselike": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/responselike/-/responselike-2.0.0.tgz", @@ -13736,41 +12825,41 @@ } }, "node_modules/restify": { - "version": "8.6.1", - "resolved": "https://registry.npmjs.org/restify/-/restify-8.6.1.tgz", - "integrity": "sha512-I54/Geo2qN4K/2Ers+zNAU/A/nwPrcoTVBVeamw/sROv/kLLuMAzidLmO3f6842tKFxxQvcNhOMYoWZAhYr3vQ==", + "version": "10.0.0", + "resolved": "https://registry.npmjs.org/restify/-/restify-10.0.0.tgz", + "integrity": "sha512-J57tSX1EPGbqVBznQ619zyFMFQno750d3lDfocTiblcQd5FZhCLD26hcW/u7hrXWetltsxoPZv/86Jc9acKfaQ==", "dev": true, "dependencies": { "assert-plus": "^1.0.0", - "bunyan": "^1.8.12", - "csv": "^5.1.1", + "csv": "^6.2.2", "escape-regexp-component": "^1.0.2", "ewma": "^2.0.1", - "find-my-way": "^2.0.1", + "find-my-way": "^7.2.0", "formidable": "^1.2.1", - "http-signature": "^1.2.0", + "http-signature": "^1.3.6", "lodash": "^4.17.11", - "lru-cache": "^5.1.1", - "mime": "^2.4.3", + "lru-cache": "^7.14.1", + "mime": "^3.0.0", "negotiator": "^0.6.2", "once": "^1.4.0", - "pidusage": "^2.0.17", + "pidusage": "^3.0.2", + "pino": "^8.7.0", "qs": "^6.7.0", "restify-errors": "^8.0.2", - "semver": "^6.1.1", - "send": "^0.16.2", + "semver": "^7.3.8", + "send": "^0.18.0", "spdy": "^4.0.0", - "uuid": "^3.3.2", + "uuid": "^9.0.0", "vasync": "^2.2.0" }, "bin": { "report-latency": "bin/report-latency" }, "engines": { - "node": ">=8.3.0" + "node": ">=10.0.0" }, "optionalDependencies": { - "dtrace-provider": "^0.8.1" + "dtrace-provider": "~0.8" } }, "node_modules/restify-errors": { @@ -13787,143 +12876,139 @@ "safe-json-stringify": "^1.0.4" } }, - "node_modules/restify/node_modules/debug": { - "version": "2.6.9", - "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", - "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "node_modules/restify/node_modules/http-signature": { + "version": "1.3.6", + "resolved": "https://registry.npmjs.org/http-signature/-/http-signature-1.3.6.tgz", + "integrity": "sha512-3adrsD6zqo4GsTqtO7FyrejHNv+NgiIfAfv68+jVlFmSr9OGy7zrxONceFRLKvnnZA5jbxQBX1u9PpB6Wi32Gw==", "dev": true, "dependencies": { - "ms": "2.0.0" + "assert-plus": "^1.0.0", + "jsprim": "^2.0.2", + "sshpk": "^1.14.1" + }, + "engines": { + "node": ">=0.10" } }, - "node_modules/restify/node_modules/destroy": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/destroy/-/destroy-1.0.4.tgz", - "integrity": "sha1-l4hXRCxEdJ5CBmE+N5RiBYJqvYA=", - "dev": true - }, - "node_modules/restify/node_modules/http-errors": { - "version": "1.6.3", - "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-1.6.3.tgz", - "integrity": "sha1-i1VoC7S+KDoLW/TqLjhYC+HZMg0=", + "node_modules/restify/node_modules/jsprim": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/jsprim/-/jsprim-2.0.2.tgz", + "integrity": "sha512-gqXddjPqQ6G40VdnI6T6yObEC+pDNvyP95wdQhkWkg7crHH3km5qP1FsOXEkzEQwnz6gz5qGTn1c2Y52wP3OyQ==", "dev": true, + "engines": [ + "node >=0.6.0" + ], "dependencies": { - "depd": "~1.1.2", - "inherits": "2.0.3", - "setprototypeof": "1.1.0", - "statuses": ">= 1.4.0 < 2" - }, - "engines": { - "node": ">= 0.6" + "assert-plus": "1.0.0", + "extsprintf": "1.3.0", + "json-schema": "0.4.0", + "verror": "1.10.0" } }, - "node_modules/restify/node_modules/inherits": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz", - "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=", - "dev": true - }, "node_modules/restify/node_modules/lru-cache": { - "version": "5.1.1", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-5.1.1.tgz", - "integrity": "sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==", + "version": "7.14.1", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-7.14.1.tgz", + "integrity": "sha512-ysxwsnTKdAx96aTRdhDOCQfDgbHnt8SK0KY8SEjO0wHinhWOFTESbjVCMPbU1uGXg/ch4lifqx0wfjOawU2+WA==", "dev": true, - "dependencies": { - "yallist": "^3.0.2" + "engines": { + "node": ">=12" } }, "node_modules/restify/node_modules/mime": { - "version": "2.6.0", - "resolved": "https://registry.npmjs.org/mime/-/mime-2.6.0.tgz", - "integrity": "sha512-USPkMeET31rOMiarsBNIHZKLGgvKc/LrjofAnBlOttf5ajRvqiRA8QsenbcooctK6d6Ts6aqZXBA+XbkKthiQg==", + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/mime/-/mime-3.0.0.tgz", + "integrity": "sha512-jSCU7/VB1loIWBZe14aEYHU/+1UMEHoaO7qxCOVJOw9GgH72VAWppxNcjU+x9a2k3GSIBXNKxXQFqRvvZ7vr3A==", "dev": true, "bin": { "mime": "cli.js" }, "engines": { - "node": ">=4.0.0" + "node": ">=10.0.0" + } + }, + "node_modules/restify/node_modules/pino": { + "version": "8.7.0", + "resolved": "https://registry.npmjs.org/pino/-/pino-8.7.0.tgz", + "integrity": "sha512-l9sA5uPxmZzwydhMWUcm1gI0YxNnYl8MfSr2h8cwLvOAzQLBLewzF247h/vqHe3/tt6fgtXeG9wdjjoetdI/vA==", + "dev": true, + "dependencies": { + "atomic-sleep": "^1.0.0", + "fast-redact": "^3.1.1", + "on-exit-leak-free": "^2.1.0", + "pino-abstract-transport": "v1.0.0", + "pino-std-serializers": "^6.0.0", + "process-warning": "^2.0.0", + "quick-format-unescaped": "^4.0.3", + "real-require": "^0.2.0", + "safe-stable-stringify": "^2.3.1", + "sonic-boom": "^3.1.0", + "thread-stream": "^2.0.0" + }, + "bin": { + "pino": "bin.js" } }, - "node_modules/restify/node_modules/ms": { + "node_modules/restify/node_modules/pino-std-serializers": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/pino-std-serializers/-/pino-std-serializers-6.0.0.tgz", + "integrity": "sha512-mMMOwSKrmyl+Y12Ri2xhH1lbzQxwwpuru9VjyJpgFIH4asSj88F2csdMwN6+M5g1Ll4rmsYghHLQJw81tgZ7LQ==", + "dev": true + }, + "node_modules/restify/node_modules/process-warning": { "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", + "resolved": "https://registry.npmjs.org/process-warning/-/process-warning-2.0.0.tgz", + "integrity": "sha512-+MmoAXoUX+VTHAlwns0h+kFUWFs/3FZy+ZuchkgjyOu3oioLAo2LB5aCfKPh2+P9O18i3m43tUEv3YqttSy0Ww==", "dev": true }, - "node_modules/restify/node_modules/on-finished": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.3.0.tgz", - "integrity": "sha1-IPEzZIGwg811M3mSoWlxqi2QaUc=", + "node_modules/restify/node_modules/semver": { + "version": "7.3.8", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.8.tgz", + "integrity": "sha512-NB1ctGL5rlHrPJtFDVIVzTyQylMLu9N9VICA6HSFJo8MCGVTMW6gfpicwKmmK/dAjTOrqu5l63JJOpDSrAis3A==", "dev": true, "dependencies": { - "ee-first": "1.1.1" + "lru-cache": "^6.0.0" + }, + "bin": { + "semver": "bin/semver.js" }, "engines": { - "node": ">= 0.8" + "node": ">=10" } }, - "node_modules/restify/node_modules/send": { - "version": "0.16.2", - "resolved": "https://registry.npmjs.org/send/-/send-0.16.2.tgz", - "integrity": "sha512-E64YFPUssFHEFBvpbbjr44NCLtI1AohxQ8ZSiJjQLskAdKuriYEP6VyGEsRDH8ScozGpkaX1BGvhanqCwkcEZw==", + "node_modules/restify/node_modules/semver/node_modules/lru-cache": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", + "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", "dev": true, "dependencies": { - "debug": "2.6.9", - "depd": "~1.1.2", - "destroy": "~1.0.4", - "encodeurl": "~1.0.2", - "escape-html": "~1.0.3", - "etag": "~1.8.1", - "fresh": "0.5.2", - "http-errors": "~1.6.2", - "mime": "1.4.1", - "ms": "2.0.0", - "on-finished": "~2.3.0", - "range-parser": "~1.2.0", - "statuses": "~1.4.0" + "yallist": "^4.0.0" }, "engines": { - "node": ">= 0.8.0" - } - }, - "node_modules/restify/node_modules/send/node_modules/mime": { - "version": "1.4.1", - "resolved": "https://registry.npmjs.org/mime/-/mime-1.4.1.tgz", - "integrity": "sha512-KI1+qOZu5DcW6wayYHSzR/tXKCDC5Om4s1z2QJjDULzLcmf3DvzS7oluY4HCTrc+9FiKmWUgeNLg7W3uIQvxtQ==", - "dev": true, - "bin": { - "mime": "cli.js" + "node": ">=10" } }, - "node_modules/restify/node_modules/setprototypeof": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.1.0.tgz", - "integrity": "sha512-BvE/TwpZX4FXExxOxZyRGQQv651MSwmWKZGqvmPcRIjDqWub67kTKuIMx43cZZrS/cBBzwBcNDWoFxt2XEFIpQ==", - "dev": true - }, - "node_modules/restify/node_modules/statuses": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/statuses/-/statuses-1.4.0.tgz", - "integrity": "sha512-zhSCtt8v2NDrRlPQpCNtw/heZLtfUDqxBM1udqikb/Hbk52LK4nQSwr10u77iopCW5LsyHpuXS0GnEc48mLeew==", + "node_modules/restify/node_modules/sonic-boom": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/sonic-boom/-/sonic-boom-3.2.0.tgz", + "integrity": "sha512-SbbZ+Kqj/XIunvIAgUZRlqd6CGQYq71tRRbXR92Za8J/R3Yh4Av+TWENiSiEgnlwckYLyP0YZQWVfyNC0dzLaA==", "dev": true, - "engines": { - "node": ">= 0.6" + "dependencies": { + "atomic-sleep": "^1.0.0" } }, "node_modules/restify/node_modules/uuid": { - "version": "3.4.0", - "resolved": "https://registry.npmjs.org/uuid/-/uuid-3.4.0.tgz", - "integrity": "sha512-HjSDRw6gZE5JMggctHBcjVak08+KEVhSIiDzFnT9S9aegmp85S/bReBVTb4QTFaRNptJ9kuYaNhnbNEOkbKb/A==", - "deprecated": "Please upgrade to version 7 or higher. Older versions may use Math.random() in certain circumstances, which is known to be problematic. See https://v8.dev/blog/math-random for details.", + "version": "9.0.0", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-9.0.0.tgz", + "integrity": "sha512-MXcSTerfPa4uqyzStbRoTgt5XIe3x5+42+q1sDuy3R5MDk66URdLMOZe5aPX/SQd+kuYAh0FdP/pO28IkQyTeg==", "dev": true, "bin": { - "uuid": "bin/uuid" + "uuid": "dist/bin/uuid" } }, "node_modules/restify/node_modules/yallist": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz", - "integrity": "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==", + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", "dev": true }, "node_modules/restore-cursor": { @@ -14057,24 +13142,6 @@ "integrity": "sha512-gH8eh2nZudPQO6TytOvbxnuhYBOvDBBLW52tz5q6X58lJcd/tkmqFR+5Z9adS8aJtURSXWThWy/xJtJwixErvg==", "dev": true }, - "node_modules/safe-regex": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/safe-regex/-/safe-regex-1.1.0.tgz", - "integrity": "sha1-QKNmnzsHfR6UPURinhV91IAjvy4=", - "dev": true, - "dependencies": { - "ret": "~0.1.10" - } - }, - "node_modules/safe-regex/node_modules/ret": { - "version": "0.1.15", - "resolved": "https://registry.npmjs.org/ret/-/ret-0.1.15.tgz", - "integrity": "sha512-TTlYpa+OL+vMMNG24xSlQGEJ3B/RzEfUlLct7b5G/ytav+wPrplCpVMFuwzXbkecJrb6IYo1iFb0S9v37754mg==", - "dev": true, - "engines": { - "node": ">=0.12" - } - }, "node_modules/safe-regex2": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/safe-regex2/-/safe-regex2-2.0.0.tgz", @@ -14119,9 +13186,9 @@ "dev": true }, "node_modules/secure-json-parse": { - "version": "2.4.0", - "resolved": "https://registry.npmjs.org/secure-json-parse/-/secure-json-parse-2.4.0.tgz", - "integrity": "sha512-Q5Z/97nbON5t/L/sH6mY2EacfjVGwrCcSi5D3btRO2GZ8pf1K1UN7Z9H5J57hjVU2Qzxr1xO+FmBhOvEkzCMmg==", + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/secure-json-parse/-/secure-json-parse-2.5.0.tgz", + "integrity": "sha512-ZQruFgZnIWH+WyO9t5rWt4ZEGqCKPwhiw+YbzTwpmT9elgLrLcfuyUiSnwwjUiVy9r4VM3urtbNF1xmEh9IL2w==", "dev": true }, "node_modules/select-hose": { @@ -14147,100 +13214,34 @@ "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", "bin": { - "semver": "bin/semver.js" - } - }, - "node_modules/semver-store": { - "version": "0.3.0", - "resolved": "https://registry.npmjs.org/semver-store/-/semver-store-0.3.0.tgz", - "integrity": "sha512-TcZvGMMy9vodEFSse30lWinkj+JgOBvPn8wRItpQRSayhc+4ssDs335uklkfvQQJgL/WvmHLVj4Ycv2s7QCQMg==", - "dev": true - }, - "node_modules/send": { - "version": "0.17.2", - "resolved": "https://registry.npmjs.org/send/-/send-0.17.2.tgz", - "integrity": "sha512-UJYB6wFSJE3G00nEivR5rgWp8c2xXvJ3OPWPhmuteU0IKj8nKbG3DrjiOmLwpnHGYWAVwA69zmTm++YG0Hmwww==", - "dev": true, - "dependencies": { - "debug": "2.6.9", - "depd": "~1.1.2", - "destroy": "~1.0.4", - "encodeurl": "~1.0.2", - "escape-html": "~1.0.3", - "etag": "~1.8.1", - "fresh": "0.5.2", - "http-errors": "1.8.1", - "mime": "1.6.0", - "ms": "2.1.3", - "on-finished": "~2.3.0", - "range-parser": "~1.2.1", - "statuses": "~1.5.0" - }, - "engines": { - "node": ">= 0.8.0" - } - }, - "node_modules/send/node_modules/debug": { - "version": "2.6.9", - "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", - "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", - "dev": true, - "dependencies": { - "ms": "2.0.0" - } - }, - "node_modules/send/node_modules/debug/node_modules/ms": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", - "dev": true - }, - "node_modules/send/node_modules/destroy": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/destroy/-/destroy-1.0.4.tgz", - "integrity": "sha1-l4hXRCxEdJ5CBmE+N5RiBYJqvYA=", - "dev": true - }, - "node_modules/send/node_modules/ms": { - "version": "2.1.3", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", - "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", - "dev": true - }, - "node_modules/send/node_modules/on-finished": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.3.0.tgz", - "integrity": "sha1-IPEzZIGwg811M3mSoWlxqi2QaUc=", - "dev": true, - "dependencies": { - "ee-first": "1.1.1" - }, - "engines": { - "node": ">= 0.8" + "semver": "bin/semver.js" } }, - "node_modules/seq-queue": { - "version": "0.0.5", - "resolved": "https://registry.npmjs.org/seq-queue/-/seq-queue-0.0.5.tgz", - "integrity": "sha1-1WgS4cAXpuTnw+Ojeh2m143TyT4=", - "dev": true - }, - "node_modules/serve-static": { - "version": "1.15.0", - "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.15.0.tgz", - "integrity": "sha512-XGuRDNjXUijsUL0vl6nSD7cwURuzEgglbOaFuZM9g3kwDXOWVTck0jLzjPzGD+TazWbboZYu52/9/XPdUgne9g==", + "node_modules/send": { + "version": "0.18.0", + "resolved": "https://registry.npmjs.org/send/-/send-0.18.0.tgz", + "integrity": "sha512-qqWzuOjSFOuqPjFe4NOsMLafToQQwBSOEpS+FwEt3A2V3vKubTquT3vmLTQpFgMXp8AlFWFuP1qKaJZOtPpVXg==", "dev": true, "dependencies": { + "debug": "2.6.9", + "depd": "2.0.0", + "destroy": "1.2.0", "encodeurl": "~1.0.2", "escape-html": "~1.0.3", - "parseurl": "~1.3.3", - "send": "0.18.0" + "etag": "~1.8.1", + "fresh": "0.5.2", + "http-errors": "2.0.0", + "mime": "1.6.0", + "ms": "2.1.3", + "on-finished": "2.4.1", + "range-parser": "~1.2.1", + "statuses": "2.0.1" }, "engines": { "node": ">= 0.8.0" } }, - "node_modules/serve-static/node_modules/debug": { + "node_modules/send/node_modules/debug": { "version": "2.6.9", "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", @@ -14249,13 +13250,13 @@ "ms": "2.0.0" } }, - "node_modules/serve-static/node_modules/debug/node_modules/ms": { + "node_modules/send/node_modules/debug/node_modules/ms": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", "dev": true }, - "node_modules/serve-static/node_modules/depd": { + "node_modules/send/node_modules/depd": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz", "integrity": "sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==", @@ -14264,7 +13265,7 @@ "node": ">= 0.8" } }, - "node_modules/serve-static/node_modules/http-errors": { + "node_modules/send/node_modules/http-errors": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-2.0.0.tgz", "integrity": "sha512-FtwrG/euBzaEjYeRqOgly7G0qviiXoJWnvEH2Z1plBdXgbyjv34pHTSb9zoeHMyDy33+DWy5Wt9Wo+TURtOYSQ==", @@ -14280,45 +13281,42 @@ "node": ">= 0.8" } }, - "node_modules/serve-static/node_modules/ms": { + "node_modules/send/node_modules/ms": { "version": "2.1.3", "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", "dev": true }, - "node_modules/serve-static/node_modules/send": { - "version": "0.18.0", - "resolved": "https://registry.npmjs.org/send/-/send-0.18.0.tgz", - "integrity": "sha512-qqWzuOjSFOuqPjFe4NOsMLafToQQwBSOEpS+FwEt3A2V3vKubTquT3vmLTQpFgMXp8AlFWFuP1qKaJZOtPpVXg==", + "node_modules/send/node_modules/statuses": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.1.tgz", + "integrity": "sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ==", + "dev": true, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/seq-queue": { + "version": "0.0.5", + "resolved": "https://registry.npmjs.org/seq-queue/-/seq-queue-0.0.5.tgz", + "integrity": "sha1-1WgS4cAXpuTnw+Ojeh2m143TyT4=", + "dev": true + }, + "node_modules/serve-static": { + "version": "1.15.0", + "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.15.0.tgz", + "integrity": "sha512-XGuRDNjXUijsUL0vl6nSD7cwURuzEgglbOaFuZM9g3kwDXOWVTck0jLzjPzGD+TazWbboZYu52/9/XPdUgne9g==", "dev": true, "dependencies": { - "debug": "2.6.9", - "depd": "2.0.0", - "destroy": "1.2.0", "encodeurl": "~1.0.2", "escape-html": "~1.0.3", - "etag": "~1.8.1", - "fresh": "0.5.2", - "http-errors": "2.0.0", - "mime": "1.6.0", - "ms": "2.1.3", - "on-finished": "2.4.1", - "range-parser": "~1.2.1", - "statuses": "2.0.1" + "parseurl": "~1.3.3", + "send": "0.18.0" }, "engines": { "node": ">= 0.8.0" } }, - "node_modules/serve-static/node_modules/statuses": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.1.tgz", - "integrity": "sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ==", - "dev": true, - "engines": { - "node": ">= 0.8" - } - }, "node_modules/set-blocking": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/set-blocking/-/set-blocking-2.0.0.tgz", @@ -14326,9 +13324,9 @@ "dev": true }, "node_modules/set-cookie-parser": { - "version": "2.5.0", - "resolved": "https://registry.npmjs.org/set-cookie-parser/-/set-cookie-parser-2.5.0.tgz", - "integrity": "sha512-cHMAtSXilfyBePduZEBVPTCftTQWz6ehWJD5YNUg4mqvRosrrjKbo4WS8JkB0/RxonMoohHm7cOGH60mDkRQ9w==", + "version": "2.5.1", + "resolved": "https://registry.npmjs.org/set-cookie-parser/-/set-cookie-parser-2.5.1.tgz", + "integrity": "sha512-1jeBGaKNGdEq4FgIrORu/N570dwoPYio8lSoYLWmX7sQ//0JY08Xh9o5pBcgmHQ/MbsYp/aZnOe1s1lIsbLprQ==", "dev": true }, "node_modules/set-cookie-serde": { @@ -14336,45 +13334,6 @@ "resolved": "https://registry.npmjs.org/set-cookie-serde/-/set-cookie-serde-1.0.0.tgz", "integrity": "sha512-Vq8e5GsupfJ7okHIvEPcfs5neCo7MZ1ZuWrO3sllYi3DOWt6bSSCpADzqXjz3k0fXehnoFIrmmhty9IN6U6BXQ==" }, - "node_modules/set-value": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/set-value/-/set-value-2.0.1.tgz", - "integrity": "sha512-JxHc1weCN68wRY0fhCoXpyK55m/XPHafOmK4UWD7m2CI14GMcFypt4w/0+NV5f/ZMby2F6S2wwA7fgynh9gWSw==", - "dev": true, - "dependencies": { - "extend-shallow": "^2.0.1", - "is-extendable": "^0.1.1", - "is-plain-object": "^2.0.3", - "split-string": "^3.0.1" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/set-value/node_modules/extend-shallow": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", - "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", - "dev": true, - "dependencies": { - "is-extendable": "^0.1.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/set-value/node_modules/is-plain-object": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-2.0.4.tgz", - "integrity": "sha512-h5PpgXkWitc38BBMYawTYMWJHFZJVnBquFE57xFpjB8pJFiF6gZ+bU+WyI/yqXiFR5mdLsgYNaPe8uao6Uv9Og==", - "dev": true, - "dependencies": { - "isobject": "^3.0.1" - }, - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/setprototypeof": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.2.0.tgz", @@ -14502,165 +13461,13 @@ "npm": ">= 3.0.0" } }, - "node_modules/snapdragon": { - "version": "0.8.2", - "resolved": "https://registry.npmjs.org/snapdragon/-/snapdragon-0.8.2.tgz", - "integrity": "sha512-FtyOnWN/wCHTVXOMwvSv26d+ko5vWlIDD6zoUJ7LW8vh+ZBC8QdljveRP+crNrtBwioEUWy/4dMtbBjA4ioNlg==", - "dev": true, - "dependencies": { - "base": "^0.11.1", - "debug": "^2.2.0", - "define-property": "^0.2.5", - "extend-shallow": "^2.0.1", - "map-cache": "^0.2.2", - "source-map": "^0.5.6", - "source-map-resolve": "^0.5.0", - "use": "^3.1.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/snapdragon-node": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/snapdragon-node/-/snapdragon-node-2.1.1.tgz", - "integrity": "sha512-O27l4xaMYt/RSQ5TR3vpWCAB5Kb/czIcqUFOM/C4fYcLnbZUc1PkjTAMjof2pBWaSTwOUd6qUHcFGVGj7aIwnw==", - "dev": true, - "dependencies": { - "define-property": "^1.0.0", - "isobject": "^3.0.0", - "snapdragon-util": "^3.0.1" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/snapdragon-node/node_modules/define-property": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/define-property/-/define-property-1.0.0.tgz", - "integrity": "sha1-dp66rz9KY6rTr56NMEybvnm/sOY=", - "dev": true, - "dependencies": { - "is-descriptor": "^1.0.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/snapdragon-node/node_modules/is-accessor-descriptor": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz", - "integrity": "sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ==", - "dev": true, - "dependencies": { - "kind-of": "^6.0.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/snapdragon-node/node_modules/is-data-descriptor": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz", - "integrity": "sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ==", - "dev": true, - "dependencies": { - "kind-of": "^6.0.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/snapdragon-node/node_modules/is-descriptor": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.2.tgz", - "integrity": "sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg==", - "dev": true, - "dependencies": { - "is-accessor-descriptor": "^1.0.0", - "is-data-descriptor": "^1.0.0", - "kind-of": "^6.0.2" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/snapdragon-node/node_modules/kind-of": { - "version": "6.0.3", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.3.tgz", - "integrity": "sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/snapdragon-util": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/snapdragon-util/-/snapdragon-util-3.0.1.tgz", - "integrity": "sha512-mbKkMdQKsjX4BAL4bRYTj21edOf8cN7XHdYUJEe+Zn99hVEYcMvKPct1IqNe7+AZPirn8BCDOQBHQZknqmKlZQ==", - "dev": true, - "dependencies": { - "kind-of": "^3.2.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/snapdragon/node_modules/debug": { - "version": "2.6.9", - "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", - "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", - "dev": true, - "dependencies": { - "ms": "2.0.0" - } - }, - "node_modules/snapdragon/node_modules/define-property": { - "version": "0.2.5", - "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", - "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", - "dev": true, - "dependencies": { - "is-descriptor": "^0.1.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/snapdragon/node_modules/extend-shallow": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", - "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", - "dev": true, - "dependencies": { - "is-extendable": "^0.1.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/snapdragon/node_modules/ms": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", - "dev": true - }, - "node_modules/snapdragon/node_modules/source-map": { - "version": "0.5.7", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", - "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/socks": { - "version": "2.6.2", - "resolved": "https://registry.npmjs.org/socks/-/socks-2.6.2.tgz", - "integrity": "sha512-zDZhHhZRY9PxRruRMR7kMhnf3I8hDs4S3f9RecfnGxvcBHQcKcIH/oUcEWffsfl1XxdYlA7nnlGbbTvPz9D8gA==", + "version": "2.7.0", + "resolved": "https://registry.npmjs.org/socks/-/socks-2.7.0.tgz", + "integrity": "sha512-scnOe9y4VuiNUULJN72GrM26BNOjVsfPXI+j+98PkyEfsIXroa5ofyjT+FzGvn/xHs73U2JtoBYAVx9Hl4quSA==", "dev": true, "dependencies": { - "ip": "^1.1.5", + "ip": "^2.0.0", "smart-buffer": "^4.2.0" }, "engines": { @@ -14688,27 +13495,6 @@ "node": ">= 8" } }, - "node_modules/source-map-resolve": { - "version": "0.5.3", - "resolved": "https://registry.npmjs.org/source-map-resolve/-/source-map-resolve-0.5.3.tgz", - "integrity": "sha512-Htz+RnsXWk5+P2slx5Jh3Q66vhQj1Cllm0zvnaY98+NFx+Dv2CF/f5O/t8x+KaNdrdIAsruNzoh/KpialbqAnw==", - "deprecated": "See https://github.com/lydell/source-map-resolve#deprecated", - "dev": true, - "dependencies": { - "atob": "^2.1.2", - "decode-uri-component": "^0.2.0", - "resolve-url": "^0.2.1", - "source-map-url": "^0.4.0", - "urix": "^0.1.0" - } - }, - "node_modules/source-map-url": { - "version": "0.4.1", - "resolved": "https://registry.npmjs.org/source-map-url/-/source-map-url-0.4.1.tgz", - "integrity": "sha512-cPiFOTLUKvJFIg4SKVScy4ilPPW6rFgMgfuZJPNoDuMs3nC1HbMUycBoJw77xFIp6z1UJQJOfx6C9GMH80DiTw==", - "deprecated": "See https://github.com/lydell/source-map-url#deprecated", - "dev": true - }, "node_modules/sparse-bitfield": { "version": "3.0.3", "resolved": "https://registry.npmjs.org/sparse-bitfield/-/sparse-bitfield-3.0.3.tgz", @@ -14837,18 +13623,6 @@ "wbuf": "^1.7.3" } }, - "node_modules/split-string": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/split-string/-/split-string-3.1.0.tgz", - "integrity": "sha512-NzNVhJDYpwceVVii8/Hu6DKfD2G+NrQHlS/V/qgv763EYudVwEcMQNxd2lh+0VrUByXN/oJkl5grOhYWvQUYiw==", - "dev": true, - "dependencies": { - "extend-shallow": "^3.0.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/split2": { "version": "2.2.0", "resolved": "https://registry.npmjs.org/split2/-/split2-2.2.0.tgz", @@ -14935,31 +13709,6 @@ "integrity": "sha512-qoRRSyROncaz1z0mvYqIE4lCd9p2R90i6GxW3uZv5ucSu8tU7B5HXUP1gG8pVZsYNVaXjk8ClXHPttLyxAL48A==", "dev": true }, - "node_modules/static-extend": { - "version": "0.1.2", - "resolved": "https://registry.npmjs.org/static-extend/-/static-extend-0.1.2.tgz", - "integrity": "sha1-YICcOcv/VTNyJv1eC1IPNB8ftcY=", - "dev": true, - "dependencies": { - "define-property": "^0.2.5", - "object-copy": "^0.1.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/static-extend/node_modules/define-property": { - "version": "0.2.5", - "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", - "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", - "dev": true, - "dependencies": { - "is-descriptor": "^0.1.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/statuses": { "version": "1.5.0", "resolved": "https://registry.npmjs.org/statuses/-/statuses-1.5.0.tgz", @@ -14987,19 +13736,19 @@ "readable-stream": "^3.0.6" } }, - "node_modules/stream-shift": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/stream-shift/-/stream-shift-1.0.1.tgz", - "integrity": "sha512-AiisoFqQ0vbGcZgQPY1cdP2I76glaVA/RauYR4G4thNFgkTqr90yXTo4LYX60Jl+sIlPNHHdGSwo01AvbKUSVQ==", + "node_modules/stream-transform": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/stream-transform/-/stream-transform-3.2.1.tgz", + "integrity": "sha512-ApK+WTJ5bCOf0A2tlec1qhvr8bGEBM/sgXXB7mysdCYgZJO5DZeaV3h3G+g0HnAQ372P5IhiGqnW29zoLOfTzQ==", "dev": true }, - "node_modules/stream-transform": { - "version": "2.1.3", - "resolved": "https://registry.npmjs.org/stream-transform/-/stream-transform-2.1.3.tgz", - "integrity": "sha512-9GHUiM5hMiCi6Y03jD2ARC1ettBXkQBoQAe7nJsPknnI0ow10aXjTnew8QtYQmLjzn974BnmWEAJgCY6ZP1DeQ==", + "node_modules/streamsearch": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/streamsearch/-/streamsearch-1.1.0.tgz", + "integrity": "sha512-Mcc5wHehp9aXz1ax6bZUyY5afg9u2rv5cqQI3mRrYkGC8rW2hM02jWuwjtL++LS5qinSyhj2QfLyNsuc+VsExg==", "dev": true, - "dependencies": { - "mixme": "^0.5.1" + "engines": { + "node": ">=10.0.0" } }, "node_modules/string_decoder": { @@ -15162,6 +13911,22 @@ "node": ">=6.0.0" } }, + "node_modules/table/node_modules/ajv": { + "version": "6.12.6", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", + "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", + "dev": true, + "dependencies": { + "fast-deep-equal": "^3.1.1", + "fast-json-stable-stringify": "^2.0.0", + "json-schema-traverse": "^0.4.1", + "uri-js": "^4.2.2" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, "node_modules/table/node_modules/ansi-regex": { "version": "4.1.1", "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.1.tgz", @@ -15186,6 +13951,12 @@ "node": ">=4" } }, + "node_modules/table/node_modules/json-schema-traverse": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", + "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", + "dev": true + }, "node_modules/table/node_modules/string-width": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/string-width/-/string-width-3.1.0.tgz", @@ -15253,9 +14024,9 @@ } }, "node_modules/tape": { - "version": "5.5.3", - "resolved": "https://registry.npmjs.org/tape/-/tape-5.5.3.tgz", - "integrity": "sha512-hPBJZBL9S7bH9vECg/KSM24slGYV589jJr4dmtiJrLD71AL66+8o4b9HdZazXZyvnilqA7eE8z5/flKiy0KsBg==", + "version": "5.6.1", + "resolved": "https://registry.npmjs.org/tape/-/tape-5.6.1.tgz", + "integrity": "sha512-reNzS3rzsJtKk0f+zJx2XlzIsjJXlIcOIrIxk5shHAG/DzW3BKyMg8UfN79oluYlcWo4lIt56ahLqwgpRT4idg==", "dev": true, "dependencies": { "array.prototype.every": "^1.1.3", @@ -15265,23 +14036,26 @@ "dotignore": "^0.1.2", "for-each": "^0.3.3", "get-package-type": "^0.1.0", - "glob": "^7.2.0", + "glob": "^7.2.3", "has": "^1.0.3", "has-dynamic-import": "^2.0.1", "inherits": "^2.0.4", "is-regex": "^1.1.4", "minimist": "^1.2.6", - "object-inspect": "^1.12.0", + "object-inspect": "^1.12.2", "object-is": "^1.1.5", "object-keys": "^1.1.1", - "object.assign": "^4.1.2", + "object.assign": "^4.1.4", "resolve": "^2.0.0-next.3", "resumer": "^0.0.0", - "string.prototype.trim": "^1.2.5", + "string.prototype.trim": "^1.2.6", "through": "^2.3.8" }, "bin": { "tape": "bin/tape" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, "node_modules/tape/node_modules/deep-equal": { @@ -15339,26 +14113,27 @@ } }, "node_modules/tedious": { - "version": "14.5.0", - "resolved": "https://registry.npmjs.org/tedious/-/tedious-14.5.0.tgz", - "integrity": "sha512-Mr/ku6J0yku9MvWKO7e//awwI52122jS5AYRz/VOI2jZZawv84iHPKF/FnHBoIEKlRjzahrtevfpNktw/eBAEw==", + "version": "15.1.0", + "resolved": "https://registry.npmjs.org/tedious/-/tedious-15.1.0.tgz", + "integrity": "sha512-D96Z8SL4ALE/rS6rOAfzWd/x+RD9vWbnNT3w5KZ0e0Tdh5FX1bKEODS+1oemSQM2ok5SktLHqSJqYQRx4yu3WA==", "dev": true, "dependencies": { - "@azure/identity": "^2.0.1", - "@azure/keyvault-keys": "^4.3.0", - "@js-joda/core": "^4.0.0", + "@azure/identity": "^2.0.4", + "@azure/keyvault-keys": "^4.4.0", + "@js-joda/core": "^5.2.0", "@types/es-aggregate-error": "^1.0.2", "bl": "^5.0.0", - "es-aggregate-error": "^1.0.7", + "es-aggregate-error": "^1.0.8", "iconv-lite": "^0.6.3", - "jsbi": "^3.2.1", + "js-md4": "^0.3.2", + "jsbi": "^4.3.0", "native-duplexpair": "^1.0.0", - "node-abort-controller": "^3.0.0", + "node-abort-controller": "^3.0.1", "punycode": "^2.1.0", "sprintf-js": "^1.1.2" }, "engines": { - "node": ">= 12" + "node": ">=14" } }, "node_modules/tedious/node_modules/bl": { @@ -15459,6 +14234,19 @@ "tav": "index.js" } }, + "node_modules/test-all-versions/node_modules/js-yaml": { + "version": "3.14.1", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.14.1.tgz", + "integrity": "sha512-okMH7OXXJ7YrN9Ok3/SXrnu4iX9yOk+25nqX4imS2npuvTYDmo/QEZoqwZkYaIDk3jVvBOTOIEgEhaLOynBS9g==", + "dev": true, + "dependencies": { + "argparse": "^1.0.7", + "esprima": "^4.0.0" + }, + "bin": { + "js-yaml": "bin/js-yaml.js" + } + }, "node_modules/test-all-versions/node_modules/log-symbols": { "version": "2.2.0", "resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-2.2.0.tgz", @@ -15498,12 +14286,12 @@ "dev": true }, "node_modules/thread-stream": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/thread-stream/-/thread-stream-1.0.0.tgz", - "integrity": "sha512-2Sw29jWubQWOcVa7MhLHJ51wjksUD/GHN4Fy3hP9w9DYTujifoZGSKBl54CMLRXWoD5h2pD707kY3fAdzhcwAg==", + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/thread-stream/-/thread-stream-2.2.0.tgz", + "integrity": "sha512-rUkv4/fnb4rqy/gGy7VuqK6wE1+1DOCOWy4RMeaV69ZHMP11tQKZvZSip1yTgrKCMZzEMcCL/bKfHvSfDHx+iQ==", "dev": true, "dependencies": { - "real-require": "^0.1.0" + "real-require": "^0.2.0" } }, "node_modules/through": { @@ -15562,9 +14350,9 @@ } }, "node_modules/tiny-lru": { - "version": "8.0.2", - "resolved": "https://registry.npmjs.org/tiny-lru/-/tiny-lru-8.0.2.tgz", - "integrity": "sha512-ApGvZ6vVvTNdsmt676grvCkUCGwzG9IqXma5Z07xJgiC5L7akUMof5U8G2JTI9Rz/ovtVhJBlY6mNhEvtjzOIg==", + "version": "10.0.1", + "resolved": "https://registry.npmjs.org/tiny-lru/-/tiny-lru-10.0.1.tgz", + "integrity": "sha512-Vst+6kEsWvb17Zpz14sRJV/f8bUWKhqm6Dc+v08iShmIJ/WxqWytHzCTd6m88pS33rE2zpX34TRmOpAJPloNCA==", "dev": true, "engines": { "node": ">=6" @@ -15591,33 +14379,6 @@ "node": ">=4" } }, - "node_modules/to-object-path": { - "version": "0.3.0", - "resolved": "https://registry.npmjs.org/to-object-path/-/to-object-path-0.3.0.tgz", - "integrity": "sha1-KXWIt7Dn4KwI4E5nL4XB9JmeF68=", - "dev": true, - "dependencies": { - "kind-of": "^3.0.2" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/to-regex": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/to-regex/-/to-regex-3.0.2.tgz", - "integrity": "sha512-FWtleNAtZ/Ki2qtqej2CXTOayOH9bHDQF+Q48VpWyDXjbYxA4Yz8iDB31zXOBUlOHHKidDbqGVrTUvQMPmBGBw==", - "dev": true, - "dependencies": { - "define-property": "^2.0.2", - "extend-shallow": "^3.0.2", - "regex-not": "^1.0.2", - "safe-regex": "^1.1.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/to-regex-range": { "version": "5.0.1", "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", @@ -15675,9 +14436,12 @@ } }, "node_modules/traverse": { - "version": "0.6.6", - "resolved": "https://registry.npmjs.org/traverse/-/traverse-0.6.6.tgz", - "integrity": "sha1-y99WD9e5r2MlAv7UD5GMFX6pcTc=" + "version": "0.6.7", + "resolved": "https://registry.npmjs.org/traverse/-/traverse-0.6.7.tgz", + "integrity": "sha512-/y956gpUo9ZNCb99YjxG7OaslxZWHfCHAUUfshwqOXmxUIvqLjVO581BT+gM59+QV9tFe6/CGG53tsA1Y7RSdg==", + "funding": { + "url": "https://github.com/sponsors/ljharb" + } }, "node_modules/triple-beam": { "version": "1.3.0", @@ -15698,9 +14462,9 @@ } }, "node_modules/tsconfig-paths/node_modules/json5": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/json5/-/json5-1.0.1.tgz", - "integrity": "sha512-aKS4WQjPenRxiQsC93MNfjx+nbF4PAdYzmd/1JIj8HYzqfbu86beTuNgXDzPknWk0n0uARlyewZo4s++ES36Ow==", + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/json5/-/json5-1.0.2.tgz", + "integrity": "sha512-g1MWMLBiz8FKi1e4w0UyVL3w+iJceWAFBAaBnnGKOpNa5f8TLktkbre1+s6oICydWAm+HRUGTmI+//xv2hvXYA==", "dev": true, "dependencies": { "minimist": "^1.2.0" @@ -15795,9 +14559,9 @@ } }, "node_modules/typescript": { - "version": "4.7.4", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.7.4.tgz", - "integrity": "sha512-C0WQT0gezHuw6AdY1M2jxUO83Rjf0HP7Sk1DtXj6j1EwkQNZrHAg2XPWlq62oqEhYvONq5pkC2Y9oPljWToLmQ==", + "version": "4.9.3", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.9.3.tgz", + "integrity": "sha512-CIfGzTelbKNEnLpLdGFgdyKhG23CKdKgQPOBc+OUNrkJ2vr+KSzsSV5kq5iWhEQbok+quxgGzrAtGWCyU7tHnA==", "dev": true, "bin": { "tsc": "bin/tsc", @@ -15844,10 +14608,13 @@ } }, "node_modules/undici": { - "version": "5.5.1", - "resolved": "https://registry.npmjs.org/undici/-/undici-5.5.1.tgz", - "integrity": "sha512-MEvryPLf18HvlCbLSzCW0U00IMftKGI5udnjrQbC5D4P0Hodwffhv+iGfWuJwg16Y/TK11ZFK8i+BPVW2z/eAw==", + "version": "5.14.0", + "resolved": "https://registry.npmjs.org/undici/-/undici-5.14.0.tgz", + "integrity": "sha512-yJlHYw6yXPPsuOH0x2Ib1Km61vu4hLiRRQoafs+WUgX1vO64vgnxiCEN9dpIrhZyHFsai3F0AEj4P9zy19enEQ==", "dev": true, + "dependencies": { + "busboy": "^1.6.0" + }, "engines": { "node": ">=12.18" } @@ -15906,21 +14673,6 @@ "resolved": "https://registry.npmjs.org/unicode-substring/-/unicode-substring-0.1.0.tgz", "integrity": "sha1-YSDOPDkDhdvND2DDK5BlxBgdSzY=" }, - "node_modules/union-value": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/union-value/-/union-value-1.0.1.tgz", - "integrity": "sha512-tJfXmxMeWYnczCVs7XAEvIV7ieppALdyepWMkHkwciRpZraG/xwT+s2JN8+pr1+8jCRf80FFzvr+MpQeeoF4Xg==", - "dev": true, - "dependencies": { - "arr-union": "^3.1.0", - "get-value": "^2.0.6", - "is-extendable": "^0.1.1", - "set-value": "^2.0.1" - }, - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/universal-user-agent": { "version": "6.0.0", "resolved": "https://registry.npmjs.org/universal-user-agent/-/universal-user-agent-6.0.0.tgz", @@ -15945,52 +14697,30 @@ "node": ">= 0.8" } }, - "node_modules/unset-value": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/unset-value/-/unset-value-1.0.0.tgz", - "integrity": "sha1-g3aHP30jNRef+x5vw6jtDfyKtVk=", - "dev": true, - "dependencies": { - "has-value": "^0.3.1", - "isobject": "^3.0.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/unset-value/node_modules/has-value": { - "version": "0.3.1", - "resolved": "https://registry.npmjs.org/has-value/-/has-value-0.3.1.tgz", - "integrity": "sha1-ex9YutpiyoJ+wKIHgCVlSEWZXh8=", + "node_modules/update-browserslist-db": { + "version": "1.0.9", + "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.0.9.tgz", + "integrity": "sha512-/xsqn21EGVdXI3EXSum1Yckj3ZVZugqyOZQ/CxYPBD/R+ko9NSUScf8tFF4dOKY+2pvSSJA/S+5B8s4Zr4kyvg==", "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/browserslist" + } + ], "dependencies": { - "get-value": "^2.0.3", - "has-values": "^0.1.4", - "isobject": "^2.0.0" + "escalade": "^3.1.1", + "picocolors": "^1.0.0" }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/unset-value/node_modules/has-value/node_modules/isobject": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/isobject/-/isobject-2.1.0.tgz", - "integrity": "sha1-8GVWEJaj8dou9GJy+BXIQNh+DIk=", - "dev": true, - "dependencies": { - "isarray": "1.0.0" + "bin": { + "browserslist-lint": "cli.js" }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/unset-value/node_modules/has-values": { - "version": "0.1.4", - "resolved": "https://registry.npmjs.org/has-values/-/has-values-0.1.4.tgz", - "integrity": "sha1-bWHeldkd/Km5oCCJrThL/49it3E=", - "dev": true, - "engines": { - "node": ">=0.10.0" + "peerDependencies": { + "browserslist": ">= 4.21.0" } }, "node_modules/uri-js": { @@ -16001,13 +14731,6 @@ "punycode": "^2.1.0" } }, - "node_modules/urix": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/urix/-/urix-0.1.0.tgz", - "integrity": "sha1-2pN/emLiH+wf0Y1Js1wpNQZ6bHI=", - "deprecated": "Please see https://github.com/lydell/urix#deprecated", - "dev": true - }, "node_modules/url": { "version": "0.10.3", "resolved": "https://registry.npmjs.org/url/-/url-0.10.3.tgz", @@ -16024,15 +14747,6 @@ "integrity": "sha1-llOgNvt8HuQjQvIyXM7v6jkmxI0=", "dev": true }, - "node_modules/use": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/use/-/use-3.1.1.tgz", - "integrity": "sha512-cwESVXlO3url9YWlFW/TA9cshCEhtu7IKJ/p5soJ/gGpj7vbvFrAY/eIioQ6Dw23KjZhYgiIo8HOs1nQ2vr/oQ==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/util-deprecate": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", @@ -16062,18 +14776,6 @@ "integrity": "sha512-l8lCEmLcLYZh4nbunNZvQCJc5pv7+RCwa8q/LdUx8u7lsWvPDKmpodJAJNwkAhJC//dFY48KuIEmjtd4RViDrA==", "dev": true }, - "node_modules/v8flags": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/v8flags/-/v8flags-3.2.0.tgz", - "integrity": "sha512-mH8etigqMfiGWdeXpaaqGfs6BndypxusHHcv2qSHyZkGEznCd/qAXCWWRzeowtL54147cktFOC4P5y+kl8d8Jg==", - "dev": true, - "dependencies": { - "homedir-polyfill": "^1.0.1" - }, - "engines": { - "node": ">= 0.10" - } - }, "node_modules/validate-npm-package-license": { "version": "3.0.4", "resolved": "https://registry.npmjs.org/validate-npm-package-license/-/validate-npm-package-license-3.0.4.tgz", @@ -16135,37 +14837,61 @@ "dev": true }, "node_modules/wait-on": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/wait-on/-/wait-on-6.0.1.tgz", - "integrity": "sha512-zht+KASY3usTY5u2LgaNqn/Cd8MukxLGjdcZxT2ns5QzDmTFc4XoWBgC+C/na+sMRZTuVygQoMYwdcVjHnYIVw==", + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/wait-on/-/wait-on-7.0.1.tgz", + "integrity": "sha512-9AnJE9qTjRQOlTZIldAaf/da2eW0eSRSgcqq85mXQja/DW3MriHxkpODDSUEg+Gri/rKEcXUZHe+cevvYItaog==", "dev": true, "dependencies": { - "axios": "^0.25.0", - "joi": "^17.6.0", + "axios": "^0.27.2", + "joi": "^17.7.0", "lodash": "^4.17.21", - "minimist": "^1.2.5", - "rxjs": "^7.5.4" + "minimist": "^1.2.7", + "rxjs": "^7.8.0" }, "bin": { "wait-on": "bin/wait-on" }, "engines": { - "node": ">=10.0.0" + "node": ">=12.0.0" } }, "node_modules/wait-on/node_modules/axios": { - "version": "0.25.0", - "resolved": "https://registry.npmjs.org/axios/-/axios-0.25.0.tgz", - "integrity": "sha512-cD8FOb0tRH3uuEe6+evtAbgJtfxr7ly3fQjYcMcuPlgkwVS9xboaVIpcDV+cYQe+yGykgwZCs1pzjntcGa6l5g==", + "version": "0.27.2", + "resolved": "https://registry.npmjs.org/axios/-/axios-0.27.2.tgz", + "integrity": "sha512-t+yRIyySRTp/wua5xEr+z1q60QmLq8ABsS5O9Me1AsE5dfKqgnCFzwiCZZ/cGNd1lq4/7akDWMxdhVlucjmnOQ==", "dev": true, "dependencies": { - "follow-redirects": "^1.14.7" + "follow-redirects": "^1.14.9", + "form-data": "^4.0.0" + } + }, + "node_modules/wait-on/node_modules/form-data": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.0.tgz", + "integrity": "sha512-ETEklSGi5t0QMZuiXoA/Q6vcnxcLQP5vdugSpuAyi6SVGi2clPPp+xgEhuMaHC+zGgn31Kd235W35f7Hykkaww==", + "dev": true, + "dependencies": { + "asynckit": "^0.4.0", + "combined-stream": "^1.0.8", + "mime-types": "^2.1.12" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/wait-on/node_modules/minimist": { + "version": "1.2.7", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.7.tgz", + "integrity": "sha512-bzfL1YUZsP41gmu/qjrEk0Q6i2ix/cVeAhbCbqH9u3zYutS1cLg00qhrD0M2MVdCcx4Sc0UpP2eBWo9rotpq6g==", + "dev": true, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, "node_modules/wait-on/node_modules/rxjs": { - "version": "7.5.5", - "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-7.5.5.tgz", - "integrity": "sha512-sy+H0pQofO95VDmFLzyaw9xNJU4KTRSwQIGM6+iG3SypAtCiLDzpeG8sJrNCWn2Up9km+KhkvTdbkrdy+yzZdw==", + "version": "7.8.0", + "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-7.8.0.tgz", + "integrity": "sha512-F2+gxDshqmIub1KdvZkaEfGDwLNpPvk9Fs6LD/MyQxNgMds/WH9OdDDXOmxUZpME+iSK3rQCctkL0DYyytUqMg==", "dev": true, "dependencies": { "tslib": "^2.1.0" @@ -16282,11 +15008,12 @@ } }, "node_modules/winston": { - "version": "3.7.2", - "resolved": "https://registry.npmjs.org/winston/-/winston-3.7.2.tgz", - "integrity": "sha512-QziIqtojHBoyzUOdQvQiar1DH0Xp9nF1A1y7NVy2DGEsz82SBDtOalS0ulTRGVT14xPX3WRWkCsdcJKqNflKng==", + "version": "3.8.2", + "resolved": "https://registry.npmjs.org/winston/-/winston-3.8.2.tgz", + "integrity": "sha512-MsE1gRx1m5jdTTO9Ld/vND4krP2To+lgDoMEHGGa4HIlAUyXJtfc7CxQcGXVyz2IBpw5hbFkj2b/AtUdQwyRew==", "dev": true, "dependencies": { + "@colors/colors": "1.5.0", "@dabh/diagnostics": "^2.0.2", "async": "^3.2.3", "is-stream": "^2.0.0", @@ -16411,9 +15138,9 @@ } }, "node_modules/ws": { - "version": "7.5.8", - "resolved": "https://registry.npmjs.org/ws/-/ws-7.5.8.tgz", - "integrity": "sha512-ri1Id1WinAX5Jqn9HejiGb8crfRio0Qgu8+MtL36rlTA6RLsMdWt1Az/19A2Qij6uSHUMphEFaTKa4WG+UNHNw==", + "version": "7.5.9", + "resolved": "https://registry.npmjs.org/ws/-/ws-7.5.9.tgz", + "integrity": "sha512-F+P9Jil7UiSKSkppIiD94dN07AwvFixvLIj1Og1Rl9GGMuNipJnV9JzjD6XuqmAeiswGvUmNLjr5cFuXwNS77Q==", "dev": true, "engines": { "node": ">=8.3.0" @@ -16594,9 +15321,9 @@ } }, "@apollo/protobufjs": { - "version": "1.2.2", - "resolved": "https://registry.npmjs.org/@apollo/protobufjs/-/protobufjs-1.2.2.tgz", - "integrity": "sha512-vF+zxhPiLtkwxONs6YanSt1EpwpGilThpneExUN5K3tCymuxNnVq2yojTvnpRjv2QfsEIt/n7ozPIIzBLwGIDQ==", + "version": "1.2.6", + "resolved": "https://registry.npmjs.org/@apollo/protobufjs/-/protobufjs-1.2.6.tgz", + "integrity": "sha512-Wqo1oSHNUj/jxmsVp4iR3I480p6qdqHikn38lKrFhfzcDJ7lwd7Ck7cHRl4JE81tWNArl77xhnG/OkZhxKBYOw==", "dev": true, "requires": { "@protobufjs/aspromise": "^1.1.2", @@ -16622,12 +15349,77 @@ } } }, + "@apollo/utils.dropunuseddefinitions": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@apollo/utils.dropunuseddefinitions/-/utils.dropunuseddefinitions-1.1.0.tgz", + "integrity": "sha512-jU1XjMr6ec9pPoL+BFWzEPW7VHHulVdGKMkPAMiCigpVIT11VmCbnij0bWob8uS3ODJ65tZLYKAh/55vLw2rbg==", + "dev": true + }, + "@apollo/utils.keyvaluecache": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@apollo/utils.keyvaluecache/-/utils.keyvaluecache-1.0.1.tgz", + "integrity": "sha512-nLgYLomqjVimEzQ4cdvVQkcryi970NDvcRVPfd0OPeXhBfda38WjBq+WhQFk+czSHrmrSp34YHBxpat0EtiowA==", + "dev": true, + "requires": { + "@apollo/utils.logger": "^1.0.0", + "lru-cache": "^7.10.1" + }, + "dependencies": { + "lru-cache": { + "version": "7.13.1", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-7.13.1.tgz", + "integrity": "sha512-CHqbAq7NFlW3RSnoWXLJBxCWaZVBrfa9UEHId2M3AW8iEBurbqduNexEUCGc3SHc6iCYXNJCDi903LajSVAEPQ==", + "dev": true + } + } + }, "@apollo/utils.logger": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/@apollo/utils.logger/-/utils.logger-1.0.0.tgz", "integrity": "sha512-dx9XrjyisD2pOa+KsB5RcDbWIAdgC91gJfeyLCgy0ctJMjQe7yZK5kdWaWlaOoCeX0z6YI9iYlg7vMPyMpQF3Q==", "dev": true }, + "@apollo/utils.printwithreducedwhitespace": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@apollo/utils.printwithreducedwhitespace/-/utils.printwithreducedwhitespace-1.1.0.tgz", + "integrity": "sha512-GfFSkAv3n1toDZ4V6u2d7L4xMwLA+lv+6hqXicMN9KELSJ9yy9RzuEXaX73c/Ry+GzRsBy/fdSUGayGqdHfT2Q==", + "dev": true + }, + "@apollo/utils.removealiases": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/@apollo/utils.removealiases/-/utils.removealiases-1.0.0.tgz", + "integrity": "sha512-6cM8sEOJW2LaGjL/0vHV0GtRaSekrPQR4DiywaApQlL9EdROASZU5PsQibe2MWeZCOhNrPRuHh4wDMwPsWTn8A==", + "dev": true + }, + "@apollo/utils.sortast": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@apollo/utils.sortast/-/utils.sortast-1.1.0.tgz", + "integrity": "sha512-VPlTsmUnOwzPK5yGZENN069y6uUHgeiSlpEhRnLFYwYNoJHsuJq2vXVwIaSmts015WTPa2fpz1inkLYByeuRQA==", + "dev": true, + "requires": { + "lodash.sortby": "^4.7.0" + } + }, + "@apollo/utils.stripsensitiveliterals": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/@apollo/utils.stripsensitiveliterals/-/utils.stripsensitiveliterals-1.2.0.tgz", + "integrity": "sha512-E41rDUzkz/cdikM5147d8nfCFVKovXxKBcjvLEQ7bjZm/cg9zEcXvS6vFY8ugTubI3fn6zoqo0CyU8zT+BGP9w==", + "dev": true + }, + "@apollo/utils.usagereporting": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/@apollo/utils.usagereporting/-/utils.usagereporting-1.0.0.tgz", + "integrity": "sha512-5PL7hJMkTPmdo3oxPtigRrIyPxDk/ddrUryHPDaezL1lSFExpNzsDd2f1j0XJoHOg350GRd3LyD64caLA2PU1w==", + "dev": true, + "requires": { + "@apollo/utils.dropunuseddefinitions": "^1.1.0", + "@apollo/utils.printwithreducedwhitespace": "^1.1.0", + "@apollo/utils.removealiases": "1.0.0", + "@apollo/utils.sortast": "^1.1.0", + "@apollo/utils.stripsensitiveliterals": "^1.2.0", + "apollo-reporting-protobuf": "^3.3.1" + } + }, "@apollographql/apollo-tools": { "version": "0.5.4", "resolved": "https://registry.npmjs.org/@apollographql/apollo-tools/-/apollo-tools-0.5.4.tgz", @@ -16897,30 +15689,28 @@ } }, "@azure/msal-node": { - "version": "1.9.0", - "resolved": "https://registry.npmjs.org/@azure/msal-node/-/msal-node-1.9.0.tgz", - "integrity": "sha512-lw6ejz1WPqcdjkwp91Gidte98+kfGxHk9eYSmmpUChzrUUrZMFGvrtrvG3Qnr6bp5d4WijVge9LMe+2QQUMhoA==", + "version": "1.14.6", + "resolved": "https://registry.npmjs.org/@azure/msal-node/-/msal-node-1.14.6.tgz", + "integrity": "sha512-em/qqFL5tLMxMPl9vormAs13OgZpmQoJbiQ/GlWr+BA77eCLoL+Ehr5xRHowYo+LFe5b+p+PJVkRvT+mLvOkwA==", "dev": true, "requires": { - "@azure/msal-common": "^6.3.0", - "axios": "^0.21.4", - "https-proxy-agent": "^5.0.0", - "jsonwebtoken": "^8.5.1", + "@azure/msal-common": "^9.0.2", + "jsonwebtoken": "^9.0.0", "uuid": "^8.3.0" }, "dependencies": { "@azure/msal-common": { - "version": "6.3.0", - "resolved": "https://registry.npmjs.org/@azure/msal-common/-/msal-common-6.3.0.tgz", - "integrity": "sha512-ZyLq9GdnLBi/83YpysE86TFKbA0TuvfNAN5Psqu20cdAjLo/4rw4ttiItdh1G//XeGErHk9qn57gi2AYU1b5/Q==", + "version": "9.0.2", + "resolved": "https://registry.npmjs.org/@azure/msal-common/-/msal-common-9.0.2.tgz", + "integrity": "sha512-qzwxuF8kZAp+rNUactMCgJh8fblq9D4lSqrrIxMDzLjgSZtjN32ix7r/HBe8QdOr76II9SVVPcMkX4sPzPfQ7w==", "dev": true } } }, "@babel/cli": { - "version": "7.17.10", - "resolved": "https://registry.npmjs.org/@babel/cli/-/cli-7.17.10.tgz", - "integrity": "sha512-OygVO1M2J4yPMNOW9pb+I6kFGpQK77HmG44Oz3hg8xQIl5L/2zq+ZohwAdSaqYgVwM0SfmPHZHphH4wR8qzVYw==", + "version": "7.19.3", + "resolved": "https://registry.npmjs.org/@babel/cli/-/cli-7.19.3.tgz", + "integrity": "sha512-643/TybmaCAe101m2tSVHi9UKpETXP9c/Ff4mD2tAwkdP6esKIfaauZFc67vGEM6r9fekbEGid+sZhbEnSe3dg==", "dev": true, "requires": { "@jridgewell/trace-mapping": "^0.3.8", @@ -16929,7 +15719,7 @@ "commander": "^4.0.1", "convert-source-map": "^1.1.0", "fs-readdir-recursive": "^1.1.0", - "glob": "^7.0.0", + "glob": "^7.2.0", "make-dir": "^2.1.0", "slash": "^2.0.0" } @@ -16944,27 +15734,27 @@ } }, "@babel/compat-data": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.18.6.tgz", - "integrity": "sha512-tzulrgDT0QD6U7BJ4TKVk2SDDg7wlP39P9yAx1RfLy7vP/7rsDRlWVfbWxElslu56+r7QOhB2NSDsabYYruoZQ==", + "version": "7.20.1", + "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.20.1.tgz", + "integrity": "sha512-EWZ4mE2diW3QALKvDMiXnbZpRvlj+nayZ112nK93SnhqOtpdsbVD4W+2tEoT3YNBAG9RBR0ISY758ZkOgsn6pQ==", "dev": true }, "@babel/core": { - "version": "7.18.2", - "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.18.2.tgz", - "integrity": "sha512-A8pri1YJiC5UnkdrWcmfZTJTV85b4UXTAfImGmCfYmax4TR9Cw8sDS0MOk++Gp2mE/BefVJ5nwy5yzqNJbP/DQ==", + "version": "7.20.2", + "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.20.2.tgz", + "integrity": "sha512-w7DbG8DtMrJcFOi4VrLm+8QM4az8Mo+PuLBKLp2zrYRCow8W/f9xiXm5sN53C8HksCyDQwCKha9JiDoIyPjT2g==", "dev": true, "requires": { "@ampproject/remapping": "^2.1.0", - "@babel/code-frame": "^7.16.7", - "@babel/generator": "^7.18.2", - "@babel/helper-compilation-targets": "^7.18.2", - "@babel/helper-module-transforms": "^7.18.0", - "@babel/helpers": "^7.18.2", - "@babel/parser": "^7.18.0", - "@babel/template": "^7.16.7", - "@babel/traverse": "^7.18.2", - "@babel/types": "^7.18.2", + "@babel/code-frame": "^7.18.6", + "@babel/generator": "^7.20.2", + "@babel/helper-compilation-targets": "^7.20.0", + "@babel/helper-module-transforms": "^7.20.2", + "@babel/helpers": "^7.20.1", + "@babel/parser": "^7.20.2", + "@babel/template": "^7.18.10", + "@babel/traverse": "^7.20.1", + "@babel/types": "^7.20.2", "convert-source-map": "^1.7.0", "debug": "^4.1.0", "gensync": "^1.0.0-beta.2", @@ -16973,12 +15763,12 @@ } }, "@babel/generator": { - "version": "7.18.7", - "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.18.7.tgz", - "integrity": "sha512-shck+7VLlY72a2w9c3zYWuE1pwOKEiQHV7GTUbSnhyl5eu3i04t30tBY82ZRWrDfo3gkakCFtevExnxbkf2a3A==", + "version": "7.20.2", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.20.2.tgz", + "integrity": "sha512-SD75PMIK6i9H8G/tfGvB4KKl4Nw6Ssos9nGgYwxbgyTP0iX/Z55DveoH86rmUB/YHTQQ+ZC0F7xxaY8l2OF44Q==", "dev": true, "requires": { - "@babel/types": "^7.18.7", + "@babel/types": "^7.20.2", "@jridgewell/gen-mapping": "^0.3.2", "jsesc": "^2.5.1" }, @@ -17016,14 +15806,14 @@ } }, "@babel/helper-compilation-targets": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.18.6.tgz", - "integrity": "sha512-vFjbfhNCzqdeAtZflUFrG5YIFqGTqsctrtkZ1D/NB0mDW9TwW3GmmUepYY4G9wCET5rY5ugz4OGTcLd614IzQg==", + "version": "7.20.0", + "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.20.0.tgz", + "integrity": "sha512-0jp//vDGp9e8hZzBc6N/KwA5ZK3Wsm/pfm4CrY7vzegkVxc65SgSn6wYOnwHe9Js9HRQ1YTCKLGPzDtaS3RoLQ==", "dev": true, "requires": { - "@babel/compat-data": "^7.18.6", + "@babel/compat-data": "^7.20.0", "@babel/helper-validator-option": "^7.18.6", - "browserslist": "^4.20.2", + "browserslist": "^4.21.3", "semver": "^6.3.0" } }, @@ -17043,9 +15833,9 @@ } }, "@babel/helper-create-regexp-features-plugin": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/helper-create-regexp-features-plugin/-/helper-create-regexp-features-plugin-7.18.6.tgz", - "integrity": "sha512-7LcpH1wnQLGrI+4v+nPp+zUvIkF9x0ddv1Hkdue10tg3gmRnLy97DXh4STiOf1qeIInyD69Qv5kKSZzKD8B/7A==", + "version": "7.19.0", + "resolved": "https://registry.npmjs.org/@babel/helper-create-regexp-features-plugin/-/helper-create-regexp-features-plugin-7.19.0.tgz", + "integrity": "sha512-htnV+mHX32DF81amCDrwIDr8nrp1PTm+3wfBN9/v8QJOLEioOCOG7qNyq0nHeFiWbT3Eb7gsPwEmV64UCQ1jzw==", "dev": true, "requires": { "@babel/helper-annotate-as-pure": "^7.18.6", @@ -17053,15 +15843,13 @@ } }, "@babel/helper-define-polyfill-provider": { - "version": "0.3.1", - "resolved": "https://registry.npmjs.org/@babel/helper-define-polyfill-provider/-/helper-define-polyfill-provider-0.3.1.tgz", - "integrity": "sha512-J9hGMpJQmtWmj46B3kBHmL38UhJGhYX7eqkcq+2gsstyYt341HmPeWspihX43yVRA0mS+8GGk2Gckc7bY/HCmA==", + "version": "0.3.3", + "resolved": "https://registry.npmjs.org/@babel/helper-define-polyfill-provider/-/helper-define-polyfill-provider-0.3.3.tgz", + "integrity": "sha512-z5aQKU4IzbqCC1XH0nAqfsFLMVSo22SBKUc0BxGrLkolTdPTructy0ToNnlO2zA4j9Q/7pjMZf0DSY+DSTYzww==", "dev": true, "requires": { - "@babel/helper-compilation-targets": "^7.13.0", - "@babel/helper-module-imports": "^7.12.13", - "@babel/helper-plugin-utils": "^7.13.0", - "@babel/traverse": "^7.13.0", + "@babel/helper-compilation-targets": "^7.17.7", + "@babel/helper-plugin-utils": "^7.16.7", "debug": "^4.1.1", "lodash.debounce": "^4.0.8", "resolve": "^1.14.2", @@ -17069,9 +15857,9 @@ } }, "@babel/helper-environment-visitor": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/helper-environment-visitor/-/helper-environment-visitor-7.18.6.tgz", - "integrity": "sha512-8n6gSfn2baOY+qlp+VSzsosjCVGFqWKmDF0cCWOybh52Dw3SEyoWR1KrhMJASjLwIEkkAufZ0xvr+SxLHSpy2Q==", + "version": "7.18.9", + "resolved": "https://registry.npmjs.org/@babel/helper-environment-visitor/-/helper-environment-visitor-7.18.9.tgz", + "integrity": "sha512-3r/aACDJ3fhQ/EVgFy0hpj8oHyHpQc+LPtJoY9SzTThAsStm4Ptegq92vqKoE3vD706ZVFWITnMnxucw+S9Ipg==", "dev": true }, "@babel/helper-explode-assignable-expression": { @@ -17084,13 +15872,13 @@ } }, "@babel/helper-function-name": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.18.6.tgz", - "integrity": "sha512-0mWMxV1aC97dhjCah5U5Ua7668r5ZmSC2DLfH2EZnf9c3/dHZKiFa5pRLMH5tjSl471tY6496ZWk/kjNONBxhw==", + "version": "7.19.0", + "resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.19.0.tgz", + "integrity": "sha512-WAwHBINyrpqywkUH0nTnNgI5ina5TFn85HKS0pbPDfxFfhyR/aNQEn4hGi1P1JyT//I0t4OgXUlofzWILRvS5w==", "dev": true, "requires": { - "@babel/template": "^7.18.6", - "@babel/types": "^7.18.6" + "@babel/template": "^7.18.10", + "@babel/types": "^7.19.0" } }, "@babel/helper-hoist-variables": { @@ -17103,12 +15891,12 @@ } }, "@babel/helper-member-expression-to-functions": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/helper-member-expression-to-functions/-/helper-member-expression-to-functions-7.18.6.tgz", - "integrity": "sha512-CeHxqwwipekotzPDUuJOfIMtcIHBuc7WAzLmTYWctVigqS5RktNMQ5bEwQSuGewzYnCtTWa3BARXeiLxDTv+Ng==", + "version": "7.18.9", + "resolved": "https://registry.npmjs.org/@babel/helper-member-expression-to-functions/-/helper-member-expression-to-functions-7.18.9.tgz", + "integrity": "sha512-RxifAh2ZoVU67PyKIO4AMi1wTenGfMR/O/ae0CCRqwgBAt5v7xjdtRw7UoSbsreKrQn5t7r89eruK/9JjYHuDg==", "dev": true, "requires": { - "@babel/types": "^7.18.6" + "@babel/types": "^7.18.9" } }, "@babel/helper-module-imports": { @@ -17121,19 +15909,19 @@ } }, "@babel/helper-module-transforms": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.18.6.tgz", - "integrity": "sha512-L//phhB4al5uucwzlimruukHB3jRd5JGClwRMD/ROrVjXfLqovYnvQrK/JK36WYyVwGGO7OD3kMyVTjx+WVPhw==", + "version": "7.20.2", + "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.20.2.tgz", + "integrity": "sha512-zvBKyJXRbmK07XhMuujYoJ48B5yvvmM6+wcpv6Ivj4Yg6qO7NOZOSnvZN9CRl1zz1Z4cKf8YejmCMh8clOoOeA==", "dev": true, "requires": { - "@babel/helper-environment-visitor": "^7.18.6", + "@babel/helper-environment-visitor": "^7.18.9", "@babel/helper-module-imports": "^7.18.6", - "@babel/helper-simple-access": "^7.18.6", + "@babel/helper-simple-access": "^7.20.2", "@babel/helper-split-export-declaration": "^7.18.6", - "@babel/helper-validator-identifier": "^7.18.6", - "@babel/template": "^7.18.6", - "@babel/traverse": "^7.18.6", - "@babel/types": "^7.18.6" + "@babel/helper-validator-identifier": "^7.19.1", + "@babel/template": "^7.18.10", + "@babel/traverse": "^7.20.1", + "@babel/types": "^7.20.2" } }, "@babel/helper-optimise-call-expression": { @@ -17146,52 +15934,52 @@ } }, "@babel/helper-plugin-utils": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.18.6.tgz", - "integrity": "sha512-gvZnm1YAAxh13eJdkb9EWHBnF3eAub3XTLCZEehHT2kWxiKVRL64+ae5Y6Ivne0mVHmMYKT+xWgZO+gQhuLUBg==", + "version": "7.20.2", + "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.20.2.tgz", + "integrity": "sha512-8RvlJG2mj4huQ4pZ+rU9lqKi9ZKiRmuvGuM2HlWmkmgOhbs6zEAw6IEiJ5cQqGbDzGZOhwuOQNtZMi/ENLjZoQ==", "dev": true }, "@babel/helper-remap-async-to-generator": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/helper-remap-async-to-generator/-/helper-remap-async-to-generator-7.18.6.tgz", - "integrity": "sha512-z5wbmV55TveUPZlCLZvxWHtrjuJd+8inFhk7DG0WW87/oJuGDcjDiu7HIvGcpf5464L6xKCg3vNkmlVVz9hwyQ==", + "version": "7.18.9", + "resolved": "https://registry.npmjs.org/@babel/helper-remap-async-to-generator/-/helper-remap-async-to-generator-7.18.9.tgz", + "integrity": "sha512-dI7q50YKd8BAv3VEfgg7PS7yD3Rtbi2J1XMXaalXO0W0164hYLnh8zpjRS0mte9MfVp/tltvr/cfdXPvJr1opA==", "dev": true, "requires": { "@babel/helper-annotate-as-pure": "^7.18.6", - "@babel/helper-environment-visitor": "^7.18.6", - "@babel/helper-wrap-function": "^7.18.6", - "@babel/types": "^7.18.6" + "@babel/helper-environment-visitor": "^7.18.9", + "@babel/helper-wrap-function": "^7.18.9", + "@babel/types": "^7.18.9" } }, "@babel/helper-replace-supers": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/helper-replace-supers/-/helper-replace-supers-7.18.6.tgz", - "integrity": "sha512-fTf7zoXnUGl9gF25fXCWE26t7Tvtyn6H4hkLSYhATwJvw2uYxd3aoXplMSe0g9XbwK7bmxNes7+FGO0rB/xC0g==", + "version": "7.19.1", + "resolved": "https://registry.npmjs.org/@babel/helper-replace-supers/-/helper-replace-supers-7.19.1.tgz", + "integrity": "sha512-T7ahH7wV0Hfs46SFh5Jz3s0B6+o8g3c+7TMxu7xKfmHikg7EAZ3I2Qk9LFhjxXq8sL7UkP5JflezNwoZa8WvWw==", "dev": true, "requires": { - "@babel/helper-environment-visitor": "^7.18.6", - "@babel/helper-member-expression-to-functions": "^7.18.6", + "@babel/helper-environment-visitor": "^7.18.9", + "@babel/helper-member-expression-to-functions": "^7.18.9", "@babel/helper-optimise-call-expression": "^7.18.6", - "@babel/traverse": "^7.18.6", - "@babel/types": "^7.18.6" + "@babel/traverse": "^7.19.1", + "@babel/types": "^7.19.0" } }, "@babel/helper-simple-access": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/helper-simple-access/-/helper-simple-access-7.18.6.tgz", - "integrity": "sha512-iNpIgTgyAvDQpDj76POqg+YEt8fPxx3yaNBg3S30dxNKm2SWfYhD0TGrK/Eu9wHpUW63VQU894TsTg+GLbUa1g==", + "version": "7.20.2", + "resolved": "https://registry.npmjs.org/@babel/helper-simple-access/-/helper-simple-access-7.20.2.tgz", + "integrity": "sha512-+0woI/WPq59IrqDYbVGfshjT5Dmk/nnbdpcF8SnMhhXObpTq2KNBdLFRFrkVdbDOyUmHBCxzm5FHV1rACIkIbA==", "dev": true, "requires": { - "@babel/types": "^7.18.6" + "@babel/types": "^7.20.2" } }, "@babel/helper-skip-transparent-expression-wrappers": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/helper-skip-transparent-expression-wrappers/-/helper-skip-transparent-expression-wrappers-7.18.6.tgz", - "integrity": "sha512-4KoLhwGS9vGethZpAhYnMejWkX64wsnHPDwvOsKWU6Fg4+AlK2Jz3TyjQLMEPvz+1zemi/WBdkYxCD0bAfIkiw==", + "version": "7.18.9", + "resolved": "https://registry.npmjs.org/@babel/helper-skip-transparent-expression-wrappers/-/helper-skip-transparent-expression-wrappers-7.18.9.tgz", + "integrity": "sha512-imytd2gHi3cJPsybLRbmFrF7u5BIEuI2cNheyKi3/iOBC63kNn3q8Crn2xVuESli0aM4KYsyEqKyS7lFL8YVtw==", "dev": true, "requires": { - "@babel/types": "^7.18.6" + "@babel/types": "^7.18.9" } }, "@babel/helper-split-export-declaration": { @@ -17203,10 +15991,16 @@ "@babel/types": "^7.18.6" } }, + "@babel/helper-string-parser": { + "version": "7.19.4", + "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.19.4.tgz", + "integrity": "sha512-nHtDoQcuqFmwYNYPz3Rah5ph2p8PFeFCsZk9A/48dPc/rGocJ5J3hAAZ7pb76VWX3fZKu+uEr/FhH5jLx7umrw==", + "dev": true + }, "@babel/helper-validator-identifier": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.18.6.tgz", - "integrity": "sha512-MmetCkz9ej86nJQV+sFCxoGGrUbU3q02kgLciwkrt9QqEB7cP39oKEY0PakknEO0Gu20SskMRi+AYZ3b1TpN9g==", + "version": "7.19.1", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.19.1.tgz", + "integrity": "sha512-awrNfaMtnHUr653GgGEs++LlAvW6w+DcPrOliSMXWCKo597CwL5Acf/wWdNkf/tfEQE3mjkeD1YOVZOUV/od1w==", "dev": true }, "@babel/helper-validator-option": { @@ -17216,26 +16010,26 @@ "dev": true }, "@babel/helper-wrap-function": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/helper-wrap-function/-/helper-wrap-function-7.18.6.tgz", - "integrity": "sha512-I5/LZfozwMNbwr/b1vhhuYD+J/mU+gfGAj5td7l5Rv9WYmH6i3Om69WGKNmlIpsVW/mF6O5bvTKbvDQZVgjqOw==", + "version": "7.18.11", + "resolved": "https://registry.npmjs.org/@babel/helper-wrap-function/-/helper-wrap-function-7.18.11.tgz", + "integrity": "sha512-oBUlbv+rjZLh2Ks9SKi4aL7eKaAXBWleHzU89mP0G6BMUlRxSckk9tSIkgDGydhgFxHuGSlBQZfnaD47oBEB7w==", "dev": true, "requires": { - "@babel/helper-function-name": "^7.18.6", - "@babel/template": "^7.18.6", - "@babel/traverse": "^7.18.6", - "@babel/types": "^7.18.6" + "@babel/helper-function-name": "^7.18.9", + "@babel/template": "^7.18.10", + "@babel/traverse": "^7.18.11", + "@babel/types": "^7.18.10" } }, "@babel/helpers": { - "version": "7.18.2", - "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.18.2.tgz", - "integrity": "sha512-j+d+u5xT5utcQSzrh9p+PaJX94h++KN+ng9b9WEJq7pkUPAd61FGqhjuUEdfknb3E/uDBb7ruwEeKkIxNJPIrg==", + "version": "7.20.1", + "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.20.1.tgz", + "integrity": "sha512-J77mUVaDTUJFZ5BpP6mMn6OIl3rEWymk2ZxDBQJUG3P+PbmyMcF3bYWvz0ma69Af1oobDqT/iAsvzhB58xhQUg==", "dev": true, "requires": { - "@babel/template": "^7.16.7", - "@babel/traverse": "^7.18.2", - "@babel/types": "^7.18.2" + "@babel/template": "^7.18.10", + "@babel/traverse": "^7.20.1", + "@babel/types": "^7.20.0" } }, "@babel/highlight": { @@ -17250,9 +16044,9 @@ } }, "@babel/parser": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.18.6.tgz", - "integrity": "sha512-uQVSa9jJUe/G/304lXspfWVpKpK4euFLgGiMQFOCpM/bgcAdeoHwi/OQz23O9GK2osz26ZiXRRV9aV+Yl1O8tw==", + "version": "7.20.2", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.20.2.tgz", + "integrity": "sha512-afk318kh2uKbo7BEj2QtEi8HVCGrwHUffrYDy7dgVcSa2j9lY3LDjPzcyGdpX7xgm35aWqvciZJ4WKmdF/SxYg==", "dev": true }, "@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression": { @@ -17265,25 +16059,25 @@ } }, "@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining/-/plugin-bugfix-v8-spread-parameters-in-optional-chaining-7.18.6.tgz", - "integrity": "sha512-Udgu8ZRgrBrttVz6A0EVL0SJ1z+RLbIeqsu632SA1hf0awEppD6TvdznoH+orIF8wtFFAV/Enmw9Y+9oV8TQcw==", + "version": "7.18.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining/-/plugin-bugfix-v8-spread-parameters-in-optional-chaining-7.18.9.tgz", + "integrity": "sha512-AHrP9jadvH7qlOj6PINbgSuphjQUAK7AOT7DPjBo9EHoLhQTnnK5u45e1Hd4DbSQEO9nqPWtQ89r+XEOWFScKg==", "dev": true, "requires": { - "@babel/helper-plugin-utils": "^7.18.6", - "@babel/helper-skip-transparent-expression-wrappers": "^7.18.6", - "@babel/plugin-proposal-optional-chaining": "^7.18.6" + "@babel/helper-plugin-utils": "^7.18.9", + "@babel/helper-skip-transparent-expression-wrappers": "^7.18.9", + "@babel/plugin-proposal-optional-chaining": "^7.18.9" } }, "@babel/plugin-proposal-async-generator-functions": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-async-generator-functions/-/plugin-proposal-async-generator-functions-7.18.6.tgz", - "integrity": "sha512-WAz4R9bvozx4qwf74M+sfqPMKfSqwM0phxPTR6iJIi8robgzXwkEgmeJG1gEKhm6sDqT/U9aV3lfcqybIpev8w==", + "version": "7.20.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-async-generator-functions/-/plugin-proposal-async-generator-functions-7.20.1.tgz", + "integrity": "sha512-Gh5rchzSwE4kC+o/6T8waD0WHEQIsDmjltY8WnWRXHUdH8axZhuH86Ov9M72YhJfDrZseQwuuWaaIT/TmePp3g==", "dev": true, "requires": { - "@babel/helper-environment-visitor": "^7.18.6", - "@babel/helper-plugin-utils": "^7.18.6", - "@babel/helper-remap-async-to-generator": "^7.18.6", + "@babel/helper-environment-visitor": "^7.18.9", + "@babel/helper-plugin-utils": "^7.19.0", + "@babel/helper-remap-async-to-generator": "^7.18.9", "@babel/plugin-syntax-async-generators": "^7.8.4" } }, @@ -17319,12 +16113,12 @@ } }, "@babel/plugin-proposal-export-namespace-from": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-export-namespace-from/-/plugin-proposal-export-namespace-from-7.18.6.tgz", - "integrity": "sha512-zr/QcUlUo7GPo6+X1wC98NJADqmy5QTFWWhqeQWiki4XHafJtLl/YMGkmRB2szDD2IYJCCdBTd4ElwhId9T7Xw==", + "version": "7.18.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-export-namespace-from/-/plugin-proposal-export-namespace-from-7.18.9.tgz", + "integrity": "sha512-k1NtHyOMvlDDFeb9G5PhUXuGj8m/wiwojgQVEhJ/fsVsMCpLyOP4h0uGEjYJKrRI+EVPlb5Jk+Gt9P97lOGwtA==", "dev": true, "requires": { - "@babel/helper-plugin-utils": "^7.18.6", + "@babel/helper-plugin-utils": "^7.18.9", "@babel/plugin-syntax-export-namespace-from": "^7.8.3" } }, @@ -17339,12 +16133,12 @@ } }, "@babel/plugin-proposal-logical-assignment-operators": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-logical-assignment-operators/-/plugin-proposal-logical-assignment-operators-7.18.6.tgz", - "integrity": "sha512-zMo66azZth/0tVd7gmkxOkOjs2rpHyhpcFo565PUP37hSp6hSd9uUKIfTDFMz58BwqgQKhJ9YxtM5XddjXVn+Q==", + "version": "7.18.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-logical-assignment-operators/-/plugin-proposal-logical-assignment-operators-7.18.9.tgz", + "integrity": "sha512-128YbMpjCrP35IOExw2Fq+x55LMP42DzhOhX2aNNIdI9avSWl2PI0yuBWarr3RYpZBSPtabfadkH2yeRiMD61Q==", "dev": true, "requires": { - "@babel/helper-plugin-utils": "^7.18.6", + "@babel/helper-plugin-utils": "^7.18.9", "@babel/plugin-syntax-logical-assignment-operators": "^7.10.4" } }, @@ -17369,16 +16163,16 @@ } }, "@babel/plugin-proposal-object-rest-spread": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-object-rest-spread/-/plugin-proposal-object-rest-spread-7.18.6.tgz", - "integrity": "sha512-9yuM6wr4rIsKa1wlUAbZEazkCrgw2sMPEXCr4Rnwetu7cEW1NydkCWytLuYletbf8vFxdJxFhwEZqMpOx2eZyw==", + "version": "7.20.2", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-object-rest-spread/-/plugin-proposal-object-rest-spread-7.20.2.tgz", + "integrity": "sha512-Ks6uej9WFK+fvIMesSqbAto5dD8Dz4VuuFvGJFKgIGSkJuRGcrwGECPA1fDgQK3/DbExBJpEkTeYeB8geIFCSQ==", "dev": true, "requires": { - "@babel/compat-data": "^7.18.6", - "@babel/helper-compilation-targets": "^7.18.6", - "@babel/helper-plugin-utils": "^7.18.6", + "@babel/compat-data": "^7.20.1", + "@babel/helper-compilation-targets": "^7.20.0", + "@babel/helper-plugin-utils": "^7.20.2", "@babel/plugin-syntax-object-rest-spread": "^7.8.3", - "@babel/plugin-transform-parameters": "^7.18.6" + "@babel/plugin-transform-parameters": "^7.20.1" } }, "@babel/plugin-proposal-optional-catch-binding": { @@ -17392,13 +16186,13 @@ } }, "@babel/plugin-proposal-optional-chaining": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-optional-chaining/-/plugin-proposal-optional-chaining-7.18.6.tgz", - "integrity": "sha512-PatI6elL5eMzoypFAiYDpYQyMtXTn+iMhuxxQt5mAXD4fEmKorpSI3PHd+i3JXBJN3xyA6MvJv7at23HffFHwA==", + "version": "7.18.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-optional-chaining/-/plugin-proposal-optional-chaining-7.18.9.tgz", + "integrity": "sha512-v5nwt4IqBXihxGsW2QmCWMDS3B3bzGIk/EQVZz2ei7f3NJl8NzAJVvUmpDW5q1CRNY+Beb/k58UAH1Km1N411w==", "dev": true, "requires": { - "@babel/helper-plugin-utils": "^7.18.6", - "@babel/helper-skip-transparent-expression-wrappers": "^7.18.6", + "@babel/helper-plugin-utils": "^7.18.9", + "@babel/helper-skip-transparent-expression-wrappers": "^7.18.9", "@babel/plugin-syntax-optional-chaining": "^7.8.3" } }, @@ -17480,12 +16274,12 @@ } }, "@babel/plugin-syntax-import-assertions": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-import-assertions/-/plugin-syntax-import-assertions-7.18.6.tgz", - "integrity": "sha512-/DU3RXad9+bZwrgWJQKbr39gYbJpLJHezqEzRzi/BHRlJ9zsQb4CK2CA/5apllXNomwA1qHwzvHl+AdEmC5krQ==", + "version": "7.20.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-import-assertions/-/plugin-syntax-import-assertions-7.20.0.tgz", + "integrity": "sha512-IUh1vakzNoWalR8ch/areW7qFopR2AEw03JlG7BbrDqmQ4X3q9uuipQwSGrUn7oGiemKjtSLDhNtQHzMHr1JdQ==", "dev": true, "requires": { - "@babel/helper-plugin-utils": "^7.18.6" + "@babel/helper-plugin-utils": "^7.19.0" } }, "@babel/plugin-syntax-json-strings": { @@ -17599,46 +16393,47 @@ } }, "@babel/plugin-transform-block-scoping": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-block-scoping/-/plugin-transform-block-scoping-7.18.6.tgz", - "integrity": "sha512-pRqwb91C42vs1ahSAWJkxOxU1RHWDn16XAa6ggQ72wjLlWyYeAcLvTtE0aM8ph3KNydy9CQF2nLYcjq1WysgxQ==", + "version": "7.20.2", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-block-scoping/-/plugin-transform-block-scoping-7.20.2.tgz", + "integrity": "sha512-y5V15+04ry69OV2wULmwhEA6jwSWXO1TwAtIwiPXcvHcoOQUqpyMVd2bDsQJMW8AurjulIyUV8kDqtjSwHy1uQ==", "dev": true, "requires": { - "@babel/helper-plugin-utils": "^7.18.6" + "@babel/helper-plugin-utils": "^7.20.2" } }, "@babel/plugin-transform-classes": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-classes/-/plugin-transform-classes-7.18.6.tgz", - "integrity": "sha512-XTg8XW/mKpzAF3actL554Jl/dOYoJtv3l8fxaEczpgz84IeeVf+T1u2CSvPHuZbt0w3JkIx4rdn/MRQI7mo0HQ==", + "version": "7.20.2", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-classes/-/plugin-transform-classes-7.20.2.tgz", + "integrity": "sha512-9rbPp0lCVVoagvtEyQKSo5L8oo0nQS/iif+lwlAz29MccX2642vWDlSZK+2T2buxbopotId2ld7zZAzRfz9j1g==", "dev": true, "requires": { "@babel/helper-annotate-as-pure": "^7.18.6", - "@babel/helper-environment-visitor": "^7.18.6", - "@babel/helper-function-name": "^7.18.6", + "@babel/helper-compilation-targets": "^7.20.0", + "@babel/helper-environment-visitor": "^7.18.9", + "@babel/helper-function-name": "^7.19.0", "@babel/helper-optimise-call-expression": "^7.18.6", - "@babel/helper-plugin-utils": "^7.18.6", - "@babel/helper-replace-supers": "^7.18.6", + "@babel/helper-plugin-utils": "^7.20.2", + "@babel/helper-replace-supers": "^7.19.1", "@babel/helper-split-export-declaration": "^7.18.6", "globals": "^11.1.0" } }, "@babel/plugin-transform-computed-properties": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-computed-properties/-/plugin-transform-computed-properties-7.18.6.tgz", - "integrity": "sha512-9repI4BhNrR0KenoR9vm3/cIc1tSBIo+u1WVjKCAynahj25O8zfbiE6JtAtHPGQSs4yZ+bA8mRasRP+qc+2R5A==", + "version": "7.18.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-computed-properties/-/plugin-transform-computed-properties-7.18.9.tgz", + "integrity": "sha512-+i0ZU1bCDymKakLxn5srGHrsAPRELC2WIbzwjLhHW9SIE1cPYkLCL0NlnXMZaM1vhfgA2+M7hySk42VBvrkBRw==", "dev": true, "requires": { - "@babel/helper-plugin-utils": "^7.18.6" + "@babel/helper-plugin-utils": "^7.18.9" } }, "@babel/plugin-transform-destructuring": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-destructuring/-/plugin-transform-destructuring-7.18.6.tgz", - "integrity": "sha512-tgy3u6lRp17ilY8r1kP4i2+HDUwxlVqq3RTc943eAWSzGgpU1qhiKpqZ5CMyHReIYPHdo3Kg8v8edKtDqSVEyQ==", + "version": "7.20.2", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-destructuring/-/plugin-transform-destructuring-7.20.2.tgz", + "integrity": "sha512-mENM+ZHrvEgxLTBXUiQ621rRXZes3KWUv6NdQlrnr1TkWVw+hUjQBZuP2X32qKlrlG2BzgR95gkuCRSkJl8vIw==", "dev": true, "requires": { - "@babel/helper-plugin-utils": "^7.18.6" + "@babel/helper-plugin-utils": "^7.20.2" } }, "@babel/plugin-transform-dotall-regex": { @@ -17652,12 +16447,12 @@ } }, "@babel/plugin-transform-duplicate-keys": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-duplicate-keys/-/plugin-transform-duplicate-keys-7.18.6.tgz", - "integrity": "sha512-NJU26U/208+sxYszf82nmGYqVF9QN8py2HFTblPT9hbawi8+1C5a9JubODLTGFuT0qlkqVinmkwOD13s0sZktg==", + "version": "7.18.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-duplicate-keys/-/plugin-transform-duplicate-keys-7.18.9.tgz", + "integrity": "sha512-d2bmXCtZXYc59/0SanQKbiWINadaJXqtvIQIzd4+hNwkWBgyCd5F/2t1kXoUdvPMrxzPvhK6EMQRROxsue+mfw==", "dev": true, "requires": { - "@babel/helper-plugin-utils": "^7.18.6" + "@babel/helper-plugin-utils": "^7.18.9" } }, "@babel/plugin-transform-exponentiation-operator": { @@ -17671,32 +16466,32 @@ } }, "@babel/plugin-transform-for-of": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-for-of/-/plugin-transform-for-of-7.18.6.tgz", - "integrity": "sha512-WAjoMf4wIiSsy88KmG7tgj2nFdEK7E46tArVtcgED7Bkj6Fg/tG5SbvNIOKxbFS2VFgNh6+iaPswBeQZm4ox8w==", + "version": "7.18.8", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-for-of/-/plugin-transform-for-of-7.18.8.tgz", + "integrity": "sha512-yEfTRnjuskWYo0k1mHUqrVWaZwrdq8AYbfrpqULOJOaucGSp4mNMVps+YtA8byoevxS/urwU75vyhQIxcCgiBQ==", "dev": true, "requires": { "@babel/helper-plugin-utils": "^7.18.6" } }, "@babel/plugin-transform-function-name": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-function-name/-/plugin-transform-function-name-7.18.6.tgz", - "integrity": "sha512-kJha/Gbs5RjzIu0CxZwf5e3aTTSlhZnHMT8zPWnJMjNpLOUgqevg+PN5oMH68nMCXnfiMo4Bhgxqj59KHTlAnA==", + "version": "7.18.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-function-name/-/plugin-transform-function-name-7.18.9.tgz", + "integrity": "sha512-WvIBoRPaJQ5yVHzcnJFor7oS5Ls0PYixlTYE63lCj2RtdQEl15M68FXQlxnG6wdraJIXRdR7KI+hQ7q/9QjrCQ==", "dev": true, "requires": { - "@babel/helper-compilation-targets": "^7.18.6", - "@babel/helper-function-name": "^7.18.6", - "@babel/helper-plugin-utils": "^7.18.6" + "@babel/helper-compilation-targets": "^7.18.9", + "@babel/helper-function-name": "^7.18.9", + "@babel/helper-plugin-utils": "^7.18.9" } }, "@babel/plugin-transform-literals": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-literals/-/plugin-transform-literals-7.18.6.tgz", - "integrity": "sha512-x3HEw0cJZVDoENXOp20HlypIHfl0zMIhMVZEBVTfmqbObIpsMxMbmU5nOEO8R7LYT+z5RORKPlTI5Hj4OsO9/Q==", + "version": "7.18.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-literals/-/plugin-transform-literals-7.18.9.tgz", + "integrity": "sha512-IFQDSRoTPnrAIrI5zoZv73IFeZu2dhu6irxQjY9rNjTT53VmKg9fenjvoiOWOkJ6mm4jKVPtdMzBY98Fp4Z4cg==", "dev": true, "requires": { - "@babel/helper-plugin-utils": "^7.18.6" + "@babel/helper-plugin-utils": "^7.18.9" } }, "@babel/plugin-transform-member-expression-literals": { @@ -17709,39 +16504,36 @@ } }, "@babel/plugin-transform-modules-amd": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-amd/-/plugin-transform-modules-amd-7.18.6.tgz", - "integrity": "sha512-Pra5aXsmTsOnjM3IajS8rTaLCy++nGM4v3YR4esk5PCsyg9z8NA5oQLwxzMUtDBd8F+UmVza3VxoAaWCbzH1rg==", + "version": "7.19.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-amd/-/plugin-transform-modules-amd-7.19.6.tgz", + "integrity": "sha512-uG3od2mXvAtIFQIh0xrpLH6r5fpSQN04gIVovl+ODLdUMANokxQLZnPBHcjmv3GxRjnqwLuHvppjjcelqUFZvg==", "dev": true, "requires": { - "@babel/helper-module-transforms": "^7.18.6", - "@babel/helper-plugin-utils": "^7.18.6", - "babel-plugin-dynamic-import-node": "^2.3.3" + "@babel/helper-module-transforms": "^7.19.6", + "@babel/helper-plugin-utils": "^7.19.0" } }, "@babel/plugin-transform-modules-commonjs": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-commonjs/-/plugin-transform-modules-commonjs-7.18.6.tgz", - "integrity": "sha512-Qfv2ZOWikpvmedXQJDSbxNqy7Xr/j2Y8/KfijM0iJyKkBTmWuvCA1yeH1yDM7NJhBW/2aXxeucLj6i80/LAJ/Q==", + "version": "7.19.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-commonjs/-/plugin-transform-modules-commonjs-7.19.6.tgz", + "integrity": "sha512-8PIa1ym4XRTKuSsOUXqDG0YaOlEuTVvHMe5JCfgBMOtHvJKw/4NGovEGN33viISshG/rZNVrACiBmPQLvWN8xQ==", "dev": true, "requires": { - "@babel/helper-module-transforms": "^7.18.6", - "@babel/helper-plugin-utils": "^7.18.6", - "@babel/helper-simple-access": "^7.18.6", - "babel-plugin-dynamic-import-node": "^2.3.3" + "@babel/helper-module-transforms": "^7.19.6", + "@babel/helper-plugin-utils": "^7.19.0", + "@babel/helper-simple-access": "^7.19.4" } }, "@babel/plugin-transform-modules-systemjs": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-systemjs/-/plugin-transform-modules-systemjs-7.18.6.tgz", - "integrity": "sha512-UbPYpXxLjTw6w6yXX2BYNxF3p6QY225wcTkfQCy3OMnSlS/C3xGtwUjEzGkldb/sy6PWLiCQ3NbYfjWUTI3t4g==", + "version": "7.19.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-systemjs/-/plugin-transform-modules-systemjs-7.19.6.tgz", + "integrity": "sha512-fqGLBepcc3kErfR9R3DnVpURmckXP7gj7bAlrTQyBxrigFqszZCkFkcoxzCp2v32XmwXLvbw+8Yq9/b+QqksjQ==", "dev": true, "requires": { "@babel/helper-hoist-variables": "^7.18.6", - "@babel/helper-module-transforms": "^7.18.6", - "@babel/helper-plugin-utils": "^7.18.6", - "@babel/helper-validator-identifier": "^7.18.6", - "babel-plugin-dynamic-import-node": "^2.3.3" + "@babel/helper-module-transforms": "^7.19.6", + "@babel/helper-plugin-utils": "^7.19.0", + "@babel/helper-validator-identifier": "^7.19.1" } }, "@babel/plugin-transform-modules-umd": { @@ -17755,13 +16547,13 @@ } }, "@babel/plugin-transform-named-capturing-groups-regex": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-named-capturing-groups-regex/-/plugin-transform-named-capturing-groups-regex-7.18.6.tgz", - "integrity": "sha512-UmEOGF8XgaIqD74bC8g7iV3RYj8lMf0Bw7NJzvnS9qQhM4mg+1WHKotUIdjxgD2RGrgFLZZPCFPFj3P/kVDYhg==", + "version": "7.19.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-named-capturing-groups-regex/-/plugin-transform-named-capturing-groups-regex-7.19.1.tgz", + "integrity": "sha512-oWk9l9WItWBQYS4FgXD4Uyy5kq898lvkXpXQxoJEY1RnvPk4R/Dvu2ebXU9q8lP+rlMwUQTFf2Ok6d78ODa0kw==", "dev": true, "requires": { - "@babel/helper-create-regexp-features-plugin": "^7.18.6", - "@babel/helper-plugin-utils": "^7.18.6" + "@babel/helper-create-regexp-features-plugin": "^7.19.0", + "@babel/helper-plugin-utils": "^7.19.0" } }, "@babel/plugin-transform-new-target": { @@ -17784,12 +16576,12 @@ } }, "@babel/plugin-transform-parameters": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-parameters/-/plugin-transform-parameters-7.18.6.tgz", - "integrity": "sha512-FjdqgMv37yVl/gwvzkcB+wfjRI8HQmc5EgOG9iGNvUY1ok+TjsoaMP7IqCDZBhkFcM5f3OPVMs6Dmp03C5k4/A==", + "version": "7.20.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-parameters/-/plugin-transform-parameters-7.20.1.tgz", + "integrity": "sha512-nDvKLrAvl+kf6BOy1UJ3MGwzzfTMgppxwiD2Jb4LO3xjYyZq30oQzDNJbCQpMdG9+j2IXHoiMrw5Cm/L6ZoxXQ==", "dev": true, "requires": { - "@babel/helper-plugin-utils": "^7.18.6" + "@babel/helper-plugin-utils": "^7.19.0" } }, "@babel/plugin-transform-property-literals": { @@ -17830,13 +16622,13 @@ } }, "@babel/plugin-transform-spread": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-spread/-/plugin-transform-spread-7.18.6.tgz", - "integrity": "sha512-ayT53rT/ENF8WWexIRg9AiV9h0aIteyWn5ptfZTZQrjk/+f3WdrJGCY4c9wcgl2+MKkKPhzbYp97FTsquZpDCw==", + "version": "7.19.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-spread/-/plugin-transform-spread-7.19.0.tgz", + "integrity": "sha512-RsuMk7j6n+r752EtzyScnWkQyuJdli6LdO5Klv8Yx0OfPVTcQkIUfS8clx5e9yHXzlnhOZF3CbQ8C2uP5j074w==", "dev": true, "requires": { - "@babel/helper-plugin-utils": "^7.18.6", - "@babel/helper-skip-transparent-expression-wrappers": "^7.18.6" + "@babel/helper-plugin-utils": "^7.19.0", + "@babel/helper-skip-transparent-expression-wrappers": "^7.18.9" } }, "@babel/plugin-transform-sticky-regex": { @@ -17849,30 +16641,30 @@ } }, "@babel/plugin-transform-template-literals": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-template-literals/-/plugin-transform-template-literals-7.18.6.tgz", - "integrity": "sha512-UuqlRrQmT2SWRvahW46cGSany0uTlcj8NYOS5sRGYi8FxPYPoLd5DDmMd32ZXEj2Jq+06uGVQKHxa/hJx2EzKw==", + "version": "7.18.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-template-literals/-/plugin-transform-template-literals-7.18.9.tgz", + "integrity": "sha512-S8cOWfT82gTezpYOiVaGHrCbhlHgKhQt8XH5ES46P2XWmX92yisoZywf5km75wv5sYcXDUCLMmMxOLCtthDgMA==", "dev": true, "requires": { - "@babel/helper-plugin-utils": "^7.18.6" + "@babel/helper-plugin-utils": "^7.18.9" } }, "@babel/plugin-transform-typeof-symbol": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-typeof-symbol/-/plugin-transform-typeof-symbol-7.18.6.tgz", - "integrity": "sha512-7m71iS/QhsPk85xSjFPovHPcH3H9qeyzsujhTc+vcdnsXavoWYJ74zx0lP5RhpC5+iDnVLO+PPMHzC11qels1g==", + "version": "7.18.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-typeof-symbol/-/plugin-transform-typeof-symbol-7.18.9.tgz", + "integrity": "sha512-SRfwTtF11G2aemAZWivL7PD+C9z52v9EvMqH9BuYbabyPuKUvSWks3oCg6041pT925L4zVFqaVBeECwsmlguEw==", "dev": true, "requires": { - "@babel/helper-plugin-utils": "^7.18.6" + "@babel/helper-plugin-utils": "^7.18.9" } }, "@babel/plugin-transform-unicode-escapes": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-escapes/-/plugin-transform-unicode-escapes-7.18.6.tgz", - "integrity": "sha512-XNRwQUXYMP7VLuy54cr/KS/WeL3AZeORhrmeZ7iewgu+X2eBqmpaLI/hzqr9ZxCeUoq0ASK4GUzSM0BDhZkLFw==", + "version": "7.18.10", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-escapes/-/plugin-transform-unicode-escapes-7.18.10.tgz", + "integrity": "sha512-kKAdAI+YzPgGY/ftStBFXTI1LZFju38rYThnfMykS+IXy8BVx+res7s2fxf1l8I35DV2T97ezo6+SGrXz6B3iQ==", "dev": true, "requires": { - "@babel/helper-plugin-utils": "^7.18.6" + "@babel/helper-plugin-utils": "^7.18.9" } }, "@babel/plugin-transform-unicode-regex": { @@ -17886,29 +16678,29 @@ } }, "@babel/preset-env": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/preset-env/-/preset-env-7.18.6.tgz", - "integrity": "sha512-WrthhuIIYKrEFAwttYzgRNQ5hULGmwTj+D6l7Zdfsv5M7IWV/OZbUfbeL++Qrzx1nVJwWROIFhCHRYQV4xbPNw==", + "version": "7.20.2", + "resolved": "https://registry.npmjs.org/@babel/preset-env/-/preset-env-7.20.2.tgz", + "integrity": "sha512-1G0efQEWR1EHkKvKHqbG+IN/QdgwfByUpM5V5QroDzGV2t3S/WXNQd693cHiHTlCFMpr9B6FkPFXDA2lQcKoDg==", "dev": true, "requires": { - "@babel/compat-data": "^7.18.6", - "@babel/helper-compilation-targets": "^7.18.6", - "@babel/helper-plugin-utils": "^7.18.6", + "@babel/compat-data": "^7.20.1", + "@babel/helper-compilation-targets": "^7.20.0", + "@babel/helper-plugin-utils": "^7.20.2", "@babel/helper-validator-option": "^7.18.6", "@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression": "^7.18.6", - "@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining": "^7.18.6", - "@babel/plugin-proposal-async-generator-functions": "^7.18.6", + "@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining": "^7.18.9", + "@babel/plugin-proposal-async-generator-functions": "^7.20.1", "@babel/plugin-proposal-class-properties": "^7.18.6", "@babel/plugin-proposal-class-static-block": "^7.18.6", "@babel/plugin-proposal-dynamic-import": "^7.18.6", - "@babel/plugin-proposal-export-namespace-from": "^7.18.6", + "@babel/plugin-proposal-export-namespace-from": "^7.18.9", "@babel/plugin-proposal-json-strings": "^7.18.6", - "@babel/plugin-proposal-logical-assignment-operators": "^7.18.6", + "@babel/plugin-proposal-logical-assignment-operators": "^7.18.9", "@babel/plugin-proposal-nullish-coalescing-operator": "^7.18.6", "@babel/plugin-proposal-numeric-separator": "^7.18.6", - "@babel/plugin-proposal-object-rest-spread": "^7.18.6", + "@babel/plugin-proposal-object-rest-spread": "^7.20.2", "@babel/plugin-proposal-optional-catch-binding": "^7.18.6", - "@babel/plugin-proposal-optional-chaining": "^7.18.6", + "@babel/plugin-proposal-optional-chaining": "^7.18.9", "@babel/plugin-proposal-private-methods": "^7.18.6", "@babel/plugin-proposal-private-property-in-object": "^7.18.6", "@babel/plugin-proposal-unicode-property-regex": "^7.18.6", @@ -17917,7 +16709,7 @@ "@babel/plugin-syntax-class-static-block": "^7.14.5", "@babel/plugin-syntax-dynamic-import": "^7.8.3", "@babel/plugin-syntax-export-namespace-from": "^7.8.3", - "@babel/plugin-syntax-import-assertions": "^7.18.6", + "@babel/plugin-syntax-import-assertions": "^7.20.0", "@babel/plugin-syntax-json-strings": "^7.8.3", "@babel/plugin-syntax-logical-assignment-operators": "^7.10.4", "@babel/plugin-syntax-nullish-coalescing-operator": "^7.8.3", @@ -17930,41 +16722,41 @@ "@babel/plugin-transform-arrow-functions": "^7.18.6", "@babel/plugin-transform-async-to-generator": "^7.18.6", "@babel/plugin-transform-block-scoped-functions": "^7.18.6", - "@babel/plugin-transform-block-scoping": "^7.18.6", - "@babel/plugin-transform-classes": "^7.18.6", - "@babel/plugin-transform-computed-properties": "^7.18.6", - "@babel/plugin-transform-destructuring": "^7.18.6", + "@babel/plugin-transform-block-scoping": "^7.20.2", + "@babel/plugin-transform-classes": "^7.20.2", + "@babel/plugin-transform-computed-properties": "^7.18.9", + "@babel/plugin-transform-destructuring": "^7.20.2", "@babel/plugin-transform-dotall-regex": "^7.18.6", - "@babel/plugin-transform-duplicate-keys": "^7.18.6", + "@babel/plugin-transform-duplicate-keys": "^7.18.9", "@babel/plugin-transform-exponentiation-operator": "^7.18.6", - "@babel/plugin-transform-for-of": "^7.18.6", - "@babel/plugin-transform-function-name": "^7.18.6", - "@babel/plugin-transform-literals": "^7.18.6", + "@babel/plugin-transform-for-of": "^7.18.8", + "@babel/plugin-transform-function-name": "^7.18.9", + "@babel/plugin-transform-literals": "^7.18.9", "@babel/plugin-transform-member-expression-literals": "^7.18.6", - "@babel/plugin-transform-modules-amd": "^7.18.6", - "@babel/plugin-transform-modules-commonjs": "^7.18.6", - "@babel/plugin-transform-modules-systemjs": "^7.18.6", + "@babel/plugin-transform-modules-amd": "^7.19.6", + "@babel/plugin-transform-modules-commonjs": "^7.19.6", + "@babel/plugin-transform-modules-systemjs": "^7.19.6", "@babel/plugin-transform-modules-umd": "^7.18.6", - "@babel/plugin-transform-named-capturing-groups-regex": "^7.18.6", + "@babel/plugin-transform-named-capturing-groups-regex": "^7.19.1", "@babel/plugin-transform-new-target": "^7.18.6", "@babel/plugin-transform-object-super": "^7.18.6", - "@babel/plugin-transform-parameters": "^7.18.6", + "@babel/plugin-transform-parameters": "^7.20.1", "@babel/plugin-transform-property-literals": "^7.18.6", "@babel/plugin-transform-regenerator": "^7.18.6", "@babel/plugin-transform-reserved-words": "^7.18.6", "@babel/plugin-transform-shorthand-properties": "^7.18.6", - "@babel/plugin-transform-spread": "^7.18.6", + "@babel/plugin-transform-spread": "^7.19.0", "@babel/plugin-transform-sticky-regex": "^7.18.6", - "@babel/plugin-transform-template-literals": "^7.18.6", - "@babel/plugin-transform-typeof-symbol": "^7.18.6", - "@babel/plugin-transform-unicode-escapes": "^7.18.6", + "@babel/plugin-transform-template-literals": "^7.18.9", + "@babel/plugin-transform-typeof-symbol": "^7.18.9", + "@babel/plugin-transform-unicode-escapes": "^7.18.10", "@babel/plugin-transform-unicode-regex": "^7.18.6", "@babel/preset-modules": "^0.1.5", - "@babel/types": "^7.18.6", - "babel-plugin-polyfill-corejs2": "^0.3.1", - "babel-plugin-polyfill-corejs3": "^0.5.2", - "babel-plugin-polyfill-regenerator": "^0.3.1", - "core-js-compat": "^3.22.1", + "@babel/types": "^7.20.2", + "babel-plugin-polyfill-corejs2": "^0.3.3", + "babel-plugin-polyfill-corejs3": "^0.6.0", + "babel-plugin-polyfill-regenerator": "^0.4.1", + "core-js-compat": "^3.25.1", "semver": "^6.3.0" } }, @@ -17991,41 +16783,42 @@ } }, "@babel/template": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.18.6.tgz", - "integrity": "sha512-JoDWzPe+wgBsTTgdnIma3iHNFC7YVJoPssVBDjiHfNlyt4YcunDtcDOUmfVDfCK5MfdsaIoX9PkijPhjH3nYUw==", + "version": "7.18.10", + "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.18.10.tgz", + "integrity": "sha512-TI+rCtooWHr3QJ27kJxfjutghu44DLnasDMwpDqCXVTal9RLp3RSYNh4NdBrRP2cQAoG9A8juOQl6P6oZG4JxA==", "dev": true, "requires": { "@babel/code-frame": "^7.18.6", - "@babel/parser": "^7.18.6", - "@babel/types": "^7.18.6" + "@babel/parser": "^7.18.10", + "@babel/types": "^7.18.10" } }, "@babel/traverse": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.18.6.tgz", - "integrity": "sha512-zS/OKyqmD7lslOtFqbscH6gMLFYOfG1YPqCKfAW5KrTeolKqvB8UelR49Fpr6y93kYkW2Ik00mT1LOGiAGvizw==", + "version": "7.20.1", + "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.20.1.tgz", + "integrity": "sha512-d3tN8fkVJwFLkHkBN479SOsw4DMZnz8cdbL/gvuDuzy3TS6Nfw80HuQqhw1pITbIruHyh7d1fMA47kWzmcUEGA==", "dev": true, "requires": { "@babel/code-frame": "^7.18.6", - "@babel/generator": "^7.18.6", - "@babel/helper-environment-visitor": "^7.18.6", - "@babel/helper-function-name": "^7.18.6", + "@babel/generator": "^7.20.1", + "@babel/helper-environment-visitor": "^7.18.9", + "@babel/helper-function-name": "^7.19.0", "@babel/helper-hoist-variables": "^7.18.6", "@babel/helper-split-export-declaration": "^7.18.6", - "@babel/parser": "^7.18.6", - "@babel/types": "^7.18.6", + "@babel/parser": "^7.20.1", + "@babel/types": "^7.20.0", "debug": "^4.1.0", "globals": "^11.1.0" } }, "@babel/types": { - "version": "7.18.7", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.18.7.tgz", - "integrity": "sha512-QG3yxTcTIBoAcQmkCs+wAPYZhu7Dk9rXKacINfNbdJDNERTbLQbHGyVG8q/YGMPeCJRIhSY0+fTc5+xuh6WPSQ==", + "version": "7.20.2", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.20.2.tgz", + "integrity": "sha512-FnnvsNWgZCr232sqtXggapvlkk/tuwR/qhGzcmxI0GXLCjmPYQPzio2FbdlWuY6y1sHFfQKk+rRbUZ9VStQMog==", "dev": true, "requires": { - "@babel/helper-validator-identifier": "^7.18.6", + "@babel/helper-string-parser": "^7.19.4", + "@babel/helper-validator-identifier": "^7.19.1", "to-fast-properties": "^2.0.0" } }, @@ -18063,9 +16856,9 @@ } }, "@elastic/elasticsearch": { - "version": "8.2.1", - "resolved": "https://registry.npmjs.org/@elastic/elasticsearch/-/elasticsearch-8.2.1.tgz", - "integrity": "sha512-Kwerd8DfNZdBGgl7fkn+20kXkw1QePB3goTv5QwW9poo2d4VbPE0EChmh6irpXWAGsVSYiKr8x6bh8dH5YdylA==", + "version": "8.5.0", + "resolved": "https://registry.npmjs.org/@elastic/elasticsearch/-/elasticsearch-8.5.0.tgz", + "integrity": "sha512-iOgr/3zQi84WmPhAplnK2W13R89VXD2oc6WhlQmH3bARQwmI+De23ZJKBEn7bvuG/AHMAqasPXX7uJIiJa2MqQ==", "dev": true, "requires": { "@elastic/transport": "^8.2.0", @@ -18111,14 +16904,14 @@ } }, "@fastify/ajv-compiler": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/@fastify/ajv-compiler/-/ajv-compiler-3.1.0.tgz", - "integrity": "sha512-+hRMMxcUmdqtnCGPwrI2yczFdlgp3IBR88WlPLimXlgRb8vHBTXz38I17R/9ui+hIt9jx0uOdZKOis77VooHfA==", + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/@fastify/ajv-compiler/-/ajv-compiler-3.3.1.tgz", + "integrity": "sha512-IRnids8lblQ8e1i8h4JLyfJmebXE+ohcj8x8X/+Ew6ZB4H0Ui05z5YL6q5FOcl0zItVpu4adRzeyVNNUwmduIg==", "dev": true, "requires": { - "ajv": "^8.10.0", + "ajv": "^8.11.0", "ajv-formats": "^2.1.1", - "fast-uri": "^1.0.1" + "fast-uri": "^2.0.0" }, "dependencies": { "ajv": { @@ -18132,15 +16925,15 @@ "require-from-string": "^2.0.2", "uri-js": "^4.2.2" } - }, - "json-schema-traverse": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", - "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==", - "dev": true } } }, + "@fastify/deepmerge": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@fastify/deepmerge/-/deepmerge-1.1.0.tgz", + "integrity": "sha512-E8Hfdvs1bG6u0N4vN5Nty6JONUfTdOciyD5rn8KnEsLKIenvOVcr210BQR9t34PRkNyjqnMLGk3e0BsaxRdL+g==", + "dev": true + }, "@fastify/error": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/@fastify/error/-/error-3.0.0.tgz", @@ -18148,9 +16941,9 @@ "dev": true }, "@fastify/fast-json-stringify-compiler": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/@fastify/fast-json-stringify-compiler/-/fast-json-stringify-compiler-4.0.0.tgz", - "integrity": "sha512-9pCi6c6tmGt/qfuf2koZQuSIG6ckP9q3mz+JoMmAq9eQ4EtA92sWoK7E0LJUn2FFTS/hp5kag+4+dWsV5ZfcXg==", + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/@fastify/fast-json-stringify-compiler/-/fast-json-stringify-compiler-4.1.0.tgz", + "integrity": "sha512-cTKBV2J9+u6VaKDhX7HepSfPSzw+F+TSd+k0wzifj4rG+4E5PjSFJCk19P8R6tr/72cuzgGd+mbB3jFT6lvAgw==", "dev": true, "requires": { "fast-json-stringify": "^5.0.0" @@ -18169,39 +16962,29 @@ } }, "fast-json-stringify": { - "version": "5.0.5", - "resolved": "https://registry.npmjs.org/fast-json-stringify/-/fast-json-stringify-5.0.5.tgz", - "integrity": "sha512-NGXE7I6dBcSTM1pprcLEIQ6nHp424mDn8ABleM17Sp7XkyPLlbIDed41/VhUiqnLICX7XiOoFsNHx/nnJ8qhig==", + "version": "5.4.0", + "resolved": "https://registry.npmjs.org/fast-json-stringify/-/fast-json-stringify-5.4.0.tgz", + "integrity": "sha512-PIzon53oX/zEGLrGbu4DpfNcYiV4K4rk+JsVrawRPO/G8cNBEMZ3KlIk2BCGqN+m1KCCA4zt5E7Hh3GG9ojRVA==", "dev": true, "requires": { + "@fastify/deepmerge": "^1.0.0", "ajv": "^8.10.0", "ajv-formats": "^2.1.1", - "deepmerge": "^4.2.2", + "fast-deep-equal": "^3.1.3", "fast-uri": "^2.1.0", "rfdc": "^1.2.0" } - }, - "fast-uri": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/fast-uri/-/fast-uri-2.1.0.tgz", - "integrity": "sha512-qKRta6N7BWEFVlyonVY/V+BMLgFqktCUV0QjT259ekAIlbVrMaFnFLxJ4s/JPl4tou56S1BzPufI60bLe29fHA==", - "dev": true - }, - "json-schema-traverse": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", - "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==", - "dev": true } } }, "@fastify/formbody": { - "version": "7.0.1", - "resolved": "https://registry.npmjs.org/@fastify/formbody/-/formbody-7.0.1.tgz", - "integrity": "sha512-CY6IfzdtidHbZezyyXv7u9dzmb2Lv92HyOZDqANuFb++5ojsqoqIb8bJz11bSgPK0MDoqww/dH6DxZDMM8N4ng==", + "version": "7.4.0", + "resolved": "https://registry.npmjs.org/@fastify/formbody/-/formbody-7.4.0.tgz", + "integrity": "sha512-H3C6h1GN56/SMrZS8N2vCT2cZr7mIHzBHzOBa5OPpjfB/D6FzP9mMpE02ZzrFX0ANeh0BAJdoXKOF2e7IbV+Og==", "dev": true, "requires": { - "fastify-plugin": "^3.0.0" + "fast-querystring": "^1.0.0", + "fastify-plugin": "^4.0.0" } }, "@graphql-tools/merge": { @@ -18280,149 +17063,238 @@ } }, "@hapi/accept": { - "version": "5.0.2", - "resolved": "https://registry.npmjs.org/@hapi/accept/-/accept-5.0.2.tgz", - "integrity": "sha512-CmzBx/bXUR8451fnZRuZAJRlzgm0Jgu5dltTX/bszmR2lheb9BpyN47Q1RbaGTsvFzn0PXAEs+lXDKfshccYZw==", + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/@hapi/accept/-/accept-6.0.0.tgz", + "integrity": "sha512-aG/Ml4kSBWCVmWvR8N8ULRuB385D8K/3OI7lquZQruH11eM7sHR5Nha30BbDzijJHtyV7Vwc6MlMwNfwb70ISg==", "dev": true, "requires": { - "@hapi/boom": "9.x.x", - "@hapi/hoek": "9.x.x" + "@hapi/boom": "^10.0.0", + "@hapi/hoek": "^10.0.0" + }, + "dependencies": { + "@hapi/hoek": { + "version": "10.0.1", + "resolved": "https://registry.npmjs.org/@hapi/hoek/-/hoek-10.0.1.tgz", + "integrity": "sha512-CvlW7jmOhWzuqOqiJQ3rQVLMcREh0eel4IBnxDx2FAcK8g7qoJRQK4L1CPBASoCY6y8e6zuCy3f2g+HWdkzcMw==", + "dev": true + } } }, "@hapi/ammo": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/@hapi/ammo/-/ammo-5.0.1.tgz", - "integrity": "sha512-FbCNwcTbnQP4VYYhLNGZmA76xb2aHg9AMPiy18NZyWMG310P5KdFGyA9v2rm5ujrIny77dEEIkMOwl0Xv+fSSA==", + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/@hapi/ammo/-/ammo-6.0.0.tgz", + "integrity": "sha512-lhX7SYtWScQaeAIL5XnE54WzyDgS5RXVeEtFEovyZcTdVzTYbo0nem56Bwko1PBcRxRUIw1v2tMb6sjFs6vEwg==", "dev": true, "requires": { - "@hapi/hoek": "9.x.x" + "@hapi/hoek": "^10.0.0" + }, + "dependencies": { + "@hapi/hoek": { + "version": "10.0.1", + "resolved": "https://registry.npmjs.org/@hapi/hoek/-/hoek-10.0.1.tgz", + "integrity": "sha512-CvlW7jmOhWzuqOqiJQ3rQVLMcREh0eel4IBnxDx2FAcK8g7qoJRQK4L1CPBASoCY6y8e6zuCy3f2g+HWdkzcMw==", + "dev": true + } } }, "@hapi/b64": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/@hapi/b64/-/b64-5.0.0.tgz", - "integrity": "sha512-ngu0tSEmrezoiIaNGG6rRvKOUkUuDdf4XTPnONHGYfSGRmDqPZX5oJL6HAdKTo1UQHECbdB4OzhWrfgVppjHUw==", + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/@hapi/b64/-/b64-6.0.0.tgz", + "integrity": "sha512-Es6o4BtzvMmNF28KJGuwUzUtMjF6ToZ1hQt3UOjaXc6TNkRefel+NyQSjc9b5q3Re7xwv23r0xK3Vo3yreaJHQ==", "dev": true, "requires": { - "@hapi/hoek": "9.x.x" + "@hapi/hoek": "^10.0.0" + }, + "dependencies": { + "@hapi/hoek": { + "version": "10.0.1", + "resolved": "https://registry.npmjs.org/@hapi/hoek/-/hoek-10.0.1.tgz", + "integrity": "sha512-CvlW7jmOhWzuqOqiJQ3rQVLMcREh0eel4IBnxDx2FAcK8g7qoJRQK4L1CPBASoCY6y8e6zuCy3f2g+HWdkzcMw==", + "dev": true + } } }, "@hapi/boom": { - "version": "9.1.4", - "resolved": "https://registry.npmjs.org/@hapi/boom/-/boom-9.1.4.tgz", - "integrity": "sha512-Ls1oH8jaN1vNsqcaHVYJrKmgMcKsC1wcp8bujvXrHaAqD2iDYq3HoOwsxwo09Cuda5R5nC0o0IxlrlTuvPuzSw==", + "version": "10.0.0", + "resolved": "https://registry.npmjs.org/@hapi/boom/-/boom-10.0.0.tgz", + "integrity": "sha512-1YVs9tLHhypBqqinKQRqh7FUERIolarQApO37OWkzD+z6y6USi871Sv746zBPKcIOBuI6g6y4FrwX87mmJ90Gg==", "dev": true, "requires": { - "@hapi/hoek": "9.x.x" + "@hapi/hoek": "10.x.x" + }, + "dependencies": { + "@hapi/hoek": { + "version": "10.0.1", + "resolved": "https://registry.npmjs.org/@hapi/hoek/-/hoek-10.0.1.tgz", + "integrity": "sha512-CvlW7jmOhWzuqOqiJQ3rQVLMcREh0eel4IBnxDx2FAcK8g7qoJRQK4L1CPBASoCY6y8e6zuCy3f2g+HWdkzcMw==", + "dev": true + } } }, "@hapi/bounce": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/@hapi/bounce/-/bounce-2.0.0.tgz", - "integrity": "sha512-JesW92uyzOOyuzJKjoLHM1ThiOvHPOLDHw01YV8yh5nCso7sDwJho1h0Ad2N+E62bZyz46TG3xhAi/78Gsct6A==", + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@hapi/bounce/-/bounce-3.0.0.tgz", + "integrity": "sha512-L0G4NcwwOYRhpcXeL76hNrLTUcObqtZMB3z4kcRVUZcR/w3v6C5Q1cTElV4/V7og1fG+wOyDR55UMFA+tWfhtA==", "dev": true, "requires": { - "@hapi/boom": "9.x.x", - "@hapi/hoek": "9.x.x" + "@hapi/boom": "^10.0.0", + "@hapi/hoek": "^10.0.0" + }, + "dependencies": { + "@hapi/hoek": { + "version": "10.0.1", + "resolved": "https://registry.npmjs.org/@hapi/hoek/-/hoek-10.0.1.tgz", + "integrity": "sha512-CvlW7jmOhWzuqOqiJQ3rQVLMcREh0eel4IBnxDx2FAcK8g7qoJRQK4L1CPBASoCY6y8e6zuCy3f2g+HWdkzcMw==", + "dev": true + } } }, "@hapi/bourne": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/@hapi/bourne/-/bourne-2.1.0.tgz", - "integrity": "sha512-i1BpaNDVLJdRBEKeJWkVO6tYX6DMFBuwMhSuWqLsY4ufeTKGVuV5rBsUhxPayXqnnWHgXUAmWK16H/ykO5Wj4Q==", + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@hapi/bourne/-/bourne-3.0.0.tgz", + "integrity": "sha512-Waj1cwPXJDucOib4a3bAISsKJVb15MKi9IvmTI/7ssVEm6sywXGjVJDhl6/umt1pK1ZS7PacXU3A1PmFKHEZ2w==", "dev": true }, "@hapi/call": { - "version": "8.0.1", - "resolved": "https://registry.npmjs.org/@hapi/call/-/call-8.0.1.tgz", - "integrity": "sha512-bOff6GTdOnoe5b8oXRV3lwkQSb/LAWylvDMae6RgEWWntd0SHtkYbQukDHKlfaYtVnSAgIavJ0kqszF/AIBb6g==", + "version": "9.0.0", + "resolved": "https://registry.npmjs.org/@hapi/call/-/call-9.0.0.tgz", + "integrity": "sha512-Z6byqbEtKF3RIH2kWG6cX64RwEqHBWYEVkNoEx6oKvkPaTrC6WTPRgr+ANo9Xa8G1GXyvs/NCMTnn3Mdj12TSA==", "dev": true, "requires": { - "@hapi/boom": "9.x.x", - "@hapi/hoek": "9.x.x" + "@hapi/boom": "^10.0.0", + "@hapi/hoek": "^10.0.0" + }, + "dependencies": { + "@hapi/hoek": { + "version": "10.0.1", + "resolved": "https://registry.npmjs.org/@hapi/hoek/-/hoek-10.0.1.tgz", + "integrity": "sha512-CvlW7jmOhWzuqOqiJQ3rQVLMcREh0eel4IBnxDx2FAcK8g7qoJRQK4L1CPBASoCY6y8e6zuCy3f2g+HWdkzcMw==", + "dev": true + } } }, "@hapi/catbox": { - "version": "11.1.1", - "resolved": "https://registry.npmjs.org/@hapi/catbox/-/catbox-11.1.1.tgz", - "integrity": "sha512-u/8HvB7dD/6X8hsZIpskSDo4yMKpHxFd7NluoylhGrL6cUfYxdQPnvUp9YU2C6F9hsyBVLGulBd9vBN1ebfXOQ==", + "version": "12.0.1", + "resolved": "https://registry.npmjs.org/@hapi/catbox/-/catbox-12.0.1.tgz", + "integrity": "sha512-EJnj0KJt9LZ/c+mo6NB7mesFhy+s+CDX3AT7de5VRCOHkzOm4ENxN/rgNd0HyI/AfT8FqyUKt1Gccd1DVg8tQA==", "dev": true, "requires": { - "@hapi/boom": "9.x.x", - "@hapi/hoek": "9.x.x", - "@hapi/podium": "4.x.x", - "@hapi/validate": "1.x.x" + "@hapi/boom": "^10.0.0", + "@hapi/hoek": "^10.0.0", + "@hapi/podium": "^5.0.0", + "@hapi/validate": "^2.0.0" + }, + "dependencies": { + "@hapi/hoek": { + "version": "10.0.1", + "resolved": "https://registry.npmjs.org/@hapi/hoek/-/hoek-10.0.1.tgz", + "integrity": "sha512-CvlW7jmOhWzuqOqiJQ3rQVLMcREh0eel4IBnxDx2FAcK8g7qoJRQK4L1CPBASoCY6y8e6zuCy3f2g+HWdkzcMw==", + "dev": true + } } }, "@hapi/catbox-memory": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/@hapi/catbox-memory/-/catbox-memory-5.0.1.tgz", - "integrity": "sha512-QWw9nOYJq5PlvChLWV8i6hQHJYfvdqiXdvTupJFh0eqLZ64Xir7mKNi96d5/ZMUAqXPursfNDIDxjFgoEDUqeQ==", + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/@hapi/catbox-memory/-/catbox-memory-6.0.0.tgz", + "integrity": "sha512-A1O30g8GdaODx/GinytF6jFm772pdTPVWJe0cF2RiTOfhgIAAagzCcpBqRgQ8olLui0F5bzUF/SAi4BmkZ4yxA==", "dev": true, "requires": { - "@hapi/boom": "9.x.x", - "@hapi/hoek": "9.x.x" + "@hapi/boom": "^10.0.0", + "@hapi/hoek": "^10.0.0" + }, + "dependencies": { + "@hapi/hoek": { + "version": "10.0.1", + "resolved": "https://registry.npmjs.org/@hapi/hoek/-/hoek-10.0.1.tgz", + "integrity": "sha512-CvlW7jmOhWzuqOqiJQ3rQVLMcREh0eel4IBnxDx2FAcK8g7qoJRQK4L1CPBASoCY6y8e6zuCy3f2g+HWdkzcMw==", + "dev": true + } } }, "@hapi/content": { - "version": "5.0.2", - "resolved": "https://registry.npmjs.org/@hapi/content/-/content-5.0.2.tgz", - "integrity": "sha512-mre4dl1ygd4ZyOH3tiYBrOUBzV7Pu/EOs8VLGf58vtOEECWed8Uuw6B4iR9AN/8uQt42tB04qpVaMyoMQh0oMw==", + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/@hapi/content/-/content-6.0.0.tgz", + "integrity": "sha512-CEhs7j+H0iQffKfe5Htdak5LBOz/Qc8TRh51cF+BFv0qnuph3Em4pjGVzJMkI2gfTDdlJKWJISGWS1rK34POGA==", "dev": true, "requires": { - "@hapi/boom": "9.x.x" + "@hapi/boom": "^10.0.0" } }, "@hapi/cryptiles": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/@hapi/cryptiles/-/cryptiles-5.1.0.tgz", - "integrity": "sha512-fo9+d1Ba5/FIoMySfMqPBR/7Pa29J2RsiPrl7bkwo5W5o+AN1dAYQRi4SPrPwwVxVGKjgLOEWrsvt1BonJSfLA==", + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/@hapi/cryptiles/-/cryptiles-6.0.0.tgz", + "integrity": "sha512-CUypQJI2F3HaKZjwlky3KyLu7p0O4WJXNJj+2AZ0czqwkwQIz8j+btOkzA3OMar8WTntnCrDx0f92PzxEK+JlA==", "dev": true, "requires": { - "@hapi/boom": "9.x.x" + "@hapi/boom": "^10.0.0" } }, "@hapi/file": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/@hapi/file/-/file-2.0.0.tgz", - "integrity": "sha512-WSrlgpvEqgPWkI18kkGELEZfXr0bYLtr16iIN4Krh9sRnzBZN6nnWxHFxtsnP684wueEySBbXPDg/WfA9xJdBQ==", + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@hapi/file/-/file-3.0.0.tgz", + "integrity": "sha512-w+lKW+yRrLhJu620jT3y+5g2mHqnKfepreykvdOcl9/6up8GrQQn+l3FRTsjHTKbkbfQFkuksHpdv2EcpKcJ4Q==", "dev": true }, "@hapi/hapi": { - "version": "20.2.2", - "resolved": "https://registry.npmjs.org/@hapi/hapi/-/hapi-20.2.2.tgz", - "integrity": "sha512-crhU6TIKt7QsksWLYctDBAXogk9PYAm7UzdpETyuBHC2pCa6/+B5NykiOVLG/3FCIgHo/raPVtan8bYtByHORQ==", - "dev": true, - "requires": { - "@hapi/accept": "^5.0.1", - "@hapi/ammo": "^5.0.1", - "@hapi/boom": "^9.1.0", - "@hapi/bounce": "^2.0.0", - "@hapi/call": "^8.0.0", - "@hapi/catbox": "^11.1.1", - "@hapi/catbox-memory": "^5.0.0", - "@hapi/heavy": "^7.0.1", - "@hapi/hoek": "^9.0.4", - "@hapi/mimos": "^6.0.0", - "@hapi/podium": "^4.1.1", - "@hapi/shot": "^5.0.5", - "@hapi/somever": "^3.0.0", - "@hapi/statehood": "^7.0.4", - "@hapi/subtext": "^7.0.3", - "@hapi/teamwork": "^5.1.1", - "@hapi/topo": "^5.0.0", - "@hapi/validate": "^1.1.1" + "version": "21.1.0", + "resolved": "https://registry.npmjs.org/@hapi/hapi/-/hapi-21.1.0.tgz", + "integrity": "sha512-het7j9yLXZMVU1IvtN2JXkPkn/UcU1j8gsZxMS0Mu1q7791IQeyhT37tpRPUhqerOtL6L0E8Z8CvVVFOYxoN6w==", + "dev": true, + "requires": { + "@hapi/accept": "^6.0.0", + "@hapi/ammo": "^6.0.0", + "@hapi/boom": "^10.0.0", + "@hapi/bounce": "^3.0.0", + "@hapi/call": "^9.0.0", + "@hapi/catbox": "^12.0.0", + "@hapi/catbox-memory": "^6.0.0", + "@hapi/heavy": "^8.0.0", + "@hapi/hoek": "^10.0.0", + "@hapi/mimos": "^7.0.0", + "@hapi/podium": "^5.0.0", + "@hapi/shot": "^6.0.0", + "@hapi/somever": "^4.1.0", + "@hapi/statehood": "^8.0.0", + "@hapi/subtext": "^8.0.0", + "@hapi/teamwork": "^6.0.0", + "@hapi/topo": "^6.0.0", + "@hapi/validate": "^2.0.0" + }, + "dependencies": { + "@hapi/hoek": { + "version": "10.0.1", + "resolved": "https://registry.npmjs.org/@hapi/hoek/-/hoek-10.0.1.tgz", + "integrity": "sha512-CvlW7jmOhWzuqOqiJQ3rQVLMcREh0eel4IBnxDx2FAcK8g7qoJRQK4L1CPBASoCY6y8e6zuCy3f2g+HWdkzcMw==", + "dev": true + }, + "@hapi/topo": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/@hapi/topo/-/topo-6.0.0.tgz", + "integrity": "sha512-aorJvN1Q1n5xrZuA50Z4X6adI6VAM2NalIVm46ALL9LUvdoqhof3JPY69jdJH8asM3PsWr2SUVYzp57EqUP41A==", + "dev": true, + "requires": { + "@hapi/hoek": "^10.0.0" + } + } } }, "@hapi/heavy": { - "version": "7.0.1", - "resolved": "https://registry.npmjs.org/@hapi/heavy/-/heavy-7.0.1.tgz", - "integrity": "sha512-vJ/vzRQ13MtRzz6Qd4zRHWS3FaUc/5uivV2TIuExGTM9Qk+7Zzqj0e2G7EpE6KztO9SalTbiIkTh7qFKj/33cA==", + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/@hapi/heavy/-/heavy-8.0.0.tgz", + "integrity": "sha512-NpKo74mF66GSwYu31IZwp11/6NmaUYxHeMTKSky09XBs8fVbzQDP83856+l+Ji6wxGmUeg75itCu1ujvEF6mdA==", "dev": true, "requires": { - "@hapi/boom": "9.x.x", - "@hapi/hoek": "9.x.x", - "@hapi/validate": "1.x.x" + "@hapi/boom": "^10.0.0", + "@hapi/hoek": "^10.0.0", + "@hapi/validate": "^2.0.0" + }, + "dependencies": { + "@hapi/hoek": { + "version": "10.0.1", + "resolved": "https://registry.npmjs.org/@hapi/hoek/-/hoek-10.0.1.tgz", + "integrity": "sha512-CvlW7jmOhWzuqOqiJQ3rQVLMcREh0eel4IBnxDx2FAcK8g7qoJRQK4L1CPBASoCY6y8e6zuCy3f2g+HWdkzcMw==", + "dev": true + } } }, "@hapi/hoek": { @@ -18432,116 +17304,180 @@ "dev": true }, "@hapi/iron": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/@hapi/iron/-/iron-6.0.0.tgz", - "integrity": "sha512-zvGvWDufiTGpTJPG1Y/McN8UqWBu0k/xs/7l++HVU535NLHXsHhy54cfEMdW7EjwKfbBfM9Xy25FmTiobb7Hvw==", + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/@hapi/iron/-/iron-7.0.0.tgz", + "integrity": "sha512-NNXJP5fpeiTCPj/4OJG2PWBjWC0/V5D8YggS9RZeuBbfUUuTYE6TbdGqLUsCzIpPI54I8W5dhwEGbRv1CnWQtw==", "dev": true, "requires": { - "@hapi/b64": "5.x.x", - "@hapi/boom": "9.x.x", - "@hapi/bourne": "2.x.x", - "@hapi/cryptiles": "5.x.x", - "@hapi/hoek": "9.x.x" + "@hapi/b64": "^6.0.0", + "@hapi/boom": "^10.0.0", + "@hapi/bourne": "^3.0.0", + "@hapi/cryptiles": "^6.0.0", + "@hapi/hoek": "^10.0.0" + }, + "dependencies": { + "@hapi/hoek": { + "version": "10.0.1", + "resolved": "https://registry.npmjs.org/@hapi/hoek/-/hoek-10.0.1.tgz", + "integrity": "sha512-CvlW7jmOhWzuqOqiJQ3rQVLMcREh0eel4IBnxDx2FAcK8g7qoJRQK4L1CPBASoCY6y8e6zuCy3f2g+HWdkzcMw==", + "dev": true + } } }, "@hapi/mimos": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/@hapi/mimos/-/mimos-6.0.0.tgz", - "integrity": "sha512-Op/67tr1I+JafN3R3XN5DucVSxKRT/Tc+tUszDwENoNpolxeXkhrJ2Czt6B6AAqrespHoivhgZBWYSuANN9QXg==", + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/@hapi/mimos/-/mimos-7.0.0.tgz", + "integrity": "sha512-ALORTrZrrBPOUX05rW4htNajoekEjQtUi1PB+17/3xs/hkdQ+gSEFbs5GdJihA49qWf7td3v4PgnvOe8mcf/jQ==", "dev": true, "requires": { - "@hapi/hoek": "9.x.x", - "mime-db": "1.x.x" + "@hapi/hoek": "^10.0.0", + "mime-db": "^1.52.0" + }, + "dependencies": { + "@hapi/hoek": { + "version": "10.0.1", + "resolved": "https://registry.npmjs.org/@hapi/hoek/-/hoek-10.0.1.tgz", + "integrity": "sha512-CvlW7jmOhWzuqOqiJQ3rQVLMcREh0eel4IBnxDx2FAcK8g7qoJRQK4L1CPBASoCY6y8e6zuCy3f2g+HWdkzcMw==", + "dev": true + } } }, "@hapi/nigel": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/@hapi/nigel/-/nigel-4.0.2.tgz", - "integrity": "sha512-ht2KoEsDW22BxQOEkLEJaqfpoKPXxi7tvabXy7B/77eFtOyG5ZEstfZwxHQcqAiZhp58Ae5vkhEqI03kawkYNw==", + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/@hapi/nigel/-/nigel-5.0.0.tgz", + "integrity": "sha512-I9eq43BnSdz1BkvMpG7mFL7J+SIfn6DLNThuxFpIOAMUnkWbPgtcFP+HHrBAeoFkowfgQrr02vsIAkAPml4hvw==", "dev": true, "requires": { - "@hapi/hoek": "^9.0.4", - "@hapi/vise": "^4.0.0" + "@hapi/hoek": "^10.0.0", + "@hapi/vise": "^5.0.0" + }, + "dependencies": { + "@hapi/hoek": { + "version": "10.0.1", + "resolved": "https://registry.npmjs.org/@hapi/hoek/-/hoek-10.0.1.tgz", + "integrity": "sha512-CvlW7jmOhWzuqOqiJQ3rQVLMcREh0eel4IBnxDx2FAcK8g7qoJRQK4L1CPBASoCY6y8e6zuCy3f2g+HWdkzcMw==", + "dev": true + } } }, "@hapi/pez": { - "version": "5.0.3", - "resolved": "https://registry.npmjs.org/@hapi/pez/-/pez-5.0.3.tgz", - "integrity": "sha512-mpikYRJjtrbJgdDHG/H9ySqYqwJ+QU/D7FXsYciS9P7NYBXE2ayKDAy3H0ou6CohOCaxPuTV4SZ0D936+VomHA==", + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/@hapi/pez/-/pez-6.0.0.tgz", + "integrity": "sha512-3bMmsvlqrVNqaNEe4JWLZVpJ40jXuQ3vDy1+fbhyJmuAdMCMCkWexsKc7fT+mu18pFIwJzlenjc4/VE3weTq7w==", "dev": true, "requires": { - "@hapi/b64": "5.x.x", - "@hapi/boom": "9.x.x", - "@hapi/content": "^5.0.2", - "@hapi/hoek": "9.x.x", - "@hapi/nigel": "4.x.x" + "@hapi/b64": "^6.0.0", + "@hapi/boom": "^10.0.0", + "@hapi/content": "^6.0.0", + "@hapi/hoek": "^10.0.0", + "@hapi/nigel": "^5.0.0" + }, + "dependencies": { + "@hapi/hoek": { + "version": "10.0.1", + "resolved": "https://registry.npmjs.org/@hapi/hoek/-/hoek-10.0.1.tgz", + "integrity": "sha512-CvlW7jmOhWzuqOqiJQ3rQVLMcREh0eel4IBnxDx2FAcK8g7qoJRQK4L1CPBASoCY6y8e6zuCy3f2g+HWdkzcMw==", + "dev": true + } } }, "@hapi/podium": { - "version": "4.1.3", - "resolved": "https://registry.npmjs.org/@hapi/podium/-/podium-4.1.3.tgz", - "integrity": "sha512-ljsKGQzLkFqnQxE7qeanvgGj4dejnciErYd30dbrYzUOF/FyS/DOF97qcrT3bhoVwCYmxa6PEMhxfCPlnUcD2g==", + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/@hapi/podium/-/podium-5.0.0.tgz", + "integrity": "sha512-SbhFdu8LOIscMS82Zsoj9abcllAqbK4qBgznzJ9yr+vS2j1EomJTukkhxb76Lml0BHCd4Hn79F+3EQg06kcf8g==", "dev": true, "requires": { - "@hapi/hoek": "9.x.x", - "@hapi/teamwork": "5.x.x", - "@hapi/validate": "1.x.x" + "@hapi/hoek": "^10.0.0", + "@hapi/teamwork": "^6.0.0", + "@hapi/validate": "^2.0.0" + }, + "dependencies": { + "@hapi/hoek": { + "version": "10.0.1", + "resolved": "https://registry.npmjs.org/@hapi/hoek/-/hoek-10.0.1.tgz", + "integrity": "sha512-CvlW7jmOhWzuqOqiJQ3rQVLMcREh0eel4IBnxDx2FAcK8g7qoJRQK4L1CPBASoCY6y8e6zuCy3f2g+HWdkzcMw==", + "dev": true + } } }, "@hapi/shot": { - "version": "5.0.5", - "resolved": "https://registry.npmjs.org/@hapi/shot/-/shot-5.0.5.tgz", - "integrity": "sha512-x5AMSZ5+j+Paa8KdfCoKh+klB78otxF+vcJR/IoN91Vo2e5ulXIW6HUsFTCU+4W6P/Etaip9nmdAx2zWDimB2A==", + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/@hapi/shot/-/shot-6.0.0.tgz", + "integrity": "sha512-RLGgzXy9GciJDunhY40NbVnLgYqp5gfBooZ2fOkAr4KbCEav/SJtYQS1N+knR7WFGzy8aooCR3XBUPI4ghHAkQ==", "dev": true, "requires": { - "@hapi/hoek": "9.x.x", - "@hapi/validate": "1.x.x" + "@hapi/hoek": "^10.0.0", + "@hapi/validate": "^2.0.0" + }, + "dependencies": { + "@hapi/hoek": { + "version": "10.0.1", + "resolved": "https://registry.npmjs.org/@hapi/hoek/-/hoek-10.0.1.tgz", + "integrity": "sha512-CvlW7jmOhWzuqOqiJQ3rQVLMcREh0eel4IBnxDx2FAcK8g7qoJRQK4L1CPBASoCY6y8e6zuCy3f2g+HWdkzcMw==", + "dev": true + } } }, "@hapi/somever": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/@hapi/somever/-/somever-3.0.1.tgz", - "integrity": "sha512-4ZTSN3YAHtgpY/M4GOtHUXgi6uZtG9nEZfNI6QrArhK0XN/RDVgijlb9kOmXwCR5VclDSkBul9FBvhSuKXx9+w==", + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/@hapi/somever/-/somever-4.1.0.tgz", + "integrity": "sha512-koNBYu7Jdcb7gaC4VcnU78rFxSlsYwuElm6NMznE0EEeznzJtvLLmDZX0SPX8kXWC/E7ONlE29HF/yiSOgWG1Q==", "dev": true, "requires": { - "@hapi/bounce": "2.x.x", - "@hapi/hoek": "9.x.x" + "@hapi/bounce": "^3.0.0", + "@hapi/hoek": "^9.0.0" } }, "@hapi/statehood": { - "version": "7.0.4", - "resolved": "https://registry.npmjs.org/@hapi/statehood/-/statehood-7.0.4.tgz", - "integrity": "sha512-Fia6atroOVmc5+2bNOxF6Zv9vpbNAjEXNcUbWXavDqhnJDlchwUUwKS5LCi5mGtCTxRhUKKHwuxuBZJkmLZ7fw==", + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/@hapi/statehood/-/statehood-8.0.0.tgz", + "integrity": "sha512-umQTPID7BwmqAv9Rx7yLtbTNzsYg4va96aLqKneb3mlBQG32uq4iOQZ6luwBVACDFhqU3C3ewhznhukN09ZkZQ==", "dev": true, "requires": { - "@hapi/boom": "9.x.x", - "@hapi/bounce": "2.x.x", - "@hapi/bourne": "2.x.x", - "@hapi/cryptiles": "5.x.x", - "@hapi/hoek": "9.x.x", - "@hapi/iron": "6.x.x", - "@hapi/validate": "1.x.x" + "@hapi/boom": "^10.0.0", + "@hapi/bounce": "^3.0.0", + "@hapi/bourne": "^3.0.0", + "@hapi/cryptiles": "^6.0.0", + "@hapi/hoek": "^10.0.0", + "@hapi/iron": "^7.0.0", + "@hapi/validate": "^2.0.0" + }, + "dependencies": { + "@hapi/hoek": { + "version": "10.0.1", + "resolved": "https://registry.npmjs.org/@hapi/hoek/-/hoek-10.0.1.tgz", + "integrity": "sha512-CvlW7jmOhWzuqOqiJQ3rQVLMcREh0eel4IBnxDx2FAcK8g7qoJRQK4L1CPBASoCY6y8e6zuCy3f2g+HWdkzcMw==", + "dev": true + } } }, "@hapi/subtext": { - "version": "7.0.3", - "resolved": "https://registry.npmjs.org/@hapi/subtext/-/subtext-7.0.3.tgz", - "integrity": "sha512-CekDizZkDGERJ01C0+TzHlKtqdXZxzSWTOaH6THBrbOHnsr3GY+yiMZC+AfNCypfE17RaIakGIAbpL2Tk1z2+A==", + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/@hapi/subtext/-/subtext-8.0.0.tgz", + "integrity": "sha512-fD+LY1U1SIUNHZJrNMIbuGl3CAd9JN8slljarFO4b8RrifkzjqbvdlZu/6iT6zlNM35GtDExf7hIepbUFUkT7A==", "dev": true, "requires": { - "@hapi/boom": "9.x.x", - "@hapi/bourne": "2.x.x", - "@hapi/content": "^5.0.2", - "@hapi/file": "2.x.x", - "@hapi/hoek": "9.x.x", - "@hapi/pez": "^5.0.1", - "@hapi/wreck": "17.x.x" + "@hapi/boom": "^10.0.0", + "@hapi/bourne": "^3.0.0", + "@hapi/content": "^6.0.0", + "@hapi/file": "^3.0.0", + "@hapi/hoek": "^10.0.0", + "@hapi/pez": "^6.0.0", + "@hapi/wreck": "^18.0.0" + }, + "dependencies": { + "@hapi/hoek": { + "version": "10.0.1", + "resolved": "https://registry.npmjs.org/@hapi/hoek/-/hoek-10.0.1.tgz", + "integrity": "sha512-CvlW7jmOhWzuqOqiJQ3rQVLMcREh0eel4IBnxDx2FAcK8g7qoJRQK4L1CPBASoCY6y8e6zuCy3f2g+HWdkzcMw==", + "dev": true + } } }, "@hapi/teamwork": { - "version": "5.1.1", - "resolved": "https://registry.npmjs.org/@hapi/teamwork/-/teamwork-5.1.1.tgz", - "integrity": "sha512-1oPx9AE5TIv+V6Ih54RP9lTZBso3rP8j4Xhb6iSVwPXtAM+sDopl5TFMv5Paw73UnpZJ9gjcrTE1BXrWt9eQrg==", + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/@hapi/teamwork/-/teamwork-6.0.0.tgz", + "integrity": "sha512-05HumSy3LWfXpmJ9cr6HzwhAavrHkJ1ZRCmNE2qJMihdM5YcWreWPfyN0yKT2ZjCM92au3ZkuodjBxOibxM67A==", "dev": true }, "@hapi/topo": { @@ -18554,33 +17490,66 @@ } }, "@hapi/validate": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/@hapi/validate/-/validate-1.1.3.tgz", - "integrity": "sha512-/XMR0N0wjw0Twzq2pQOzPBZlDzkekGcoCtzO314BpIEsbXdYGthQUbxgkGDf4nhk1+IPDAsXqWjMohRQYO06UA==", + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/@hapi/validate/-/validate-2.0.0.tgz", + "integrity": "sha512-w5m8MvBgqGndbMIB+AWmXTb8CLtF1DlIxbnbAHNAo7aFuNQuI1Ywc2e0zDLK5fbFXDoqRzNrHnC7JjNJ+hDigw==", "dev": true, "requires": { - "@hapi/hoek": "^9.0.0", - "@hapi/topo": "^5.0.0" + "@hapi/hoek": "^10.0.0", + "@hapi/topo": "^6.0.0" + }, + "dependencies": { + "@hapi/hoek": { + "version": "10.0.1", + "resolved": "https://registry.npmjs.org/@hapi/hoek/-/hoek-10.0.1.tgz", + "integrity": "sha512-CvlW7jmOhWzuqOqiJQ3rQVLMcREh0eel4IBnxDx2FAcK8g7qoJRQK4L1CPBASoCY6y8e6zuCy3f2g+HWdkzcMw==", + "dev": true + }, + "@hapi/topo": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/@hapi/topo/-/topo-6.0.0.tgz", + "integrity": "sha512-aorJvN1Q1n5xrZuA50Z4X6adI6VAM2NalIVm46ALL9LUvdoqhof3JPY69jdJH8asM3PsWr2SUVYzp57EqUP41A==", + "dev": true, + "requires": { + "@hapi/hoek": "^10.0.0" + } + } } }, "@hapi/vise": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/@hapi/vise/-/vise-4.0.0.tgz", - "integrity": "sha512-eYyLkuUiFZTer59h+SGy7hUm+qE9p+UemePTHLlIWppEd+wExn3Df5jO04bFQTm7nleF5V8CtuYQYb+VFpZ6Sg==", + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/@hapi/vise/-/vise-5.0.0.tgz", + "integrity": "sha512-bz/PA7DHIvsd/2eoW7t9WpU8+k9pofZHppYEn1mCTOVnC/cGN3hCEYaoAe6BpoeJM72iJDKZEOWvQvfgCrmzxA==", "dev": true, "requires": { - "@hapi/hoek": "9.x.x" + "@hapi/hoek": "^10.0.0" + }, + "dependencies": { + "@hapi/hoek": { + "version": "10.0.1", + "resolved": "https://registry.npmjs.org/@hapi/hoek/-/hoek-10.0.1.tgz", + "integrity": "sha512-CvlW7jmOhWzuqOqiJQ3rQVLMcREh0eel4IBnxDx2FAcK8g7qoJRQK4L1CPBASoCY6y8e6zuCy3f2g+HWdkzcMw==", + "dev": true + } } }, "@hapi/wreck": { - "version": "17.2.0", - "resolved": "https://registry.npmjs.org/@hapi/wreck/-/wreck-17.2.0.tgz", - "integrity": "sha512-pJ5kjYoRPYDv+eIuiLQqhGon341fr2bNIYZjuotuPJG/3Ilzr/XtI+JAp0A86E2bYfsS3zBPABuS2ICkaXFT8g==", + "version": "18.0.0", + "resolved": "https://registry.npmjs.org/@hapi/wreck/-/wreck-18.0.0.tgz", + "integrity": "sha512-Yk9STxoM06Hjjq58cH0KFG91u9F2h9eVE72o8vUr3AfK80qt7I2POG5+cDGTEntbnvvzm0ERow2sjG3QsqCWUA==", "dev": true, "requires": { - "@hapi/boom": "9.x.x", - "@hapi/bourne": "2.x.x", - "@hapi/hoek": "9.x.x" + "@hapi/boom": "^10.0.0", + "@hapi/bourne": "^3.0.0", + "@hapi/hoek": "^10.0.0" + }, + "dependencies": { + "@hapi/hoek": { + "version": "10.0.1", + "resolved": "https://registry.npmjs.org/@hapi/hoek/-/hoek-10.0.1.tgz", + "integrity": "sha512-CvlW7jmOhWzuqOqiJQ3rQVLMcREh0eel4IBnxDx2FAcK8g7qoJRQK4L1CPBASoCY6y8e6zuCy3f2g+HWdkzcMw==", + "dev": true + } } }, "@ioredis/commands": { @@ -18608,6 +17577,16 @@ "integrity": "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==", "dev": true }, + "js-yaml": { + "version": "3.14.1", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.14.1.tgz", + "integrity": "sha512-okMH7OXXJ7YrN9Ok3/SXrnu4iX9yOk+25nqX4imS2npuvTYDmo/QEZoqwZkYaIDk3jVvBOTOIEgEhaLOynBS9g==", + "dev": true, + "requires": { + "argparse": "^1.0.7", + "esprima": "^4.0.0" + } + }, "resolve-from": { "version": "5.0.0", "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-5.0.0.tgz", @@ -18667,22 +17646,48 @@ } }, "@js-joda/core": { - "version": "4.3.1", - "resolved": "https://registry.npmjs.org/@js-joda/core/-/core-4.3.1.tgz", - "integrity": "sha512-oeaetlodcqVsiZDxnEcqsbs+sXBkASxua0mXs5OXuPQXz3/wdPTMlxwfQ4z2HKcOik3S9voW3QJkp/KLWDhvRQ==", + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/@js-joda/core/-/core-5.2.0.tgz", + "integrity": "sha512-0OriPYIaMLB3XiLQMe0BXKVIqeriTn3H7JMOzTsHEtt7Zqq+TetCu97KnAhU3ckiQZKBxfZshft+H1OC4D1lXw==", "dev": true }, "@koa/router": { - "version": "9.4.0", - "resolved": "https://registry.npmjs.org/@koa/router/-/router-9.4.0.tgz", - "integrity": "sha512-dOOXgzqaDoHu5qqMEPLKEgLz5CeIA7q8+1W62mCvFVCOqeC71UoTGJ4u1xUSOpIl2J1x2pqrNULkFteUeZW3/A==", + "version": "12.0.0", + "resolved": "https://registry.npmjs.org/@koa/router/-/router-12.0.0.tgz", + "integrity": "sha512-cnnxeKHXlt7XARJptflGURdJaO+ITpNkOHmQu7NHmCoRinPbyvFzce/EG/E8Zy81yQ1W9MoSdtklc3nyaDReUw==", "dev": true, "requires": { - "debug": "^4.1.1", - "http-errors": "^1.7.3", + "http-errors": "^2.0.0", "koa-compose": "^4.1.0", "methods": "^1.1.2", - "path-to-regexp": "^6.1.0" + "path-to-regexp": "^6.2.1" + }, + "dependencies": { + "depd": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz", + "integrity": "sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==", + "dev": true + }, + "http-errors": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-2.0.0.tgz", + "integrity": "sha512-FtwrG/euBzaEjYeRqOgly7G0qviiXoJWnvEH2Z1plBdXgbyjv34pHTSb9zoeHMyDy33+DWy5Wt9Wo+TURtOYSQ==", + "dev": true, + "requires": { + "depd": "2.0.0", + "inherits": "2.0.4", + "setprototypeof": "1.2.0", + "statuses": "2.0.1", + "toidentifier": "1.0.1" + } + }, + "statuses": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.1.tgz", + "integrity": "sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ==", + "dev": true + } } }, "@netflix/nerror": { @@ -18904,7 +17909,7 @@ "@protobufjs/aspromise": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/@protobufjs/aspromise/-/aspromise-1.1.2.tgz", - "integrity": "sha1-m4sMxmPWaafY9vXQiToU00jzD78=", + "integrity": "sha512-j+gKExEuLmKwvz3OgROXtrJ2UG2x8Ch2YZUxahh+s1F2HZ+wAceUNLkvy6zKCPVRkU++ZWQrdxsUeQXmcg4uoQ==", "dev": true }, "@protobufjs/base64": { @@ -18922,13 +17927,13 @@ "@protobufjs/eventemitter": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/@protobufjs/eventemitter/-/eventemitter-1.1.0.tgz", - "integrity": "sha1-NVy8mLr61ZePntCV85diHx0Ga3A=", + "integrity": "sha512-j9ednRT81vYJ9OfVuXG6ERSTdEL1xVsNgqpkxMsbIabzSo3goCjDIveeGv5d03om39ML71RdmrGNjG5SReBP/Q==", "dev": true }, "@protobufjs/fetch": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/@protobufjs/fetch/-/fetch-1.1.0.tgz", - "integrity": "sha1-upn7WYYUr2VwDBYZ/wbUVLDYTEU=", + "integrity": "sha512-lljVXpqXebpsijW71PZaCYeIcE5on1w5DlQy5WH6GLbFryLUrBD4932W/E2BSpfRJWseIL4v/KPgBFxDOIdKpQ==", "dev": true, "requires": { "@protobufjs/aspromise": "^1.1.1", @@ -18938,31 +17943,86 @@ "@protobufjs/float": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/@protobufjs/float/-/float-1.0.2.tgz", - "integrity": "sha1-Xp4avctz/Ap8uLKR33jIy9l7h9E=", + "integrity": "sha512-Ddb+kVXlXst9d+R9PfTIxh1EdNkgoRe5tOX6t01f1lYWOvJnSPDBlG241QLzcyPdoNTsblLUdujGSE4RzrTZGQ==", "dev": true }, "@protobufjs/inquire": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/@protobufjs/inquire/-/inquire-1.1.0.tgz", - "integrity": "sha1-/yAOPnzyQp4tyvwRQIKOjMY48Ik=", + "integrity": "sha512-kdSefcPdruJiFMVSbn801t4vFK7KB/5gd2fYvrxhuJYg8ILrmn9SKSX2tZdV6V+ksulWqS7aXjBcRXl3wHoD9Q==", "dev": true }, "@protobufjs/path": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/@protobufjs/path/-/path-1.1.2.tgz", - "integrity": "sha1-bMKyDFya1q0NzP0hynZz2Nf79o0=", + "integrity": "sha512-6JOcJ5Tm08dOHAbdR3GrvP+yUUfkjG5ePsHYczMFLq3ZmMkAD98cDgcT2iA1lJ9NVwFd4tH/iSSoe44YWkltEA==", "dev": true }, "@protobufjs/pool": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/@protobufjs/pool/-/pool-1.1.0.tgz", - "integrity": "sha1-Cf0V8tbTq/qbZbw2ZQbWrXhG/1Q=", + "integrity": "sha512-0kELaGSIDBKvcgS4zkjz1PeddatrjYcmMWOlAuAPwAeccUrPHdUqo/J6LiymHHEiJT5NrF1UVwxY14f+fy4WQw==", "dev": true }, "@protobufjs/utf8": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/@protobufjs/utf8/-/utf8-1.1.0.tgz", - "integrity": "sha1-p3c2C1s5oaLlEG+OhY8v0tBgxXA=", + "integrity": "sha512-Vvn3zZrhQZkkBE8LSuW3em98c0FwgO4nxzv6OdSxPKJIEKY2bGbHn+mhGIPerzI4twdxaP8/0+06HBpwf345Lw==", + "dev": true + }, + "@redis/bloom": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/@redis/bloom/-/bloom-1.0.2.tgz", + "integrity": "sha512-EBw7Ag1hPgFzdznK2PBblc1kdlj5B5Cw3XwI9/oG7tSn85/HKy3X9xHy/8tm/eNXJYHLXHJL/pkwBpFMVVefkw==", + "dev": true + }, + "@redis/client": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/@redis/client/-/client-1.3.0.tgz", + "integrity": "sha512-XCFV60nloXAefDsPnYMjHGtvbtHR8fV5Om8cQ0JYqTNbWcQo/4AryzJ2luRj4blveWazRK/j40gES8M7Cp6cfQ==", + "dev": true, + "requires": { + "cluster-key-slot": "1.1.0", + "generic-pool": "3.8.2", + "yallist": "4.0.0" + }, + "dependencies": { + "generic-pool": { + "version": "3.8.2", + "resolved": "https://registry.npmjs.org/generic-pool/-/generic-pool-3.8.2.tgz", + "integrity": "sha512-nGToKy6p3PAbYQ7p1UlWl6vSPwfwU6TMSWK7TTu+WUY4ZjyZQGniGGt2oNVvyNSpyZYSB43zMXVLcBm08MTMkg==", + "dev": true + }, + "yallist": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", + "dev": true + } + } + }, + "@redis/graph": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@redis/graph/-/graph-1.0.1.tgz", + "integrity": "sha512-oDE4myMCJOCVKYMygEMWuriBgqlS5FqdWerikMoJxzmmTUErnTRRgmIDa2VcgytACZMFqpAOWDzops4DOlnkfQ==", + "dev": true + }, + "@redis/json": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/@redis/json/-/json-1.0.4.tgz", + "integrity": "sha512-LUZE2Gdrhg0Rx7AN+cZkb1e6HjoSKaeeW8rYnt89Tly13GBI5eP4CwDVr+MY8BAYfCg4/N15OUrtLoona9uSgw==", + "dev": true + }, + "@redis/search": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@redis/search/-/search-1.1.0.tgz", + "integrity": "sha512-NyFZEVnxIJEybpy+YskjgOJRNsfTYqaPbK/Buv6W2kmFNaRk85JiqjJZA5QkRmWvGbyQYwoO5QfDi2wHskKrQQ==", + "dev": true + }, + "@redis/time-series": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/@redis/time-series/-/time-series-1.0.3.tgz", + "integrity": "sha512-OFp0q4SGrTH0Mruf6oFsHGea58u8vS/iI5+NpYdicaM+7BgqBZH8FFvNZ8rYYLrUO/QRqMq72NpXmxLVNcdmjA==", "dev": true }, "@sideway/address": { @@ -18975,9 +18035,9 @@ } }, "@sideway/formula": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/@sideway/formula/-/formula-3.0.0.tgz", - "integrity": "sha512-vHe7wZ4NOXVfkoRb8T5otiENVlT7a3IAiw7H5M2+GO+9CDgcVUUsX1zalAztCmwyOr2RUTGJdgB+ZvSVqmdHmg==", + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/@sideway/formula/-/formula-3.0.1.tgz", + "integrity": "sha512-/poHZJJVjx3L+zVD6g9KgHfYnb443oi7wLu/XKojDviHy6HOEOA6z1Trk5aR1dGcmPenJEgb2sK2I80LeS3MIg==", "dev": true }, "@sideway/pinpoint": { @@ -19063,9 +18123,9 @@ } }, "@types/express": { - "version": "4.17.13", - "resolved": "https://registry.npmjs.org/@types/express/-/express-4.17.13.tgz", - "integrity": "sha512-6bSZTPaTIACxn48l50SR+axgrqm6qXFIxrdAKaG6PaJk3+zuUr35hBlgT7vOmJcum+OEaIBLtHV/qloEAFITeA==", + "version": "4.17.14", + "resolved": "https://registry.npmjs.org/@types/express/-/express-4.17.14.tgz", + "integrity": "sha512-TEbt+vaPFQ+xpxFLFssxUDXj5cWCxZJjIcB7Yg0k0GMHGtgtQgpvx/MUQUeAkNbA9AAGrwkAsoeItdTgS7FMyg==", "dev": true, "requires": { "@types/body-parser": "*", @@ -19075,9 +18135,9 @@ } }, "@types/express-serve-static-core": { - "version": "4.17.28", - "resolved": "https://registry.npmjs.org/@types/express-serve-static-core/-/express-serve-static-core-4.17.28.tgz", - "integrity": "sha512-P1BJAEAW3E2DJUlkgq4tOL3RyMunoWXqbSCygWo5ZIWTjUgN1YnaXWW4VWl/oc8vs/XoYibEGBKP0uZyF4AHig==", + "version": "4.17.31", + "resolved": "https://registry.npmjs.org/@types/express-serve-static-core/-/express-serve-static-core-4.17.31.tgz", + "integrity": "sha512-DxMhY+NAsTwMMFHBTtJFNp5qiHKJ7TeqOo23zVEM9alT1Ml27Q3xcTH0xwxn7Q0BbMcVEJOs/7aQtUWupUQN3Q==", "dev": true, "requires": { "@types/node": "*", @@ -19153,9 +18213,9 @@ "dev": true }, "@types/mime": { - "version": "1.3.2", - "resolved": "https://registry.npmjs.org/@types/mime/-/mime-1.3.2.tgz", - "integrity": "sha512-YATxVxgRqNH6nHEIsvg6k2Boc1JHI9ZbH5iWFFv/MTkchz3b1ieGDa5T0a9RznNdI0KhVbdbWSN+KWWrQZRxTw==", + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/@types/mime/-/mime-3.0.1.tgz", + "integrity": "sha512-Y4XFY5VJAuw0FgAqPNd6NNoV44jbq9Bz2L7Rh/J6jLTiHBSBJa9fxqQIvkIld4GsoDOcCbvzOUAbLPsSKKg+uA==", "dev": true }, "@types/minimatch": { @@ -19165,9 +18225,9 @@ "dev": true }, "@types/node": { - "version": "18.0.3", - "resolved": "https://registry.npmjs.org/@types/node/-/node-18.0.3.tgz", - "integrity": "sha512-HzNRZtp4eepNitP+BD6k2L6DROIDG4Q0fm4x+dwfsr6LGmROENnok75VGw40628xf+iR24WeMFcHuuBDUAzzsQ==", + "version": "18.11.9", + "resolved": "https://registry.npmjs.org/@types/node/-/node-18.11.9.tgz", + "integrity": "sha512-CRpX21/kGdzjOpFsZSkcrXMGIBWMGNIHXXBVFSH+ggkftxg+XYP20TESbh+zFvFj3EQOl5byk0HTRn1IL6hbqg==", "dev": true }, "@types/node-fetch": { @@ -19257,12 +18317,12 @@ } }, "@types/serve-static": { - "version": "1.13.10", - "resolved": "https://registry.npmjs.org/@types/serve-static/-/serve-static-1.13.10.tgz", - "integrity": "sha512-nCkHGI4w7ZgAdNkrEu0bv+4xNV/XDqW+DydknebMOQwkpDGx8G+HTlj7R7ABI8i8nKxVw0wtKPi1D+lPOkh4YQ==", + "version": "1.15.0", + "resolved": "https://registry.npmjs.org/@types/serve-static/-/serve-static-1.15.0.tgz", + "integrity": "sha512-z5xyF6uh8CbjAu9760KDKsH2FcDxZ2tFCsA4HIMWE6IkiYMXfVoa+4f9KX+FN0ZLsaMw1WNG2ETLA6N+/YA+cg==", "dev": true, "requires": { - "@types/mime": "^1", + "@types/mime": "*", "@types/node": "*" } }, @@ -19276,21 +18336,30 @@ } }, "@types/webidl-conversions": { - "version": "6.1.1", - "resolved": "https://registry.npmjs.org/@types/webidl-conversions/-/webidl-conversions-6.1.1.tgz", - "integrity": "sha512-XAahCdThVuCFDQLT7R7Pk/vqeObFNL3YqRyFZg+AqAP/W1/w3xHaIxuW7WszQqTbIBOPRcItYJIou3i/mppu3Q==", + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/@types/webidl-conversions/-/webidl-conversions-7.0.0.tgz", + "integrity": "sha512-xTE1E+YF4aWPJJeUzaZI5DRntlkY3+BCVJi0axFptnjGmAoWxkyREIh/XMrfxVLejwQxMCfDXdICo0VLxThrog==", "dev": true }, "@types/whatwg-url": { - "version": "8.2.1", - "resolved": "https://registry.npmjs.org/@types/whatwg-url/-/whatwg-url-8.2.1.tgz", - "integrity": "sha512-2YubE1sjj5ifxievI5Ge1sckb9k/Er66HyR2c+3+I6VDUUg1TLPdYYTEbQ+DjRkS4nTxMJhgWfSfMRD2sl2EYQ==", + "version": "8.2.2", + "resolved": "https://registry.npmjs.org/@types/whatwg-url/-/whatwg-url-8.2.2.tgz", + "integrity": "sha512-FtQu10RWgn3D9U4aazdwIE2yzphmTJREDqNdODHrbrZmmMqI0vMheC/6NE/J1Yveaj8H+ela+YwWTjq5PGmuhA==", "dev": true, "requires": { "@types/node": "*", "@types/webidl-conversions": "*" } }, + "abort-controller": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/abort-controller/-/abort-controller-3.0.0.tgz", + "integrity": "sha512-h8lQ8tacZYnR3vNQTgibj+tODHI5/+l06Au2Pcriv/Gmet0eaj4TwWH41sO9wnHDiQsEj19q0drzdWdeAHtweg==", + "dev": true, + "requires": { + "event-target-shim": "^5.0.0" + } + }, "abstract-logging": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/abstract-logging/-/abstract-logging-2.0.1.tgz", @@ -19376,14 +18445,15 @@ "indent-string": "^4.0.0" } }, - "ajv": { - "version": "6.12.6", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", - "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", + "ajv": { + "version": "7.2.4", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-7.2.4.tgz", + "integrity": "sha512-nBeQgg/ZZA3u3SYxyaDvpvDtgZ/EZPF547ARgZBrG9Bhu1vKDwAIjtIf+sDtJUKa2zOcEbmRLBRSyMraS/Oy1A==", + "dev": true, "requires": { "fast-deep-equal": "^3.1.1", - "fast-json-stable-stringify": "^2.0.0", - "json-schema-traverse": "^0.4.1", + "json-schema-traverse": "^1.0.0", + "require-from-string": "^2.0.2", "uri-js": "^4.2.2" } }, @@ -19407,12 +18477,6 @@ "require-from-string": "^2.0.2", "uri-js": "^4.2.2" } - }, - "json-schema-traverse": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", - "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==", - "dev": true } } }, @@ -19479,61 +18543,61 @@ } }, "apollo-datasource": { - "version": "3.3.1", - "resolved": "https://registry.npmjs.org/apollo-datasource/-/apollo-datasource-3.3.1.tgz", - "integrity": "sha512-Z3a8rEUXVPIZ1p8xrFL8bcNhWmhOmovgDArvwIwmJOBnh093ZpRfO+ESJEDAN4KswmyzCLDAwjsW4zQOONdRUw==", + "version": "3.3.2", + "resolved": "https://registry.npmjs.org/apollo-datasource/-/apollo-datasource-3.3.2.tgz", + "integrity": "sha512-L5TiS8E2Hn/Yz7SSnWIVbZw0ZfEIXZCa5VUiVxD9P53JvSrf4aStvsFDlGWPvpIdCR+aly2CfoB79B9/JjKFqg==", "dev": true, "requires": { - "apollo-server-caching": "^3.3.0", + "@apollo/utils.keyvaluecache": "^1.0.1", "apollo-server-env": "^4.2.1" } }, "apollo-reporting-protobuf": { - "version": "3.3.1", - "resolved": "https://registry.npmjs.org/apollo-reporting-protobuf/-/apollo-reporting-protobuf-3.3.1.tgz", - "integrity": "sha512-tyvj3Vj71TCh6c8PtdHOLgHHBSJ05DF/A/Po3q8yfHTBkOPcOJZE/GGN/PT/pwKg7HHxKcAeHDw7+xciVvGx0w==", - "dev": true, - "requires": { - "@apollo/protobufjs": "1.2.2" - } - }, - "apollo-server-caching": { - "version": "3.3.0", - "resolved": "https://registry.npmjs.org/apollo-server-caching/-/apollo-server-caching-3.3.0.tgz", - "integrity": "sha512-Wgcb0ArjZ5DjQ7ID+tvxUcZ7Yxdbk5l1MxZL8D8gkyjooOkhPNzjRVQ7ubPoXqO54PrOMOTm1ejVhsF+AfIirQ==", + "version": "3.3.3", + "resolved": "https://registry.npmjs.org/apollo-reporting-protobuf/-/apollo-reporting-protobuf-3.3.3.tgz", + "integrity": "sha512-L3+DdClhLMaRZWVmMbBcwl4Ic77CnEBPXLW53F7hkYhkaZD88ivbCVB1w/x5gunO6ZHrdzhjq0FHmTsBvPo7aQ==", "dev": true, "requires": { - "lru-cache": "^6.0.0" + "@apollo/protobufjs": "1.2.6" } }, "apollo-server-core": { - "version": "3.7.0", - "resolved": "https://registry.npmjs.org/apollo-server-core/-/apollo-server-core-3.7.0.tgz", - "integrity": "sha512-xUCDjrBzPVbttbh/HenuQdivco/dcXE2oIDYwCU6FU2RBXqxWFmuCl2Xe7VPA/5Frw/4snJDLCyVte9PA5edww==", + "version": "3.11.1", + "resolved": "https://registry.npmjs.org/apollo-server-core/-/apollo-server-core-3.11.1.tgz", + "integrity": "sha512-t/eCKrRFK1lYZlc5pHD99iG7Np7CEm3SmbDiONA7fckR3EaB/pdsEdIkIwQ5QBBpT5JLp/nwvrZRVwhaWmaRvw==", "dev": true, "requires": { + "@apollo/utils.keyvaluecache": "^1.0.1", "@apollo/utils.logger": "^1.0.0", + "@apollo/utils.usagereporting": "^1.0.0", "@apollographql/apollo-tools": "^0.5.3", "@apollographql/graphql-playground-html": "1.6.29", "@graphql-tools/mock": "^8.1.2", "@graphql-tools/schema": "^8.0.0", "@josephg/resolvable": "^1.0.0", - "apollo-datasource": "^3.3.1", - "apollo-reporting-protobuf": "^3.3.1", - "apollo-server-caching": "^3.3.0", + "apollo-datasource": "^3.3.2", + "apollo-reporting-protobuf": "^3.3.3", "apollo-server-env": "^4.2.1", "apollo-server-errors": "^3.3.1", - "apollo-server-plugin-base": "^3.5.3", - "apollo-server-types": "^3.5.3", + "apollo-server-plugin-base": "^3.7.1", + "apollo-server-types": "^3.7.1", "async-retry": "^1.2.1", "fast-json-stable-stringify": "^2.1.0", "graphql-tag": "^2.11.0", - "lodash.sortby": "^4.7.0", "loglevel": "^1.6.8", "lru-cache": "^6.0.0", + "node-abort-controller": "^3.0.1", "sha.js": "^2.4.11", - "uuid": "^8.0.0", + "uuid": "^9.0.0", "whatwg-mimetype": "^3.0.0" + }, + "dependencies": { + "uuid": { + "version": "9.0.0", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-9.0.0.tgz", + "integrity": "sha512-MXcSTerfPa4uqyzStbRoTgt5XIe3x5+42+q1sDuy3R5MDk66URdLMOZe5aPX/SQd+kuYAh0FdP/pO28IkQyTeg==", + "dev": true + } } }, "apollo-server-env": { @@ -19552,41 +18616,42 @@ "dev": true }, "apollo-server-express": { - "version": "3.7.0", - "resolved": "https://registry.npmjs.org/apollo-server-express/-/apollo-server-express-3.7.0.tgz", - "integrity": "sha512-176LSK7YBxwfleurtbfr5SYMheNNJSHrQa2h4QuosLqhfFJkfTpI2iBW56N737U47QfyueCOvkjNZVq86e3n2g==", + "version": "3.11.1", + "resolved": "https://registry.npmjs.org/apollo-server-express/-/apollo-server-express-3.11.1.tgz", + "integrity": "sha512-x9ngcpXbBlt4naCXTwNtBFb/mOd9OU0wtFXvJkObHF26NsRazu3DxDfEuekA6V1NFOocD+A9jmVMQeQWug5MgA==", "dev": true, "requires": { "@types/accepts": "^1.3.5", "@types/body-parser": "1.19.2", "@types/cors": "2.8.12", - "@types/express": "4.17.13", - "@types/express-serve-static-core": "4.17.28", + "@types/express": "4.17.14", + "@types/express-serve-static-core": "4.17.31", "accepts": "^1.3.5", - "apollo-server-core": "^3.7.0", - "apollo-server-types": "^3.5.3", + "apollo-server-core": "^3.11.1", + "apollo-server-types": "^3.7.1", "body-parser": "^1.19.0", "cors": "^2.8.5", "parseurl": "^1.3.3" } }, "apollo-server-plugin-base": { - "version": "3.5.3", - "resolved": "https://registry.npmjs.org/apollo-server-plugin-base/-/apollo-server-plugin-base-3.5.3.tgz", - "integrity": "sha512-zojm3qiUGYtM5k1PPrCJnLZSDNqvWvmIDvqBjCu3wI3iNZqNm3MOA86eYGFfaBi/WNu3qYIj6QE3T7w0XjRV1A==", + "version": "3.7.1", + "resolved": "https://registry.npmjs.org/apollo-server-plugin-base/-/apollo-server-plugin-base-3.7.1.tgz", + "integrity": "sha512-g3vJStmQtQvjGI289UkLMfThmOEOddpVgHLHT2bNj0sCD/bbisj4xKbBHETqaURokteqSWyyd4RDTUe0wAUDNQ==", "dev": true, "requires": { - "apollo-server-types": "^3.5.3" + "apollo-server-types": "^3.7.1" } }, "apollo-server-types": { - "version": "3.5.3", - "resolved": "https://registry.npmjs.org/apollo-server-types/-/apollo-server-types-3.5.3.tgz", - "integrity": "sha512-Qf5mMVTDyABEeyjGecwMsk0y0km4KuW8/j/UwBDQkAAW1QRy+w8nqi+wvSoA5hNXiYCdJN4U4nxTxm9+2eiT4w==", + "version": "3.7.1", + "resolved": "https://registry.npmjs.org/apollo-server-types/-/apollo-server-types-3.7.1.tgz", + "integrity": "sha512-aE9RDVplmkaOj/OduNmGa+0a1B5RIWI0o3zC1zLvBTVWMKTpo0ifVf11TyMkLCY+T7cnZqVqwyShziOyC3FyUw==", "dev": true, "requires": { - "apollo-reporting-protobuf": "^3.3.1", - "apollo-server-caching": "^3.3.0", + "@apollo/utils.keyvaluecache": "^1.0.1", + "@apollo/utils.logger": "^1.0.0", + "apollo-reporting-protobuf": "^3.3.3", "apollo-server-env": "^4.2.1" } }, @@ -19614,30 +18679,6 @@ "sprintf-js": "~1.0.2" } }, - "arr-diff": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/arr-diff/-/arr-diff-4.0.0.tgz", - "integrity": "sha1-1kYQdP6/7HHn4VI1dhoyml3HxSA=", - "dev": true - }, - "arr-flatten": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/arr-flatten/-/arr-flatten-1.1.0.tgz", - "integrity": "sha512-L3hKV5R/p5o81R7O02IGnwpDmkp6E982XhtbuwSe3O4qOtMMMtodicASA1Cny2U+aCXcNpml+m4dPsvsJ3jatg==", - "dev": true - }, - "arr-union": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/arr-union/-/arr-union-3.1.0.tgz", - "integrity": "sha1-45sJrqne+Gao8gbiiK9jkZuuOcQ=", - "dev": true - }, - "array-each": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/array-each/-/array-each-1.0.1.tgz", - "integrity": "sha1-p5SvDAWrF1KEbudTofIRoFugxE8=", - "dev": true - }, "array-flatten": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-1.1.1.tgz", @@ -19657,24 +18698,12 @@ "is-string": "^1.0.7" } }, - "array-slice": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/array-slice/-/array-slice-1.1.0.tgz", - "integrity": "sha512-B1qMD3RBP7O8o0H2KbrXDyB0IccejMF15+87Lvlor12ONPRHP6gTjXMNkt/d3ZuOGbAe66hFmaCfECI24Ufp6w==", - "dev": true - }, "array-union": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/array-union/-/array-union-2.1.0.tgz", "integrity": "sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw==", "dev": true }, - "array-unique": { - "version": "0.3.2", - "resolved": "https://registry.npmjs.org/array-unique/-/array-unique-0.3.2.tgz", - "integrity": "sha1-qJS3XUvE9s1nnvMkSp/Y9Gri1Cg=", - "dev": true - }, "array.prototype.every": { "version": "1.1.3", "resolved": "https://registry.npmjs.org/array.prototype.every/-/array.prototype.every-1.1.3.tgz", @@ -19720,12 +18749,6 @@ "integrity": "sha1-8S4PPF13sLHN2RRpQuTpbB5N1SU=", "dev": true }, - "assign-symbols": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/assign-symbols/-/assign-symbols-1.0.0.tgz", - "integrity": "sha1-WWZ/QfrdTyDMvCu5a41Pf3jsA2c=", - "dev": true - }, "astral-regex": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/astral-regex/-/astral-regex-1.0.0.tgz", @@ -19785,12 +18808,6 @@ "integrity": "sha1-x57Zf380y48robyXkLzDZkdLS3k=", "dev": true }, - "atob": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/atob/-/atob-2.1.2.tgz", - "integrity": "sha512-Wm6ukoaOGJi/73p/cl2GvLjTI5JM1k/O14isD73YML8StrH/7/lRFgmg8nICZgD3bZZvjwCGxtMOD3wWNAu8cg==", - "dev": true - }, "atomic-sleep": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/atomic-sleep/-/atomic-sleep-1.0.0.tgz", @@ -19803,15 +18820,14 @@ "dev": true }, "avvio": { - "version": "8.1.3", - "resolved": "https://registry.npmjs.org/avvio/-/avvio-8.1.3.tgz", - "integrity": "sha512-tl9TC0yDRKzP6gFLkrInqPyx8AkfBC/0QRnwkE9Jo31+OJjLrE/73GJuE0QgSB0Vpv38CTJJZGqU9hczowclWw==", + "version": "8.2.0", + "resolved": "https://registry.npmjs.org/avvio/-/avvio-8.2.0.tgz", + "integrity": "sha512-bbCQdg7bpEv6kGH41RO/3B2/GMMmJSo2iBK+X8AWN9mujtfUipMDfIjsgHCfpnKqoGEQrrmCDKSa5OQ19+fDmg==", "dev": true, "requires": { "archy": "^1.0.0", "debug": "^4.0.0", - "fastq": "^1.6.1", - "queue-microtask": "^1.1.2" + "fastq": "^1.6.1" } }, "aws-sdk": { @@ -19860,43 +18876,34 @@ "follow-redirects": "^1.14.0" } }, - "babel-plugin-dynamic-import-node": { - "version": "2.3.3", - "resolved": "https://registry.npmjs.org/babel-plugin-dynamic-import-node/-/babel-plugin-dynamic-import-node-2.3.3.tgz", - "integrity": "sha512-jZVI+s9Zg3IqA/kdi0i6UDCybUI3aSBLnglhYbSSjKlV7yF1F/5LWv8MakQmvYpnbJDS6fcBL2KzHSxNCMtWSQ==", - "dev": true, - "requires": { - "object.assign": "^4.1.0" - } - }, "babel-plugin-polyfill-corejs2": { - "version": "0.3.1", - "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-corejs2/-/babel-plugin-polyfill-corejs2-0.3.1.tgz", - "integrity": "sha512-v7/T6EQcNfVLfcN2X8Lulb7DjprieyLWJK/zOWH5DUYcAgex9sP3h25Q+DLsX9TloXe3y1O8l2q2Jv9q8UVB9w==", + "version": "0.3.3", + "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-corejs2/-/babel-plugin-polyfill-corejs2-0.3.3.tgz", + "integrity": "sha512-8hOdmFYFSZhqg2C/JgLUQ+t52o5nirNwaWM2B9LWteozwIvM14VSwdsCAUET10qT+kmySAlseadmfeeSWFCy+Q==", "dev": true, "requires": { - "@babel/compat-data": "^7.13.11", - "@babel/helper-define-polyfill-provider": "^0.3.1", + "@babel/compat-data": "^7.17.7", + "@babel/helper-define-polyfill-provider": "^0.3.3", "semver": "^6.1.1" } }, "babel-plugin-polyfill-corejs3": { - "version": "0.5.2", - "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-corejs3/-/babel-plugin-polyfill-corejs3-0.5.2.tgz", - "integrity": "sha512-G3uJih0XWiID451fpeFaYGVuxHEjzKTHtc9uGFEjR6hHrvNzeS/PX+LLLcetJcytsB5m4j+K3o/EpXJNb/5IEQ==", + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-corejs3/-/babel-plugin-polyfill-corejs3-0.6.0.tgz", + "integrity": "sha512-+eHqR6OPcBhJOGgsIar7xoAB1GcSwVUA3XjAd7HJNzOXT4wv6/H7KIdA/Nc60cvUlDbKApmqNvD1B1bzOt4nyA==", "dev": true, "requires": { - "@babel/helper-define-polyfill-provider": "^0.3.1", - "core-js-compat": "^3.21.0" + "@babel/helper-define-polyfill-provider": "^0.3.3", + "core-js-compat": "^3.25.1" } }, "babel-plugin-polyfill-regenerator": { - "version": "0.3.1", - "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-regenerator/-/babel-plugin-polyfill-regenerator-0.3.1.tgz", - "integrity": "sha512-Y2B06tvgHYt1x0yz17jGkGeeMr5FeKUu+ASJ+N6nB5lQ8Dapfg42i0OVrf8PNGJ3zKL4A23snMi1IRwrqqND7A==", + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-regenerator/-/babel-plugin-polyfill-regenerator-0.4.1.tgz", + "integrity": "sha512-NtQGmyQDXjQqQ+IzRkBVwEOz9lQ4zxAQZgoAYEtU9dJjnl1Oc98qnN7jcp+bE7O7aYzVpavXE3/VKXNzUbh7aw==", "dev": true, "requires": { - "@babel/helper-define-polyfill-provider": "^0.3.1" + "@babel/helper-define-polyfill-provider": "^0.3.3" } }, "babel-walk": { @@ -19990,67 +18997,6 @@ "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", "dev": true }, - "base": { - "version": "0.11.2", - "resolved": "https://registry.npmjs.org/base/-/base-0.11.2.tgz", - "integrity": "sha512-5T6P4xPgpp0YDFvSWwEZ4NoE3aM4QBQXDzmVbraCkFj8zHM+mba8SyqB5DbZWyR7mYHo6Y7BdQo3MoA4m0TeQg==", - "dev": true, - "requires": { - "cache-base": "^1.0.1", - "class-utils": "^0.3.5", - "component-emitter": "^1.2.1", - "define-property": "^1.0.0", - "isobject": "^3.0.1", - "mixin-deep": "^1.2.0", - "pascalcase": "^0.1.1" - }, - "dependencies": { - "define-property": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/define-property/-/define-property-1.0.0.tgz", - "integrity": "sha1-dp66rz9KY6rTr56NMEybvnm/sOY=", - "dev": true, - "requires": { - "is-descriptor": "^1.0.0" - } - }, - "is-accessor-descriptor": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz", - "integrity": "sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ==", - "dev": true, - "requires": { - "kind-of": "^6.0.0" - } - }, - "is-data-descriptor": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz", - "integrity": "sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ==", - "dev": true, - "requires": { - "kind-of": "^6.0.0" - } - }, - "is-descriptor": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.2.tgz", - "integrity": "sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg==", - "dev": true, - "requires": { - "is-accessor-descriptor": "^1.0.0", - "is-data-descriptor": "^1.0.0", - "kind-of": "^6.0.2" - } - }, - "kind-of": { - "version": "6.0.3", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.3.tgz", - "integrity": "sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==", - "dev": true - } - } - }, "base64-js": { "version": "1.5.1", "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz", @@ -20138,9 +19084,9 @@ "dev": true }, "body-parser": { - "version": "1.20.0", - "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.20.0.tgz", - "integrity": "sha512-DfJ+q6EPcGKZD1QWUjSpqp+Q7bDQTsQIF4zfUAtZ6qk+H/3/QRhg9CEp39ss+/T2vw0+HaidC0ecJj/DRLIaKg==", + "version": "1.20.1", + "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.20.1.tgz", + "integrity": "sha512-jWi7abTbYwajOytWCQc37VulmWiRae5RyTpaCyDcS5/lMdtwSz5lOpDE67srw/HYe35f1z3fDQw+3txg7gNtWw==", "dev": true, "requires": { "bytes": "3.1.2", @@ -20151,7 +19097,7 @@ "http-errors": "2.0.0", "iconv-lite": "0.4.24", "on-finished": "2.4.1", - "qs": "6.10.3", + "qs": "6.11.0", "raw-body": "2.5.1", "type-is": "~1.6.18", "unpipe": "1.0.0" @@ -20227,22 +19173,21 @@ } }, "browserslist": { - "version": "4.20.3", - "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.20.3.tgz", - "integrity": "sha512-NBhymBQl1zM0Y5dQT/O+xiLP9/rzOIQdKM/eMJBAq7yBgaB6krIYLGejrwVYnSHZdqjscB1SPuAjHwxjvN6Wdg==", + "version": "4.21.4", + "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.21.4.tgz", + "integrity": "sha512-CBHJJdDmgjl3daYjN5Cp5kbTf1mUhZoS+beLklHIvkOWscs83YAhLlF3Wsh/lciQYAcbBJgTOD44VtG31ZM4Hw==", "dev": true, "requires": { - "caniuse-lite": "^1.0.30001332", - "electron-to-chromium": "^1.4.118", - "escalade": "^3.1.1", - "node-releases": "^2.0.3", - "picocolors": "^1.0.0" + "caniuse-lite": "^1.0.30001400", + "electron-to-chromium": "^1.4.251", + "node-releases": "^2.0.6", + "update-browserslist-db": "^1.0.9" } }, "bson": { - "version": "4.6.3", - "resolved": "https://registry.npmjs.org/bson/-/bson-4.6.3.tgz", - "integrity": "sha512-rAqP5hcUVJhXP2MCSNVsf0oM2OGU1So6A9pVRDYayvJ5+hygXHQApf87wd5NlhPM1J9RJnbqxIG/f8QTzRoQ4A==", + "version": "4.7.0", + "resolved": "https://registry.npmjs.org/bson/-/bson-4.7.0.tgz", + "integrity": "sha512-VrlEE4vuiO1WTpfof4VmaVolCVYkYTgB9iWgYNOrVlnifpME/06fhFRmONgBhClD5pFC1t9ZWqFUQEQAzY43bA==", "dev": true, "requires": { "buffer": "^5.6.0" @@ -20289,16 +19234,13 @@ "integrity": "sha512-a7ZpuTZU1TRtnwyCNW3I5dc0wWNC3VR9S++Ewyk2HHZdrO3CQJqSpd+95Us590V6AL7JqUAH2IwZ/398PmNFgw==", "dev": true }, - "bunyan": { - "version": "1.8.15", - "resolved": "https://registry.npmjs.org/bunyan/-/bunyan-1.8.15.tgz", - "integrity": "sha512-0tECWShh6wUysgucJcBAoYegf3JJoZWibxdqhTm7OHPeT42qdjkZ29QCMcKwbgU1kiH+auSIasNRXMLWXafXig==", + "busboy": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/busboy/-/busboy-1.6.0.tgz", + "integrity": "sha512-8SFQbg/0hQ9xy3UNTB0YEnsNBbWfhf7RtnzpL7TkBiTBRfrQ9Fxcnz7VJsleJpyp6rVLvXiuORqjlHi5q+PYuA==", "dev": true, "requires": { - "dtrace-provider": "~0.8", - "moment": "^2.19.3", - "mv": "~2", - "safe-json-stringify": "~1" + "streamsearch": "^1.1.0" } }, "bytes": { @@ -20307,23 +19249,6 @@ "integrity": "sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==", "dev": true }, - "cache-base": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/cache-base/-/cache-base-1.0.1.tgz", - "integrity": "sha512-AKcdTnFSWATd5/GCPRxr2ChwIJ85CeyrEyjRHlKxQ56d4XJMGym0uAiKn0xbLOGOl3+yRpOTi484dVCEc5AUzQ==", - "dev": true, - "requires": { - "collection-visit": "^1.0.0", - "component-emitter": "^1.2.1", - "get-value": "^2.0.6", - "has-value": "^1.0.0", - "isobject": "^3.0.1", - "set-value": "^2.0.0", - "to-object-path": "^0.3.0", - "union-value": "^1.0.0", - "unset-value": "^1.0.0" - } - }, "cache-content-type": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/cache-content-type/-/cache-content-type-1.0.1.tgz", @@ -20394,9 +19319,9 @@ "dev": true }, "caniuse-lite": { - "version": "1.0.30001338", - "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001338.tgz", - "integrity": "sha512-1gLHWyfVoRDsHieO+CaeYe7jSo/MT7D7lhaXUiwwbuR5BwQxORs0f1tAwUSQr3YbxRXJvxHM/PA5FfPQRnsPeQ==", + "version": "1.0.30001406", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001406.tgz", + "integrity": "sha512-bWTlaXUy/rq0BBtYShc/jArYfBPjEV95euvZ8JVtO43oQExEN/WquoqpufFjNu4kSpi5cy5kMbNvzztWDfv1Jg==", "dev": true }, "caseless": { @@ -20406,9 +19331,9 @@ "dev": true }, "cassandra-driver": { - "version": "4.6.3", - "resolved": "https://registry.npmjs.org/cassandra-driver/-/cassandra-driver-4.6.3.tgz", - "integrity": "sha512-npW670TXjTHrdb15LUFN01wssb9vvz6SuNYcppesoKcUXx3Q29nXVhRtnvsnkG0BaSnDGvCCR4udrzYLsbh+sg==", + "version": "4.6.4", + "resolved": "https://registry.npmjs.org/cassandra-driver/-/cassandra-driver-4.6.4.tgz", + "integrity": "sha512-SksbIK0cZ2QZRx8ti7w+PnLqldyY+6kU2gRWFChwXFTtrD/ce8cQICDEHxyPwx+DeILwRnMrPf9cjUGizYw9Vg==", "dev": true, "requires": { "@types/long": "^4.0.0", @@ -20473,29 +19398,6 @@ "integrity": "sha512-5tK7EtrZ0N+OLFMthtqOj4fI2Jeb88C4CAZPu25LDVUgXJ0A3Js4PMGqrn0JU1W0Mh1/Z8wZzYPxqUrXeBboCQ==", "dev": true }, - "class-utils": { - "version": "0.3.6", - "resolved": "https://registry.npmjs.org/class-utils/-/class-utils-0.3.6.tgz", - "integrity": "sha512-qOhPa/Fj7s6TY8H8esGu5QNpMMQxz79h+urzrNYN6mn+9BnxlDGf5QZ+XeCDsxSjPqsSR56XOZOJmpeurnLMeg==", - "dev": true, - "requires": { - "arr-union": "^3.1.0", - "define-property": "^0.2.5", - "isobject": "^3.0.0", - "static-extend": "^0.1.1" - }, - "dependencies": { - "define-property": { - "version": "0.2.5", - "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", - "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", - "dev": true, - "requires": { - "is-descriptor": "^0.1.0" - } - } - } - }, "clean-stack": { "version": "2.2.0", "resolved": "https://registry.npmjs.org/clean-stack/-/clean-stack-2.2.0.tgz", @@ -20581,16 +19483,6 @@ "type-is": "^1.6.16" } }, - "collection-visit": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/collection-visit/-/collection-visit-1.0.0.tgz", - "integrity": "sha1-S8A3PBZLwykbTTaMgpzxqApZ3KA=", - "dev": true, - "requires": { - "map-visit": "^1.0.0", - "object-visit": "^1.0.0" - } - }, "color": { "version": "3.2.1", "resolved": "https://registry.npmjs.org/color/-/color-3.2.1.tgz", @@ -20627,9 +19519,9 @@ } }, "colorette": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/colorette/-/colorette-1.2.1.tgz", - "integrity": "sha512-puCDz0CzydiSYOrnXpz/PKd69zRrribezjtE9yd4zvytoRc8+RY/KJPvtPFKZS3E3wP6neGyMe0vOTlHO5L3Pw==", + "version": "2.0.16", + "resolved": "https://registry.npmjs.org/colorette/-/colorette-2.0.16.tgz", + "integrity": "sha512-hUewv7oMjCp+wkBv5Rm0v87eJhq4woh5rSR+42YSQJKecCqgIqNkZ6lAlQms/BwHPJA5NKMRlpxPRv0n8HQW6g==", "dev": true }, "colorspace": { @@ -20673,12 +19565,6 @@ "integrity": "sha1-3dgA2gxmEnOTzKWVDqloo6rxJTs=", "dev": true }, - "component-emitter": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/component-emitter/-/component-emitter-1.3.0.tgz", - "integrity": "sha512-Rd3se6QB+sO1TwqZjscQrurpEPIfO0/yYnSin6Q/rD3mOutHvUrCAhJub3r90uNb+SESBuE0QYoB90YdfatsRg==", - "dev": true - }, "compress-brotli": { "version": "1.3.8", "resolved": "https://registry.npmjs.org/compress-brotli/-/compress-brotli-1.3.8.tgz", @@ -20759,11 +19645,6 @@ "resolved": "https://registry.npmjs.org/console-log-level/-/console-log-level-1.4.1.tgz", "integrity": "sha512-VZzbIORbP+PPcN/gg3DXClTLPLg5Slwd5fL2MIc+o1qZ4BXBvWyc6QxPk6T/Mkr6IVjRpoAGf32XxP3ZWMVRcQ==" }, - "container-info": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/container-info/-/container-info-1.1.0.tgz", - "integrity": "sha512-eD2zLAmxGS2kmL4f1jY8BdOqnmpL6X70kvzTBW/9FIQnxoxiBJ4htMsTmtPLPWRs7NHYFvqKQ1VtppV08mdsQA==" - }, "content-disposition": { "version": "0.5.4", "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.4.tgz", @@ -20825,12 +19706,6 @@ } } }, - "copy-descriptor": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/copy-descriptor/-/copy-descriptor-0.1.1.tgz", - "integrity": "sha1-Z29us8OZl8LuGsOpJP1hJHSPV40=", - "dev": true - }, "copy-to": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/copy-to/-/copy-to-2.0.1.tgz", @@ -20838,21 +19713,12 @@ "dev": true }, "core-js-compat": { - "version": "3.22.4", - "resolved": "https://registry.npmjs.org/core-js-compat/-/core-js-compat-3.22.4.tgz", - "integrity": "sha512-dIWcsszDezkFZrfm1cnB4f/J85gyhiCpxbgBdohWCDtSVuAaChTSpPV7ldOQf/Xds2U5xCIJZOK82G4ZPAIswA==", + "version": "3.25.2", + "resolved": "https://registry.npmjs.org/core-js-compat/-/core-js-compat-3.25.2.tgz", + "integrity": "sha512-TxfyECD4smdn3/CjWxczVtJqVLEEC2up7/82t7vC0AzNogr+4nQ8vyF7abxAuTXWvjTClSbvGhU0RgqA4ToQaQ==", "dev": true, "requires": { - "browserslist": "^4.20.3", - "semver": "7.0.0" - }, - "dependencies": { - "semver": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.0.0.tgz", - "integrity": "sha512-+GB6zVA9LWh6zovYQLALHwv5rb2PHGlJi3lfiqIHxR0uuwCgefcOJc59v9fv1w8GbStwxuuqqAjI9NMAOOgq1A==", - "dev": true - } + "browserslist": "^4.21.4" } }, "core-util-is": { @@ -20898,33 +19764,33 @@ "dev": true }, "csv": { - "version": "5.5.3", - "resolved": "https://registry.npmjs.org/csv/-/csv-5.5.3.tgz", - "integrity": "sha512-QTaY0XjjhTQOdguARF0lGKm5/mEq9PD9/VhZZegHDIBq2tQwgNpHc3dneD4mGo2iJs+fTKv5Bp0fZ+BRuY3Z0g==", + "version": "6.2.5", + "resolved": "https://registry.npmjs.org/csv/-/csv-6.2.5.tgz", + "integrity": "sha512-T+K0H7MIrlrnP6KxYKo3lK+uLl6OC2Gmwdd81TG/VdkhKvpatl35sR7tyRSpDLGl22y2T+q9KvNHnVtn4OAscQ==", "dev": true, "requires": { - "csv-generate": "^3.4.3", - "csv-parse": "^4.16.3", - "csv-stringify": "^5.6.5", - "stream-transform": "^2.1.3" + "csv-generate": "^4.2.1", + "csv-parse": "^5.3.3", + "csv-stringify": "^6.2.3", + "stream-transform": "^3.2.1" } }, "csv-generate": { - "version": "3.4.3", - "resolved": "https://registry.npmjs.org/csv-generate/-/csv-generate-3.4.3.tgz", - "integrity": "sha512-w/T+rqR0vwvHqWs/1ZyMDWtHHSJaN06klRqJXBEpDJaM/+dZkso0OKh1VcuuYvK3XM53KysVNq8Ko/epCK8wOw==", + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/csv-generate/-/csv-generate-4.2.1.tgz", + "integrity": "sha512-w6GFHjvApv6bcJ2xdi9JGsH6ZvUBfC+vUdfefnEzurXG6hMRwzkBLnhztU2H7v7+zfCk1I/knnQ+tGbgpxWrBw==", "dev": true }, "csv-parse": { - "version": "4.16.3", - "resolved": "https://registry.npmjs.org/csv-parse/-/csv-parse-4.16.3.tgz", - "integrity": "sha512-cO1I/zmz4w2dcKHVvpCr7JVRu8/FymG5OEpmvsZYlccYolPBLoVGKUHgNoc4ZGkFeFlWGEDmMyBM+TTqRdW/wg==", + "version": "5.3.3", + "resolved": "https://registry.npmjs.org/csv-parse/-/csv-parse-5.3.3.tgz", + "integrity": "sha512-kEWkAPleNEdhFNkHQpFHu9RYPogsFj3dx6bCxL847fsiLgidzWg0z/O0B1kVWMJUc5ky64zGp18LX2T3DQrOfw==", "dev": true }, "csv-stringify": { - "version": "5.6.5", - "resolved": "https://registry.npmjs.org/csv-stringify/-/csv-stringify-5.6.5.tgz", - "integrity": "sha512-PjiQ659aQ+fUTQqSrd1XEDnOr52jh30RBurfzkscaE2tPaFsDH5wOAHJiw8XAHphRknCwMUE9KRayc4K/NbO8A==", + "version": "6.2.3", + "resolved": "https://registry.npmjs.org/csv-stringify/-/csv-stringify-6.2.3.tgz", + "integrity": "sha512-4qGjUMwnlaRc00gc2jrIYh2w/h1fo25B0mTuY9K8fBiIgtmCX3LcgUbrEGViL98Ci4Se/F5LFEtu8k+dItJVZQ==", "dev": true }, "dargs": { @@ -20959,12 +19825,6 @@ "integrity": "sha1-9lNNFRSCabIDUue+4m9QH5oZEpA=", "dev": true }, - "decode-uri-component": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/decode-uri-component/-/decode-uri-component-0.2.0.tgz", - "integrity": "sha1-6zkTMzRYd1y4TNGh+uBiEGu4dUU=", - "dev": true - }, "decompress-response": { "version": "6.0.0", "resolved": "https://registry.npmjs.org/decompress-response/-/decompress-response-6.0.0.tgz", @@ -21060,53 +19920,6 @@ "object-keys": "^1.1.1" } }, - "define-property": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/define-property/-/define-property-2.0.2.tgz", - "integrity": "sha512-jwK2UV4cnPpbcG7+VRARKTZPUWowwXA8bzH5NP6ud0oeAxyYPuGZUAC7hMugpCdz4BeSZl2Dl9k66CHJ/46ZYQ==", - "dev": true, - "requires": { - "is-descriptor": "^1.0.2", - "isobject": "^3.0.1" - }, - "dependencies": { - "is-accessor-descriptor": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz", - "integrity": "sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ==", - "dev": true, - "requires": { - "kind-of": "^6.0.0" - } - }, - "is-data-descriptor": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz", - "integrity": "sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ==", - "dev": true, - "requires": { - "kind-of": "^6.0.0" - } - }, - "is-descriptor": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.2.tgz", - "integrity": "sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg==", - "dev": true, - "requires": { - "is-accessor-descriptor": "^1.0.0", - "is-data-descriptor": "^1.0.0", - "kind-of": "^6.0.2" - } - }, - "kind-of": { - "version": "6.0.3", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.3.tgz", - "integrity": "sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==", - "dev": true - } - } - }, "defined": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/defined/-/defined-1.0.0.tgz", @@ -21149,12 +19962,6 @@ "integrity": "sha1-hMbhWbgZBP3KWaDvRM2HDTElD5o=", "dev": true }, - "denque": { - "version": "1.5.1", - "resolved": "https://registry.npmjs.org/denque/-/denque-1.5.1.tgz", - "integrity": "sha512-XwE+iZ4D6ZUB7mfYRMb5wByE8L74HCn30FBN7sWnXksWc1LO1bPDl67pBR9o/kC4z/xSNAwkMYcGgqDV3BE3Hw==", - "dev": true - }, "depd": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/depd/-/depd-1.1.2.tgz", @@ -21213,12 +20020,6 @@ "integrity": "sha512-2sJGJTaXIIaR1w4iJSNoN0hnMY7Gpc/n8D4qSCJw8QqFWXf7cuAgnEHxBpweaVcPevC2l3KpjYCx3NypQQgaJg==", "dev": true }, - "detect-file": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/detect-file/-/detect-file-1.0.0.tgz", - "integrity": "sha1-8NZtA2cqglyxtzvbP+YjEMjlUrc=", - "dev": true - }, "detect-node": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/detect-node/-/detect-node-2.1.0.tgz", @@ -21236,6 +20037,12 @@ "minimist": "^1.1.1" } }, + "diagnostics_channel": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/diagnostics_channel/-/diagnostics_channel-1.1.0.tgz", + "integrity": "sha512-OE1ngLDjSBPG6Tx0YATELzYzy3RKHC+7veQ8gLa8yS7AAgw65mFbVdcsu3501abqOZCEZqZyAIemB0zXlqDSuw==", + "dev": true + }, "dir-glob": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/dir-glob/-/dir-glob-3.0.1.tgz", @@ -21261,9 +20068,9 @@ "dev": true }, "dotenv": { - "version": "16.0.1", - "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-16.0.1.tgz", - "integrity": "sha512-1K6hR6wtk2FviQ4kEiSjFiH5rpzEVi8WW0x96aztHVMhEspNpc4DVOUTEHtEva5VThQ8IaBX1Pe4gSzpVVUsKQ==", + "version": "16.0.3", + "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-16.0.3.tgz", + "integrity": "sha512-7GO6HghkA5fYG9TYnNxi14/7K9f5occMlp3zXAuSxn7CKCxt9xbNWG7yF8hTCSUchlfWSe3uLmlPfigevRItzQ==", "dev": true }, "dotignore": { @@ -21285,18 +20092,6 @@ "nan": "^2.14.0" } }, - "duplexify": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/duplexify/-/duplexify-4.1.2.tgz", - "integrity": "sha512-fz3OjcNCHmRP12MJoZMPglx8m4rrFP8rovnk4vT8Fs+aonZoCwGg10dSsQsfP/E62eZcPTMSMP6686fu9Qlqtw==", - "dev": true, - "requires": { - "end-of-stream": "^1.4.1", - "inherits": "^2.0.3", - "readable-stream": "^3.1.1", - "stream-shift": "^1.0.0" - } - }, "ecc-jsbn": { "version": "0.1.2", "resolved": "https://registry.npmjs.org/ecc-jsbn/-/ecc-jsbn-0.1.2.tgz", @@ -21323,13 +20118,12 @@ "dev": true }, "elastic-apm-http-client": { - "version": "11.0.1", - "resolved": "https://registry.npmjs.org/elastic-apm-http-client/-/elastic-apm-http-client-11.0.1.tgz", - "integrity": "sha512-5AOWlhs2WlZpI+DfgGqY/8Rk7KF8WeevaO8R961eBylavU6GWhLRNiJncohn5jsvrqhmeT19azBvy/oYRN7bJw==", + "version": "11.0.4", + "resolved": "https://registry.npmjs.org/elastic-apm-http-client/-/elastic-apm-http-client-11.0.4.tgz", + "integrity": "sha512-449Qj/STi9hgnIk2KQ7719E7lpM3/i4Afs7NUhSOX8wV3sxn/+ItIHx9kKJthzhDDezxIfQcH83v83AF67GspQ==", "requires": { "agentkeepalive": "^4.2.1", "breadth-filter": "^2.0.0", - "container-info": "^1.0.1", "end-of-stream": "^1.4.4", "fast-safe-stringify": "^2.0.7", "fast-stream-to-buffer": "^1.0.0", @@ -21408,9 +20202,9 @@ } }, "electron-to-chromium": { - "version": "1.4.137", - "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.137.tgz", - "integrity": "sha512-0Rcpald12O11BUogJagX3HsCN3FE83DSqWjgXoHo5a72KUKMSfI39XBgJpgNNxS9fuGzytaFjE06kZkiVFy2qA==", + "version": "1.4.254", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.254.tgz", + "integrity": "sha512-Sh/7YsHqQYkA6ZHuHMy24e6TE4eX6KZVsZb9E/DvU1nQRIrH4BflO/4k+83tfdYvDl+MObvlqHPRICzEdC9c6Q==", "dev": true }, "emoji-regex": { @@ -21614,6 +20408,18 @@ "v8-compile-cache": "^2.0.3" }, "dependencies": { + "ajv": { + "version": "6.12.6", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", + "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", + "dev": true, + "requires": { + "fast-deep-equal": "^3.1.1", + "fast-json-stable-stringify": "^2.0.0", + "json-schema-traverse": "^0.4.1", + "uri-js": "^4.2.2" + } + }, "ansi-regex": { "version": "4.1.1", "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.1.tgz", @@ -21635,6 +20441,22 @@ "integrity": "sha512-cyFDKrqc/YdcWFniJhzI42+AzS+gNwmUzOSFcRCQYwySuBBBy/KjuxWLZ/FHEH6Moq1NizMOBWyTcv8O4OZIMg==", "dev": true }, + "js-yaml": { + "version": "3.14.1", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.14.1.tgz", + "integrity": "sha512-okMH7OXXJ7YrN9Ok3/SXrnu4iX9yOk+25nqX4imS2npuvTYDmo/QEZoqwZkYaIDk3jVvBOTOIEgEhaLOynBS9g==", + "dev": true, + "requires": { + "argparse": "^1.0.7", + "esprima": "^4.0.0" + } + }, + "json-schema-traverse": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", + "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", + "dev": true + }, "strip-ansi": { "version": "5.2.0", "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-5.2.0.tgz", @@ -21818,9 +20640,9 @@ } }, "eslint-plugin-license-header": { - "version": "0.4.0", - "resolved": "https://registry.npmjs.org/eslint-plugin-license-header/-/eslint-plugin-license-header-0.4.0.tgz", - "integrity": "sha512-KNpyxD+r8d9VoioyaHofUDsrYO+epVv/WjGZKugfO+qVN1KvHi/LwpXXY1618OCOYEaRNXZeRUtbOIb2YvJXTw==", + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/eslint-plugin-license-header/-/eslint-plugin-license-header-0.6.0.tgz", + "integrity": "sha512-IEywStBWaDBDMkogYoKUAdaOuomZ+YaQmdoSD2vHmXobekM+XuP6SWLlvwUUhIbdocn3MTlb5CUJ8E4VHz1c/w==", "dev": true, "requires": { "requireindex": "^1.2.0" @@ -21963,6 +20785,12 @@ "integrity": "sha1-Qa4u62XvpiJorr/qg6x9eSmbCIc=", "dev": true }, + "event-target-shim": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/event-target-shim/-/event-target-shim-5.0.1.tgz", + "integrity": "sha512-i/2XbnSz/uxRCU6+NdVJgKWDTM427+MqYbkQzD321DuCQJUqOuJKIA0IM2+W2xtYHdKOmZ4dR6fExsd4SXL+WQ==", + "dev": true + }, "events": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/events/-/events-1.1.1.tgz", @@ -21984,74 +20812,15 @@ "assert-plus": "^1.0.0" } }, - "expand-brackets": { - "version": "2.1.4", - "resolved": "https://registry.npmjs.org/expand-brackets/-/expand-brackets-2.1.4.tgz", - "integrity": "sha1-t3c14xXOMPa27/D4OwQVGiJEliI=", - "dev": true, - "requires": { - "debug": "^2.3.3", - "define-property": "^0.2.5", - "extend-shallow": "^2.0.1", - "posix-character-classes": "^0.1.0", - "regex-not": "^1.0.0", - "snapdragon": "^0.8.1", - "to-regex": "^3.0.1" - }, - "dependencies": { - "debug": { - "version": "2.6.9", - "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", - "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", - "dev": true, - "requires": { - "ms": "2.0.0" - } - }, - "define-property": { - "version": "0.2.5", - "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", - "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", - "dev": true, - "requires": { - "is-descriptor": "^0.1.0" - } - }, - "extend-shallow": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", - "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", - "dev": true, - "requires": { - "is-extendable": "^0.1.0" - } - }, - "ms": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", - "dev": true - } - } - }, - "expand-tilde": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/expand-tilde/-/expand-tilde-2.0.2.tgz", - "integrity": "sha1-l+gBqgUt8CRU3kawK/YhZCzchQI=", - "dev": true, - "requires": { - "homedir-polyfill": "^1.0.1" - } - }, "express": { - "version": "4.18.1", - "resolved": "https://registry.npmjs.org/express/-/express-4.18.1.tgz", - "integrity": "sha512-zZBcOX9TfehHQhtupq57OF8lFZ3UZi08Y97dwFCkD8p9d/d2Y3M+ykKcwaMDEL+4qyUolgBDX6AblpR3fL212Q==", + "version": "4.18.2", + "resolved": "https://registry.npmjs.org/express/-/express-4.18.2.tgz", + "integrity": "sha512-5/PsL6iGPdfQ/lKM1UuielYgv3BUoJfz1aUwU9vHZ+J7gyvwdQXFEBIEIaxeGf0GIcreATNyBExtalisDbuMqQ==", "dev": true, "requires": { "accepts": "~1.3.8", "array-flatten": "1.1.1", - "body-parser": "1.20.0", + "body-parser": "1.20.1", "content-disposition": "0.5.4", "content-type": "~1.0.4", "cookie": "0.5.0", @@ -22070,7 +20839,7 @@ "parseurl": "~1.3.3", "path-to-regexp": "0.1.7", "proxy-addr": "~2.0.7", - "qs": "6.10.3", + "qs": "6.11.0", "range-parser": "~1.2.1", "safe-buffer": "5.2.1", "send": "0.18.0", @@ -22122,41 +20891,12 @@ "integrity": "sha1-32BBeABfUi8V60SQ5yR6G/qmf4w=", "dev": true }, - "safe-buffer": { - "version": "5.2.1", - "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", - "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", - "dev": true - }, - "send": { - "version": "0.18.0", - "resolved": "https://registry.npmjs.org/send/-/send-0.18.0.tgz", - "integrity": "sha512-qqWzuOjSFOuqPjFe4NOsMLafToQQwBSOEpS+FwEt3A2V3vKubTquT3vmLTQpFgMXp8AlFWFuP1qKaJZOtPpVXg==", - "dev": true, - "requires": { - "debug": "2.6.9", - "depd": "2.0.0", - "destroy": "1.2.0", - "encodeurl": "~1.0.2", - "escape-html": "~1.0.3", - "etag": "~1.8.1", - "fresh": "0.5.2", - "http-errors": "2.0.0", - "mime": "1.6.0", - "ms": "2.1.3", - "on-finished": "2.4.1", - "range-parser": "~1.2.1", - "statuses": "2.0.1" - }, - "dependencies": { - "ms": { - "version": "2.1.3", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", - "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", - "dev": true - } - } - }, + "safe-buffer": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", + "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", + "dev": true + }, "statuses": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.1.tgz", @@ -22241,36 +20981,6 @@ "integrity": "sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==", "dev": true }, - "extend-shallow": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-3.0.2.tgz", - "integrity": "sha1-Jqcarwc7OfshJxcnRhMcJwQCjbg=", - "dev": true, - "requires": { - "assign-symbols": "^1.0.0", - "is-extendable": "^1.0.1" - }, - "dependencies": { - "is-extendable": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-1.0.1.tgz", - "integrity": "sha512-arnXMxT1hhoKo9k1LZdmlNyJdDDfy2v0fXjFlmok4+i8ul/6WlbVge9bhM74OpNPQPMGUToDtz+KXa1PneJxOA==", - "dev": true, - "requires": { - "is-plain-object": "^2.0.4" - } - }, - "is-plain-object": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-2.0.4.tgz", - "integrity": "sha512-h5PpgXkWitc38BBMYawTYMWJHFZJVnBquFE57xFpjB8pJFiF6gZ+bU+WyI/yqXiFR5mdLsgYNaPe8uao6Uv9Og==", - "dev": true, - "requires": { - "isobject": "^3.0.1" - } - } - } - }, "external-editor": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/external-editor/-/external-editor-3.1.0.tgz", @@ -22282,77 +20992,6 @@ "tmp": "^0.0.33" } }, - "extglob": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/extglob/-/extglob-2.0.4.tgz", - "integrity": "sha512-Nmb6QXkELsuBr24CJSkilo6UHHgbekK5UiZgfE6UHD3Eb27YC6oD+bhcT+tJ6cl8dmsgdQxnWlcry8ksBIBLpw==", - "dev": true, - "requires": { - "array-unique": "^0.3.2", - "define-property": "^1.0.0", - "expand-brackets": "^2.1.4", - "extend-shallow": "^2.0.1", - "fragment-cache": "^0.2.1", - "regex-not": "^1.0.0", - "snapdragon": "^0.8.1", - "to-regex": "^3.0.1" - }, - "dependencies": { - "define-property": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/define-property/-/define-property-1.0.0.tgz", - "integrity": "sha1-dp66rz9KY6rTr56NMEybvnm/sOY=", - "dev": true, - "requires": { - "is-descriptor": "^1.0.0" - } - }, - "extend-shallow": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", - "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", - "dev": true, - "requires": { - "is-extendable": "^0.1.0" - } - }, - "is-accessor-descriptor": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz", - "integrity": "sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ==", - "dev": true, - "requires": { - "kind-of": "^6.0.0" - } - }, - "is-data-descriptor": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz", - "integrity": "sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ==", - "dev": true, - "requires": { - "kind-of": "^6.0.0" - } - }, - "is-descriptor": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.2.tgz", - "integrity": "sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg==", - "dev": true, - "requires": { - "is-accessor-descriptor": "^1.0.0", - "is-data-descriptor": "^1.0.0", - "kind-of": "^6.0.2" - } - }, - "kind-of": { - "version": "6.0.3", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.3.tgz", - "integrity": "sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==", - "dev": true - } - } - }, "extsprintf": { "version": "1.3.0", "resolved": "https://registry.npmjs.org/extsprintf/-/extsprintf-1.3.0.tgz", @@ -22397,6 +21036,24 @@ "deepmerge": "^4.2.2", "rfdc": "^1.2.0", "string-similarity": "^4.0.1" + }, + "dependencies": { + "ajv": { + "version": "6.12.6", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", + "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", + "requires": { + "fast-deep-equal": "^3.1.1", + "fast-json-stable-stringify": "^2.0.0", + "json-schema-traverse": "^0.4.1", + "uri-js": "^4.2.2" + } + }, + "json-schema-traverse": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", + "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==" + } } }, "fast-levenshtein": { @@ -22405,6 +21062,15 @@ "integrity": "sha1-PYpcZog6FqMMqGQ+hR8Zuqd5eRc=", "dev": true }, + "fast-querystring": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/fast-querystring/-/fast-querystring-1.0.0.tgz", + "integrity": "sha512-3LQi62IhQoDlmt4ULCYmh17vRO2EtS7hTSsG4WwoKWgV7GLMKBOecEh+aiavASnLx8I2y89OD33AGLo0ccRhzA==", + "dev": true, + "requires": { + "fast-decode-uri-component": "^1.0.1" + } + }, "fast-redact": { "version": "3.1.1", "resolved": "https://registry.npmjs.org/fast-redact/-/fast-redact-3.1.1.tgz", @@ -22424,66 +21090,57 @@ } }, "fast-uri": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/fast-uri/-/fast-uri-1.0.1.tgz", - "integrity": "sha512-dbO/+ny6lX4tt7pvfPMTiHfQVR5igYKFa5BJ2a21TWuOgd2ySp5DYswsEGuMcJZLL3/eJ/MQJ5KNcXyNUvDt8w==", + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/fast-uri/-/fast-uri-2.1.0.tgz", + "integrity": "sha512-qKRta6N7BWEFVlyonVY/V+BMLgFqktCUV0QjT259ekAIlbVrMaFnFLxJ4s/JPl4tou56S1BzPufI60bLe29fHA==", "dev": true }, "fastify": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/fastify/-/fastify-4.2.0.tgz", - "integrity": "sha512-0QXEp+8ceKc0fwVakeBLM/1Ss/+fc7a3auuygT+1GjbSAgHfwqxSucUuu0rYjziu32UgEZXfjItYN/a89HWKhw==", + "version": "4.11.0", + "resolved": "https://registry.npmjs.org/fastify/-/fastify-4.11.0.tgz", + "integrity": "sha512-JteZ8pjEqd+6n+azQnQfSJV8MUMxAmxbvC2Dx/Mybj039Lf/u3kda9Kq84uy/huCpqCzZoyHIZS5JFGF3wLztw==", "dev": true, "requires": { - "@fastify/ajv-compiler": "^3.1.0", + "@fastify/ajv-compiler": "^3.3.1", "@fastify/error": "^3.0.0", - "@fastify/fast-json-stringify-compiler": "^4.0.0", + "@fastify/fast-json-stringify-compiler": "^4.1.0", "abstract-logging": "^2.0.1", - "avvio": "^8.1.3", - "find-my-way": "^7.0.0", - "light-my-request": "^5.0.0", - "pino": "^8.0.0", + "avvio": "^8.2.0", + "content-type": "^1.0.4", + "find-my-way": "^7.3.0", + "light-my-request": "^5.6.1", + "pino": "^8.5.0", "process-warning": "^2.0.0", "proxy-addr": "^2.0.7", "rfdc": "^1.3.0", - "secure-json-parse": "^2.4.0", + "secure-json-parse": "^2.5.0", "semver": "^7.3.7", - "tiny-lru": "^8.0.2" + "tiny-lru": "^10.0.0" }, "dependencies": { - "find-my-way": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/find-my-way/-/find-my-way-7.0.0.tgz", - "integrity": "sha512-NHVohYPYRXgj6jxXVRwm4iMQjA2ggJpyewHz7Nq7hvBnHoYJJIyHuxNzs8QLPTLQfoqxZzls2g6Zm79XMbhXjA==", - "dev": true, - "requires": { - "fast-deep-equal": "^3.1.3", - "safe-regex2": "^2.0.0" - } - }, "pino": { - "version": "8.0.0", - "resolved": "https://registry.npmjs.org/pino/-/pino-8.0.0.tgz", - "integrity": "sha512-EvZh9ZUoLGkrhqhoF9UBxw2/ZiAhXHUKlGrI4WUT/wLu0sfu8Wr3NJaZ6lxcy/S51W0PMSon5KE7ujPAhc/G6g==", + "version": "8.6.1", + "resolved": "https://registry.npmjs.org/pino/-/pino-8.6.1.tgz", + "integrity": "sha512-fi+V2K98eMZjQ/uEHHSiMALNrz7HaFdKNYuyA3ZUrbH0f1e8sPFDmeRGzg7ZH2q4QDxGnJPOswmqlEaTAZeDPA==", "dev": true, "requires": { "atomic-sleep": "^1.0.0", - "fast-redact": "^3.0.0", - "on-exit-leak-free": "^1.0.0", - "pino-abstract-transport": "v0.5.0", - "pino-std-serializers": "^5.0.0", + "fast-redact": "^3.1.1", + "on-exit-leak-free": "^2.1.0", + "pino-abstract-transport": "v1.0.0", + "pino-std-serializers": "^6.0.0", "process-warning": "^2.0.0", "quick-format-unescaped": "^4.0.3", - "real-require": "^0.1.0", - "safe-stable-stringify": "^2.1.0", - "sonic-boom": "^3.0.0", - "thread-stream": "^1.0.0" + "real-require": "^0.2.0", + "safe-stable-stringify": "^2.3.1", + "sonic-boom": "^3.1.0", + "thread-stream": "^2.0.0" } }, "pino-std-serializers": { - "version": "5.3.0", - "resolved": "https://registry.npmjs.org/pino-std-serializers/-/pino-std-serializers-5.3.0.tgz", - "integrity": "sha512-Jm6EfiTTWUMxiyi07RUPpD9KLntgqc4P9lriWZG5TpabeJYxG/zkI5aUdTpUdgfS1mj3YD+0n3BINbQTz9r0Ig==", + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/pino-std-serializers/-/pino-std-serializers-6.0.0.tgz", + "integrity": "sha512-mMMOwSKrmyl+Y12Ri2xhH1lbzQxwwpuru9VjyJpgFIH4asSj88F2csdMwN6+M5g1Ll4rmsYghHLQJw81tgZ7LQ==", "dev": true }, "process-warning": { @@ -22502,9 +21159,9 @@ } }, "sonic-boom": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/sonic-boom/-/sonic-boom-3.0.0.tgz", - "integrity": "sha512-p5DiZOZHbJ2ZO5MADczp5qrfOd3W5Vr2vHxfCpe7G4AzPwVOweIjbfgku8wSQUuk+Y5Yuo8W7JqRe6XKmKistg==", + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/sonic-boom/-/sonic-boom-3.2.0.tgz", + "integrity": "sha512-SbbZ+Kqj/XIunvIAgUZRlqd6CGQYq71tRRbXR92Za8J/R3Yh4Av+TWENiSiEgnlwckYLyP0YZQWVfyNC0dzLaA==", "dev": true, "requires": { "atomic-sleep": "^1.0.0" @@ -22513,9 +21170,9 @@ } }, "fastify-plugin": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/fastify-plugin/-/fastify-plugin-3.0.1.tgz", - "integrity": "sha512-qKcDXmuZadJqdTm6vlCqioEbyewF60b/0LOFCcYN1B6BIZGlYJumWWOYs70SFYLDAH4YqdE1cxH/RKMG7rFxgA==", + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/fastify-plugin/-/fastify-plugin-4.2.1.tgz", + "integrity": "sha512-dlGKiwLzRBKkEf5J5ho0uAD/Jdv8GQVUbriB3tAX3ehRUXE4gTV3lRd5inEg9li1aLzb0EGj8y2K4/8g1TN06g==", "dev": true }, "fastq": { @@ -22629,14 +21286,14 @@ } }, "find-my-way": { - "version": "2.2.5", - "resolved": "https://registry.npmjs.org/find-my-way/-/find-my-way-2.2.5.tgz", - "integrity": "sha512-GjRZZlGcGmTh9t+6Xrj5K0YprpoAFCAiCPgmAH9Kb09O4oX6hYuckDfnDipYj+Q7B1GtYWSzDI5HEecNYscLQg==", + "version": "7.3.1", + "resolved": "https://registry.npmjs.org/find-my-way/-/find-my-way-7.3.1.tgz", + "integrity": "sha512-kGvM08SOkqvheLcuQ8GW9t/H901Qb9rZEbcNWbXopzy4jDRoaJpJoObPSKf4MnQLZ20ZTp7rL5MpF6rf+pqmyg==", "dev": true, "requires": { - "fast-decode-uri-component": "^1.0.0", - "safe-regex2": "^2.0.0", - "semver-store": "^0.3.0" + "fast-deep-equal": "^3.1.3", + "fast-querystring": "^1.0.0", + "safe-regex2": "^2.0.0" } }, "find-up": { @@ -22649,159 +21306,6 @@ "path-exists": "^4.0.0" } }, - "findup-sync": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/findup-sync/-/findup-sync-3.0.0.tgz", - "integrity": "sha512-YbffarhcicEhOrm4CtrwdKBdCuz576RLdhJDsIfvNtxUuhdRet1qZcsMjqbePtAseKdAnDyM/IyXbu7PRPRLYg==", - "dev": true, - "requires": { - "detect-file": "^1.0.0", - "is-glob": "^4.0.0", - "micromatch": "^3.0.4", - "resolve-dir": "^1.0.1" - }, - "dependencies": { - "braces": { - "version": "2.3.2", - "resolved": "https://registry.npmjs.org/braces/-/braces-2.3.2.tgz", - "integrity": "sha512-aNdbnj9P8PjdXU4ybaWLK2IF3jc/EoDYbC7AazW6to3TRsfXxscC9UXOB5iDiEQrkyIbWp2SLQda4+QAa7nc3w==", - "dev": true, - "requires": { - "arr-flatten": "^1.1.0", - "array-unique": "^0.3.2", - "extend-shallow": "^2.0.1", - "fill-range": "^4.0.0", - "isobject": "^3.0.1", - "repeat-element": "^1.1.2", - "snapdragon": "^0.8.1", - "snapdragon-node": "^2.0.1", - "split-string": "^3.0.2", - "to-regex": "^3.0.1" - }, - "dependencies": { - "extend-shallow": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", - "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", - "dev": true, - "requires": { - "is-extendable": "^0.1.0" - } - } - } - }, - "fill-range": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-4.0.0.tgz", - "integrity": "sha1-1USBHUKPmOsGpj3EAtJAPDKMOPc=", - "dev": true, - "requires": { - "extend-shallow": "^2.0.1", - "is-number": "^3.0.0", - "repeat-string": "^1.6.1", - "to-regex-range": "^2.1.0" - }, - "dependencies": { - "extend-shallow": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", - "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", - "dev": true, - "requires": { - "is-extendable": "^0.1.0" - } - } - } - }, - "is-number": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/is-number/-/is-number-3.0.0.tgz", - "integrity": "sha1-JP1iAaR4LPUFYcgQJ2r8fRLXEZU=", - "dev": true, - "requires": { - "kind-of": "^3.0.2" - }, - "dependencies": { - "kind-of": { - "version": "3.2.2", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", - "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", - "dev": true, - "requires": { - "is-buffer": "^1.1.5" - } - } - } - }, - "kind-of": { - "version": "6.0.3", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.3.tgz", - "integrity": "sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==", - "dev": true - }, - "micromatch": { - "version": "3.1.10", - "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-3.1.10.tgz", - "integrity": "sha512-MWikgl9n9M3w+bpsY3He8L+w9eF9338xRl8IAO5viDizwSzziFEyUzo2xrrloB64ADbTf8uA8vRqqttDTOmccg==", - "dev": true, - "requires": { - "arr-diff": "^4.0.0", - "array-unique": "^0.3.2", - "braces": "^2.3.1", - "define-property": "^2.0.2", - "extend-shallow": "^3.0.2", - "extglob": "^2.0.4", - "fragment-cache": "^0.2.1", - "kind-of": "^6.0.2", - "nanomatch": "^1.2.9", - "object.pick": "^1.3.0", - "regex-not": "^1.0.0", - "snapdragon": "^0.8.1", - "to-regex": "^3.0.2" - } - }, - "to-regex-range": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-2.1.1.tgz", - "integrity": "sha1-fIDBe53+vlmeJzZ+DU3VWQFB2zg=", - "dev": true, - "requires": { - "is-number": "^3.0.0", - "repeat-string": "^1.6.1" - } - } - } - }, - "fined": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/fined/-/fined-1.2.0.tgz", - "integrity": "sha512-ZYDqPLGxDkDhDZBjZBb+oD1+j0rA4E0pXY50eplAAOPg2N/gUBSSk5IM1/QhPfyVo19lJ+CvXpqfvk+b2p/8Ng==", - "dev": true, - "requires": { - "expand-tilde": "^2.0.2", - "is-plain-object": "^2.0.3", - "object.defaults": "^1.1.0", - "object.pick": "^1.2.0", - "parse-filepath": "^1.0.1" - }, - "dependencies": { - "is-plain-object": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-2.0.4.tgz", - "integrity": "sha512-h5PpgXkWitc38BBMYawTYMWJHFZJVnBquFE57xFpjB8pJFiF6gZ+bU+WyI/yqXiFR5mdLsgYNaPe8uao6Uv9Og==", - "dev": true, - "requires": { - "isobject": "^3.0.1" - } - } - } - }, - "flagged-respawn": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/flagged-respawn/-/flagged-respawn-1.0.1.tgz", - "integrity": "sha512-lNaHNVymajmk0OJMBn8fVUAU1BtDeKIqKoVhk4xAALB57aALg6b4W0MfJ/cUE0g9YBXy5XhSlPIpYIJ7HaY/3Q==", - "dev": true - }, "flat-cache": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-2.0.1.tgz", @@ -22856,21 +21360,6 @@ "is-callable": "^1.1.3" } }, - "for-in": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/for-in/-/for-in-1.0.2.tgz", - "integrity": "sha1-gQaNKVqBQuwKxybG4iAMMPttXoA=", - "dev": true - }, - "for-own": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/for-own/-/for-own-1.0.0.tgz", - "integrity": "sha1-xjMy9BXO3EsE2/5wz4NklMU8tEs=", - "dev": true, - "requires": { - "for-in": "^1.0.1" - } - }, "foreach": { "version": "2.0.5", "resolved": "https://registry.npmjs.org/foreach/-/foreach-2.0.5.tgz", @@ -22964,15 +21453,6 @@ "resolved": "https://registry.npmjs.org/forwarded-parse/-/forwarded-parse-2.1.2.tgz", "integrity": "sha512-alTFZZQDKMporBH77856pXgzhEzaUVmLCDk+egLgIgHst3Tpndzz8MnKe+GzRJRfvVdn69HhpW7cmXzvtLvJAw==" }, - "fragment-cache": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/fragment-cache/-/fragment-cache-0.2.1.tgz", - "integrity": "sha1-QpD60n8T6Jvn8zeZxrxaCr//DRk=", - "dev": true, - "requires": { - "map-cache": "^0.2.2" - } - }, "fresh": { "version": "0.5.2", "resolved": "https://registry.npmjs.org/fresh/-/fresh-0.5.2.tgz", @@ -23041,9 +21521,9 @@ } }, "generic-pool": { - "version": "3.8.2", - "resolved": "https://registry.npmjs.org/generic-pool/-/generic-pool-3.8.2.tgz", - "integrity": "sha512-nGToKy6p3PAbYQ7p1UlWl6vSPwfwU6TMSWK7TTu+WUY4ZjyZQGniGGt2oNVvyNSpyZYSB43zMXVLcBm08MTMkg==", + "version": "3.9.0", + "resolved": "https://registry.npmjs.org/generic-pool/-/generic-pool-3.9.0.tgz", + "integrity": "sha512-hymDOu5B53XvN4QT9dBmZxPX4CWhBPPLguTZ9MMFeFa/Kg0xWVfylOVNlJji/E7yTZWFd/q9GO5TxDLq156D7g==", "dev": true }, "gensync": { @@ -23098,12 +21578,6 @@ "get-intrinsic": "^1.1.1" } }, - "get-value": { - "version": "2.0.6", - "resolved": "https://registry.npmjs.org/get-value/-/get-value-2.0.6.tgz", - "integrity": "sha1-3BXKHGcjh8p2vTesCjlbogQqLCg=", - "dev": true - }, "getopts": { "version": "2.2.5", "resolved": "https://registry.npmjs.org/getopts/-/getopts-2.2.5.tgz", @@ -23120,15 +21594,15 @@ } }, "glob": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.0.tgz", - "integrity": "sha512-lmLf6gtyrPq8tTjSmrO94wBeQbFR3HbLHbuyD69wuyQkImp2hWqMGB47OX65FBkPffO641IP9jWa1z4ivqG26Q==", + "version": "7.2.3", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", + "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", "dev": true, "requires": { "fs.realpath": "^1.0.0", "inflight": "^1.0.4", "inherits": "2", - "minimatch": "^3.0.4", + "minimatch": "^3.1.1", "once": "^1.3.0", "path-is-absolute": "^1.0.0" } @@ -23142,30 +21616,6 @@ "is-glob": "^4.0.1" } }, - "global-modules": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/global-modules/-/global-modules-1.0.0.tgz", - "integrity": "sha512-sKzpEkf11GpOFuw0Zzjzmt4B4UZwjOcG757PPvrfhxcLFbq0wpsgpOqxpxtxFiCG4DtG93M6XRVbF2oGdev7bg==", - "dev": true, - "requires": { - "global-prefix": "^1.0.1", - "is-windows": "^1.0.1", - "resolve-dir": "^1.0.0" - } - }, - "global-prefix": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/global-prefix/-/global-prefix-1.0.2.tgz", - "integrity": "sha1-2/dDxsFJklk8ZVVoy2btMsASLr4=", - "dev": true, - "requires": { - "expand-tilde": "^2.0.2", - "homedir-polyfill": "^1.0.1", - "ini": "^1.3.4", - "is-windows": "^1.0.1", - "which": "^1.2.14" - } - }, "globals": { "version": "11.12.0", "resolved": "https://registry.npmjs.org/globals/-/globals-11.12.0.tgz", @@ -23204,9 +21654,9 @@ } }, "got": { - "version": "11.8.5", - "resolved": "https://registry.npmjs.org/got/-/got-11.8.5.tgz", - "integrity": "sha512-o0Je4NvQObAuZPHLFoRSkdG2lTgtcynqymzg2Vupdx6PorhaT5MCbIyXG6d4D94kk8ZG57QeosgdiqfJWhEhlQ==", + "version": "11.8.6", + "resolved": "https://registry.npmjs.org/got/-/got-11.8.6.tgz", + "integrity": "sha512-6tfZ91bOr7bOXnK7PRDCGBLa1H4U080YHNaAQ2KsMGlLEzRbk44nsZF2E1IeRc3vtJHPVbKCYgdFbaGO2ljd8g==", "dev": true, "requires": { "@sindresorhus/is": "^4.0.0", @@ -23284,6 +21734,26 @@ "requires": { "ajv": "^6.12.3", "har-schema": "^2.0.0" + }, + "dependencies": { + "ajv": { + "version": "6.12.6", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", + "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", + "dev": true, + "requires": { + "fast-deep-equal": "^3.1.1", + "fast-json-stable-stringify": "^2.0.0", + "json-schema-traverse": "^0.4.1", + "uri-js": "^4.2.2" + } + }, + "json-schema-traverse": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", + "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", + "dev": true + } } }, "has": { @@ -23353,58 +21823,6 @@ "has-symbols": "^1.0.2" } }, - "has-value": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/has-value/-/has-value-1.0.0.tgz", - "integrity": "sha1-GLKB2lhbHFxR3vJMkw7SmgvmsXc=", - "dev": true, - "requires": { - "get-value": "^2.0.6", - "has-values": "^1.0.0", - "isobject": "^3.0.0" - } - }, - "has-values": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/has-values/-/has-values-1.0.0.tgz", - "integrity": "sha1-lbC2P+whRmGab+V/51Yo1aOe/k8=", - "dev": true, - "requires": { - "is-number": "^3.0.0", - "kind-of": "^4.0.0" - }, - "dependencies": { - "is-number": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/is-number/-/is-number-3.0.0.tgz", - "integrity": "sha1-JP1iAaR4LPUFYcgQJ2r8fRLXEZU=", - "dev": true, - "requires": { - "kind-of": "^3.0.2" - }, - "dependencies": { - "kind-of": { - "version": "3.2.2", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", - "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", - "dev": true, - "requires": { - "is-buffer": "^1.1.5" - } - } - } - }, - "kind-of": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-4.0.0.tgz", - "integrity": "sha1-IIE989cSkosgc3hpGkUGb65y3Vc=", - "dev": true, - "requires": { - "is-buffer": "^1.1.5" - } - } - } - }, "hasha": { "version": "5.2.2", "resolved": "https://registry.npmjs.org/hasha/-/hasha-5.2.2.tgz", @@ -23425,15 +21843,6 @@ "simple-lru-cache": "0.0.x" } }, - "homedir-polyfill": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/homedir-polyfill/-/homedir-polyfill-1.0.3.tgz", - "integrity": "sha512-eSmmWE5bZTK2Nou4g0AI3zZ9rswp7GRKoKXS1BLUkvPviOqs4YTN1djQIqrXy9k5gEtdLPy86JjRwsNM9tnDcA==", - "dev": true, - "requires": { - "parse-passwd": "^1.0.0" - } - }, "hosted-git-info": { "version": "2.8.9", "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-2.8.9.tgz", @@ -23650,12 +22059,6 @@ "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==" }, - "ini": { - "version": "1.3.8", - "resolved": "https://registry.npmjs.org/ini/-/ini-1.3.8.tgz", - "integrity": "sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew==", - "dev": true - }, "inquirer": { "version": "7.3.3", "resolved": "https://registry.npmjs.org/inquirer/-/inquirer-7.3.3.tgz", @@ -23745,9 +22148,9 @@ "dev": true }, "ioredis": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/ioredis/-/ioredis-5.1.0.tgz", - "integrity": "sha512-HYHnvwxFwefeUBj0hZFejLvd8Q/YNAfnZlZG/hSRxkRhXMs1H8soMEVccHd1WlLrKkynorXBsAtqDGskOdAfVQ==", + "version": "5.2.3", + "resolved": "https://registry.npmjs.org/ioredis/-/ioredis-5.2.3.tgz", + "integrity": "sha512-gQNcMF23/NpvjCaa1b5YycUyQJ9rBNH2xP94LWinNpodMWVUPP5Ai/xXANn/SM7gfIvI62B5CCvZxhg5pOgyMw==", "dev": true, "requires": { "@ioredis/commands": "^1.1.1", @@ -23770,9 +22173,9 @@ } }, "ip": { - "version": "1.1.5", - "resolved": "https://registry.npmjs.org/ip/-/ip-1.1.5.tgz", - "integrity": "sha1-vd7XARQpCCjAoDnnLvJfWq7ENUo=", + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ip/-/ip-2.0.0.tgz", + "integrity": "sha512-WKa+XuLG1A1R0UWhl2+1XQSi+fZWMsYKffMZTTYsiZaUD8k2yDAj5atimTUD2TZkyCkNEeYE5NhFZmupOGtjYQ==", "dev": true }, "ipaddr.js": { @@ -23781,25 +22184,6 @@ "integrity": "sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g==", "dev": true }, - "is-absolute": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-absolute/-/is-absolute-1.0.0.tgz", - "integrity": "sha512-dOWoqflvcydARa360Gvv18DZ/gRuHKi2NU/wU5X1ZFzdYfH29nkiNZsF3mp4OJ3H4yo9Mx8A/uAGNzpzPN3yBA==", - "dev": true, - "requires": { - "is-relative": "^1.0.0", - "is-windows": "^1.0.1" - } - }, - "is-accessor-descriptor": { - "version": "0.1.6", - "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-0.1.6.tgz", - "integrity": "sha1-qeEss66Nh2cn7u84Q/igiXtcmNY=", - "dev": true, - "requires": { - "kind-of": "^3.0.2" - } - }, "is-arguments": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/is-arguments/-/is-arguments-1.1.1.tgz", @@ -23837,12 +22221,6 @@ "has-tostringtag": "^1.0.0" } }, - "is-buffer": { - "version": "1.1.6", - "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-1.1.6.tgz", - "integrity": "sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w==", - "dev": true - }, "is-callable": { "version": "1.2.4", "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.2.4.tgz", @@ -23858,22 +22236,13 @@ } }, "is-core-module": { - "version": "2.8.1", - "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.8.1.tgz", - "integrity": "sha512-SdNCUs284hr40hFTFP6l0IfZ/RSrMXF3qgoRHd3/79unUTvrFO/JoXwkGm+5J/Oe3E/b5GsnG330uUNgRpu1PA==", + "version": "2.10.0", + "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.10.0.tgz", + "integrity": "sha512-Erxj2n/LDAZ7H8WNJXd9tw38GYM3dv8rk8Zcs+jJuxYTW7sozH+SS8NtrSjVL1/vpLvWi1hxy96IzjJ3EHTJJg==", "requires": { "has": "^1.0.3" } }, - "is-data-descriptor": { - "version": "0.1.4", - "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-0.1.4.tgz", - "integrity": "sha1-C17mSDiOLIYCgueT8YVv7D8wG1Y=", - "dev": true, - "requires": { - "kind-of": "^3.0.2" - } - }, "is-date-object": { "version": "1.0.5", "resolved": "https://registry.npmjs.org/is-date-object/-/is-date-object-1.0.5.tgz", @@ -23882,25 +22251,6 @@ "has-tostringtag": "^1.0.0" } }, - "is-descriptor": { - "version": "0.1.6", - "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-0.1.6.tgz", - "integrity": "sha512-avDYr0SB3DwO9zsMov0gKCESFYqCnE4hq/4z3TdUlukEy5t9C0YRq7HLrsN52NAcqXKaepeCD0n+B0arnVG3Hg==", - "dev": true, - "requires": { - "is-accessor-descriptor": "^0.1.6", - "is-data-descriptor": "^0.1.4", - "kind-of": "^5.0.0" - }, - "dependencies": { - "kind-of": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-5.1.0.tgz", - "integrity": "sha512-NGEErnH6F2vUuXDh+OlbcKW7/wOcfdRHaZ7VWtqCztfHri/++YKmP51OdWeGPuqCOba6kk2OTe5d02VmTB80Pw==", - "dev": true - } - } - }, "is-docker": { "version": "2.2.1", "resolved": "https://registry.npmjs.org/is-docker/-/is-docker-2.2.1.tgz", @@ -23917,12 +22267,6 @@ "object-assign": "^4.1.1" } }, - "is-extendable": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-0.1.1.tgz", - "integrity": "sha1-YrEQ4omkcUGOPsNqYX1HLjAd/Ik=", - "dev": true - }, "is-extglob": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", @@ -24180,12 +22524,6 @@ "integrity": "sha1-6PvzdNxVb/iUehDcsFctYz8s+hA=", "dev": true }, - "isobject": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz", - "integrity": "sha1-TkMekrEalzFjaqH5yNHMvP2reN8=", - "dev": true - }, "isstream": { "version": "0.1.2", "resolved": "https://registry.npmjs.org/isstream/-/isstream-0.1.2.tgz", @@ -24391,9 +22729,9 @@ "dev": true }, "joi": { - "version": "17.6.0", - "resolved": "https://registry.npmjs.org/joi/-/joi-17.6.0.tgz", - "integrity": "sha512-OX5dG6DTbcr/kbMFj0KGYxuew69HPcAE3K/sZpEV2nP6e/j/C0HV+HNiBPCASxdx5T7DMoa0s8UeHWMnb6n2zw==", + "version": "17.7.0", + "resolved": "https://registry.npmjs.org/joi/-/joi-17.7.0.tgz", + "integrity": "sha512-1/ugc8djfn93rTE3WRKdCzGGt/EtiYKxITMO4Wiv6q5JL1gl9ePt4kBsl1S499nbosspfctIQTpYIhSmHA3WAg==", "dev": true, "requires": { "@hapi/hoek": "^9.0.0", @@ -24403,6 +22741,12 @@ "@sideway/pinpoint": "^2.0.0" } }, + "js-md4": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/js-md4/-/js-md4-0.3.2.tgz", + "integrity": "sha512-/GDnfQYsltsjRswQhN9fhv3EMw2sCpUdrdxyWDOUK7eyD++r3gRhzgiQgc/x4MAv2i1iuQ4lxO5mvqM3vj4bwA==", + "dev": true + }, "js-stringify": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/js-stringify/-/js-stringify-1.0.2.tgz", @@ -24416,19 +22760,26 @@ "dev": true }, "js-yaml": { - "version": "3.14.1", - "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.14.1.tgz", - "integrity": "sha512-okMH7OXXJ7YrN9Ok3/SXrnu4iX9yOk+25nqX4imS2npuvTYDmo/QEZoqwZkYaIDk3jVvBOTOIEgEhaLOynBS9g==", + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", + "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==", "dev": true, "requires": { - "argparse": "^1.0.7", - "esprima": "^4.0.0" + "argparse": "^2.0.1" + }, + "dependencies": { + "argparse": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", + "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", + "dev": true + } } }, "jsbi": { - "version": "3.2.5", - "resolved": "https://registry.npmjs.org/jsbi/-/jsbi-3.2.5.tgz", - "integrity": "sha512-aBE4n43IPvjaddScbvWRA2YlTzKEynHzu7MqOyTipdHucf/VxS63ViCjxYRg86M8Rxwbt/GfzHl1kKERkt45fQ==", + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/jsbi/-/jsbi-4.3.0.tgz", + "integrity": "sha512-SnZNcinB4RIcnEyZqFPdGPVgrg2AcnykiBy0sHVJQKHYeaLUvi3Exj+iaPpLnFVkDPZIV4U0yvgC9/R4uEAZ9g==", "dev": true }, "jsbn": { @@ -24462,9 +22813,10 @@ "dev": true }, "json-schema-traverse": { - "version": "0.4.1", - "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", - "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==" + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", + "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==", + "dev": true }, "json-stable-stringify-without-jsonify": { "version": "1.0.1", @@ -24479,27 +22831,21 @@ "dev": true }, "json5": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.1.tgz", - "integrity": "sha512-1hqLFMSrGHRHxav9q9gNjJ5EXznIxGVO09xQRrwplcS8qs28pZ8s8hupZAmqDwZUmVZ2Qb2jnyPOWcDH8m8dlA==", + "version": "2.2.3", + "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.3.tgz", + "integrity": "sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==", "dev": true }, "jsonwebtoken": { - "version": "8.5.1", - "resolved": "https://registry.npmjs.org/jsonwebtoken/-/jsonwebtoken-8.5.1.tgz", - "integrity": "sha512-XjwVfRS6jTMsqYs0EsuJ4LGxXV14zQybNd4L2r0UvbVnSF9Af8x7p5MzbJ90Ioz/9TI41/hTCvznF/loiSzn8w==", + "version": "9.0.0", + "resolved": "https://registry.npmjs.org/jsonwebtoken/-/jsonwebtoken-9.0.0.tgz", + "integrity": "sha512-tuGfYXxkQGDPnLJ7SibiQgVgeDgfbPq2k2ICcbgqW8WxWLBAxKQM/ZCu/IT8SOSwmaYl4dpTFCW5xZv7YbbWUw==", "dev": true, "requires": { "jws": "^3.2.2", - "lodash.includes": "^4.3.0", - "lodash.isboolean": "^3.0.3", - "lodash.isinteger": "^4.0.4", - "lodash.isnumber": "^3.0.3", - "lodash.isplainobject": "^4.0.6", - "lodash.isstring": "^4.0.1", - "lodash.once": "^4.0.0", + "lodash": "^4.17.21", "ms": "^2.1.1", - "semver": "^5.6.0" + "semver": "^7.3.8" }, "dependencies": { "jwa": { @@ -24524,10 +22870,13 @@ } }, "semver": { - "version": "5.7.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", - "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==", - "dev": true + "version": "7.3.8", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.8.tgz", + "integrity": "sha512-NB1ctGL5rlHrPJtFDVIVzTyQylMLu9N9VICA6HSFJo8MCGVTMW6gfpicwKmmK/dAjTOrqu5l63JJOpDSrAis3A==", + "dev": true, + "requires": { + "lru-cache": "^6.0.0" + } } } }, @@ -24583,56 +22932,54 @@ "json-buffer": "3.0.1" } }, - "kind-of": { - "version": "3.2.2", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", - "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", - "dev": true, - "requires": { - "is-buffer": "^1.1.5" - } - }, "knex": { - "version": "0.21.21", - "resolved": "https://registry.npmjs.org/knex/-/knex-0.21.21.tgz", - "integrity": "sha512-cjw5qO1EzVKjbywcVa61IQJMLt7PfYBRI/2NwCA/B9beXgbw652wDNLz+JM+UKKNsfwprq0ugYqBYc9q4JN36A==", + "version": "0.95.15", + "resolved": "https://registry.npmjs.org/knex/-/knex-0.95.15.tgz", + "integrity": "sha512-Loq6WgHaWlmL2bfZGWPsy4l8xw4pOE+tmLGkPG0auBppxpI0UcK+GYCycJcqz9W54f2LiGewkCVLBm3Wq4ur/w==", "dev": true, "requires": { - "colorette": "1.2.1", - "commander": "^6.2.0", - "debug": "4.3.1", + "colorette": "2.0.16", + "commander": "^7.1.0", + "debug": "4.3.2", + "escalade": "^3.1.1", "esm": "^3.2.25", "getopts": "2.2.5", "interpret": "^2.2.0", - "liftoff": "3.1.0", - "lodash": "^4.17.20", - "pg-connection-string": "2.4.0", + "lodash": "^4.17.21", + "pg-connection-string": "2.5.0", + "rechoir": "0.7.0", + "resolve-from": "^5.0.0", "tarn": "^3.0.1", - "tildify": "2.0.0", - "v8flags": "^3.2.0" + "tildify": "2.0.0" }, "dependencies": { "commander": { - "version": "6.2.1", - "resolved": "https://registry.npmjs.org/commander/-/commander-6.2.1.tgz", - "integrity": "sha512-U7VdrJFnJgo4xjrHpTzu0yrHPGImdsmD95ZlgYSEajAn2JKzDhDTPG9kBTefmObL2w/ngeZnilk+OV9CG3d7UA==", + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/commander/-/commander-7.2.0.tgz", + "integrity": "sha512-QrWXB+ZQSVPmIWIhtEO9H+gwHaMGYiF5ChvoJ+K9ZGHG/sVsa6yiesAD1GC/x46sET00Xlwo1u49RVVVzvcSkw==", "dev": true }, "debug": { - "version": "4.3.1", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.1.tgz", - "integrity": "sha512-doEwdvm4PCeK4K3RQN2ZC2BYUBaxwLARCqZmMjtF8a51J2Rb0xpVloFRnCODwqjpwnAoao4pelN8l3RJdv3gRQ==", + "version": "4.3.2", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.2.tgz", + "integrity": "sha512-mOp8wKcvj7XxC78zLgw/ZA+6TSgkoE2C/ienthhRD298T7UNwAg9diBpLRxC0mOezLl4B0xV7M0cCO6P/O0Xhw==", "dev": true, "requires": { "ms": "2.1.2" } + }, + "resolve-from": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-5.0.0.tgz", + "integrity": "sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==", + "dev": true } } }, "koa": { - "version": "2.13.4", - "resolved": "https://registry.npmjs.org/koa/-/koa-2.13.4.tgz", - "integrity": "sha512-43zkIKubNbnrULWlHdN5h1g3SEKXOEzoAlRsHOTFpnlDu8JlAOZSMJBLULusuXRequboiwJcj5vtYXKB3k7+2g==", + "version": "2.14.1", + "resolved": "https://registry.npmjs.org/koa/-/koa-2.14.1.tgz", + "integrity": "sha512-USJFyZgi2l0wDgqkfD27gL4YGno7TfUkcmOe6UOLFOVuN+J7FwnNu4Dydl4CUQzraM1lBAiGed0M9OVJoT0Kqw==", "dev": true, "requires": { "accepts": "^1.3.5", @@ -24695,16 +23042,42 @@ } }, "koa-router": { - "version": "9.4.0", - "resolved": "https://registry.npmjs.org/koa-router/-/koa-router-9.4.0.tgz", - "integrity": "sha512-RO/Y8XqSNM2J5vQeDaBI/7iRpL50C9QEudY4d3T4D1A2VMKLH0swmfjxDFPiIpVDLuNN6mVD9zBI1eFTHB6QaA==", + "version": "12.0.0", + "resolved": "https://registry.npmjs.org/koa-router/-/koa-router-12.0.0.tgz", + "integrity": "sha512-zGrdiXygGYW8WvrzeGsHZvKnHs4DzyGoqJ9a8iHlRkiwuEAOAPyI27//OlhoWdgFAEIM3qbUgr0KCuRaP/TCag==", "dev": true, "requires": { - "debug": "^4.1.1", - "http-errors": "^1.7.3", + "http-errors": "^2.0.0", "koa-compose": "^4.1.0", "methods": "^1.1.2", - "path-to-regexp": "^6.1.0" + "path-to-regexp": "^6.2.1" + }, + "dependencies": { + "depd": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz", + "integrity": "sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==", + "dev": true + }, + "http-errors": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-2.0.0.tgz", + "integrity": "sha512-FtwrG/euBzaEjYeRqOgly7G0qviiXoJWnvEH2Z1plBdXgbyjv34pHTSb9zoeHMyDy33+DWy5Wt9Wo+TURtOYSQ==", + "dev": true, + "requires": { + "depd": "2.0.0", + "inherits": "2.0.4", + "setprototypeof": "1.2.0", + "statuses": "2.0.1", + "toidentifier": "1.0.1" + } + }, + "statuses": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.1.tgz", + "integrity": "sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ==", + "dev": true + } } }, "kuler": { @@ -24714,20 +23087,20 @@ "dev": true }, "lambda-local": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/lambda-local/-/lambda-local-2.0.2.tgz", - "integrity": "sha512-sCE0U645QdmQOx5y028kZnmvbfho4NkdAjmJuA8KdwPQS8tz9sByz281WHyEAfcBfXci/9eQxNURuL996Q8ybw==", + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/lambda-local/-/lambda-local-2.0.3.tgz", + "integrity": "sha512-Vs55gujwdjhPL2VpXEXAWWwxiOYdnVPDsMgwOr9BqC0O1EoSXs1S8TKBmD/ySEnPVRiQfFlABcQgcykF1mkE8Q==", "dev": true, "requires": { - "commander": "^9.0.0", - "dotenv": "^16.0.0", - "winston": "^3.6.0" + "commander": "^9.4.0", + "dotenv": "^16.0.2", + "winston": "^3.8.2" }, "dependencies": { "commander": { - "version": "9.3.0", - "resolved": "https://registry.npmjs.org/commander/-/commander-9.3.0.tgz", - "integrity": "sha512-hv95iU5uXPbK83mjrJKuZyFM/LBAoCV/XhVGkS5Je6tl7sxr6A0ITMw5WoRV46/UaJ46Nllm3Xt7IaJhXTIkzw==", + "version": "9.4.1", + "resolved": "https://registry.npmjs.org/commander/-/commander-9.4.1.tgz", + "integrity": "sha512-5EEkTNyHNGFPD2H+c/dXXfQZYa/scCKasxWcXJaWnNJ99pnQN9Vnmqow+p+PlFPE63Q6mThaZws1T+HxfpgtPw==", "dev": true } } @@ -24742,61 +23115,21 @@ "type-check": "~0.3.2" } }, - "liftoff": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/liftoff/-/liftoff-3.1.0.tgz", - "integrity": "sha512-DlIPlJUkCV0Ips2zf2pJP0unEoT1kwYhiiPUGF3s/jtxTCjziNLoiVVh+jqWOWeFi6mmwQ5fNxvAUyPad4Dfog==", - "dev": true, - "requires": { - "extend": "^3.0.0", - "findup-sync": "^3.0.0", - "fined": "^1.0.1", - "flagged-respawn": "^1.0.0", - "is-plain-object": "^2.0.4", - "object.map": "^1.0.0", - "rechoir": "^0.6.2", - "resolve": "^1.1.7" - }, - "dependencies": { - "is-plain-object": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-2.0.4.tgz", - "integrity": "sha512-h5PpgXkWitc38BBMYawTYMWJHFZJVnBquFE57xFpjB8pJFiF6gZ+bU+WyI/yqXiFR5mdLsgYNaPe8uao6Uv9Og==", - "dev": true, - "requires": { - "isobject": "^3.0.1" - } - } - } - }, "light-my-request": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/light-my-request/-/light-my-request-5.0.0.tgz", - "integrity": "sha512-0OPHKV+uHgBOnRokzL1LqeMCnSAo5l/rZS7kyB6G1I8qxGCvhXpq1M6WK565Y9A5CSn50l3DVaHnJ5FCdpguZQ==", + "version": "5.6.1", + "resolved": "https://registry.npmjs.org/light-my-request/-/light-my-request-5.6.1.tgz", + "integrity": "sha512-sbJnC1UBRivi9L1kICr3CESb82pNiPNB3TvtdIrZZqW0Qh8uDXvoywMmWKZlihDcmw952CMICCzM+54LDf+E+g==", "dev": true, "requires": { - "ajv": "^8.1.0", "cookie": "^0.5.0", - "process-warning": "^1.0.0", + "process-warning": "^2.0.0", "set-cookie-parser": "^2.4.1" }, "dependencies": { - "ajv": { - "version": "8.11.0", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.11.0.tgz", - "integrity": "sha512-wGgprdCvMalC0BztXvitD2hC04YffAvtsUn93JbGXYLAtCUO4xd17mCCZQxUOItiBwZvJScWo8NIvQMQ71rdpg==", - "dev": true, - "requires": { - "fast-deep-equal": "^3.1.1", - "json-schema-traverse": "^1.0.0", - "require-from-string": "^2.0.2", - "uri-js": "^4.2.2" - } - }, - "json-schema-traverse": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", - "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==", + "process-warning": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/process-warning/-/process-warning-2.0.0.tgz", + "integrity": "sha512-+MmoAXoUX+VTHAlwns0h+kFUWFs/3FZy+ZuchkgjyOu3oioLAo2LB5aCfKPh2+P9O18i3m43tUEv3YqttSy0Ww==", "dev": true } } @@ -24819,7 +23152,7 @@ "lodash.debounce": { "version": "4.0.8", "resolved": "https://registry.npmjs.org/lodash.debounce/-/lodash.debounce-4.0.8.tgz", - "integrity": "sha1-gteb/zCmfEAF/9XiUVMArZyk168=", + "integrity": "sha512-FT1yDzDYEoYWhnSGnpE/4Kj1fLZkDFyqRb7fNt6FdYOSxlUWAtp42Eh6Wb0rGIv/m9Bgo7x4GhQbm5Ys4SG5ow==", "dev": true }, "lodash.defaults": { @@ -24846,12 +23179,6 @@ "integrity": "sha1-+wMJF/hqMTTlvJvsDWngAT3f7bI=", "dev": true }, - "lodash.includes": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/lodash.includes/-/lodash.includes-4.3.0.tgz", - "integrity": "sha1-YLuYqHy5I8aMoeUTJUgzFISfVT8=", - "dev": true - }, "lodash.intersection": { "version": "4.4.0", "resolved": "https://registry.npmjs.org/lodash.intersection/-/lodash.intersection-4.4.0.tgz", @@ -24864,48 +23191,18 @@ "integrity": "sha1-L1c9hcaiQon/AGY7SRwdM4/zRYo=", "dev": true }, - "lodash.isboolean": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/lodash.isboolean/-/lodash.isboolean-3.0.3.tgz", - "integrity": "sha1-bC4XHbKiV82WgC/UOwGyDV9YcPY=", - "dev": true - }, "lodash.isempty": { "version": "4.4.0", "resolved": "https://registry.npmjs.org/lodash.isempty/-/lodash.isempty-4.4.0.tgz", "integrity": "sha1-b4bL7di+TsmHvpqvM8loTbGzHn4=", "dev": true }, - "lodash.isinteger": { - "version": "4.0.4", - "resolved": "https://registry.npmjs.org/lodash.isinteger/-/lodash.isinteger-4.0.4.tgz", - "integrity": "sha1-YZwK89A/iwTDH1iChAt3sRzWg0M=", - "dev": true - }, - "lodash.isnumber": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/lodash.isnumber/-/lodash.isnumber-3.0.3.tgz", - "integrity": "sha1-POdoEMWSjQM1IwGsKHMX8RwLH/w=", - "dev": true - }, - "lodash.isplainobject": { - "version": "4.0.6", - "resolved": "https://registry.npmjs.org/lodash.isplainobject/-/lodash.isplainobject-4.0.6.tgz", - "integrity": "sha1-fFJqUtibRcRcxpC4gWO+BJf1UMs=", - "dev": true - }, "lodash.isstring": { "version": "4.0.1", "resolved": "https://registry.npmjs.org/lodash.isstring/-/lodash.isstring-4.0.1.tgz", "integrity": "sha1-1SfftUVuynzJu5XV2ur4i6VKVFE=", "dev": true }, - "lodash.once": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/lodash.once/-/lodash.once-4.1.1.tgz", - "integrity": "sha1-DdOXEhPHxW34gJd9UEyI+0cal6w=", - "dev": true - }, "lodash.sortby": { "version": "4.7.0", "resolved": "https://registry.npmjs.org/lodash.sortby/-/lodash.sortby-4.7.0.tgz", @@ -25042,38 +23339,6 @@ } } }, - "make-iterator": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/make-iterator/-/make-iterator-1.0.1.tgz", - "integrity": "sha512-pxiuXh0iVEq7VM7KMIhs5gxsfxCux2URptUQaXo4iZZJxBAzTPOLE2BumO5dbfVYq/hBJFBR/a1mFDmOx5AGmw==", - "dev": true, - "requires": { - "kind-of": "^6.0.2" - }, - "dependencies": { - "kind-of": { - "version": "6.0.3", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.3.tgz", - "integrity": "sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==", - "dev": true - } - } - }, - "map-cache": { - "version": "0.2.2", - "resolved": "https://registry.npmjs.org/map-cache/-/map-cache-0.2.2.tgz", - "integrity": "sha1-wyq9C9ZSXZsFFkW7TyasXcmKDb8=", - "dev": true - }, - "map-visit": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/map-visit/-/map-visit-1.0.0.tgz", - "integrity": "sha1-7Nyo8TFE5mDxtb1B8S80edmN+48=", - "dev": true, - "requires": { - "object-visit": "^1.0.0" - } - }, "mapcap": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/mapcap/-/mapcap-1.0.0.tgz", @@ -25241,42 +23506,6 @@ } } }, - "mixin-deep": { - "version": "1.3.2", - "resolved": "https://registry.npmjs.org/mixin-deep/-/mixin-deep-1.3.2.tgz", - "integrity": "sha512-WRoDn//mXBiJ1H40rqa3vH0toePwSsGb45iInWlTySa+Uu4k3tYUSxa2v1KqAiLtvlrSzaExqS1gtk96A9zvEA==", - "dev": true, - "requires": { - "for-in": "^1.0.2", - "is-extendable": "^1.0.1" - }, - "dependencies": { - "is-extendable": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-1.0.1.tgz", - "integrity": "sha512-arnXMxT1hhoKo9k1LZdmlNyJdDDfy2v0fXjFlmok4+i8ul/6WlbVge9bhM74OpNPQPMGUToDtz+KXa1PneJxOA==", - "dev": true, - "requires": { - "is-plain-object": "^2.0.4" - } - }, - "is-plain-object": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-2.0.4.tgz", - "integrity": "sha512-h5PpgXkWitc38BBMYawTYMWJHFZJVnBquFE57xFpjB8pJFiF6gZ+bU+WyI/yqXiFR5mdLsgYNaPe8uao6Uv9Og==", - "dev": true, - "requires": { - "isobject": "^3.0.1" - } - } - } - }, - "mixme": { - "version": "0.5.4", - "resolved": "https://registry.npmjs.org/mixme/-/mixme-0.5.4.tgz", - "integrity": "sha512-3KYa4m4Vlqx98GPdOHghxSdNtTvcP8E0kkaJ5Dlh+h2DRzF7zpuVVcA8B0QpKd11YJeP9QQ7ASkKzOeu195Wzw==", - "dev": true - }, "mkdirp": { "version": "0.5.6", "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.6.tgz", @@ -25291,38 +23520,31 @@ "resolved": "https://registry.npmjs.org/module-details-from-path/-/module-details-from-path-1.0.3.tgz", "integrity": "sha1-EUyUlnPiqKNenTV4hSeqN7Z52is=" }, - "moment": { - "version": "2.29.4", - "resolved": "https://registry.npmjs.org/moment/-/moment-2.29.4.tgz", - "integrity": "sha512-5LC9SOxjSc2HF6vO2CyuTDNivEdoz2IvyJJGj6X8DJ0eFyfszE0QiEd+iXmBvUP3WHxSjFH/vIsA0EN00cgr8w==", - "dev": true, - "optional": true - }, "mongodb": { - "version": "4.6.0", - "resolved": "https://registry.npmjs.org/mongodb/-/mongodb-4.6.0.tgz", - "integrity": "sha512-1gsxVXmjFTPJ+CkMG9olE4bcVsyY8lBJN9m5B5vj+LZ7wkBqq3PO8RVmNX9GwCBOBz1KV0zM00vPviUearSv7A==", + "version": "4.10.0", + "resolved": "https://registry.npmjs.org/mongodb/-/mongodb-4.10.0.tgz", + "integrity": "sha512-My2QxLTw0Cc1O9gih0mz4mqo145Jq4rLAQx0Glk/Ha9iYBzYpt4I2QFNRIh35uNFNfe8KFQcdwY1/HKxXBkinw==", "dev": true, "requires": { - "bson": "^4.6.3", - "denque": "^2.0.1", - "mongodb-connection-string-url": "^2.5.2", + "bson": "^4.7.0", + "denque": "^2.1.0", + "mongodb-connection-string-url": "^2.5.3", "saslprep": "^1.0.3", - "socks": "^2.6.2" + "socks": "^2.7.0" }, "dependencies": { "denque": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/denque/-/denque-2.0.1.tgz", - "integrity": "sha512-tfiWc6BQLXNLpNiR5iGd0Ocu3P3VpxfzFiqubLgMfhfOw9WyvgJBd46CClNn9k3qfbjvT//0cf7AlYRX/OslMQ==", + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/denque/-/denque-2.1.0.tgz", + "integrity": "sha512-HVQE3AAb/pxF8fQAoiqpvg9i3evqug3hoiwakOyZAwJm+6vZehbkYXZ0l4JxS+I3QxM97v5aaRNhj8v5oBhekw==", "dev": true } } }, "mongodb-connection-string-url": { - "version": "2.5.2", - "resolved": "https://registry.npmjs.org/mongodb-connection-string-url/-/mongodb-connection-string-url-2.5.2.tgz", - "integrity": "sha512-tWDyIG8cQlI5k3skB6ywaEA5F9f5OntrKKsT/Lteub2zgwSUlhqEN2inGgBTm8bpYJf8QYBdA/5naz65XDpczA==", + "version": "2.5.3", + "resolved": "https://registry.npmjs.org/mongodb-connection-string-url/-/mongodb-connection-string-url-2.5.3.tgz", + "integrity": "sha512-f+/WsED+xF4B74l3k9V/XkTVj5/fxFH2o5ToKXd8Iyi5UhM+sO9u0Ape17Mvl/GkZaFtM0HQnzAG5OTmhKw+tQ==", "dev": true, "requires": { "@types/whatwg-url": "^8.2.1", @@ -25392,44 +23614,6 @@ "integrity": "sha512-nnbWWOkoWyUsTjKrhgD0dcz22mdkSnpYqbEjIm2nhwhuxlSkpywJmBo8h0ZqJdkp73mb90SssHkN4rsRaBAfAA==", "dev": true }, - "mv": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/mv/-/mv-2.1.1.tgz", - "integrity": "sha1-rmzg1vbV4KT32JN5jQPB6pVZtqI=", - "dev": true, - "optional": true, - "requires": { - "mkdirp": "~0.5.1", - "ncp": "~2.0.0", - "rimraf": "~2.4.0" - }, - "dependencies": { - "glob": { - "version": "6.0.4", - "resolved": "https://registry.npmjs.org/glob/-/glob-6.0.4.tgz", - "integrity": "sha1-DwiGD2oVUSey+t1PnOJLGqtuTSI=", - "dev": true, - "optional": true, - "requires": { - "inflight": "^1.0.4", - "inherits": "2", - "minimatch": "2 || 3", - "once": "^1.3.0", - "path-is-absolute": "^1.0.0" - } - }, - "rimraf": { - "version": "2.4.5", - "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.4.5.tgz", - "integrity": "sha1-7nEM5dk6j9uFb7Xqj/Di11k0sto=", - "dev": true, - "optional": true, - "requires": { - "glob": "^6.0.1" - } - } - } - }, "mysql": { "version": "2.18.1", "resolved": "https://registry.npmjs.org/mysql/-/mysql-2.18.1.tgz", @@ -25529,39 +23713,12 @@ } }, "nan": { - "version": "2.15.0", - "resolved": "https://registry.npmjs.org/nan/-/nan-2.15.0.tgz", - "integrity": "sha512-8ZtvEnA2c5aYCZYd1cvgdnU6cqwixRoYg70xPLWUws5ORTa/lnw+u4amixRS/Ac5U5mQVgp9pnlSUnbNWFaWZQ==", + "version": "2.17.0", + "resolved": "https://registry.npmjs.org/nan/-/nan-2.17.0.tgz", + "integrity": "sha512-2ZTgtl0nJsO0KQCjEpxcIr5D+Yv90plTitZt9JBfQvVJDS5seMl3FOvsh3+9CoYWXf/1l5OaZzzF6nDm4cagaQ==", "dev": true, "optional": true }, - "nanomatch": { - "version": "1.2.13", - "resolved": "https://registry.npmjs.org/nanomatch/-/nanomatch-1.2.13.tgz", - "integrity": "sha512-fpoe2T0RbHwBTBUOftAfBPaDEi06ufaUai0mE6Yn1kacc3SnTErfb/h+X94VXzI64rKFHYImXSvdwGGCmwOqCA==", - "dev": true, - "requires": { - "arr-diff": "^4.0.0", - "array-unique": "^0.3.2", - "define-property": "^2.0.2", - "extend-shallow": "^3.0.2", - "fragment-cache": "^0.2.1", - "is-windows": "^1.0.2", - "kind-of": "^6.0.2", - "object.pick": "^1.3.0", - "regex-not": "^1.0.0", - "snapdragon": "^0.8.1", - "to-regex": "^3.0.1" - }, - "dependencies": { - "kind-of": { - "version": "6.0.3", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.3.tgz", - "integrity": "sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==", - "dev": true - } - } - }, "native-duplexpair": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/native-duplexpair/-/native-duplexpair-1.0.0.tgz", @@ -25574,13 +23731,6 @@ "integrity": "sha1-Sr6/7tdUHywnrPspvbvRXI1bpPc=", "dev": true }, - "ncp": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ncp/-/ncp-2.0.0.tgz", - "integrity": "sha1-GVoh1sRuNh0vsSgbo4uR6d9727M=", - "dev": true, - "optional": true - }, "ndjson": { "version": "1.5.0", "resolved": "https://registry.npmjs.org/ndjson/-/ndjson-1.5.0.tgz", @@ -25671,9 +23821,9 @@ } }, "node-releases": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.4.tgz", - "integrity": "sha512-gbMzqQtTtDz/00jQzZ21PQzdI9PyLYqUSvD0p3naOhX4odFji0ZxYdnVwPTxmSwkmxhcFImpozceidSG+AgoPQ==", + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.6.tgz", + "integrity": "sha512-PiVXnNuFm5+iYkLBNeq5211hvO38y63T0i2KKh2KnUs3RpzJ+JtODFjkD8yjLwnDkTYF1eKXheUwdssR+NRZdg==", "dev": true }, "normalize-package-data": { @@ -25893,28 +24043,6 @@ "integrity": "sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM=", "dev": true }, - "object-copy": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/object-copy/-/object-copy-0.1.0.tgz", - "integrity": "sha1-fn2Fi3gb18mRpBupde04EnVOmYw=", - "dev": true, - "requires": { - "copy-descriptor": "^0.1.0", - "define-property": "^0.2.5", - "kind-of": "^3.0.3" - }, - "dependencies": { - "define-property": { - "version": "0.2.5", - "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", - "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", - "dev": true, - "requires": { - "is-descriptor": "^0.1.0" - } - } - } - }, "object-filter-sequence": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/object-filter-sequence/-/object-filter-sequence-1.0.0.tgz", @@ -25929,9 +24057,9 @@ } }, "object-inspect": { - "version": "1.12.0", - "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.12.0.tgz", - "integrity": "sha512-Ho2z80bVIvJloH+YzRmpZVQe87+qASmBUKZDWgx9cu+KDrX2ZDH/3tMy+gXbZETVGs2M8YdxObOh7XAtim9Y0g==" + "version": "1.12.2", + "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.12.2.tgz", + "integrity": "sha512-z+cPxW0QGUp0mcqcsgQyLVRDoXFQbXOwBaqyF7VIgI4TWNQsDHrBpUQslRmIfAoYWdYzs6UlKJtB2XJpTaNSpQ==" }, "object-is": { "version": "1.1.5", @@ -25948,36 +24076,15 @@ "resolved": "https://registry.npmjs.org/object-keys/-/object-keys-1.1.1.tgz", "integrity": "sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==" }, - "object-visit": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/object-visit/-/object-visit-1.0.1.tgz", - "integrity": "sha1-95xEk68MU3e1n+OdOV5BBC3QRbs=", - "dev": true, - "requires": { - "isobject": "^3.0.0" - } - }, - "object.assign": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/object.assign/-/object.assign-4.1.2.tgz", - "integrity": "sha512-ixT2L5THXsApyiUPYKmW+2EHpXXe5Ii3M+f4e+aJFAHao5amFRW6J0OO6c/LU8Be47utCx2GL89hxGB6XSmKuQ==", - "requires": { - "call-bind": "^1.0.0", - "define-properties": "^1.1.3", - "has-symbols": "^1.0.1", - "object-keys": "^1.1.1" - } - }, - "object.defaults": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/object.defaults/-/object.defaults-1.1.0.tgz", - "integrity": "sha1-On+GgzS0B96gbaFtiNXNKeQ1/s8=", - "dev": true, + "object.assign": { + "version": "4.1.4", + "resolved": "https://registry.npmjs.org/object.assign/-/object.assign-4.1.4.tgz", + "integrity": "sha512-1mxKf0e58bvyjSCtKYY4sRe9itRk3PJpquJOjeIkz885CczcI4IvJJDLPS72oowuSh+pBxUFROpX+TU++hxhZQ==", "requires": { - "array-each": "^1.0.1", - "array-slice": "^1.0.0", - "for-own": "^1.0.0", - "isobject": "^3.0.0" + "call-bind": "^1.0.2", + "define-properties": "^1.1.4", + "has-symbols": "^1.0.3", + "object-keys": "^1.1.1" } }, "object.entries": { @@ -25990,25 +24097,6 @@ "es-abstract": "^1.19.1" } }, - "object.map": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/object.map/-/object.map-1.0.1.tgz", - "integrity": "sha1-z4Plncj8wK1fQlDh94s7gb2AHTc=", - "dev": true, - "requires": { - "for-own": "^1.0.0", - "make-iterator": "^1.0.0" - } - }, - "object.pick": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/object.pick/-/object.pick-1.3.0.tgz", - "integrity": "sha1-h6EKxMFpS9Lhy/U1kaZhQftd10c=", - "dev": true, - "requires": { - "isobject": "^3.0.1" - } - }, "object.values": { "version": "1.1.5", "resolved": "https://registry.npmjs.org/object.values/-/object.values-1.1.5.tgz", @@ -26027,9 +24115,9 @@ "dev": true }, "on-exit-leak-free": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/on-exit-leak-free/-/on-exit-leak-free-1.0.0.tgz", - "integrity": "sha512-Ve8ubhrXRdnuCJ5bQSQpP3uaV43K1PMcOfSRC1pqHgRZommXCgsXwh08jVC5NpjwScE23BPDwDvVg4cov3mwjw==", + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/on-exit-leak-free/-/on-exit-leak-free-2.1.0.tgz", + "integrity": "sha512-VuCaZZAjReZ3vUwgOB8LxAosIurDiAW0s13rI1YwmaP++jvcxP77AWoQvenZebpCA2m8WC1/EosPYPMjnRAp/w==", "dev": true }, "on-finished": { @@ -26251,35 +24339,12 @@ "callsites": "^3.0.0" } }, - "parse-filepath": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/parse-filepath/-/parse-filepath-1.0.2.tgz", - "integrity": "sha1-pjISf1Oq89FYdvWHLz/6x2PWyJE=", - "dev": true, - "requires": { - "is-absolute": "^1.0.0", - "map-cache": "^0.2.0", - "path-root": "^0.1.1" - } - }, - "parse-passwd": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/parse-passwd/-/parse-passwd-1.0.0.tgz", - "integrity": "sha1-bVuTSkVpk7I9N/QKOC1vFmao5cY=", - "dev": true - }, "parseurl": { "version": "1.3.3", "resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.3.tgz", "integrity": "sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==", "dev": true }, - "pascalcase": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/pascalcase/-/pascalcase-0.1.1.tgz", - "integrity": "sha1-s2PlXoAGym/iF4TS2yK9FdeRfxQ=", - "dev": true - }, "path-exists": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", @@ -26303,21 +24368,6 @@ "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz", "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==" }, - "path-root": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/path-root/-/path-root-0.1.1.tgz", - "integrity": "sha1-mkpoFMrBwM1zNgqV8yCDyOpHRbc=", - "dev": true, - "requires": { - "path-root-regex": "^0.1.0" - } - }, - "path-root-regex": { - "version": "0.1.2", - "resolved": "https://registry.npmjs.org/path-root-regex/-/path-root-regex-0.1.2.tgz", - "integrity": "sha1-v8zcjfWxLcUsi0PsONGNcsBLqW0=", - "dev": true - }, "path-to-regexp": { "version": "6.2.1", "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-6.2.1.tgz", @@ -26337,32 +24387,24 @@ "dev": true }, "pg": { - "version": "8.7.3", - "resolved": "https://registry.npmjs.org/pg/-/pg-8.7.3.tgz", - "integrity": "sha512-HPmH4GH4H3AOprDJOazoIcpI49XFsHCe8xlrjHkWiapdbHK+HLtbm/GQzXYAZwmPju/kzKhjaSfMACG+8cgJcw==", + "version": "8.8.0", + "resolved": "https://registry.npmjs.org/pg/-/pg-8.8.0.tgz", + "integrity": "sha512-UXYN0ziKj+AeNNP7VDMwrehpACThH7LUl/p8TDFpEUuSejCUIwGSfxpHsPvtM6/WXFy6SU4E5RG4IJV/TZAGjw==", "dev": true, "requires": { "buffer-writer": "2.0.0", "packet-reader": "1.0.0", "pg-connection-string": "^2.5.0", - "pg-pool": "^3.5.1", + "pg-pool": "^3.5.2", "pg-protocol": "^1.5.0", "pg-types": "^2.1.0", "pgpass": "1.x" - }, - "dependencies": { - "pg-connection-string": { - "version": "2.5.0", - "resolved": "https://registry.npmjs.org/pg-connection-string/-/pg-connection-string-2.5.0.tgz", - "integrity": "sha512-r5o/V/ORTA6TmUnyWZR9nCj1klXCO2CEKNRlVuJptZe85QuhFayC7WeMic7ndayT5IRIR0S0xFxFi2ousartlQ==", - "dev": true - } } }, "pg-connection-string": { - "version": "2.4.0", - "resolved": "https://registry.npmjs.org/pg-connection-string/-/pg-connection-string-2.4.0.tgz", - "integrity": "sha512-3iBXuv7XKvxeMrIgym7njT+HlZkwZqqGX4Bu9cci8xHZNT+Um1gWKqCsAzcC0d95rcKMU5WBg6YRUcHyV0HZKQ==", + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/pg-connection-string/-/pg-connection-string-2.5.0.tgz", + "integrity": "sha512-r5o/V/ORTA6TmUnyWZR9nCj1klXCO2CEKNRlVuJptZe85QuhFayC7WeMic7ndayT5IRIR0S0xFxFi2ousartlQ==", "dev": true }, "pg-int8": { @@ -26372,9 +24414,9 @@ "dev": true }, "pg-pool": { - "version": "3.5.1", - "resolved": "https://registry.npmjs.org/pg-pool/-/pg-pool-3.5.1.tgz", - "integrity": "sha512-6iCR0wVrro6OOHFsyavV+i6KYL4lVNyYAB9RD18w66xSzN+d8b66HiwuP30Gp1SH5O9T82fckkzsRjlrhD0ioQ==", + "version": "3.5.2", + "resolved": "https://registry.npmjs.org/pg-pool/-/pg-pool-3.5.2.tgz", + "integrity": "sha512-His3Fh17Z4eg7oANLob6ZvH8xIVen3phEZh2QuyrIl4dQSDVEabNducv6ysROKpDNPSD+12tONZVWfSgMvDD9w==", "dev": true }, "pg-protocol": { @@ -26426,9 +24468,9 @@ "dev": true }, "pidusage": { - "version": "2.0.21", - "resolved": "https://registry.npmjs.org/pidusage/-/pidusage-2.0.21.tgz", - "integrity": "sha512-cv3xAQos+pugVX+BfXpHsbyz/dLzX+lr44zNMsYiGxUw+kV5sgQCIcLd1z+0vq+KyC7dJ+/ts2PsfgWfSC3WXA==", + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/pidusage/-/pidusage-3.0.2.tgz", + "integrity": "sha512-g0VU+y08pKw5M8EZ2rIGiEBaB8wrQMjYGFfW2QVIfyT8V+fq8YFLkvlz4bz5ljvFDJYNFCWT3PWqcRr2FKO81w==", "dev": true, "requires": { "safe-buffer": "^5.2.1" @@ -26463,15 +24505,49 @@ } }, "pino-abstract-transport": { - "version": "0.5.0", - "resolved": "https://registry.npmjs.org/pino-abstract-transport/-/pino-abstract-transport-0.5.0.tgz", - "integrity": "sha512-+KAgmVeqXYbTtU2FScx1XS3kNyfZ5TrXY07V96QnUSFqo2gAqlvmaxH67Lj7SWazqsMabf+58ctdTcBgnOLUOQ==", + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/pino-abstract-transport/-/pino-abstract-transport-1.0.0.tgz", + "integrity": "sha512-c7vo5OpW4wIS42hUVcT5REsL8ZljsUfBjqV/e2sFxmFEFZiq1XLUp5EYLtuDH6PEHq9W1egWqRbnLUP5FuZmOA==", "dev": true, "requires": { - "duplexify": "^4.1.2", + "readable-stream": "^4.0.0", "split2": "^4.0.0" }, "dependencies": { + "buffer": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/buffer/-/buffer-6.0.3.tgz", + "integrity": "sha512-FTiCpNxtwiZZHEZbcbTIcZjERVICn9yq/pDFkTl95/AxzD1naBctN7YO68riM/gLSDY7sdrMby8hofADYuuqOA==", + "dev": true, + "requires": { + "base64-js": "^1.3.1", + "ieee754": "^1.2.1" + } + }, + "events": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/events/-/events-3.3.0.tgz", + "integrity": "sha512-mQw+2fkQbALzQ7V0MY0IqdnXNOeTtP4r0lN9z7AAawCXgqea7bDii20AYrIBrFd/Hx0M2Ocz6S111CaFkUcb0Q==", + "dev": true + }, + "ieee754": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.2.1.tgz", + "integrity": "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==", + "dev": true + }, + "readable-stream": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-4.2.0.tgz", + "integrity": "sha512-gJrBHsaI3lgBoGMW/jHZsQ/o/TIWiu5ENCJG1BB7fuCKzpFM8GaS2UoBVt9NO+oI+3FcrBNbUkl3ilDe09aY4A==", + "dev": true, + "requires": { + "abort-controller": "^3.0.0", + "buffer": "^6.0.3", + "events": "^3.3.0", + "process": "^0.11.10" + } + }, "split2": { "version": "4.1.0", "resolved": "https://registry.npmjs.org/split2/-/split2-4.1.0.tgz", @@ -26545,12 +24621,6 @@ "integrity": "sha512-fnWVljUchTro6RiCFvCXBbNhJc2NijN7oIQxbwsyL0buWJPG85v81ehlHI9fXrJsMNgTofEoWIQeClKpgxFLrg==", "dev": true }, - "posix-character-classes": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/posix-character-classes/-/posix-character-classes-0.1.1.tgz", - "integrity": "sha1-AerA/jta9xoqbAL+q7jB/vfgDqs=", - "dev": true - }, "postgres-array": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/postgres-array/-/postgres-array-2.0.0.tgz", @@ -26867,9 +24937,9 @@ "integrity": "sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A==" }, "qs": { - "version": "6.10.3", - "resolved": "https://registry.npmjs.org/qs/-/qs-6.10.3.tgz", - "integrity": "sha512-wr7M2E0OFRfIfJZjKGieI8lBKb7fRCH4Fv5KNPEs7gJ8jadvotdsS08PzOKR7opXhZ/Xkjtt3WF9g38drmyRqQ==", + "version": "6.11.0", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.11.0.tgz", + "integrity": "sha512-MvjoMCJwEarSbUYk5O+nmoSzSutSsTwF85zcHPQ9OrlFoZOYIjaqBAJIqIXjptyD5vThxGq52Xu/MaJzRkIk4Q==", "dev": true, "requires": { "side-channel": "^1.0.4" @@ -26976,38 +25046,34 @@ } }, "real-require": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/real-require/-/real-require-0.1.0.tgz", - "integrity": "sha512-r/H9MzAWtrv8aSVjPCMFpDMl5q66GqtmmRkRjpHTsp4zBAa+snZyiQNlMONiUmEJcsnaw0wCauJ2GWODr/aFkg==", + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/real-require/-/real-require-0.2.0.tgz", + "integrity": "sha512-57frrGM/OCTLqLOAh0mhVA9VBMHd+9U7Zb2THMGdBUoZVOtGbJzjxsYGDJ3A9AYYCP4hn6y1TVbaOfzWtm5GFg==", "dev": true }, "rechoir": { - "version": "0.6.2", - "resolved": "https://registry.npmjs.org/rechoir/-/rechoir-0.6.2.tgz", - "integrity": "sha1-hSBLVNuoLVdC4oyWdW70OvUOM4Q=", + "version": "0.7.0", + "resolved": "https://registry.npmjs.org/rechoir/-/rechoir-0.7.0.tgz", + "integrity": "sha512-ADsDEH2bvbjltXEP+hTIAmeFekTFK0V2BTxMkok6qILyAJEXV0AFfoWcAq4yfll5VdIMd/RVXq0lR+wQi5ZU3Q==", "dev": true, "requires": { - "resolve": "^1.1.6" + "resolve": "^1.9.0" } }, "redis": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/redis/-/redis-3.1.2.tgz", - "integrity": "sha512-grn5KoZLr/qrRQVwoSkmzdbw6pwF+/rwODtrOr6vuBRiR/f3rjSTGupbF90Zpqm2oenix8Do6RV7pYEkGwlKkw==", + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/redis/-/redis-4.3.1.tgz", + "integrity": "sha512-cM7yFU5CA6zyCF7N/+SSTcSJQSRMEKN0k0Whhu6J7n9mmXRoXugfWDBo5iOzGwABmsWKSwGPTU5J4Bxbl+0mrA==", "dev": true, "requires": { - "denque": "^1.5.0", - "redis-commands": "^1.7.0", - "redis-errors": "^1.2.0", - "redis-parser": "^3.0.0" + "@redis/bloom": "1.0.2", + "@redis/client": "1.3.0", + "@redis/graph": "1.0.1", + "@redis/json": "1.0.4", + "@redis/search": "1.1.0", + "@redis/time-series": "1.0.3" } }, - "redis-commands": { - "version": "1.7.0", - "resolved": "https://registry.npmjs.org/redis-commands/-/redis-commands-1.7.0.tgz", - "integrity": "sha512-nJWqw3bTFy21hX/CPKHth6sfhZbdiHP6bTawSgQBlKOVRG7EZkfHbbHwQJnrE4vsQf0CMNE+3gJ4Fmm16vdVlQ==", - "dev": true - }, "redis-errors": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/redis-errors/-/redis-errors-1.2.0.tgz", @@ -27053,16 +25119,6 @@ "@babel/runtime": "^7.8.4" } }, - "regex-not": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/regex-not/-/regex-not-1.0.2.tgz", - "integrity": "sha512-J6SDjUgDxQj5NusnOtdFxDwN/+HWykR8GELwctJ7mdqhcyy1xEc4SRFHUXvxTp661YaVKAjfRLZ9cCqS6tn32A==", - "dev": true, - "requires": { - "extend-shallow": "^3.0.2", - "safe-regex": "^1.1.0" - } - }, "regexp.prototype.flags": { "version": "1.4.3", "resolved": "https://registry.npmjs.org/regexp.prototype.flags/-/regexp.prototype.flags-1.4.3.tgz", @@ -27130,18 +25186,6 @@ "es6-error": "^4.0.1" } }, - "repeat-element": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/repeat-element/-/repeat-element-1.1.4.tgz", - "integrity": "sha512-LFiNfRcSu7KK3evMyYOuCzv3L10TW7yC1G2/+StMjK8Y6Vqd2MG7r/Qjw4ghtuCOjFvlnms/iMmLqpvW/ES/WQ==", - "dev": true - }, - "repeat-string": { - "version": "1.6.1", - "resolved": "https://registry.npmjs.org/repeat-string/-/repeat-string-1.6.1.tgz", - "integrity": "sha1-jcrkcOHIirwtYA//Sndihtp15jc=", - "dev": true - }, "request": { "version": "2.88.2", "resolved": "https://registry.npmjs.org/request/-/request-2.88.2.tgz", @@ -27221,13 +25265,13 @@ "dev": true }, "require-in-the-middle": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/require-in-the-middle/-/require-in-the-middle-5.1.0.tgz", - "integrity": "sha512-M2rLKVupQfJ5lf9OvqFGIT+9iVLnTmjgbOmpil12hiSQNn5zJTKGPoIisETNjfK+09vP3rpm1zJajmErpr2sEQ==", + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/require-in-the-middle/-/require-in-the-middle-5.2.0.tgz", + "integrity": "sha512-efCx3b+0Z69/LGJmm9Yvi4cqEdxnoGnxYxGxBghkkTTFeXRtTCmmhO0AnAfHz59k957uTSuy8WaHqOs8wbYUWg==", "requires": { "debug": "^4.1.1", "module-details-from-path": "^1.0.3", - "resolve": "^1.12.0" + "resolve": "^1.22.1" } }, "require-main-filename": { @@ -27243,11 +25287,11 @@ "dev": true }, "resolve": { - "version": "1.22.0", - "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.0.tgz", - "integrity": "sha512-Hhtrw0nLeSrFQ7phPp4OOcVjLPIeMnRlr5mcnVuMe7M/7eBn98A3hmFRLoFo3DLZkivSYwhRUJTyPyWAk56WLw==", + "version": "1.22.1", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.1.tgz", + "integrity": "sha512-nBpuuYuY5jFsli/JIs1oldw6fOQCBioohqWZg/2hiaOybXOft4lonv85uDOKXdf8rhyK159cxU5cDcK/NKk8zw==", "requires": { - "is-core-module": "^2.8.1", + "is-core-module": "^2.9.0", "path-parse": "^1.0.7", "supports-preserve-symlinks-flag": "^1.0.0" } @@ -27258,28 +25302,12 @@ "integrity": "sha512-0a1F4l73/ZFZOakJnQ3FvkJ2+gSTQWz/r2KE5OdDY0TxPm5h4GkqkWWfM47T7HsbnOtcJVEF4epCVy6u7Q3K+g==", "dev": true }, - "resolve-dir": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/resolve-dir/-/resolve-dir-1.0.1.tgz", - "integrity": "sha1-eaQGRMNivoLybv/nOcm7U4IEb0M=", - "dev": true, - "requires": { - "expand-tilde": "^2.0.0", - "global-modules": "^1.0.0" - } - }, "resolve-from": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz", "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==", "dev": true }, - "resolve-url": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/resolve-url/-/resolve-url-0.2.1.tgz", - "integrity": "sha1-LGN/53yJOv0qZj/iGqkIAGjiBSo=", - "dev": true - }, "responselike": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/responselike/-/responselike-2.0.0.tgz", @@ -27290,149 +25318,140 @@ } }, "restify": { - "version": "8.6.1", - "resolved": "https://registry.npmjs.org/restify/-/restify-8.6.1.tgz", - "integrity": "sha512-I54/Geo2qN4K/2Ers+zNAU/A/nwPrcoTVBVeamw/sROv/kLLuMAzidLmO3f6842tKFxxQvcNhOMYoWZAhYr3vQ==", + "version": "10.0.0", + "resolved": "https://registry.npmjs.org/restify/-/restify-10.0.0.tgz", + "integrity": "sha512-J57tSX1EPGbqVBznQ619zyFMFQno750d3lDfocTiblcQd5FZhCLD26hcW/u7hrXWetltsxoPZv/86Jc9acKfaQ==", "dev": true, "requires": { "assert-plus": "^1.0.0", - "bunyan": "^1.8.12", - "csv": "^5.1.1", - "dtrace-provider": "^0.8.1", + "csv": "^6.2.2", + "dtrace-provider": "~0.8", "escape-regexp-component": "^1.0.2", "ewma": "^2.0.1", - "find-my-way": "^2.0.1", + "find-my-way": "^7.2.0", "formidable": "^1.2.1", - "http-signature": "^1.2.0", + "http-signature": "^1.3.6", "lodash": "^4.17.11", - "lru-cache": "^5.1.1", - "mime": "^2.4.3", + "lru-cache": "^7.14.1", + "mime": "^3.0.0", "negotiator": "^0.6.2", "once": "^1.4.0", - "pidusage": "^2.0.17", + "pidusage": "^3.0.2", + "pino": "^8.7.0", "qs": "^6.7.0", "restify-errors": "^8.0.2", - "semver": "^6.1.1", - "send": "^0.16.2", + "semver": "^7.3.8", + "send": "^0.18.0", "spdy": "^4.0.0", - "uuid": "^3.3.2", + "uuid": "^9.0.0", "vasync": "^2.2.0" }, "dependencies": { - "debug": { - "version": "2.6.9", - "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", - "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "http-signature": { + "version": "1.3.6", + "resolved": "https://registry.npmjs.org/http-signature/-/http-signature-1.3.6.tgz", + "integrity": "sha512-3adrsD6zqo4GsTqtO7FyrejHNv+NgiIfAfv68+jVlFmSr9OGy7zrxONceFRLKvnnZA5jbxQBX1u9PpB6Wi32Gw==", "dev": true, "requires": { - "ms": "2.0.0" + "assert-plus": "^1.0.0", + "jsprim": "^2.0.2", + "sshpk": "^1.14.1" } }, - "destroy": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/destroy/-/destroy-1.0.4.tgz", - "integrity": "sha1-l4hXRCxEdJ5CBmE+N5RiBYJqvYA=", - "dev": true - }, - "http-errors": { - "version": "1.6.3", - "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-1.6.3.tgz", - "integrity": "sha1-i1VoC7S+KDoLW/TqLjhYC+HZMg0=", + "jsprim": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/jsprim/-/jsprim-2.0.2.tgz", + "integrity": "sha512-gqXddjPqQ6G40VdnI6T6yObEC+pDNvyP95wdQhkWkg7crHH3km5qP1FsOXEkzEQwnz6gz5qGTn1c2Y52wP3OyQ==", "dev": true, "requires": { - "depd": "~1.1.2", - "inherits": "2.0.3", - "setprototypeof": "1.1.0", - "statuses": ">= 1.4.0 < 2" + "assert-plus": "1.0.0", + "extsprintf": "1.3.0", + "json-schema": "0.4.0", + "verror": "1.10.0" } }, - "inherits": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz", - "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=", + "lru-cache": { + "version": "7.14.1", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-7.14.1.tgz", + "integrity": "sha512-ysxwsnTKdAx96aTRdhDOCQfDgbHnt8SK0KY8SEjO0wHinhWOFTESbjVCMPbU1uGXg/ch4lifqx0wfjOawU2+WA==", "dev": true }, - "lru-cache": { - "version": "5.1.1", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-5.1.1.tgz", - "integrity": "sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==", + "mime": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/mime/-/mime-3.0.0.tgz", + "integrity": "sha512-jSCU7/VB1loIWBZe14aEYHU/+1UMEHoaO7qxCOVJOw9GgH72VAWppxNcjU+x9a2k3GSIBXNKxXQFqRvvZ7vr3A==", + "dev": true + }, + "pino": { + "version": "8.7.0", + "resolved": "https://registry.npmjs.org/pino/-/pino-8.7.0.tgz", + "integrity": "sha512-l9sA5uPxmZzwydhMWUcm1gI0YxNnYl8MfSr2h8cwLvOAzQLBLewzF247h/vqHe3/tt6fgtXeG9wdjjoetdI/vA==", "dev": true, "requires": { - "yallist": "^3.0.2" + "atomic-sleep": "^1.0.0", + "fast-redact": "^3.1.1", + "on-exit-leak-free": "^2.1.0", + "pino-abstract-transport": "v1.0.0", + "pino-std-serializers": "^6.0.0", + "process-warning": "^2.0.0", + "quick-format-unescaped": "^4.0.3", + "real-require": "^0.2.0", + "safe-stable-stringify": "^2.3.1", + "sonic-boom": "^3.1.0", + "thread-stream": "^2.0.0" } }, - "mime": { - "version": "2.6.0", - "resolved": "https://registry.npmjs.org/mime/-/mime-2.6.0.tgz", - "integrity": "sha512-USPkMeET31rOMiarsBNIHZKLGgvKc/LrjofAnBlOttf5ajRvqiRA8QsenbcooctK6d6Ts6aqZXBA+XbkKthiQg==", + "pino-std-serializers": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/pino-std-serializers/-/pino-std-serializers-6.0.0.tgz", + "integrity": "sha512-mMMOwSKrmyl+Y12Ri2xhH1lbzQxwwpuru9VjyJpgFIH4asSj88F2csdMwN6+M5g1Ll4rmsYghHLQJw81tgZ7LQ==", "dev": true }, - "ms": { + "process-warning": { "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", + "resolved": "https://registry.npmjs.org/process-warning/-/process-warning-2.0.0.tgz", + "integrity": "sha512-+MmoAXoUX+VTHAlwns0h+kFUWFs/3FZy+ZuchkgjyOu3oioLAo2LB5aCfKPh2+P9O18i3m43tUEv3YqttSy0Ww==", "dev": true }, - "on-finished": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.3.0.tgz", - "integrity": "sha1-IPEzZIGwg811M3mSoWlxqi2QaUc=", - "dev": true, - "requires": { - "ee-first": "1.1.1" - } - }, - "send": { - "version": "0.16.2", - "resolved": "https://registry.npmjs.org/send/-/send-0.16.2.tgz", - "integrity": "sha512-E64YFPUssFHEFBvpbbjr44NCLtI1AohxQ8ZSiJjQLskAdKuriYEP6VyGEsRDH8ScozGpkaX1BGvhanqCwkcEZw==", + "semver": { + "version": "7.3.8", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.8.tgz", + "integrity": "sha512-NB1ctGL5rlHrPJtFDVIVzTyQylMLu9N9VICA6HSFJo8MCGVTMW6gfpicwKmmK/dAjTOrqu5l63JJOpDSrAis3A==", "dev": true, "requires": { - "debug": "2.6.9", - "depd": "~1.1.2", - "destroy": "~1.0.4", - "encodeurl": "~1.0.2", - "escape-html": "~1.0.3", - "etag": "~1.8.1", - "fresh": "0.5.2", - "http-errors": "~1.6.2", - "mime": "1.4.1", - "ms": "2.0.0", - "on-finished": "~2.3.0", - "range-parser": "~1.2.0", - "statuses": "~1.4.0" + "lru-cache": "^6.0.0" }, "dependencies": { - "mime": { - "version": "1.4.1", - "resolved": "https://registry.npmjs.org/mime/-/mime-1.4.1.tgz", - "integrity": "sha512-KI1+qOZu5DcW6wayYHSzR/tXKCDC5Om4s1z2QJjDULzLcmf3DvzS7oluY4HCTrc+9FiKmWUgeNLg7W3uIQvxtQ==", - "dev": true + "lru-cache": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", + "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", + "dev": true, + "requires": { + "yallist": "^4.0.0" + } } } }, - "setprototypeof": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.1.0.tgz", - "integrity": "sha512-BvE/TwpZX4FXExxOxZyRGQQv651MSwmWKZGqvmPcRIjDqWub67kTKuIMx43cZZrS/cBBzwBcNDWoFxt2XEFIpQ==", - "dev": true - }, - "statuses": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/statuses/-/statuses-1.4.0.tgz", - "integrity": "sha512-zhSCtt8v2NDrRlPQpCNtw/heZLtfUDqxBM1udqikb/Hbk52LK4nQSwr10u77iopCW5LsyHpuXS0GnEc48mLeew==", - "dev": true + "sonic-boom": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/sonic-boom/-/sonic-boom-3.2.0.tgz", + "integrity": "sha512-SbbZ+Kqj/XIunvIAgUZRlqd6CGQYq71tRRbXR92Za8J/R3Yh4Av+TWENiSiEgnlwckYLyP0YZQWVfyNC0dzLaA==", + "dev": true, + "requires": { + "atomic-sleep": "^1.0.0" + } }, "uuid": { - "version": "3.4.0", - "resolved": "https://registry.npmjs.org/uuid/-/uuid-3.4.0.tgz", - "integrity": "sha512-HjSDRw6gZE5JMggctHBcjVak08+KEVhSIiDzFnT9S9aegmp85S/bReBVTb4QTFaRNptJ9kuYaNhnbNEOkbKb/A==", + "version": "9.0.0", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-9.0.0.tgz", + "integrity": "sha512-MXcSTerfPa4uqyzStbRoTgt5XIe3x5+42+q1sDuy3R5MDk66URdLMOZe5aPX/SQd+kuYAh0FdP/pO28IkQyTeg==", "dev": true }, "yallist": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz", - "integrity": "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==", + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", "dev": true } } @@ -27543,23 +25562,6 @@ "integrity": "sha512-gH8eh2nZudPQO6TytOvbxnuhYBOvDBBLW52tz5q6X58lJcd/tkmqFR+5Z9adS8aJtURSXWThWy/xJtJwixErvg==", "dev": true }, - "safe-regex": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/safe-regex/-/safe-regex-1.1.0.tgz", - "integrity": "sha1-QKNmnzsHfR6UPURinhV91IAjvy4=", - "dev": true, - "requires": { - "ret": "~0.1.10" - }, - "dependencies": { - "ret": { - "version": "0.1.15", - "resolved": "https://registry.npmjs.org/ret/-/ret-0.1.15.tgz", - "integrity": "sha512-TTlYpa+OL+vMMNG24xSlQGEJ3B/RzEfUlLct7b5G/ytav+wPrplCpVMFuwzXbkecJrb6IYo1iFb0S9v37754mg==", - "dev": true - } - } - }, "safe-regex2": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/safe-regex2/-/safe-regex2-2.0.0.tgz", @@ -27598,9 +25600,9 @@ "dev": true }, "secure-json-parse": { - "version": "2.4.0", - "resolved": "https://registry.npmjs.org/secure-json-parse/-/secure-json-parse-2.4.0.tgz", - "integrity": "sha512-Q5Z/97nbON5t/L/sH6mY2EacfjVGwrCcSi5D3btRO2GZ8pf1K1UN7Z9H5J57hjVU2Qzxr1xO+FmBhOvEkzCMmg==", + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/secure-json-parse/-/secure-json-parse-2.5.0.tgz", + "integrity": "sha512-ZQruFgZnIWH+WyO9t5rWt4ZEGqCKPwhiw+YbzTwpmT9elgLrLcfuyUiSnwwjUiVy9r4VM3urtbNF1xmEh9IL2w==", "dev": true }, "select-hose": { @@ -27623,89 +25625,25 @@ "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==" }, - "semver-store": { - "version": "0.3.0", - "resolved": "https://registry.npmjs.org/semver-store/-/semver-store-0.3.0.tgz", - "integrity": "sha512-TcZvGMMy9vodEFSse30lWinkj+JgOBvPn8wRItpQRSayhc+4ssDs335uklkfvQQJgL/WvmHLVj4Ycv2s7QCQMg==", - "dev": true - }, - "send": { - "version": "0.17.2", - "resolved": "https://registry.npmjs.org/send/-/send-0.17.2.tgz", - "integrity": "sha512-UJYB6wFSJE3G00nEivR5rgWp8c2xXvJ3OPWPhmuteU0IKj8nKbG3DrjiOmLwpnHGYWAVwA69zmTm++YG0Hmwww==", - "dev": true, - "requires": { - "debug": "2.6.9", - "depd": "~1.1.2", - "destroy": "~1.0.4", - "encodeurl": "~1.0.2", - "escape-html": "~1.0.3", - "etag": "~1.8.1", - "fresh": "0.5.2", - "http-errors": "1.8.1", - "mime": "1.6.0", - "ms": "2.1.3", - "on-finished": "~2.3.0", - "range-parser": "~1.2.1", - "statuses": "~1.5.0" - }, - "dependencies": { - "debug": { - "version": "2.6.9", - "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", - "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", - "dev": true, - "requires": { - "ms": "2.0.0" - }, - "dependencies": { - "ms": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", - "dev": true - } - } - }, - "destroy": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/destroy/-/destroy-1.0.4.tgz", - "integrity": "sha1-l4hXRCxEdJ5CBmE+N5RiBYJqvYA=", - "dev": true - }, - "ms": { - "version": "2.1.3", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", - "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", - "dev": true - }, - "on-finished": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.3.0.tgz", - "integrity": "sha1-IPEzZIGwg811M3mSoWlxqi2QaUc=", - "dev": true, - "requires": { - "ee-first": "1.1.1" - } - } - } - }, - "seq-queue": { - "version": "0.0.5", - "resolved": "https://registry.npmjs.org/seq-queue/-/seq-queue-0.0.5.tgz", - "integrity": "sha1-1WgS4cAXpuTnw+Ojeh2m143TyT4=", - "dev": true - }, - "serve-static": { - "version": "1.15.0", - "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.15.0.tgz", - "integrity": "sha512-XGuRDNjXUijsUL0vl6nSD7cwURuzEgglbOaFuZM9g3kwDXOWVTck0jLzjPzGD+TazWbboZYu52/9/XPdUgne9g==", + "send": { + "version": "0.18.0", + "resolved": "https://registry.npmjs.org/send/-/send-0.18.0.tgz", + "integrity": "sha512-qqWzuOjSFOuqPjFe4NOsMLafToQQwBSOEpS+FwEt3A2V3vKubTquT3vmLTQpFgMXp8AlFWFuP1qKaJZOtPpVXg==", "dev": true, "requires": { + "debug": "2.6.9", + "depd": "2.0.0", + "destroy": "1.2.0", "encodeurl": "~1.0.2", "escape-html": "~1.0.3", - "parseurl": "~1.3.3", - "send": "0.18.0" + "etag": "~1.8.1", + "fresh": "0.5.2", + "http-errors": "2.0.0", + "mime": "1.6.0", + "ms": "2.1.3", + "on-finished": "2.4.1", + "range-parser": "~1.2.1", + "statuses": "2.0.1" }, "dependencies": { "debug": { @@ -27720,7 +25658,7 @@ "ms": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", "dev": true } } @@ -27750,27 +25688,6 @@ "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", "dev": true }, - "send": { - "version": "0.18.0", - "resolved": "https://registry.npmjs.org/send/-/send-0.18.0.tgz", - "integrity": "sha512-qqWzuOjSFOuqPjFe4NOsMLafToQQwBSOEpS+FwEt3A2V3vKubTquT3vmLTQpFgMXp8AlFWFuP1qKaJZOtPpVXg==", - "dev": true, - "requires": { - "debug": "2.6.9", - "depd": "2.0.0", - "destroy": "1.2.0", - "encodeurl": "~1.0.2", - "escape-html": "~1.0.3", - "etag": "~1.8.1", - "fresh": "0.5.2", - "http-errors": "2.0.0", - "mime": "1.6.0", - "ms": "2.1.3", - "on-finished": "2.4.1", - "range-parser": "~1.2.1", - "statuses": "2.0.1" - } - }, "statuses": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.1.tgz", @@ -27779,6 +25696,24 @@ } } }, + "seq-queue": { + "version": "0.0.5", + "resolved": "https://registry.npmjs.org/seq-queue/-/seq-queue-0.0.5.tgz", + "integrity": "sha1-1WgS4cAXpuTnw+Ojeh2m143TyT4=", + "dev": true + }, + "serve-static": { + "version": "1.15.0", + "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.15.0.tgz", + "integrity": "sha512-XGuRDNjXUijsUL0vl6nSD7cwURuzEgglbOaFuZM9g3kwDXOWVTck0jLzjPzGD+TazWbboZYu52/9/XPdUgne9g==", + "dev": true, + "requires": { + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "parseurl": "~1.3.3", + "send": "0.18.0" + } + }, "set-blocking": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/set-blocking/-/set-blocking-2.0.0.tgz", @@ -27786,9 +25721,9 @@ "dev": true }, "set-cookie-parser": { - "version": "2.5.0", - "resolved": "https://registry.npmjs.org/set-cookie-parser/-/set-cookie-parser-2.5.0.tgz", - "integrity": "sha512-cHMAtSXilfyBePduZEBVPTCftTQWz6ehWJD5YNUg4mqvRosrrjKbo4WS8JkB0/RxonMoohHm7cOGH60mDkRQ9w==", + "version": "2.5.1", + "resolved": "https://registry.npmjs.org/set-cookie-parser/-/set-cookie-parser-2.5.1.tgz", + "integrity": "sha512-1jeBGaKNGdEq4FgIrORu/N570dwoPYio8lSoYLWmX7sQ//0JY08Xh9o5pBcgmHQ/MbsYp/aZnOe1s1lIsbLprQ==", "dev": true }, "set-cookie-serde": { @@ -27796,38 +25731,6 @@ "resolved": "https://registry.npmjs.org/set-cookie-serde/-/set-cookie-serde-1.0.0.tgz", "integrity": "sha512-Vq8e5GsupfJ7okHIvEPcfs5neCo7MZ1ZuWrO3sllYi3DOWt6bSSCpADzqXjz3k0fXehnoFIrmmhty9IN6U6BXQ==" }, - "set-value": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/set-value/-/set-value-2.0.1.tgz", - "integrity": "sha512-JxHc1weCN68wRY0fhCoXpyK55m/XPHafOmK4UWD7m2CI14GMcFypt4w/0+NV5f/ZMby2F6S2wwA7fgynh9gWSw==", - "dev": true, - "requires": { - "extend-shallow": "^2.0.1", - "is-extendable": "^0.1.1", - "is-plain-object": "^2.0.3", - "split-string": "^3.0.1" - }, - "dependencies": { - "extend-shallow": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", - "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", - "dev": true, - "requires": { - "is-extendable": "^0.1.0" - } - }, - "is-plain-object": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-2.0.4.tgz", - "integrity": "sha512-h5PpgXkWitc38BBMYawTYMWJHFZJVnBquFE57xFpjB8pJFiF6gZ+bU+WyI/yqXiFR5mdLsgYNaPe8uao6Uv9Og==", - "dev": true, - "requires": { - "isobject": "^3.0.1" - } - } - } - }, "setprototypeof": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.2.0.tgz", @@ -27934,136 +25837,13 @@ "integrity": "sha512-94hK0Hh8rPqQl2xXc3HsaBoOXKV20MToPkcXvwbISWLEs+64sBq5kFgn2kJDHb1Pry9yrP0dxrCI9RRci7RXKg==", "dev": true }, - "snapdragon": { - "version": "0.8.2", - "resolved": "https://registry.npmjs.org/snapdragon/-/snapdragon-0.8.2.tgz", - "integrity": "sha512-FtyOnWN/wCHTVXOMwvSv26d+ko5vWlIDD6zoUJ7LW8vh+ZBC8QdljveRP+crNrtBwioEUWy/4dMtbBjA4ioNlg==", - "dev": true, - "requires": { - "base": "^0.11.1", - "debug": "^2.2.0", - "define-property": "^0.2.5", - "extend-shallow": "^2.0.1", - "map-cache": "^0.2.2", - "source-map": "^0.5.6", - "source-map-resolve": "^0.5.0", - "use": "^3.1.0" - }, - "dependencies": { - "debug": { - "version": "2.6.9", - "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", - "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", - "dev": true, - "requires": { - "ms": "2.0.0" - } - }, - "define-property": { - "version": "0.2.5", - "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", - "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", - "dev": true, - "requires": { - "is-descriptor": "^0.1.0" - } - }, - "extend-shallow": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", - "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", - "dev": true, - "requires": { - "is-extendable": "^0.1.0" - } - }, - "ms": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", - "dev": true - }, - "source-map": { - "version": "0.5.7", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", - "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=", - "dev": true - } - } - }, - "snapdragon-node": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/snapdragon-node/-/snapdragon-node-2.1.1.tgz", - "integrity": "sha512-O27l4xaMYt/RSQ5TR3vpWCAB5Kb/czIcqUFOM/C4fYcLnbZUc1PkjTAMjof2pBWaSTwOUd6qUHcFGVGj7aIwnw==", - "dev": true, - "requires": { - "define-property": "^1.0.0", - "isobject": "^3.0.0", - "snapdragon-util": "^3.0.1" - }, - "dependencies": { - "define-property": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/define-property/-/define-property-1.0.0.tgz", - "integrity": "sha1-dp66rz9KY6rTr56NMEybvnm/sOY=", - "dev": true, - "requires": { - "is-descriptor": "^1.0.0" - } - }, - "is-accessor-descriptor": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz", - "integrity": "sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ==", - "dev": true, - "requires": { - "kind-of": "^6.0.0" - } - }, - "is-data-descriptor": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz", - "integrity": "sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ==", - "dev": true, - "requires": { - "kind-of": "^6.0.0" - } - }, - "is-descriptor": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.2.tgz", - "integrity": "sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg==", - "dev": true, - "requires": { - "is-accessor-descriptor": "^1.0.0", - "is-data-descriptor": "^1.0.0", - "kind-of": "^6.0.2" - } - }, - "kind-of": { - "version": "6.0.3", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.3.tgz", - "integrity": "sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==", - "dev": true - } - } - }, - "snapdragon-util": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/snapdragon-util/-/snapdragon-util-3.0.1.tgz", - "integrity": "sha512-mbKkMdQKsjX4BAL4bRYTj21edOf8cN7XHdYUJEe+Zn99hVEYcMvKPct1IqNe7+AZPirn8BCDOQBHQZknqmKlZQ==", - "dev": true, - "requires": { - "kind-of": "^3.2.0" - } - }, "socks": { - "version": "2.6.2", - "resolved": "https://registry.npmjs.org/socks/-/socks-2.6.2.tgz", - "integrity": "sha512-zDZhHhZRY9PxRruRMR7kMhnf3I8hDs4S3f9RecfnGxvcBHQcKcIH/oUcEWffsfl1XxdYlA7nnlGbbTvPz9D8gA==", + "version": "2.7.0", + "resolved": "https://registry.npmjs.org/socks/-/socks-2.7.0.tgz", + "integrity": "sha512-scnOe9y4VuiNUULJN72GrM26BNOjVsfPXI+j+98PkyEfsIXroa5ofyjT+FzGvn/xHs73U2JtoBYAVx9Hl4quSA==", "dev": true, "requires": { - "ip": "^1.1.5", + "ip": "^2.0.0", "smart-buffer": "^4.2.0" } }, @@ -28084,25 +25864,6 @@ "whatwg-url": "^7.0.0" } }, - "source-map-resolve": { - "version": "0.5.3", - "resolved": "https://registry.npmjs.org/source-map-resolve/-/source-map-resolve-0.5.3.tgz", - "integrity": "sha512-Htz+RnsXWk5+P2slx5Jh3Q66vhQj1Cllm0zvnaY98+NFx+Dv2CF/f5O/t8x+KaNdrdIAsruNzoh/KpialbqAnw==", - "dev": true, - "requires": { - "atob": "^2.1.2", - "decode-uri-component": "^0.2.0", - "resolve-url": "^0.2.1", - "source-map-url": "^0.4.0", - "urix": "^0.1.0" - } - }, - "source-map-url": { - "version": "0.4.1", - "resolved": "https://registry.npmjs.org/source-map-url/-/source-map-url-0.4.1.tgz", - "integrity": "sha512-cPiFOTLUKvJFIg4SKVScy4ilPPW6rFgMgfuZJPNoDuMs3nC1HbMUycBoJw77xFIp6z1UJQJOfx6C9GMH80DiTw==", - "dev": true - }, "sparse-bitfield": { "version": "3.0.3", "resolved": "https://registry.npmjs.org/sparse-bitfield/-/sparse-bitfield-3.0.3.tgz", @@ -28215,15 +25976,6 @@ "wbuf": "^1.7.3" } }, - "split-string": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/split-string/-/split-string-3.1.0.tgz", - "integrity": "sha512-NzNVhJDYpwceVVii8/Hu6DKfD2G+NrQHlS/V/qgv763EYudVwEcMQNxd2lh+0VrUByXN/oJkl5grOhYWvQUYiw==", - "dev": true, - "requires": { - "extend-shallow": "^3.0.0" - } - }, "split2": { "version": "2.2.0", "resolved": "https://registry.npmjs.org/split2/-/split2-2.2.0.tgz", @@ -28295,27 +26047,6 @@ "integrity": "sha512-qoRRSyROncaz1z0mvYqIE4lCd9p2R90i6GxW3uZv5ucSu8tU7B5HXUP1gG8pVZsYNVaXjk8ClXHPttLyxAL48A==", "dev": true }, - "static-extend": { - "version": "0.1.2", - "resolved": "https://registry.npmjs.org/static-extend/-/static-extend-0.1.2.tgz", - "integrity": "sha1-YICcOcv/VTNyJv1eC1IPNB8ftcY=", - "dev": true, - "requires": { - "define-property": "^0.2.5", - "object-copy": "^0.1.0" - }, - "dependencies": { - "define-property": { - "version": "0.2.5", - "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", - "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", - "dev": true, - "requires": { - "is-descriptor": "^0.1.0" - } - } - } - }, "statuses": { "version": "1.5.0", "resolved": "https://registry.npmjs.org/statuses/-/statuses-1.5.0.tgz", @@ -28336,20 +26067,17 @@ "readable-stream": "^3.0.6" } }, - "stream-shift": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/stream-shift/-/stream-shift-1.0.1.tgz", - "integrity": "sha512-AiisoFqQ0vbGcZgQPY1cdP2I76glaVA/RauYR4G4thNFgkTqr90yXTo4LYX60Jl+sIlPNHHdGSwo01AvbKUSVQ==", + "stream-transform": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/stream-transform/-/stream-transform-3.2.1.tgz", + "integrity": "sha512-ApK+WTJ5bCOf0A2tlec1qhvr8bGEBM/sgXXB7mysdCYgZJO5DZeaV3h3G+g0HnAQ372P5IhiGqnW29zoLOfTzQ==", "dev": true }, - "stream-transform": { - "version": "2.1.3", - "resolved": "https://registry.npmjs.org/stream-transform/-/stream-transform-2.1.3.tgz", - "integrity": "sha512-9GHUiM5hMiCi6Y03jD2ARC1ettBXkQBoQAe7nJsPknnI0ow10aXjTnew8QtYQmLjzn974BnmWEAJgCY6ZP1DeQ==", - "dev": true, - "requires": { - "mixme": "^0.5.1" - } + "streamsearch": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/streamsearch/-/streamsearch-1.1.0.tgz", + "integrity": "sha512-Mcc5wHehp9aXz1ax6bZUyY5afg9u2rv5cqQI3mRrYkGC8rW2hM02jWuwjtL++LS5qinSyhj2QfLyNsuc+VsExg==", + "dev": true }, "string_decoder": { "version": "1.3.0", @@ -28460,6 +26188,18 @@ "string-width": "^3.0.0" }, "dependencies": { + "ajv": { + "version": "6.12.6", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", + "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", + "dev": true, + "requires": { + "fast-deep-equal": "^3.1.1", + "fast-json-stable-stringify": "^2.0.0", + "json-schema-traverse": "^0.4.1", + "uri-js": "^4.2.2" + } + }, "ansi-regex": { "version": "4.1.1", "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.1.tgz", @@ -28478,6 +26218,12 @@ "integrity": "sha1-o7MKXE8ZkYMWeqq5O+764937ZU8=", "dev": true }, + "json-schema-traverse": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", + "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", + "dev": true + }, "string-width": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/string-width/-/string-width-3.1.0.tgz", @@ -28532,9 +26278,9 @@ } }, "tape": { - "version": "5.5.3", - "resolved": "https://registry.npmjs.org/tape/-/tape-5.5.3.tgz", - "integrity": "sha512-hPBJZBL9S7bH9vECg/KSM24slGYV589jJr4dmtiJrLD71AL66+8o4b9HdZazXZyvnilqA7eE8z5/flKiy0KsBg==", + "version": "5.6.1", + "resolved": "https://registry.npmjs.org/tape/-/tape-5.6.1.tgz", + "integrity": "sha512-reNzS3rzsJtKk0f+zJx2XlzIsjJXlIcOIrIxk5shHAG/DzW3BKyMg8UfN79oluYlcWo4lIt56ahLqwgpRT4idg==", "dev": true, "requires": { "array.prototype.every": "^1.1.3", @@ -28544,19 +26290,19 @@ "dotignore": "^0.1.2", "for-each": "^0.3.3", "get-package-type": "^0.1.0", - "glob": "^7.2.0", + "glob": "^7.2.3", "has": "^1.0.3", "has-dynamic-import": "^2.0.1", "inherits": "^2.0.4", "is-regex": "^1.1.4", "minimist": "^1.2.6", - "object-inspect": "^1.12.0", + "object-inspect": "^1.12.2", "object-is": "^1.1.5", "object-keys": "^1.1.1", - "object.assign": "^4.1.2", + "object.assign": "^4.1.4", "resolve": "^2.0.0-next.3", "resumer": "^0.0.0", - "string.prototype.trim": "^1.2.5", + "string.prototype.trim": "^1.2.6", "through": "^2.3.8" }, "dependencies": { @@ -28608,21 +26354,22 @@ "dev": true }, "tedious": { - "version": "14.5.0", - "resolved": "https://registry.npmjs.org/tedious/-/tedious-14.5.0.tgz", - "integrity": "sha512-Mr/ku6J0yku9MvWKO7e//awwI52122jS5AYRz/VOI2jZZawv84iHPKF/FnHBoIEKlRjzahrtevfpNktw/eBAEw==", + "version": "15.1.0", + "resolved": "https://registry.npmjs.org/tedious/-/tedious-15.1.0.tgz", + "integrity": "sha512-D96Z8SL4ALE/rS6rOAfzWd/x+RD9vWbnNT3w5KZ0e0Tdh5FX1bKEODS+1oemSQM2ok5SktLHqSJqYQRx4yu3WA==", "dev": true, "requires": { - "@azure/identity": "^2.0.1", - "@azure/keyvault-keys": "^4.3.0", - "@js-joda/core": "^4.0.0", + "@azure/identity": "^2.0.4", + "@azure/keyvault-keys": "^4.4.0", + "@js-joda/core": "^5.2.0", "@types/es-aggregate-error": "^1.0.2", "bl": "^5.0.0", - "es-aggregate-error": "^1.0.7", + "es-aggregate-error": "^1.0.8", "iconv-lite": "^0.6.3", - "jsbi": "^3.2.1", + "js-md4": "^0.3.2", + "jsbi": "^4.3.0", "native-duplexpair": "^1.0.0", - "node-abort-controller": "^3.0.0", + "node-abort-controller": "^3.0.1", "punycode": "^2.1.0", "sprintf-js": "^1.1.2" }, @@ -28693,6 +26440,16 @@ "which": "^1.3.1" }, "dependencies": { + "js-yaml": { + "version": "3.14.1", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.14.1.tgz", + "integrity": "sha512-okMH7OXXJ7YrN9Ok3/SXrnu4iX9yOk+25nqX4imS2npuvTYDmo/QEZoqwZkYaIDk3jVvBOTOIEgEhaLOynBS9g==", + "dev": true, + "requires": { + "argparse": "^1.0.7", + "esprima": "^4.0.0" + } + }, "log-symbols": { "version": "2.2.0", "resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-2.2.0.tgz", @@ -28728,12 +26485,12 @@ "dev": true }, "thread-stream": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/thread-stream/-/thread-stream-1.0.0.tgz", - "integrity": "sha512-2Sw29jWubQWOcVa7MhLHJ51wjksUD/GHN4Fy3hP9w9DYTujifoZGSKBl54CMLRXWoD5h2pD707kY3fAdzhcwAg==", + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/thread-stream/-/thread-stream-2.2.0.tgz", + "integrity": "sha512-rUkv4/fnb4rqy/gGy7VuqK6wE1+1DOCOWy4RMeaV69ZHMP11tQKZvZSip1yTgrKCMZzEMcCL/bKfHvSfDHx+iQ==", "dev": true, "requires": { - "real-require": "^0.1.0" + "real-require": "^0.2.0" } }, "through": { @@ -28791,9 +26548,9 @@ "dev": true }, "tiny-lru": { - "version": "8.0.2", - "resolved": "https://registry.npmjs.org/tiny-lru/-/tiny-lru-8.0.2.tgz", - "integrity": "sha512-ApGvZ6vVvTNdsmt676grvCkUCGwzG9IqXma5Z07xJgiC5L7akUMof5U8G2JTI9Rz/ovtVhJBlY6mNhEvtjzOIg==", + "version": "10.0.1", + "resolved": "https://registry.npmjs.org/tiny-lru/-/tiny-lru-10.0.1.tgz", + "integrity": "sha512-Vst+6kEsWvb17Zpz14sRJV/f8bUWKhqm6Dc+v08iShmIJ/WxqWytHzCTd6m88pS33rE2zpX34TRmOpAJPloNCA==", "dev": true }, "tmp": { @@ -28811,27 +26568,6 @@ "integrity": "sha1-3F5pjL0HkmW8c+A3doGk5Og/YW4=", "dev": true }, - "to-object-path": { - "version": "0.3.0", - "resolved": "https://registry.npmjs.org/to-object-path/-/to-object-path-0.3.0.tgz", - "integrity": "sha1-KXWIt7Dn4KwI4E5nL4XB9JmeF68=", - "dev": true, - "requires": { - "kind-of": "^3.0.2" - } - }, - "to-regex": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/to-regex/-/to-regex-3.0.2.tgz", - "integrity": "sha512-FWtleNAtZ/Ki2qtqej2CXTOayOH9bHDQF+Q48VpWyDXjbYxA4Yz8iDB31zXOBUlOHHKidDbqGVrTUvQMPmBGBw==", - "dev": true, - "requires": { - "define-property": "^2.0.2", - "extend-shallow": "^3.0.2", - "regex-not": "^1.0.2", - "safe-regex": "^1.1.0" - } - }, "to-regex-range": { "version": "5.0.1", "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", @@ -28880,9 +26616,9 @@ } }, "traverse": { - "version": "0.6.6", - "resolved": "https://registry.npmjs.org/traverse/-/traverse-0.6.6.tgz", - "integrity": "sha1-y99WD9e5r2MlAv7UD5GMFX6pcTc=" + "version": "0.6.7", + "resolved": "https://registry.npmjs.org/traverse/-/traverse-0.6.7.tgz", + "integrity": "sha512-/y956gpUo9ZNCb99YjxG7OaslxZWHfCHAUUfshwqOXmxUIvqLjVO581BT+gM59+QV9tFe6/CGG53tsA1Y7RSdg==" }, "triple-beam": { "version": "1.3.0", @@ -28903,9 +26639,9 @@ }, "dependencies": { "json5": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/json5/-/json5-1.0.1.tgz", - "integrity": "sha512-aKS4WQjPenRxiQsC93MNfjx+nbF4PAdYzmd/1JIj8HYzqfbu86beTuNgXDzPknWk0n0uARlyewZo4s++ES36Ow==", + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/json5/-/json5-1.0.2.tgz", + "integrity": "sha512-g1MWMLBiz8FKi1e4w0UyVL3w+iJceWAFBAaBnnGKOpNa5f8TLktkbre1+s6oICydWAm+HRUGTmI+//xv2hvXYA==", "dev": true, "requires": { "minimist": "^1.2.0" @@ -28981,9 +26717,9 @@ } }, "typescript": { - "version": "4.7.4", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.7.4.tgz", - "integrity": "sha512-C0WQT0gezHuw6AdY1M2jxUO83Rjf0HP7Sk1DtXj6j1EwkQNZrHAg2XPWlq62oqEhYvONq5pkC2Y9oPljWToLmQ==", + "version": "4.9.3", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.9.3.tgz", + "integrity": "sha512-CIfGzTelbKNEnLpLdGFgdyKhG23CKdKgQPOBc+OUNrkJ2vr+KSzsSV5kq5iWhEQbok+quxgGzrAtGWCyU7tHnA==", "dev": true }, "uglify-js": { @@ -29011,10 +26747,13 @@ "dev": true }, "undici": { - "version": "5.5.1", - "resolved": "https://registry.npmjs.org/undici/-/undici-5.5.1.tgz", - "integrity": "sha512-MEvryPLf18HvlCbLSzCW0U00IMftKGI5udnjrQbC5D4P0Hodwffhv+iGfWuJwg16Y/TK11ZFK8i+BPVW2z/eAw==", - "dev": true + "version": "5.14.0", + "resolved": "https://registry.npmjs.org/undici/-/undici-5.14.0.tgz", + "integrity": "sha512-yJlHYw6yXPPsuOH0x2Ib1Km61vu4hLiRRQoafs+WUgX1vO64vgnxiCEN9dpIrhZyHFsai3F0AEj4P9zy19enEQ==", + "dev": true, + "requires": { + "busboy": "^1.6.0" + } }, "unicode-byte-truncate": { "version": "1.0.0", @@ -29058,18 +26797,6 @@ "resolved": "https://registry.npmjs.org/unicode-substring/-/unicode-substring-0.1.0.tgz", "integrity": "sha1-YSDOPDkDhdvND2DDK5BlxBgdSzY=" }, - "union-value": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/union-value/-/union-value-1.0.1.tgz", - "integrity": "sha512-tJfXmxMeWYnczCVs7XAEvIV7ieppALdyepWMkHkwciRpZraG/xwT+s2JN8+pr1+8jCRf80FFzvr+MpQeeoF4Xg==", - "dev": true, - "requires": { - "arr-union": "^3.1.0", - "get-value": "^2.0.6", - "is-extendable": "^0.1.1", - "set-value": "^2.0.1" - } - }, "universal-user-agent": { "version": "6.0.0", "resolved": "https://registry.npmjs.org/universal-user-agent/-/universal-user-agent-6.0.0.tgz", @@ -29088,44 +26815,14 @@ "integrity": "sha1-sr9O6FFKrmFltIF4KdIbLvSZBOw=", "dev": true }, - "unset-value": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/unset-value/-/unset-value-1.0.0.tgz", - "integrity": "sha1-g3aHP30jNRef+x5vw6jtDfyKtVk=", + "update-browserslist-db": { + "version": "1.0.9", + "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.0.9.tgz", + "integrity": "sha512-/xsqn21EGVdXI3EXSum1Yckj3ZVZugqyOZQ/CxYPBD/R+ko9NSUScf8tFF4dOKY+2pvSSJA/S+5B8s4Zr4kyvg==", "dev": true, "requires": { - "has-value": "^0.3.1", - "isobject": "^3.0.0" - }, - "dependencies": { - "has-value": { - "version": "0.3.1", - "resolved": "https://registry.npmjs.org/has-value/-/has-value-0.3.1.tgz", - "integrity": "sha1-ex9YutpiyoJ+wKIHgCVlSEWZXh8=", - "dev": true, - "requires": { - "get-value": "^2.0.3", - "has-values": "^0.1.4", - "isobject": "^2.0.0" - }, - "dependencies": { - "isobject": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/isobject/-/isobject-2.1.0.tgz", - "integrity": "sha1-8GVWEJaj8dou9GJy+BXIQNh+DIk=", - "dev": true, - "requires": { - "isarray": "1.0.0" - } - } - } - }, - "has-values": { - "version": "0.1.4", - "resolved": "https://registry.npmjs.org/has-values/-/has-values-0.1.4.tgz", - "integrity": "sha1-bWHeldkd/Km5oCCJrThL/49it3E=", - "dev": true - } + "escalade": "^3.1.1", + "picocolors": "^1.0.0" } }, "uri-js": { @@ -29136,12 +26833,6 @@ "punycode": "^2.1.0" } }, - "urix": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/urix/-/urix-0.1.0.tgz", - "integrity": "sha1-2pN/emLiH+wf0Y1Js1wpNQZ6bHI=", - "dev": true - }, "url": { "version": "0.10.3", "resolved": "https://registry.npmjs.org/url/-/url-0.10.3.tgz", @@ -29160,12 +26851,6 @@ } } }, - "use": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/use/-/use-3.1.1.tgz", - "integrity": "sha512-cwESVXlO3url9YWlFW/TA9cshCEhtu7IKJ/p5soJ/gGpj7vbvFrAY/eIioQ6Dw23KjZhYgiIo8HOs1nQ2vr/oQ==", - "dev": true - }, "util-deprecate": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", @@ -29189,15 +26874,6 @@ "integrity": "sha512-l8lCEmLcLYZh4nbunNZvQCJc5pv7+RCwa8q/LdUx8u7lsWvPDKmpodJAJNwkAhJC//dFY48KuIEmjtd4RViDrA==", "dev": true }, - "v8flags": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/v8flags/-/v8flags-3.2.0.tgz", - "integrity": "sha512-mH8etigqMfiGWdeXpaaqGfs6BndypxusHHcv2qSHyZkGEznCd/qAXCWWRzeowtL54147cktFOC4P5y+kl8d8Jg==", - "dev": true, - "requires": { - "homedir-polyfill": "^1.0.1" - } - }, "validate-npm-package-license": { "version": "3.0.4", "resolved": "https://registry.npmjs.org/validate-npm-package-license/-/validate-npm-package-license-3.0.4.tgz", @@ -29249,31 +26925,49 @@ } }, "wait-on": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/wait-on/-/wait-on-6.0.1.tgz", - "integrity": "sha512-zht+KASY3usTY5u2LgaNqn/Cd8MukxLGjdcZxT2ns5QzDmTFc4XoWBgC+C/na+sMRZTuVygQoMYwdcVjHnYIVw==", + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/wait-on/-/wait-on-7.0.1.tgz", + "integrity": "sha512-9AnJE9qTjRQOlTZIldAaf/da2eW0eSRSgcqq85mXQja/DW3MriHxkpODDSUEg+Gri/rKEcXUZHe+cevvYItaog==", "dev": true, "requires": { - "axios": "^0.25.0", - "joi": "^17.6.0", + "axios": "^0.27.2", + "joi": "^17.7.0", "lodash": "^4.17.21", - "minimist": "^1.2.5", - "rxjs": "^7.5.4" + "minimist": "^1.2.7", + "rxjs": "^7.8.0" }, "dependencies": { "axios": { - "version": "0.25.0", - "resolved": "https://registry.npmjs.org/axios/-/axios-0.25.0.tgz", - "integrity": "sha512-cD8FOb0tRH3uuEe6+evtAbgJtfxr7ly3fQjYcMcuPlgkwVS9xboaVIpcDV+cYQe+yGykgwZCs1pzjntcGa6l5g==", + "version": "0.27.2", + "resolved": "https://registry.npmjs.org/axios/-/axios-0.27.2.tgz", + "integrity": "sha512-t+yRIyySRTp/wua5xEr+z1q60QmLq8ABsS5O9Me1AsE5dfKqgnCFzwiCZZ/cGNd1lq4/7akDWMxdhVlucjmnOQ==", "dev": true, "requires": { - "follow-redirects": "^1.14.7" + "follow-redirects": "^1.14.9", + "form-data": "^4.0.0" } }, + "form-data": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.0.tgz", + "integrity": "sha512-ETEklSGi5t0QMZuiXoA/Q6vcnxcLQP5vdugSpuAyi6SVGi2clPPp+xgEhuMaHC+zGgn31Kd235W35f7Hykkaww==", + "dev": true, + "requires": { + "asynckit": "^0.4.0", + "combined-stream": "^1.0.8", + "mime-types": "^2.1.12" + } + }, + "minimist": { + "version": "1.2.7", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.7.tgz", + "integrity": "sha512-bzfL1YUZsP41gmu/qjrEk0Q6i2ix/cVeAhbCbqH9u3zYutS1cLg00qhrD0M2MVdCcx4Sc0UpP2eBWo9rotpq6g==", + "dev": true + }, "rxjs": { - "version": "7.5.5", - "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-7.5.5.tgz", - "integrity": "sha512-sy+H0pQofO95VDmFLzyaw9xNJU4KTRSwQIGM6+iG3SypAtCiLDzpeG8sJrNCWn2Up9km+KhkvTdbkrdy+yzZdw==", + "version": "7.8.0", + "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-7.8.0.tgz", + "integrity": "sha512-F2+gxDshqmIub1KdvZkaEfGDwLNpPvk9Fs6LD/MyQxNgMds/WH9OdDDXOmxUZpME+iSK3rQCctkL0DYyytUqMg==", "dev": true, "requires": { "tslib": "^2.1.0" @@ -29374,11 +27068,12 @@ } }, "winston": { - "version": "3.7.2", - "resolved": "https://registry.npmjs.org/winston/-/winston-3.7.2.tgz", - "integrity": "sha512-QziIqtojHBoyzUOdQvQiar1DH0Xp9nF1A1y7NVy2DGEsz82SBDtOalS0ulTRGVT14xPX3WRWkCsdcJKqNflKng==", + "version": "3.8.2", + "resolved": "https://registry.npmjs.org/winston/-/winston-3.8.2.tgz", + "integrity": "sha512-MsE1gRx1m5jdTTO9Ld/vND4krP2To+lgDoMEHGGa4HIlAUyXJtfc7CxQcGXVyz2IBpw5hbFkj2b/AtUdQwyRew==", "dev": true, "requires": { + "@colors/colors": "1.5.0", "@dabh/diagnostics": "^2.0.2", "async": "^3.2.3", "is-stream": "^2.0.0", @@ -29478,9 +27173,9 @@ } }, "ws": { - "version": "7.5.8", - "resolved": "https://registry.npmjs.org/ws/-/ws-7.5.8.tgz", - "integrity": "sha512-ri1Id1WinAX5Jqn9HejiGb8crfRio0Qgu8+MtL36rlTA6RLsMdWt1Az/19A2Qij6uSHUMphEFaTKa4WG+UNHNw==", + "version": "7.5.9", + "resolved": "https://registry.npmjs.org/ws/-/ws-7.5.9.tgz", + "integrity": "sha512-F+P9Jil7UiSKSkppIiD94dN07AwvFixvLIj1Og1Rl9GGMuNipJnV9JzjD6XuqmAeiswGvUmNLjr5cFuXwNS77Q==", "dev": true }, "xml2js": { diff --git a/package.json b/package.json index 09fcdbfc686..12e3c16713f 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "elastic-apm-node", - "version": "3.36.0", + "version": "3.41.1", "description": "The official Elastic APM agent for Node.js", "main": "index.js", "types": "index.d.ts", @@ -8,17 +8,18 @@ "backport": "backport", "docs:open": "PREVIEW=1 npm run docs:build", "docs:build": "./docs/scripts/build_docs.sh apm-agent-nodejs ./docs ./build", - "lint": "npm run lint:eslint && npm run lint:license-files", + "lint": "npm run lint:eslint && npm run lint:license-files && npm run lint:yaml-files", "lint:eslint": "eslint . # requires node >=8.10", "lint:fix": "eslint --fix . # requires node >=8.10", "lint:license-files": "./dev-utils/gen-notice.sh --lint . # requires node >=16", + "lint:yaml-files": "./dev-utils/lint-yaml-files.sh # requires node >=10", "coverage": "COVERAGE=true ./test/script/run_tests.sh", "test": "./test/script/run_tests.sh", - "test:deps": "dependency-check start.js index.js 'lib/**/*.js' 'test/**/*.js' --no-dev -i async_hooks -i perf_hooks -i parseurl", - "test:tav": "tav --quiet", + "test:deps": "dependency-check index.js start.js start-next.js 'lib/**/*.js' 'test/**/*.js' '!test/instrumentation/modules/next/a-nextjs-app' --no-dev -i async_hooks -i perf_hooks -i parseurl -i node:http", + "test:tav": "tav --quiet && (cd test/instrumentation/modules/next/a-nextjs-app && tav --quiet)", "test:docs": "./test/script/docker/run_docs.sh", "test:types": "tsc --project test/types/tsconfig.json && tsc --project test/types/transpile/tsconfig.json && node test/types/transpile/index.js && tsc --project test/types/transpile-default/tsconfig.json && node test/types/transpile-default/index.js", - "test:babel": "babel test/babel/src.js --out-file test/babel/out.js && node test/babel/out.js", + "test:babel": "babel test/babel/src.js --out-file test/babel/out.js && cd test/babel && node out.js", "test:esm": "node --experimental-modules test/esm/index.mjs", "bench": "./test/benchmarks/scripts/run-benchmarks.sh", "bench:ci": "./test/benchmarks/scripts/run-benchmarks-ci.sh", @@ -27,7 +28,8 @@ "docker:start": "docker-compose -f ./test/docker-compose.yml up -d", "docker:stop": "docker-compose -f ./test/docker-compose.yml down", "docker:clean": "./test/script/docker/cleanup.sh", - "docker:dev": "docker-compose -f ./dev-utils/docker-compose.yml run --workdir=/agent nodejs-agent" + "docker:dev": "docker-compose -f ./dev-utils/docker-compose.yml run --workdir=/agent nodejs-agent", + "package:snapshot": "rm -rf ./build/snapshot && mkdir -p ./build/snapshot && npm pack --pack-destination ./build/snapshot" }, "directories": { "test": "test" @@ -37,15 +39,17 @@ "lib", "types", "start.js", + "start-next.js", "index.d.ts", - "start.d.ts" + "start.d.ts", + "start-next.d.ts" ], "repository": { "type": "git", "url": "git://github.com/elastic/apm-agent-nodejs.git" }, "engines": { - "node": "^8.6.0 || 10 || 12 || 14 || 16 || 17 || 18" + "node": "^8.6.0 || 10 || 12 || 14 || 16 || 17 || 18 || 19" }, "keywords": [ "opbeat", @@ -90,7 +94,7 @@ "basic-auth": "^2.0.1", "cookie": "^0.5.0", "core-util-is": "^1.0.2", - "elastic-apm-http-client": "11.0.1", + "elastic-apm-http-client": "11.0.4", "end-of-stream": "^1.4.4", "error-callsites": "^2.0.4", "error-stack-parser": "^2.0.6", @@ -106,7 +110,7 @@ "original-url": "^1.2.3", "pino": "^6.11.2", "relative-microtime": "^2.0.0", - "require-in-the-middle": "^5.0.3", + "require-in-the-middle": "^5.2.0", "semver": "^6.3.0", "set-cookie-serde": "^1.0.0", "shallow-clone-shim": "^2.0.0", @@ -119,14 +123,14 @@ "@babel/cli": "^7.8.4", "@babel/core": "^7.8.4", "@babel/preset-env": "^7.8.4", - "@elastic/elasticsearch": "^8.2.0-patch.1", + "@elastic/elasticsearch": "^8.2.1", "@elastic/elasticsearch-canary": "^8.2.0-canary.2", "@fastify/formbody": "^7.0.1", - "@hapi/hapi": "^20.1.2", - "@koa/router": "^9.0.1", - "@types/node": "^18.0.1", + "@hapi/hapi": "^21.0.0", + "@koa/router": "^12.0.0", + "@types/node": "^18.11.9", "@types/pino": "^6.3.8", - "ajv": "^6.12.6", + "ajv": "^7.2.4", "apollo-server-core": "^3.0.0", "apollo-server-express": "^3.0.0", "aws-sdk": "^2.622.0", @@ -138,14 +142,14 @@ "clone": "^2.0.0", "columnify": "^1.5.4", "connect": "^3.7.0", - "container-info": "^1.0.1", "dashdash": "^2.0.0", "dependency-check": "^4.1.0", + "diagnostics_channel": "^1.1.0", "elasticsearch": "^16.7.3", "eslint": "^6.8.0", "eslint-config-standard": "^14.1.1", "eslint-plugin-import": "^2.25.4", - "eslint-plugin-license-header": "^0.4.0", + "eslint-plugin-license-header": "^0.6.0", "eslint-plugin-node": "^11.1.0", "eslint-plugin-promise": "^4.3.1", "eslint-plugin-standard": "^4.1.0", @@ -161,10 +165,11 @@ "handlebars": "^4.7.3", "https-pem": "^3.0.0", "ioredis": "^5.1.0", - "knex": "^0.21.2", + "js-yaml": "^4.1.0", + "knex": "^0.95.15", "koa": "^2.11.0", "koa-bodyparser": "^4.3.0", - "koa-router": "^9.0.1", + "koa-router": "^12.0.0", "lambda-local": "^2.0.2", "memcached": "^2.2.2", "mimic-response": "^2.1.0", @@ -180,19 +185,19 @@ "once": "^1.4.0", "pg": "^8.7.1", "pug": "^3.0.1", - "redis": "^3.1.2", + "redis": "^4.3.0", "request": "^2.88.2", - "restify": "^8.5.1", + "restify": "^10.0.0", "rimraf": "^3.0.2", - "send": "^0.17.1", "tap-junit": "^5.0.1", "tape": "^5.0.0", - "tedious": "^14.5.0", + "tedious": "^15.1.0", "test-all-versions": "^4.1.1", "thunky": "^1.1.0", "typescript": "^4.7.4", + "undici": "^5.8.0", "vasync": "^2.2.0", - "wait-on": "^6.0.1", + "wait-on": "^7.0.1", "ws": "^7.2.1" } } diff --git a/start-next.d.ts b/start-next.d.ts new file mode 100644 index 00000000000..b5ac73aa553 --- /dev/null +++ b/start-next.d.ts @@ -0,0 +1,8 @@ +/* + * Copyright Elasticsearch B.V. and other contributors where applicable. + * Licensed under the BSD 2-Clause License; you may not use this file except in + * compliance with the BSD 2-Clause License. + */ + +import * as agent from './'; +export = agent; diff --git a/start-next.js b/start-next.js new file mode 100644 index 00000000000..89b6faa3d47 --- /dev/null +++ b/start-next.js @@ -0,0 +1,27 @@ +/* + * Copyright Elasticsearch B.V. and other contributors where applicable. + * Licensed under the BSD 2-Clause License; you may not use this file except in + * compliance with the BSD 2-Clause License. + */ + +'use strict' + +// Use this module via `node --require=elastic-apm-node/start-next.js ...` +// to monitor a Next.js app with Elastic APM. + +const apm = require('./').start() + +// Flush APM data on server process termination. +// https://nextjs.org/docs/deployment#manual-graceful-shutdowns +// Note: Support for NEXT_MANUAL_SIG_HANDLE was added in next@12.1.7-canary.7, +// so this `apm.flush()` will only happen in that and later versions. +process.env.NEXT_MANUAL_SIG_HANDLE = 1 +function flushApmAndExit () { + apm.flush(() => { + process.exit(0) + }) +} +process.on('SIGTERM', flushApmAndExit) +process.on('SIGINT', flushApmAndExit) + +module.exports = apm diff --git a/test/_is_hapi_incompat.js b/test/_is_hapi_incompat.js index ef3c152234a..3b1e47da69e 100644 --- a/test/_is_hapi_incompat.js +++ b/test/_is_hapi_incompat.js @@ -30,6 +30,10 @@ function isHapiIncompat (moduleName) { if (semver.gte(process.version, '16.0.0') && semver.lt(hapiVersion, '20.1.2')) { return true } + // hapi 21+ requires Node.js 14.10.0 or higher. + if (semver.lt(process.version, '14.10.0') && semver.gte(hapiVersion, '21.0.0')) { + return true + } // hapi does not work on early versions of Node.js 10 because of // https://github.com/nodejs/node/issues/20516 diff --git a/test/_is_restify_incompat.js b/test/_is_restify_incompat.js new file mode 100644 index 00000000000..2f100b2fdf2 --- /dev/null +++ b/test/_is_restify_incompat.js @@ -0,0 +1,42 @@ +/* + * Copyright Elasticsearch B.V. and other contributors where applicable. + * Licensed under the BSD 2-Clause License; you may not use this file except in + * compliance with the BSD 2-Clause License. + */ + +'use strict' + +var semver = require('semver') + +/** + * Return whether the current 'restify' version is incompatible with the + * current version of node. If so, this returns a string that can be used + * as a reason for a test skip message. Otherwise it returns false. + * + * Usage: + * const isRestifyIncompat = require('.../_is_restify_incompat')() + * if (isRestifyIncompat) { + * console.log(`# SKIP ${isRestifyIncompat}`) + * process.exit() + * } + * + * Dev Note: These version ranges should mirror the restify section of ".tav.yml". + * + * @returns {string | boolean} + */ +function isRestifyIncompat () { + const nodeVer = process.version + const restifyVer = require('restify/package.json').version + const msg = `restify@${restifyVer} is incompatible with node@${nodeVer}` + + if (semver.satisfies(restifyVer, '<10.0.0') && semver.satisfies(nodeVer, '>=18.0.0', { includePrerelease: true })) { + return msg + } + if (semver.satisfies(restifyVer, '>=9.0.0') && semver.satisfies(nodeVer, '<14.18.0')) { + return msg + } + + return false +} + +module.exports = isRestifyIncompat diff --git a/test/_validate_schema.js b/test/_validate_schema.js new file mode 100644 index 00000000000..102a9e6df32 --- /dev/null +++ b/test/_validate_schema.js @@ -0,0 +1,52 @@ +/* + * Copyright Elasticsearch B.V. and other contributors where applicable. + * Licensed under the BSD 2-Clause License; you may not use this file except in + * compliance with the BSD 2-Clause License. + */ + +'use strict' + +// Validate an APM server intake object against its schema. +// +// Usage example: +// const { validateSpan } = require('./_validate_schema') +// const errs = validateSpan(mySpanObj) +// `errs` is null if mySpanObj is valid, else it is an array of ajv ErrorObject. + +const fs = require('fs') +const { join } = require('path') + +const Ajv = require('ajv').default + +const ajv = new Ajv({ allErrors: true, allowUnionTypes: true, strict: true }) +const schemaDir = join(__dirname, 'integration', 'api-schema', 'apm-server-schema') + +/** + * Create a validator function for the given APM Server intake type (e.g. + * 'span', 'metadata'). + * + * @returns {(data: object) => null | ajv.ErrorObject[]} + */ +function createValidator (apmType, cb) { + const schemaPath = join(schemaDir, apmType + '.json') + const content = fs.readFileSync(schemaPath, { encoding: 'utf8' }) + const schema = JSON.parse(content) + const validate = ajv.compile(schema) + + return function (data) { + const valid = validate(data) + if (valid) { + return null + } else { + return validate.errors + } + } +} + +module.exports = { + validateMetadata: createValidator('metadata'), + validateTransaction: createValidator('transaction'), + validateSpan: createValidator('span'), + validateError: createValidator('error'), + validateMetricset: createValidator('metricset') +} diff --git a/test/agent.test.js b/test/agent.test.js index 861ebf7e0b6..fddfc7562b3 100644 --- a/test/agent.test.js +++ b/test/agent.test.js @@ -16,7 +16,6 @@ var http = require('http') var path = require('path') var os = require('os') -var { sync: containerInfo } = require('container-info') var test = require('tape') const Agent = require('../lib/agent') @@ -26,8 +25,6 @@ const { MockAPMServer } = require('./_mock_apm_server') const { NoopTransport } = require('../lib/noop-transport') var packageJson = require('../package.json') -var inContainer = 'containerId' in (containerInfo() || {}) - // Options to pass to `agent.start()` to turn off some default agent behavior // that is unhelpful for these tests. const agentOpts = { @@ -57,19 +54,20 @@ function assertMetadata (t, payload) { t.deepEqual(payload.service.runtime, { name: 'node', version: process.versions.node }, 'metadata: service.runtime') t.deepEqual(payload.service.agent, { name: 'nodejs', version: packageJson.version }, 'metadata: service.agent') - const expectedSystemKeys = ['hostname', 'architecture', 'platform'] - if (inContainer) expectedSystemKeys.push('container') - - t.deepEqual(Object.keys(payload.system), expectedSystemKeys, 'metadata: system') - t.strictEqual(payload.system.hostname, os.hostname(), 'metadata: system.hostname') - t.strictEqual(payload.system.architecture, process.arch, 'metadata: system.architecture') - t.strictEqual(payload.system.platform, process.platform, 'metadata: system.platform') - - if (inContainer) { - t.deepEqual(Object.keys(payload.system.container), ['id'], 'metadata: system.container') - t.strictEqual(typeof payload.system.container.id, 'string', 'metadata: system.container.id is a string') - t.ok(/^[\da-f]{64}$/.test(payload.system.container.id), 'metadata: system.container.id') + const system = Object.assign({}, payload.system) + t.strictEqual(system.hostname, os.hostname(), 'metadata: system.hostname') + delete system.hostname + t.strictEqual(system.architecture, process.arch, 'metadata: system.architecture') + delete system.architecture + t.strictEqual(system.platform, process.platform, 'metadata: system.platform') + delete system.platform + if (system.container) { + t.deepEqual(Object.keys(system.container), ['id'], 'metadata: system.container') + t.strictEqual(typeof system.container.id, 'string', 'metadata: system.container.id is a string') + t.ok(/^[\da-f]{64}$/.test(system.container.id), 'metadata: system.container.id') + delete system.container } + t.equal(Object.keys(system).length, 0, 'metadata: system, no unexpected keys: ' + JSON.stringify(system)) t.ok(payload.process, 'metadata: process') t.strictEqual(payload.process.pid, process.pid, 'metadata: process.pid') @@ -416,7 +414,7 @@ test('#startSpan()', function (t) { var span = agent.startSpan() t.ok(span, 'should return a span') t.strictEqual(span.name, 'unnamed') - t.strictEqual(span.type, null) + t.strictEqual(span.type, 'custom') t.strictEqual(span.subtype, null) t.strictEqual(span.action, null) agent.destroy() diff --git a/test/babel/elastic-apm-node.js b/test/babel/elastic-apm-node.js new file mode 100644 index 00000000000..6133db04791 --- /dev/null +++ b/test/babel/elastic-apm-node.js @@ -0,0 +1,18 @@ +/* + * Copyright Elasticsearch B.V. and other contributors where applicable. + * Licensed under the BSD 2-Clause License; you may not use this file except in + * compliance with the BSD 2-Clause License. + */ + +const { CapturingTransport } = require('../_capturing_transport') + +module.exports = { + serviceName: 'test-babel', + logUncaughtExceptions: true, + + // Setup a transport that captures sent data, so we can assert that expected + // data was sent. + transport: () => { + return new CapturingTransport() + } +} diff --git a/test/babel/src.js b/test/babel/src.js index 7cea0b42e43..bd63b76c84c 100644 --- a/test/babel/src.js +++ b/test/babel/src.js @@ -6,10 +6,33 @@ 'use strict' -import agent from '../../' +// Note that we cannot use `import apm from 'elastic-apm-node'; apm.start()` +// with Babel's translation from ESM to CommonJS, otherwise the `apm.start()` +// will come *after* the imports we need to instrument (e.g. `import http ...`). +// +// APM agent config is coming from "./elastic-apm-node.js". +import apm from '../../start' -agent.start({ - captureExceptions: false, - metricsInterval: '0', - centralConfig: false +// Start and HTTP server and make a request to it. If APM is working we'd +// expect a captured transaction for the server request. +import assert from 'assert' +import http from 'http' +const server = http.createServer((req, res) => { + req.resume() + req.on('end', () => { + res.end('pong') + }) +}) +server.listen(4321, () => { + http.get('http://localhost:4321', (res) => { + console.log('CLIENT: res.headers:', res.headers) + res.on('data', chunk => { + console.log('CLIENT: res data: %j', chunk.toString()) + }) + res.on('end', () => { + assert(apm._transport.transactions && apm._transport.transactions.length === 1, + 'got the expected APM transaction') + server.close() + }) + }) }) diff --git a/test/benchmarks/utils/analyzer.js b/test/benchmarks/utils/analyzer.js index ad6954152da..c39f21ac73d 100644 --- a/test/benchmarks/utils/analyzer.js +++ b/test/benchmarks/utils/analyzer.js @@ -66,7 +66,7 @@ function storeResult () { bench } - const data = `{"index":{"_index":"benchmark-nodejs","_type":"_doc"}}\n${JSON.stringify(result)}\n` + const data = `{"index":{"_index":"benchmark-nodejs"}}\n${JSON.stringify(result)}\n` appendFile(outputFile, data, function (err) { if (err) throw err diff --git a/test/central-config-enabled.test.js b/test/central-config-enabled.test.js index 24a5a17998b..366ad153358 100644 --- a/test/central-config-enabled.test.js +++ b/test/central-config-enabled.test.js @@ -71,7 +71,8 @@ test('remote config enabled', function (t) { transaction_ignore_urls: ['foo'], log_level: 'warn', span_stack_trace_min_duration: '50ms', - trace_continuation_strategy: 'restart_external' + trace_continuation_strategy: 'restart_external', + exit_span_min_duration: '25ms' } const expect = { transactionSampleRate: 0.42, @@ -80,7 +81,8 @@ test('remote config enabled', function (t) { transactionIgnoreUrls: ['foo'], logLevel: 'warn', spanStackTraceMinDuration: 0.05, - traceContinuationStrategy: 'restart_external' + traceContinuationStrategy: 'restart_external', + exitSpanMinDuration: 0.025 } runTestsWithServer(t, updates, expect) diff --git a/test/config.test.js b/test/config.test.js index 20297ee96b1..d66950babd5 100644 --- a/test/config.test.js +++ b/test/config.test.js @@ -118,7 +118,6 @@ var optionFixtures = [ ['apiKey', 'API_KEY'], ['apiRequestSize', 'API_REQUEST_SIZE', 768 * 1024], ['apiRequestTime', 'API_REQUEST_TIME', 10], - ['asyncHooks', 'ASYNC_HOOKS', true], ['captureBody', 'CAPTURE_BODY', 'off'], ['captureErrorLogStackTraces', 'CAPTURE_ERROR_LOG_STACK_TRACES', config.CAPTURE_ERROR_LOG_STACK_TRACES_MESSAGES], ['captureExceptions', 'CAPTURE_EXCEPTIONS', true], @@ -149,7 +148,7 @@ var optionFixtures = [ ['secretToken', 'SECRET_TOKEN'], ['serverCaCertFile', 'SERVER_CA_CERT_FILE'], ['serverTimeout', 'SERVER_TIMEOUT', 30], - ['serverUrl', 'SERVER_URL'], + ['serverUrl', 'SERVER_URL', 'http://127.0.0.1:8200'], ['serviceName', 'SERVICE_NAME', apmName], ['serviceNodeName', 'SERVICE_NODE_NAME'], ['serviceVersion', 'SERVICE_VERSION', apmVersion], @@ -676,20 +675,26 @@ test('should separate strings and regexes into their own ignore arrays', functio t.end() }) -test('should compile wildcards from string', function (t) { +test('should prepare WildcardMatcher array config vars', function (t) { var agent = new Agent() agent.start(Object.assign( {}, agentOptsNoopTransport, { - transactionIgnoreUrls: ['foo', '/str1', '/wil*card'] + transactionIgnoreUrls: ['foo', 'bar', '/wil*card'], + elasticsearchCaptureBodyUrls: ['*/_search', '*/_eql/search'] } )) - t.strictEqual( - agent._conf.transactionIgnoreUrlRegExp.length, - 3, - 'was everything added?' + t.equal( + agent._conf.transactionIgnoreUrlRegExp.toString(), + '/^foo$/i,/^bar$/i,/^\\/wil.*card$/i', + 'transactionIgnoreUrlRegExp' + ) + t.equal( + agent._conf.elasticsearchCaptureBodyUrlsRegExp.toString(), + '/^.*\\/_search$/i,/^.*\\/_eql\\/search$/i', + 'elasticsearchCaptureBodyUrlsRegExp' ) agent.destroy() @@ -1015,9 +1020,32 @@ test('disableInstrumentations', function (t) { // https://github.com/restify/node-restify/issues/1888 modules.delete('restify') } - if (semver.lt(process.version, '12.3.0')) { + if (semver.lt(process.version, '14.0.0')) { modules.delete('tedious') } + if (semver.lt(process.version, '12.18.0')) { + modules.delete('undici') // undici@5 supports node >=12.18 + } + if (semver.lt(process.version, '12.0.0')) { + modules.delete('koa-router') // koa-router@11 supports node >=12 + modules.delete('@koa/router') // koa-router@11 supports node >=12 + } + if (semver.lt(process.version, '14.8.0')) { + modules.delete('restify') + } + modules.delete('next/dist/server/api-utils/node') + modules.delete('next/dist/server/dev/next-dev-server') + modules.delete('next/dist/server/next') + modules.delete('next/dist/server/next-server') + if (semver.lt(process.version, '14.0.0')) { + modules.delete('redis') // redis@4 supports node >=14 + modules.delete('@redis/client/dist/lib/client') // redis@4 supports node >=14 + modules.delete('@redis/client/dist/lib/client/commands-queue') // redis@4 supports node >=14 + } + + // @node-redis only present for redis >4 <4.1 -- + modules.delete('@node-redis/client/dist/lib/client') // redis@4 supports node >=14 + modules.delete('@node-redis/client/dist/lib/client/commands-queue') // redis@4 supports node >=14 function testSlice (t, name, selector) { var selection = selector(modules) @@ -1229,6 +1257,11 @@ test('parsing of ARRAY and KEY_VALUE opts', function (t) { expect: { transactionIgnoreUrls: ['foo', 'bar bling'] } }, + { + opts: { elasticsearchCaptureBodyUrls: '*/_search, */_msearch/template ' }, + expect: { elasticsearchCaptureBodyUrls: ['*/_search', '*/_msearch/template'] } + }, + { opts: { disableInstrumentations: 'foo, bar' }, expect: { disableInstrumentations: ['foo', 'bar'] } @@ -1665,6 +1698,120 @@ test('spanStackTraceMinDuration', suite => { suite.end() }) +// `contextManager` is synthesized from itself and `asyncHooks`. +test('contextManager', suite => { + const contextManagerTestScenarios = [ + { + name: 'contextManager defaults to empty', + startOpts: {}, + env: {}, + expectedVal: undefined + }, + { + name: 'contextManager=patch is valid', + startOpts: { + contextManager: 'patch' + }, + env: {}, + expectedVal: 'patch' + }, + { + name: 'contextManager=asynchooks is valid', + startOpts: { + contextManager: 'asynchooks' + }, + env: {}, + expectedVal: 'asynchooks' + }, + { + name: 'contextManager=asynclocalstorage is valid', + startOpts: { + contextManager: 'asynclocalstorage' + }, + env: {}, + expectedVal: 'asynclocalstorage' + }, + { + name: 'ELASTIC_APM_CONTEXT_MANAGER works', + startOpts: {}, + env: { + ELASTIC_APM_CONTEXT_MANAGER: 'asynchooks' + }, + expectedVal: 'asynchooks' + }, + { + name: 'contextManager=bogus', + startOpts: { + contextManager: 'bogus' + }, + env: {}, + expectedVal: undefined + }, + { + name: 'both asyncHooks and contextManager ignores the former', + startOpts: { + asyncHooks: false, + contextManager: 'asynchooks' + }, + env: {}, + expectedVal: 'asynchooks' + }, + { + name: 'asyncHooks=false sets contextManager="patch"', + startOpts: { + asyncHooks: false + }, + env: {}, + expectedVal: 'patch' + }, + { + name: 'asyncHooks=true sets contextManager=undefined', + startOpts: { + asyncHooks: true + }, + env: {}, + expectedVal: undefined + }, + { + name: 'asyncHooks=bogus sets contextManager=undefined', + startOpts: { + asyncHooks: 'bogus' + }, + env: {}, + expectedVal: undefined + } + ] + + contextManagerTestScenarios.forEach(scenario => { + suite.test(scenario.name, t => { + const preEnv = Object.assign({}, process.env) + // Tests run in Jenkins CI sets `ELASTIC_APM_CONTEXT_MANAGER`, which + // interferes with these tests. + delete process.env.ELASTIC_APM_CONTEXT_MANAGER + for (const [k, v] of Object.entries(scenario.env)) { + process.env[k] = v + } + const agent = new Agent() + agent.start(Object.assign({}, agentOptsNoopTransport, scenario.startOpts)) + + t.notOk('asyncHooks' in agent._conf, 'asyncHooks is not set on agent._conf') + t.strictEqual(agent._conf.contextManager, scenario.expectedVal, `contextManager=${scenario.expectedVal}`) + + agent.destroy() + for (const k of Object.keys(process.env)) { + if (!(k in preEnv)) { + delete process.env[k] + } else if (process.env[k] !== preEnv[k]) { + process.env[k] = preEnv[k] + } + } + t.end() + }) + }) + + suite.end() +}) + test('env variable names', suite => { // flatten const names = [].concat(...Object.values(config.ENV_TABLE)) diff --git a/test/context-propagation-only.test.js b/test/context-propagation-only.test.js index 1d163ea4b81..d928c38b77d 100644 --- a/test/context-propagation-only.test.js +++ b/test/context-propagation-only.test.js @@ -191,7 +191,7 @@ tape.test('contextPropagationOnly', function (suite) { // stacktrace collection when contextPropagationOnly=true. It isn't a // perfect way to test that. const durationMs = duration[0] / 1e3 + duration[1] / 1e6 - const THRESHOLD_MS = 3 // Is this long enough for slow CI? + const THRESHOLD_MS = 5 // Is this long enough for slow CI? t.ok(durationMs < THRESHOLD_MS, `captureError is fast (<${THRESHOLD_MS}ms): ${durationMs}ms`) t.equal(server.events.length, 0, 'no events sent to APM server intake') diff --git a/test/docker-compose.yml b/test/docker-compose.yml index 36f228815a3..d4bb56ae367 100644 --- a/test/docker-compose.yml +++ b/test/docker-compose.yml @@ -19,7 +19,7 @@ services: retries: 30 mongodb: - image: mongo + image: mongo:5 ports: - "27017:27017" volumes: diff --git a/test/errors.test.js b/test/errors.test.js index 788efc8035b..49c651f48a3 100644 --- a/test/errors.test.js +++ b/test/errors.test.js @@ -13,7 +13,7 @@ const path = require('path') const tape = require('tape') const logging = require('../lib/logging') -const { createAPMError, generateErrorId, _moduleNameFromFrames } = require('../lib/errors') +const { createAPMError, generateErrorId, attributesFromErr, _moduleNameFromFrames } = require('../lib/errors') const { dottedLookup } = require('./_utils') const log = logging.createLogger('off') @@ -331,3 +331,43 @@ tape.test('#_moduleNameFromFrames()', function (suite) { suite.end() }) + +tape.test('#attributesFromErr()', function (suite) { + var cases = [ + // 'err' is an Error instance, or a function that returns one. + { + name: 'no attrs', + err: new Error('boom'), + expectedAttrs: undefined + }, + { + name: 'string attr', + err: () => { + const err = new Error('boom') + err.aStr = 'hello' + return err + }, + expectedAttrs: { aStr: 'hello' } + }, + { + name: 'Invalid Date attr', + err: () => { + const err = new Error('boom') + err.aDate = new Date('invalid') + return err + }, + expectedAttrs: { aDate: 'Invalid Date' } + } + ] + + cases.forEach(function (opts) { + suite.test(opts.name, function (t) { + const err = typeof (opts.err) === 'function' ? opts.err() : opts.err + const attrs = attributesFromErr(err) + t.deepEqual(attrs, opts.expectedAttrs, 'got expected attrs') + t.end() + }) + }) + + suite.end() +}) diff --git a/test/fixtures/json-specs/cgroup_parsing.json b/test/fixtures/json-specs/cgroup_parsing.json new file mode 100644 index 00000000000..f28d87d4c35 --- /dev/null +++ b/test/fixtures/json-specs/cgroup_parsing.json @@ -0,0 +1,22 @@ +{ + "testUnderscores": { + "groupLine": "1:name=systemd:/kubepods.slice/kubepods-burstable.slice/kubepods-burstable-pod90d81341_92de_11e7_8cf2_507b9d4141fa.slice/crio-2227daf62df6694645fee5df53c1f91271546a9560e8600a525690ae252b7f63.scope", + "containerId": "2227daf62df6694645fee5df53c1f91271546a9560e8600a525690ae252b7f63", + "podId": "90d81341-92de-11e7-8cf2-507b9d4141fa" + }, + "testOpenshiftForm": { + "groupLine": "9:freezer:/kubepods.slice/kubepods-pod22949dce_fd8b_11ea_8ede_98f2b32c645c.slice/docker-b15a5bdedd2e7645c3be271364324321b908314e4c77857bbfd32a041148c07f.scope", + "containerId": "b15a5bdedd2e7645c3be271364324321b908314e4c77857bbfd32a041148c07f", + "podId": "22949dce-fd8b-11ea-8ede-98f2b32c645c" + }, + "testUbuntuCGroup": { + "groupLine": "1:name=systemd:/user.slice/user-1000.slice/user@1000.service/apps.slice/apps-org.gnome.Terminal.slice/vte-spawn-75bc72bd-6642-4cf5-b62c-0674e11bfc84.scope", + "containerId": null, + "podId": null + }, + "testAwsEcsCGroup": { + "groupLine": "1:name=systemd:/ecs/03752a671e744971a862edcee6195646/03752a671e744971a862edcee6195646-4015103728", + "containerId": "03752a671e744971a862edcee6195646-4015103728", + "podId": null + } +} diff --git a/test/instrumentation/context.test.js b/test/instrumentation/context.test.js index b88f8dfb69b..bc06677f5dc 100644 --- a/test/instrumentation/context.test.js +++ b/test/instrumentation/context.test.js @@ -12,12 +12,7 @@ var { getHTTPDestination, getDBDestination } = require('../../lib/instrumentatio test('#getHTTPDestination', function (t) { t.test('username and pass', (t) => { const url = 'http://user:pass@testing.local:1234/path?query' - t.deepEqual(getHTTPDestination(url, 'external'), { - service: { - name: 'http://testing.local:1234', - resource: 'testing.local:1234', - type: 'external' - }, + t.deepEqual(getHTTPDestination(url), { address: 'testing.local', port: 1234 }) @@ -26,13 +21,7 @@ test('#getHTTPDestination', function (t) { t.test('https with custom port', () => { const url = 'https://example.com:2222' - t.deepEqual(getHTTPDestination(url, 'external'), { - service: - { - name: 'https://example.com:2222', - resource: 'example.com:2222', - type: 'external' - }, + t.deepEqual(getHTTPDestination(url), { address: 'example.com', port: 2222 }) @@ -41,12 +30,7 @@ test('#getHTTPDestination', function (t) { t.test('https default port', (t) => { const url = 'https://www.elastic.co/products/apm' - t.deepEqual(getHTTPDestination(url, 'external'), { - service: { - name: 'https://www.elastic.co', - resource: 'www.elastic.co:443', - type: 'external' - }, + t.deepEqual(getHTTPDestination(url), { address: 'www.elastic.co', port: 443 }) @@ -55,12 +39,7 @@ test('#getHTTPDestination', function (t) { t.test('http default port', (t) => { const url = 'http://www.elastic.co/products/apm' - t.deepEqual(getHTTPDestination(url, 'external'), { - service: { - name: 'http://www.elastic.co', - resource: 'www.elastic.co:80', - type: 'external' - }, + t.deepEqual(getHTTPDestination(url), { address: 'www.elastic.co', port: 80 }) @@ -69,12 +48,7 @@ test('#getHTTPDestination', function (t) { t.test('ipv6', (t) => { const url = 'http://[::1]' - t.deepEqual(getHTTPDestination(url, 'external'), { - service: { - name: 'http://[::1]', - resource: '[::1]:80', - type: 'external' - }, + t.deepEqual(getHTTPDestination(url), { address: '::1', port: 80 }) @@ -83,12 +57,7 @@ test('#getHTTPDestination', function (t) { t.test('ipv6 https custom port', (t) => { const url = 'https://[::1]:80/' - t.deepEqual(getHTTPDestination(url, 'external'), { - service: { - name: 'https://[::1]:80', - resource: '[::1]:80', - type: 'external' - }, + t.deepEqual(getHTTPDestination(url), { address: '::1', port: 80 }) @@ -97,31 +66,18 @@ test('#getHTTPDestination', function (t) { }) test('#getDBDestination', function (t) { - const span = { type: 'db', subtype: 'memcached' } const host = 'localhost' const port = '8080' - const service = { - name: span.subtype, - resource: span.subtype, - type: span.type - } - - t.test('service fields', (t) => { - t.deepEqual(getDBDestination(span), { service }) - t.end() - }) t.test('host when present', (t) => { - t.deepEqual(getDBDestination(span, host), { - service, + t.deepEqual(getDBDestination(host), { address: host }) t.end() }) t.test('port when present', (t) => { - t.deepEqual(getDBDestination(span, null, port), { - service, + t.deepEqual(getDBDestination(null, port), { port: 8080 }) t.end() diff --git a/test/instrumentation/async-hooks.test.js b/test/instrumentation/core-async-apis.test.js similarity index 93% rename from test/instrumentation/async-hooks.test.js rename to test/instrumentation/core-async-apis.test.js index 548934d4881..e59199f4f84 100644 --- a/test/instrumentation/async-hooks.test.js +++ b/test/instrumentation/core-async-apis.test.js @@ -6,14 +6,10 @@ 'use strict' -var flag = process.env.ELASTIC_APM_ASYNC_HOOKS -delete process.env.ELASTIC_APM_ASYNC_HOOKS var agent = require('../..').start({ - serviceName: 'test', - captureExceptions: false, - asyncHooks: true + serviceName: 'test-core-async-apis', + captureExceptions: false }) -process.env.ELASTIC_APM_ASYNC_HOOKS = flag var test = require('tape') diff --git a/test/instrumentation/drop-fast-exit-spans.test.js b/test/instrumentation/drop-fast-exit-spans.test.js new file mode 100644 index 00000000000..cb9866091f7 --- /dev/null +++ b/test/instrumentation/drop-fast-exit-spans.test.js @@ -0,0 +1,108 @@ +/* + * Copyright Elasticsearch B.V. and other contributors where applicable. + * Licensed under the BSD 2-Clause License; you may not use this file except in + * compliance with the BSD 2-Clause License. + */ + +// Test `exitSpanMinDuration` handling. + +const { CapturingTransport } = require('../_capturing_transport') +const agent = require('../..').start({ + serviceName: 'test-fast-exit-span', + breakdownMetrics: false, + captureExceptions: false, + metricsInterval: 0, + centralConfig: false, + cloudProvider: 'none', + exitSpanMinDuration: '50ms', // Using a large value to not get surprised by event-loop delay on busy CI VMs. + spanStackTraceMinDuration: 0, // Always have span stacktraces. + transport () { return new CapturingTransport() } +}) +const Transaction = require('../../lib/instrumentation/transaction') +const Span = require('../../lib/instrumentation/span') +const { OUTCOME_FAILURE } = require('../../lib/constants') +const mockClient = require('../_mock_http_client') +const tape = require('tape') + +tape.test('discardable tests', function (t) { + const trans = new Transaction(agent) + const spanDefault = new Span(trans, 'foo', 'bar') + t.equals(spanDefault.discardable, false, 'spans are not discardable by default') + + const spanExit = new Span(trans, 'foo', 'bar', { exitSpan: true }) + t.equals(spanExit.discardable, true, 'exit spans are discardable') + + const spanOutcome = new Span(trans, 'foo', 'bar', { exitSpan: true }) + t.equals(spanOutcome.discardable, true, 'exit spans are discardable') + spanOutcome.setOutcome(OUTCOME_FAILURE) + t.equals(spanOutcome.discardable, false, 'failed spans are not discardable') + + const spanPropagation = new Span(trans, 'foo', 'bar', { exitSpan: true }) + t.equals(spanPropagation.discardable, true, 'exit spans are discardable') + + const newHeaders = {} + spanPropagation.propagateTraceContextHeaders(newHeaders, function (carrier, name, value) { + carrier[name] = value + }) + t.equals(spanPropagation.discardable, false, 'spans with propagated context are not discardable') + t.end() +}) + +tape.test('end to end test', function (t) { + resetAgent(function (data) { + t.equals(data.length, 2) + const span = data.spans.pop() + t.equals(span.name, 'long span', `the long span was not dropped (duration ${span.duration}ms > ${agent._conf.exitSpanMinDuration * 1000}ms) was not dropped`) + t.end() + }) + + agent.startTransaction('test') + const span1 = agent.startSpan('short span', 'type', 'subtype', 'action', { exitSpan: true }) + span1.end() // almost immediate, shorter than exitSpanMinDuration + + const span2 = agent.startSpan('long span', 'type', 'subtype', 'action', { exitSpan: true }) + setTimeout(function () { + span2.end() + agent.endTransaction() + agent.flush() + }, 100) // longer than exitSpanMinDuration +}) + +// Test that a composite span faster than `exitSpanMinDuration` is dropped. +tape.test('end to end test with compression', function (t) { + resetAgent(function (data) { + t.equals(data.spans.length, 0, 'the composite span was dropped') + t.end() + }) + + agent.startTransaction('test') + let firstSpan, finalSpan + setTimeout(function () { + firstSpan = agent.startSpan('name1', 'db', 'mysql', { exitSpan: true }) + setTimeout(function () { + firstSpan.end() + }, 1) + }, 1) + + setTimeout(function () { + const span = agent.startSpan('name1', 'db', 'mysql', { exitSpan: true }) + setTimeout(function () { + span.end() + }, 1) + }, 2) + + setTimeout(function () { + finalSpan = agent.startSpan('name1', 'db', 'mysql', { exitSpan: true }) + setTimeout(function () { + finalSpan.end() + agent.endTransaction() + agent.flush() + }, 1) + }, 3) +}) + +function resetAgent (/* numExpected, */ cb) { + agent._instrumentation.testReset() + agent._transport = mockClient(/* numExpected, */ cb) + agent.captureError = function (err) { throw err } +} diff --git a/test/instrumentation/dropped-span-stats.test.js b/test/instrumentation/dropped-span-stats.test.js index ca3c2454e27..84ab16813cf 100644 --- a/test/instrumentation/dropped-span-stats.test.js +++ b/test/instrumentation/dropped-span-stats.test.js @@ -6,7 +6,7 @@ 'use strict' const agent = require('../..').start({ - serviceName: 'test-span-stats', + serviceName: 'test-dropped-span-stats', captureExceptions: false, metricsInterval: 0, centralConfig: false, @@ -18,130 +18,111 @@ const agent = require('../..').start({ const tape = require('tape') const { OUTCOME_FAILURE, OUTCOME_SUCCESS } = require('../../lib/constants') +const { MAX_DROPPED_SPAN_STATS } = require('../../lib/instrumentation/dropped-span-stats') -const destinationContext = { - service: { - resource: 'foo' - } -} -tape.test(function (suite) { - suite.test('test DroppedSpanStats invalid cases', function (test) { - const transaction = agent.startTransaction('trans') - const span = agent.startSpan('foo', 'baz', 'bar', { exitSpan: true }) - span.setDestinationContext(destinationContext) +tape.test('test DroppedSpanStats invalid cases', function (test) { + const transaction = agent.startTransaction('trans') + + const span = agent.startSpan('foo', 'baz', 'bar', { exitSpan: true }) + span.setOutcome(OUTCOME_SUCCESS) + span.end() + test.ok(transaction.captureDroppedSpan(span), 'captured dropped stats for span') + + test.ok(!transaction.captureDroppedSpan(null), 'did not capture dropped stats for span=null') + + const nonExitSpan = agent.startSpan('foo', 'baz', 'bar') + nonExitSpan.setOutcome(OUTCOME_SUCCESS) + nonExitSpan.end() + test.ok(!transaction.captureDroppedSpan(nonExitSpan), 'did not capture dropped stats for nonExitSpan') + + transaction.end() + test.end() +}) + +tape.test('test DroppedSpanStats objects', function (test) { + const transaction = agent.startTransaction('trans') + for (let i = 0; i < 2; i++) { + const span = agent.startSpan('aSpanName', 'aSpanType', 'aSpanSubtype', { exitSpan: true }) span.setOutcome(OUTCOME_SUCCESS) span.end() + test.ok( + transaction.captureDroppedSpan(span) + ) + } - test.ok(transaction.captureDroppedSpan(span)) - - test.ok(!transaction.captureDroppedSpan(null)) + for (let i = 0; i < 3; i++) { + const span = agent.startSpan('aSpanName', 'aSpanType', 'aSpanSubtype', { exitSpan: true }) + span.setOutcome(OUTCOME_FAILURE) + span.end() + test.ok( + transaction.captureDroppedSpan(span) + ) + } + for (let i = 0; i < 4; i++) { + const span = agent.startSpan('aSpanName', 'aSpanType', 'aSpanSubtype', { exitSpan: true }) span.setOutcome(OUTCOME_SUCCESS) - span.setDestinationContext({ - service: {} - }) - test.ok(!transaction.captureDroppedSpan(span)) - - transaction.end() - test.end() - }) - - suite.test('test DroppedSpanStats objects', function (test) { - const transaction = agent.startTransaction('trans') - for (let i = 0; i < 2; i++) { - const span = agent.startSpan('foo', 'baz', 'bar', { exitSpan: true }) - span.setDestinationContext(destinationContext) - span.setOutcome(OUTCOME_SUCCESS) - span.end() - test.ok( - transaction.captureDroppedSpan(span) - ) - } - - for (let i = 0; i < 3; i++) { - const span = agent.startSpan('foo', 'baz', 'bar', { exitSpan: true }) - span.setDestinationContext(destinationContext) - span.setOutcome(OUTCOME_FAILURE) - span.end() - test.ok( - transaction.captureDroppedSpan(span) - ) - } - - for (let i = 0; i < 4; i++) { - const span = agent.startSpan('foo', 'baz', 'bar', { exitSpan: true }) - span.setDestinationContext({ - service: { - resource: 'bar' - } - }) - span.setOutcome(OUTCOME_SUCCESS) - span.end() - span._duration = 1000 // override duration so we can test the sum - test.ok( - transaction.captureDroppedSpan(span) - ) - } - transaction.end() - - // three distinct resource/outcome pairs captured - test.equals(transaction._droppedSpanStats.statsMap.size, 3) - - const payload = transaction._encode() - const stats = payload.dropped_spans_stats - test.equals(stats[0].duration.count, 2) - test.equals(stats[0].destination_service_resource, 'foo') - test.equals(stats[0].outcome, OUTCOME_SUCCESS) - - test.equals(stats[1].duration.count, 3) - test.equals(stats[1].destination_service_resource, 'foo') - test.equals(stats[1].outcome, OUTCOME_FAILURE) - - test.equals(stats[2].duration.count, 4) - test.equals(stats[2].destination_service_resource, 'bar') - test.equals(stats[2].duration.sum.us, 4000000) - test.equals(stats[2].outcome, OUTCOME_SUCCESS) - - test.end() - }) - - suite.test('test DroppedSpanStats max items', function (test) { - const transaction = agent.startTransaction('trans') - for (let i = 0; i < 128; i++) { - const destinationContext = { - service: { - resource: 'foo' + i - } - } - const span = agent.startSpan('foo', 'baz', 'bar', { exitSpan: true }) - span.setDestinationContext(destinationContext) - span.setOutcome(OUTCOME_FAILURE) - span.end() - test.ok(transaction.captureDroppedSpan(span)) - } - - // one too many + span.setServiceTarget('aTargType', 'aTargName') + span.end() + span._duration = 1000 // override duration so we can test the sum + test.ok( + transaction.captureDroppedSpan(span) + ) + } + transaction.end() + + // three distinct resource/outcome pairs captured + test.equals(transaction._droppedSpanStats.statsMap.size, 3) + + const payload = transaction._encode() + const stats = payload.dropped_spans_stats + test.equals(stats[0].duration.count, 2) + test.equals(stats[0].destination_service_resource, 'aSpanSubtype') + test.equals(stats[0].service_target_type, 'aSpanSubtype', 'dropped_span_stats[0].service_target_type') + test.equals(stats[0].service_target_name, undefined, 'dropped_span_stats[0].service_target_name') + test.equals(stats[0].outcome, OUTCOME_SUCCESS, 'dropped_span_stats[0].outcome') + + test.equals(stats[1].duration.count, 3) + test.equals(stats[1].destination_service_resource, 'aSpanSubtype') + test.equals(stats[1].service_target_type, 'aSpanSubtype', 'dropped_span_stats[1].service_target_type') + test.equals(stats[1].service_target_name, undefined, 'dropped_span_stats[1].service_target_name') + test.equals(stats[1].outcome, OUTCOME_FAILURE, 'dropped_span_stats[1].outcome') + + test.equals(stats[2].duration.count, 4) + test.equals(stats[2].destination_service_resource, 'aTargType/aTargName') + test.equals(stats[2].duration.sum.us, 4000000) + test.equals(stats[2].service_target_type, 'aTargType', 'dropped_span_stats[2].service_target_type') + test.equals(stats[2].service_target_name, 'aTargName', 'dropped_span_stats[2].service_target_name') + test.equals(stats[2].outcome, OUTCOME_SUCCESS, 'dropped_span_stats[2].outcome') + + test.end() +}) + +tape.test('test DroppedSpanStats max items', function (test) { + const transaction = agent.startTransaction('trans') + for (let i = 0; i < MAX_DROPPED_SPAN_STATS; i++) { const span = agent.startSpan('foo', 'baz', 'bar', { exitSpan: true }) - span.setDestinationContext(destinationContext) + span.setServiceTarget('aTargType', 'aTargName-' + i) span.setOutcome(OUTCOME_FAILURE) span.end() - test.ok(!transaction.captureDroppedSpan(span)) - - // and we're still able to increment spans that fit the previous profile - const span2 = agent.startSpan('foo', 'baz', 'bar', { exitSpan: true }) - span2.setDestinationContext({ - service: { - resource: 'foo0' - } - }) - span2.setOutcome(OUTCOME_FAILURE) - span2.end() - test.ok(transaction.captureDroppedSpan(span2)) - - transaction.end() - test.equals(transaction._droppedSpanStats.statsMap.size, 128) - test.end() - }) - - suite.end() + test.ok(transaction.captureDroppedSpan(span)) + } + + // one too many + const span = agent.startSpan('foo', 'baz', 'bar', { exitSpan: true }) + span.setServiceTarget('aTargType', 'aTargName') + span.setOutcome(OUTCOME_FAILURE) + span.end() + test.ok(!transaction.captureDroppedSpan(span), 'did not capture stats for this dropped span (hit MAX_DROPPED_SPAN_STATS)') + + // and we're still able to increment spans that fit the previous profile + const span2 = agent.startSpan('foo', 'baz', 'bar', { exitSpan: true }) + span2.setServiceTarget('aTargType', 'aTargName-' + 0) + span2.setOutcome(OUTCOME_FAILURE) + span2.end() + test.ok(transaction.captureDroppedSpan(span2), 'DID capture stats for this previously seen span stats key') + + transaction.end() + test.equals(transaction._droppedSpanStats.statsMap.size, MAX_DROPPED_SPAN_STATS) + test.end() }) diff --git a/test/instrumentation/fs.test.js b/test/instrumentation/fs.test.js index 06176c038d7..f8082546660 100644 --- a/test/instrumentation/fs.test.js +++ b/test/instrumentation/fs.test.js @@ -14,8 +14,7 @@ const apm = require('../..').start({ metricsInterval: '0s', centralConfig: false, cloudProvider: 'none', - disableSend: true, - asyncHooks: false + disableSend: true }) const fs = require('fs') diff --git a/test/instrumentation/github-issue-2715.test.js b/test/instrumentation/github-issue-2715.test.js index 617ae14f787..ce91c862b88 100644 --- a/test/instrumentation/github-issue-2715.test.js +++ b/test/instrumentation/github-issue-2715.test.js @@ -27,21 +27,14 @@ tape.test(function (suite) { console.log() t.end() }) - const destinationContext = { - service: { - resource: 'foo' - } - } + const dbContext = { statement: 'SELECT foo from bar', type: 'sql' } agent.startTransaction('test') const span1 = agent.startSpan('name1', 'db', 'mysql', { exitSpan: true }) - - span1.setDestinationContext(destinationContext) span1.setDbContext(dbContext) span1.end() const span2 = agent.startSpan('name1', 'db', 'mysql', { exitSpan: true }) - span2.setDestinationContext(destinationContext) span2.setDbContext(dbContext) span2.end() diff --git a/test/instrumentation/github-issue-75.test.js b/test/instrumentation/github-issue-75.test.js deleted file mode 100644 index 7f9ade9f948..00000000000 --- a/test/instrumentation/github-issue-75.test.js +++ /dev/null @@ -1,85 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and other contributors where applicable. - * Licensed under the BSD 2-Clause License; you may not use this file except in - * compliance with the BSD 2-Clause License. - */ - -'use strict' - -var agent = require('../..').start({ - serviceName: 'test', - captureExceptions: false, - metricsInterval: 0, - asyncHooks: true -}) - -var http = require('http') - -var send = require('send') -var test = require('tape') - -var mockClient = require('../_mock_http_client') - -// run it 5 times in case of false positives due to race conditions -times(5, function (n, done) { - test('https://github.com/elastic/apm-agent-nodejs/issues/75 ' + n, function (t) { - resetAgent(4, function (data) { - t.strictEqual(data.transactions.length, 2, 'should create transactions') - t.strictEqual(data.spans.length, 2, 'should create spans') - data.spans.forEach(function (span) { - let trans - data.transactions = data.transactions.filter(function (_trans) { - const match = span.name === _trans.id - if (match) trans = _trans - return !match - }) - t.ok(trans, 'span should belong to transaction') - }) - server.close() - t.end() - done() - }) - - var server = http.createServer(function (req, res) { - var span = agent.startSpan(agent.currentTransaction.id) - setTimeout(function () { - span.end() - send(req, __filename).pipe(res) - }, 50) - }) - - var requestNo = 0 - - server.listen(function () { - request() - request() - }) - - function request () { - var port = server.address().port - http.get('http://localhost:' + port, function (res) { - res.on('end', function () { - if (++requestNo === 2) { - agent.flush() - } - }) - res.resume() - }) - } - }) -}) - -function times (max, fn) { - var n = 0 - run() - function run () { - if (++n > max) return - fn(n, run) - } -} - -function resetAgent (expected, cb) { - agent._instrumentation.testReset() - agent._transport = mockClient(expected, cb) - agent.captureError = function (err) { throw err } -} diff --git a/test/instrumentation/modules/@elastic/elasticsearch.test.js b/test/instrumentation/modules/@elastic/elasticsearch.test.js index cc486e1b682..2a2576f5190 100644 --- a/test/instrumentation/modules/@elastic/elasticsearch.test.js +++ b/test/instrumentation/modules/@elastic/elasticsearch.test.js @@ -17,6 +17,9 @@ const agent = require('../../../..').start({ spanCompressionEnabled: false }) +const { URL } = require('url') + +const config = require('../../../../lib/config') const { safeGetPackageVersion } = require('../../../_utils') // Support running these tests with a different package name -- typically @@ -55,20 +58,22 @@ const mockClient = require('../../../_mock_http_client') const shimmer = require('../../../../lib/instrumentation/shimmer') const { MockES } = require('./_mock_es') -const host = (process.env.ES_HOST || 'localhost') + ':9200' +let haveDiagCh = false +try { + require('diagnostics_channel') + haveDiagCh = true +} catch (_noModErr) { + // pass +} + +const port = 9200 +const host = `${process.env.ES_HOST || 'localhost'}:${port}` const clientOpts = { node: 'http://' + host } -// Limitation: For v8 of the ES client, these tests assume the non-default -// `HttpConnection` is used rather than the default usage of undici, because -// the tests check for an HTTP span for each ES request and currently the -// undici HTTP client is not instrumented. -if (semver.satisfies(esVersion, '>=8', { includePrerelease: true })) { - clientOpts.Connection = es.HttpConnection -} test('client.ping with promise', function (t) { - resetAgent(checkDataAndEnd(t, 'HEAD', '/', null, 200)) + resetAgent(checkDataAndEnd(t, 'HEAD /', `http://${host}/`, 200)) agent.startTransaction('myTrans') @@ -83,7 +88,7 @@ test('client.ping with promise', function (t) { // Callback-style was dropped in ES client v8. if (!semver.satisfies(esVersion, '>=8', { includePrerelease: true })) { test('client.ping with callback', function (t) { - resetAgent(checkDataAndEnd(t, 'HEAD', '/', null, 200)) + resetAgent(checkDataAndEnd(t, 'HEAD /', `http://${host}/`, 200)) agent.startTransaction('myTrans') @@ -100,7 +105,7 @@ if (!semver.satisfies(esVersion, '>=8', { includePrerelease: true })) { test('client.search with promise', function (t) { const searchOpts = { q: 'pants' } - resetAgent(checkDataAndEnd(t, 'GET', '/_search', 'q=pants', 200)) + resetAgent(checkDataAndEnd(t, 'GET /_search', `http://${host}/_search?q=pants`, 200)) agent.startTransaction('myTrans') @@ -121,7 +126,7 @@ if (semver.gte(process.version, '10.0.0')) { test('client.child', function (t) { const searchOpts = { q: 'pants' } - resetAgent(checkDataAndEnd(t, 'GET', '/_search', 'q=pants', 200)) + resetAgent(checkDataAndEnd(t, 'GET /_search', `http://${host}/_search?q=pants`, 200)) agent.startTransaction('myTrans') @@ -141,7 +146,7 @@ if (semver.gte(process.version, '10.0.0')) { test('client.search with queryparam', function (t) { const searchOpts = { q: 'pants' } - resetAgent(checkDataAndEnd(t, 'GET', '/_search', 'q=pants', 200)) + resetAgent(checkDataAndEnd(t, 'GET /_search', `http://${host}/_search?q=pants`, 200)) agent.startTransaction('myTrans') @@ -168,7 +173,13 @@ if (semver.gte(process.version, '10.0.0')) { body: body } - resetAgent(checkDataAndEnd(t, 'POST', `/${searchOpts.index}/_search`, JSON.stringify(body), 200)) + resetAgent(checkDataAndEnd( + t, + `POST /${searchOpts.index}/_search`, + `http://${host}/${searchOpts.index}/_search`, + 200, + JSON.stringify(body) + )) agent.startTransaction('myTrans') @@ -197,7 +208,13 @@ if (semver.gte(process.version, '10.0.0')) { let expectedDbStatement = Object.assign({}, searchOpts) delete expectedDbStatement.index expectedDbStatement = JSON.stringify(expectedDbStatement) - resetAgent(checkDataAndEnd(t, 'POST', `/${searchOpts.index}/_search`, expectedDbStatement, 200)) + resetAgent(checkDataAndEnd( + t, + `POST /${searchOpts.index}/_search`, + `http://${host}/${searchOpts.index}/_search`, + 200, + expectedDbStatement + )) agent.startTransaction('myTrans') @@ -228,20 +245,24 @@ if (semver.gte(process.version, '10.0.0')) { size: 2, sort: 'myField:asc' } - let statement + let query, statement // ES client version 8 merges options into `body` differently from earlier // versions. if (semver.satisfies(esVersion, '>=8', { includePrerelease: true })) { - statement = `sort=myField%3Aasc - -{"query":{"match":{"request":"bar"}},"size":2}` + query = 'sort=myField%3Aasc' + statement = '{"query":{"match":{"request":"bar"}},"size":2}' } else { - statement = `size=2&sort=myField%3Aasc - -${JSON.stringify(body)}` + query = 'size=2&sort=myField%3Aasc' + statement = JSON.stringify(body) } - resetAgent(checkDataAndEnd(t, 'POST', `/${searchOpts.index}/_search`, statement, 200)) + resetAgent(checkDataAndEnd( + t, + `POST /${searchOpts.index}/_search`, + `http://${host}/${searchOpts.index}/_search?${query}`, + 200, + statement + )) agent.startTransaction('myTrans') @@ -269,7 +290,13 @@ ${JSON.stringify(body)}` } } - resetAgent(checkDataAndEnd(t, 'POST', '/_search/template', JSON.stringify(body), 200)) + resetAgent(checkDataAndEnd( + t, + 'POST /_search/template', + `http://${host}/_search/template`, + 200, + JSON.stringify(body) + )) agent.startTransaction('myTrans') @@ -299,12 +326,16 @@ ${JSON.stringify(body)}` typed_keys: false, body: body } - const statement = `search_type=query_then_fetch&typed_keys=false - -${body.map(JSON.stringify).join('\n')} -` + const query = 'search_type=query_then_fetch&typed_keys=false' + const statement = body.map(JSON.stringify).join('\n') + '\n' - resetAgent(checkDataAndEnd(t, 'POST', '/_msearch', statement, 200)) + resetAgent(checkDataAndEnd( + t, + 'POST /_msearch', + `http://${host}/_msearch?${query}`, + 200, + statement + )) agent.startTransaction('myTrans') @@ -336,7 +367,13 @@ ${body.map(JSON.stringify).join('\n')} ] const statement = body.map(JSON.stringify).join('\n') + '\n' - resetAgent(checkDataAndEnd(t, 'POST', '/_msearch/template', statement, 200)) + resetAgent(checkDataAndEnd( + t, + 'POST /_msearch/template', + `http://${host}/_msearch/template`, + 200, + statement + )) agent.startTransaction('myTrans') @@ -350,6 +387,71 @@ ${body.map(JSON.stringify).join('\n')} t.ok(agent.currentSpan === null, 'no currentSpan in sync code after @elastic/elasticsearch client command') }) + // Test the determination of the Elasticsearch cluster name from the + // "x-found-handling-cluster" header included in Elastic Cloud. (Only test + // with client versions >=8 to avoid the product-check complications in 7.x + // clients. Also cannot test with contextManager="patch", because of the + // limitation described in "modules/@elastic/elasticsearch.js".) + if (semver.satisfies(esVersion, '>=8') && + agent._conf.contextManager !== config.CONTEXT_MANAGER_PATCH) { + test('cluster name from "x-found-handling-cluster"', function (t) { + // Create a mock Elasticsearch server that mimics a search response from + // a cloud instance. + const esServer = new MockES({ + responses: [ + { + statusCode: 200, + headers: { + 'content-length': '162', + 'content-type': 'application/json', + 'x-cloud-request-id': 'quf1Yfx0SyOSIytmwkYMrw', + 'x-elastic-product': 'Elasticsearch', + 'x-found-handling-cluster': 'eb2cefb2bb97bb0e9179d92f79eceb1b', + 'x-found-handling-instance': 'instance-0000000000', + date: 'Wed, 07 Sep 2022 16:32:45 GMT' + }, + body: '{"took":5,"timed_out":false,"_shards":{"total":25,"successful":25,"skipped":0,"failed":0},"hits":{"total":{"value":0,"relation":"eq"},"max_score":null,"hits":[]}}' + } + ] + }) + esServer.start(function (esUrl) { + resetAgent( + function done (data) { + // Drop the transaction captured for the request received by the + // mock ES server, so we can use `checkDataAndEnd()`. + data.transactions.shift() + checkDataAndEnd( + t, + 'GET /_search', + `${esUrl}/_search?q=pants`, + 200, + null, + 'eb2cefb2bb97bb0e9179d92f79eceb1b' + )(data) + } + ) + + agent.startTransaction('myTrans') + const client = new es.Client(Object.assign( + {}, + clientOpts, + { node: esUrl } + )) + client.search({ q: 'pants' }) + .catch(err => { + t.fail('should not have gotten here') + t.error(err) + }) + .finally(() => { + agent.endTransaction() + agent.flush() + client.close() + esServer.close() + }) + }) + }) + } + // Test some error scenarios. // 'ResponseError' is the client's way of passing back an Elasticsearch API @@ -704,68 +806,83 @@ ${body.map(JSON.stringify).join('\n')} // Ensure that even without HTTP child spans, trace-context propagation to // Elasticsearch still works. - test('context-propagation works', function (t) { - const mockResponses = [ - { - statusCode: 200, - headers: { - 'X-elastic-product': 'Elasticsearch', - 'content-type': 'application/json' - }, - body: '{"took":0,"timed_out":false,"_shards":{"total":0,"successful":0,"skipped":0,"failed":0},"hits":{"total":{"value":0,"relation":"eq"},"max_score":0,"hits":[]}}' - } - ] - if (semver.gte(esVersion, '7.14.0') && semver.satisfies(esVersion, '7.x')) { - // First request will be "GET /" for a product check. - mockResponses.unshift({ - statusCode: 200, - headers: { - 'X-elastic-product': 'Elasticsearch', - 'content-type': 'application/json' - }, - body: '{"name":"645a066f9b52","cluster_name":"docker-cluster","cluster_uuid":"1pR-cy9dSLWO7TNxI3kodA","version":{"number":"8.0.0-beta1","build_flavor":"default","build_type":"docker","build_hash":"ba1f616138a589f12eb0c6f678aee96377525b8f","build_date":"2021-11-04T12:35:26.989068569Z","build_snapshot":false,"lucene_version":"9.0.0","minimum_wire_compatibility_version":"7.16.0","minimum_index_compatibility_version":"7.0.0"},"tagline":"You Know, for Search"}' - }) + const clientOptsToTry = {} // -> + if (!es.HttpConnection) { + // This is pre-v8 of the ES client. Just test the default client options. + clientOptsToTry.default = clientOpts + } else { + if (haveDiagCh) { + clientOptsToTry.UndiciConnection = clientOpts } - const esServer = new MockES({ responses: mockResponses }) - esServer.start(function (esUrl) { - resetAgent( - function done (data) { + // Also test the ES client configured to use HttpConnection rather than its + // default UndiciConnection. This is relevant for Kibana that, currently, + // uses HttpConnection. + clientOptsToTry.HttpConnection = Object.assign({}, clientOpts, { Connection: es.HttpConnection }) + } + Object.keys(clientOptsToTry).forEach(clientOptsName => { + test(`context-propagation works (${clientOptsName} client options)`, function (t) { + const mockResponses = [ + { + statusCode: 200, + headers: { + 'X-elastic-product': 'Elasticsearch', + 'content-type': 'application/json' + }, + body: '{"took":0,"timed_out":false,"_shards":{"total":0,"successful":0,"skipped":0,"failed":0},"hits":{"total":{"value":0,"relation":"eq"},"max_score":0,"hits":[]}}' + } + ] + if (semver.gte(esVersion, '7.14.0') && semver.satisfies(esVersion, '7.x')) { + // First request will be "GET /" for a product check. + mockResponses.unshift({ + statusCode: 200, + headers: { + 'X-elastic-product': 'Elasticsearch', + 'content-type': 'application/json' + }, + body: '{"name":"645a066f9b52","cluster_name":"docker-cluster","cluster_uuid":"1pR-cy9dSLWO7TNxI3kodA","version":{"number":"8.0.0-beta1","build_flavor":"default","build_type":"docker","build_hash":"ba1f616138a589f12eb0c6f678aee96377525b8f","build_date":"2021-11-04T12:35:26.989068569Z","build_snapshot":false,"lucene_version":"9.0.0","minimum_wire_compatibility_version":"7.16.0","minimum_index_compatibility_version":"7.0.0"},"tagline":"You Know, for Search"}' + }) + } + const esServer = new MockES({ responses: mockResponses }) + esServer.start(function (esUrl) { + resetAgent( + function done (data) { // Assert that the ES server request for the `client.search()` is as // expected. - const searchSpan = data.spans[data.spans.length - 1] - const esServerReq = esServer.requests[esServer.requests.length - 1] - const tracestate = esServerReq.headers.tracestate - t.equal(tracestate, 'es=s:1', 'esServer request included the expected tracestate header') - t.ok(esServerReq.headers.traceparent, 'esServer request included a traceparent header') - const traceparent = TraceParent.fromString(esServerReq.headers.traceparent) - t.equal(traceparent.traceId, myTrans.traceId, 'traceparent.traceId') - // node-traceparent erroneously (IMHO) calls this field `id` instead - // of `parentId`. - t.equal(traceparent.id, searchSpan.id, 'traceparent.id') - t.end() - } - ) + const searchSpan = data.spans[data.spans.length - 1] + const esServerReq = esServer.requests[esServer.requests.length - 1] + const tracestate = esServerReq.headers.tracestate + t.equal(tracestate, 'es=s:1', 'esServer request included the expected tracestate header') + t.ok(esServerReq.headers.traceparent, 'esServer request included a traceparent header') + const traceparent = TraceParent.fromString(esServerReq.headers.traceparent) + t.equal(traceparent.traceId, myTrans.traceId, 'traceparent.traceId') + // node-traceparent erroneously (IMHO) calls this field `id` instead + // of `parentId`. + t.equal(traceparent.id, searchSpan.id, 'traceparent.id') + t.end() + } + ) - const myTrans = agent.startTransaction('myTrans') - const client = new es.Client(Object.assign( - {}, - clientOpts, - { node: esUrl } - )) - client.search({ q: 'pants' }) - .then(() => { - t.ok('client.search succeeded') - }) - .catch((err) => { - t.error(err, 'no error from client.search') - }) - .finally(() => { - myTrans.end() - agent.flush() - client.close() - esServer.close() - }) - t.ok(agent.currentSpan === null, 'no currentSpan in sync code after @elastic/elasticsearch client command') + const myTrans = agent.startTransaction('myTrans') + const client = new es.Client(Object.assign( + {}, + clientOptsToTry[clientOptsName], + { node: esUrl } + )) + client.search({ q: 'pants' }) + .then(() => { + t.ok('client.search succeeded') + }) + .catch((err) => { + t.error(err, 'no error from client.search') + }) + .finally(() => { + myTrans.end() + agent.flush() + client.close() + esServer.close() + }) + t.ok(agent.currentSpan === null, 'no currentSpan in sync code after @elastic/elasticsearch client command') + }) }) }) } @@ -802,7 +919,7 @@ function checkSpanOutcomesSuccess (t) { } } -function checkDataAndEnd (t, method, path, dbStatement, statusCode) { +function checkDataAndEnd (t, expectedName, expectedHttpUrl, expectedStatusCode, expectedDbStatement, expectedClusterName) { return function (data) { t.equal(data.transactions.length, 1, 'should have 1 transaction') const trans = data.transactions[0] @@ -828,33 +945,47 @@ function checkDataAndEnd (t, method, path, dbStatement, statusCode) { t.strictEqual(esSpan.subtype, 'elasticsearch') t.strictEqual(esSpan.action, 'request') t.strictEqual(esSpan.sync, false, 'span.sync=false') - t.equal(esSpan.name, 'Elasticsearch: ' + method + ' ' + path, 'elasticsearch span should have expected name') + t.equal(esSpan.name, 'Elasticsearch: ' + expectedName, 'elasticsearch span should have expected name') + + const expectedDb = { type: 'elasticsearch' } + if (expectedDbStatement) { expectedDb.statement = expectedDbStatement } + if (expectedClusterName) { expectedDb.instance = expectedClusterName } + t.deepEqual(esSpan.context.db, expectedDb, 'span.context.db') + + const expectedServiceTarget = { type: 'elasticsearch' } + if (expectedClusterName) { expectedServiceTarget.name = expectedClusterName } + t.deepEqual(esSpan.context.service.target, expectedServiceTarget, 'span.context.service.target') - // Iff the test case provided a `dbStatement`, then we expect `.context.db`. - if (typeof dbStatement === 'string') { - t.deepEqual(esSpan.context.db, - { type: 'elasticsearch', statement: dbStatement }, - 'elasticsearch span has correct .context.db') + const expectedDestination = { + address: host.split(':')[0], + port: port, + service: { type: '', name: '', resource: 'elasticsearch' } + } + if (expectedHttpUrl) { + const parsed = new URL(expectedHttpUrl) + expectedDestination.address = parsed.hostname + expectedDestination.port = Number(parsed.port) + } + if (expectedClusterName) { + expectedDestination.service.resource += '/' + expectedClusterName + } + t.deepEqual(esSpan.context.destination, expectedDestination, 'span.context.destination') + + if (expectedHttpUrl) { + t.equal(esSpan.context.http.url, expectedHttpUrl, 'span.context.http.url') } else { - t.notOk(esSpan.context && esSpan.context.db, 'elasticsearch span should not have .context.db') + t.notOk(esSpan.context.http && esSpan.context.http.url, 'should not have span.context.http.url') } - // Ensure "destination" context is set. - t.equal(esSpan.context.destination.service.name, 'elasticsearch', - 'elasticsearch span.context.destination.service.name=="elasticsearch"') - - // Iff the test case provided an expected `statusCode`, then we expect - // `.context.http`. The exception is with @elastic/elasticsearch >=8 - // and `asyncHooks=false` (see "Limitations" section in the instrumentation - // code). - if (statusCode !== undefined) { - if (semver.satisfies(esVersion, '>=8', { includePrerelease: true }) && - agent._conf.asyncHooks === false) { - t.comment('skip span.context.http check because of asyncHooks=false + esVersion>=8 limitation') - } else { - t.equal(esSpan.context.http.status_code, statusCode, 'context.http.status_code') - t.ok(esSpan.context.http.response.encoded_body_size, 'context.http.response.encoded_body_size is present') - } + // With @elastic/elasticsearch >=8 and `contextManager="patch"` there is + // a limitation such that some HTTP context fields cannot be captured. + // (See "Limitations" section in the instrumentation code.) + if (semver.satisfies(esVersion, '>=8', { includePrerelease: true }) && + agent._conf.contextManager === config.CONTEXT_MANAGER_PATCH) { + t.comment('skip span.context.http.{status_code,response} check because of contextManager="patch" + esVersion>=8 limitation') + } else { + t.equal(esSpan.context.http.status_code, expectedStatusCode, 'context.http.status_code') + t.ok(esSpan.context.http.response.encoded_body_size, 'context.http.response.encoded_body_size is present') } t.end() diff --git a/test/instrumentation/modules/aws-sdk/dynamodb.test.js b/test/instrumentation/modules/aws-sdk/dynamodb.test.js index 3513d1d33ef..a27a0634bb6 100644 --- a/test/instrumentation/modules/aws-sdk/dynamodb.test.js +++ b/test/instrumentation/modules/aws-sdk/dynamodb.test.js @@ -7,8 +7,7 @@ 'use strict' const agent = require('../../../..').start({ - serviceName: 'test', - secretToken: 'test', + serviceName: 'test-dynamodb', captureExceptions: false, metricsInterval: 0, centralConfig: 'none', @@ -28,14 +27,15 @@ const { getStatementFromRequest, getAddressFromRequest, getMethodFromRequest -} = - require('../../../../lib/instrumentation/modules/aws-sdk/dynamodb') +} = require('../../../../lib/instrumentation/modules/aws-sdk/dynamodb') + +const AWS_REGION = 'us-west-2' initializeAwsSdk() function initializeAwsSdk () { // SDk requires a region to be set - AWS.config.update({ region: 'us-west-2' }) + AWS.config.update({ region: AWS_REGION }) // without fake credentials the aws-sdk will attempt to fetch // credentials as though it was on an EC2 instance @@ -64,11 +64,11 @@ tape.test('AWS DynamoDB: Unit Test Functions', function (test) { const request = { service: { config: { - region: 'us-west-2' + region: AWS_REGION } } } - t.equals(getRegionFromRequest(request), 'us-west-2') + t.equals(getRegionFromRequest(request), AWS_REGION) t.equals(getRegionFromRequest({}), undefined) t.equals(getRegionFromRequest({ service: null }), null) t.equals(getRegionFromRequest({ service: { config: null } }), null) @@ -157,10 +157,21 @@ tape.test('AWS DynamoDB: End to End Test', function (test) { t.equals(span.type, 'db', 'span type correctly set') t.equals(span.subtype, 'dynamodb', 'span subtype set correctly') t.equals(span.action, 'query', 'query set correctly') - t.equals(span.context.db.statement, 'id = :foo', 'statment set in context correctly') - t.equals(span.context.destination.service.name, 'dynamodb', 'service name in destination context') + t.deepEqual(span.context.service.target, { type: 'dynamodb', name: AWS_REGION }, 'span.context.service.target') + t.deepEqual(span.context.destination, { + address: 'localhost', + port: port, + cloud: { region: AWS_REGION }, + service: { type: '', name: '', resource: `dynamodb/${AWS_REGION}` } + }, 'span.context.destination') + t.deepEqual(span.context.db, { + instance: AWS_REGION, + statement: params.KeyConditionExpression, + type: 'dynamodb' + }, 'span.context.db') t.end() }) + const port = listener.address().port AWS.config.update({ endpoint: `http://localhost:${port}` @@ -195,10 +206,20 @@ tape.test('AWS DynamoDB: End to End Test', function (test) { t.equals(span.type, 'db', 'span type correctly set') t.equals(span.subtype, 'dynamodb', 'span subtype set correctly') t.equals(span.action, 'query', 'query set correctly') - t.equals(span.context.destination.service.name, 'dynamodb', 'service name in destination context') - + t.deepEqual(span.context.service.target, { type: 'dynamodb', name: AWS_REGION }, 'span.context.service.target') + t.deepEqual(span.context.destination, { + address: 'localhost', + port: port, + cloud: { region: AWS_REGION }, + service: { type: '', name: '', resource: `dynamodb/${AWS_REGION}` } + }, 'span.context.destination') + t.deepEqual(span.context.db, { + instance: AWS_REGION, + type: 'dynamodb' + }, 'span.context.db') t.end() }) + const port = listener.address().port AWS.config.update({ endpoint: `http://localhost:${port}` diff --git a/test/instrumentation/modules/aws-sdk/s3.test.js b/test/instrumentation/modules/aws-sdk/s3.test.js index 997e49e16f0..a1a2741159a 100644 --- a/test/instrumentation/modules/aws-sdk/s3.test.js +++ b/test/instrumentation/modules/aws-sdk/s3.test.js @@ -20,6 +20,7 @@ const { execFile } = require('child_process') const tape = require('tape') const { MockAPMServer } = require('../../../_mock_apm_server') +const { validateSpan } = require('../../../_validate_schema') const LOCALSTACK_HOST = process.env.LOCALSTACK_HOST || 'localhost' const endpoint = 'http://' + LOCALSTACK_HOST + ':4566' @@ -70,6 +71,10 @@ tape.test('simple S3 usage scenario', function (t) { // Compare some common fields across all spans. const spans = events.filter(e => e.span) .map(e => e.span) + spans.forEach(s => { + const errs = validateSpan(s) + t.equal(errs, null, 'span is valid (per apm-server intake schema)') + }) t.equal(spans.filter(s => s.trace_id === tx.trace_id).length, spans.length, 'all spans have the same trace_id') t.equal(spans.filter(s => s.transaction_id === tx.id).length, @@ -99,13 +104,14 @@ tape.test('simple S3 usage scenario', function (t) { subtype: 's3', action: 'ListBuckets', context: { - http: { status_code: 200, response: { encoded_body_size: 205 } }, + service: { target: { type: 's3' } }, destination: { address: LOCALSTACK_HOST, port: 4566, - service: { name: 's3', type: 'storage' }, - cloud: { region: 'us-east-2' } - } + cloud: { region: 'us-east-2' }, + service: { type: '', name: '', resource: 's3' } + }, + http: { status_code: 200, response: { encoded_body_size: 205 } } }, outcome: 'success' }, 'listAllBuckets produced expected span') @@ -116,17 +122,14 @@ tape.test('simple S3 usage scenario', function (t) { subtype: 's3', action: 'CreateBucket', context: { - http: { status_code: 200, response: { encoded_body_size: 177 } }, + service: { target: { type: 's3', name: 'elasticapmtest-bucket-1' } }, destination: { address: LOCALSTACK_HOST, port: 4566, - service: { - name: 's3', - type: 'storage', - resource: 'elasticapmtest-bucket-1' - }, - cloud: { region: 'us-east-2' } - } + cloud: { region: 'us-east-2' }, + service: { type: '', name: '', resource: 'elasticapmtest-bucket-1' } + }, + http: { status_code: 200, response: { encoded_body_size: 177 } } }, outcome: 'success' }, 'createTheBucketIfNecessary produced expected span') @@ -137,17 +140,14 @@ tape.test('simple S3 usage scenario', function (t) { subtype: 's3', action: 'HeadBucket', context: { - http: { status_code: 200 }, + service: { target: { type: 's3', name: 'elasticapmtest-bucket-1' } }, destination: { address: LOCALSTACK_HOST, port: 4566, - service: { - name: 's3', - type: 'storage', - resource: 'elasticapmtest-bucket-1' - }, - cloud: { region: 'us-east-2' } - } + cloud: { region: 'us-east-2' }, + service: { type: '', name: '', resource: 'elasticapmtest-bucket-1' } + }, + http: { status_code: 200 } }, outcome: 'success' }, 'waitForBucketToExist produced expected span') @@ -158,17 +158,14 @@ tape.test('simple S3 usage scenario', function (t) { subtype: 's3', action: 'PutObject', context: { - http: { status_code: 200 }, + service: { target: { type: 's3', name: 'elasticapmtest-bucket-1' } }, destination: { address: LOCALSTACK_HOST, port: 4566, - service: { - name: 's3', - type: 'storage', - resource: 'elasticapmtest-bucket-1' - }, - cloud: { region: 'us-east-2' } - } + cloud: { region: 'us-east-2' }, + service: { type: '', name: '', resource: 'elasticapmtest-bucket-1' } + }, + http: { status_code: 200 } }, outcome: 'success' }, 'createObj produced expected span') @@ -179,17 +176,14 @@ tape.test('simple S3 usage scenario', function (t) { subtype: 's3', action: 'HeadObject', context: { - http: { status_code: 200 }, + service: { target: { type: 's3', name: 'elasticapmtest-bucket-1' } }, destination: { address: LOCALSTACK_HOST, port: 4566, - service: { - name: 's3', - type: 'storage', - resource: 'elasticapmtest-bucket-1' - }, - cloud: { region: 'us-east-2' } - } + cloud: { region: 'us-east-2' }, + service: { type: '', name: '', resource: 'elasticapmtest-bucket-1' } + }, + http: { status_code: 200 } }, outcome: 'success' }, 'waitForObjectToExist produced expected span') @@ -200,17 +194,14 @@ tape.test('simple S3 usage scenario', function (t) { subtype: 's3', action: 'GetObject', context: { - http: { status_code: 200, response: { encoded_body_size: 8 } }, + service: { target: { type: 's3', name: 'elasticapmtest-bucket-1' } }, destination: { address: LOCALSTACK_HOST, port: 4566, - service: { - name: 's3', - type: 'storage', - resource: 'elasticapmtest-bucket-1' - }, - cloud: { region: 'us-east-2' } - } + cloud: { region: 'us-east-2' }, + service: { type: '', name: '', resource: 'elasticapmtest-bucket-1' } + }, + http: { status_code: 200, response: { encoded_body_size: 8 } } }, outcome: 'success' }, 'getObj produced expected span') @@ -221,17 +212,14 @@ tape.test('simple S3 usage scenario', function (t) { subtype: 's3', action: 'GetObject', context: { - http: { status_code: 304 }, + service: { target: { type: 's3', name: 'elasticapmtest-bucket-1' } }, destination: { address: LOCALSTACK_HOST, port: 4566, - service: { - name: 's3', - type: 'storage', - resource: 'elasticapmtest-bucket-1' - }, - cloud: { region: 'us-east-2' } - } + cloud: { region: 'us-east-2' }, + service: { type: '', name: '', resource: 'elasticapmtest-bucket-1' } + }, + http: { status_code: 304 } }, outcome: 'success' }, 'getObjConditionalGet produced expected span') @@ -242,17 +230,14 @@ tape.test('simple S3 usage scenario', function (t) { subtype: 's3', action: 'GetObject', context: { - http: { status_code: 200, response: { encoded_body_size: 8 } }, + service: { target: { type: 's3', name: 'elasticapmtest-bucket-1' } }, destination: { address: LOCALSTACK_HOST, port: 4566, - service: { - name: 's3', - type: 'storage', - resource: 'elasticapmtest-bucket-1' - }, - cloud: { region: 'us-east-2' } - } + cloud: { region: 'us-east-2' }, + service: { type: '', name: '', resource: 'elasticapmtest-bucket-1' } + }, + http: { status_code: 200, response: { encoded_body_size: 8 } } }, outcome: 'success' }, 'getObjUsingPromise produced expected span') @@ -264,17 +249,14 @@ tape.test('simple S3 usage scenario', function (t) { subtype: 's3', action: 'GetObject', context: { - http: { status_code: 404, response: { encoded_body_size: 207 } }, + service: { target: { type: 's3', name: 'elasticapmtest-bucket-1' } }, destination: { address: LOCALSTACK_HOST, port: 4566, - service: { - name: 's3', - type: 'storage', - resource: 'elasticapmtest-bucket-1' - }, - cloud: { region: 'us-east-2' } - } + cloud: { region: 'us-east-2' }, + service: { type: '', name: '', resource: 'elasticapmtest-bucket-1' } + }, + http: { status_code: 404, response: { encoded_body_size: 207 } } }, outcome: 'failure' }, 'getObjNonExistantObject produced expected span') @@ -289,17 +271,14 @@ tape.test('simple S3 usage scenario', function (t) { subtype: 's3', action: 'DeleteObject', context: { - http: { status_code: 204 }, + service: { target: { type: 's3', name: 'elasticapmtest-bucket-1' } }, destination: { address: LOCALSTACK_HOST, port: 4566, - service: { - name: 's3', - type: 'storage', - resource: 'elasticapmtest-bucket-1' - }, - cloud: { region: 'us-east-2' } - } + cloud: { region: 'us-east-2' }, + service: { type: '', name: '', resource: 'elasticapmtest-bucket-1' } + }, + http: { status_code: 204 } }, outcome: 'success' }, 'deleteTheObj produced expected span') @@ -310,17 +289,14 @@ tape.test('simple S3 usage scenario', function (t) { subtype: 's3', action: 'DeleteBucket', context: { - http: { status_code: 204 }, + service: { target: { type: 's3', name: 'elasticapmtest-bucket-1' } }, destination: { address: LOCALSTACK_HOST, port: 4566, - service: { - name: 's3', - type: 'storage', - resource: 'elasticapmtest-bucket-1' - }, - cloud: { region: 'us-east-2' } - } + cloud: { region: 'us-east-2' }, + service: { type: '', name: '', resource: 'elasticapmtest-bucket-1' } + }, + http: { status_code: 204 } }, outcome: 'success' }, 'deleteTheBucketIfCreatedIt produced expected span') diff --git a/test/instrumentation/modules/aws-sdk/sns.test.js b/test/instrumentation/modules/aws-sdk/sns.test.js index 2811e97038d..95abce2b7c7 100644 --- a/test/instrumentation/modules/aws-sdk/sns.test.js +++ b/test/instrumentation/modules/aws-sdk/sns.test.js @@ -191,11 +191,6 @@ tape.test('AWS SNS: Unit Test Functions', function (test) { { address: 'example.com', port: 1234, - service: { - resource: 'sns/topic-name', - type: 'messaging', - name: 'sns' - }, cloud: { region: 'us-west-2' } } ) @@ -205,11 +200,6 @@ tape.test('AWS SNS: Unit Test Functions', function (test) { { address: null, port: null, - service: { - resource: 'sns/undefined', - type: 'messaging', - name: 'sns' - }, cloud: { region: null } } ) @@ -219,11 +209,6 @@ tape.test('AWS SNS: Unit Test Functions', function (test) { { address: undefined, port: undefined, - service: { - resource: 'sns/undefined', - type: 'messaging', - name: 'sns' - }, cloud: { region: undefined } } ) @@ -253,12 +238,15 @@ tape.test('AWS SNS: End to End Test', function (test) { t.equals(span.action, 'publish', 'span action set correctly') t.equals(span.sync, false, 'span.sync is false') t.equals(span.context.message.queue.name, 'topic-name') - t.equals(span.context.destination.service.resource, 'sns/topic-name') - t.equals(span.context.destination.service.type, 'messaging') - t.equals(span.context.destination.service.name, 'sns') - t.equals(span.context.destination.address, 'localhost') - t.equals(span.context.destination.port, port) - t.equals(span.context.destination.cloud.region, 'us-west-2') + t.deepEquals(span.context.service.target, + { type: 'sns', name: 'topic-name' }, + 'span.context.service.target') + t.deepEquals(span.context.destination, { + address: 'localhost', + port: port, + cloud: { region: 'us-west-2' }, + service: { type: '', name: '', resource: 'sns/topic-name' } + }, 'span.context.destination') t.end() }) @@ -303,12 +291,15 @@ tape.test('AWS SNS: End to End Test', function (test) { t.equals(span.action, 'publish', 'span action set correctly') t.equals(span.sync, false, 'span.sync is false') t.equals(span.context.message.queue.name, 'topic-name') - t.equals(span.context.destination.service.resource, 'sns/topic-name') - t.equals(span.context.destination.service.type, 'messaging') - t.equals(span.context.destination.service.name, 'sns') - t.equals(span.context.destination.address, 'localhost') - t.equals(span.context.destination.port, port) - t.equals(span.context.destination.cloud.region, 'us-west-2') + t.deepEquals(span.context.service.target, + { type: 'sns', name: 'topic-name' }, + 'span.context.service.target') + t.deepEquals(span.context.destination, { + address: 'localhost', + port: port, + cloud: { region: 'us-west-2' }, + service: { type: '', name: '', resource: 'sns/topic-name' } + }, 'span.context.destination') t.end() }) diff --git a/test/instrumentation/modules/aws-sdk/sqs.test.js b/test/instrumentation/modules/aws-sdk/sqs.test.js index d3294461449..61f0bbc8ad8 100644 --- a/test/instrumentation/modules/aws-sdk/sqs.test.js +++ b/test/instrumentation/modules/aws-sdk/sqs.test.js @@ -168,6 +168,10 @@ tape.test('AWS SQS: Unit Test Functions', function (test) { service: { config: { region: 'region-name' + }, + endpoint: { + hostname: 'example.com', + port: 1234 } }, params: { @@ -179,11 +183,8 @@ tape.test('AWS SQS: Unit Test Functions', function (test) { t.equals(getQueueNameFromRequest(request), 'bing') t.deepEquals(getMessageDestinationContextFromRequest(request), { - service: { - name: 'sqs', - resource: 'sqs/bing', - type: 'messaging' - }, + address: 'example.com', + port: 1234, cloud: { region: 'region-name' } @@ -208,7 +209,15 @@ tape.test('AWS SQS: End to End Tests', function (test) { t.equals(spanSqs.type, 'messaging', 'span type set to messaging') t.equals(spanSqs.subtype, 'sqs', 'span subtype set to sqs') t.equals(spanSqs.action, 'send', 'span action matches API method called') - t.equals(spanSqs.context.destination.service.type, 'messaging', 'messaging context set') + t.deepEqual(spanSqs.context.service.target, + { type: 'sqs', name: 'our-queue' }, + 'span.context.service.target') + t.deepEqual(spanSqs.context.destination, { + address: 'sqs.us-west.amazonaws.com', + port: 443, + cloud: { region: 'us-west' }, + service: { type: '', name: '', resource: 'sqs/our-queue' } + }, 'span.context.destination') t.equals(spanSqs.context.message.queue.name, 'our-queue', 'queue name context set') t.end() @@ -238,7 +247,15 @@ tape.test('AWS SQS: End to End Tests', function (test) { t.equals(spanSqs.type, 'messaging', 'span type set to messaging') t.equals(spanSqs.subtype, 'sqs', 'span subtype set to sqs') t.equals(spanSqs.action, 'send_batch', 'span action matches API method called') - t.equals(spanSqs.context.destination.service.type, 'messaging', 'messaging context set') + t.deepEqual(spanSqs.context.service.target, + { type: 'sqs', name: 'our-queue' }, + 'span.context.service.target') + t.deepEqual(spanSqs.context.destination, { + address: 'sqs.us-west.amazonaws.com', + port: 443, + cloud: { region: 'us-west' }, + service: { type: '', name: '', resource: 'sqs/our-queue' } + }, 'span.context.destination') t.equals(spanSqs.context.message.queue.name, 'our-queue', 'queue name context set') t.end() @@ -267,7 +284,15 @@ tape.test('AWS SQS: End to End Tests', function (test) { t.equals(spanSqs.type, 'messaging', 'span type set to messaging') t.equals(spanSqs.subtype, 'sqs', 'span subtype set to sqs') t.equals(spanSqs.action, 'delete', 'span action matches API method called') - t.equals(spanSqs.context.destination.service.type, 'messaging', 'messaging context set') + t.deepEqual(spanSqs.context.service.target, + { type: 'sqs', name: 'our-queue' }, + 'span.context.service.target') + t.deepEqual(spanSqs.context.destination, { + address: 'sqs.us-west.amazonaws.com', + port: 443, + cloud: { region: 'us-west' }, + service: { type: '', name: '', resource: 'sqs/our-queue' } + }, 'span.context.destination') t.equals(spanSqs.context.message.queue.name, 'our-queue', 'queue name context set') t.end() @@ -296,7 +321,15 @@ tape.test('AWS SQS: End to End Tests', function (test) { t.equals(spanSqs.type, 'messaging', 'span type set to messaging') t.equals(spanSqs.subtype, 'sqs', 'span subtype set to sqs') t.equals(spanSqs.action, 'delete_batch', 'span action matches API method called') - t.equals(spanSqs.context.destination.service.type, 'messaging', 'messaging context set') + t.deepEqual(spanSqs.context.service.target, + { type: 'sqs', name: 'our-queue' }, + 'span.context.service.target') + t.deepEqual(spanSqs.context.destination, { + address: 'sqs.us-west.amazonaws.com', + port: 443, + cloud: { region: 'us-west' }, + service: { type: '', name: '', resource: 'sqs/our-queue' } + }, 'span.context.destination') t.equals(spanSqs.context.message.queue.name, 'our-queue', 'queue name context set') t.end() @@ -325,7 +358,15 @@ tape.test('AWS SQS: End to End Tests', function (test) { t.equals(spanSqs.type, 'messaging', 'span type set to messaging') t.equals(spanSqs.subtype, 'sqs', 'span subtype set to sqs') t.equals(spanSqs.action, 'poll', 'span action matches API method called') - t.equals(spanSqs.context.destination.service.type, 'messaging', 'messaging context set') + t.deepEqual(spanSqs.context.service.target, + { type: 'sqs', name: 'our-queue' }, + 'span.context.service.target') + t.deepEqual(spanSqs.context.destination, { + address: 'sqs.us-west.amazonaws.com', + port: 443, + cloud: { region: 'us-west' }, + service: { type: '', name: '', resource: 'sqs/our-queue' } + }, 'span.context.destination') t.equals(spanSqs.context.message.queue.name, 'our-queue', 'queue name context set') t.end() @@ -409,7 +450,15 @@ tape.test('AWS SQS: End to End Tests', function (test) { t.equals(spanSqs.type, 'messaging', 'span type set to messaging') t.equals(spanSqs.subtype, 'sqs', 'span subtype set to sqs') t.equals(spanSqs.action, 'send', 'span action matches API method called') - t.equals(spanSqs.context.destination.service.type, 'messaging', 'messaging context set') + t.deepEqual(spanSqs.context.service.target, + { type: 'sqs', name: 'our-queue' }, + 'span.context.service.target') + t.deepEqual(spanSqs.context.destination, { + address: 'sqs.us-west.amazonaws.com', + port: 443, + cloud: { region: 'us-west' }, + service: { type: '', name: '', resource: 'sqs/our-queue' } + }, 'span.context.destination') t.equals(spanSqs.context.message.queue.name, 'our-queue', 'queue name context set') t.end() @@ -447,7 +496,15 @@ tape.test('AWS SQS: End to End Tests', function (test) { t.equals(spanSqs.type, 'messaging', 'span type set to messaging') t.equals(spanSqs.subtype, 'sqs', 'span subtype set to sqs') t.equals(spanSqs.action, 'send_batch', 'span action matches API method called') - t.equals(spanSqs.context.destination.service.type, 'messaging', 'messaging context set') + t.deepEqual(spanSqs.context.service.target, + { type: 'sqs', name: 'our-queue' }, + 'span.context.service.target') + t.deepEqual(spanSqs.context.destination, { + address: 'sqs.us-west.amazonaws.com', + port: 443, + cloud: { region: 'us-west' }, + service: { type: '', name: '', resource: 'sqs/our-queue' } + }, 'span.context.destination') t.equals(spanSqs.context.message.queue.name, 'our-queue', 'queue name context set') t.end() @@ -480,7 +537,15 @@ tape.test('AWS SQS: End to End Tests', function (test) { t.equals(spanSqs.type, 'messaging', 'span type set to messaging') t.equals(spanSqs.subtype, 'sqs', 'span subtype set to sqs') t.equals(spanSqs.action, 'delete', 'span action matches API method called') - t.equals(spanSqs.context.destination.service.type, 'messaging', 'messaging context set') + t.deepEqual(spanSqs.context.service.target, + { type: 'sqs', name: 'our-queue' }, + 'span.context.service.target') + t.deepEqual(spanSqs.context.destination, { + address: 'sqs.us-west.amazonaws.com', + port: 443, + cloud: { region: 'us-west' }, + service: { type: '', name: '', resource: 'sqs/our-queue' } + }, 'span.context.destination') t.equals(spanSqs.context.message.queue.name, 'our-queue', 'queue name context set') t.end() @@ -514,7 +579,15 @@ tape.test('AWS SQS: End to End Tests', function (test) { t.equals(spanSqs.type, 'messaging', 'span type set to messaging') t.equals(spanSqs.subtype, 'sqs', 'span subtype set to sqs') t.equals(spanSqs.action, 'delete_batch', 'span action matches API method called') - t.equals(spanSqs.context.destination.service.type, 'messaging', 'messaging context set') + t.deepEqual(spanSqs.context.service.target, + { type: 'sqs', name: 'our-queue' }, + 'span.context.service.target') + t.deepEqual(spanSqs.context.destination, { + address: 'sqs.us-west.amazonaws.com', + port: 443, + cloud: { region: 'us-west' }, + service: { type: '', name: '', resource: 'sqs/our-queue' } + }, 'span.context.destination') t.equals(spanSqs.context.message.queue.name, 'our-queue', 'queue name context set') t.end() @@ -548,7 +621,15 @@ tape.test('AWS SQS: End to End Tests', function (test) { t.equals(spanSqs.type, 'messaging', 'span type set to messaging') t.equals(spanSqs.subtype, 'sqs', 'span subtype set to sqs') t.equals(spanSqs.action, 'poll', 'span action matches API method called') - t.equals(spanSqs.context.destination.service.type, 'messaging', 'messaging context set') + t.deepEqual(spanSqs.context.service.target, + { type: 'sqs', name: 'our-queue' }, + 'span.context.service.target') + t.deepEqual(spanSqs.context.destination, { + address: 'sqs.us-west.amazonaws.com', + port: 443, + cloud: { region: 'us-west' }, + service: { type: '', name: '', resource: 'sqs/our-queue' } + }, 'span.context.destination') t.equals(spanSqs.context.message.queue.name, 'our-queue', 'queue name context set') t.deepEqual(spanSqs.links, [{ trace_id: '460d51b6ed3ab96be45f2580b8016509', diff --git a/test/instrumentation/modules/cassandra-driver/_utils.js b/test/instrumentation/modules/cassandra-driver/_utils.js index 240bbb4de0b..1292065aeb8 100644 --- a/test/instrumentation/modules/cassandra-driver/_utils.js +++ b/test/instrumentation/modules/cassandra-driver/_utils.js @@ -6,6 +6,7 @@ 'use strict' +const assert = require('assert') const cassandra = require('cassandra-driver') const defaultOptions = { @@ -14,9 +15,11 @@ const defaultOptions = { } function maybeInitialize (options) { + options = options || {} if (!options.keyspace) { return Promise.resolve() } + assert(options.table, 'makeClient options must include "table" if "keyspace" is provided') const keyspace = options.keyspace const query1 = ` @@ -26,7 +29,7 @@ function maybeInitialize (options) { }; ` const query2 = ` - CREATE TABLE IF NOT EXISTS ${keyspace}.${keyspace}(id uuid,text varchar,PRIMARY KEY(id)); + CREATE TABLE IF NOT EXISTS ${keyspace}.${options.table}(id uuid,text varchar,PRIMARY KEY(id)); ` const client = new cassandra.Client(defaultOptions) @@ -42,11 +45,18 @@ function maybeInitialize (options) { }) } -module.exports = function makeClient (t, opts) { - const options = Object.assign({}, defaultOptions, opts) +/** + * Return a promise for a Cassandra client. + * + * Optionally `opts.keyspace` and `opts.table` can be provided to initialize a + * keyspace and table for testing. The caller should provide neither option, or + * both. + */ +function makeClient (t, opts) { + const cassOpts = Object.assign({}, defaultOptions, { keyspace: opts && opts.keyspace }) - return maybeInitialize(options).then(() => { - const client = new cassandra.Client(options) + return maybeInitialize(opts).then(() => { + const client = new cassandra.Client(cassOpts) t.on('end', () => { client.shutdown() @@ -55,3 +65,7 @@ module.exports = function makeClient (t, opts) { return client }) } + +module.exports = { + makeClient +} diff --git a/test/instrumentation/modules/cassandra-driver/index.test.js b/test/instrumentation/modules/cassandra-driver/index.test.js index 811a9031e30..5ff13471b93 100644 --- a/test/instrumentation/modules/cassandra-driver/index.test.js +++ b/test/instrumentation/modules/cassandra-driver/index.test.js @@ -19,7 +19,7 @@ const semver = require('semver') const test = require('tape') const version = require('cassandra-driver/package.json').version -const makeClient = require('./_utils') +const { makeClient } = require('./_utils') const mockClient = require('../../../_mock_http_client') const hasPromises = semver.satisfies(version, '>=3.2') @@ -88,7 +88,9 @@ test('execute - callback', function (t) { if (hasPromises) { test('batch - promise', function (t) { - const sql = 'INSERT INTO test (id, text) VALUES (uuid(), ?)' + const keyspace = 'mykeyspace' + const table = 'myTable' + const sql = `INSERT INTO ${table} (id, text) VALUES (uuid(), ?)` const summary = 'Cassandra: Batch query' resetAgent(3, function (data) { @@ -97,9 +99,9 @@ if (hasPromises) { const trans = data.transactions[0] t.strictEqual(trans.name, 'foo', 'transaction name') - assertConnectSpan(t, data.spans[0]) + assertConnectSpan(t, data.spans[0], keyspace) const joined = `${sql};\n${sql}` - assertSpan(t, joined, summary, data.spans[1]) + assertSpan(t, data.spans[1], joined, summary, keyspace) t.end() }) @@ -109,7 +111,7 @@ if (hasPromises) { { query: sql, params: ['bar'] } ] - makeClient(t, { keyspace: 'test' }).then(client => { + makeClient(t, { keyspace, table }).then(client => { agent.startTransaction('foo') assertPromise(t, client.batch(queries)) @@ -119,7 +121,9 @@ if (hasPromises) { } test('batch - callback', function (t) { - const sql = 'INSERT INTO test (id, text) VALUES (uuid(), ?)' + const keyspace = 'mykeyspace' + const table = 'myTable' + const sql = `INSERT INTO ${table} (id, text) VALUES (uuid(), ?)` const summary = 'Cassandra: Batch query' resetAgent(3, function (data) { @@ -128,9 +132,9 @@ test('batch - callback', function (t) { const trans = data.transactions[0] t.strictEqual(trans.name, 'foo', 'transaction name') - assertConnectSpan(t, data.spans[0]) + assertConnectSpan(t, data.spans[0], keyspace) const joined = `${sql};\n${sql}` - assertSpan(t, joined, summary, data.spans[1]) + assertSpan(t, data.spans[1], joined, summary, keyspace) t.end() }) @@ -140,7 +144,7 @@ test('batch - callback', function (t) { { query: sql, params: ['bar'] } ] - makeClient(t, { keyspace: 'test' }).then(client => { + makeClient(t, { keyspace, table }).then(client => { agent.startTransaction('foo') client.batch(queries, assertCallback(t, function (err) { @@ -228,25 +232,56 @@ function assertBasicQuery (t, sql, summary, data) { t.strictEqual(trans.name, 'foo', 'transaction name') assertConnectSpan(t, data.spans[0]) - assertSpan(t, sql, summary, data.spans[1]) + assertSpan(t, data.spans[1], sql, summary) } -function assertConnectSpan (t, span) { +function assertConnectSpan (t, span, keyspace) { t.strictEqual(span.name, 'Cassandra: Connect', 'span name') t.strictEqual(span.type, 'db', 'span type') t.strictEqual(span.subtype, 'cassandra', 'span subtype') t.strictEqual(span.action, 'connect', 'span action') + if (keyspace) { + t.deepEqual(span.context.db, { type: 'cassandra', instance: keyspace }, 'span.context.db') + t.deepEqual(span.context.service.target, { type: 'cassandra', name: keyspace }, 'span.context.service.target') + t.deepEqual(span.context.destination, { + service: { type: '', name: '', resource: `cassandra/${keyspace}` } + }, 'span.context.destination') + } else { + t.deepEqual(span.context.db, { type: 'cassandra' }, 'span.context.db') + t.deepEqual(span.context.service.target, { type: 'cassandra' }, 'span.context.service.target') + t.deepEqual(span.context.destination, { + service: { type: '', name: '', resource: 'cassandra' } + }, 'span.context.destination') + } } -function assertSpan (t, sql, summary, span) { +function assertSpan (t, span, sql, summary, keyspace) { t.strictEqual(span.name, summary, 'span name') t.strictEqual(span.type, 'db', 'span type') t.strictEqual(span.subtype, 'cassandra', 'span subtype') t.strictEqual(span.action, 'query', 'span action') - t.deepEqual(span.context.db, { - statement: sql, - type: 'cassandra' - }, 'database context') + if (keyspace) { + t.deepEqual(span.context.db, { + type: 'cassandra', + statement: sql, + instance: keyspace + }, 'span.context.db') + t.deepEqual(span.context.service.target, + { type: 'cassandra', name: keyspace }, + 'span.context.service.target') + t.deepEqual(span.context.destination, { + service: { type: '', name: '', resource: `cassandra/${keyspace}` } + }, 'span.context.destination') + } else { + t.deepEqual(span.context.db, { + type: 'cassandra', + statement: sql + }, 'span.context.db') + t.deepEqual(span.context.service.target, { type: 'cassandra' }, 'span.context.service.target') + t.deepEqual(span.context.destination, { + service: { type: '', name: '', resource: 'cassandra' } + }, 'span.context.destination') + } } function resetAgent (expected, cb) { diff --git a/test/instrumentation/modules/elasticsearch.test.js b/test/instrumentation/modules/elasticsearch.test.js index a8a96d3bb9b..2440f3a9582 100644 --- a/test/instrumentation/modules/elasticsearch.test.js +++ b/test/instrumentation/modules/elasticsearch.test.js @@ -6,14 +6,11 @@ 'use strict' -const { pathIsAQuery } = require('../../../lib/instrumentation/elasticsearch-shared') - process.env.ELASTIC_APM_TEST = true var host = (process.env.ES_HOST || 'localhost') + ':9200' var agent = require('../../..').start({ - serviceName: 'test', - secretToken: 'test', + serviceName: 'test-elasticsearch-legacy-client', captureExceptions: false, metricsInterval: 0, centralConfig: false, @@ -31,7 +28,7 @@ var mockClient = require('../../_mock_http_client') var findObjInArray = require('../../_utils').findObjInArray test('client.ping with callback', function userLandCode (t) { - resetAgent(done(t, 'HEAD', '/')) + resetAgent(assertApmDataAndEnd(t, 'HEAD /', `http://${host}/`)) agent.startTransaction('foo') @@ -46,7 +43,7 @@ test('client.ping with callback', function userLandCode (t) { }) test('client.ping with promise', function userLandCode (t) { - resetAgent(done(t, 'HEAD', '/')) + resetAgent(assertApmDataAndEnd(t, 'HEAD /', `http://${host}/`)) agent.startTransaction('foo') @@ -62,7 +59,7 @@ test('client.ping with promise', function userLandCode (t) { }) test('client.search with callback', function userLandCode (t) { - resetAgent(done(t, 'POST', '/_search', 'q=pants')) + resetAgent(assertApmDataAndEnd(t, 'POST /_search', `http://${host}/_search?q=pants`)) agent.startTransaction('foo') @@ -78,7 +75,7 @@ test('client.search with callback', function userLandCode (t) { }) test('client.search with abort', function userLandCode (t) { - resetAgent(done(t, 'POST', '/_search', 'q=pants')) + resetAgent(assertApmDataAndEnd(t, 'POST /_search', `http://${host}/_search?q=pants`)) agent.startTransaction('foo') @@ -110,7 +107,12 @@ if (semver.satisfies(pkg.version, '>= 10')) { } } - resetAgent(done(t, 'POST', '/_search/template', JSON.stringify(body))) + resetAgent(assertApmDataAndEnd( + t, + 'POST /_search/template', + `http://${host}/_search/template`, + JSON.stringify(body) + )) agent.startTransaction('foo') @@ -140,7 +142,7 @@ if (semver.satisfies(pkg.version, '>= 13')) { var statement = body.map(JSON.stringify).join('\n') + '\n' - resetAgent(done(t, 'POST', '/_msearch', statement)) + resetAgent(assertApmDataAndEnd(t, 'POST /_msearch', `http://${host}/_msearch`, statement)) agent.startTransaction('foo') @@ -173,7 +175,7 @@ if (semver.satisfies(pkg.version, '>= 13')) { var statement = body.map(JSON.stringify).join('\n') + '\n' - resetAgent(done(t, 'POST', '/_msearch/template', statement)) + resetAgent(assertApmDataAndEnd(t, 'POST /_msearch/template', `http://${host}/_msearch/template`, statement)) agent.startTransaction('foo') @@ -189,7 +191,7 @@ if (semver.satisfies(pkg.version, '>= 13')) { } test('client.count with callback', function userLandCode (t) { - resetAgent(done(t, 'POST', '/_count', '')) + resetAgent(assertApmDataAndEnd(t, 'POST /_count', `http://${host}/_count`)) agent.startTransaction('foo') @@ -203,7 +205,7 @@ test('client.count with callback', function userLandCode (t) { }) test('client with host=', function userLandCode (t) { - resetAgent(done(t, 'HEAD', '/')) + resetAgent(assertApmDataAndEnd(t, 'HEAD /', `http://${host}/`)) agent.startTransaction('foo') var client = new elasticsearch.Client({ host: [host] }) client.ping(function (err) { @@ -215,7 +217,7 @@ test('client with host=', function userLandCode (t) { }) test('client with hosts=', function userLandCode (t) { - resetAgent(done(t, 'HEAD', '/')) + resetAgent(assertApmDataAndEnd(t, 'HEAD /', `http://${host}/`)) agent.startTransaction('foo') var client = new elasticsearch.Client({ hosts: [host, host] }) client.ping(function (err) { @@ -227,7 +229,7 @@ test('client with hosts=', function userLandCode (t) { }) test('client with hosts="http://host:port"', function userLandCode (t) { - resetAgent(done(t, 'HEAD', '/')) + resetAgent(assertApmDataAndEnd(t, 'HEAD /', `http://${host}/`)) agent.startTransaction('foo') let hostWithProto = host if (!hostWithProto.startsWith('http')) { @@ -242,7 +244,22 @@ test('client with hosts="http://host:port"', function userLandCode (t) { t.ok(agent.currentSpan === null, 'no currentSpan in sync code after elasticsearch client command') }) -function done (t, method, path, query) { +test('client with host=', function userLandCode (t) { + resetAgent(assertApmDataAndEnd(t, 'HEAD /', `http://${host}/`)) + agent.startTransaction('foo') + const [hostname, port] = host.split(':') + var client = new elasticsearch.Client({ + host: [{ host: hostname, port: port }] + }) + client.ping(function (err) { + t.error(err) + agent.endTransaction() + agent.flush() + }) + t.ok(agent.currentSpan === null, 'no currentSpan in sync code after elasticsearch client command') +}) + +function assertApmDataAndEnd (t, expectedName, expectedHttpUrl, expectedDbStatement) { return function (data, cb) { t.strictEqual(data.transactions.length, 1, 'should have 1 transaction') t.strictEqual(data.spans.length, 1, 'should have 1 span') @@ -261,26 +278,32 @@ function done (t, method, path, query) { t.strictEqual(span.subtype, subtype) t.strictEqual(span.action, action) - t.strictEqual(span.name, 'Elasticsearch: ' + method + ' ' + path) + t.strictEqual(span.name, 'Elasticsearch: ' + expectedName) t.ok(span.stacktrace.some(function (frame) { return frame.function === 'userLandCode' }), 'include user-land code frame') - if (pathIsAQuery.test(path)) { - t.deepEqual(span.context.db, { statement: query, type: 'elasticsearch' }) + if (expectedDbStatement) { + t.deepEqual(span.context.db, { type: 'elasticsearch', statement: expectedDbStatement }, 'span.context.db') + } else { + t.deepEqual(span.context.db, { type: 'elasticsearch' }, 'span.context.db') + } + + if (expectedHttpUrl) { + t.equal(span.context.http.url, expectedHttpUrl, 'span.context.http.url') } else { - t.notOk(span.context.db, 'span should not have "context.db"') + t.notOk(span.context.http && span.context.http.url, 'should not have span.context.http.url') } + t.deepEqual(span.context.service.target, { type: 'elasticsearch' }, 'span.context.service.target') + const [address, port] = host.split(':') t.deepEqual(span.context.destination, { - service: { - name: 'elasticsearch', resource: 'elasticsearch', type: 'db' - }, + address, port: Number(port), - address - }) + service: { type: '', name: '', resource: 'elasticsearch' } + }, 'span.context.destination') t.end() } diff --git a/test/instrumentation/modules/graphql.test.js b/test/instrumentation/modules/graphql.test.js index c108bfcfea0..a9a71a5c49f 100644 --- a/test/instrumentation/modules/graphql.test.js +++ b/test/instrumentation/modules/graphql.test.js @@ -26,7 +26,11 @@ var test = require('tape') var mockClient = require('../../_mock_http_client') -if (semver.lt(graphqlVer, '16.0.0')) { +// See explanation of these in "lib/instrumentation/modules/graphql.js". +const onlySupportsPositionalArgs = semver.lt(graphqlVer, '0.10.0') +const onlySupportsSingleArg = semver.gte(graphqlVer, '16.0.0') + +if (!onlySupportsSingleArg) { // graphql@16 dropped support for positional arguments. test('graphql.graphql(...) - positional args', function (t) { resetAgent(done(t)) @@ -51,27 +55,29 @@ if (semver.lt(graphqlVer, '16.0.0')) { }) } -test('graphql.graphql(...) - single GraphQLArgs arg', function (t) { - resetAgent(done(t)) +if (!onlySupportsPositionalArgs) { + test('graphql.graphql(...) - single GraphQLArgs arg', function (t) { + resetAgent(done(t)) - var schema = graphql.buildSchema('type Query { hello: String }') - var rootValue = { - hello () { - return 'Hello world!' + var schema = graphql.buildSchema('type Query { hello: String }') + var rootValue = { + hello () { + return 'Hello world!' + } } - } - var query = '{ hello }' + var query = '{ hello }' - agent.startTransaction('foo') + agent.startTransaction('foo') - graphql.graphql({ schema, source: query, rootValue }).then(function (response) { - t.ok(agent.currentSpan === null, 'no currentSpan .graphql().then(...)') - agent.endTransaction() - t.deepLooseEqual(response, { data: { hello: 'Hello world!' } }) - agent.flush() + graphql.graphql({ schema, source: query, rootValue }).then(function (response) { + t.ok(agent.currentSpan === null, 'no currentSpan .graphql().then(...)') + agent.endTransaction() + t.deepLooseEqual(response, { data: { hello: 'Hello world!' } }) + agent.flush() + }) + t.ok(agent.currentSpan === null, 'no currentSpan in sync code after .graphql(...)') }) - t.ok(agent.currentSpan === null, 'no currentSpan in sync code after .graphql(...)') -}) +} test('graphql.graphql - invalid query', function (t) { resetAgent(done(t, 'Unknown Query')) @@ -86,7 +92,7 @@ test('graphql.graphql - invalid query', function (t) { agent.startTransaction('foo') - graphql.graphql({ schema, source: query, rootValue }).then(function (response) { + graphql.graphql(...buildGraphqlArgs({ schema, source: query, rootValue })).then(function (response) { t.ok(agent.currentSpan === null, 'no currentSpan .graphql().then(...)') agent.endTransaction() t.deepEqual(Object.keys(response), ['errors']) @@ -120,14 +126,14 @@ test('graphql.graphql - transaction ended', function (t) { agent.startTransaction('foo').end() - graphql.graphql({ schema, source: query, rootValue }).then(function (response) { + graphql.graphql(...buildGraphqlArgs({ schema, source: query, rootValue })).then(function (response) { t.ok(agent.currentSpan === null, 'no currentSpan .graphql().then(...)') t.deepLooseEqual(response, { data: { hello: 'Hello world!' } }) }) t.ok(agent.currentSpan === null, 'no currentSpan in sync code after .graphql(...)') }) -if (semver.lt(graphqlVer, '16.0.0')) { +if (!onlySupportsSingleArg) { // graphql@16 dropped support for positional arguments. test('graphql.execute(...) - positional args', function (t) { resetAgent(done(t)) @@ -179,41 +185,43 @@ test('graphql.execute - transaction ended', function (t) { agent.startTransaction('foo').end() - graphql.execute({ schema, document, rootValue }).then(function (response) { + graphql.execute(...buildExecuteArgs({ schema, document, rootValue })).then(function (response) { t.ok(agent.currentSpan === null, 'no currentSpan .execute().then(...)') t.deepLooseEqual(response, { data: { hello: 'Hello world!' } }) }) t.ok(agent.currentSpan === null, 'no currentSpan in sync code after .execute(...)') }) -test('graphql.execute(...) - single ExecutionArgs arg', function (t) { - resetAgent(done(t)) +if (!onlySupportsPositionalArgs) { + test('graphql.execute(...) - single ExecutionArgs arg', function (t) { + resetAgent(done(t)) - var schema = graphql.buildSchema('type Query { hello: String }') - var rootValue = { - hello () { - return Promise.resolve('Hello world!') + var schema = graphql.buildSchema('type Query { hello: String }') + var rootValue = { + hello () { + return Promise.resolve('Hello world!') + } + } + var query = '{ hello }' + var source = new graphql.Source(query) + var documentAST = graphql.parse(source) + var args = { + schema: schema, + document: documentAST, + rootValue: rootValue } - } - var query = '{ hello }' - var source = new graphql.Source(query) - var documentAST = graphql.parse(source) - var args = { - schema: schema, - document: documentAST, - rootValue: rootValue - } - agent.startTransaction('foo') + agent.startTransaction('foo') - graphql.execute(args).then(function (response) { - t.ok(agent.currentSpan === null, 'no currentSpan .execute().then(...)') - agent.endTransaction() - t.deepLooseEqual(response, { data: { hello: 'Hello world!' } }) - agent.flush() + graphql.execute(args).then(function (response) { + t.ok(agent.currentSpan === null, 'no currentSpan .execute().then(...)') + agent.endTransaction() + t.deepLooseEqual(response, { data: { hello: 'Hello world!' } }) + agent.flush() + }) + t.ok(agent.currentSpan === null, 'no currentSpan in sync code after .execute(...)') }) - t.ok(agent.currentSpan === null, 'no currentSpan in sync code after .execute(...)') -}) +} if (semver.satisfies(graphqlVer, '>=0.12')) { test('graphql.execute sync', function (t) { @@ -231,7 +239,7 @@ if (semver.satisfies(graphqlVer, '>=0.12')) { agent.startTransaction('foo') - var response = graphql.execute({ schema, document, rootValue }) + var response = graphql.execute(...buildExecuteArgs({ schema, document, rootValue })) t.ok(agent.currentSpan === null, 'no currentSpan in sync code after .execute(...)') agent.endTransaction() @@ -264,6 +272,41 @@ function done (t, spanNameSuffix) { } } +// Take the modern (single object argument) calling signature for +// `graphql.graphql()` and return an arguments array that can be used to +// call it with whatever the appropriate call signature is for the current +// graphql version. +function buildGraphqlArgs (args) { + if (onlySupportsPositionalArgs) { + const { + schema, + source, + rootValue, + contextValue, + variableValues, + operationName, + fieldResolver, + typeResolver + } = args + return [schema, source, rootValue, contextValue, variableValues, operationName, fieldResolver, typeResolver].filter(a => a !== undefined) + } else { + return [args] + } +} + +// Take the modern (single object argument) calling signature for +// `graphql.execute()` and return an arguments array that can be used to +// call it with whatever the appropriate call signature is for the current +// graphql version. +function buildExecuteArgs (args) { + if (onlySupportsPositionalArgs) { + const { schema, document, variableValues, rootValue } = args + return [schema, document, variableValues, rootValue].filter(a => a !== undefined) + } else { + return [args] + } +} + function resetAgent (expected, cb) { if (typeof executed === 'function') return resetAgent(2, expected) agent._instrumentation.testReset() diff --git a/test/instrumentation/modules/http/http-run-context.test.js b/test/instrumentation/modules/http/http-run-context.test.js index 70ce8f0e985..a8be58ce66f 100644 --- a/test/instrumentation/modules/http/http-run-context.test.js +++ b/test/instrumentation/modules/http/http-run-context.test.js @@ -95,9 +95,11 @@ cases.forEach(c => { ELASTIC_APM_SERVER_URL: serverUrl }) }, - function done (err, _stdout, _stderr) { + function done (err, stdout, stderr) { t.error(err, `${scriptPath} exited non-zero`) if (err) { + t.comment(`${scriptPath} stdout:\n${stdout}\n`) + t.comment(`${scriptPath} stderr:\n${stderr}\n`) t.comment('skip checks because script errored out') } else { c.check(t, server.events) diff --git a/test/instrumentation/modules/http/ignore-url-does-not-leak-trans.test.js b/test/instrumentation/modules/http/ignore-url-does-not-leak-trans.test.js index 85ce81b576c..f21adc0fc28 100644 --- a/test/instrumentation/modules/http/ignore-url-does-not-leak-trans.test.js +++ b/test/instrumentation/modules/http/ignore-url-does-not-leak-trans.test.js @@ -27,8 +27,10 @@ const apm = require('../../../..').start({ } }) -if (Number(process.versions.node.split('.')[0]) <= 8 && !apm._conf.asyncHooks) { - // With node v8 and asyncHooks=false, i.e. relying on patch-async.js, we +const config = require('../../../../lib/config') +if (Number(process.versions.node.split('.')[0]) <= 8 && + apm._conf.contextManager === config.CONTEXT_MANAGER_PATCH) { + // With node v8 and contextManager="patch", i.e. relying on patch-async.js, we // do not support this test as written. Given node v8 support *and* arguably // patch-async.js support are near EOL, it isn't worth rewriting this test // case. @@ -41,7 +43,7 @@ if (Number(process.versions.node.split('.')[0]) <= 8 && !apm._conf.asyncHooks) { // instead of `process.nextTick`. patch-async.js is only able to patch the // latter. This means a missed patch of "emitListeningNT" used to emit // the server "listening" event, and context loss for `onListen()` below. - console.log('# SKIP node <=8 and asyncHooks=false loses run context for server.listen callback') + console.log('# SKIP node <=8 and contextManager="patch" loses run context for server.listen callback') process.exit() } diff --git a/test/instrumentation/modules/http/node-prefixed-http-require.test.js b/test/instrumentation/modules/http/node-prefixed-http-require.test.js new file mode 100644 index 00000000000..8178b8e58d1 --- /dev/null +++ b/test/instrumentation/modules/http/node-prefixed-http-require.test.js @@ -0,0 +1,61 @@ +/* + * Copyright Elasticsearch B.V. and other contributors where applicable. + * Licensed under the BSD 2-Clause License; you may not use this file except in + * compliance with the BSD 2-Clause License. + */ + +'use strict' + +// Test that instrumentation of core modules works when required with the +// 'node:' prefix. + +const { CapturingTransport } = require('../../../_capturing_transport') + +const apm = require('../../../..').start({ + serviceName: 'test-node-prefixed-http-require', + captureExceptions: false, + metricsInterval: 0, + centralConfig: false, + cloudProvider: 'none', + transport () { + return new CapturingTransport() + } +}) + +try { + var http = require('node:http') +} catch (_requireErr) { + console.log(`# SKIP node ${process.version} doesn't support require('node:...')`) + process.exit() +} + +const test = require('tape') +const { findObjInArray } = require('../../../_utils') + +test('node:http instrumentation works', function (t) { + var server = http.createServer(function (req, res) { + res.end('pong') + }) + + server.listen(function onListen () { + const aTrans = apm.startTransaction('aTrans', 'manual') + const port = server.address().port + const url = 'http://localhost:' + port + http.get(url, function (res) { + res.resume() + res.on('end', function () { + aTrans.end() + server.close() + apm.flush(() => { + const aTrans_ = findObjInArray(apm._transport.transactions, 'name', 'aTrans') + const httpClientSpan = findObjInArray(apm._transport.spans, 'name', `GET localhost:${port}`) + const httpServerTrans = findObjInArray(apm._transport.transactions, 'type', 'request') + t.ok(aTrans_ && httpClientSpan && httpServerTrans, 'received the expected trace objs') + t.equal(httpClientSpan.parent_id, aTrans_.id, 'http client span is a child of the manual trans') + t.equal(httpServerTrans.parent_id, httpClientSpan.id, 'http server trans is a child of the http client span') + t.end() + }) + }) + }) + }) +}) diff --git a/test/instrumentation/modules/http/outgoing.test.js b/test/instrumentation/modules/http/outgoing.test.js index 45ed9966b73..5ace7dc2c0d 100644 --- a/test/instrumentation/modules/http/outgoing.test.js +++ b/test/instrumentation/modules/http/outgoing.test.js @@ -188,15 +188,19 @@ function echoTest (type, opts, handler) { status_code: 200, url: `${type}://localhost:${port}/` }) + t.deepEqual(data.spans[0].context.service.target, { + type: 'http', + name: `localhost:${port}` + }, 'span.context.service.target') t.deepEqual(data.spans[0].context.destination, { service: { - name: `${type}://localhost:${port}`, - resource: `localhost:${port}`, - type: data.spans[0].type + type: '', + name: '', + resource: `localhost:${port}` }, address: 'localhost', port: Number(port) - }) + }, 'span.context.destination') t.end() cp.kill() }) @@ -253,15 +257,19 @@ function abortTest (type, handler) { t.deepEqual(data.spans[0].context.http, httpContext) if (httpContext.url) { + t.deepEqual(data.spans[0].context.service.target, { + type: 'http', + name: `localhost:${port}` + }, 'span.context.service.target') t.deepEqual(data.spans[0].context.destination, { service: { - name: `${type}://localhost:${port}`, - resource: `localhost:${port}`, - type: data.spans[0].type + type: '', + name: '', + resource: `localhost:${port}` }, address: 'localhost', port: Number(port) - }) + }, 'span.context.destination') } t.end() cp.kill() diff --git a/test/instrumentation/modules/http2.test.js b/test/instrumentation/modules/http2.test.js index 13d475c5849..074dac16906 100644 --- a/test/instrumentation/modules/http2.test.js +++ b/test/instrumentation/modules/http2.test.js @@ -335,7 +335,7 @@ isSecure.forEach(secure => { }) test(`http2.request${secure ? ' secure' : ' '}`, t => { - t.plan(38) + t.plan(39) resetAgent(3, (data) => { t.strictEqual(data.transactions.length, 2) @@ -357,16 +357,20 @@ isSecure.forEach(secure => { method: 'GET', status_code: 200, url: `http${secure ? 's' : ''}://localhost:${port}/sub` - }) + }, 'span.context.http') t.deepEqual(span.context.destination, { service: { - name: `http${secure ? 's' : ''}://localhost:${port}`, - resource: `localhost:${port}`, - type: span.type + type: '', + name: '', + resource: `localhost:${port}` }, address: 'localhost', port - }) + }, 'span.context.destination') + t.deepEqual(span.context.service.target, { + type: 'http', + name: `localhost:${port}` + }, 'span.context.service.target') server.close() }) diff --git a/test/instrumentation/modules/ioredis.test.js b/test/instrumentation/modules/ioredis.test.js index 0b81a4cc38b..e7d388f4e28 100644 --- a/test/instrumentation/modules/ioredis.test.js +++ b/test/instrumentation/modules/ioredis.test.js @@ -11,6 +11,7 @@ var agent = require('../../..').start({ captureExceptions: false, metricsInterval: 0, centralConfig: false, + apmServerVersion: '8.0.0', spanCompressionEnabled: false }) @@ -172,12 +173,14 @@ function done (t) { groups.forEach(function (name, i) { const span = data.spans[i] t.strictEqual(span.name, name, 'span.name') - t.strictEqual(span.type, 'cache', 'span.type') + t.strictEqual(span.type, 'db', 'span.type') t.strictEqual(span.subtype, 'redis', 'span.subtype') + t.strictEqual(span.action, 'query', 'span.action') + t.deepEqual(span.context.service.target, { type: 'redis' }, 'span.context.service.target') t.deepEqual(span.context.destination, { - service: { name: 'redis', resource: 'redis', type: 'cache' }, address: process.env.REDIS_HOST || 'localhost', - port: 6379 + port: 6379, + service: { name: '', type: '', resource: 'redis' } }, 'span.context.destination') t.strictEqual(span.parent_id, trans.id, 'span is a child of the transaction') }) diff --git a/test/instrumentation/modules/koa-router/shared.js b/test/instrumentation/modules/koa-router/shared.js index e8976a60cc7..2bb85702589 100644 --- a/test/instrumentation/modules/koa-router/shared.js +++ b/test/instrumentation/modules/koa-router/shared.js @@ -15,12 +15,19 @@ module.exports = (moduleName) => { centralConfig: false }) - var routerVersion = require(`${moduleName}/package`).version + const semver = require('semver') + const routerVersion = require(`${moduleName}/package`).version + + // koa-router >=11 requires Node.js >=12. + if (semver.lt(process.version, '12.0.0') && semver.gte(routerVersion, '11.0.0')) { + // Skip out of this test. + console.log(`# SKIP cannot test ${moduleName}@${routerVersion} with node ${process.version}`) + process.exit() + } var http = require('http') var Koa = require('koa') - var semver = require('semver') var test = require('tape') var Router = require(moduleName) diff --git a/test/instrumentation/modules/memcached.test.js b/test/instrumentation/modules/memcached.test.js index 6acc35a8f0b..689c017fd97 100644 --- a/test/instrumentation/modules/memcached.test.js +++ b/test/instrumentation/modules/memcached.test.js @@ -71,11 +71,13 @@ test('memcached', function (t) { t.strictEqual(spans[6].action, 'get') t.strictEqual(spans[6].context.db.statement, 'get foo') spans.forEach(span => { + t.deepEqual(span.context.service.target, { type: 'memcached' }, + 'span.context.service.target') t.deepEqual(span.context.destination, { - service: { name: 'memcached', resource: 'memcached', type: 'db' }, + service: { type: '', name: '', resource: 'memcached' }, address: host, port: 11211 - }) + }, 'span.context.destination') }) spans.forEach(span => { t.equal(span.parent_id, data.transactions[0].id, diff --git a/test/instrumentation/modules/mongodb-core.test.js b/test/instrumentation/modules/mongodb-core.test.js index 47b5a4d28b2..9ec0f0fb3c3 100644 --- a/test/instrumentation/modules/mongodb-core.test.js +++ b/test/instrumentation/modules/mongodb-core.test.js @@ -7,11 +7,12 @@ 'use strict' var agent = require('../../..').start({ - serviceName: 'test', - secretToken: 'test', + serviceName: 'test-mongodb-core', captureExceptions: false, metricsInterval: 0, - centralConfig: false + centralConfig: false, + cloudProvider: 'none', + spanCompressionEnabled: false }) var Server = require('mongodb-core').Server @@ -52,7 +53,7 @@ test('instrument simple command', function (t) { // - mongodb-core@1.x always does a `admin.$cmd.ismaster` or // `system.$cmd.ismaster` (the latter in for mongodb-core@<=1.2.22) // command on initial connection. The APM agent captures this if - // asyncHooks=true. + // `contextManager != "patch"`. // - mongodb-core@1.x includes `elasticapm.$cmd.command` spans after the // insert, update, and remove commands. for (var i = 0; i < data.spans.length; i++) { @@ -79,6 +80,24 @@ test('instrument simple command', function (t) { var offset = span.timestamp - trans.timestamp t.ok(offset + span.duration * 1000 < trans.duration * 1000, `span ends (${span.timestamp / 1000 + span.duration}ms) before the transaction (${trans.timestamp / 1000 + trans.duration}ms)`) + const dbInstance = expectedSpanNamesInOrder[0].slice(0, expectedSpanNamesInOrder[0].lastIndexOf('.')) + t.deepEqual(span.context.db, { type: 'mongodb', instance: dbInstance }, 'span.context.db') + t.deepEqual(span.context.service.target, { type: 'mongodb', name: dbInstance }, 'span.context.service.target') + + // A current limitation of the mongodb-core instrumentation is that + // it does not set destination.{address,port} for cursor operations like + // "find". + if (span.context.destination.address) { + t.deepEqual(span.context.destination, { + address: span.context.destination.address, + port: 27017, + service: { type: '', name: '', resource: `mongodb/${dbInstance}` } + }, 'span.context.destination') + } else { + t.deepEqual(span.context.destination, { + service: { type: '', name: '', resource: `mongodb/${dbInstance}` } + }, 'span.context.destination') + } expectedSpanNamesInOrder.shift() } diff --git a/test/instrumentation/modules/mongodb.test.js b/test/instrumentation/modules/mongodb.test.js index e2c6bec19dd..40efd9b90ce 100644 --- a/test/instrumentation/modules/mongodb.test.js +++ b/test/instrumentation/modules/mongodb.test.js @@ -175,10 +175,10 @@ test('ensure run context', async function (t) { test('instrument simple command', function (t) { resetAgentStates([ - makeSpanTest(t, 'elasticapm.test.insert'), - makeSpanTest(t, 'elasticapm.test.update'), - makeSpanTest(t, 'elasticapm.test.delete'), - makeSpanTest(t, 'elasticapm.test.find'), + makeSpanTest(t, 'elasticapm.test.insert', 'insert'), + makeSpanTest(t, 'elasticapm.test.update', 'update'), + makeSpanTest(t, 'elasticapm.test.delete', 'delete'), + makeSpanTest(t, 'elasticapm.test.find', 'find'), makeTransactionTest(t) ], function () { t.end() @@ -255,17 +255,20 @@ function makeTransactionTest (t) { } } -function makeSpanTest (t, name) { +function makeSpanTest (t, name, action) { return { find (type, span) { return type === 'span' && span.name === name }, test (span) { t.ok(span, 'found valid span') - t.strictEqual(span.name, name, `span name is "${name}"`) - t.strictEqual(span.type, 'db', 'span type is "db"') - t.strictEqual(span.subtype, 'mongodb', 'span subtype is "mongodb"') - t.strictEqual(span.action, 'query', 'span action is "query"') + t.strictEqual(span.name, name, 'span.name') + t.strictEqual(span.type, 'db', 'span.type') + t.strictEqual(span.subtype, 'mongodb', 'span.subtype') + t.strictEqual(span.action, action, 'span.action') + + t.deepEqual(span.context.db, { type: 'mongodb', instance: 'elasticapm' }, 'span.context.db') + t.deepEqual(span.context.service.target, { type: 'mongodb', name: 'elasticapm' }, 'span.context.service.target') // We can't easily assert destination.address because mongodb >3.5.0 // returns a resolved IP for the given connection hostname. In our CI @@ -273,13 +276,9 @@ function makeSpanTest (t, name) { // some IP. We could `dns.resolve4()` here, but that's overkill I think. t.ok(span.context.destination.address, 'context.destination.address is defined') t.deepEqual(span.context.destination, { - service: { - name: 'mongodb', - resource: 'mongodb', - type: 'db' - }, address: span.context.destination.address, - port: 27017 + port: 27017, + service: { type: '', name: '', resource: 'mongodb/elasticapm' } }, 'span.context.destination') } } diff --git a/test/instrumentation/modules/mysql/mysql.test.js b/test/instrumentation/modules/mysql/mysql.test.js index 538615750fd..e81dfd1a3a6 100644 --- a/test/instrumentation/modules/mysql/mysql.test.js +++ b/test/instrumentation/modules/mysql/mysql.test.js @@ -456,16 +456,25 @@ function assertBasicQuery (t, sql, data) { } function assertSpan (t, span, sql) { - t.strictEqual(span.name, 'SELECT') - t.strictEqual(span.type, 'db') - t.strictEqual(span.subtype, 'mysql') - t.strictEqual(span.action, 'query') - t.deepEqual(span.context.db, { statement: sql, type: 'sql' }) + t.strictEqual(span.name, 'SELECT', 'span.name') + t.strictEqual(span.type, 'db', 'span.type') + t.strictEqual(span.subtype, 'mysql', 'span.subtype') + t.strictEqual(span.action, 'query', 'span.action') + t.deepEqual(span.context.db, { + statement: sql, + type: 'sql', + user: connectionOptions.user, + instance: connectionOptions.database + }, 'span.context.db') + t.deepEqual(span.context.service.target, { + type: 'mysql', + name: connectionOptions.database + }, 'span.context.service.target') t.deepEqual(span.context.destination, { - service: { name: 'mysql', resource: 'mysql', type: 'db' }, address: connectionOptions.host, - port: 3306 - }) + port: 3306, + service: { type: '', name: '', resource: `mysql/${connectionOptions.database}` } + }, 'span.context.destination') } function createConnection (cb) { diff --git a/test/instrumentation/modules/mysql2/mysql.test.js b/test/instrumentation/modules/mysql2/mysql.test.js index b366f85c874..9dff1ae63ff 100644 --- a/test/instrumentation/modules/mysql2/mysql.test.js +++ b/test/instrumentation/modules/mysql2/mysql.test.js @@ -399,12 +399,25 @@ function assertBasicQuery (t, sql, data) { } function assertSpan (t, span, sql) { - t.strictEqual(span.name, 'SELECT') - t.strictEqual(span.type, 'db') - t.strictEqual(span.subtype, 'mysql') - t.strictEqual(span.action, 'query') - t.deepEqual(span.context.db, { statement: sql, type: 'sql' }) - t.deepEqual(span.context.destination, { service: { name: 'mysql', resource: 'mysql', type: 'db' }, port: 3306, address: connectionOptions.host }) + t.strictEqual(span.name, 'SELECT', 'span.name') + t.strictEqual(span.type, 'db', 'span.type') + t.strictEqual(span.subtype, 'mysql', 'span.subtype') + t.strictEqual(span.action, 'query', 'span.action') + t.deepEqual(span.context.db, { + type: 'sql', + instance: connectionOptions.database, + user: connectionOptions.user, + statement: sql + }, 'span.context.db') + t.deepEqual(span.context.service.target, { + type: 'mysql', + name: connectionOptions.database + }, 'span.context.service.target') + t.deepEqual(span.context.destination, { + address: connectionOptions.host, + port: 3306, + service: { type: '', name: '', resource: `mysql/${connectionOptions.database}` } + }, 'span.context.destination') } function createConnection (cb) { diff --git a/test/instrumentation/modules/next/a-nextjs-app/.tav.yml b/test/instrumentation/modules/next/a-nextjs-app/.tav.yml new file mode 100644 index 00000000000..68803dafc54 --- /dev/null +++ b/test/instrumentation/modules/next/a-nextjs-app/.tav.yml @@ -0,0 +1,36 @@ +# Test Next.js versions. +# +# - We instrument Next.js ">=11.1.0 <14.0.0". I don't see much value in testing +# every patch-level release. Instead we will test the latest patch release +# for each minor. (It would be nice if tav supported this natively.) +# - Next.js 11 supports back to node v12.22.0 and v14.5.0. However, when this +# instrumentation was added, Node v12 was already EOL, so there is less value +# in testing it. +# - Next.js 11 crashes with Node >=17 unless this workaround is used; +# NODE_OPTIONS=--openssl-legacy-provider ... +# See https://github.com/vercel/next.js/issues/30078 for details. There isn't +# much value in testing this old Next.js version with newer Node versions. +next-11: + name: next + versions: '11.1.0 || 11.1.4' + node: '>=14.5.0 <17.0.0' + commands: node ../next.test.js + peerDependencies: + - "react@^17.0.2" + - "react-dom@^17.0.2" +next-12: + name: next + versions: '12.0.10 || 12.1.6 || 12.2.6 || 12.3.1 || >12.3.1 <13' + node: '>=14.5.0' + commands: node ../next.test.js + peerDependencies: + - "react@^18.2.0" + - "react-dom@^18.2.0" +next: + name: next + versions: '>=13.0.0 <14' + node: '>=14.6.0' + commands: node ../next.test.js + peerDependencies: + - "react@^18.2.0" + - "react-dom@^18.2.0" diff --git a/test/instrumentation/modules/next/a-nextjs-app/components/Header.js b/test/instrumentation/modules/next/a-nextjs-app/components/Header.js new file mode 100644 index 00000000000..5236d499618 --- /dev/null +++ b/test/instrumentation/modules/next/a-nextjs-app/components/Header.js @@ -0,0 +1,31 @@ +/* + * Copyright Elasticsearch B.V. and other contributors where applicable. + * Licensed under the BSD 2-Clause License; you may not use this file except in + * compliance with the BSD 2-Clause License. + */ + +import Head from 'next/head' +import Link from 'next/link' + +function Header () { + return ( + <> + + A Next.js App + +
+
+ Home +  |  + APage +  |  + AnSSRPage +  |  + ADynamicPage/42 +
+
+ + ) +} + +export default Header diff --git a/test/instrumentation/modules/next/a-nextjs-app/next.config.js b/test/instrumentation/modules/next/a-nextjs-app/next.config.js new file mode 100644 index 00000000000..de686f23cbb --- /dev/null +++ b/test/instrumentation/modules/next/a-nextjs-app/next.config.js @@ -0,0 +1,57 @@ +/* + * Copyright Elasticsearch B.V. and other contributors where applicable. + * Licensed under the BSD 2-Clause License; you may not use this file except in + * compliance with the BSD 2-Clause License. + */ + +/** + * @type {import('next').NextConfig} + */ +const nextConfig = { + async redirects () { + return [ + { + source: '/redirect-to-a-page', + destination: '/a-page', + permanent: false + } + ] + }, + async rewrites () { + return { + beforeFiles: [ + { + source: '/rewrite-with-a-has-condition', + destination: '/a-page', + has: [{ type: 'query', key: 'overrideMe' }] + } + ], + afterFiles: [ + { + source: '/rewrite-to-a-page', + destination: '/a-page' + }, + { + source: '/rewrite-to-a-dynamic-page/:num', + destination: '/a-dynamic-page/:num' + }, + { + source: '/rewrite-to-a-public-file', + destination: '/favicon.ico' + }, + { + source: '/rewrite-to-a-404', + destination: '/no-such-page' + } + ], + fallback: [ + { + source: '/rewrite-external/:path*', + destination: 'https://old.example.com/:path*' + } + ] + } + } +} + +module.exports = nextConfig diff --git a/test/instrumentation/modules/next/a-nextjs-app/package-lock.json b/test/instrumentation/modules/next/a-nextjs-app/package-lock.json new file mode 100644 index 00000000000..07069e011d1 --- /dev/null +++ b/test/instrumentation/modules/next/a-nextjs-app/package-lock.json @@ -0,0 +1,622 @@ +{ + "name": "a-nextjs-app", + "version": "1.0.0", + "lockfileVersion": 2, + "requires": true, + "packages": { + "": { + "name": "a-nextjs-app", + "version": "1.0.0", + "license": "BSD-2-Clause", + "dependencies": { + "next": "^13.1.1", + "react": "^18.2.0", + "react-dom": "^18.2.0" + } + }, + "node_modules/@next/env": { + "version": "13.1.1", + "resolved": "https://registry.npmjs.org/@next/env/-/env-13.1.1.tgz", + "integrity": "sha512-vFMyXtPjSAiOXOywMojxfKIqE3VWN5RCAx+tT3AS3pcKjMLFTCJFUWsKv8hC+87Z1F4W3r68qTwDFZIFmd5Xkw==" + }, + "node_modules/@next/swc-android-arm-eabi": { + "version": "13.1.1", + "resolved": "https://registry.npmjs.org/@next/swc-android-arm-eabi/-/swc-android-arm-eabi-13.1.1.tgz", + "integrity": "sha512-qnFCx1kT3JTWhWve4VkeWuZiyjG0b5T6J2iWuin74lORCupdrNukxkq9Pm+Z7PsatxuwVJMhjUoYz7H4cWzx2A==", + "cpu": [ + "arm" + ], + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@next/swc-android-arm64": { + "version": "13.1.1", + "resolved": "https://registry.npmjs.org/@next/swc-android-arm64/-/swc-android-arm64-13.1.1.tgz", + "integrity": "sha512-eCiZhTzjySubNqUnNkQCjU3Fh+ep3C6b5DCM5FKzsTH/3Gr/4Y7EiaPZKILbvnXmhWtKPIdcY6Zjx51t4VeTfA==", + "cpu": [ + "arm64" + ], + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@next/swc-darwin-arm64": { + "version": "13.1.1", + "resolved": "https://registry.npmjs.org/@next/swc-darwin-arm64/-/swc-darwin-arm64-13.1.1.tgz", + "integrity": "sha512-9zRJSSIwER5tu9ADDkPw5rIZ+Np44HTXpYMr0rkM656IvssowPxmhK0rTreC1gpUCYwFsRbxarUJnJsTWiutPg==", + "cpu": [ + "arm64" + ], + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@next/swc-darwin-x64": { + "version": "13.1.1", + "resolved": "https://registry.npmjs.org/@next/swc-darwin-x64/-/swc-darwin-x64-13.1.1.tgz", + "integrity": "sha512-qWr9qEn5nrnlhB0rtjSdR00RRZEtxg4EGvicIipqZWEyayPxhUu6NwKiG8wZiYZCLfJ5KWr66PGSNeDMGlNaiA==", + "cpu": [ + "x64" + ], + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@next/swc-freebsd-x64": { + "version": "13.1.1", + "resolved": "https://registry.npmjs.org/@next/swc-freebsd-x64/-/swc-freebsd-x64-13.1.1.tgz", + "integrity": "sha512-UwP4w/NcQ7V/VJEj3tGVszgb4pyUCt3lzJfUhjDMUmQbzG9LDvgiZgAGMYH6L21MoyAATJQPDGiAMWAPKsmumA==", + "cpu": [ + "x64" + ], + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@next/swc-linux-arm-gnueabihf": { + "version": "13.1.1", + "resolved": "https://registry.npmjs.org/@next/swc-linux-arm-gnueabihf/-/swc-linux-arm-gnueabihf-13.1.1.tgz", + "integrity": "sha512-CnsxmKHco9sosBs1XcvCXP845Db+Wx1G0qouV5+Gr+HT/ZlDYEWKoHVDgnJXLVEQzq4FmHddBNGbXvgqM1Gfkg==", + "cpu": [ + "arm" + ], + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@next/swc-linux-arm64-gnu": { + "version": "13.1.1", + "resolved": "https://registry.npmjs.org/@next/swc-linux-arm64-gnu/-/swc-linux-arm64-gnu-13.1.1.tgz", + "integrity": "sha512-JfDq1eri5Dif+VDpTkONRd083780nsMCOKoFG87wA0sa4xL8LGcXIBAkUGIC1uVy9SMsr2scA9CySLD/i+Oqiw==", + "cpu": [ + "arm64" + ], + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@next/swc-linux-arm64-musl": { + "version": "13.1.1", + "resolved": "https://registry.npmjs.org/@next/swc-linux-arm64-musl/-/swc-linux-arm64-musl-13.1.1.tgz", + "integrity": "sha512-GA67ZbDq2AW0CY07zzGt07M5b5Yaq5qUpFIoW3UFfjOPgb0Sqf3DAW7GtFMK1sF4ROHsRDMGQ9rnT0VM2dVfKA==", + "cpu": [ + "arm64" + ], + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@next/swc-linux-x64-gnu": { + "version": "13.1.1", + "resolved": "https://registry.npmjs.org/@next/swc-linux-x64-gnu/-/swc-linux-x64-gnu-13.1.1.tgz", + "integrity": "sha512-nnjuBrbzvqaOJaV+XgT8/+lmXrSCOt1YYZn/irbDb2fR2QprL6Q7WJNgwsZNxiLSfLdv+2RJGGegBx9sLBEzGA==", + "cpu": [ + "x64" + ], + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@next/swc-linux-x64-musl": { + "version": "13.1.1", + "resolved": "https://registry.npmjs.org/@next/swc-linux-x64-musl/-/swc-linux-x64-musl-13.1.1.tgz", + "integrity": "sha512-CM9xnAQNIZ8zf/igbIT/i3xWbQZYaF397H+JroF5VMOCUleElaMdQLL5riJml8wUfPoN3dtfn2s4peSr3azz/g==", + "cpu": [ + "x64" + ], + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@next/swc-win32-arm64-msvc": { + "version": "13.1.1", + "resolved": "https://registry.npmjs.org/@next/swc-win32-arm64-msvc/-/swc-win32-arm64-msvc-13.1.1.tgz", + "integrity": "sha512-pzUHOGrbgfGgPlOMx9xk3QdPJoRPU+om84hqVoe6u+E0RdwOG0Ho/2UxCgDqmvpUrMab1Deltlt6RqcXFpnigQ==", + "cpu": [ + "arm64" + ], + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@next/swc-win32-ia32-msvc": { + "version": "13.1.1", + "resolved": "https://registry.npmjs.org/@next/swc-win32-ia32-msvc/-/swc-win32-ia32-msvc-13.1.1.tgz", + "integrity": "sha512-WeX8kVS46aobM9a7Xr/kEPcrTyiwJqQv/tbw6nhJ4fH9xNZ+cEcyPoQkwPo570dCOLz3Zo9S2q0E6lJ/EAUOBg==", + "cpu": [ + "ia32" + ], + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@next/swc-win32-x64-msvc": { + "version": "13.1.1", + "resolved": "https://registry.npmjs.org/@next/swc-win32-x64-msvc/-/swc-win32-x64-msvc-13.1.1.tgz", + "integrity": "sha512-mVF0/3/5QAc5EGVnb8ll31nNvf3BWpPY4pBb84tk+BfQglWLqc5AC9q1Ht/YMWiEgs8ALNKEQ3GQnbY0bJF2Gg==", + "cpu": [ + "x64" + ], + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@swc/helpers": { + "version": "0.4.14", + "resolved": "https://registry.npmjs.org/@swc/helpers/-/helpers-0.4.14.tgz", + "integrity": "sha512-4C7nX/dvpzB7za4Ql9K81xK3HPxCpHMgwTZVyf+9JQ6VUbn9jjZVN7/Nkdz/Ugzs2CSjqnL/UPXroiVBVHUWUw==", + "dependencies": { + "tslib": "^2.4.0" + } + }, + "node_modules/caniuse-lite": { + "version": "1.0.30001426", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001426.tgz", + "integrity": "sha512-n7cosrHLl8AWt0wwZw/PJZgUg3lV0gk9LMI7ikGJwhyhgsd2Nb65vKvmSexCqq/J7rbH3mFG6yZZiPR5dLPW5A==", + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/caniuse-lite" + } + ] + }, + "node_modules/client-only": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/client-only/-/client-only-0.0.1.tgz", + "integrity": "sha512-IV3Ou0jSMzZrd3pZ48nLkT9DA7Ag1pnPzaiQhpW7c3RbcqqzvzzVu+L8gfqMp/8IM2MQtSiqaCxrrcfu8I8rMA==" + }, + "node_modules/js-tokens": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", + "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==" + }, + "node_modules/loose-envify": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.4.0.tgz", + "integrity": "sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==", + "dependencies": { + "js-tokens": "^3.0.0 || ^4.0.0" + }, + "bin": { + "loose-envify": "cli.js" + } + }, + "node_modules/nanoid": { + "version": "3.3.4", + "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.4.tgz", + "integrity": "sha512-MqBkQh/OHTS2egovRtLk45wEyNXwF+cokD+1YPf9u5VfJiRdAiRwB2froX5Co9Rh20xs4siNPm8naNotSD6RBw==", + "bin": { + "nanoid": "bin/nanoid.cjs" + }, + "engines": { + "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1" + } + }, + "node_modules/next": { + "version": "13.1.1", + "resolved": "https://registry.npmjs.org/next/-/next-13.1.1.tgz", + "integrity": "sha512-R5eBAaIa3X7LJeYvv1bMdGnAVF4fVToEjim7MkflceFPuANY3YyvFxXee/A+acrSYwYPvOvf7f6v/BM/48ea5w==", + "dependencies": { + "@next/env": "13.1.1", + "@swc/helpers": "0.4.14", + "caniuse-lite": "^1.0.30001406", + "postcss": "8.4.14", + "styled-jsx": "5.1.1" + }, + "bin": { + "next": "dist/bin/next" + }, + "engines": { + "node": ">=14.6.0" + }, + "optionalDependencies": { + "@next/swc-android-arm-eabi": "13.1.1", + "@next/swc-android-arm64": "13.1.1", + "@next/swc-darwin-arm64": "13.1.1", + "@next/swc-darwin-x64": "13.1.1", + "@next/swc-freebsd-x64": "13.1.1", + "@next/swc-linux-arm-gnueabihf": "13.1.1", + "@next/swc-linux-arm64-gnu": "13.1.1", + "@next/swc-linux-arm64-musl": "13.1.1", + "@next/swc-linux-x64-gnu": "13.1.1", + "@next/swc-linux-x64-musl": "13.1.1", + "@next/swc-win32-arm64-msvc": "13.1.1", + "@next/swc-win32-ia32-msvc": "13.1.1", + "@next/swc-win32-x64-msvc": "13.1.1" + }, + "peerDependencies": { + "fibers": ">= 3.1.0", + "node-sass": "^6.0.0 || ^7.0.0", + "react": "^18.2.0", + "react-dom": "^18.2.0", + "sass": "^1.3.0" + }, + "peerDependenciesMeta": { + "fibers": { + "optional": true + }, + "node-sass": { + "optional": true + }, + "sass": { + "optional": true + } + } + }, + "node_modules/picocolors": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.0.0.tgz", + "integrity": "sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ==" + }, + "node_modules/postcss": { + "version": "8.4.14", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.14.tgz", + "integrity": "sha512-E398TUmfAYFPBSdzgeieK2Y1+1cpdxJx8yXbK/m57nRhKSmk1GB2tO4lbLBtlkfPQTDKfe4Xqv1ASWPpayPEig==", + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/postcss" + } + ], + "dependencies": { + "nanoid": "^3.3.4", + "picocolors": "^1.0.0", + "source-map-js": "^1.0.2" + }, + "engines": { + "node": "^10 || ^12 || >=14" + } + }, + "node_modules/react": { + "version": "18.2.0", + "resolved": "https://registry.npmjs.org/react/-/react-18.2.0.tgz", + "integrity": "sha512-/3IjMdb2L9QbBdWiW5e3P2/npwMBaU9mHCSCUzNln0ZCYbcfTsGbTJrU/kGemdH2IWmB2ioZ+zkxtmq6g09fGQ==", + "dependencies": { + "loose-envify": "^1.1.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/react-dom": { + "version": "18.2.0", + "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-18.2.0.tgz", + "integrity": "sha512-6IMTriUmvsjHUjNtEDudZfuDQUoWXVxKHhlEGSk81n4YFS+r/Kl99wXiwlVXtPBtJenozv2P+hxDsw9eA7Xo6g==", + "dependencies": { + "loose-envify": "^1.1.0", + "scheduler": "^0.23.0" + }, + "peerDependencies": { + "react": "^18.2.0" + } + }, + "node_modules/scheduler": { + "version": "0.23.0", + "resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.23.0.tgz", + "integrity": "sha512-CtuThmgHNg7zIZWAXi3AsyIzA3n4xx7aNyjwC2VJldO2LMVDhFK+63xGqq6CsJH4rTAt6/M+N4GhZiDYPx9eUw==", + "dependencies": { + "loose-envify": "^1.1.0" + } + }, + "node_modules/source-map-js": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.0.2.tgz", + "integrity": "sha512-R0XvVJ9WusLiqTCEiGCmICCMplcCkIwwR11mOSD9CR5u+IXYdiseeEuXCVAjS54zqwkLcPNnmU4OeJ6tUrWhDw==", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/styled-jsx": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/styled-jsx/-/styled-jsx-5.1.1.tgz", + "integrity": "sha512-pW7uC1l4mBZ8ugbiZrcIsiIvVx1UmTfw7UkC3Um2tmfUq9Bhk8IiyEIPl6F8agHgjzku6j0xQEZbfA5uSgSaCw==", + "dependencies": { + "client-only": "0.0.1" + }, + "engines": { + "node": ">= 12.0.0" + }, + "peerDependencies": { + "react": ">= 16.8.0 || 17.x.x || ^18.0.0-0" + }, + "peerDependenciesMeta": { + "@babel/core": { + "optional": true + }, + "babel-plugin-macros": { + "optional": true + } + } + }, + "node_modules/tslib": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.4.1.tgz", + "integrity": "sha512-tGyy4dAjRIEwI7BzsB0lynWgOpfqjUdq91XXAlIWD2OwKBH7oCl/GZG/HT4BOHrTlPMOASlMQ7veyTqpmRcrNA==" + } + }, + "dependencies": { + "@next/env": { + "version": "13.1.1", + "resolved": "https://registry.npmjs.org/@next/env/-/env-13.1.1.tgz", + "integrity": "sha512-vFMyXtPjSAiOXOywMojxfKIqE3VWN5RCAx+tT3AS3pcKjMLFTCJFUWsKv8hC+87Z1F4W3r68qTwDFZIFmd5Xkw==" + }, + "@next/swc-android-arm-eabi": { + "version": "13.1.1", + "resolved": "https://registry.npmjs.org/@next/swc-android-arm-eabi/-/swc-android-arm-eabi-13.1.1.tgz", + "integrity": "sha512-qnFCx1kT3JTWhWve4VkeWuZiyjG0b5T6J2iWuin74lORCupdrNukxkq9Pm+Z7PsatxuwVJMhjUoYz7H4cWzx2A==", + "optional": true + }, + "@next/swc-android-arm64": { + "version": "13.1.1", + "resolved": "https://registry.npmjs.org/@next/swc-android-arm64/-/swc-android-arm64-13.1.1.tgz", + "integrity": "sha512-eCiZhTzjySubNqUnNkQCjU3Fh+ep3C6b5DCM5FKzsTH/3Gr/4Y7EiaPZKILbvnXmhWtKPIdcY6Zjx51t4VeTfA==", + "optional": true + }, + "@next/swc-darwin-arm64": { + "version": "13.1.1", + "resolved": "https://registry.npmjs.org/@next/swc-darwin-arm64/-/swc-darwin-arm64-13.1.1.tgz", + "integrity": "sha512-9zRJSSIwER5tu9ADDkPw5rIZ+Np44HTXpYMr0rkM656IvssowPxmhK0rTreC1gpUCYwFsRbxarUJnJsTWiutPg==", + "optional": true + }, + "@next/swc-darwin-x64": { + "version": "13.1.1", + "resolved": "https://registry.npmjs.org/@next/swc-darwin-x64/-/swc-darwin-x64-13.1.1.tgz", + "integrity": "sha512-qWr9qEn5nrnlhB0rtjSdR00RRZEtxg4EGvicIipqZWEyayPxhUu6NwKiG8wZiYZCLfJ5KWr66PGSNeDMGlNaiA==", + "optional": true + }, + "@next/swc-freebsd-x64": { + "version": "13.1.1", + "resolved": "https://registry.npmjs.org/@next/swc-freebsd-x64/-/swc-freebsd-x64-13.1.1.tgz", + "integrity": "sha512-UwP4w/NcQ7V/VJEj3tGVszgb4pyUCt3lzJfUhjDMUmQbzG9LDvgiZgAGMYH6L21MoyAATJQPDGiAMWAPKsmumA==", + "optional": true + }, + "@next/swc-linux-arm-gnueabihf": { + "version": "13.1.1", + "resolved": "https://registry.npmjs.org/@next/swc-linux-arm-gnueabihf/-/swc-linux-arm-gnueabihf-13.1.1.tgz", + "integrity": "sha512-CnsxmKHco9sosBs1XcvCXP845Db+Wx1G0qouV5+Gr+HT/ZlDYEWKoHVDgnJXLVEQzq4FmHddBNGbXvgqM1Gfkg==", + "optional": true + }, + "@next/swc-linux-arm64-gnu": { + "version": "13.1.1", + "resolved": "https://registry.npmjs.org/@next/swc-linux-arm64-gnu/-/swc-linux-arm64-gnu-13.1.1.tgz", + "integrity": "sha512-JfDq1eri5Dif+VDpTkONRd083780nsMCOKoFG87wA0sa4xL8LGcXIBAkUGIC1uVy9SMsr2scA9CySLD/i+Oqiw==", + "optional": true + }, + "@next/swc-linux-arm64-musl": { + "version": "13.1.1", + "resolved": "https://registry.npmjs.org/@next/swc-linux-arm64-musl/-/swc-linux-arm64-musl-13.1.1.tgz", + "integrity": "sha512-GA67ZbDq2AW0CY07zzGt07M5b5Yaq5qUpFIoW3UFfjOPgb0Sqf3DAW7GtFMK1sF4ROHsRDMGQ9rnT0VM2dVfKA==", + "optional": true + }, + "@next/swc-linux-x64-gnu": { + "version": "13.1.1", + "resolved": "https://registry.npmjs.org/@next/swc-linux-x64-gnu/-/swc-linux-x64-gnu-13.1.1.tgz", + "integrity": "sha512-nnjuBrbzvqaOJaV+XgT8/+lmXrSCOt1YYZn/irbDb2fR2QprL6Q7WJNgwsZNxiLSfLdv+2RJGGegBx9sLBEzGA==", + "optional": true + }, + "@next/swc-linux-x64-musl": { + "version": "13.1.1", + "resolved": "https://registry.npmjs.org/@next/swc-linux-x64-musl/-/swc-linux-x64-musl-13.1.1.tgz", + "integrity": "sha512-CM9xnAQNIZ8zf/igbIT/i3xWbQZYaF397H+JroF5VMOCUleElaMdQLL5riJml8wUfPoN3dtfn2s4peSr3azz/g==", + "optional": true + }, + "@next/swc-win32-arm64-msvc": { + "version": "13.1.1", + "resolved": "https://registry.npmjs.org/@next/swc-win32-arm64-msvc/-/swc-win32-arm64-msvc-13.1.1.tgz", + "integrity": "sha512-pzUHOGrbgfGgPlOMx9xk3QdPJoRPU+om84hqVoe6u+E0RdwOG0Ho/2UxCgDqmvpUrMab1Deltlt6RqcXFpnigQ==", + "optional": true + }, + "@next/swc-win32-ia32-msvc": { + "version": "13.1.1", + "resolved": "https://registry.npmjs.org/@next/swc-win32-ia32-msvc/-/swc-win32-ia32-msvc-13.1.1.tgz", + "integrity": "sha512-WeX8kVS46aobM9a7Xr/kEPcrTyiwJqQv/tbw6nhJ4fH9xNZ+cEcyPoQkwPo570dCOLz3Zo9S2q0E6lJ/EAUOBg==", + "optional": true + }, + "@next/swc-win32-x64-msvc": { + "version": "13.1.1", + "resolved": "https://registry.npmjs.org/@next/swc-win32-x64-msvc/-/swc-win32-x64-msvc-13.1.1.tgz", + "integrity": "sha512-mVF0/3/5QAc5EGVnb8ll31nNvf3BWpPY4pBb84tk+BfQglWLqc5AC9q1Ht/YMWiEgs8ALNKEQ3GQnbY0bJF2Gg==", + "optional": true + }, + "@swc/helpers": { + "version": "0.4.14", + "resolved": "https://registry.npmjs.org/@swc/helpers/-/helpers-0.4.14.tgz", + "integrity": "sha512-4C7nX/dvpzB7za4Ql9K81xK3HPxCpHMgwTZVyf+9JQ6VUbn9jjZVN7/Nkdz/Ugzs2CSjqnL/UPXroiVBVHUWUw==", + "requires": { + "tslib": "^2.4.0" + } + }, + "caniuse-lite": { + "version": "1.0.30001426", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001426.tgz", + "integrity": "sha512-n7cosrHLl8AWt0wwZw/PJZgUg3lV0gk9LMI7ikGJwhyhgsd2Nb65vKvmSexCqq/J7rbH3mFG6yZZiPR5dLPW5A==" + }, + "client-only": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/client-only/-/client-only-0.0.1.tgz", + "integrity": "sha512-IV3Ou0jSMzZrd3pZ48nLkT9DA7Ag1pnPzaiQhpW7c3RbcqqzvzzVu+L8gfqMp/8IM2MQtSiqaCxrrcfu8I8rMA==" + }, + "js-tokens": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", + "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==" + }, + "loose-envify": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.4.0.tgz", + "integrity": "sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==", + "requires": { + "js-tokens": "^3.0.0 || ^4.0.0" + } + }, + "nanoid": { + "version": "3.3.4", + "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.4.tgz", + "integrity": "sha512-MqBkQh/OHTS2egovRtLk45wEyNXwF+cokD+1YPf9u5VfJiRdAiRwB2froX5Co9Rh20xs4siNPm8naNotSD6RBw==" + }, + "next": { + "version": "13.1.1", + "resolved": "https://registry.npmjs.org/next/-/next-13.1.1.tgz", + "integrity": "sha512-R5eBAaIa3X7LJeYvv1bMdGnAVF4fVToEjim7MkflceFPuANY3YyvFxXee/A+acrSYwYPvOvf7f6v/BM/48ea5w==", + "requires": { + "@next/env": "13.1.1", + "@next/swc-android-arm-eabi": "13.1.1", + "@next/swc-android-arm64": "13.1.1", + "@next/swc-darwin-arm64": "13.1.1", + "@next/swc-darwin-x64": "13.1.1", + "@next/swc-freebsd-x64": "13.1.1", + "@next/swc-linux-arm-gnueabihf": "13.1.1", + "@next/swc-linux-arm64-gnu": "13.1.1", + "@next/swc-linux-arm64-musl": "13.1.1", + "@next/swc-linux-x64-gnu": "13.1.1", + "@next/swc-linux-x64-musl": "13.1.1", + "@next/swc-win32-arm64-msvc": "13.1.1", + "@next/swc-win32-ia32-msvc": "13.1.1", + "@next/swc-win32-x64-msvc": "13.1.1", + "@swc/helpers": "0.4.14", + "caniuse-lite": "^1.0.30001406", + "postcss": "8.4.14", + "styled-jsx": "5.1.1" + } + }, + "picocolors": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.0.0.tgz", + "integrity": "sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ==" + }, + "postcss": { + "version": "8.4.14", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.14.tgz", + "integrity": "sha512-E398TUmfAYFPBSdzgeieK2Y1+1cpdxJx8yXbK/m57nRhKSmk1GB2tO4lbLBtlkfPQTDKfe4Xqv1ASWPpayPEig==", + "requires": { + "nanoid": "^3.3.4", + "picocolors": "^1.0.0", + "source-map-js": "^1.0.2" + } + }, + "react": { + "version": "18.2.0", + "resolved": "https://registry.npmjs.org/react/-/react-18.2.0.tgz", + "integrity": "sha512-/3IjMdb2L9QbBdWiW5e3P2/npwMBaU9mHCSCUzNln0ZCYbcfTsGbTJrU/kGemdH2IWmB2ioZ+zkxtmq6g09fGQ==", + "requires": { + "loose-envify": "^1.1.0" + } + }, + "react-dom": { + "version": "18.2.0", + "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-18.2.0.tgz", + "integrity": "sha512-6IMTriUmvsjHUjNtEDudZfuDQUoWXVxKHhlEGSk81n4YFS+r/Kl99wXiwlVXtPBtJenozv2P+hxDsw9eA7Xo6g==", + "requires": { + "loose-envify": "^1.1.0", + "scheduler": "^0.23.0" + } + }, + "scheduler": { + "version": "0.23.0", + "resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.23.0.tgz", + "integrity": "sha512-CtuThmgHNg7zIZWAXi3AsyIzA3n4xx7aNyjwC2VJldO2LMVDhFK+63xGqq6CsJH4rTAt6/M+N4GhZiDYPx9eUw==", + "requires": { + "loose-envify": "^1.1.0" + } + }, + "source-map-js": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.0.2.tgz", + "integrity": "sha512-R0XvVJ9WusLiqTCEiGCmICCMplcCkIwwR11mOSD9CR5u+IXYdiseeEuXCVAjS54zqwkLcPNnmU4OeJ6tUrWhDw==" + }, + "styled-jsx": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/styled-jsx/-/styled-jsx-5.1.1.tgz", + "integrity": "sha512-pW7uC1l4mBZ8ugbiZrcIsiIvVx1UmTfw7UkC3Um2tmfUq9Bhk8IiyEIPl6F8agHgjzku6j0xQEZbfA5uSgSaCw==", + "requires": { + "client-only": "0.0.1" + } + }, + "tslib": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.4.1.tgz", + "integrity": "sha512-tGyy4dAjRIEwI7BzsB0lynWgOpfqjUdq91XXAlIWD2OwKBH7oCl/GZG/HT4BOHrTlPMOASlMQ7veyTqpmRcrNA==" + } + } +} diff --git a/test/instrumentation/modules/next/a-nextjs-app/package.json b/test/instrumentation/modules/next/a-nextjs-app/package.json new file mode 100644 index 00000000000..e01d41d19a7 --- /dev/null +++ b/test/instrumentation/modules/next/a-nextjs-app/package.json @@ -0,0 +1,18 @@ +{ + "name": "a-nextjs-app", + "version": "1.0.0", + "description": "a Next.js app to test elastic-apm-node instrumentation", + "private": true, + "scripts": { + "dev": "NODE_OPTIONS='-r ../../../../../start-next.js' next dev", + "build": "next build", + "start": "NODE_OPTIONS='-r ../../../../../start-next.js' next start" + }, + "keywords": [], + "license": "BSD-2-Clause", + "dependencies": { + "next": "^13.1.1", + "react": "^18.2.0", + "react-dom": "^18.2.0" + } +} diff --git a/test/instrumentation/modules/next/a-nextjs-app/pages/a-dynamic-page/[num].js b/test/instrumentation/modules/next/a-nextjs-app/pages/a-dynamic-page/[num].js new file mode 100644 index 00000000000..f6a6bb7f32f --- /dev/null +++ b/test/instrumentation/modules/next/a-nextjs-app/pages/a-dynamic-page/[num].js @@ -0,0 +1,45 @@ +/* + * Copyright Elasticsearch B.V. and other contributors where applicable. + * Licensed under the BSD 2-Clause License; you may not use this file except in + * compliance with the BSD 2-Clause License. + */ + +import { useRouter } from 'next/router' +import Header from '../../components/Header' + +// Run at build time to determine a set of dynamic paths to prerender at build time. +// https://nextjs.org/docs/basic-features/data-fetching/get-static-paths +export async function getStaticPaths () { + return { + paths: [ + { params: { num: '41' } }, + { params: { num: '42' } }, + { params: { num: '43' } } + ], + fallback: true // false, true, or 'blocking' + } +} + +export async function getStaticProps ({ params }) { + return { + props: { + doubleThat: Number(params.num) * 2 + } + } +} + +const ADynamicPage = ({ doubleThat }) => { + const router = useRouter() + const { num } = router.query + + return ( + <> +
+
+
This is ADynamicPage {num} - doubleThat is {doubleThat}
+
+ + ) +} + +export default ADynamicPage diff --git a/test/instrumentation/modules/next/a-nextjs-app/pages/a-page.js b/test/instrumentation/modules/next/a-nextjs-app/pages/a-page.js new file mode 100644 index 00000000000..b7999ac53ab --- /dev/null +++ b/test/instrumentation/modules/next/a-nextjs-app/pages/a-page.js @@ -0,0 +1,35 @@ +/* + * Copyright Elasticsearch B.V. and other contributors where applicable. + * Licensed under the BSD 2-Clause License; you may not use this file except in + * compliance with the BSD 2-Clause License. + */ + +// A static page. + +import Image from 'next/image' +import Header from '../components/Header' + +import img from '../public/elastic-logo.png' + +// Runs at build time. +export async function getStaticProps () { + return { + props: { + buildTime: Date.now() + } + } +} + +function APage ({ buildTime }) { + return ( + <> +
+
+
This is APage (built at {new Date(buildTime).toISOString()})
+ Elastic logo +
+ + ) +} + +export default APage diff --git a/test/instrumentation/modules/next/a-nextjs-app/pages/a-throw-in-getServerSideProps.js b/test/instrumentation/modules/next/a-nextjs-app/pages/a-throw-in-getServerSideProps.js new file mode 100644 index 00000000000..bc360406d3f --- /dev/null +++ b/test/instrumentation/modules/next/a-nextjs-app/pages/a-throw-in-getServerSideProps.js @@ -0,0 +1,28 @@ +/* + * Copyright Elasticsearch B.V. and other contributors where applicable. + * Licensed under the BSD 2-Clause License; you may not use this file except in + * compliance with the BSD 2-Clause License. + */ + +// A page that throws in `getServerSideProps`. +// https://nextjs.org/docs/basic-features/data-fetching/get-server-side-props#does-getserversideprops-render-an-error-page + +import Header from '../components/Header' + +// Gets called on every request. +export async function getServerSideProps () { + throw new Error('thrown error in getServerSideProps') +} + +function AThrowInGetServerSideProps () { + return ( + <> +
+
+
This is AThrowInGetServerSideProps.
+
+ + ) +} + +export default AThrowInGetServerSideProps diff --git a/test/instrumentation/modules/next/a-nextjs-app/pages/a-throw-in-page-handler.js b/test/instrumentation/modules/next/a-nextjs-app/pages/a-throw-in-page-handler.js new file mode 100644 index 00000000000..cf51456cf73 --- /dev/null +++ b/test/instrumentation/modules/next/a-nextjs-app/pages/a-throw-in-page-handler.js @@ -0,0 +1,25 @@ +/* + * Copyright Elasticsearch B.V. and other contributors where applicable. + * Licensed under the BSD 2-Clause License; you may not use this file except in + * compliance with the BSD 2-Clause License. + */ + +// Gets called on every request. +export async function getServerSideProps () { + return { + props: { + currTime: Date.now() + } + } +} + +function AThrowInPageHandler ({ currTime }) { + // If this is called from a browser-side click of a , e.g. as on the + // index.js page, then this function is executed client-side. If called + // via separately visiting http://localhost:3000/a-throw-in-page-handler + // or via `curl -i ...`, then this is executed server-side. Only in the + // latter case will the Node.js APM agent capture an error, of course. + throw new Error('throw in page handler') +} + +export default AThrowInPageHandler diff --git a/test/instrumentation/modules/next/a-nextjs-app/pages/an-ssr-page.js b/test/instrumentation/modules/next/a-nextjs-app/pages/an-ssr-page.js new file mode 100644 index 00000000000..ffdf2ed410d --- /dev/null +++ b/test/instrumentation/modules/next/a-nextjs-app/pages/an-ssr-page.js @@ -0,0 +1,31 @@ +/* + * Copyright Elasticsearch B.V. and other contributors where applicable. + * Licensed under the BSD 2-Clause License; you may not use this file except in + * compliance with the BSD 2-Clause License. + */ + +// A server-side rendered page. + +import Header from '../components/Header' + +// Gets called on every request. +export async function getServerSideProps () { + return { + props: { + currTime: Date.now() + } + } +} + +function AnSSRPage ({ currTime }) { + return ( + <> +
+
+
This is AnSSRPage (currTime is {new Date(currTime).toISOString()})
+
+ + ) +} + +export default AnSSRPage diff --git a/test/instrumentation/modules/next/a-nextjs-app/pages/api/a-dynamic-api-endpoint/[num].js b/test/instrumentation/modules/next/a-nextjs-app/pages/api/a-dynamic-api-endpoint/[num].js new file mode 100644 index 00000000000..2884ae9104d --- /dev/null +++ b/test/instrumentation/modules/next/a-nextjs-app/pages/api/a-dynamic-api-endpoint/[num].js @@ -0,0 +1,26 @@ +/* + * Copyright Elasticsearch B.V. and other contributors where applicable. + * Licensed under the BSD 2-Clause License; you may not use this file except in + * compliance with the BSD 2-Clause License. + */ + +// A dynamic API endpoint. + +// Always executed server-side. +export default function aDynamicApiEndpoint (req, res) { + const { num } = req.query + const n = Number(num) + if (isNaN(n)) { + res.status(400).json({ + num, + error: 'num is not a Number' + }) + } else { + res.status(200).json({ + num, + n, + double: n * 2, + floor: Math.floor(n) + }) + } +} diff --git a/test/instrumentation/modules/next/a-nextjs-app/pages/api/an-api-endpoint-that-throws.js b/test/instrumentation/modules/next/a-nextjs-app/pages/api/an-api-endpoint-that-throws.js new file mode 100644 index 00000000000..96403cc64f6 --- /dev/null +++ b/test/instrumentation/modules/next/a-nextjs-app/pages/api/an-api-endpoint-that-throws.js @@ -0,0 +1,12 @@ +/* + * Copyright Elasticsearch B.V. and other contributors where applicable. + * Licensed under the BSD 2-Clause License; you may not use this file except in + * compliance with the BSD 2-Clause License. + */ + +// An API endpoint whose handler throws, to test error handling. + +// Always executed server-side. +export default function anApiEndpointThatThrows (req, res) { + throw new Error('An error thrown in anApiEndpointThatThrows handler') +} diff --git a/test/instrumentation/modules/next/a-nextjs-app/pages/api/an-api-endpoint.js b/test/instrumentation/modules/next/a-nextjs-app/pages/api/an-api-endpoint.js new file mode 100644 index 00000000000..1d655ed59a3 --- /dev/null +++ b/test/instrumentation/modules/next/a-nextjs-app/pages/api/an-api-endpoint.js @@ -0,0 +1,12 @@ +/* + * Copyright Elasticsearch B.V. and other contributors where applicable. + * Licensed under the BSD 2-Clause License; you may not use this file except in + * compliance with the BSD 2-Clause License. + */ + +// An API endpoint. + +// Always executed server-side. +export default function anApiEndpoint (req, res) { + res.status(200).json({ ping: 'pong' }) +} diff --git a/test/instrumentation/modules/next/a-nextjs-app/pages/index.js b/test/instrumentation/modules/next/a-nextjs-app/pages/index.js new file mode 100644 index 00000000000..3db50aaf52c --- /dev/null +++ b/test/instrumentation/modules/next/a-nextjs-app/pages/index.js @@ -0,0 +1,76 @@ +/* + * Copyright Elasticsearch B.V. and other contributors where applicable. + * Licensed under the BSD 2-Clause License; you may not use this file except in + * compliance with the BSD 2-Clause License. + */ + +import Link from 'next/link' +import Header from '../components/Header' + +function IndexPage () { + return ( + <> +
+
+
Welcome to A-Next.js-App! This is IndexPage.
+
    +
  • + + Go to APage (it is static in a prod build because it only implements getStaticProps) + +
  • +
  • + + Go to AnSSRPage (its getServerSideProps is called on the server every time) + +
  • +
  • + + Go to ADynamicPage/42 (it supports other numbers; 41, 42, and 43 are pre-generated) + +
  • + +
  • + + Go to a page that redirects to APage + +
  • +
  • + + Go to a page that rewrites to APage + +
  • + +
  • + + Go to AnApiEndpoint + +
  • +
  • + + Go to ADynamicApiEndpoint/3.14159 + +
  • + +
  • + + Go to AThrowInPageHandler + +
  • +
  • + + Go to AThrowInGetServerSideProps + +
  • +
  • + + Go to AnApiEndpointThatThrows + +
  • +
+
+ + ) +} + +export default IndexPage diff --git a/test/instrumentation/modules/next/a-nextjs-app/public/elastic-logo.png b/test/instrumentation/modules/next/a-nextjs-app/public/elastic-logo.png new file mode 100644 index 00000000000..a3a10778d3a Binary files /dev/null and b/test/instrumentation/modules/next/a-nextjs-app/public/elastic-logo.png differ diff --git a/test/instrumentation/modules/next/a-nextjs-app/public/favicon.ico b/test/instrumentation/modules/next/a-nextjs-app/public/favicon.ico new file mode 100644 index 00000000000..9aa824a1034 Binary files /dev/null and b/test/instrumentation/modules/next/a-nextjs-app/public/favicon.ico differ diff --git a/test/instrumentation/modules/next/next.test.js b/test/instrumentation/modules/next/next.test.js new file mode 100644 index 00000000000..aa1c3256095 --- /dev/null +++ b/test/instrumentation/modules/next/next.test.js @@ -0,0 +1,846 @@ +/* + * Copyright Elasticsearch B.V. and other contributors where applicable. + * Licensed under the BSD 2-Clause License; you may not use this file except in + * compliance with the BSD 2-Clause License. + */ + +'use strict' + +// Test Next.js instrumentation. +// +// This test roughly does the following: +// - Start a MockAPMServer to capture intake requests. +// - `npm ci` to build the "a-nextjs-app" project, if necessary. +// - Test instrumentation when using the Next.js production server. +// - `next build && next start` configured to send to our MockAPMServer. +// - Make every request in `TEST_REQUESTS` to the Next.js app. +// - Stop the Next.js app ("apmsetup.js" will flush the APM agent on SIGTERM). +// - Check all the received APM trace data matches the expected values in +// `TEST_REQUESTS`. +// - Test instrumentation when using the Next.js dev server. +// - `next dev` +// - (Same as above.) + +const assert = require('assert') +const { exec, spawn } = require('child_process') +const fs = require('fs') +const http = require('http') +const os = require('os') +const path = require('path') +const semver = require('semver') +const tape = require('tape') + +const { MockAPMServer } = require('../../../_mock_apm_server') + +if (os.platform() === 'win32') { + // Limitation: currently don't support testing on Windows. + // The current mechanism using shell=true to spawn on Windows *and* attempting + // to use SIGTERM to terminal the Next.js server doesn't work because cmd.exe + // does an interactive prompt. Lovely. + // Terminate batch job (Y/N)? + console.log('# SKIP Next.js testing currently is not supported on windows') + process.exit() +} +if (semver.lt(process.version, '14.6.0')) { + // While some earlier supported versions of Next.js work with node v12, + // next@13 cannot even be imported with node v12 (newer JS syntax is used). + // To simplify, and because node v12 is EOL, we skip any testing with + // node <=14.6.0 (next@13's min supported node version). + console.log(`# SKIP test next with node <14.6.0 (node ${process.version})`) + process.exit() +} +if (process.env.ELASTIC_APM_CONTEXT_MANAGER === 'patch') { + console.log('# SKIP Next.js instrumentation does not work with contextManager="patch"') + process.exit() +} + +const testAppDir = path.join(__dirname, 'a-nextjs-app') + +// Match ANSI escapes (from https://stackoverflow.com/a/29497680/14444044). +const ANSI_RE = /[\u001b\u009b][[()#;?]*(?:[0-9]{1,4}(?:;[0-9]{0,4})*)?[0-9A-ORZcf-nqry=><]/g /* eslint-disable-line no-control-regex */ + +let apmServer +let nextJsVersion // Determined after `npm ci` is run. +let serverUrl + +// TEST_REQUESTS is an array of requests to test against both a prod-server and +// dev-server run of the 'a-nextjs-app' test app. Each entry is: +// +// { +// testName: '', +// // An object with request options, or a `(buildId) => { ... }` that +// // returns request options. +// reqOpts: Object | Function, +// // An object with expectations of the server response. +// expectedRes: { ... }, +// // Make test assertions of the APM events received for the request. +// checkApmEvents: (t, apmEventsForReq) => { ... }, +// } +// +let TEST_REQUESTS = [ + // Redirects. + { + testName: 'trailing slash redirect', + reqOpts: { method: 'GET', path: '/a-page/' }, + expectedRes: { + statusCode: 308, + headers: { location: '/a-page' } + }, + checkApmEvents: (t, apmEventsForReq) => { + t.equal(apmEventsForReq.length, 1) + const trans = apmEventsForReq[0].transaction + t.equal(trans.name, 'Next.js Redirect route /:path+/', 'transaction.name') + t.equal(trans.context.response.status_code, 308, 'transaction.context.response.status_code') + } + }, + { + testName: 'configured (in next.config.js) redirect', + reqOpts: { method: 'GET', path: '/redirect-to-a-page' }, + expectedRes: { + statusCode: 307, + headers: { location: '/a-page' } + }, + checkApmEvents: (t, apmEventsForReq) => { + t.equal(apmEventsForReq.length, 1) + const trans = apmEventsForReq[0].transaction + t.equal(trans.name, 'Next.js Redirect route /redirect-to-a-page', 'transaction.name') + t.equal(trans.context.response.status_code, 307, 'transaction.context.response.status_code') + } + }, + + // Rewrites are configured in "next.config.js". + { + testName: 'rewrite to a page', + reqOpts: { method: 'GET', path: '/rewrite-to-a-page' }, + expectedRes: { + statusCode: 200, + headers: { 'content-type': /text\/html/ }, + // This shows that we got the content from "pages/a-page.js". + body: /This is APage/ + }, + checkApmEvents: (t, apmEventsForReq) => { + t.equal(apmEventsForReq.length, 1) + const trans = apmEventsForReq[0].transaction + t.equal(trans.name, 'Next.js Rewrite route /rewrite-to-a-page -> /a-page', 'transaction.name') + t.equal(trans.context.response.status_code, 200, 'transaction.context.response.status_code') + } + }, + { + testName: 'rewrite to a dynamic page', + reqOpts: { method: 'GET', path: '/rewrite-to-a-dynamic-page/3.14159' }, + expectedRes: { + statusCode: 200, + headers: { 'content-type': /text\/html/ }, + body: /This is ADynamicPage/ + }, + checkApmEvents: (t, apmEventsForReq) => { + t.equal(apmEventsForReq.length, 1) + const trans = apmEventsForReq[0].transaction + t.equal(trans.name, 'Next.js Rewrite route /rewrite-to-a-dynamic-page/:num -> /a-dynamic-page/:num', 'transaction.name') + t.equal(trans.context.response.status_code, 200, 'transaction.context.response.status_code') + } + }, + { + testName: 'rewrite to a /public/... folder file', + reqOpts: { method: 'GET', path: '/rewrite-to-a-public-file' }, + expectedRes: { + statusCode: 200, + headers: { 'content-type': 'image/x-icon' } + }, + checkApmEvents: (t, apmEventsForReq) => { + t.equal(apmEventsForReq.length, 1) + const trans = apmEventsForReq[0].transaction + t.equal(trans.name, 'Next.js Rewrite route /rewrite-to-a-public-file -> /favicon.ico', 'transaction.name') + t.equal(trans.context.response.status_code, 200, 'transaction.context.response.status_code') + } + }, + { + testName: 'rewrite to a 404', + reqOpts: { method: 'GET', path: '/rewrite-to-a-404' }, + expectedRes: { + statusCode: 404 + }, + checkApmEvents: (t, apmEventsForReq) => { + t.equal(apmEventsForReq.length, 1) + const trans = apmEventsForReq[0].transaction + t.equal(trans.name, 'Next.js Rewrite route /rewrite-to-a-404 -> /no-such-page', 'transaction.name') + t.equal(trans.context.response.status_code, 404, 'transaction.context.response.status_code') + } + }, + { + testName: 'rewrite to a external site', + reqOpts: { method: 'GET', path: '/rewrite-external/foo' }, + expectedRes: { + // This is a 500 because the configured `old.example.com` doesn't resolve. + statusCode: 500 + }, + checkApmEvents: (t, apmEventsForReq) => { + t.ok(apmEventsForReq.length === 1 || apmEventsForReq.length === 2, 'expected number of APM events') + const trans = apmEventsForReq[0].transaction + t.equal(trans.name, 'Next.js Rewrite route /rewrite-external/:path* -> https://old.example.com/:path*', 'transaction.name') + t.equal(trans.context.response.status_code, 500, 'transaction.context.response.status_code') + // Limitation: Currently the instrumentation only captures an error with + // the DevServer, because Next.js special cases dev-mode and calls + // `renderErrorToResponse`. To capture the error with NextNodeServer we + // would need to shim `Server.run()` in base-server.js. + if (apmEventsForReq.length === 2) { + const error = apmEventsForReq[1].error + t.equal(trans.trace_id, error.trace_id, 'transaction and error are in same trace') + t.equal(error.parent_id, trans.id, 'error is a child of the transaction') + t.equal(error.transaction.type, 'request', 'error.transaction.type') + t.equal(error.transaction.name, trans.name, 'error.transaction.name') + t.equal(error.exception.message, 'getaddrinfo ENOTFOUND old.example.com', 'error.exception.message') + } + } + }, + + // The different kinds of pages. + { + testName: 'index page', + reqOpts: { method: 'GET', path: '/' }, + expectedRes: { + statusCode: 200, + headers: { 'content-type': /text\/html/ }, + body: /This is IndexPage/ + }, + checkApmEvents: (t, apmEventsForReq) => { + t.equal(apmEventsForReq.length, 1) + const trans = apmEventsForReq[0].transaction + t.equal(trans.name, 'GET /', 'transaction.name') + t.equal(trans.context.response.status_code, 200, 'transaction.context.response.status_code') + } + }, + { + testName: 'a page (Server-Side Generated, SSG)', + reqOpts: { method: 'GET', path: '/a-page' }, + expectedRes: { + statusCode: 200, + headers: { 'content-type': /text\/html/ }, + body: /This is APage/ + }, + checkApmEvents: (t, apmEventsForReq) => { + t.equal(apmEventsForReq.length, 1) + const trans = apmEventsForReq[0].transaction + t.equal(trans.name, 'GET /a-page', 'transaction.name') + t.equal(trans.context.response.status_code, 200, 'transaction.context.response.status_code') + } + }, + { + testName: 'a dynamic page', + reqOpts: { method: 'GET', path: '/a-dynamic-page/42' }, + expectedRes: { + statusCode: 200, + headers: { 'content-type': /text\/html/ }, + body: /This is ADynamicPage/ + }, + checkApmEvents: (t, apmEventsForReq) => { + t.equal(apmEventsForReq.length, 1) + const trans = apmEventsForReq[0].transaction + t.equal(trans.name, 'GET /a-dynamic-page/[num]', 'transaction.name') + t.equal(trans.context.response.status_code, 200, 'transaction.context.response.status_code') + } + }, + { + testName: 'a server-side rendered (SSR) page', + reqOpts: { method: 'GET', path: '/an-ssr-page' }, + expectedRes: { + statusCode: 200, + headers: { 'content-type': /text\/html/ }, + body: /This is AnSSRPage/ + }, + checkApmEvents: (t, apmEventsForReq) => { + t.equal(apmEventsForReq.length, 1) + const trans = apmEventsForReq[0].transaction + t.equal(trans.name, 'GET /an-ssr-page', 'transaction.name') + t.equal(trans.context.response.status_code, 200, 'transaction.context.response.status_code') + } + }, + + // API endpoint pages + { + testName: 'an API endpoint page', + reqOpts: { method: 'GET', path: '/api/an-api-endpoint' }, + expectedRes: { + statusCode: 200, + headers: { 'content-type': /application\/json/ }, + body: '{"ping":"pong"}' + }, + checkApmEvents: (t, apmEventsForReq) => { + t.equal(apmEventsForReq.length, 1) + const trans = apmEventsForReq[0].transaction + t.equal(trans.name, 'GET /api/an-api-endpoint', 'transaction.name') + t.equal(trans.context.response.status_code, 200, 'transaction.context.response.status_code') + } + }, + { + testName: 'a dynamic API endpoint page', + reqOpts: { method: 'GET', path: '/api/a-dynamic-api-endpoint/123' }, + expectedRes: { + statusCode: 200, + headers: { 'content-type': /application\/json/ }, + body: '{"num":"123","n":123,"double":246,"floor":123}' + }, + checkApmEvents: (t, apmEventsForReq) => { + t.equal(apmEventsForReq.length, 1) + const trans = apmEventsForReq[0].transaction + t.equal(trans.name, 'GET /api/a-dynamic-api-endpoint/[num]', 'transaction.name') + t.equal(trans.context.response.status_code, 200, 'transaction.context.response.status_code') + } + }, + + // Various internal Next.js routes. + // The other routes that our instrumentation covers are listed in + // `wrapFsRoute` in "next-server.js" and "next-dev-server.js". + { + testName: '"_next/data catchall" route', + reqOpts: buildId => { + return { method: 'GET', path: `/_next/data/${buildId}/a-page.json` } + }, + expectedRes: { + statusCode: 200, + headers: { 'content-type': /application\/json/ } + }, + checkApmEvents: (t, apmEventsForReq) => { + t.equal(apmEventsForReq.length, 1) + const trans = apmEventsForReq[0].transaction + t.equal(trans.name, 'Next.js _next/data route /a-page', 'transaction.name') + t.equal(trans.context.response.status_code, 200, 'transaction.context.response.status_code') + } + }, + + // Error capture cases + { + testName: 'an API endpoint that throws', + // Limitation: In Next.js commit 6bc7c4d9c (included in 12.0.11-canary.14), + // the `apiResolver()` method that we instrument was moved from + // next/dist/server/api-utils.js to next/dist/server/api-utils/node.js. + // We instrument the latter. To support error capture in API endpoint + // handlers in early versions we'd need to instrument the former path as well. + nextVersionRange: '>=12.0.11-canary.14', + reqOpts: { method: 'GET', path: '/api/an-api-endpoint-that-throws' }, + expectedRes: { + statusCode: 500 + }, + checkApmEvents: (t, apmEventsForReq) => { + t.equal(apmEventsForReq.length, 2) + const trans = apmEventsForReq[0].transaction + const error = apmEventsForReq[1].error + t.equal(trans.name, 'GET /api/an-api-endpoint-that-throws', 'transaction.name') + t.equal(trans.context.response.status_code, 500, 'transaction.context.response.status_code') + t.ok(error, 'captured an APM error') + t.equal(trans.trace_id, error.trace_id, 'transaction and error are in same trace') + t.equal(error.parent_id, trans.id, 'error is a child of the transaction') + t.equal(error.transaction.type, 'request', 'error.transaction.type') + t.equal(error.transaction.name, trans.name, 'error.transaction.name') + t.equal(error.exception.message, 'An error thrown in anApiEndpointThatThrows handler', 'error.exception.message') + } + }, + { + testName: 'a throw in a page handler', + reqOpts: { method: 'GET', path: '/a-throw-in-page-handler' }, + expectedRes: { + statusCode: 500 + }, + checkApmEvents: (t, apmEventsForReq) => { + t.equal(apmEventsForReq.length, 2) + const trans = apmEventsForReq[0].transaction + const error = apmEventsForReq[1].error + t.equal(trans.name, 'GET /a-throw-in-page-handler', 'transaction.name') + t.equal(trans.context.response.status_code, 500, 'transaction.context.response.status_code') + t.ok(error, 'captured an APM error') + t.equal(trans.trace_id, error.trace_id, 'transaction and error are in same trace') + t.equal(error.parent_id, trans.id, 'error is a child of the transaction') + t.equal(error.transaction.type, 'request', 'error.transaction.type') + t.equal(error.transaction.name, trans.name, 'error.transaction.name') + t.equal(error.exception.message, 'throw in page handler', 'error.exception.message') + } + }, + { + testName: 'a throw in getServerSideProps', + // Limitation: There was a bug in v11.1.0 where the error handling flow in + // the *dev* server was incomplete. This was fixed in + // https://github.com/vercel/next.js/pull/28520, included in version + // 11.1.1-canary.18. + nextVersionRange: '>=11.1.1-canary.18', + reqOpts: { method: 'GET', path: '/a-throw-in-getServerSideProps' }, + expectedRes: { + statusCode: 500 + }, + checkApmEvents: (t, apmEventsForReq) => { + t.equal(apmEventsForReq.length, 2) + const trans = apmEventsForReq[0].transaction + const error = apmEventsForReq[1].error + t.equal(trans.name, 'GET /a-throw-in-getServerSideProps', 'transaction.name') + t.equal(trans.context.response.status_code, 500, 'transaction.context.response.status_code') + t.ok(error, 'captured an APM error') + t.equal(trans.trace_id, error.trace_id, 'transaction and error are in same trace') + t.equal(error.parent_id, trans.id, 'error is a child of the transaction') + t.equal(error.transaction.type, 'request', 'error.transaction.type') + t.equal(error.transaction.name, trans.name, 'error.transaction.name') + t.equal(error.exception.message, 'thrown error in getServerSideProps', 'error.exception.message') + } + } +] +// Dev Note: To limit a test run to a particular test request, provide a +// string value to DEV_TEST_FILTER that matches `testName`. +var DEV_TEST_FILTER = null +if (DEV_TEST_FILTER) { + TEST_REQUESTS = TEST_REQUESTS.filter(testReq => ~testReq.testName.indexOf(DEV_TEST_FILTER)) + assert(TEST_REQUESTS.length > 0, 'DEV_TEST_FILTER should not result in an *empty* TEST_REQUESTS') +} + +// ---- utility functions + +/** + * Format the given data for passing to `t.comment()`. + * + * - t.comment() wipes leading whitespace. Prefix lines with '|' to avoid + * that, and to visually group a multi-line write. + * - Drop ANSI escape characters, because those include control chars that + * are illegal in XML. When we convert TAP output to JUnit XML for + * Jenkins, then Jenkins complains about invalid XML. `FORCE_COLOR=0` + * can be used to disable ANSI escapes in `next dev`'s usage of chalk, + * but not in its coloured exception output. + */ +function formatForTComment (data) { + return data.toString('utf8') + .replace(ANSI_RE, '') + .trimRight().replace(/\n/g, '\n|') + '\n' +} + +/** + * Wait for the test a-nextjs-app server to be ready. + * + * This polls `GET /api/an-api-endpoint` until the expected 200 response is + * received. It times out after ~10s. + * + * @param {Test} t - This is only used to `t.comment(...)` with progress. + * @param {Function} cb - Calls `cb(err)` if there was a timeout, `cb()` on + * success. + */ +function waitForServerReady (t, cb) { + let sentinel = 10 + + const pollForServerReady = () => { + const req = http.get( + 'http://localhost:3000/api/an-api-endpoint', + { + agent: false, + timeout: 500 + }, + res => { + if (res.statusCode !== 200) { + res.resume() + scheduleNextPoll(`statusCode=${res.statusCode}`) + } + const chunks = [] + res.on('data', chunk => { chunks.push(chunk) }) + res.on('end', () => { + try { + const body = Buffer.concat(chunks).toString() + if (body && JSON.parse(body).ping === 'pong') { + cb() + } else { + scheduleNextPoll(`unexpected body: ${body}`) + } + } catch (bodyErr) { + scheduleNextPoll(bodyErr.message) + } + }) + } + ) + req.on('error', err => { + scheduleNextPoll(err.message) + }) + } + + const scheduleNextPoll = (msg) => { + t.comment(`[sentinel=${sentinel} ${new Date().toISOString()}] wait another 1s for server ready: ${msg}`) + sentinel-- + if (sentinel <= 0) { + cb(new Error('timed out')) + } else { + setTimeout(pollForServerReady, 1000) + } + } + + pollForServerReady() +} + +async function makeTestRequest (t, testReq, buildId) { + return new Promise((resolve, reject) => { + let reqOpts = testReq.reqOpts + if (typeof reqOpts === 'function') { + reqOpts = reqOpts(buildId) + } + const url = `http://localhost:3000${reqOpts.path}` + t.comment(`makeTestRequest: ${testReq.testName} (${reqOpts.method} ${url})`) + const req = http.request( + url, + { + method: reqOpts.method + }, + res => { + const chunks = [] + res.on('data', chunk => { chunks.push(chunk) }) + res.on('end', () => { + const body = Buffer.concat(chunks) + if (testReq.expectedRes.statusCode) { + t.equal(res.statusCode, testReq.expectedRes.statusCode, `res.statusCode === ${testReq.expectedRes.statusCode}`) + } + if (testReq.expectedRes.headers) { + for (const [k, v] of Object.entries(testReq.expectedRes.headers)) { + if (v instanceof RegExp) { + t.ok(v.test(res.headers[k]), `res.headers[${JSON.stringify(k)}] =~ ${v}`) + } else { + t.equal(res.headers[k], v, `res.headers[${JSON.stringify(k)}] === ${JSON.stringify(v)}`) + } + } + } + if (testReq.expectedRes.body) { + if (testReq.expectedRes.body instanceof RegExp) { + t.ok(testReq.expectedRes.body.test(body), `body =~ ${testReq.expectedRes.body}`) + } else if (typeof testReq.expectedRes.body === 'string') { + t.equal(body.toString(), testReq.expectedRes.body, 'body') + } else { + t.fail(`unsupported type for TEST_REQUESTS[].expectedRes.body: ${typeof testReq.expectedRes.body}`) + } + } + resolve() + }) + } + ) + req.on('error', reject) + req.end() + }) +} + +function getEventField (e, fieldName) { + return (e.transaction || e.error || e.span)[fieldName] +} + +/** + * Return the buildId for this Next.js prod server. The buildId is stored + * in ".next/BUILD_ID" by `next build`. + */ +function getNextProdServerBuildId () { + const buildIdPath = path.join(testAppDir, '.next', 'BUILD_ID') + return fs.readFileSync(buildIdPath, 'utf8').trim() +} + +/** + * Assert that the given `apmEvents` (events that the mock APM server received) + * match all the expected APM events in `TEST_REQUESTS`. + */ +function checkExpectedApmEvents (t, apmEvents) { + // metadata + let evt = apmEvents.shift() + t.ok(evt.metadata, 'metadata is first event') + t.equal(evt.metadata.service.name, 'a-nextjs-app', 'metadata.service.name') + t.equal(evt.metadata.service.framework.name, 'Next.js', 'metadata.service.framework.name') + t.equal(evt.metadata.service.framework.version, nextJsVersion, 'metadata.service.framework.version') + + // Filter out any metadata from separate requests, and metricsets which we + // aren't testing. + apmEvents = apmEvents + .filter(e => !e.metadata) + .filter(e => !e.metricset) + + // One `GET /api/an-api-endpoint` from waitForServerReady. + evt = apmEvents.shift() + t.equal(evt.transaction.name, 'GET /api/an-api-endpoint', 'waitForServerReady request') + t.equal(evt.transaction.outcome, 'success', 'transaction.outcome') + + // Sort all the remaining APM events and check expectations from TEST_REQUESTS. + apmEvents = apmEvents + .sort((a, b) => { + return getEventField(a, 'timestamp') < getEventField(b, 'timestamp') ? -1 : 1 + }) + TEST_REQUESTS.forEach(testReq => { + t.comment(`check APM events for "${testReq.testName}"`) + // Collect all events for this transaction's trace_id, and pass that to + // the `checkApmEvents` function for this request. + assert(apmEvents.length > 0 && apmEvents[0].transaction, `next APM event is a transaction: ${JSON.stringify(apmEvents[0])}`) + const traceId = apmEvents[0].transaction.trace_id + const apmEventsForReq = apmEvents.filter(e => getEventField(e, 'trace_id') === traceId) + apmEvents = apmEvents.filter(e => getEventField(e, 'trace_id') !== traceId) + testReq.checkApmEvents(t, apmEventsForReq) + }) + + t.equal(apmEvents.length, 0, 'no additional unexpected APM server events: ' + JSON.stringify(apmEvents)) +} + +// ---- tests + +// We need to `npm ci` for a first test run. However, *only* for a first test +// run, otherwise this will override any possible `npm install --no-save ...` +// changes made by a TAV runner. +const haveNodeModules = fs.existsSync(path.join(testAppDir, 'node_modules')) +tape.test(`setup: npm ci (in ${testAppDir})`, { skip: haveNodeModules }, t => { + const startTime = Date.now() + exec( + 'npm ci', + { + cwd: testAppDir + }, + function (err, stdout, stderr) { + t.error(err, `"npm ci" succeeded (took ${(Date.now() - startTime) / 1000}s)`) + if (err) { + t.comment(`$ npm ci\n-- stdout --\n${stdout}\n-- stderr --\n${stderr}\n--`) + } + t.end() + } + ) +}) + +tape.test('setup: filter TEST_REQUESTS', t => { + // This version can only be fetched after the above `npm ci`. + nextJsVersion = require(path.join(testAppDir, 'node_modules/next/package.json')).version + + // Some entries in TEST_REQUESTS are only run for newer versions of Next.js. + TEST_REQUESTS = TEST_REQUESTS.filter(testReq => { + if (testReq.nextVersionRange && !semver.satisfies(nextJsVersion, testReq.nextVersionRange, { includePrerelease: true })) { + t.comment(`skip "${testReq.testName}" because next@${nextJsVersion} does not satisfy "${testReq.nextVersionRange}"`) + return false + } else { + return true + } + }) + + t.end() +}) + +tape.test('setup: mock APM server', t => { + apmServer = new MockAPMServer({ apmServerVersion: '7.15.0' }) + apmServer.start(function (serverUrl_) { + serverUrl = serverUrl_ + t.comment('mock APM serverUrl: ' + serverUrl) + t.end() + }) +}) + +// Test the Next "prod" server. I.e. `next build && next start`. +tape.test('-- prod server tests --', suite => { + let nextServerProc + + suite.test('setup: npm run build', t => { + const startTime = Date.now() + exec( + 'npm run build', + { + cwd: testAppDir + }, + function (err, stdout, stderr) { + t.error(err, `"npm run build" succeeded (took ${(Date.now() - startTime) / 1000}s)`) + if (err) { + t.comment(`$ npm run build\n-- stdout --\n${stdout}\n-- stderr --\n${stderr}\n--`) + } + t.end() + } + ) + }) + + suite.test('setup: start Next.js prod server (next start)', t => { + // Ideally we would simply spawn `npm run start` -- which handles setting + // NODE_OPTIONS. However, that results in a process tree: + // + // `- npm + // `- /tmp/.../tmp-$hash.sh + // `- node ./node_modules/.bin/next start + // that, in Docker, will reduce to: + // + // `- node ./node_modules/.bin/next start + // And our attempts to signal, `nextServerProc.kill()`, will fail to signal + // the actual server because the `npm` process is gone. + nextServerProc = spawn( + path.normalize('./node_modules/.bin/next'), + // Be explicit about "localhost" here, otherwise with node v18 we can + // get the server listening on IPv6 and the client connecting on IPv4. + ['start', '-H', 'localhost'], + { + shell: os.platform() === 'win32', + cwd: testAppDir, + env: Object.assign({}, process.env, { + NODE_OPTIONS: '-r ../../../../../start-next.js', + ELASTIC_APM_SERVER_URL: serverUrl, + ELASTIC_APM_API_REQUEST_TIME: '2s', + // Disable Next.js telemetry (https://nextjs.org/telemetry), + // otherwise get additional `POST telemetry.nextjs.org` spans that + // break assertions. + NEXT_TELEMETRY_DISABLED: '1' + }) + } + ) + nextServerProc.on('error', err => { + t.error(err, 'no error from "next start"') + }) + nextServerProc.stdout.on('data', data => { + t.comment(`[Next.js server stdout] ${formatForTComment(data)}`) + }) + nextServerProc.stderr.on('data', data => { + t.comment(`[Next.js server stderr] ${formatForTComment(data)}`) + }) + + // Allow some time for an early fail of `next start`, e.g. if there is + // already a user of port 3000... + const onEarlyClose = code => { + t.fail(`"next start" failed early: code=${code}`) + nextServerProc = null + clearTimeout(earlyCloseTimer) + t.end() + } + nextServerProc.on('close', onEarlyClose) + const earlyCloseTimer = setTimeout(() => { + nextServerProc.removeListener('close', onEarlyClose) + + // ... then wait for the server to be ready. + waitForServerReady(t, waitErr => { + if (waitErr) { + t.fail(`error waiting for Next.js server to be ready: ${waitErr.message}`) + nextServerProc.kill('SIGKILL') + nextServerProc = null + } else { + t.comment('Next.js server is ready') + } + t.end() + }) + }, 1000) + }) + + suite.test('make requests', async t => { + if (!nextServerProc) { + t.skip('there is no nextServerProc') + t.end() + return + } + + const buildId = getNextProdServerBuildId() + apmServer.clear() + for (let i = 0; i < TEST_REQUESTS.length; i++) { + await makeTestRequest(t, TEST_REQUESTS[i], buildId) + } + t.end() + }) + + suite.test('check all APM events', t => { + if (!nextServerProc) { + t.skip('there is no nextServerProc') + t.end() + return + } + + // To ensure we get all the trace data from the instrumented Next.js + // server, we wait 2x the `apiRequestTime` (set above) before stopping it. + nextServerProc.on('close', code => { + t.equal(code, 0, 'Next.js server exit status was 0') + checkExpectedApmEvents(t, apmServer.events) + t.end() + }) + setTimeout(() => { + nextServerProc.kill('SIGTERM') + }, 4000) // 2x ELASTIC_APM_API_REQUEST_SIZE set above + }) + + suite.end() +}) + +// Test the Next "dev" server. I.e. `next dev`. +tape.test('-- dev server tests --', suite => { + let nextServerProc + + suite.test('setup: start Next.js dev server (next dev)', t => { + // See the warning notes for `spawn()` above. The same apply here. + nextServerProc = spawn( + path.normalize('./node_modules/.bin/next'), + ['dev', '-H', 'localhost'], + { + shell: os.platform() === 'win32', + cwd: testAppDir, + env: Object.assign({}, process.env, { + NODE_OPTIONS: '-r ../../../../../start-next.js', + ELASTIC_APM_SERVER_URL: serverUrl, + ELASTIC_APM_API_REQUEST_TIME: '2s', + // Disable Next.js telemetry (https://nextjs.org/telemetry), + // otherwise get additional `POST telemetry.nextjs.org` spans that + // break assertions. + NEXT_TELEMETRY_DISABLED: '1' + }) + } + ) + nextServerProc.on('error', err => { + t.error(err, 'no error from "next dev"') + }) + nextServerProc.stdout.on('data', data => { + t.comment(`[Next.js server stdout] ${formatForTComment(data)}`) + }) + nextServerProc.stderr.on('data', data => { + t.comment(`[Next.js server stderr] ${formatForTComment(data)}`) + }) + + // Allow some time for an early fail of `next dev`, e.g. if there is + // already a user of port 3000... + const onEarlyClose = code => { + t.fail(`"next dev" failed early: code=${code}`) + nextServerProc = null + clearTimeout(earlyCloseTimer) + t.end() + } + nextServerProc.on('close', onEarlyClose) + const earlyCloseTimer = setTimeout(() => { + nextServerProc.removeListener('close', onEarlyClose) + + // ... then wait for the server to be ready. + waitForServerReady(t, waitErr => { + if (waitErr) { + t.fail(`error waiting for Next.js server to be ready: ${waitErr.message}`) + nextServerProc.kill('SIGKILL') + nextServerProc = null + } else { + t.comment('Next.js server is ready') + } + t.end() + }) + }, 1000) + }) + + suite.test('make requests', async t => { + if (!nextServerProc) { + t.skip('there is no nextServerProc') + t.end() + return + } + apmServer.clear() + + for (let i = 0; i < TEST_REQUESTS.length; i++) { + await makeTestRequest(t, TEST_REQUESTS[i], 'development') + } + + t.end() + }) + + suite.test('check all APM events', t => { + if (!nextServerProc) { + t.skip('there is no nextServerProc') + t.end() + return + } + + // To ensure we get all the trace data from the instrumented Next.js + // server, we wait 2x the `apiRequestTime` (set above) before stopping it. + nextServerProc.on('close', code => { + t.equal(code, 0, 'Next.js server exit status was 0') + checkExpectedApmEvents(t, apmServer.events) + t.end() + }) + setTimeout(() => { + nextServerProc.kill('SIGTERM') + }, 4000) // 2x ELASTIC_APM_API_REQUEST_SIZE set above + }) + + suite.end() +}) + +tape.test('teardown: mock APM server', t => { + apmServer.close() + t.end() +}) diff --git a/test/instrumentation/modules/pg/knex-no-span-stack-traces.test.js b/test/instrumentation/modules/pg/knex-no-span-stack-traces.test.js new file mode 100644 index 00000000000..3e5f9b1a226 --- /dev/null +++ b/test/instrumentation/modules/pg/knex-no-span-stack-traces.test.js @@ -0,0 +1,46 @@ +/* + * Copyright Elasticsearch B.V. and other contributors where applicable. + * Licensed under the BSD 2-Clause License; you may not use this file except in + * compliance with the BSD 2-Clause License. + */ + +'use strict' + +var agent = require('../../../..').start({ + serviceName: 'test-knex-no-span-stack-traces', + secretToken: 'test', + captureExceptions: false, + metricsInterval: 0, + centralConfig: false, + apmServerVersion: '8.0.0', + // Disable span stack traces, to test that knex instrumentation is then disabled. + spanStackTraceMinDuration: -1 +}) + +var knexVersion = require('knex/package').version +var semver = require('semver') + +// knex 0.18.0 min supported node is v8, knex 0.21.0 min supported node is v10 +if ((semver.gte(knexVersion, '0.18.0') && semver.lt(process.version, '8.6.0')) || + (semver.gte(knexVersion, '0.21.0') && semver.lt(process.version, '10.22.0'))) { + console.log(`# SKIP knex@${knexVersion} does not support node ${process.version}`) + process.exit() +} +// Instrumentation does not work with Knex >=0.95.0 and `contextManager=patch`. +// The "patch" context manager is deprecated. +if (semver.gte(knexVersion, '0.95.0') && agent._conf.contextManager === 'patch') { + console.log(`# SKIP knex@${knexVersion} and contextManager='patch' is not support`) + process.exit() +} + +var Knex = require('knex') +var test = require('tape') + +test('knex instrumentation is disabled if not collecting span stacktraces', t => { + // To test that knex instrumentation did *not* happen, we are assuming that + // knex instrumentation wraps `Knex.Client.prototype.runner` and changes the + // method name (to `wrappedRunner`). + const runnerMethod = Knex.Client.prototype.runner + t.equal(runnerMethod.name, 'runner', 'Knex.Client.prototype.runner method name has not been changed') + t.end() +}) diff --git a/test/instrumentation/modules/pg/knex.test.js b/test/instrumentation/modules/pg/knex.test.js index 40eeda2b84c..0612c4864a2 100644 --- a/test/instrumentation/modules/pg/knex.test.js +++ b/test/instrumentation/modules/pg/knex.test.js @@ -27,6 +27,12 @@ if ((semver.gte(knexVersion, '0.18.0') && semver.lt(process.version, '8.6.0')) | console.log(`# SKIP knex@${knexVersion} does not support node ${process.version}`) process.exit() } +// Instrumentation does not work with Knex >=0.95.0 and `contextManager=patch`. +// The "patch" context manager is deprecated. +if (semver.gte(knexVersion, '0.95.0') && agent._conf.contextManager === 'patch') { + console.log(`# SKIP knex@${knexVersion} and contextManager='patch' is not supported`) + process.exit() +} var Knex = require('knex') var test = require('tape') diff --git a/test/instrumentation/modules/pg/pg.test.js b/test/instrumentation/modules/pg/pg.test.js index 11d9b54fdc2..6b3e64de61d 100644 --- a/test/instrumentation/modules/pg/pg.test.js +++ b/test/instrumentation/modules/pg/pg.test.js @@ -577,16 +577,20 @@ function assertSpan (t, span, sql) { t.strictEqual(span.type, 'db') t.strictEqual(span.subtype, 'postgresql') t.strictEqual(span.action, 'query') - t.deepEqual(span.context.db, { statement: sql, type: 'sql' }) + t.deepEqual(span.context.db, { + type: 'sql', + statement: sql, + instance: 'test_elastic_apm', + user: process.env.PGUSER || 'postgres' + }, 'span.context.db') + t.deepEqual(span.context.service.target, + { type: 'postgresql', name: 'test_elastic_apm' }, + 'span.context.service.target') t.deepEqual(span.context.destination, { - service: { - name: 'postgresql', - resource: 'postgresql', - type: 'db' - }, address: process.env.PGHOST || 'localhost', - port: 5432 - }) + port: 5432, + service: { type: '', name: '', resource: 'postgresql/test_elastic_apm' } + }, 'span.context.destination') } function createClient (cb) { diff --git a/test/instrumentation/modules/redis-2-3.test.js b/test/instrumentation/modules/redis-2-3.test.js new file mode 100644 index 00000000000..725ea63fa7a --- /dev/null +++ b/test/instrumentation/modules/redis-2-3.test.js @@ -0,0 +1,249 @@ +/* + * Copyright Elasticsearch B.V. and other contributors where applicable. + * Licensed under the BSD 2-Clause License; you may not use this file except in + * compliance with the BSD 2-Clause License. + */ + +'use strict' + +var redisVersion = require('redis/package.json').version +var semver = require('semver') +if (semver.gte(redisVersion, '4.0.0')) { + console.log('# SKIP: skipping redis-2-3.test.js tests >=4.0.0') + process.exit(0) +} + +var agent = require('../../..').start({ + serviceName: 'test-redis-2-3', + captureExceptions: false, + metricsInterval: 0, + centralConfig: false, + spanCompressionEnabled: false +}) + +var redis = require('redis') + +var test = require('tape') + +var findObjInArray = require('../../_utils').findObjInArray +var mockClient = require('../../_mock_http_client') + +test('redis', function (t) { + resetAgent(function (data) { + t.strictEqual(data.transactions.length, 2, 'have 2 transactions') + + // We expect a 'transBeforeClient' transaction, and we want to ensure it + // does *not* have spans for each of the client commands. It *possibly* + // (with contextManager="patch" it doesn't) has an "INFO" span for the + // internal INFO command the RedisClient setup does. + var trans = findObjInArray(data.transactions, 'name', 'transBeforeClient') + t.ok(trans, 'have "transBeforeClient" transaction') + var spans = data.spans.filter(s => s.transaction_id === trans.id) + .filter(s => s.name !== 'INFO') + t.equal(spans.length, 0, 'there are no non-INFO spans in the "transBeforeClient" transaction') + + // Sort the remaining spans by timestamp, because asynchronous-span.end() + // means they can be set to APM server out of order. + spans = data.spans + .filter(s => s.transaction_id !== trans.id) + .sort((a, b) => { return a.timestamp < b.timestamp ? -1 : 1 }) + trans = findObjInArray(data.transactions, 'name', 'transAfterClient') + t.ok(trans, 'have "transAfterClient" transaction') + t.strictEqual(trans.result, 'success', 'trans.result') + + var expectedSpanNames = [ + 'FLUSHALL', + 'SET', + 'SET', + 'HSET', + 'HSET', + 'HKEYS' + ] + t.equal(spans.length, expectedSpanNames.length, 'have the expected number of spans') + for (var i = 0; i < expectedSpanNames.length; i++) { + const expectedName = expectedSpanNames[i] + const span = spans[i] + t.strictEqual(span.transaction_id, trans.id, 'span.transaction_id') + t.strictEqual(span.name, expectedName, 'span.name') + t.strictEqual(span.type, 'db', 'span.type') + t.strictEqual(span.subtype, 'redis', 'span.subtype') + t.strictEqual(span.action, 'query', 'span.action') + t.deepEqual(span.context.service.target, { type: 'redis' }, 'span.context.service.target') + t.deepEqual(span.context.destination, { + address: process.env.REDIS_HOST || '127.0.0.1', + port: 6379, + service: { name: '', type: '', resource: 'redis' } + }, 'span.context.destination') + t.deepEqual(span.context.db, { type: 'redis' }, 'span.context.db') + t.strictEqual(span.parent_id, trans.id, 'span is a child of the transaction') + + var offset = span.timestamp - trans.timestamp + t.ok(offset + span.duration * 1000 < trans.duration * 1000, + 'span ended before transaction ended') + } + + t.end() + }) + + // If a redis client is not yet "ready" it will queue client commands, and + // then send them after "ready". Internally this results in calling + // RedisClient.internal_send_command *twice* for each queued command. If the + // instrumentation isn't careful, it is easy to instrument both of those + // calls. The latter call will only result in a span if there is a + // currentTransaction for the async task in which the redis client is created. + // That's what `transBeforeClient` is: to make sure we *don't* get + // double-spans. + var transBeforeClient = agent.startTransaction('transBeforeClient') + + var client = redis.createClient('6379', process.env.REDIS_HOST) + + var transAfterClient = agent.startTransaction('transAfterClient') + + client.flushall(function (err, reply) { + t.error(err, 'no flushall error') + t.strictEqual(reply, 'OK', 'reply is OK') + var done = 0 + + client.set('string key', 'string val', function (err, reply) { + t.error(err) + t.strictEqual(reply, 'OK', 'reply is OK') + done++ + }) + + // callback is optional + client.set('string key', 'string val') + + client.hset('hash key', 'hashtest 1', 'some value', function (err, reply) { + t.error(err, 'no hset error') + t.strictEqual(reply, 1, 'hset reply is 1') + done++ + }) + client.hset(['hash key', 'hashtest 2', 'some other value'], function (err, reply) { + t.error(err, 'no hset error') + t.strictEqual(reply, 1, 'hset reply is 1') + done++ + }) + + client.hkeys('hash key', function (err, replies) { + t.error(err, 'no hkeys error') + t.strictEqual(replies.length, 2, 'got two replies') + replies.forEach(function (reply, i) { + t.strictEqual(reply, 'hashtest ' + (i + 1), `reply ${i} value`) + }) + done++ + t.strictEqual(done, 4, 'done 4 callbacks') + + transAfterClient.end() + transBeforeClient.end() + client.quit() + agent.flush() + }) + }) +}) + +// Skip testing error capture with redis 2.x. It works, but there are behaviour +// differences (e.g. `client.quit()` throws with `enable_offline_queue: false`) +// such that testing is a pain. Redis 2.x is too old to bother. +if (semver.satisfies(redisVersion, '>=3.0.0')) { + test('redis client error', function (t) { + resetAgent(function (data) { + t.equal(data.transactions.length, 1, 'got 1 transaction') + t.equal(data.spans.length, 1, 'got 1 span') + t.equal(data.errors.length, 1, 'got 1 error') + t.equal(data.spans[0].name, 'SET', 'span.name') + t.equal(data.spans[0].parent_id, data.transactions[0].id, 'span.parent_id') + t.equal(data.spans[0].outcome, 'failure', 'span.outcome') + t.equal(data.errors[0].transaction_id, data.transactions[0].id, 'error.transaction_id') + t.equal(data.errors[0].parent_id, data.spans[0].id, 'error.parent_id, error is a child of the failing span') + t.equal(data.errors[0].exception.type, 'AbortError', 'error.exception.type') + t.end() + }) + + // Simulate a redis client error with `enable_offline_queue: false` and a + // quick `.set()` before the client connection ready. + var client = redis.createClient({ + host: process.env.REDIS_HOST, + port: '6379', + enable_offline_queue: false + }) + var t0 = agent.startTransaction('t0') + client.set('k', 'v', function (err, reply) { + t.ok(err, 'got error from client.set') + t.equal(err.name, 'AbortError', 'error.name') + t.ok(reply === undefined, 'no reply') + t0.end() + client.quit() + agent.flush() + }) + }) +} + +test('client.cmd(...) call signatures', function (t) { + let nCbCalled = 0 + function myCb () { + nCbCalled++ + } + + resetAgent(function (data) { + t.equal(nCbCalled, 2, 'myCb was called the expected number of times') + t.equal(data.transactions.length, 1, 'got 1 transaction') + data.spans.sort((a, b) => { return a.timestamp < b.timestamp ? -1 : 1 }) + t.deepEqual( + data.spans.map(s => s.name), + ['INFO', 'SET', 'GET', 'SET'], + 'got the expected span names' + ) + t.end() + }) + + var client = redis.createClient('6379', process.env.REDIS_HOST) + client.on('ready', function () { + var t0 = agent.startTransaction('t0') + + // Use different call signatures to trigger the different forms of arguments + // to the internal RedisClient.send_command that we are wrapping. + client.info() + client.set('k', 'v') + client.get('k', myCb) + client.set(['k', 'v'], myCb) + + t0.end() + client.quit() + agent.flush() + }) +}) + +if (semver.satisfies(redisVersion, '<=2.4.2')) { + // Redis <=2.4.2 allowed a callback as the last item in an args array. + // Support for this was dropped in commit 60eee34de1. + test('client.cmd([args..., myCb]) call signature', function (t) { + let nCbCalled = 0 + function myCb () { + nCbCalled++ + } + + resetAgent(function (data) { + t.equal(nCbCalled, 1, 'myCb was called the expected number of times') + t.equal(data.transactions.length, 1, 'got 1 transaction') + t.equal(data.spans.length, 1, 'got 1 span') + t.equal(data.spans[0].name, 'GET', 'span name is GET') + t.end() + }) + + var client = redis.createClient('6379', process.env.REDIS_HOST) + client.on('ready', function () { + var t0 = agent.startTransaction('t0') + + client.get(['k', myCb]) + + t0.end() + client.quit() + agent.flush() + }) + }) +} + +function resetAgent (cb) { + agent._instrumentation.testReset() + agent._transport = mockClient(cb) +} diff --git a/test/instrumentation/modules/redis.test.js b/test/instrumentation/modules/redis.test.js index df339c7cc51..73d0962ec9c 100644 --- a/test/instrumentation/modules/redis.test.js +++ b/test/instrumentation/modules/redis.test.js @@ -6,7 +6,20 @@ 'use strict' -var agent = require('../../..').start({ +const redisVersion = require('redis/package.json').version +const semver = require('semver') + +if (semver.lt(redisVersion, '4.0.0')) { + console.log('# SKIP: skipping redis.test.js tests <4.0.0') + process.exit(0) +} + +if (semver.lt(process.version, '14.0.0')) { + console.log('# SKIP: skipping redis.test.js tests node node <14 ') + process.exit(0) +} + +const agent = require('../../..').start({ serviceName: 'test-redis', captureExceptions: false, metricsInterval: 0, @@ -14,38 +27,24 @@ var agent = require('../../..').start({ spanCompressionEnabled: false }) -var redis = require('redis') -var redisVersion = require('redis/package.json').version -var semver = require('semver') -var test = require('tape') +const redis = require('redis') +const test = require('tape') -var findObjInArray = require('../../_utils').findObjInArray -var mockClient = require('../../_mock_http_client') +const mockClient = require('../../_mock_http_client') test('redis', function (t) { resetAgent(function (data) { - t.strictEqual(data.transactions.length, 2, 'have 2 transactions') - - // We expect a 'transBeforeClient' transaction, and we want to ensure it - // does *not* have spans for each of the client commands. It *possibly* - // (with asyncHooks=false it doesn't) has an "INFO" span for the internal - // INFO command the RedisClient setup does. - var trans = findObjInArray(data.transactions, 'name', 'transBeforeClient') - t.ok(trans, 'have "transBeforeClient" transaction') - var spans = data.spans.filter(s => s.transaction_id === trans.id) - .filter(s => s.name !== 'INFO') - t.equal(spans.length, 0, 'there are no non-INFO spans in the "transBeforeClient" transaction') + t.strictEqual(data.transactions.length, 1, 'have 1 transaction') + const trans = data.transactions[0] + t.ok(trans.name, 'aTrans', 'trans.name') + t.strictEqual(trans.result, 'success', 'trans.result') // Sort the remaining spans by timestamp, because asynchronous-span.end() // means they can be set to APM server out of order. - spans = data.spans - .filter(s => s.transaction_id !== trans.id) + const spans = data.spans .sort((a, b) => { return a.timestamp < b.timestamp ? -1 : 1 }) - trans = findObjInArray(data.transactions, 'name', 'transAfterClient') - t.ok(trans, 'have "transAfterClient" transaction') - t.strictEqual(trans.result, 'success', 'trans.result') - var expectedSpanNames = [ + const expectedSpanNames = [ 'FLUSHALL', 'SET', 'SET', @@ -54,21 +53,23 @@ test('redis', function (t) { 'HKEYS' ] t.equal(spans.length, expectedSpanNames.length, 'have the expected number of spans') - for (var i = 0; i < expectedSpanNames.length; i++) { + for (let i = 0; i < expectedSpanNames.length; i++) { const expectedName = expectedSpanNames[i] const span = spans[i] + t.strictEqual(span.transaction_id, trans.id, 'span.transaction_id') t.strictEqual(span.name, expectedName, 'span.name') - t.strictEqual(span.type, 'cache', 'span.type') + t.strictEqual(span.type, 'db', 'span.type') t.strictEqual(span.subtype, 'redis', 'span.subtype') t.deepEqual(span.context.destination, { - service: { name: 'redis', resource: 'redis', type: 'cache' }, - address: process.env.REDIS_HOST || '127.0.0.1', - port: 6379 + address: process.env.REDIS_HOST || 'localhost', + port: 6379, + service: { name: '', type: '', resource: 'redis' } }, 'span.context.destination') + t.deepEqual(span.context.db, { type: 'redis' }, 'span.context.db') t.strictEqual(span.parent_id, trans.id, 'span is a child of the transaction') - var offset = span.timestamp - trans.timestamp + const offset = span.timestamp - trans.timestamp t.ok(offset + span.duration * 1000 < trans.duration * 1000, 'span ended before transaction ended') } @@ -76,47 +77,45 @@ test('redis', function (t) { t.end() }) - // If a redis client is not yet "ready" it will queue client commands, and - // then send them after "ready". Internally this results in calling - // RedisClient.internal_send_command *twice* for each queued command. If the - // instrumentation isn't careful, it is easy to instrument both of those - // calls. The latter call will only result in a span if there is a - // currentTransaction for the async task in which the redis client is created. - // That's what `transBeforeClient` is: to make sure we *don't* get - // double-spans. - var transBeforeClient = agent.startTransaction('transBeforeClient') - - var client = redis.createClient('6379', process.env.REDIS_HOST) + const client = redis.createClient({ + socket: { + port: '6379', + host: process.env.REDIS_HOST + } + }) + client.connect() - var transAfterClient = agent.startTransaction('transAfterClient') + const trans = agent.startTransaction('aTrans') - client.flushall(function (err, reply) { - t.error(err, 'no flushall error') + client.flushAll().then(function (reply) { t.strictEqual(reply, 'OK', 'reply is OK') - var done = 0 + let done = 0 - client.set('string key', 'string val', function (err, reply) { - t.error(err) + client.set('string key', 'string val').then(function (reply) { t.strictEqual(reply, 'OK', 'reply is OK') done++ + }).catch(function (err) { + t.error(err) }) // callback is optional client.set('string key', 'string val') - client.hset('hash key', 'hashtest 1', 'some value', function (err, reply) { - t.error(err, 'no hset error') + client.hSet('hash key', 'hashtest 1', 'some value').then(function (reply) { t.strictEqual(reply, 1, 'hset reply is 1') done++ - }) - client.hset(['hash key', 'hashtest 2', 'some other value'], function (err, reply) { + }).catch(function (err) { t.error(err, 'no hset error') + }) + + client.hSet('hash key', ['hashtest 2', 'some other value']).then(function (reply) { t.strictEqual(reply, 1, 'hset reply is 1') done++ + }).catch(function (err) { + t.error(err, 'no hset error') }) - client.hkeys('hash key', function (err, replies) { - t.error(err, 'no hkeys error') + client.hKeys('hash key').then(function (replies) { t.strictEqual(replies.length, 2, 'got two replies') replies.forEach(function (reply, i) { t.strictEqual(reply, 'hashtest ' + (i + 1), `reply ${i} value`) @@ -124,115 +123,56 @@ test('redis', function (t) { done++ t.strictEqual(done, 4, 'done 4 callbacks') - transAfterClient.end() - transBeforeClient.end() + trans.end() client.quit() agent.flush() + }).catch(function (err) { + t.error(err, 'no hkeys error') }) + }).catch(function (err) { + t.error(err, 'no flushall error') }) }) -// Skip testing error capture with redis 2.x. It works, but there are behaviour -// differences (e.g. `client.quit()` throws with `enable_offline_queue: false`) -// such that testing is a pain. Redis 2.x is too old to bother. -if (semver.satisfies(redisVersion, '>=3.0.0')) { - test('redis client error', function (t) { - resetAgent(function (data) { - t.equal(data.transactions.length, 1, 'got 1 transaction') - t.equal(data.spans.length, 1, 'got 1 span') - t.equal(data.errors.length, 1, 'got 1 error') - t.equal(data.spans[0].name, 'SET', 'span.name') - t.equal(data.spans[0].parent_id, data.transactions[0].id, 'span.parent_id') - t.equal(data.spans[0].outcome, 'failure', 'span.outcome') - t.equal(data.errors[0].transaction_id, data.transactions[0].id, 'error.transaction_id') - t.equal(data.errors[0].parent_id, data.spans[0].id, 'error.parent_id, error is a child of the failing span') - t.equal(data.errors[0].exception.type, 'AbortError', 'error.exception.type') - t.end() - }) - - // Simulate a redis client error with `enable_offline_queue: false` and a - // quick `.set()` before the client connection ready. - var client = redis.createClient({ - host: process.env.REDIS_HOST, - port: '6379', - enable_offline_queue: false - }) - var t0 = agent.startTransaction('t0') - client.set('k', 'v', function (err, reply) { - t.ok(err, 'got error from client.set') - t.equal(err.name, 'AbortError', 'error.name') - t.ok(reply === undefined, 'no reply') - t0.end() - client.quit() - agent.flush() - }) - }) -} - -test('client.cmd(...) call signatures', function (t) { - let nCbCalled = 0 - function myCb () { - nCbCalled++ - } - +// The `redis.set('foo')` we are using to trigger a client error case only +// causes an error in redis >=4.1.0. +test('redis client error', { skip: semver.lt(redisVersion, '4.1.0') }, function (t) { resetAgent(function (data) { - t.equal(nCbCalled, 2, 'myCb was called the expected number of times') t.equal(data.transactions.length, 1, 'got 1 transaction') - data.spans.sort((a, b) => { return a.timestamp < b.timestamp ? -1 : 1 }) - t.deepEqual( - data.spans.map(s => s.name), - ['INFO', 'SET', 'GET', 'SET'], - 'got the expected span names' - ) + t.equal(data.spans.length, 1, 'got 1 span') + t.equal(data.errors.length, 1, 'got 1 error') + t.equal(data.spans[0].name, 'SET', 'span.name') + t.equal(data.spans[0].parent_id, data.transactions[0].id, 'span.parent_id') + t.equal(data.spans[0].outcome, 'failure', 'span.outcome') + t.equal(data.errors[0].transaction_id, data.transactions[0].id, 'error.transaction_id') + t.equal(data.errors[0].parent_id, data.spans[0].id, 'error.parent_id, error is a child of the failing span') + t.equal(data.errors[0].exception.type, 'TypeError', 'error.exception.type') t.end() }) - var client = redis.createClient('6379', process.env.REDIS_HOST) - client.on('ready', function () { - var t0 = agent.startTransaction('t0') - - // Use different call signatures to trigger the different forms of arguments - // to the internal RedisClient.send_command that we are wrapping. - client.info() - client.set('k', 'v') - client.get('k', myCb) - client.set(['k', 'v'], myCb) - + // no .finally in Node 8, endPromise performs + // actions we'd normally perform there + function endProimse (t0, client, agent) { t0.end() client.quit() agent.flush() - }) -}) - -if (semver.satisfies(redisVersion, '<=2.4.2')) { - // Redis <=2.4.2 allowed a callback as the last item in an args array. - // Support for this was dropped in commit 60eee34de1. - test('client.cmd([args..., myCb]) call signature', function (t) { - let nCbCalled = 0 - function myCb () { - nCbCalled++ + } + const client = redis.createClient({ + socket: { + port: '6379', + host: process.env.REDIS_HOST } - - resetAgent(function (data) { - t.equal(nCbCalled, 1, 'myCb was called the expected number of times') - t.equal(data.transactions.length, 1, 'got 1 transaction') - t.equal(data.spans.length, 1, 'got 1 span') - t.equal(data.spans[0].name, 'GET', 'span name is GET') - t.end() - }) - - var client = redis.createClient('6379', process.env.REDIS_HOST) - client.on('ready', function () { - var t0 = agent.startTransaction('t0') - - client.get(['k', myCb]) - - t0.end() - client.quit() - agent.flush() - }) }) -} + client.connect() + const t0 = agent.startTransaction('t0') + client.set('foo').then(function (response) { + t.fail('no response expected') + endProimse(t0, client, agent) + }).catch(function (error) { + t.ok(error, 'expected error') + endProimse(t0, client, agent) + }) +}) function resetAgent (cb) { agent._instrumentation.testReset() diff --git a/test/instrumentation/modules/redis4-legacy.test.js b/test/instrumentation/modules/redis4-legacy.test.js new file mode 100644 index 00000000000..e790fe36fe7 --- /dev/null +++ b/test/instrumentation/modules/redis4-legacy.test.js @@ -0,0 +1,137 @@ +/* + * Copyright Elasticsearch B.V. and other contributors where applicable. + * Licensed under the BSD 2-Clause License; you may not use this file except in + * compliance with the BSD 2-Clause License. + */ + +'use strict' + +// this test file is about testing `legacyMode` +// https://github.com/redis/node-redis/blob/HEAD/docs/v3-to-v4.md#legacy-mode +const redisVersion = require('redis/package.json').version +const semver = require('semver') +if (semver.lt(redisVersion, '4.0.0')) { + console.log('# SKIP: skipping redis4-legacy.test.js tests') + process.exit(0) +} + +if (semver.lt(process.version, '14.0.0')) { + console.log('# SKIP: skipping redis4-legacy.test.js tests node node <14 ') + process.exit(0) +} + +const agent = require('../../..').start({ + serviceName: 'test-redis', + captureExceptions: false, + metricsInterval: 0, + centralConfig: false, + spanCompressionEnabled: false +}) + +const redis = require('redis') +const test = require('tape') + +const mockClient = require('../../_mock_http_client') + +test('redis', function (t) { + resetAgent(function (data) { + t.strictEqual(data.transactions.length, 1, 'have 1 transaction') + const trans = data.transactions[0] + t.ok(trans.name, 'aTrans', 'trans.name') + t.strictEqual(trans.result, 'success', 'trans.result') + + // Sort the remaining spans by timestamp, because asynchronous-span.end() + // means they can be set to APM server out of order. + const spans = data.spans + .sort((a, b) => { return a.timestamp < b.timestamp ? -1 : 1 }) + + const expectedSpanNames = [ + 'FLUSHALL', + 'SET', + 'SET', + 'HSET', + 'HSET', + 'HKEYS' + ] + t.equal(spans.length, expectedSpanNames.length, 'have the expected number of spans') + for (let i = 0; i < expectedSpanNames.length; i++) { + const expectedName = expectedSpanNames[i] + const span = spans[i] + t.strictEqual(span.transaction_id, trans.id, 'span.transaction_id') + t.strictEqual(span.name, expectedName, 'span.name') + t.strictEqual(span.type, 'db', 'span.type') + t.strictEqual(span.subtype, 'redis', 'span.subtype') + t.strictEqual(span.action, 'query', 'span.action') + t.deepEqual(span.context.service.target, { type: 'redis' }, 'span.context.service.target') + t.deepEqual(span.context.destination, { + address: process.env.REDIS_HOST || 'localhost', + port: 6379, + service: { name: '', type: '', resource: 'redis' } + }, 'span.context.destination') + t.deepEqual(span.context.db, { type: 'redis' }, 'span.context.db') + t.strictEqual(span.parent_id, trans.id, 'span is a child of the transaction') + + const offset = span.timestamp - trans.timestamp + t.ok(offset + span.duration * 1000 < trans.duration * 1000, + 'span ended before transaction ended') + } + t.end() + client.disconnect() + }) + + const client = redis.createClient({ + socket: { + host: process.env.REDIS_HOST, + port: '6379' + }, + legacyMode: true + }) + + client.on('error', err => console.log('client error', err)) + client.connect() + const trans = agent.startTransaction('aTrans') + + client.flushall(function (err, reply) { + t.error(err, 'no flushall error') + t.strictEqual(reply, 'OK', 'reply is OK') + let done = 0 + + client.set('string key', 'string val', function (err, reply) { + t.error(err) + t.strictEqual(reply, 'OK', 'reply is OK') + done++ + }) + + // callback is optional + client.set('string key', 'string val') + + client.hset('hash key', 'hashtest 1', 'some value', function (err, reply) { + t.error(err, 'no hset error') + t.strictEqual(reply, 1, 'hset reply is 1') + done++ + }) + client.hset(['hash key', 'hashtest 2', 'some other value'], function (err, reply) { + t.error(err, 'no hset error') + t.strictEqual(reply, 1, 'hset reply is 1') + done++ + }) + + client.hkeys('hash key', function (err, replies) { + t.error(err, 'no hkeys error') + t.strictEqual(replies.length, 2, 'got two replies') + replies.forEach(function (reply, i) { + t.strictEqual(reply, 'hashtest ' + (i + 1), `reply ${i} value`) + }) + done++ + t.strictEqual(done, 4, 'done 4 callbacks') + + trans.end() + agent.flush() + }) + }) +}) + +function resetAgent (cb) { + agent._instrumentation.testReset() + agent._transport = mockClient(cb) +} diff --git a/test/instrumentation/modules/restify/basic.test.js b/test/instrumentation/modules/restify/basic.test.js index e586247778f..426efe306cc 100644 --- a/test/instrumentation/modules/restify/basic.test.js +++ b/test/instrumentation/modules/restify/basic.test.js @@ -6,11 +6,9 @@ 'use strict' -// Restify is broken on latest node v18 nightlies. -// https://github.com/restify/node-restify/issues/1888 -const semver = require('semver') -if (semver.satisfies(process.version, '>17.x', { includePrerelease: true })) { - console.log(`# SKIP restify does not support node ${process.version}`) +const isRestifyIncompat = require('../../../_is_restify_incompat')() +if (isRestifyIncompat) { + console.log(`# SKIP ${isRestifyIncompat}`) process.exit() } diff --git a/test/instrumentation/modules/restify/set-framework.test.js b/test/instrumentation/modules/restify/set-framework.test.js index f2548dfe4ec..8403732eab6 100644 --- a/test/instrumentation/modules/restify/set-framework.test.js +++ b/test/instrumentation/modules/restify/set-framework.test.js @@ -6,11 +6,9 @@ 'use strict' -// Restify is broken on latest node v18 nightlies. -// https://github.com/restify/node-restify/issues/1888 -const semver = require('semver') -if (semver.satisfies(process.version, '>17.x', { includePrerelease: true })) { - console.log(`# SKIP restify does not support node ${process.version}`) +const isRestifyIncompat = require('../../../_is_restify_incompat')() +if (isRestifyIncompat) { + console.log(`# SKIP ${isRestifyIncompat}`) process.exit() } diff --git a/test/instrumentation/modules/tedious.test.js b/test/instrumentation/modules/tedious.test.js index 85c7b08f217..a3403937b19 100644 --- a/test/instrumentation/modules/tedious.test.js +++ b/test/instrumentation/modules/tedious.test.js @@ -11,13 +11,14 @@ const agent = require('../../../').start({ captureExceptions: false, metricsInterval: 0, centralConfig: false, + apmServerVersion: '8.0.0', spanCompressionEnabled: false }) -// tedious >=12 only supports node >=12.3.0, tedious 11 only supports node >=10.17.0 const tediousVer = require('../../../node_modules/tedious/package.json').version const semver = require('semver') -if ((semver.gte(tediousVer, '12.0.0') && semver.lt(process.version, '12.3.0')) || +if ((semver.gte(tediousVer, '15.0.0') && semver.lt(process.version, '14.0.0')) || + (semver.gte(tediousVer, '12.0.0') && semver.lt(process.version, '12.3.0')) || (semver.gte(tediousVer, '11.0.0') && semver.lt(process.version, '10.17.0'))) { console.log(`# SKIP tedious@${tediousVer} does not support node ${process.version}`) process.exit() @@ -170,15 +171,16 @@ function assertQuery (t, sql, span, name) { statement: sql, type: 'sql' }, 'span db context') + t.deepEqual(span.context.service.target, { type: 'mssql' }, 'span.context.service.target') t.deepEqual(span.context.destination, { service: { - name: 'mssql', - resource: 'mssql', - type: 'db' + type: '', + name: '', + resource: 'mssql' }, address: hostname, port: 1433 - }, 'span destination context') + }, 'span.context.destination') } function assertBasicQuery (t, sql, data) { diff --git a/test/instrumentation/modules/undici/fetch.test.js b/test/instrumentation/modules/undici/fetch.test.js new file mode 100644 index 00000000000..8377e4d4286 --- /dev/null +++ b/test/instrumentation/modules/undici/fetch.test.js @@ -0,0 +1,120 @@ +/* + * Copyright Elasticsearch B.V. and other contributors where applicable. + * Licensed under the BSD 2-Clause License; you may not use this file except in + * compliance with the BSD 2-Clause License. + */ + +'use strict' + +// Test node v18's `fetch` implementation (based on undici). +// +// Importantly, this test must not `require('undici')` because part of the +// test is whether the APM agent knows to enable undici instrumentation even +// without the import. + +if (!global.fetch) { + console.log(`# SKIP there is no global fetch() in node ${process.version}`) + process.exit() +} +/* global fetch */ // for eslint + +process.env.ELASTIC_APM_TEST = true +const { CapturingTransport } = require('../../../_capturing_transport') +const apm = require('../../../..').start({ + serviceName: 'test-fetch', + captureExceptions: false, + metricsInterval: 0, + centralConfig: false, + apmServerVersion: '8.0.0', + spanCompressionEnabled: false, + transport () { return new CapturingTransport() } +}) + +const http = require('http') +const { promisify } = require('util') +const test = require('tape') + +const promisyApmFlush = promisify(apm.flush.bind(apm)) +let server +let origin +let lastServerReq + +// ---- support functions + +function assertUndiciSpan (t, span, url, reqFailed) { + const u = new URL(url) + t.equal(span.name, `GET ${u.host}`, 'span.name') + t.equal(span.type, 'external', 'span.type') + t.equal(span.subtype, 'http', 'span.subtype') + t.equal(span.action, 'GET', 'span.action') + t.equal(span.outcome, reqFailed ? 'failure' : 'success', 'span.outcome') + t.equal(span.context.http.method, 'GET', 'span.context.http.method') + t.equal(span.context.http.url, url, 'span.context.http.url') + if (!reqFailed) { + t.equal(span.context.http.status_code, 200, 'span.context.http.status_code') + t.equal(span.context.http.response.encoded_body_size, 4, 'span.context.http.response.encoded_body_size') + } + t.deepEqual(span.context.service.target, + { type: 'http', name: u.host }, + 'span.context.service.target') + t.deepEqual(span.context.destination, { + address: u.hostname, + port: Number(u.port), + service: { type: '', name: '', resource: u.host } + }, 'span.context.destination') +} + +// ---- tests + +test('setup', t => { + server = http.createServer((req, res) => { + lastServerReq = req + req.resume() + req.on('end', () => { + setTimeout(() => { + res.end('pong') + }, 10) + }) + }) + server.listen(() => { + origin = `http://localhost:${server.address().port}` + t.end() + }) +}) + +test('fetch', async t => { + apm._transport.clear() + const aTrans = apm.startTransaction('aTransName') + + const url = origin + '/ping' + const res = await fetch(url) + t.equal(res.status, 200, 'res.status') + const text = await res.text() + t.equal(text, 'pong', 'response body') + + aTrans.end() + t.error(await promisyApmFlush(), 'no apm.flush() error') + + t.equal(apm._transport.spans.length, 1) + const span = apm._transport.spans[0] + assertUndiciSpan(t, span, url) + + // Test trace-context propagation. + t.equal(lastServerReq.headers.traceparent, + `00-${span.trace_id}-${span.id}-01`, + 'serverReq.headers.traceparent') + t.equal(lastServerReq.headers.tracestate, 'es=s:1', 'serverReq.headers.tracestate') + + t.end() +}) + +test('teardown', t => { + server.close() + + // Note that this test file will now hang for ~4s until Node's bundled + // undici (used to implement `fetch()`) Keep-Alive timeout ends. I don't + // know of a way to avoid that. + t.comment('expected 4s hang for fetch() internal Keep-Alive timeout') + + t.end() +}) diff --git a/test/instrumentation/modules/undici/undici.test.js b/test/instrumentation/modules/undici/undici.test.js new file mode 100644 index 00000000000..a65902fcfdc --- /dev/null +++ b/test/instrumentation/modules/undici/undici.test.js @@ -0,0 +1,225 @@ +/* + * Copyright Elasticsearch B.V. and other contributors where applicable. + * Licensed under the BSD 2-Clause License; you may not use this file except in + * compliance with the BSD 2-Clause License. + */ + +'use strict' + +process.env.ELASTIC_APM_TEST = true +const { CapturingTransport } = require('../../../_capturing_transport') +const apm = require('../../../..').start({ + serviceName: 'test-undici', + captureExceptions: false, + metricsInterval: 0, + centralConfig: false, + apmServerVersion: '8.0.0', + spanCompressionEnabled: false, + transport () { return new CapturingTransport() } +}) + +// Skip (exit the process) if this undici instrumentation isn't supported. +try { + require('diagnostics_channel') +} catch (_noModErr) { + console.log('# SKIP undici instrumention is not supported (no "diagnostics_channel" module)') + process.exit() +} +const semver = require('semver') +if (semver.lt(process.version, '12.18.0')) { + console.log('# SKIP undici instrumention does not support node %s', process.version) + process.exit() +} + +const http = require('http') +const { Writable } = require('stream') +const { promisify } = require('util') +const test = require('tape') +const undici = require('undici') + +const promisyApmFlush = promisify(apm.flush.bind(apm)) +let server +let origin +let lastServerReq + +// ---- support functions + +// Undici docs (https://github.com/nodejs/undici#garbage-collection) suggest +// that an undici response body should always be consumed. +async function consumeResponseBody (body) { + return new Promise(resolve => { + const devNull = new Writable({ + write (_chunk, _encoding, cb) { + setImmediate(cb) + } + }) + body.pipe(devNull) + body.on('end', resolve) + }) +} + +function assertUndiciSpan (t, span, url, reqFailed) { + const u = new URL(url) + t.equal(span.name, `GET ${u.host}`, 'span.name') + t.equal(span.type, 'external', 'span.type') + t.equal(span.subtype, 'http', 'span.subtype') + t.equal(span.action, 'GET', 'span.action') + t.equal(span.outcome, reqFailed ? 'failure' : 'success', 'span.outcome') + t.equal(span.context.http.method, 'GET', 'span.context.http.method') + t.equal(span.context.http.url, url, 'span.context.http.url') + if (!reqFailed) { + t.equal(span.context.http.status_code, 200, 'span.context.http.status_code') + t.equal(span.context.http.response.encoded_body_size, 4, 'span.context.http.response.encoded_body_size') + } + t.deepEqual(span.context.service.target, + { type: 'http', name: u.host }, + 'span.context.service.target') + t.deepEqual(span.context.destination, { + address: u.hostname, + port: Number(u.port), + service: { type: '', name: '', resource: u.host } + }, 'span.context.destination') +} + +// ---- tests + +test('setup', t => { + server = http.createServer((req, res) => { + lastServerReq = req + req.resume() + req.on('end', () => { + setTimeout(() => { + res.end('pong') + }, 10) + }) + }) + server.listen(() => { + origin = `http://localhost:${server.address().port}` + t.end() + }) +}) + +test('undici.request', async t => { + apm._transport.clear() + const aTrans = apm.startTransaction('aTransName') + + const url = origin + '/ping' + const { statusCode, body } = await undici.request(url) + t.equal(statusCode, 200, 'statusCode') + await consumeResponseBody(body) + + aTrans.end() + t.error(await promisyApmFlush(), 'no apm.flush() error') + + t.equal(apm._transport.spans.length, 1) + const span = apm._transport.spans[0] + assertUndiciSpan(t, span, url) + + // Test trace-context propagation. + t.equal(lastServerReq.headers.traceparent, + `00-${span.trace_id}-${span.id}-01`, + 'serverReq.headers.traceparent') + t.equal(lastServerReq.headers.tracestate, 'es=s:1', 'serverReq.headers.tracestate') + + t.end() +}) + +test('undici.stream', async t => { + apm._transport.clear() + const aTrans = apm.startTransaction('aTransName') + + // https://undici.nodejs.org/#/docs/api/Dispatcher?id=example-1-basic-get-stream-request + const url = origin + '/ping' + const chunks = [] + await undici.stream( + url, + { opaque: { chunks } }, + ({ statusCode, opaque: { chunks } }) => { + t.equal(statusCode, 200, 'statusCode') + return new Writable({ + write (chunk, _encoding, cb) { + chunks.push(chunk) + cb() + } + }) + } + ) + t.equal(chunks.join(''), 'pong', 'response body') + + aTrans.end() + t.error(await promisyApmFlush(), 'no apm.flush() error') + + t.equal(apm._transport.spans.length, 1) + const span = apm._transport.spans[0] + assertUndiciSpan(t, span, url) + + t.end() +}) + +if (undici.fetch) { + test('undici.fetch', async t => { + apm._transport.clear() + const aTrans = apm.startTransaction('aTransName') + + const url = origin + '/ping' + const res = await undici.fetch(url) + t.equal(res.status, 200, 'res.status') + const text = await res.text() + t.equal(text, 'pong', 'response body') + + aTrans.end() + t.error(await promisyApmFlush(), 'no apm.flush() error') + + t.equal(apm._transport.spans.length, 1) + const span = apm._transport.spans[0] + assertUndiciSpan(t, span, url) + + t.end() + }) +} + +if (global.AbortController) { + test('undici.request AbortSignal', async t => { + apm._transport.clear() + const aTrans = apm.startTransaction('aTransName', 'manual') + + const url = origin + '/ping' + const ac = new AbortController() // eslint-disable-line no-undef + setTimeout(() => { + ac.abort() + }, 5) // Abort before the ~10ms expected response time of the request. + try { + await undici.request(url, { signal: ac.signal }) + t.fail('should not get here') + } catch (reqErr) { + t.ok(reqErr, 'got a request error') + + aTrans.end() + t.error(await promisyApmFlush(), 'no apm.flush() error') + + t.equal(apm._transport.spans.length, 1) + const span = apm._transport.spans[0] + assertUndiciSpan(t, span, url, true) + + t.equal(apm._transport.errors.length, 1) + const error = apm._transport.errors[0] + t.equal(error.parent_id, span.id, 'error.parent_id') + t.equal(error.trace_id, span.trace_id, 'error.trace_id') + t.equal(error.transaction_id, aTrans.id, 'error.transaction_id') + t.deepEqual(error.transaction, { name: 'aTransName', type: 'manual', sampled: true }, 'error.transaction') + t.equal(error.exception.message, 'Request aborted', 'error.exception.message') + t.equal(error.exception.type, 'AbortError', 'error.exception.type') + t.equal(error.exception.code, 'UND_ERR_ABORTED', 'error.exception.code') + t.equal(error.exception.module, 'undici', 'error.exception.module') + t.equal(error.exception.handled, true, 'error.exception.handled') + + t.end() + } + }) +} + +test('teardown', t => { + undici.getGlobalDispatcher().close() // Close kept-alive sockets. + server.close() + t.end() +}) diff --git a/test/instrumentation/span-compression.test.js b/test/instrumentation/span-compression.test.js index 1e025c7e098..f1434461e55 100644 --- a/test/instrumentation/span-compression.test.js +++ b/test/instrumentation/span-compression.test.js @@ -23,12 +23,7 @@ const constantsGlobal = require('../../lib/constants') const mockClient = require('../_mock_http_client') const tape = require('tape') - -const destinationContext = { - service: { - resource: 'foo' - } -} +const { NoopTransport } = require('../../lib/noop-transport') // `setTimeout` precision is ~1ms. It can fire its callback up to a millisecond // early. Comparisons on the minimum time for an action using setTimeout should @@ -54,7 +49,6 @@ tape.test('integration/end-to-end span compression tests', function (suite) { let firstSpan, finalSpan setTimeout(function () { firstSpan = agent.startSpan('name1', 'db', 'mysql', { exitSpan: true }) - firstSpan.setDestinationContext(destinationContext) setTimeout(function () { firstSpan.end() }, 10) @@ -62,7 +56,6 @@ tape.test('integration/end-to-end span compression tests', function (suite) { setTimeout(function () { const span = agent.startSpan('name1', 'db', 'mysql', { exitSpan: true }) - span.setDestinationContext(destinationContext) setTimeout(function () { span.end() }, 10) @@ -70,7 +63,6 @@ tape.test('integration/end-to-end span compression tests', function (suite) { setTimeout(function () { finalSpan = agent.startSpan('name1', 'db', 'mysql', { exitSpan: true }) - finalSpan.setDestinationContext(destinationContext) setTimeout(function () { finalSpan.end() agent.endTransaction() @@ -83,7 +75,7 @@ tape.test('integration/end-to-end span compression tests', function (suite) { resetAgent(function (data) { t.equals(data.length, 2) const span = data.spans.shift() - t.equals(span.name, 'Calls to foo') + t.equals(span.name, 'Calls to mysql') t.equals(span.composite.compression_strategy, constants.STRATEGY_SAME_KIND) t.equals(span.composite.count, 3) t.true(span.composite.sum > 30 - (3 * SET_TIMEOUT_EPSILON_MS), @@ -97,7 +89,6 @@ tape.test('integration/end-to-end span compression tests', function (suite) { let firstSpan, finalSpan setTimeout(function () { firstSpan = agent.startSpan('name1', 'db', 'mysql', { exitSpan: true }) - firstSpan.setDestinationContext(destinationContext) setTimeout(function () { firstSpan.end() }, 10) @@ -105,7 +96,6 @@ tape.test('integration/end-to-end span compression tests', function (suite) { setTimeout(function () { const span = agent.startSpan('name2', 'db', 'mysql', { exitSpan: true }) - span.setDestinationContext(destinationContext) setTimeout(function () { span.end() }, 10) @@ -113,7 +103,6 @@ tape.test('integration/end-to-end span compression tests', function (suite) { setTimeout(function () { finalSpan = agent.startSpan('name3', 'db', 'mysql', { exitSpan: true }) - finalSpan.setDestinationContext(destinationContext) setTimeout(function () { finalSpan.end() agent.endTransaction() @@ -129,18 +118,16 @@ tape.test('integration/end-to-end span compression tests', function (suite) { t.equals(data.transactions.length, 1) const span = data.spans[0] - t.equals(span.name, 'Calls to mysql') + t.equals(span.name, 'Calls to mysql', 'same_kind composite span.name') t.end() }) var t0 = agent.startTransaction('t0') setImmediate(() => { var s1 = t0.startSpan('s1', 'db', 'mysql', { exitSpan: true }) - s1.setDestinationContext({ service: { name: 'mysql', resource: 'mysql', type: 'db' } }) setTimeout(() => { s1.end() var s2 = t0.startSpan('s2', 'db', 'mysql', { exitSpan: true }) - s2.setDestinationContext({ service: { name: 'mysql', resource: 'mysql', type: 'db' } }) setTimeout(() => { s2.end() t0.end() @@ -157,7 +144,6 @@ tape.test('integration/end-to-end span compression tests', function (suite) { const t0 = agent.startTransaction('t0') const s1 = agent.startSpan('SELECT FROM a', 'db', 'mysql', { exitSpan: true }) - s1.setDestinationContext({ service: { name: 'mysql', resource: 'mysql', type: 'db' } }) setTimeout(() => { s1.end() @@ -165,7 +151,6 @@ tape.test('integration/end-to-end span compression tests', function (suite) { setTimeout(() => { const s2 = agent.startSpan('SELECT FROM b', 'db', 'mysql', { exitSpan: true }) - s2.setDestinationContext({ service: { name: 'mysql', resource: 'mysql', type: 'db' } }) s2.end() }, 200) @@ -173,10 +158,68 @@ tape.test('integration/end-to-end span compression tests', function (suite) { t0.end() }, 300) }) + + // The scenario is as follows: + // trans t0 + // span s1: _bufferdSpan=s2 + // span s2: ended, compressible -> buffered on s1 + // span s3: incompressible, _bufferdSpan=s4 + // span s4: ended, compressible -> buffered on s3 + // + // What happens when s3 ends? We expect: + // - s4 is encoded and sent + // - s2 is encoded and sent + // - s3 is encoded and sent + // + // This tests the following from https://github.com/elastic/apm/blob/main/specs/agents/handling-huge-traces/tracing-spans-compress.md#span-buffering + // > A buffered span gets reported when + // > 1. its parent ends + // > 2. a non-compressible sibling ends + suite.test('ensure a span buffered on parent is sent when incompressible span ends', function (t) { + resetAgent(function (data) { + // We expect sent spans for: s4, s2, and s3; in that order. + t.equals(data.length, 3, '3 events sent') + t.equals(data.spans.length, 3, '3 spans sent') + t.equals(data.spans.map(s => s.name).join(','), 's4,s2,s3', + 'sent spans are s4,s2,s3; in that order') + t.end() + }) + + const t0 = agent.startTransaction('t0') + setImmediate(() => { + const s1 = agent.startSpan('s1', 'manual') + + setImmediate(() => { + const s2 = agent.startSpan('s2', 'db', 'mysql', { exitSpan: true }) + t.equal(s2.getParentSpan().name, 's1', 's2 is a child of s1') + s2.end() + t.equal(s1.getBufferedSpan().name, 's2', 's2 is buffered on s1') + + const s3 = t0.startSpan('s3', 'manual') // incompressible (because exitSpan=false) + t.equal(s3.getParentSpan().name, 's1', 's3 is a child of s1') + + setImmediate(() => { + const s4 = agent.startSpan('s4', 'db', 'mysql', { exitSpan: true }) + t.equal(s4.getParentSpan().name, 's3', 's4 is a child of s3') + s4.end() + t.equal(s3.getBufferedSpan().name, 's4', 's4 is buffered on s3') + + s3.end() + }) + }) + }) + }) + suite.end() }) tape.test('unit tests', function (suite) { + // Clean up after the latest `resetAgent()` call above. Otherwise, if + // there is another write to the hacked `agent._transport`, then in 200ms + // the last registered callback will be invoked, resulting in a double + // `t.end()`. + agent._transport = new NoopTransport() + suite.test('test _getCompressionStrategy invalid', function (t) { const c = new SpanCompression(agent) t.equals(false, c._getCompressionStrategy({}, {})) @@ -186,24 +229,22 @@ tape.test('unit tests', function (suite) { suite.test('test _getCompressionStrategy exact match', function (t) { const c = new SpanCompression(agent) const trans = new Transaction(agent) - const span1 = new Span(trans, 'name', 'type', 'subtype') - const span2 = new Span(trans, 'name', 'type', 'subtype') + const span1 = new Span(trans, 'name', 'type', 'subtype', { exitSpan: true }) + span1.end() + const span2 = new Span(trans, 'name', 'type', 'subtype', { exitSpan: true }) + span2.end() - span1.setDestinationContext(destinationContext) - span2.setDestinationContext(destinationContext) - - t.equals(constants.STRATEGY_EXACT_MATCH, c._getCompressionStrategy(span1, span2)) + t.equals(c._getCompressionStrategy(span1, span2), constants.STRATEGY_EXACT_MATCH) t.end() }) suite.test('test _getCompressionStrategy same kind', function (t) { const c = new SpanCompression(agent) const trans = new Transaction(agent) - const span1 = new Span(trans, 'name1', 'type', 'subtype') - const span2 = new Span(trans, 'name2', 'type', 'subtype') - - span1.setDestinationContext(destinationContext) - span2.setDestinationContext(destinationContext) + const span1 = new Span(trans, 'name1', 'type', 'subtype', { exitSpan: true }) + span1.end() + const span2 = new Span(trans, 'name2', 'type', 'subtype', { exitSpan: true }) + span2.end() t.equals(constants.STRATEGY_SAME_KIND, c._getCompressionStrategy(span1, span2)) t.end() @@ -212,11 +253,10 @@ tape.test('unit tests', function (suite) { suite.test('test _getCompressionStrategy no strategy', function (t) { const c = new SpanCompression(agent) const trans = new Transaction(agent) - const span1 = new Span(trans, 'name1', 'type2', 'subtype') - const span2 = new Span(trans, 'name2', 'type', 'subtype') - - span1.setDestinationContext(destinationContext) - span2.setDestinationContext(destinationContext) + const span1 = new Span(trans, 'name1', 'type2', 'subtype', { exitSpan: true }) + span1.end() + const span2 = new Span(trans, 'name2', 'type', 'subtype', { exitSpan: true }) + span2.end() t.equals(false, c._getCompressionStrategy(span1, span2)) t.end() @@ -245,22 +285,22 @@ tape.test('unit tests', function (suite) { suite.test('test tryToCompress exact match', function (t) { const c = new SpanCompression(agent) const trans = new Transaction(agent) - const span1 = new Span(trans, 'name', 'type', 'mysql') - span1.setDestinationContext(destinationContext) + const span1 = new Span(trans, 'name', 'type', 'mysql', { exitSpan: true }) + span1.end() span1._duration = 2 // time in milliseconds/ms - const span2 = new Span(trans, 'name', 'type', 'mysql') - span2.setDestinationContext(destinationContext) + const span2 = new Span(trans, 'name', 'type', 'mysql', { exitSpan: true }) + span2.end() span2._endTimestamp = span1.timestamp + 5000 // time in microseconds/us span2._duration = 3 // time in milliseconds/ms - const span3 = new Span(trans, 'name', 'type', 'mysql') - span3.setDestinationContext(destinationContext) + const span3 = new Span(trans, 'name', 'type', 'mysql', { exitSpan: true }) + span3.end() span3._endTimestamp = span2._endTimestamp + 4000 // time in microseconds/us span3._duration = 4 // time in milliseconds/ms - const spanSameKind = new Span(trans, 'name 2', 'type', 'mysql') - spanSameKind.setDestinationContext(destinationContext) + const spanSameKind = new Span(trans, 'name 2', 'type', 'mysql', { exitSpan: true }) + spanSameKind.end() spanSameKind._endTimestamp = span3._endTimestamp + 3000 // time in microseconds/us spanSameKind._duration = 2 // time in milliseconds/ms @@ -287,24 +327,24 @@ tape.test('unit tests', function (suite) { suite.test('test tryToCompress same kind', function (t) { const c = new SpanCompression(agent) const trans = new Transaction(agent) - const span1 = new Span(trans, 'name 1', 'type', 'mysql') - span1.setDestinationContext(destinationContext) + const span1 = new Span(trans, 'name 1', 'type', 'mysql', { exitSpan: true }) + span1.end() span1._duration = 2 // time in milliseconds/ms - const span2 = new Span(trans, 'name 2', 'type', 'mysql') - span2.setDestinationContext(destinationContext) + const span2 = new Span(trans, 'name 2', 'type', 'mysql', { exitSpan: true }) + span2.end() span2._endTimestamp = span1.timestamp + 5000 // time in microseconds/us span2._duration = 3 // time in milliseconds/ms // span three is set to be an "exact match" of span 2 in order // to ensure the strategy stays same kind - const span3 = new Span(trans, 'name 2', 'type', 'mysql') - span3.setDestinationContext(destinationContext) + const span3 = new Span(trans, 'name 2', 'type', 'mysql', { exitSpan: true }) + span3.end() span3._endTimestamp = span2._endTimestamp + 4000 // time in microseconds/us span3._duration = 4 // time in milliseconds/ms - const spanNotSameKind = new Span(trans, 'name 4', 'type', 'other') - spanNotSameKind.setDestinationContext(destinationContext) + const spanNotSameKind = new Span(trans, 'name 4', 'type', 'other', { exitSpan: true }) + spanNotSameKind.end() spanNotSameKind._endTimestamp = span3._endTimestamp + 3000 // time in microseconds/us spanNotSameKind._duration = 2 // time in milliseconds/ms @@ -331,19 +371,19 @@ tape.test('unit tests', function (suite) { suite.test('test tryToCompress same kind, then exact match', function (t) { const c = new SpanCompression(agent) const trans = new Transaction(agent) - const span1 = new Span(trans, 'name 1', 'type', 'mysql') - span1.setDestinationContext(destinationContext) + const span1 = new Span(trans, 'name 1', 'type', 'mysql', { exitSpan: true }) + span1.end() span1._duration = 2 // time in milliseconds/ms - const span2 = new Span(trans, 'name 2', 'type', 'mysql') - span2.setDestinationContext(destinationContext) + const span2 = new Span(trans, 'name 2', 'type', 'mysql', { exitSpan: true }) + span2.end() span2._endTimestamp = span1.timestamp + 5000 // time in microseconds/us span2._duration = 3 // time in milliseconds/ms // span three is set to be an "exact match" of span 1 in order // to ensure the strategy stays same kind - const span3 = new Span(trans, 'name 1', 'type', 'mysql') - span3.setDestinationContext(destinationContext) + const span3 = new Span(trans, 'name 1', 'type', 'mysql', { exitSpan: true }) + span3.end() span3._endTimestamp = span2._endTimestamp + 4000 // time in microseconds/us span3._duration = 4 // time in milliseconds/ms @@ -369,16 +409,16 @@ tape.test('unit tests', function (suite) { const c = new SpanCompression(agent) const trans = new Transaction(agent) - const span = new Span(trans, 'name', 'type', 'mysql') - span.setDestinationContext(destinationContext) + const span = new Span(trans, 'name', 'type', 'mysql', { exitSpan: true }) + span.end() span._duration = 20 // time in milliseconds/ms - const spanOver = new Span(trans, 'name', 'type', 'mysql') - spanOver.setDestinationContext(destinationContext) + const spanOver = new Span(trans, 'name', 'type', 'mysql', { exitSpan: true }) + spanOver.end() spanOver._duration = 61 // time in milliseconds/ms - const spanUnder = new Span(trans, 'name', 'type', 'mysql') - spanUnder.setDestinationContext(destinationContext) + const spanUnder = new Span(trans, 'name', 'type', 'mysql', { exitSpan: true }) + spanUnder.end() spanUnder._duration = 60 // time in milliseconds/ms t.ok(!c.tryToCompress(span, spanOver), '61ms is > spanCompressionExactMatchMaxDuration') @@ -394,16 +434,16 @@ tape.test('unit tests', function (suite) { const c = new SpanCompression(agent) const trans = new Transaction(agent) - const span = new Span(trans, 'name', 'type', 'mysql') - span.setDestinationContext(destinationContext) + const span = new Span(trans, 'name', 'type', 'mysql', { exitSpan: true }) + span.end() span._duration = 20 // time in milliseconds/ms - const spanOver = new Span(trans, 'name 2', 'type', 'mysql') - spanOver.setDestinationContext(destinationContext) + const spanOver = new Span(trans, 'name 2', 'type', 'mysql', { exitSpan: true }) + spanOver.end() spanOver._duration = 51 // time in milliseconds/ms - const spanUnder = new Span(trans, 'name 2', 'type', 'mysql') - spanUnder.setDestinationContext(destinationContext) + const spanUnder = new Span(trans, 'name 2', 'type', 'mysql', { exitSpan: true }) + spanUnder.end() spanUnder._duration = 50 // time in milliseconds/ms t.ok(!c.tryToCompress(span, spanOver), '51ms is > spanCompressionSameKindMaxDuration') @@ -441,8 +481,8 @@ tape.test('unit tests', function (suite) { suite.test('isCompressionEligible _hasPropagated', function (t) { const trans = new Transaction(agent) - // test outcome logic const span = new Span(trans, 'foo', 'baz', 'bar', { exitSpan: true }) + span.end() span._hasPropagatedTraceContext = false t.true(span.isCompressionEligible()) diff --git a/test/instrumentation/span.test.js b/test/instrumentation/span.test.js index 95924bcc5a6..488579fab55 100644 --- a/test/instrumentation/span.test.js +++ b/test/instrumentation/span.test.js @@ -324,9 +324,9 @@ test('#_encode() - with meta data', function myTest2 (t) { var trans = new Transaction(agent) var span = new Span(trans, 'foo', 'bar') var timerStart = span._timer.start - span.end() span.setDbContext({ statement: 'foo', type: 'bar' }) span.setLabel('baz', 1) + span.end() span._encode(function (err, payload) { t.error(err) t.deepEqual(Object.keys(payload), ['id', 'transaction_id', 'parent_id', 'trace_id', 'name', 'type', 'subtype', 'action', 'timestamp', 'duration', 'context', 'stacktrace', 'sync', 'outcome', 'sample_rate']) @@ -341,7 +341,10 @@ test('#_encode() - with meta data', function myTest2 (t) { t.strictEqual(payload.type, 'bar') t.strictEqual(payload.timestamp, timerStart) t.ok(payload.duration > 0) - t.deepEqual(payload.context, { db: { statement: 'foo', type: 'bar' }, http: undefined, tags: { baz: '1' }, destination: undefined, message: undefined }) + t.deepEqual(payload.context, { + db: { statement: 'foo', type: 'bar' }, + tags: { baz: '1' } + }) assert.stacktrace(t, 'myTest2', __filename, payload.stacktrace, agent) t.end() }) diff --git a/test/instrumentation/transaction.test.js b/test/instrumentation/transaction.test.js index d7233d29110..52818dc81d4 100644 --- a/test/instrumentation/transaction.test.js +++ b/test/instrumentation/transaction.test.js @@ -506,11 +506,6 @@ test('#_encode() - dropped spans', function (t) { var span0 = trans.startSpan('s0', 'type0') trans.startSpan('s1', 'type1') var span2 = trans.startSpan('s2', { exitSpan: true }) - span2.setDestinationContext({ - service: { - resource: 'foo' - } - }) if (span2.isRecorded()) { t.fail('should have dropped the span') } diff --git a/test/integration/api-schema/_utils.js b/test/integration/api-schema/_utils.js index 4d6f883e457..d5a1cb8fb70 100644 --- a/test/integration/api-schema/_utils.js +++ b/test/integration/api-schema/_utils.js @@ -9,10 +9,10 @@ const fs = require('fs') const { join } = require('path') -const Ajv = require('ajv') +const Ajv = require('ajv').default const thunky = require('thunky') -const ajv = new Ajv({ allErrors: true }) +const ajv = new Ajv({ allErrors: true, allowUnionTypes: true, strict: true }) const schemaDir = join(__dirname, 'apm-server-schema') exports.metadataValidator = thunky(function (cb) { diff --git a/test/integration/api-schema/apm-server-schema/error.json b/test/integration/api-schema/apm-server-schema/error.json index 23822f3ab7c..1a421afc1d6 100644 --- a/test/integration/api-schema/apm-server-schema/error.json +++ b/test/integration/api-schema/apm-server-schema/error.json @@ -355,14 +355,14 @@ "description": "DecodedBodySize holds the size of the decoded payload.", "type": [ "null", - "number" + "integer" ] }, "encoded_body_size": { "description": "EncodedBodySize holds the size of the encoded payload.", "type": [ "null", - "number" + "integer" ] }, "finished": { @@ -410,7 +410,7 @@ "description": "TransferSize holds the total size of the payload.", "type": [ "null", - "number" + "integer" ] } } diff --git a/test/integration/api-schema/apm-server-schema/log.json b/test/integration/api-schema/apm-server-schema/log.json new file mode 100644 index 00000000000..dd0cd4eb478 --- /dev/null +++ b/test/integration/api-schema/apm-server-schema/log.json @@ -0,0 +1,87 @@ +{ + "$id": "docs/spec/v2/log", + "type": "object", + "properties": { + "@timestamp": { + "description": "Timestamp holds the recorded time of the event, UTC based and formatted as microseconds since Unix epoch", + "type": [ + "null", + "integer" + ] + }, + "faas": { + "description": "FAAS holds fields related to Function as a Service events.", + "type": [ + "null", + "object" + ], + "properties": { + "coldstart": { + "description": "Indicates whether a function invocation was a cold start or not.", + "type": [ + "null", + "boolean" + ] + }, + "execution": { + "description": "The request id of the function invocation.", + "type": [ + "null", + "string" + ] + }, + "id": { + "description": "A unique identifier of the invoked serverless function.", + "type": [ + "null", + "string" + ] + }, + "name": { + "description": "The lambda function name.", + "type": [ + "null", + "string" + ] + }, + "trigger": { + "description": "Trigger attributes.", + "type": [ + "null", + "object" + ], + "properties": { + "request_id": { + "description": "The id of the origin trigger request.", + "type": [ + "null", + "string" + ] + }, + "type": { + "description": "The trigger type.", + "type": [ + "null", + "string" + ] + } + } + }, + "version": { + "description": "The lambda function version.", + "type": [ + "null", + "string" + ] + } + } + }, + "message": { + "description": "Message logged as part of the log. In case a parameterized message is captured, Message should contain the same information, but with any placeholders being replaced.", + "type": [ + "null", + "string" + ] + } + } +} \ No newline at end of file diff --git a/test/integration/api-schema/apm-server-schema/metadata.json b/test/integration/api-schema/apm-server-schema/metadata.json index 2b5d9d22271..7103bbeb5a4 100644 --- a/test/integration/api-schema/apm-server-schema/metadata.json +++ b/test/integration/api-schema/apm-server-schema/metadata.json @@ -234,6 +234,14 @@ "description": "Agent holds information about the APM agent capturing the event.", "type": "object", "properties": { + "activation_method": { + "description": "ActivationMethod of the APM agent capturing information.", + "type": [ + "null", + "string" + ], + "maxLength": 1024 + }, "ephemeral_id": { "description": "EphemeralID is a free format ID used for metrics correlation by agents", "type": [ diff --git a/test/integration/api-schema/apm-server-schema/span.json b/test/integration/api-schema/apm-server-schema/span.json index 9bbf4bc64a2..e86da9a69cd 100644 --- a/test/integration/api-schema/apm-server-schema/span.json +++ b/test/integration/api-schema/apm-server-schema/span.json @@ -45,9 +45,9 @@ } }, "required": [ + "compression_strategy", "count", - "sum", - "compression_strategy" + "sum" ] }, "context": { @@ -181,6 +181,22 @@ ], "maxLength": 1024 }, + "request": { + "description": "Request describes the HTTP request information.", + "type": [ + "null", + "object" + ], + "properties": { + "id": { + "description": "ID holds the unique identifier for the http request.", + "type": [ + "null", + "string" + ] + } + } + }, "response": { "description": "Response describes the HTTP response information in case the event was created as a result of an HTTP request.", "type": [ @@ -192,14 +208,14 @@ "description": "DecodedBodySize holds the size of the decoded payload.", "type": [ "null", - "number" + "integer" ] }, "encoded_body_size": { "description": "EncodedBodySize holds the size of the encoded payload.", "type": [ "null", - "number" + "integer" ] }, "headers": { @@ -233,7 +249,7 @@ "description": "TransferSize holds the total size of the payload.", "type": [ "null", - "number" + "integer" ] } } @@ -855,12 +871,12 @@ } }, "required": [ - "duration", "id", + "trace_id", "name", "parent_id", - "trace_id", - "type" + "type", + "duration" ], "anyOf": [ { diff --git a/test/integration/api-schema/apm-server-schema/transaction.json b/test/integration/api-schema/apm-server-schema/transaction.json index c0d5d5c7032..cdc6262f352 100644 --- a/test/integration/api-schema/apm-server-schema/transaction.json +++ b/test/integration/api-schema/apm-server-schema/transaction.json @@ -354,14 +354,14 @@ "description": "DecodedBodySize holds the size of the decoded payload.", "type": [ "null", - "number" + "integer" ] }, "encoded_body_size": { "description": "EncodedBodySize holds the size of the encoded payload.", "type": [ "null", - "number" + "integer" ] }, "finished": { @@ -409,7 +409,7 @@ "description": "TransferSize holds the total size of the payload.", "type": [ "null", - "number" + "integer" ] } } @@ -1122,10 +1122,10 @@ } }, "required": [ - "duration", + "trace_id", "id", + "type", "span_count", - "trace_id", - "type" + "duration" ] } \ No newline at end of file diff --git a/test/integration/api-schema/basic.test.js b/test/integration/api-schema/basic.test.js index 82d857bf6d3..09a83dae675 100644 --- a/test/integration/api-schema/basic.test.js +++ b/test/integration/api-schema/basic.test.js @@ -75,17 +75,17 @@ const next = afterAll(function (err, validators) { t.strictEqual(validateError({ id: 'foo', exception: {} }), false) validateFieldMessages(t, validateError.errors, [ { - dataPath: '.exception', + dataPath: '/exception', params: { missingProperty: 'message' }, message: 'should have required property \'message\'' }, { - dataPath: '.exception', + dataPath: '/exception', params: { missingProperty: 'type' }, message: 'should have required property \'type\'' }, { - dataPath: '.exception', + dataPath: '/exception', params: {}, message: 'should match some schema in anyOf' } @@ -94,7 +94,7 @@ const next = afterAll(function (err, validators) { t.strictEqual(validateError({ id: 'foo', log: {} }), false) validateFieldMessages(t, validateError.errors, [ { - dataPath: '.log', + dataPath: '/log', params: { missingProperty: 'message' }, message: 'should have required property \'message\'' } diff --git a/test/lambda/fixtures/aws_api_http_test_data.json b/test/lambda/fixtures/aws_api_http_test_data.json index c91b5ea14a5..4de825f5409 100644 --- a/test/lambda/fixtures/aws_api_http_test_data.json +++ b/test/lambda/fixtures/aws_api_http_test_data.json @@ -2,10 +2,11 @@ "version": "2.0", "routeKey": "ANY /the-function-name", "rawPath": "/default/the-function-name", - "rawQueryString": "", + "rawQueryString": "q=foo", "headers": { "accept": "*/*", - "content-length": "0", + "content-length": "13", + "content-type": "application/json", "host": "21mj4tsk90.execute-api.us-west-2.amazonaws.com", "user-agent": "curl/7.64.1", "x-amzn-trace-id": "Root=1-611598fd-16b2bd060ca70cab7eb87c47", @@ -13,13 +14,14 @@ "x-forwarded-port": "443", "x-forwarded-proto": "https" }, + "queryStringParameters": { "q": "huh" }, "requestContext": { "accountId": "000000000000", "apiId": "21mj4tsk90", "domainName": "21mj4tsk90.execute-api.us-west-2.amazonaws.com", "domainPrefix": "21mj4tsk90", "http": { - "method": "GET", + "method": "POST", "path": "/default/the-function-name", "protocol": "HTTP/1.1", "sourceIp": "67.171.184.49", @@ -31,5 +33,6 @@ "time": "12/Aug/2021:21:56:13 +0000", "timeEpoch": 1628805373222 }, + "body": "{\"foo\":\"bar\"}", "isBase64Encoded": false } diff --git a/test/lambda/fixtures/aws_api_rest_test_data.json b/test/lambda/fixtures/aws_api_rest_test_data.json index c37b39f9480..3dec89d986c 100644 --- a/test/lambda/fixtures/aws_api_rest_test_data.json +++ b/test/lambda/fixtures/aws_api_rest_test_data.json @@ -78,8 +78,8 @@ "https" ] }, - "queryStringParameters": null, - "multiValueQueryStringParameters": null, + "queryStringParameters": { "q": "myquery" }, + "multiValueQueryStringParameters": { "q": [ "myquery" ] }, "pathParameters": null, "stageVariables": null, "requestContext": { diff --git a/test/lambda/mock/transaction.js b/test/lambda/mock/transaction.js index 115d180e250..3062526b67f 100644 --- a/test/lambda/mock/transaction.js +++ b/test/lambda/mock/transaction.js @@ -24,6 +24,10 @@ module.exports = class TransactionMock { this.opts = opts } + setDefaultName (name) { + this.name = name + } + setCustomContext (custom) { if (!custom) { return diff --git a/test/lambda/trans-setDefaultName.test.js b/test/lambda/trans-setDefaultName.test.js new file mode 100644 index 00000000000..0d8ae130a8d --- /dev/null +++ b/test/lambda/trans-setDefaultName.test.js @@ -0,0 +1,116 @@ +/* + * Copyright Elasticsearch B.V. and other contributors where applicable. + * Licensed under the BSD 2-Clause License; you may not use this file except in + * compliance with the BSD 2-Clause License. + */ + +'use strict' + +// Test that instrumentation using `Transaction.setDefaultName(...)` still +// works after the Lambda instrumentation has set the transaction name. + +const lambdaLocal = require('lambda-local') +const tape = require('tape') + +const apm = require('../../') +const { MockAPMServer } = require('../_mock_apm_server') + +// Setup env for both apm.start() and lambdaLocal.execute(). +process.env.AWS_LAMBDA_FUNCTION_NAME = 'fixture-function-name' +// Set these values to have stable data from lambdaLocal.execute(). +process.env.AWS_EXECUTION_ENV = 'AWS_Lambda_nodejs14.x' +process.env.AWS_REGION = 'us-east-1' +process.env.AWS_ACCOUNT_ID = '123456789012' +// A lambda-local limitation is that it doesn't set AWS_LAMBDA_LOG_GROUP_NAME +// and AWS_LAMBDA_LOG_STREAM_NAME (per +// https://docs.aws.amazon.com/lambda/latest/dg/configuration-envvars.html). +process.env.AWS_LAMBDA_LOG_GROUP_NAME = `/aws/lambda/${process.env.AWS_LAMBDA_FUNCTION_NAME}` +process.env.AWS_LAMBDA_LOG_STREAM_NAME = '2021/11/01/[1.0]lambda/e7b05091b39b4aa2aef19efe4d262e79' +// Avoid the lambda-local loading AWS credentials and session info from +// a configured real AWS profile and possibly emitting this warning: +// warning Using both auth systems: aws_access_key/id and secret_access_token! +process.env.AWS_PROFILE = 'fake' + +function loadFixture (file) { + return require('./fixtures/' + file) +} + +tape.test('lambda instrumentation does not break trans.setDefaultName', function (suite) { + let server + let serverUrl + + suite.test('setup', function (t) { + server = new MockAPMServer() + server.start(function (serverUrl_) { + serverUrl = serverUrl_ + t.comment('mock APM serverUrl: ' + serverUrl) + apm.start({ + serverUrl, + logLevel: 'off', + captureExceptions: false + }) + t.comment('APM agent started') + t.end() + }) + }) + + const eventCases = [ + { + name: 'TRIGGER_GENERIC', + event: loadFixture('generic.json') + }, + { + name: 'TRIGGER_API_GATEWAY', + event: loadFixture('aws_api_http_test_data.json') + }, + { + name: 'TRIGGER_SNS', + event: loadFixture('aws_sns_test_data.json') + }, + { + name: 'TRIGGER_SQS', + event: loadFixture('aws_sqs_test_data.json') + }, + { + name: 'TRIGGER_S3_SINGLE_EVENT', + event: loadFixture('aws_s3_test_data.json') + } + ] + eventCases.forEach(eventCase => { + suite.test(`trans.setDefaultName(...) works with ${eventCase.name} event type`, function (t) { + const handler = apm.lambda((event, _context, cb) => { + // Simulate some other instrumentation using `Transaction.setDefaultName(...)`. + // For example the graphql instrumentation will do this to set the + // transaction name. This should *work*. + apm.currentTransaction.setDefaultName('setting this trans name should work') + + cb(null, 'hi') + }) + + server.clear() + lambdaLocal.execute({ + event: eventCase.event, + lambdaFunc: { + [process.env.AWS_LAMBDA_FUNCTION_NAME]: handler + }, + lambdaHandler: process.env.AWS_LAMBDA_FUNCTION_NAME, + timeoutMs: 3000, + verboseLevel: 0, + callback: function (err, result) { + t.error(err, `no error from executing the lambda handler: err=${JSON.stringify(err)}`) + const trans = server.events[1].transaction + t.equal(trans.name, 'setting this trans name should work') + t.end() + } + }) + }) + }) + + suite.test('teardown', function (t) { + server.close() + t.end() + apm.destroy() + }) + + suite.end() +}) diff --git a/test/lambda/transaction.test.js b/test/lambda/transaction.test.js index 302a07d3dea..3918b655f02 100644 --- a/test/lambda/transaction.test.js +++ b/test/lambda/transaction.test.js @@ -54,7 +54,7 @@ tape.test('transaction data TRIGGER_API_GATEWAY v2', function (t) { t.strictEquals(transaction._faas.trigger.type, 'http', 'execution value set') t.strictEquals(transaction._faas.trigger.request_id, event.requestContext.requestId, 'execution value set') t.strictEquals(transaction.type, 'request', 'transaction type set') - t.strictEquals(transaction.name, 'GET /default/the-function-name', 'transaction named correctly') + t.strictEquals(transaction.name, 'POST /default/the-function-name', 'transaction named correctly') t.strictEquals(transaction._cloud.origin.provider, 'aws', 'cloud origin provider set correctly') t.strictEquals(transaction._service.origin.name, '21mj4tsk90.execute-api.us-west-2.amazonaws.com', 'service origin name set correctly') t.strictEquals(transaction._service.origin.id, '21mj4tsk90', 'service origin id set correctly') diff --git a/test/lambda/transaction2.test.js b/test/lambda/transaction2.test.js new file mode 100644 index 00000000000..005de6c35b7 --- /dev/null +++ b/test/lambda/transaction2.test.js @@ -0,0 +1,215 @@ +/* + * Copyright Elasticsearch B.V. and other contributors where applicable. + * Licensed under the BSD 2-Clause License; you may not use this file except in + * compliance with the BSD 2-Clause License. + */ + +'use strict' + +// Test "transaction" objects created for Lambda instrumentation. +// +// (This is similar to "transaction.test.js", but uses the real Agent, not the +// "AgentMock". The mock doesn't fully test the "transaction" intake event +// object creation path.) + +const lambdaLocal = require('lambda-local') +const tape = require('tape') + +const apm = require('../../') +const { MockAPMServer } = require('../_mock_apm_server') + +// Setup env for both apm.start() and lambdaLocal.execute(). +process.env.AWS_LAMBDA_FUNCTION_NAME = 'fixture-function-name' +// Set these values to have stable data from lambdaLocal.execute(). +process.env.AWS_EXECUTION_ENV = 'AWS_Lambda_nodejs14.x' +process.env.AWS_REGION = 'us-east-1' +process.env.AWS_ACCOUNT_ID = '123456789012' +// A lambda-local limitation is that it doesn't set AWS_LAMBDA_LOG_GROUP_NAME +// and AWS_LAMBDA_LOG_STREAM_NAME (per +// https://docs.aws.amazon.com/lambda/latest/dg/configuration-envvars.html). +process.env.AWS_LAMBDA_LOG_GROUP_NAME = `/aws/lambda/${process.env.AWS_LAMBDA_FUNCTION_NAME}` +process.env.AWS_LAMBDA_LOG_STREAM_NAME = '2021/11/01/[1.0]lambda/e7b05091b39b4aa2aef19efe4d262e79' +// Avoid the lambda-local loading AWS credentials and session info from +// a configured real AWS profile and possibly emitting this warning: +// warning Using both auth systems: aws_access_key/id and secret_access_token! +process.env.AWS_PROFILE = 'fake' + +function loadFixture (file) { + return require('./fixtures/' + file) +} + +tape.test('lambda transactions', function (suite) { + let server + let serverUrl + + suite.test('setup', function (t) { + server = new MockAPMServer() + server.start(function (serverUrl_) { + serverUrl = serverUrl_ + t.comment('mock APM serverUrl: ' + serverUrl) + apm.start({ + serverUrl, + logLevel: 'off', + captureExceptions: false, + captureBody: 'all' + }) + t.comment('APM agent started') + t.end() + }) + }) + + // Test HTTP context -- `transaction.context.{request,response}` -- for + // some event types. + const httpContextCases = [ + { + name: 'API Gateway (payload format version 1.0)', + event: loadFixture('aws_api_rest_test_data.json'), + checkApmEvents: (t, events) => { + const trans = events[1].transaction + t.deepEqual(trans.context.request, { + http_version: '1.1', + method: 'GET', + url: { + raw: '/dev/fetch_all?q=myquery', + protocol: 'https:', + hostname: '02plqthge2.execute-api.us-east-1.amazonaws.com', + port: '443', + pathname: '/dev/fetch_all', + search: '?q=myquery', + full: 'https://02plqthge2.execute-api.us-east-1.amazonaws.com:443/dev/fetch_all?q=myquery' + }, + headers: { + accept: 'text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8', + 'accept-encoding': 'gzip, deflate, br', + 'accept-language': 'en-US,en;q=0.5', + 'cloudfront-forwarded-proto': 'https', + 'cloudfront-is-desktop-viewer': 'true', + 'cloudfront-is-mobile-viewer': 'false', + 'cloudfront-is-smarttv-viewer': 'false', + 'cloudfront-is-tablet-viewer': 'false', + 'cloudfront-viewer-country': 'US', + host: '02plqthge2.execute-api.us-east-1.amazonaws.com', + 'upgrade-insecure-requests': '1', + 'user-agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10.15; rv:72.0) Gecko/20100101 Firefox/72.0', + via: '2.0 969f35f01b6eddd92239a3e818fc1e0d.cloudfront.net (CloudFront)', + 'x-amz-cf-id': 'eDbpfDwO-CRYymEFLkW6CBCsU_H_PS8R93_us53QWvXWLS45v3NvQw==', + 'x-amzn-trace-id': 'Root=1-5e502af4-fd0c1c6fdc164e1d6361183b', + 'x-forwarded-for': '76.76.241.57, 52.46.47.139', + 'x-forwarded-port': '443', + 'x-forwarded-proto': 'https' + }, + socket: { remote_address: '76.76.241.57' } + }, 'transaction.context.request') + t.deepEqual(trans.context.response, { + status_code: 202, + headers: { Foo: 'bar' } + }, 'transaction.context.response') + } + }, + { + name: 'API Gateway (payload format version 2.0)', + event: loadFixture('aws_api_http_test_data.json'), + checkApmEvents: (t, events) => { + const trans = events[1].transaction + t.deepEqual(trans.context.request, { + http_version: '1.1', + method: 'POST', + url: { + raw: '/default/the-function-name?q=foo', + protocol: 'https:', + hostname: '21mj4tsk90.execute-api.us-west-2.amazonaws.com', + port: '443', + pathname: '/default/the-function-name', + search: '?q=foo', + full: 'https://21mj4tsk90.execute-api.us-west-2.amazonaws.com:443/default/the-function-name?q=foo' + }, + headers: { + accept: '*/*', + 'content-length': '13', + 'content-type': 'application/json', + host: '21mj4tsk90.execute-api.us-west-2.amazonaws.com', + 'user-agent': 'curl/7.64.1', + 'x-amzn-trace-id': 'Root=1-611598fd-16b2bd060ca70cab7eb87c47', + 'x-forwarded-for': '67.171.184.49', + 'x-forwarded-port': '443', + 'x-forwarded-proto': 'https' + }, + socket: { remote_address: '67.171.184.49' }, + body: '{"foo":"bar"}' + }, 'transaction.context.request') + t.deepEqual(trans.context.response, { + status_code: 202, + headers: { Foo: 'bar' } + }, 'transaction.context.response') + } + }, + { + name: 'API Gateway 2.0 event with inferred response data', + event: loadFixture('aws_api_http_test_data.json'), + handler: (_event, _context, cb) => { + cb(null, 'hi') + }, + checkApmEvents: (t, events) => { + const trans = events[1].transaction + t.deepEqual(trans.context.response, { + status_code: 200, + headers: { 'content-type': 'application/json' } + }, 'transaction.context.response') + } + }, + { + name: 'API Gateway event, handler returns error, captured error should have HTTP context', + event: loadFixture('aws_api_http_test_data.json'), + handler: (_event, _context, cb) => { + cb(new Error('boom')) + }, + checkApmEvents: (t, events) => { + const trans = events[1].transaction + const error = events[2].error + t.equal(trans.outcome, 'failure', 'transaction.outcome') + t.equal(error.transaction_id, trans.id, 'error.transaction_id') + t.ok(error.context.request, 'has error.context.request') + t.equal(error.context.response.status_code, 500, 'error.context.response.status_code') + } + } + ] + httpContextCases.forEach(c => { + suite.test(c.name, { skip: c.skip || false }, function (t) { + const handler = c.handler || ( + (_event, _context, cb) => { + cb(null, { + statusCode: 202, + headers: { + Foo: 'bar' + }, + body: 'hi' + }) + } + ) + const wrappedHandler = apm.lambda(handler) + + server.clear() + lambdaLocal.execute({ + event: c.event, + lambdaFunc: { + [process.env.AWS_LAMBDA_FUNCTION_NAME]: wrappedHandler + }, + lambdaHandler: process.env.AWS_LAMBDA_FUNCTION_NAME, + timeoutMs: 3000, + verboseLevel: 0, + callback: function (_err, _result) { + c.checkApmEvents(t, server.events) + t.end() + } + }) + }) + }) + + suite.test('teardown', function (t) { + server.close() + t.end() + apm.destroy() + }) + + suite.end() +}) diff --git a/test/metrics/breakdown.test.js b/test/metrics/breakdown.test.js index 1e3fc200fd5..928ba0b0721 100644 --- a/test/metrics/breakdown.test.js +++ b/test/metrics/breakdown.test.js @@ -276,9 +276,9 @@ test('with parallel sub-spans', t => { }) setImmediate(function () { // Note: This use of `childOf` is to ensure span1 is a child of the - // transaction for the special case of (a) asyncHooks=false such that we are - // using "patch-async.js" and (b) use of `agent.destroy(); new Agent()`. - // The latter breaks patch-async's patching of setImmediate. + // transaction for the special case of (a) contextManager="patch" such that + // we are using "patch-async.js" and (b) use of `agent.destroy(); new + // Agent()`. The latter breaks patch-async's patching of setImmediate. var span1 = agent.startSpan('SELECT * FROM b', 'db.mysql', { startTime: 10, childOf: transaction }) setImmediate(function () { diff --git a/test/opentelemetry-bridge/otel-bridge-feature.test.js b/test/opentelemetry-bridge/otel-bridge-feature.test.js index 8fa61da7a1a..98da1c36542 100644 --- a/test/opentelemetry-bridge/otel-bridge-feature.test.js +++ b/test/opentelemetry-bridge/otel-bridge-feature.test.js @@ -7,11 +7,18 @@ 'use strict' // Test functionality described in: -// https://github.com/elastic/apm/blob/main/tests/agents/gherkin-specs/otel_bridge.feature#L30 -// https://github.com/elastic/apm/blob/main/specs/agents/tracing-api-otel.md#compatibility-mapping +// https://github.com/elastic/apm/blob/main/tests/agents/gherkin-specs/otel_bridge.feature#L30 +// which largely tests compatibility mapping described here: +// https://github.com/elastic/apm/blob/main/specs/agents/tracing-api-otel.md#compatibility-mapping // -// See https://github.com/elastic/apm-agent-nodejs/pull/2672 for why we aren't -// testing with the Gherkin .feature files directly. +// It would be more convenient for maintenance to test "otel_bridge.feature" +// directly. However we cannot test Gherkin (.feature) files directly. +// See https://github.com/elastic/apm-agent-nodejs/pull/2672 for why. +// +// Instead, this file is a *manual* painstaking translation of the logic of +// "otel_bridge.feature". +// - Currently at commit 4412a55 of https://github.com/elastic/apm/commits/main/tests/agents/gherkin-specs/otel_bridge.feature +// - Each "Scenario: ..." from "otel_bridge.feature" is a separate test case below. const otel = require('@opentelemetry/api') const tape = require('tape') @@ -20,7 +27,7 @@ const Agent = require('../../lib/agent') const { OUTCOME_UNKNOWN, OUTCOME_SUCCESS, OUTCOME_FAILURE } = require('../../lib/constants') const { MockAPMServer } = require('../_mock_apm_server') -tape.test('APM Server e.span) .map(e => e.span) - .sort((a, b) => a.name - b.name) // Cannot use "timestamp" for sorting, because #2180. + .sort((a, b) => a.name < b.name ? -1 : 1) // Cannot use "timestamp" for sorting, because #2180. t.equal(spans.length, examples.length, `got ${examples.length} spans`) for (let i = 0; i < examples.length; i++) { const ex = examples[i] const span = spans[i] + t.comment(`example: ${JSON.stringify(ex)}`) t.ok(span, 'Then Elastic bridged object is a span') t.equal(span.otel.span_kind, otel.SpanKind[ex.kind], 'Then Elastic bridged span OTel kind is ""') t.equal(span.type, ex.type, 'Then Elastic bridged span type is ""') @@ -107,7 +115,7 @@ tape.test('APM Server e.transaction) .map(e => e.transaction) - .sort((a, b) => a.name - b.name) // Cannot use "timestamp" for sorting, because #2180. + .sort((a, b) => a.name < b.name ? -1 : 1) // Cannot use "timestamp" for sorting, because #2180. t.equal(transactions.length, examples.length, `got ${examples.length} transactions`) for (let i = 0; i < examples.length; i++) { const ex = examples[i] @@ -136,7 +144,7 @@ tape.test('APM Server e.transaction) .map(e => e.transaction) - .sort((a, b) => a.name - b.name) // Cannot use "timestamp" for sorting, because #2180. + .sort((a, b) => a.name < b.name ? -1 : 1) // Cannot use "timestamp" for sorting, because #2180. t.equal(transactions.length, examples.length, `got ${examples.length} transactions`) for (let i = 0; i < examples.length; i++) { const ex = examples[i] @@ -167,7 +175,7 @@ tape.test('APM Server e.span) .map(e => e.span) - .sort((a, b) => a.name - b.name) // Cannot use "timestamp" for sorting, because #2180. + .sort((a, b) => a.name < b.name ? -1 : 1) // Cannot use "timestamp" for sorting, because #2180. t.equal(spans.length, examples.length, `got ${examples.length} spans`) for (let i = 0; i < examples.length; i++) { const ex = examples[i] @@ -194,7 +202,7 @@ tape.test('APM Server e.transaction) .map(e => e.transaction) - .sort((a, b) => a.name - b.name) // Cannot use "timestamp" for sorting, because #2180. + .sort((a, b) => a.name < b.name ? -1 : 1) // Cannot use "timestamp" for sorting, because #2180. t.equal(transactions.length, examples.length, `got ${examples.length} transactions`) for (let i = 0; i < examples.length; i++) { const trans = transactions[i] @@ -212,39 +220,39 @@ tape.test('APM Server { @@ -258,7 +266,7 @@ tape.test('APM Server e.span) .map(e => e.span) - .sort((a, b) => a.name - b.name) // Cannot use "timestamp" for sorting, because #2180. + .sort((a, b) => a.name < b.name ? -1 : 1) // Cannot use "timestamp" for sorting, because #2180. t.equal(spans.length, examples.length, `got ${examples.length} spans`) for (let i = 0; i < examples.length; i++) { const ex = examples[i] @@ -266,7 +274,9 @@ tape.test('APM Server "') + t.equal(span.context.destination.service.resource, ex.target_service_name, 'Then Elastic bridged span destination resource is set to ""') + t.equal(span.context.service.target.type, 'http', 'Then Elastic bridged span service target type is \'http\' ...') + t.equal(span.context.service.target.name, ex.target_service_name, 'Then Elastic bridged span service target ... name is ""') } apmServer.clear() @@ -282,31 +292,35 @@ tape.test('APM Server { @@ -320,7 +334,7 @@ tape.test('APM Server e.span) .map(e => e.span) - .sort((a, b) => a.name - b.name) // Cannot use "timestamp" for sorting, because #2180. + .sort((a, b) => a.name < b.name ? -1 : 1) // Cannot use "timestamp" for sorting, because #2180. t.equal(spans.length, examples.length, `got ${examples.length} spans`) for (let i = 0; i < examples.length; i++) { const ex = examples[i] @@ -329,6 +343,8 @@ tape.test('APM Server "') t.deepEqual(span.otel.attributes, ex.attributes, 'Then Elastic bridged span OTel attributes are copied as-is') t.equal(span.context.destination.service.resource, ex.resource, 'Then Elastic bridged span destination resource is set to ""') + t.equal(span.context.service.target.type, ex.attributes['db.system'], 'Then Elastic bridged span service target type is "" ...') + t.equal(span.context.service.target.name, ex.target_service_name, 'Then Elastic bridged span service target ... name is ""') } apmServer.clear() @@ -360,7 +376,7 @@ tape.test('APM Server e.span) .map(e => e.span) - .sort((a, b) => a.name - b.name) // Cannot use "timestamp" for sorting, because #2180. + .sort((a, b) => a.name < b.name ? -1 : 1) // Cannot use "timestamp" for sorting, because #2180. t.equal(spans.length, examples.length, `got ${examples.length} spans`) for (let i = 0; i < examples.length; i++) { const ex = examples[i] @@ -441,6 +461,8 @@ tape.test('APM Server "') t.deepEqual(span.otel.attributes, ex.attributes, 'Then Elastic bridged span OTel attributes are copied as-is') t.equal(span.context.destination.service.resource, ex.resource, 'Then Elastic bridged span destination resource is set to ""') + t.equal(span.context.service.target.type, ex.attributes['messaging.system'], 'Then Elastic bridged span service target type is "" ...') + t.equal(span.context.service.target.name, ex.target_service_name, 'Then Elastic bridged span service target ... name is ""') } apmServer.clear() @@ -461,7 +483,8 @@ tape.test('APM Server { @@ -520,11 +548,12 @@ tape.test('APM Server e.span) .map(e => e.span) - .sort((a, b) => a.name - b.name) // Cannot use "timestamp" for sorting, because #2180. + .sort((a, b) => a.name < b.name ? -1 : 1) // Cannot use "timestamp" for sorting, because #2180. t.equal(spans.length, examples.length, `got ${examples.length} spans`) for (let i = 0; i < examples.length; i++) { const ex = examples[i] const span = spans[i] + t.comment('attributes: ' + JSON.stringify(ex.attributes)) t.equal(span.type, 'external', 'Then Elastic bridged span type is "external"') t.equal(span.subtype, ex.attributes['rpc.system'], 'Then Elastic bridged span subtype is ""') t.deepEqual(span.otel.attributes, ex.attributes, 'Then Elastic bridged span OTel attributes are copied as-is') diff --git a/test/sanitize-field-names/_fixtures.js b/test/sanitize-field-names/_fixtures.js index 8a2128f53a4..e622f97230c 100644 --- a/test/sanitize-field-names/_fixtures.js +++ b/test/sanitize-field-names/_fixtures.js @@ -58,6 +58,7 @@ module.exports = [ authorization: 'eleven', 'set-cookie': 'twelve', 'X-Authy-Thing': 'thirteen', + 'X-Ms-Client-Principal': 'fourteen', keepmeRequest: 'request' }, responseHeaders: { @@ -74,6 +75,7 @@ module.exports = [ authorization: 'eleven', 'set-cookie': 'twelve', 'X-Authy-Thing': 'thirteen', + 'X-Ms-Client-Principal': 'fourteen', keepmeResponse: 'response' }, formFields: { @@ -90,6 +92,7 @@ module.exports = [ authorization: 'eleven', 'set-cookie': 'twelve', 'X-Authy-Thing': 'thirteen', + 'X-Ms-Client-Principal': 'fourteen', keepmeForm: 'formFields' } }, @@ -98,7 +101,8 @@ module.exports = [ undefined: [ 'password', 'passwd', 'pwd', 'secret', 'Somethingkey', 'FOOtokenBAR', 'ZIPsessionZAP', 'FOOsessionBAR', 'FULLOFcreditBEES', 'SINGcardSONG', - 'authorization', 'set-cookie', 'X-Authy-Thing' + 'authorization', 'set-cookie', 'X-Authy-Thing', + 'X-Ms-Client-Principal' ], defined: { keepmeRequest: 'request' } }, @@ -106,7 +110,8 @@ module.exports = [ undefined: [ 'password', 'passwd', 'pwd', 'secret', 'Somethingkey', 'FOOtokenBAR', 'ZIPsessionZAP', 'FOOsessionBAR', 'FULLOFcreditBEES', 'SINGcardSONG', - 'authorization', 'set-cookie', 'X-Authy-Thing' + 'authorization', 'set-cookie', 'X-Authy-Thing', + 'X-Ms-Client-Principal' ], defined: { keepmeResponse: 'response' } }, @@ -114,7 +119,8 @@ module.exports = [ undefined: [ 'password', 'passwd', 'pwd', 'secret', 'Somethingkey', 'FOOtokenBAR', 'ZIPsessionZAP', 'FOOsessionBAR', 'FULLOFcreditBEES', 'SINGcardSONG', - 'authorization', 'set-cookie', 'X-Authy-Thing' + 'authorization', 'set-cookie', 'X-Authy-Thing', + 'X-Ms-Client-Principal' ], defined: { keepmeForm: 'formFields' } } @@ -139,6 +145,7 @@ module.exports = [ authorization: 'eleven', 'set-cookie': 'twelve', 'X-Authy-Thing': 'thirteen', + 'X-Ms-Client-Principal': 'fourteen', keepmeRequest: 'request' }, responseHeaders: { @@ -155,6 +162,7 @@ module.exports = [ authorization: 'eleven', 'set-cookie': 'twelve', 'X-Authy-Thing': 'thirteen', + 'X-Ms-Client-Principal': 'fourteen', keepmeResponse: 'response' }, formFields: { @@ -171,6 +179,7 @@ module.exports = [ authorization: 'eleven', 'set-cookie': 'twelve', 'X-Authy-Thing': 'thirteen', + 'X-Ms-Client-Principal': 'fourteen', keepmeForm: 'formFields' } }, @@ -179,7 +188,8 @@ module.exports = [ undefined: [ 'password', 'passwd', 'pwd', 'secret', 'Somethingkey', 'FOOtokenBAR', 'ZIPsessionZAP', 'FOOsessionBAR', 'FULLOFcreditBEES', 'SINGcardSONG', - 'authorization', 'set-cookie', 'X-Authy-Thing' + 'authorization', 'set-cookie', 'X-Authy-Thing', + 'X-Ms-Client-Principal' ], defined: { keepmeRequest: 'request' } }, @@ -187,7 +197,8 @@ module.exports = [ undefined: [ 'password', 'passwd', 'pwd', 'secret', 'Somethingkey', 'FOOtokenBAR', 'ZIPsessionZAP', 'FOOsessionBAR', 'FULLOFcreditBEES', 'SINGcardSONG', - 'authorization', 'set-cookie', 'X-Authy-Thing' + 'authorization', 'set-cookie', 'X-Authy-Thing', + 'X-Ms-Client-Principal' ], defined: { keepmeResponse: 'response' } }, @@ -195,7 +206,8 @@ module.exports = [ undefined: [ 'password', 'passwd', 'pwd', 'secret', 'Somethingkey', 'FOOtokenBAR', 'ZIPsessionZAP', 'FOOsessionBAR', 'FULLOFcreditBEES', 'SINGcardSONG', - 'authorization', 'set-cookie', 'X-Authy-Thing' + 'authorization', 'set-cookie', 'X-Authy-Thing', + 'X-Ms-Client-Principal' ], defined: { keepmeForm: 'formFields' } } diff --git a/test/sanitize-field-names/restify.test.js b/test/sanitize-field-names/restify.test.js index db78fdb79bc..51669697991 100644 --- a/test/sanitize-field-names/restify.test.js +++ b/test/sanitize-field-names/restify.test.js @@ -6,11 +6,9 @@ 'use strict' -// Restify is broken on latest node v18 nightlies. -// https://github.com/restify/node-restify/issues/1888 -const semver = require('semver') -if (semver.satisfies(process.version, '>17.x', { includePrerelease: true })) { - console.log(`# SKIP restify does not support node ${process.version}`) +const isRestifyIncompat = require('../_is_restify_incompat')() +if (isRestifyIncompat) { + console.log(`# SKIP ${isRestifyIncompat}`) process.exit() } diff --git a/test/service-resource-inference.test.js b/test/service-resource-inference.test.js new file mode 100644 index 00000000000..55b0fb2b329 --- /dev/null +++ b/test/service-resource-inference.test.js @@ -0,0 +1,93 @@ +/* + * Copyright Elasticsearch B.V. and other contributors where applicable. + * Licensed under the BSD 2-Clause License; you may not use this file except in + * compliance with the BSD 2-Clause License. + */ + +'use strict' + +// Test cases from the cross-agent "json-specs/service_resource_inference.json" +// from apm.git. + +const { CapturingTransport } = require('./_capturing_transport') +const apm = require('..').start({ + serviceName: 'test-service-resource-inference', + logUncaughtExceptions: true, + metricsInterval: '0s', + centralConfig: false, + logLevel: 'off', + spanCompressionEnabled: false, + transport () { return new CapturingTransport() } +}) + +const test = require('tape') +const { URL } = require('url') + +test('setup: current trans', t => { + apm.startTransaction('aTrans', 'manual') + t.end() +}) + +var testData = require('./fixtures/json-specs/service_resource_inference.json') +testData.forEach(testDatum => { + test(testDatum.failure_message, t => { + // 1. Create a span according to `testDatum.span`. + const spanOpts = { + exitSpan: testDatum.span.exit === 'true' + } + const span = apm.startSpan('aSpan', testDatum.span.type, testDatum.span.subtype, spanOpts) + if (testDatum.span.context) { + if (testDatum.span.context.db) { + span.setDbContext(testDatum.span.context.db) + } + if (testDatum.span.context.http) { + // service_resource_inference.json oddly provides context.http.url as + // an object with "host" and "port" fields, rather than as a URL string + // as accepted by the intake API. So we need to construct it. + const httpContext = Object.assign({}, testDatum.span.context.http) + if (httpContext.url) { + const u = new URL('', 'http://example.com') + if (httpContext.url.host) { u.hostname = httpContext.url.host } + if (httpContext.url.port) { u.port = httpContext.url.port } + httpContext.url = u.href + } + span.setHttpContext(httpContext) + } + if (testDatum.span.context.message) { + span.setMessageContext(testDatum.span.context.message) + } + if (testDatum.span.context.service && testDatum.span.context.service.target) { + span.setServiceTarget(testDatum.span.context.service.target.type, testDatum.span.context.service.target.name) + } + } + span.end() + + // 2. Then assert that it has the expected destination.service.resource and + // service.target. + apm.flush(() => { + const spanPayload = apm._transport.spans.pop() + if (testDatum.expected_resource === null) { + t.ok(!(spanPayload.context && spanPayload.context.destination && spanPayload.context.destination.service), + 'no span.context.destination.service.resource') + } else { + t.equal(spanPayload.context.destination.service.resource, + testDatum.expected_resource, + 'span.context.destination.service.resource') + } + if (testDatum.expected_service_target === null) { + t.ok(!(spanPayload.context && spanPayload.context.service && spanPayload.context.service.target), + 'no span.context.service.target') + } else { + t.deepEqual(spanPayload.context.service.target, + testDatum.expected_service_target, + 'span.context.service.target') + } + t.end() + }) + }) +}) + +test('teardown', t => { + apm.endTransaction() + t.end() +}) diff --git a/test/stacktraces/fixtures/get-prepare-stacktrace.js b/test/stacktraces/fixtures/get-prepare-stacktrace.js new file mode 100644 index 00000000000..02a19bc63f5 --- /dev/null +++ b/test/stacktraces/fixtures/get-prepare-stacktrace.js @@ -0,0 +1,20 @@ +/* + * Copyright Elasticsearch B.V. and other contributors where applicable. + * Licensed under the BSD 2-Clause License; you may not use this file except in + * compliance with the BSD 2-Clause License. + */ + +// print name of error.prepareStackTrace function to STDOUT +require('../../../').start({ + serviceName: 'test-get-prepare-stacktrace', + logUncaughtExceptions: true, + metricsInterval: 0, + centralConfig: false, + logLevel: 'off' +}) +function main () { + const name = Error.prepareStackTrace ? Error.prepareStackTrace.name : undefined + console.log(name) +} + +main() diff --git a/test/stacktraces/stacktraces.test.js b/test/stacktraces/stacktraces.test.js index 65503fa474d..12759d526af 100644 --- a/test/stacktraces/stacktraces.test.js +++ b/test/stacktraces/stacktraces.test.js @@ -16,7 +16,7 @@ const tape = require('tape') const logging = require('../../lib/logging') const { MockAPMServer } = require('../_mock_apm_server') -const { gatherStackTrace, stackTraceFromErrStackString } = require('../../lib/stacktraces') +const { gatherStackTrace, initStackTraceCollection, stackTraceFromErrStackString } = require('../../lib/stacktraces') const log = logging.createLogger('off') @@ -304,6 +304,7 @@ tape.test('stackTraceFromErrStackString()', function (t) { }) tape.test('gatherStackTrace()', function (suite) { + initStackTraceCollection() function thisIsMyFunction () { // before 2 // before 1 @@ -398,5 +399,51 @@ tape.test('gatherStackTrace()', function (suite) { }) }) + tape.test('Error.prepareStackTrace is set', function (t) { + const server = new MockAPMServer() + server.start(function (serverUrl) { + execFile( + process.execPath, + ['fixtures/get-prepare-stacktrace.js'], + { + cwd: __dirname, + timeout: 3000, + env: Object.assign({}, process.env, { + ELASTIC_APM_ACTIVE: true + }) + }, + function done (err, _stdout, _stderr) { + t.ok(!err) + t.equals(_stdout.trim(), 'csPrepareStackTrace', 'Error.prepareStackTrace is set') + server.close() + t.end() + } + ) + }) + }) + + tape.test('Error.prepareStackTrace is not set', function (t) { + const server = new MockAPMServer() + server.start(function (serverUrl) { + execFile( + process.execPath, + ['fixtures/get-prepare-stacktrace.js'], + { + cwd: __dirname, + timeout: 3000, + env: Object.assign({}, process.env, { + ELASTIC_APM_ACTIVE: false + }) + }, + function done (err, _stdout, _stderr) { + t.ok(!err) + t.equals(_stdout.trim(), 'undefined', 'Error.prepareStackTrace is set') + server.close() + t.end() + } + ) + }) + }) + suite.end() }) diff --git a/test/traceContinuationStrategy.test.js b/test/traceContinuationStrategy.test.js index 2c3269d6236..ff4e25f4a2d 100644 --- a/test/traceContinuationStrategy.test.js +++ b/test/traceContinuationStrategy.test.js @@ -20,6 +20,8 @@ const http = require('http') const semver = require('semver') const tape = require('tape') +const config = require('../lib/config') + // Ensure that, by default, an HTTP request with a valid traceparent to an // instrumented HTTP server *uses* that traceparent. tape.test('traceContinuationStrategy default is continue', t => { @@ -60,8 +62,9 @@ tape.test('traceContinuationStrategy=continue', t => { res.end('pong') }) server.listen(function () { - if (semver.satisfies(process.version, '<=8') && apm._conf.asyncHooks === false) { - // There is some bug in node v8 and lower and with asyncHooks=false + if (semver.satisfies(process.version, '<=8') && + apm._conf.contextManager === config.CONTEXT_MANAGER_PATCH) { + // There is some bug in node v8 and lower and with contextManager="patch" // instrumentation where this listener callback takes the run context of // the preceding test's transaction. Hack it back. apm._instrumentation.supersedeWithEmptyRunContext() @@ -97,8 +100,9 @@ tape.test('traceContinuationStrategy=restart', t => { res.end('pong') }) server.listen(function () { - if (semver.satisfies(process.version, '<=8') && apm._conf.asyncHooks === false) { - // There is some bug in node v8 and lower and with asyncHooks=false + if (semver.satisfies(process.version, '<=8') && + apm._conf.contextManager === config.CONTEXT_MANAGER_PATCH) { + // There is some bug in node v8 and lower and with contextManager="patch" // instrumentation where this listener callback takes the run context of // the preceding test's transaction. Hack it back. apm._instrumentation.supersedeWithEmptyRunContext() @@ -138,8 +142,9 @@ tape.test('traceContinuationStrategy=restart_external (no tracestate)', t => { res.end('pong') }) server.listen(function () { - if (semver.satisfies(process.version, '<=8') && apm._conf.asyncHooks === false) { - // There is some bug in node v8 and lower and with asyncHooks=false + if (semver.satisfies(process.version, '<=8') && + apm._conf.contextManager === config.CONTEXT_MANAGER_PATCH) { + // There is some bug in node v8 and lower and with contextManager="patch" // instrumentation where this listener callback takes the run context of // the preceding test's transaction. Hack it back. apm._instrumentation.supersedeWithEmptyRunContext() @@ -178,8 +183,9 @@ tape.test('traceContinuationStrategy=restart_external (tracestate without "es")' res.end('pong') }) server.listen(function () { - if (semver.satisfies(process.version, '<=8') && apm._conf.asyncHooks === false) { - // There is some bug in node v8 and lower and with asyncHooks=false + if (semver.satisfies(process.version, '<=8') && + apm._conf.contextManager === config.CONTEXT_MANAGER_PATCH) { + // There is some bug in node v8 and lower and with contextManager="patch" // instrumentation where this listener callback takes the run context of // the preceding test's transaction. Hack it back. apm._instrumentation.supersedeWithEmptyRunContext() @@ -217,8 +223,9 @@ tape.test('traceContinuationStrategy=restart_external (tracestate with "es")', t res.end('pong') }) server.listen(function () { - if (semver.satisfies(process.version, '<=8') && apm._conf.asyncHooks === false) { - // There is some bug in node v8 and lower and with asyncHooks=false + if (semver.satisfies(process.version, '<=8') && + apm._conf.contextManager === config.CONTEXT_MANAGER_PATCH) { + // There is some bug in node v8 and lower and with contextManager="patch" // instrumentation where this listener callback takes the run context of // the preceding test's transaction. Hack it back. apm._instrumentation.supersedeWithEmptyRunContext() diff --git a/test/types/index.ts b/test/types/index.ts index 8ed7a940d5f..6e2fa05b948 100644 --- a/test/types/index.ts +++ b/test/types/index.ts @@ -87,6 +87,9 @@ apm.captureError({ message: 'hello %s', params: ['world'] }, { tags: { foo: 'bar apm.captureError(new Error('foo'), () => {}) apm.captureError('foo', () => {}) apm.captureError({ message: 'hello %s', params: ['world'] }, () => {}) +apm.captureError(new Error('an error on the transaction'), { parent: trans }) +apm.captureError(new Error('an error on the span'), { parent: span }) +apm.captureError(new Error('an error with explicitly no parent'), { parent: null }) apm.startTransaction() apm.startTransaction('foo') @@ -97,6 +100,8 @@ apm.startTransaction('foo', { startTime: 1 }) apm.startTransaction('foo', 'type', { startTime: 1 }) apm.startTransaction('foo', 'type', 'subtype', { startTime: 1 }) apm.startTransaction('foo', 'type', 'subtype', 'action', { startTime: 1 }) +apm.startTransaction('foo', { childOf: '00-12345678901234567890123456789012-1234567890123456-01' }) +apm.startTransaction('foo', { tracestate: 'foo=42,bar=43' }) apm.startTransaction('foo', { links: [{ context: '00-12345678901234567890123456789012-1234567890123456-01' }] }) apm.setTransactionName('foo') @@ -219,6 +224,11 @@ apm.logger.fatal('') span.setOutcome('failure') + span.setServiceTarget('myServiceTargetType') + span.setServiceTarget('myServiceTargetType', 'myServiceTargetName') + span.setServiceTarget(null, null) + span.setServiceTarget() + span.end() span.end(42) }