diff --git a/.devcontainer/devcontainer.json b/.devcontainer/devcontainer.json index bd207514cb..b49ea2d8a5 100644 --- a/.devcontainer/devcontainer.json +++ b/.devcontainer/devcontainer.json @@ -22,7 +22,6 @@ "firsttris.vscode-jest-runner", "visualstudioexptteam.vscodeintellicode", "amazonwebservices.aws-toolkit-vscode", - "ms-vscode.vscode-typescript-tslint-plugin", "ms-azuretools.vscode-docker" ], // Use 'postCreateCommand' to run commands after the container is created. diff --git a/.eslintrc.js b/.eslintrc.js index b83ce24ffc..ef25880334 100644 --- a/.eslintrc.js +++ b/.eslintrc.js @@ -1,4 +1,5 @@ module.exports = { + root: true, env: { browser: false, es2020: true, @@ -63,5 +64,5 @@ module.exports = { 'prefer-arrow-callback': 'error', quotes: [ 'error', 'single', { allowTemplateLiterals: true } ], semi: [ 'error', 'always' ] - }, + } }; diff --git a/.github/ISSUE_TEMPLATE/bug_report.yml b/.github/ISSUE_TEMPLATE/bug_report.yml index efaecdb144..ef199d42c0 100644 --- a/.github/ISSUE_TEMPLATE/bug_report.yml +++ b/.github/ISSUE_TEMPLATE/bug_report.yml @@ -28,23 +28,31 @@ body: attributes: label: Code snippet description: Please share a code snippet to help us reproduce the issue - render: JavaScript + placeholder: | + ```typescript + some code here + ``` validations: required: true - - type: textarea - id: solution - attributes: - label: Possible Solution - description: If known, please suggest a potential resolution - validations: - required: false - type: textarea id: steps attributes: label: Steps to Reproduce description: Please share how we might be able to reproduce this issue + placeholder: | + 1. In this environment... + 2. With this config... + 3. Run '...' + 4. See error... validations: required: true + - type: textarea + id: solution + attributes: + label: Possible Solution + description: If known, please suggest a potential resolution + validations: + required: false - type: input id: version attributes: @@ -69,7 +77,7 @@ body: label: Packaging format used options: - Lambda Layers - - Npm + - npm multiple: true validations: required: true diff --git a/.github/ISSUE_TEMPLATE/config.yml b/.github/ISSUE_TEMPLATE/config.yml index 1aac771b9b..59579b9724 100644 --- a/.github/ISSUE_TEMPLATE/config.yml +++ b/.github/ISSUE_TEMPLATE/config.yml @@ -2,4 +2,7 @@ blank_issues_enabled: false contact_links: - name: Ask a question url: https://github.com/awslabs/aws-lambda-powertools-typescript/discussions/new - about: Ask a general question about Lambda Powertools \ No newline at end of file + about: Ask a general question about Lambda Powertools + - name: Join Community Discord Server + url: https://discord.gg/B8zZKbbyET + about: "Check out the #typescript channel" \ No newline at end of file diff --git a/.github/ISSUE_TEMPLATE/feature_request.yml b/.github/ISSUE_TEMPLATE/feature_request.yml index 964a4cc897..eb77d4d838 100644 --- a/.github/ISSUE_TEMPLATE/feature_request.yml +++ b/.github/ISSUE_TEMPLATE/feature_request.yml @@ -7,8 +7,6 @@ body: attributes: value: | Thank you for taking the time to suggest an idea to the Lambda Powertools project. - - *Future readers*: Please react with πŸ‘ and your use case to help us understand customer demand. - type: textarea id: problem attributes: @@ -38,11 +36,17 @@ body: options: - label: This feature request meets [Lambda Powertools Tenets](https://awslabs.github.io/aws-lambda-powertools-typescript/latest/#tenets) required: true - - label: Should this be considered in other Lambda Powertools languages? i.e. [Python](https://github.com/awslabs/aws-lambda-powertools-python/), [Java](https://github.com/awslabs/aws-lambda-powertools-java/) + - label: Should this be considered in other Lambda Powertools languages? i.e. [Python](https://github.com/awslabs/aws-lambda-powertools-python/), [Java](https://github.com/awslabs/aws-lambda-powertools-java/), and [.NET](https://github.com/awslabs/aws-lambda-powertools-dotnet/) required: false - type: markdown attributes: value: | --- - **Disclaimer**: After creating an issue, please wait until it is triaged and confirmed by a maintainer before implementing it. This will reduce amount of rework and the chance that a pull request gets rejected. \ No newline at end of file + **Disclaimer**: After creating an issue, please wait until it is triaged and confirmed by a maintainer before implementing it. This will reduce amount of rework and the chance that a pull request gets rejected. + - type: input + id: notes + attributes: + label: Future readers + description: Please not edit this field + value: "Please react with πŸ‘ and your use case to help us understand customer demand." \ No newline at end of file diff --git a/.github/ISSUE_TEMPLATE/maintenance.yml b/.github/ISSUE_TEMPLATE/maintenance.yml index cfd98ca876..505a284360 100644 --- a/.github/ISSUE_TEMPLATE/maintenance.yml +++ b/.github/ISSUE_TEMPLATE/maintenance.yml @@ -7,8 +7,6 @@ body: attributes: value: | Thank you for taking the time to help us improve this project. - - *Future readers*: Please react with πŸ‘ and your use case to help us understand customer demand. - type: textarea id: activity attributes: @@ -52,11 +50,17 @@ body: options: - label: This request meets [Lambda Powertools Tenets](https://awslabs.github.io/aws-lambda-powertools-typescript/latest/#tenets) required: true - - label: Should this be considered in other Lambda Powertools languages? i.e. [Python](https://github.com/awslabs/aws-lambda-powertools-python/), [Java](https://github.com/awslabs/aws-lambda-powertools-java/) + - label: Should this be considered in other Lambda Powertools languages? i.e. [Python](https://github.com/awslabs/aws-lambda-powertools-python/), [Java](https://github.com/awslabs/aws-lambda-powertools-java/), and [.NET](https://github.com/awslabs/aws-lambda-powertools-dotnet/) required: false - type: markdown attributes: value: | --- - **Disclaimer**: After creating an issue, please wait until it is triaged and confirmed by a maintainer before implementing it. This will reduce amount of rework and the chance that a pull request gets rejected. \ No newline at end of file + **Disclaimer**: After creating an issue, please wait until it is triaged and confirmed by a maintainer before implementing it. This will reduce amount of rework and the chance that a pull request gets rejected. + - type: input + id: notes + attributes: + label: Future readers + description: Please not edit this field + value: "Please react with πŸ‘ and your use case to help us understand customer demand." \ No newline at end of file diff --git a/.github/ISSUE_TEMPLATE/rfc.yml b/.github/ISSUE_TEMPLATE/rfc.yml index 8f6c075476..ea9e5a2b98 100644 --- a/.github/ISSUE_TEMPLATE/rfc.yml +++ b/.github/ISSUE_TEMPLATE/rfc.yml @@ -83,7 +83,7 @@ body: options: - label: This feature request meets [Lambda Powertools Tenets](https://awslabs.github.io/aws-lambda-powertools-typescript/latest/#tenets) required: true - - label: Should this be considered in other Lambda Powertools languages? i.e. [Python](https://github.com/awslabs/aws-lambda-powertools-python/), [Java](https://github.com/awslabs/aws-lambda-powertools-java/) + - label: Should this be considered in other Lambda Powertools languages? i.e. [Python](https://github.com/awslabs/aws-lambda-powertools-python/), [Java](https://github.com/awslabs/aws-lambda-powertools-java/), and [.NET](https://github.com/awslabs/aws-lambda-powertools-dotnet/) required: false - type: markdown attributes: @@ -96,4 +96,10 @@ body: * RFC PR: * Approved by: '' - * Reviewed by: '' \ No newline at end of file + * Reviewed by: '' + - type: input + id: notes + attributes: + label: Future readers + description: Please not edit this field + value: "Please react with πŸ‘ and your use case to help us understand customer demand." \ No newline at end of file diff --git a/.github/PULL_REQUEST_TEMPLATE.md b/.github/PULL_REQUEST_TEMPLATE.md index 02304c842c..a199f2ea66 100644 --- a/.github/PULL_REQUEST_TEMPLATE.md +++ b/.github/PULL_REQUEST_TEMPLATE.md @@ -25,11 +25,6 @@ **Issue number:** -### PR status - -***Is this ready for review?:*** NO -***Is it a breaking change?:*** NO - ## Checklist - [ ] [My changes meet the tenets criteria](https://awslabs.github.io/aws-lambda-powertools-typescript/#tenets) @@ -46,9 +41,13 @@ ### Breaking change checklist +***Is it a breaking change?:*** NO + - [ ] I have documented the migration process - [ ] I have added, implemented necessary warnings (if it can live side by side) --- By submitting this pull request, I confirm that you can use, modify, copy, and redistribute this contribution, under the terms of your choice. + +**Disclaimer**: We value your time and bandwidth. As such, any pull requests created on non-triaged issues might not be successful. \ No newline at end of file diff --git a/.github/scripts/setup_tmp_layer_files.sh b/.github/scripts/setup_tmp_layer_files.sh new file mode 100644 index 0000000000..77c5875734 --- /dev/null +++ b/.github/scripts/setup_tmp_layer_files.sh @@ -0,0 +1,13 @@ +#!/usr/bin/env bash +rm -rf tmp/nodejs +mkdir -p tmp/nodejs +cd tmp/nodejs +npm init -y +npm i \ + @aws-lambda-powertools/logger@$VERSION \ + @aws-lambda-powertools/metrics@$VERSION \ + @aws-lambda-powertools/tracer@$VERSION +rm -rf node_modules/@types \ + package.json \ + package-lock.json +cd ../.. \ No newline at end of file diff --git a/.github/scripts/update_layer_arn.sh b/.github/scripts/update_layer_arn.sh new file mode 100755 index 0000000000..51a7149880 --- /dev/null +++ b/.github/scripts/update_layer_arn.sh @@ -0,0 +1,72 @@ +#!/bin/bash + +# This script is run during the reusable_update_v2_layer_arn_docs CI job, +# and it is responsible for replacing the layer ARN in our documentation, +# based on the output files generated by CDK when deploying to each pseudo_region. +# +# see .github/workflows/reusable_deploy_v2_layer_stack.yml + +set -eo pipefail + +if [[ $# -ne 1 ]]; then + cat < line + # sed doesn't support \d+ in a portable way, so we cheat with (:digit: :digit: *) + sed -i -e "s/$prefix:[[:digit:]][[:digit:]]*/$line/g" docs/index.md + + # We use the eu-central-1 layer as the version for all the frameworks (SAM, CDK, SLS, etc) + # We could have used any other region. What's important is the version at the end. + + # Examples of strings found in the documentation with pseudo regions: + # arn:aws:lambda:{region}:094274105915:layer:AWSLambdaPowertoolsTypeScript:39 + # arn:aws:lambda:${AWS::Region}:094274105915:layer:AWSLambdaPowertoolsTypeScript:39 + # arn:aws:lambda:${aws:region}:094274105915:layer:AWSLambdaPowertoolsTypeScript:39 + # arn:aws:lambda:{env.region}:094274105915:layer:AWSLambdaPowertoolsTypeScript:39 + if [[ "$line" == *"eu-central-1"* ]]; then + # These are all the framework pseudo parameters currently found in the docs + for pseudo_region in '{region}' '${AWS::Region}' '${aws::region}' '{aws::region}' '{env.region}' '${cdk.Stack.of(this).region}' '${aws.getRegionOutput().name}'; do + prefix_pseudo_region=$(echo "$prefix" | sed "s/eu-central-1/${pseudo_region}/") + # prefix_pseudo_region = arn:aws:lambda:${AWS::Region}:094274105915:layer:AWSLambdaPowertoolsTypeScript + + line_pseudo_region=$(echo "$line" | sed "s/eu-central-1/${pseudo_region}/") + # line_pseudo_region = arn:aws:lambda:${AWS::Region}:094274105915:layer:AWSLambdaPowertoolsTypeScript:49 + + # Replace all the "prefix_pseudo_region"'s in the file + # prefix_pseudo_region:\d+ ==> line_pseudo_region + sed -i -e "s/$prefix_pseudo_region:[[:digit:]][[:digit:]]*/$line_pseudo_region/g" docs/index.md + done + fi + done +done diff --git a/.github/stale.yml b/.github/stale.yml deleted file mode 100644 index d6bdd4c29c..0000000000 --- a/.github/stale.yml +++ /dev/null @@ -1,16 +0,0 @@ -only: issues -daysUntilStale: 30 -daysUntilClose: 7 -exemptLabels: - - type/bug - - type/bug-upstream - - type/feature-request - - type/RFC -staleLabel: pending-close-response-required -markComment: > - This issue has been automatically marked as stale because it has not had - recent activity. It will be closed if no further activity occurs. Thank you - for your contributions. -closeComment: > - This issue has been automatically closed because of inactivity. - Please open a new issue if you are still encountering problems. diff --git a/.github/workflows/make-release.yml b/.github/workflows/make-release.yml index 838081df3c..c5b5a78ee9 100644 --- a/.github/workflows/make-release.yml +++ b/.github/workflows/make-release.yml @@ -9,6 +9,8 @@ jobs: publish-npm: needs: run-unit-tests runs-on: ubuntu-latest + outputs: + RELEASE_VERSION: ${{ steps.set-release-version.outputs.RELEASE_VERSION }} steps: - name: Checkout code uses: actions/checkout@v3 @@ -28,7 +30,7 @@ jobs: npm set "//registry.npmjs.org/:_authToken=${{ secrets.NPM_TOKEN }}" - name: Cache node modules id: cache-node-modules - uses: actions/cache@v3 + uses: actions/cache@69d9d449aced6a2ede0bc19182fadc3a0a42d2b0 # v3.2.6 with: path: "./node_modules" # Use the combo between node version, name, and SHA-256 hash of the lock file as cache key so that @@ -47,3 +49,21 @@ jobs: git remote set-url origin https://x-access-token:${GH_TOKEN}@github.com/$GITHUB_REPOSITORY npx lerna version --conventional-commits --force-publish --yes npx lerna publish from-git --no-verify-access --yes + - name: Set release version + id: set-release-version + run: | + RELEASE=$(npm view @aws-lambda-powertools/tracer version) + echo RELEASE_VERSION="$RELEASE_VERSION" >> "$GITHUB_OUTPUT" + + # NOTE: Watch out for the depth limit of 4 nested workflow_calls. + # publish_layer -> reusable_deploy_layer_stack -> reusable_update_layer_arn_docs + publish_layer: + needs: publish-npm + secrets: inherit + permissions: + id-token: write + contents: write + pages: write + uses: ./.github/workflows/publish_layer.yml + with: + latest_published_version: ${{ needs.publish-npm.outputs.RELEASE_VERSION }} diff --git a/.github/workflows/measure-packages-size.yml b/.github/workflows/measure-packages-size.yml index 830cdd867e..e8b15b3480 100644 --- a/.github/workflows/measure-packages-size.yml +++ b/.github/workflows/measure-packages-size.yml @@ -31,9 +31,9 @@ jobs: with: ref: ${{ steps.extract_PR_details.outputs.headSHA }} - name: Packages size report - uses: flochaz/pkg-size-action@v2.0.0 + uses: flochaz/pkg-size-action@e41584e9396375027c8a3c68909e3eca55719e47 # v.2.0.0 with: - build-command: mkdir dist && npm run package -w packages/logger -w packages/tracer -w packages/metrics -w packages/commons && npm run package-bundle -w packages/logger -w packages/tracer -w packages/metrics -w packages/commons && bash -c "mv ./packages/*/dist/* dist/" && ls dist + build-command: mkdir dist && npm run package -w packages/logger -w packages/tracer -w packages/metrics -w packages/commons -w packages/parameters && npm run package-bundle -w packages/logger -w packages/tracer -w packages/metrics -w packages/commons -w packages/parameters && bash -c "mv ./packages/*/dist/* dist/" && ls dist dist-directory: /dist pr-number: ${{ inputs.prNumber }} env: diff --git a/.github/workflows/on-merge-to-main.yml b/.github/workflows/on-merge-to-main.yml index 411cd14ee8..71567ad1cb 100644 --- a/.github/workflows/on-merge-to-main.yml +++ b/.github/workflows/on-merge-to-main.yml @@ -21,23 +21,14 @@ jobs: needs: get_pr_details if: ${{ needs.get_pr_details.outputs.prIsMerged == 'true' }} uses: ./.github/workflows/reusable-run-linting-check-and-unit-tests.yml - publish: - needs: - [get_pr_details, run-unit-tests] - uses: ./.github/workflows/reusable-publish-docs.yml - with: - workflow_origin: ${{ github.event.repository.full_name }} - prIsMerged: ${{ needs.get_pr_details.outputs.prIsMerged }} - secrets: - token: ${{ secrets.GITHUB_TOKEN }} update-release-draft: - needs: publish + needs: run-unit-tests runs-on: ubuntu-latest steps: - name: Checkout code uses: actions/checkout@v3 - name: Update release draft - uses: release-drafter/release-drafter@v5.20.0 + uses: release-drafter/release-drafter@569eb7ee3a85817ab916c8f8ff03a5bd96c9c83e # v5.23.0 env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} release_label_on_merge: diff --git a/.github/workflows/on-workflows-push-pr.yml b/.github/workflows/on-workflows-push-pr.yml new file mode 100644 index 0000000000..5b272f9357 --- /dev/null +++ b/.github/workflows/on-workflows-push-pr.yml @@ -0,0 +1,33 @@ +name: Lockdown untrusted workflows + +on: + push: + paths: + - ".github/workflows/**" + pull_request: + paths: + - ".github/workflows/**" + +jobs: + enforce_pinned_workflows: + name: Harden Security + runs-on: ubuntu-latest + steps: + - name: Checkout code + uses: actions/checkout@v3 + - name: Ensure 3rd party workflows have SHA pinned + uses: zgosalvez/github-actions-ensure-sha-pinned-actions@b9ddf6a5153efe6fb94f071c8915175afdce60fa # v2.1.0 + with: + # Trusted GitHub Actions and/or organizations + allowlist: | + aws-actions/ + actions/stale + actions/checkout + actions/github-script + actions/setup-node + actions/setup-python + actions/upload-artifact + actions/download-artifact + github/codeql-action/init + github/codeql-action/analyze + dependabot/fetch-metadata \ No newline at end of file diff --git a/.github/workflows/on_doc_merge.yml b/.github/workflows/on_doc_merge.yml new file mode 100644 index 0000000000..ff1e5ec487 --- /dev/null +++ b/.github/workflows/on_doc_merge.yml @@ -0,0 +1,22 @@ +name: Docs + +on: + push: + branches: + - main + paths: + - "docs/**" + - "mkdocs.yml" + +jobs: + release-docs: + permissions: + contents: write + pages: write + uses: ./.github/workflows/reusable-publish-docs.yml + with: + workflow_origin: ${{ github.event.repository.full_name }} + version: dev + alias: stage + secrets: + token: ${{ secrets.GITHUB_TOKEN }} \ No newline at end of file diff --git a/.github/workflows/publish-docs-on-release.yml b/.github/workflows/publish-docs-on-release.yml deleted file mode 100644 index 7d5a4fdcc3..0000000000 --- a/.github/workflows/publish-docs-on-release.yml +++ /dev/null @@ -1,23 +0,0 @@ -name: Publish docs on release - -on: - # Triggered manually - workflow_dispatch: - inputs: - versionNumber: - required: true - type: string - description: "If running this manually please insert a version number that corresponds to the latest published in the GitHub releases (i.e. v1.1.1)" - # Or triggered as result of a release - release: - types: [released] - -jobs: - publish-docs: - uses: ./.github/workflows/reusable-publish-docs.yml - with: - workflow_origin: ${{ github.event.repository.full_name }} - isRelease: "true" - versionNumber: ${{ inputs.versionNumber }} - secrets: - token: ${{ secrets.GITHUB_TOKEN }} diff --git a/.github/workflows/publish_layer.yaml b/.github/workflows/publish_layer.yaml deleted file mode 100644 index 5f5baf9a45..0000000000 --- a/.github/workflows/publish_layer.yaml +++ /dev/null @@ -1,81 +0,0 @@ -name: Deploy layer to all regions - -permissions: - id-token: write - contents: read - -on: - # Manual trigger - workflow_dispatch: - inputs: - latest_published_version: - description: "Latest npm published version to rebuild corresponding layer for, e.g. v1.0.2" - default: "v1.0.2" - required: true - # Automatic trigger after release - workflow_run: - workflows: ["Make Release"] - types: - - completed - -jobs: - # Build layer by running cdk synth in layer-publisher directory and uploading cdk.out for deployment - build-layer: - runs-on: ubuntu-latest - if: ${{ (github.event.workflow_run.conclusion == 'success') || (github.event_name == 'workflow_dispatch') }} - defaults: - run: - working-directory: ./layer-publisher - steps: - - name: checkout - uses: actions/checkout@v3 - with: - fetch-depth: 0 - - name: Setup Node.js - uses: actions/setup-node@v3 - with: - node-version: "18" - - name: Set release notes tag - run: | - RELEASE_INPUT=${{ inputs.latest_published_version }} - LATEST_TAG=$(git describe --tag --abbrev=0) - RELEASE_TAG_VERSION=${RELEASE_INPUT:-$LATEST_TAG} - echo "RELEASE_TAG_VERSION=${RELEASE_TAG_VERSION:1}" >> $GITHUB_ENV - - name: install cdk and deps - run: | - npm install -g aws-cdk@2.29.0 - cdk --version - - name: install deps - run: | - npm ci - - name: CDK build - run: cdk synth --context PowerToolsPackageVersion=$RELEASE_TAG_VERSION -o cdk.out - - name: zip output - run: zip -r cdk.out.zip cdk.out - - name: Archive CDK artifacts - uses: actions/upload-artifact@v3 - with: - name: cdk-layer-artefact - path: layer-publisher/cdk.out.zip - - # Deploy layer to all regions in beta account - deploy-beta: - needs: - - build-layer - uses: ./.github/workflows/reusable_deploy_layer_stack.yml - with: - stage: "BETA" - artefact-name: "cdk-layer-artefact" - secrets: - target-account-role: ${{ secrets.AWS_LAYERS_BETA_ROLE_ARN }} - - # Deploy layer to all regions in prod account - deploy-prod: - needs: - - deploy-beta - uses: ./.github/workflows/reusable_deploy_layer_stack.yml - with: - stage: "PROD" - artefact-name: "cdk-layer-artefact" - secrets: - target-account-role: ${{ secrets.AWS_LAYERS_PROD_ROLE_ARN }} \ No newline at end of file diff --git a/.github/workflows/publish_layer.yml b/.github/workflows/publish_layer.yml new file mode 100644 index 0000000000..0ba75b0b63 --- /dev/null +++ b/.github/workflows/publish_layer.yml @@ -0,0 +1,122 @@ +name: Deploy layer to all regions + +permissions: + id-token: write + contents: write + pages: write + +on: + # Manual trigger + workflow_dispatch: + inputs: + latest_published_version: + description: "Latest npm published version to rebuild corresponding layer for, e.g. v1.0.2" + default: "v1.0.2" + required: true + + workflow_call: + inputs: + latest_published_version: + type: string + description: "Latest npm published version to rebuild latest docs for, e.g. 2.0.0, 2.0.0a1 (pre-release)" + required: true + pre_release: + description: "Publishes documentation using a pre-release tag (2.0.0a1)." + default: false + type: boolean + required: false + +jobs: + # Build layer by running cdk synth in layer-publisher directory and uploading cdk.out for deployment + build-layer: + runs-on: ubuntu-latest + if: ${{ (github.event.workflow_run.conclusion == 'success') || (github.event_name == 'workflow_dispatch') }} + steps: + - name: checkout + uses: actions/checkout@v3 + with: + fetch-depth: 0 + - name: Setup Node.js + uses: actions/setup-node@v3 + with: + node-version: "18" + - name: Set release notes tag + run: | + RELEASE_INPUT=${{ inputs.latest_published_version }} + LATEST_TAG=$(git describe --tag --abbrev=0) + RELEASE_TAG_VERSION=${RELEASE_INPUT:-$LATEST_TAG} + echo "RELEASE_TAG_VERSION=${RELEASE_TAG_VERSION:1}" >> $GITHUB_ENV + - name: Cache node modules + id: cache-node-modules + uses: actions/cache@69d9d449aced6a2ede0bc19182fadc3a0a42d2b0 # v3.2.6 + with: + path: "./node_modules" + # Use the combo between node version, name, and SHA-256 hash of the lock file as cache key so that + # if one of them changes the cache is invalidated/discarded + key: 18-cache-utilities-node-modules-${{ hashFiles('./package-lock.json') }} + - name: Install dependencies + # We can skip the installation if there was a cache hit + if: steps.cache-node-modules.outputs.cache-hit != 'true' + # See https://github.com/npm/cli/issues/4475 to see why --foreground-scripts + run: npm ci --foreground-scripts + - name: Create layer files + run: | + export VERSION=$RELEASE_TAG_VERSION + bash .github/scripts/setup_tmp_layer_files.sh + - name: CDK build + run: npm run cdk -w layers -- synth --context PowertoolsPackageVersion=$RELEASE_TAG_VERSION -o cdk.out + - name: zip output + run: zip -r cdk.out.zip cdk.out + - name: Archive CDK artifacts + uses: actions/upload-artifact@v3 + with: + name: cdk-layer-artifact + path: layers/cdk.out.zip + + # Deploy layer to all regions in beta account + deploy-beta: + needs: + - build-layer + uses: ./.github/workflows/reusable_deploy_layer_stack.yml + with: + stage: "BETA" + artifact-name: "cdk-layer-artifact" + latest_published_version: ${{ inputs.latest_published_version }} + secrets: + target-account-role: ${{ secrets.AWS_LAYERS_BETA_ROLE_ARN }} + + # Deploy layer to all regions in prod account + deploy-prod: + needs: + - deploy-beta + uses: ./.github/workflows/reusable_deploy_layer_stack.yml + with: + stage: "PROD" + artifact-name: "cdk-layer-artifact" + latest_published_version: ${{ inputs.latest_published_version }} + secrets: + target-account-role: ${{ secrets.AWS_LAYERS_PROD_ROLE_ARN }} + + prepare_docs_alias: + runs-on: ubuntu-latest + permissions: + contents: read + outputs: + DOCS_ALIAS: ${{ steps.set-alias.outputs.DOCS_ALIAS }} + steps: + - name: Set docs alias + id: set-alias + run: | + DOCS_ALIAS=latest + if [[ "${{ inputs.pre_release }}" == true ]] ; then + DOCS_ALIAS=alpha + fi + echo DOCS_ALIAS="$DOCS_ALIAS" >> "$GITHUB_OUTPUT" + + release-docs: + needs: [ deploy-prod, prepare_docs_alias ] + uses: ./.github/workflows/reusable-publish-docs.yml + with: + version: ${{ inputs.latest_published_version }} + alias: ${{ needs.prepare_docs_alias.outputs.DOCS_ALIAS }} + detached_mode: true diff --git a/.github/workflows/reusable-publish-docs.yml b/.github/workflows/reusable-publish-docs.yml index b2d3aed5da..9a7f114ebb 100644 --- a/.github/workflows/reusable-publish-docs.yml +++ b/.github/workflows/reusable-publish-docs.yml @@ -1,38 +1,33 @@ name: Reusable Publish docs +env: + BRANCH: main + ORIGIN: awslabs/aws-lambda-powertools-typescript + on: workflow_call: inputs: - workflow_origin: # see https://github.com/awslabs/aws-lambda-powertools-python/issues/1349 + version: + description: "Version to build and publish docs (1.28.0, develop)" required: true type: string - prIsMerged: - required: false - default: "false" - type: string - isRelease: - required: false - default: "false" + alias: + description: "Alias to associate version (latest, stage)" + required: true type: string - versionNumber: + detached_mode: + description: "Whether it's running in git detached mode to ensure git is sync'd" required: false - default: "" - type: string - secrets: - token: - required: true + default: false + type: boolean jobs: publish-docs: - # see https://github.com/awslabs/aws-lambda-powertools-python/issues/1349 - if: ${{ inputs.workflow_origin == 'awslabs/aws-lambda-powertools-typescript' }} runs-on: ubuntu-latest steps: - name: Checkout code uses: actions/checkout@v3 with: - # Here `token` is needed to avoid incurring in error GH006 Protected Branch Update Failed, - token: ${{ secrets.token }} # While `fetch-depth` is used to allow the workflow to later commit & push the changes. fetch-depth: 0 - name: Setup NodeJS @@ -44,7 +39,7 @@ jobs: # if one of them changes the cache is invalidated/discarded - name: Cache node modules id: cache-node-modules - uses: actions/cache@v3 + uses: actions/cache@69d9d449aced6a2ede0bc19182fadc3a0a42d2b0 # v3.2.6 with: path: "./node_modules" key: 18-cache-utils-node-modules-${{ hashFiles('./package-lock.json') }} @@ -65,32 +60,6 @@ jobs: uses: actions/setup-python@v4 with: python-version: "3.8" - # We run this step only when the workflow has been triggered by a release - # in this case we publish the docs to `/latest` - - name: (Conditional) Set RELEASE_VERSION env var to `latest` - if: ${{ inputs.isRelease == 'true' }} - run: | - RELEASE_VERSION=$(echo ${{ github.ref_name }} | sed 's/v//') - EXPLICIT_RELEASE_VERSION=$(echo ${{ inputs.versionNumber }} | sed 's/v//') - if [ $EXPLICIT_RELEASE_VERSION != "" ]; then - echo "RELEASE_VERSION=${EXPLICIT_RELEASE_VERSION}" - echo "RELEASE_VERSION=${EXPLICIT_RELEASE_VERSION}" >> $GITHUB_ENV - else - echo "RELEASE_VERSION=${RELEASE_VERSION}" - echo "RELEASE_VERSION=${RELEASE_VERSION}" >> $GITHUB_ENV - fi - # We run this step only when the workflow has been triggered by a PR merge - # in this case we publish the docs to `/dev` - - name: (Conditional) Set RELEASE_VERSION env var to `dev` - if: ${{ inputs.prIsMerged == 'true' }} - run: | - echo "RELEASE_VERSION=dev" >> $GITHUB_ENV - - name: Check RELEASE_VERSION env var - if: ${{ env.RELEASE_VERSION == '' }} - uses: actions/github-script@v3 - with: - script: | - core.setFailed('RELEASE_VERSION env var is empty.') - name: Install doc generation dependencies run: | pip install --upgrade pip @@ -98,35 +67,41 @@ jobs: - name: Setup doc deploy run: | git config --global user.name Docs deploy - git config --global user.email docs@dummy.bot.com - - name: Publish docs to latest if isRelease - if: ${{ env.RELEASE_VERSION != 'dev' }} + git config --global user.email aws-devax-open-source@amazon.com + - name: Git refresh tip (detached mode) + # Git Detached mode (release notes) doesn't have origin + if: ${{ inputs.detached_mode }} + run: | + git config pull.rebase true + git config remote.origin.url >&- || git remote add origin https://github.com/"$ORIGIN" + git pull origin "$BRANCH" + - name: Build docs website and API reference + run: | + make release-docs VERSION="$VERSION" ALIAS="$ALIAS" + poetry run mike set-default --push latest + - name: Build docs website and API reference + env: + VERSION: ${{ inputs.version }} + ALIAS: ${{ inputs.alias }} run: | rm -rf site mkdocs build - mike deploy --push --update-aliases --no-redirect "${{ env.RELEASE_VERSION }}" "latest" + mike deploy --push --update-aliases --no-redirect ${{ env.VERSION }} ${{ env.ALIAS }}" # Set latest version as a default mike set-default --push latest - - name: Publish docs to dev - if: ${{ env.RELEASE_VERSION == 'dev' }} - run: | - rm -rf site - mkdocs build - mike deploy --push dev - - name: Build API docs - run: | - rm -rf api - npm run docs-generateApiDoc + - name: Release API docs - uses: peaceiris/actions-gh-pages@v3 + uses: peaceiris/actions-gh-pages@bd8c6b06eba6b3d25d72b7a1767993c0aeee42e7 # v3.9.2 + env: + VERSION: ${{ inputs.version }} with: github_token: ${{ secrets.GITHUB_TOKEN }} publish_dir: ./api keep_files: true - destination_dir: ${{ env.RELEASE_VERSION }}/api - - name: Release API docs to latest if isRelease - if: ${{ env.RELEASE_VERSION != 'dev' }} - uses: peaceiris/actions-gh-pages@v3 + destination_dir: ${{ env.VERSION }}/api + - name: Release API docs to latest + if: ${{ inputs.alias == 'latest' }} + uses: peaceiris/actions-gh-pages@bd8c6b06eba6b3d25d72b7a1767993c0aeee42e7 with: github_token: ${{ secrets.GITHUB_TOKEN }} publish_dir: ./api diff --git a/.github/workflows/reusable-run-linting-check-and-unit-tests.yml b/.github/workflows/reusable-run-linting-check-and-unit-tests.yml index 1ce91c800c..1d54928957 100644 --- a/.github/workflows/reusable-run-linting-check-and-unit-tests.yml +++ b/.github/workflows/reusable-run-linting-check-and-unit-tests.yml @@ -24,7 +24,7 @@ jobs: run: npm i -g npm@next-8 - name: Cache node modules id: cache-node-modules - uses: actions/cache@v3 + uses: actions/cache@69d9d449aced6a2ede0bc19182fadc3a0a42d2b0 # v3.2.6 with: path: "./node_modules" # Use the combo between node version, name, and SHA-256 hash of the lock file as cache key so that @@ -64,11 +64,11 @@ jobs: - name: Setup NodeJS uses: actions/setup-node@v3 with: - node-version: 16 + node-version: 18 cache: "npm" - name: Cache node modules id: cache-node-modules - uses: actions/cache@v3 + uses: actions/cache@69d9d449aced6a2ede0bc19182fadc3a0a42d2b0 # v3.2.6 with: path: "./examples/${{ matrix.example }}/node_modules" # Use the combo between example, name, and SHA-256 hash of all example lock files as cache key. @@ -88,29 +88,69 @@ jobs: runs-on: ubuntu-latest env: NODE_ENV: dev - defaults: - run: - working-directory: layer-publisher steps: - name: Checkout code uses: actions/checkout@v3 - name: Setup NodeJS uses: actions/setup-node@v3 with: - node-version: 16 + node-version: 18 cache: "npm" - name: Cache node modules id: cache-node-modules - uses: actions/cache@v3 + uses: actions/cache@69d9d449aced6a2ede0bc19182fadc3a0a42d2b0 # v3.2.6 with: - path: "./layer-publisher/node_modules" - # Use the combo between example, name, and SHA-256 hash of the layer-publisher lock files as cache key. - key: cache-layer-publisher-node-modules-${{ hashFiles('./layer-publisher/package-lock.json') }} - - name: Install Layer publisher + path: "./node_modules" + # Use the combo between node version, name, and SHA-256 hash of the lock file as cache key so that + # if one of them changes the cache is invalidated/discarded + key: 18-cache-utilities-node-modules-${{ hashFiles('./package-lock.json') }} + - name: Install dependencies # We can skip the installation if there was a cache hit if: steps.cache-node-modules.outputs.cache-hit != 'true' - run: npm ci + # See https://github.com/npm/cli/issues/4475 to see why --foreground-scripts + run: npm ci --foreground-scripts - name: Run linting - run: npm run lint + run: npm run lint -w layers + - name: Create layer files + run: | + export VERSION=latest + bash .github/scripts/setup_tmp_layer_files.sh - name: Run tests - run: npm t + run: npm run test:unit -w layers + check-docs-snippets: + runs-on: ubuntu-latest + env: + NODE_ENV: dev + steps: + - name: Checkout code + uses: actions/checkout@v3 + - name: Setup NodeJS + uses: actions/setup-node@v3 + with: + node-version: 18 + cache: "npm" + - name: Setup npm + run: npm i -g npm@next-8 + - name: Cache node modules + id: cache-node-modules + uses: actions/cache@69d9d449aced6a2ede0bc19182fadc3a0a42d2b0 # v3.2.6 + with: + path: "./node_modules" + # Use the combo between node version, name, and SHA-256 hash of the lock file as cache key so that + # if one of them changes the cache is invalidated/discarded + key: 18-cache-utilities-node-modules-${{ hashFiles('./package-lock.json') }} + - name: Install dependencies + # We can skip the installation if there was a cache hit + if: steps.cache-node-modules.outputs.cache-hit != 'true' + # See https://github.com/npm/cli/issues/4475 to see why --foreground-scripts + run: npm ci --foreground-scripts + - name: Build packages + # If there's a cache hit we still need to manually build the packages + # this would otherwise have been done automatically as a part of the + # post-install npm hook + if: steps.cache-node-modules.outputs.cache-hit == 'true' + run: | + npm run build -w packages/commons + npm run build -w packages/logger & npm run build -w packages/tracer & npm run build -w packages/metrics & npm run build -w packages/parameters & npm run build -w packages/idempotency & npm run build -w docs/snippets + - name: Run linting + run: npm run lint -w docs/snippets diff --git a/.github/workflows/reusable_deploy_layer_stack.yml b/.github/workflows/reusable_deploy_layer_stack.yml index 3de0d8aba2..8222e7811e 100644 --- a/.github/workflows/reusable_deploy_layer_stack.yml +++ b/.github/workflows/reusable_deploy_layer_stack.yml @@ -8,21 +8,25 @@ on: workflow_call: inputs: stage: + description: "Deployment stage (BETA, PROD)" required: true type: string - artefact-name: + artifact-name: + description: "CDK Layer artifact name to download" + required: true + type: string + latest_published_version: + description: "Latest version that is published" required: true type: string secrets: target-account-role: required: true + jobs: deploy-cdk-stack: runs-on: ubuntu-latest - defaults: - run: - working-directory: ./layer-publisher strategy: fail-fast: false matrix: @@ -30,6 +34,7 @@ jobs: [ "af-south-1", "eu-central-1", + "eu-central-2", "us-east-1", "us-east-2", "us-west-1", @@ -38,24 +43,26 @@ jobs: "ap-south-1", "ap-northeast-1", "ap-northeast-2", + "ap-northeast-3", "ap-southeast-1", "ap-southeast-2", + "ap-southeast-3", + "ap-southeast-4", "ca-central-1", "eu-west-1", "eu-west-2", "eu-west-3", "eu-south-1", + "eu-south-2", "eu-north-1", "sa-east-1", - "ap-southeast-3", - "ap-northeast-3", "me-south-1", ] steps: - name: checkout uses: actions/checkout@v3 - name: aws credentials - uses: aws-actions/configure-aws-credentials@v1 + uses: aws-actions/configure-aws-credentials@186395a8644e48f35e7b453e8a7128d9a3948296 with: aws-region: ${{ matrix.region }} role-to-assume: ${{ secrets.target-account-role }} @@ -63,19 +70,47 @@ jobs: uses: actions/setup-node@v3 with: node-version: "18" - - name: install cdk and deps - run: | - npm install -g aws-cdk@2.29.0 - cdk --version - - name: install deps - run: | - npm ci + - name: Cache node modules + id: cache-node-modules + uses: actions/cache@69d9d449aced6a2ede0bc19182fadc3a0a42d2b0 # v3.2.6 + with: + path: "./node_modules" + # Use the combo between node version, name, and SHA-256 hash of the lock file as cache key so that + # if one of them changes the cache is invalidated/discarded + key: 18-cache-utilities-node-modules-${{ hashFiles('./package-lock.json') }} + - name: Install dependencies + # We can skip the installation if there was a cache hit + if: steps.cache-node-modules.outputs.cache-hit != 'true' + # See https://github.com/npm/cli/issues/4475 to see why --foreground-scripts + run: npm ci --foreground-scripts - name: Download artifact uses: actions/download-artifact@v3 with: - name: ${{ inputs.artefact-name }} - path: layer-publisher - - name: unzip artefact + name: ${{ inputs.artifact-name }} + path: layers + - name: Unzip artifact run: unzip cdk.out.zip - - name: CDK Deploy Layer - run: cdk deploy --app cdk.out --context region=${{ matrix.region }} 'LayerPublisherStack' --require-approval never --verbose + - name: Deploy Layer + run: npm run cdk -w layers -- deploy --app cdk.out --context region=${{ matrix.region }} 'LayerPublisherStack' --require-approval never --verbose --outputs-file cdk-outputs.json + - name: Store latest Layer ARN + if: ${{ inputs.stage == 'PROD' }} + run: | + mkdir cdk-layer-stack + jq -r -c '.LayerPublisherStack.LatestLayerArn' cdk-outputs.json > cdk-layer-stack/${{ matrix.region }}-layer-version.txt + cat cdk-layer-stack/${{ matrix.region }}-layer-version.txt + - name: Save Layer ARN artifact + if: ${{ inputs.stage == 'PROD' }} + uses: actions/upload-artifact@v3 + with: + name: cdk-layer-stack + path: ./layer/cdk-layer-stack/* # NOTE: upload-artifact does not inherit working-directory setting. + if-no-files-found: error + retention-days: 1 + update_layer_arn_docs: + needs: deploy-cdk-stack + permissions: + contents: write + if: ${{ inputs.stage == 'PROD' }} + uses: ./.github/workflows/reusable_update_layer_arn_docs.yml + with: + latest_published_version: ${{ inputs.latest_published_version }} \ No newline at end of file diff --git a/.github/workflows/reusable_update_layer_arn_docs.yml b/.github/workflows/reusable_update_layer_arn_docs.yml new file mode 100644 index 0000000000..db63440d43 --- /dev/null +++ b/.github/workflows/reusable_update_layer_arn_docs.yml @@ -0,0 +1,52 @@ +name: Update V2 Layer ARN Docs + +on: + workflow_call: + inputs: + latest_published_version: + description: "Latest NPM published version to rebuild latest docs for, e.g. 1.5.1" + type: string + required: true + +permissions: + contents: write + +env: + BRANCH: main + +jobs: + publish_layer_arn: + # Force Github action to run only a single job at a time (based on the group name) + # This is to prevent race-condition and inconsistencies with changelog push + concurrency: + group: changelog-build + runs-on: ubuntu-latest + steps: + - name: Checkout repository # reusable workflows start clean, so we need to checkout again + uses: actions/checkout@v3 + with: + fetch-depth: 0 + - name: Git client setup and refresh tip + run: | + git config user.name "Release bot" + git config user.email "aws-devax-open-source@amazon.com" + git config pull.rebase true + git config remote.origin.url >&- || git remote add origin https://github.com/"${origin}" # Git Detached mode (release notes) doesn't have origin + git pull origin "${BRANCH}" + - name: Download CDK layer artifact + uses: actions/download-artifact@v3 + with: + name: cdk-layer-stack + path: cdk-layer-stack/ + - name: Replace layer versions in documentation + run: | + ls -la cdk-layer-stack/ + ./.github/scripts/update_layer_arn.sh cdk-layer-stack + - name: Update documentation in trunk + run: | + HAS_CHANGE=$(git status --porcelain) + test -z "${HAS_CHANGE}" && echo "Nothing to update" && exit 0 + git add docs/index.md + git commit -m "chore: update layer ARN on documentation" + git pull origin "${BRANCH}" # prevents concurrent branch update failing push + git push origin HEAD:refs/heads/"${BRANCH}" diff --git a/.github/workflows/run-e2e-tests.yml b/.github/workflows/run-e2e-tests.yml index 617ccc4a06..dffe8073c7 100644 --- a/.github/workflows/run-e2e-tests.yml +++ b/.github/workflows/run-e2e-tests.yml @@ -19,7 +19,7 @@ jobs: contents: read strategy: matrix: - package: [logger, metrics, tracer] + package: [logger, metrics, tracer, parameters] version: [14, 16, 18] fail-fast: false steps: @@ -52,7 +52,7 @@ jobs: # See https://github.com/npm/cli/issues/4475 to see why --foreground-scripts run: npm ci --foreground-scripts - name: Setup AWS credentials - uses: aws-actions/configure-aws-credentials@v1.6.1 + uses: aws-actions/configure-aws-credentials@186395a8644e48f35e7b453e8a7128d9a3948296 with: role-to-assume: ${{ secrets.AWS_ROLE_ARN_TO_ASSUME }} aws-region: eu-west-1 @@ -98,13 +98,13 @@ jobs: - name: Setup npm run: npm i -g npm@next-8 - name: "Configure AWS credentials" - uses: aws-actions/configure-aws-credentials@v1.6.1 + uses: aws-actions/configure-aws-credentials@186395a8644e48f35e7b453e8a7128d9a3948296 with: role-to-assume: ${{ secrets.AWS_ROLE_ARN_TO_ASSUME }} aws-region: eu-west-1 - name: Cache node modules for commons id: cache-node-modules - uses: actions/cache@v3 + uses: actions/cache@69d9d449aced6a2ede0bc19182fadc3a0a42d2b0 # v3.2.6 with: path: "./node_modules" # Use the combo between node version, name, and SHA-256 hash of the lock file as cache key so that @@ -122,8 +122,9 @@ jobs: if: steps.cache-node-modules.outputs.cache-hit == 'true' run: | npm run build -w packages/commons - - name: Run integration test on layers + - name: Create layer files run: | - npm ci --foreground-scripts - RUNTIME=nodejs${{ matrix.version }}.x npm run test:e2e - working-directory: layer-publisher + export VERSION=latest + bash .github/scripts/setup_tmp_layer_files.sh + - name: Run integration test on layers + run: RUNTIME=nodejs${{ matrix.version }}.x npm run test:e2e -w layers diff --git a/.github/workflows/stale-issues.yml b/.github/workflows/stale-issues.yml index 15b5dff177..e080faba7f 100644 --- a/.github/workflows/stale-issues.yml +++ b/.github/workflows/stale-issues.yml @@ -1,46 +1,35 @@ name: "Close stale issues" -# Controls when the action will run. - on: schedule: - cron: "0 0 * * *" jobs: - cleanup: + check-issues: runs-on: ubuntu-latest - name: Stale issue job + permissions: + issues: write steps: - - uses: aws-actions/stale-issue-cleanup@e1cf8a5d54b4ff316c76f5356079d3a8df84137e + - uses: actions/stale@v7 with: - # Setting messages to an empty string will cause the automation to skip - # that category - ancient-issue-message: Greetings! We’re closing this issue because it has been open a long time and hasn’t been updated in a while and may not be getting the attention it deserves. We encourage you to check if this is still an issue in the latest release and if you find that this is still a problem, please feel free to comment or open a new issue. - stale-issue-message: This issue has not received a response in 2 weeks. If you still think there is a problem, please leave a comment to avoid the issue from automatically closing. - stale-pr-message: This PR has not received a response in 2 weeks. If you still think there is a problem, please leave a comment to avoid the PR from automatically closing. - # These labels are required - stale-issue-label: closing-soon - exempt-issue-label: no-autoclose - stale-pr-label: closing-soon - exempt-pr-label: pr/needs-review - response-requested-label: response-requested - - # Don't set closed-for-staleness label to skip closing very old issues - # regardless of label - closed-for-staleness-label: closed-for-staleness - - # Issue timing - days-before-stale: 14 - days-before-close: 7 - days-before-ancient: 365 - - # If you don't want to mark a issue as being ancient based on a - # threshold of "upvotes", you can set this here. An "upvote" is - # the total number of +1, heart, hooray, and rocket reactions - # on an issue. - minimum-upvotes-to-exempt: 5 - repo-token: ${{ secrets.GITHUB_TOKEN }} - loglevel: DEBUG - # Set dry-run to true to not perform label or close actions. - # dry-run: true + stale-issue-message: "This issue has not received a response in 2 weeks. If you still think there is a problem, please leave a comment to avoid the issue from automatically closing." + close-issue-message: "Greetings! We are closing this issue because it has been open a long time and hasn’t been updated in a while and may not be getting the attention it deserves. We encourage you to check if this is still an issue in the latest release and if you find that this is still a problem, please feel free to comment or reopen the issue." + # Label applied or removed when an issue becomes stale + stale-issue-label: status/pending-close-response-required + remove-stale-when-updated: true + # Label and close type when a stale issue is finally closed + close-issue-label: status/rejected + close-issue-reason: not_planned + # Exempt any issue that hasn't been triaged yet, or that is clearly labeled + exempt-issue-labels: triage,status/confirmed,status/blocked,status/on-hold,status/completed + # Include only issues that were labeled as `need-more-information` (aka only issues that need more info from the customer) + only-issue-labels: need-more-information + # Settings specific to issues + days-before-issue-stale: 14 + days-before-issue-close: 7 + # Set to ignore PRs + days-before-pr-stale: -1 + days-before-pr-close: -1 + # Operations + operations-per-run: 60 diff --git a/.gitignore b/.gitignore index ce7e2e2eb5..489c489c75 100644 --- a/.gitignore +++ b/.gitignore @@ -42,4 +42,7 @@ site # SAM Example copies files /examples/sam/src/handlers/* -!/examples/sam/src/handlers/COPY_LAMBDA_FUNCTIONS_HERE \ No newline at end of file +!/examples/sam/src/handlers/COPY_LAMBDA_FUNCTIONS_HERE + +# Layer temp files +tmp \ No newline at end of file diff --git a/.gitpod.yml b/.gitpod.yml index 06cac6a0bb..33253c2032 100644 --- a/.gitpod.yml +++ b/.gitpod.yml @@ -17,5 +17,4 @@ vscode: - dbaeumer.vscode-eslint - esbenp.prettier-vscode - firsttris.vscode-jest-runner - - ms-azuretools.vscode-docker - - ms-vscode.vscode-typescript-tslint-plugin + - ms-azuretools.vscode-docker \ No newline at end of file diff --git a/.husky/pre-commit b/.husky/pre-commit index 19d7e73c29..7f18baea4f 100755 --- a/.husky/pre-commit +++ b/.husky/pre-commit @@ -5,6 +5,4 @@ npm run lint-fix -ws cd examples/sam && npm run lint-fix cd ../.. cd examples/cdk && npm run lint-fix -cd ../.. -cd layer-publisher && npm run lint-fix -cd .. +cd ../.. \ No newline at end of file diff --git a/.husky/pre-push b/.husky/pre-push index e9b6f2754c..3b6d564252 100755 --- a/.husky/pre-push +++ b/.husky/pre-push @@ -1,4 +1,10 @@ #!/bin/sh . "$(dirname "$0")/_/husky.sh" -npm t -ws \ No newline at end of file +npm t \ + -w packages/commons \ + -w packages/logger \ + -w packages/metrics \ + -w packages/tracer \ + -w packages/idempotency \ + -w packages/parameters \ No newline at end of file diff --git a/CHANGELOG.md b/CHANGELOG.md index 64952bcef9..a8e61293d5 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,6 +3,30 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. +# [1.6.0](https://github.com/awslabs/aws-lambda-powertools-typescript/compare/v1.5.1...v1.6.0) (2023-03-02) + + +### Bug Fixes + +* **docs:** logger bringYourOwnFormatter snippet [#1253](https://github.com/awslabs/aws-lambda-powertools-typescript/issues/1253) ([#1254](https://github.com/awslabs/aws-lambda-powertools-typescript/issues/1254)) ([fdbba32](https://github.com/awslabs/aws-lambda-powertools-typescript/commit/fdbba32d8b3545730d242ac4fd1ef2d83cdbccce)) +* hardcoded cdk version in `publish_layer.yaml` ([#1232](https://github.com/awslabs/aws-lambda-powertools-typescript/issues/1232)) ([63a3909](https://github.com/awslabs/aws-lambda-powertools-typescript/commit/63a3909063637ca2306a718a10e35e54881f570e)) +* **logger:** createChild not passing all parent's attributes ([#1267](https://github.com/awslabs/aws-lambda-powertools-typescript/issues/1267)) ([84ab4b9](https://github.com/awslabs/aws-lambda-powertools-typescript/commit/84ab4b911d17d687bdbe60ded31f1e2b6860feb3)) +* **logger:** middleware stores initial persistent attributes correctly ([#1329](https://github.com/awslabs/aws-lambda-powertools-typescript/issues/1329)) ([6b32304](https://github.com/awslabs/aws-lambda-powertools-typescript/commit/6b3230489895dc1abdfc6ad56daeeb555fda529f)) +* **parameters:** handle base64/binaries in transformer ([#1326](https://github.com/awslabs/aws-lambda-powertools-typescript/issues/1326)) ([bb50c04](https://github.com/awslabs/aws-lambda-powertools-typescript/commit/bb50c04f5b2e6a144295b453577a7ea1a15ac011)) +* **parameters:** Tokenize attribute names in `DynamoDBProvider` ([#1239](https://github.com/awslabs/aws-lambda-powertools-typescript/issues/1239)) ([f3e5ed7](https://github.com/awslabs/aws-lambda-powertools-typescript/commit/f3e5ed70c7e5baa3f3aa15428e8d6cb56b096f26)) + + +### Features + +* **idempotency:** Add function wrapper and decorator ([#1262](https://github.com/awslabs/aws-lambda-powertools-typescript/issues/1262)) ([eacb1d9](https://github.com/awslabs/aws-lambda-powertools-typescript/commit/eacb1d9f59a82ad34234f51198ed215c41a64b41)) +* **layers:** add new regions ([#1322](https://github.com/awslabs/aws-lambda-powertools-typescript/issues/1322)) ([618613b](https://github.com/awslabs/aws-lambda-powertools-typescript/commit/618613b9a69166553dd9ef8d5b92f89e1cdf79d0)) +* **logger:** make loglevel types stricter ([#1313](https://github.com/awslabs/aws-lambda-powertools-typescript/issues/1313)) ([5af51d3](https://github.com/awslabs/aws-lambda-powertools-typescript/commit/5af51d319dee68d7a7ba832721580d7a6e655249)) +* **parameters:** add support for custom AWS SDK v3 clients for providers ([#1260](https://github.com/awslabs/aws-lambda-powertools-typescript/issues/1260)) ([3a8cfa0](https://github.com/awslabs/aws-lambda-powertools-typescript/commit/3a8cfa0d6e5aaa5c2c36d97d7835dbf5287b7110)) + + + + + ## [1.5.1](https://github.com/awslabs/aws-lambda-powertools-typescript/compare/v1.5.0...v1.5.1) (2023-01-13) diff --git a/LICENSE-THIRD-PARTY b/LICENSE-THIRD-PARTY index 4adf7eeb2f..98a63dfc1f 100644 --- a/LICENSE-THIRD-PARTY +++ b/LICENSE-THIRD-PARTY @@ -55,3 +55,29 @@ ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + +****************************** + +@middy/core +3.6.2 +MIT License + +Copyright (c) 2017-2023 [Luciano Mammino](https://github.com/lmammino), [will Farrell](https://github.com/willfarrell) and the [Middy team](https://github.com/middyjs/middy/graphs/contributors) + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. \ No newline at end of file diff --git a/MAINTAINERS.md b/MAINTAINERS.md index 6792654c1a..2d13d63424 100644 --- a/MAINTAINERS.md +++ b/MAINTAINERS.md @@ -102,7 +102,7 @@ These are the most common labels used by maintainers to triage issues, pull requ | good-first-issue | Something that is suitable for those who want to start contributing | | | help-wanted | Tasks you want help from anyone to move forward | Bandwidth, complex topics, etc. | | need-customer-feedback | Tasks that need more feedback before proceeding | 80/20% rule, uncertain, etc. | -| need-more-information | Missing information before making any calls | | +| need-more-information | Missing information before making any calls | Triggers stale automation after 2 weeks | | need-issue | PR is missing a related issue for tracking change | | ## Maintainer Responsibilities @@ -268,6 +268,8 @@ In other cases, you may have constrained capacity. Use `help=wanted` label when When in doubt, use `need-more-information` or `need-customer-feedback` labels to signal more context and feedback are necessary before proceeding. You can also use `status/on-hold` label when you expect it might take a while to gather enough information before you can decide. +Note that issues marked as `need-more-information` will be automatically closed after 3 weeks of inactivity. + ### Crediting contributions We credit all contributions as part of each [release note](https://github.com/awslabs/aws-lambda-powertools-typescript/releases) as an automated process. If you find contributors are missing from the release note you're producing, please add them manually. @@ -296,4 +298,4 @@ In the rare cases where both parties don't have the bandwidth or expertise to co ## Automation -🚧 WIP 🚧 \ No newline at end of file +🚧 WIP 🚧 diff --git a/README.md b/README.md index d97b378def..213d08a1b5 100644 --- a/README.md +++ b/README.md @@ -2,7 +2,7 @@ [![Join our Discord](https://dcbadge.vercel.app/api/server/B8zZKbbyET)](https://discord.gg/B8zZKbbyET) -A suite of utilities for AWS Lambda functions to ease the adoption of best practices such as tracing, structured logging, custom metrics, and more. +Powertools is a developer toolkit to implement Serverless [best practices and increase developer velocity](https://awslabs.github.io/aws-lambda-powertools-typescript/latest/#features). You can use the library in both TypeScript and JavaScript code bases. diff --git a/docs/Dockerfile b/docs/Dockerfile index 7084973a1f..40c4a3e4b4 100644 --- a/docs/Dockerfile +++ b/docs/Dockerfile @@ -1,2 +1,2 @@ FROM squidfunk/mkdocs-material -RUN pip install mkdocs-git-revision-date-plugin mkdocs-glightbox +RUN pip install mkdocs-git-revision-date-plugin==0.3.2 mkdocs-exclude==1.0.2 diff --git a/docs/core/logger.md b/docs/core/logger.md index c05fad22f0..fb25804135 100644 --- a/docs/core/logger.md +++ b/docs/core/logger.md @@ -390,8 +390,9 @@ The error will be logged with default key name `error`, but you can also pass yo ### Using multiple Logger instances across your code -Logger supports quick instance cloning via the `createChild` method. -This can be useful for example if you want to enable multiple Loggers with different logging levels in the same Lambda invocation. +The `createChild` method allows you to create a child instance of the Logger, which inherits all of the attributes from its parent. You have the option to override any of the settings and attributes from the parent logger, including [its settings](#utility-settings), any [persistent attributes](#appending-persistent-additional-log-keys-and-values), and [the log formatter](#custom-log-formatter-bring-your-own-formatter). Once a child logger is created, the logger and its parent will act as separate instances of the Logger class, and as such any change to one won't be applied to the other. + + The following example shows how to create multiple Loggers that share service name and persistent attributes while specifying different logging levels within a single Lambda invocation. As the result, only ERROR logs with all the inherited attributes will be displayed in CloudWatch Logs from the child logger, but all logs emitted will have the same service name and persistent attributes. === "handler.ts" @@ -407,6 +408,8 @@ This can be useful for example if you want to enable multiple Loggers with diffe "message": "This is an INFO log, from the parent logger", "service": "serverlessAirline", "timestamp": "2021-12-12T22:32:54.667Z", + "aws_account_id":"123456789012", + "aws_region":"eu-west-1", "xray_trace_id": "abcdef123456abcdef123456abcdef123456" } { @@ -414,6 +417,8 @@ This can be useful for example if you want to enable multiple Loggers with diffe "message": "This is an ERROR log, from the parent logger", "service": "serverlessAirline", "timestamp": "2021-12-12T22:32:54.670Z", + "aws_account_id":"123456789012", + "aws_region":"eu-west-1", "xray_trace_id": "abcdef123456abcdef123456abcdef123456" } { @@ -421,6 +426,8 @@ This can be useful for example if you want to enable multiple Loggers with diffe "message": "This is an ERROR log, from the child logger", "service": "serverlessAirline", "timestamp": "2021-12-12T22:32:54.670Z", + "aws_account_id":"123456789012", + "aws_region":"eu-west-1", "xray_trace_id": "abcdef123456abcdef123456abcdef123456" } ``` @@ -598,6 +605,9 @@ This is how the printed log would look: } ``` +!!! tip "Custom Log formatter and Child loggers" + It is not necessary to pass the `LogFormatter` each time a [child logger](#using-multiple-logger-instances-across-your-code) is created. The parent's LogFormatter will be inherited by the child logger. + ## Testing your code ### Inject Lambda Context diff --git a/docs/core/metrics.md b/docs/core/metrics.md index 661cc78de6..12f74854bd 100644 --- a/docs/core/metrics.md +++ b/docs/core/metrics.md @@ -51,13 +51,7 @@ The `Metrics` utility must always be instantiated outside of the Lambda handler. === "handler.ts" ```typescript hl_lines="1 3" - import { Metrics } from '@aws-lambda-powertools/metrics'; - - const metrics = new Metrics({ namespace: 'serverlessAirline', serviceName: 'orders' }); - - export const handler = async (_event, _context): Promise => { - // ... - }; + --8<-- "docs/snippets/metrics/basicUsage.ts" ``` ### Utility settings @@ -81,16 +75,7 @@ The `Metrics` utility is instantiated outside of the Lambda handler. In doing th === "handler.ts" ```typescript hl_lines="1 4" - import { Metrics } from '@aws-lambda-powertools/metrics'; - - // Metrics parameters fetched from the environment variables (see template.yaml tab) - const metrics = new Metrics(); - - // You can also pass the parameters in the constructor - // const metrics = new Metrics({ - // namespace: 'serverlessAirline', - // serviceName: 'orders' - // }); + --8<-- "docs/snippets/metrics/sam.ts" ``` === "template.yml" @@ -116,28 +101,13 @@ You can create metrics using the `addMetric` method, and you can create dimensio === "Metrics" ```typescript hl_lines="6" - import { Metrics, MetricUnits } from '@aws-lambda-powertools/metrics'; - - const metrics = new Metrics({ namespace: 'serverlessAirline', serviceName: 'orders' }); - - export const handler = async (_event: any, _context: any): Promise => { - metrics.addMetric('successfulBooking', MetricUnits.Count, 1); - metrics.publishStoredMetrics(); - }; + --8<-- "docs/snippets/metrics/createMetrics.ts" ``` === "Metrics with custom dimensions" ```typescript hl_lines="6-7" - import { Metrics, MetricUnits } from '@aws-lambda-powertools/metrics'; - - const metrics = new Metrics({ namespace: 'serverlessAirline', serviceName: 'orders' }); - - export const handler = async (_event: any, _context: any): Promise => { - metrics.addDimension('environment', 'prod'); - metrics.addMetric('successfulBooking', MetricUnits.Count, 1); - metrics.publishStoredMetrics(); - }; + --8<-- "docs/snippets/metrics/customDimensions.ts" ``` !!! tip "Autocomplete Metric Units" @@ -155,17 +125,8 @@ You can call `addMetric()` with the same name multiple times. The values will be === "addMetric() with the same name" - ```typescript hl_lines="8 10" - import { Metrics, MetricUnits } from '@aws-lambda-powertools/metrics'; - import { Context } from 'aws-lambda'; - - const metrics = new Metrics({ namespace:'serverlessAirline', serviceName:'orders' }); - - export const handler = async (event: any, context: Context): Promise => { - metrics.addMetric('performedActionA', MetricUnits.Count, 2); - // do something else... - metrics.addMetric('performedActionA', MetricUnits.Count, 1); - }; + ```typescript hl_lines="7 9" + --8<-- "docs/snippets/metrics/multiValueMetrics.ts" ``` === "Example CloudWatch Logs excerpt" @@ -210,17 +171,7 @@ You can add default dimensions to your metrics by passing them as parameters in === "constructor" ```typescript hl_lines="6" - import { Metrics, MetricUnits } from '@aws-lambda-powertools/metrics'; - - const metrics = new Metrics({ - namespace: 'serverlessAirline', - serviceName: 'orders', - defaultDimensions: { 'environment': 'prod', 'foo': 'bar' } - }); - - export const handler = async (_event: any, _context: any): Promise => { - metrics.addMetric('successfulBooking', MetricUnits.Count, 1); - }; + --8<-- "docs/snippets/metrics/defaultDimensions.ts" ``` === "Middy middleware" @@ -230,53 +181,19 @@ You can add default dimensions to your metrics by passing them as parameters in Learn more about [its usage and lifecycle in the official Middy documentation](https://middy.js.org/docs/intro/getting-started){target="_blank"}. ```typescript hl_lines="1-2 11 13" - import { Metrics, MetricUnits, logMetrics } from '@aws-lambda-powertools/metrics'; - import middy from '@middy/core'; - - const metrics = new Metrics({ namespace: 'serverlessAirline', serviceName: 'orders' }); - - const lambdaHandler = async (_event: any, _context: any): Promise => { - metrics.addMetric('successfulBooking', MetricUnits.Count, 1); - }; - - // Wrap the handler with middy - export const handler = middy(lambdaHandler) - // Use the middleware by passing the Metrics instance as a parameter - .use(logMetrics(metrics, { defaultDimensions:{ 'environment': 'prod', 'foo': 'bar' } })); + --8<-- "docs/snippets/metrics/defaultDimensionsMiddy.ts" ``` === "setDefaultDimensions method" ```typescript hl_lines="4" - import { Metrics, MetricUnits } from '@aws-lambda-powertools/metrics'; - - const metrics = new Metrics({ namespace: 'serverlessAirline', serviceName: 'orders' }); - metrics.setDefaultDimensions({ 'environment': 'prod', 'foo': 'bar' }); - - export const handler = async (event: any, _context: any): Promise => { - metrics.addMetric('successfulBooking', MetricUnits.Count, 1); - }; + --8<-- "docs/snippets/metrics/setDefaultDimensions.ts" ``` === "with logMetrics decorator" ```typescript hl_lines="9" - import { Metrics, MetricUnits } from '@aws-lambda-powertools/metrics'; - import { LambdaInterface } from '@aws-lambda-powertools/commons'; - - const metrics = new Metrics({ namespace: 'serverlessAirline', serviceName: 'orders' }); - const DEFAULT_DIMENSIONS = { 'environment': 'prod', 'foo': 'bar' }; - - export class Lambda implements LambdaInterface { - // Decorate your handler class method - @metrics.logMetrics({ defaultDimensions: DEFAULT_DIMENSIONS }) - public async handler(_event: any, _context: any): Promise { - metrics.addMetric('successfulBooking', MetricUnits.Count, 1); - } - } - - const handlerClass = new Lambda(); - export const handler = handlerClass.handler.bind(handlerClass); // (1) + --8<-- "docs/snippets/metrics/defaultDimensionsDecorator.ts" ``` 1. Binding your handler method allows your handler to access `this` within the class methods. @@ -310,17 +227,7 @@ See below an example of how to automatically flush metrics with the Middy-compat === "handler.ts" ```typescript hl_lines="1-2 7 10-11" - import { Metrics, MetricUnits, logMetrics } from '@aws-lambda-powertools/metrics'; - import middy from '@middy/core'; - - const metrics = new Metrics({ namespace: 'serverlessAirline', serviceName: 'orders' }); - - const lambdaHandler = async (_event: any, _context: any): Promise => { - metrics.addMetric('successfulBooking', MetricUnits.Count, 1); - }; - - export const handler = middy(lambdaHandler) - .use(logMetrics(metrics)); + --8<-- "docs/snippets/metrics/middy.ts" ``` === "Example CloudWatch Logs excerpt" @@ -360,21 +267,7 @@ The `logMetrics` decorator of the metrics utility can be used when your Lambda h === "handler.ts" ```typescript hl_lines="8" - import { Metrics, MetricUnits } from '@aws-lambda-powertools/metrics'; - import { LambdaInterface } from '@aws-lambda-powertools/commons'; - - const metrics = new Metrics({ namespace: 'serverlessAirline', serviceName: 'orders' }); - - class Lambda implements LambdaInterface { - - @metrics.logMetrics() - public async handler(_event: any, _context: any): Promise { - metrics.addMetric('successfulBooking', MetricUnits.Count, 1); - } - } - - const handlerClass = new Lambda(); - export const handler = handlerClass.handler.bind(handlerClass); // (1) + --8<-- "docs/snippets/metrics/decorator.ts" ``` 1. Binding your handler method allows your handler to access `this` within the class methods. @@ -415,14 +308,7 @@ Metrics, dimensions and namespace validation still applies. === "handler.ts" ```typescript hl_lines="7" - import { Metrics, MetricUnits } from '@aws-lambda-powertools/metrics'; - - const metrics = new Metrics({ namespace: 'serverlessAirline', serviceName: 'orders' }); - - export const handler = async (_event: any, _context: any): Promise => { - metrics.addMetric('successfulBooking', MetricUnits.Count, 10); - metrics.publishStoredMetrics(); - }; + --8<-- "docs/snippets/metrics/manual.ts" ``` === "Example CloudWatch Logs excerpt" @@ -460,17 +346,7 @@ If you want to ensure that at least one metric is emitted before you flush them, === "handler.ts" ```typescript hl_lines="11" - import { Metrics, MetricUnits, logMetrics } from '@aws-lambda-powertools/metrics'; - import middy from '@middy/core'; - - const metrics = new Metrics({ namespace: 'serverlessAirline', serviceName: 'orders' }); - - const lambdaHandler = async (_event: any, _context: any): Promise => { - metrics.addMetric('successfulBooking', MetricUnits.Count, 1); - }; - - export const handler = middy(lambdaHandler) - .use(logMetrics(metrics, { throwOnEmptyMetrics: true })); + --8<-- "docs/snippets/metrics/throwOnEmptyMetrics.ts" ``` ### Capturing a cold start invocation as metric @@ -480,34 +356,13 @@ You can optionally capture cold start metrics with the `logMetrics` middleware o === "Middy Middleware" ```typescript hl_lines="11" - import { Metrics, MetricUnits, logMetrics } from '@aws-lambda-powertools/metrics'; - import middy from '@middy/core'; - - const metrics = new Metrics({ namespace: 'serverlessAirline', serviceName: 'orders' }); - - const lambdaHandler = async (_event: any, _context: any): Promise => { - metrics.addMetric('successfulBooking', MetricUnits.Count, 1); - }; - - export const handler = middy(lambdaHandler) - .use(logMetrics(metrics, { captureColdStartMetric: true })); + --8<-- "docs/snippets/metrics/captureColdStartMetricMiddy.ts" ``` === "logMetrics decorator" ```typescript hl_lines="8" - import { Metrics, MetricUnits } from '@aws-lambda-powertools/metrics'; - import { LambdaInterface } from '@aws-lambda-powertools/commons'; - - const metrics = new Metrics({ namespace: 'serverlessAirline', serviceName: 'orders' }); - - export class MyFunction implements LambdaInterface { - - @metrics.logMetrics({ captureColdStartMetric: true }) - public async handler(_event: any, _context: any): Promise { - metrics.addMetric('successfulBooking', MetricUnits.Count, 1); - } - } + --8<-- "docs/snippets/metrics/captureColdStartMetricDecorator.ts" ``` If it's a cold start invocation, this feature will: @@ -531,18 +386,7 @@ You can add high-cardinality data as part of your Metrics log with the `addMetad === "handler.ts" ```typescript hl_lines="8" - import { Metrics, MetricUnits, logMetrics } from '@aws-lambda-powertools/metrics'; - import middy from '@middy/core'; - - const metrics = new Metrics({ namespace: 'serverlessAirline', serviceName: 'orders' }); - - const lambdaHandler = async (_event: any, _context: any): Promise => { - metrics.addMetric('successfulBooking', MetricUnits.Count, 1); - metrics.addMetadata('bookingId', '7051cd10-6283-11ec-90d6-0242ac120003'); - }; - - export const handler = middy(lambdaHandler) - .use(logMetrics(metrics)); + --8<-- "docs/snippets/metrics/addMetadata.ts" ``` === "Example CloudWatch Logs excerpt" @@ -594,51 +438,13 @@ CloudWatch EMF uses the same dimensions across all your metrics. Use `singleMetr === "Middy Middleware" ```typescript hl_lines="11 13-14" - import { Metrics, MetricUnits, logMetrics } from '@aws-lambda-powertools/metrics'; - import middy from '@middy/core'; - - const metrics = new Metrics({ namespace: 'serverlessAirline', serviceName: 'orders' }); - - const lambdaHandler = async (_event: any, _context: any): Promise => { - metrics.addDimension('metricUnit', 'milliseconds'); - // This metric will have the "metricUnit" dimension, and no "metricType" dimension: - metrics.addMetric('latency', MetricUnits.Milliseconds, 56); - - const singleMetric = metrics.singleMetric(); - // This metric will have the "metricType" dimension, and no "metricUnit" dimension: - singleMetric.addDimension('metricType', 'business'); - singleMetric.addMetric('orderSubmitted', MetricUnits.Count, 1); - }; - - export const handler = middy(lambdaHandler) - .use(logMetrics(metrics)); + --8<-- "docs/snippets/metrics/singleMetricDifferentDimsMiddy.ts" ``` === "logMetrics decorator" ```typescript hl_lines="14 16-17" - import { Metrics, MetricUnits } from '@aws-lambda-powertools/metrics'; - import { LambdaInterface } from '@aws-lambda-powertools/commons'; - - const metrics = new Metrics({ namespace: 'serverlessAirline', serviceName: 'orders' }); - - class Lambda implements LambdaInterface { - - @metrics.logMetrics() - public async handler(_event: any, _context: any): Promise { - metrics.addDimension('metricUnit', 'milliseconds'); - // This metric will have the "metricUnit" dimension, and no "metricType" dimension: - metrics.addMetric('latency', MetricUnits.Milliseconds, 56); - - const singleMetric = metrics.singleMetric(); - // This metric will have the "metricType" dimension, and no "metricUnit" dimension: - singleMetric.addDimension('metricType', 'business'); - singleMetric.addMetric('orderSubmitted', MetricUnits.Count, 1); - } - } - - const handlerClass = new Lambda(); - export const handler = handlerClass.handler.bind(handlerClass); // (1) + --8<-- "docs/snippets/metrics/singleMetricDifferentDimsDecorator.ts" ``` 1. Binding your handler method allows your handler to access `this` within the class methods. \ No newline at end of file diff --git a/docs/index.md b/docs/index.md index ef585e68a1..2f9eb56ff0 100644 --- a/docs/index.md +++ b/docs/index.md @@ -3,12 +3,12 @@ title: Homepage description: AWS Lambda Powertools for TypeScript --- -A suite of utilities for AWS Lambda functions running on the Node.js runtime, to ease adopting best practices such as tracing, structured logging, custom metrics, [**and more**](#features). +Powertools is a developer toolkit to implement Serverless [best practices and increase developer velocity](#features). You can use Powertools in both TypeScript and JavaScript code bases. ???+ tip - Powertools is also available for [Python](https://awslabs.github.io/aws-lambda-powertools-python/){target="_blank"}, [Java](https://awslabs.github.io/aws-lambda-powertools-java/latest/){target="_blank"}, and [.NET](https://awslabs.github.io/aws-lambda-powertools-dotnet/){target="_blank"} + Powertools is also available for [Python](https://awslabs.github.io/aws-lambda-powertools-python/){target="_blank"}, [Java](https://awslabs.github.io/aws-lambda-powertools-java/){target="_blank"}, and [.NET](https://awslabs.github.io/aws-lambda-powertools-dotnet/){target="_blank"} ??? hint "Support this project by becoming a reference customer, sharing your work, or using Layers :heart:" @@ -26,7 +26,7 @@ You can use Powertools in both TypeScript and JavaScript code bases. Powertools is available in the following formats: -* **Lambda Layer**: [**arn:aws:lambda:{region}:094274105915:layer:AWSLambdaPowertoolsTypeScript:6**](#){: .copyMe}:clipboard: +* **Lambda Layer**: [**arn:aws:lambda:{region}:094274105915:layer:AWSLambdaPowertoolsTypeScript:8**](#){: .copyMe}:clipboard: * **npm**: **`npm install @aws-lambda-powertools/tracer @aws-lambda-powertools/metrics @aws-lambda-powertools/logger`** ### Lambda Layer @@ -37,25 +37,33 @@ You can include Lambda Powertools Lambda Layer using [AWS Lambda Console](https: ??? note "Note: Click to expand and copy any regional Lambda Layer ARN" - | Region | Layer ARN - |--------------------------- | --------------------------- - | `us-east-1` | [arn:aws:lambda:us-east-1:094274105915:layer:AWSLambdaPowertoolsTypeScript:6](#){: .copyMe}:clipboard: - | `us-east-2` | [arn:aws:lambda:us-east-2:094274105915:layer:AWSLambdaPowertoolsTypeScript:6](#){: .copyMe}:clipboard: - | `us-west-1` | [arn:aws:lambda:us-west-1:094274105915:layer:AWSLambdaPowertoolsTypeScript:6](#){: .copyMe}:clipboard: - | `us-west-2` | [arn:aws:lambda:us-west-2:094274105915:layer:AWSLambdaPowertoolsTypeScript:6](#){: .copyMe}:clipboard: - | `ap-south-1` | [arn:aws:lambda:ap-south-1:094274105915:layer:AWSLambdaPowertoolsTypeScript:6](#){: .copyMe}:clipboard: - | `ap-northeast-1` | [arn:aws:lambda:ap-northeast-1:094274105915:layer:AWSLambdaPowertoolsTypeScript:6](#){: .copyMe}:clipboard: - | `ap-northeast-2` | [arn:aws:lambda:ap-northeast-2:094274105915:layer:AWSLambdaPowertoolsTypeScript:6](#){: .copyMe}:clipboard: - | `ap-northeast-3` | [arn:aws:lambda:ap-northeast-3:094274105915:layer:AWSLambdaPowertoolsTypeScript:6](#){: .copyMe}:clipboard: - | `ap-southeast-1` | [arn:aws:lambda:ap-southeast-1:094274105915:layer:AWSLambdaPowertoolsTypeScript:6](#){: .copyMe}:clipboard: - | `ap-southeast-2` | [arn:aws:lambda:ap-southeast-2:094274105915:layer:AWSLambdaPowertoolsTypeScript:6](#){: .copyMe}:clipboard: - | `eu-central-1` | [arn:aws:lambda:eu-central-1:094274105915:layer:AWSLambdaPowertoolsTypeScript:6](#){: .copyMe}:clipboard: - | `eu-west-1` | [arn:aws:lambda:eu-west-1:094274105915:layer:AWSLambdaPowertoolsTypeScript:6](#){: .copyMe}:clipboard: - | `eu-west-2` | [arn:aws:lambda:eu-west-2:094274105915:layer:AWSLambdaPowertoolsTypeScript:6](#){: .copyMe}:clipboard: - | `eu-west-3` | [arn:aws:lambda:eu-west-3:094274105915:layer:AWSLambdaPowertoolsTypeScript:6](#){: .copyMe}:clipboard: - | `eu-north-1` | [arn:aws:lambda:eu-north-1:094274105915:layer:AWSLambdaPowertoolsTypeScript:6](#){: .copyMe}:clipboard: - | `ca-central-1` | [arn:aws:lambda:ca-central-1:094274105915:layer:AWSLambdaPowertoolsTypeScript:6](#){: .copyMe}:clipboard: - | `sa-east-1` | [arn:aws:lambda:sa-east-1:094274105915:layer:AWSLambdaPowertoolsTypeScript:6](#){: .copyMe}:clipboard: + | Region | Layer ARN | + | ---------------- | ----------------------------------------------------------------------------------------------------------- | + | `us-east-1` | [arn:aws:lambda:us-east-1:094274105915:layer:AWSLambdaPowertoolsTypeScript:8](#){: .copyMe}:clipboard: | + | `us-east-2` | [arn:aws:lambda:us-east-2:094274105915:layer:AWSLambdaPowertoolsTypeScript:8](#){: .copyMe}:clipboard: | + | `us-west-1` | [arn:aws:lambda:us-west-1:094274105915:layer:AWSLambdaPowertoolsTypeScript:8](#){: .copyMe}:clipboard: | + | `us-west-2` | [arn:aws:lambda:us-west-2:094274105915:layer:AWSLambdaPowertoolsTypeScript:8](#){: .copyMe}:clipboard: | + | `ap-south-1` | [arn:aws:lambda:ap-south-1:094274105915:layer:AWSLambdaPowertoolsTypeScript:8](#){: .copyMe}:clipboard: | + | `ap-east-1` | [arn:aws:lambda:ap-east-1:094274105915:layer:AWSLambdaPowertoolsTypeScript:8](#){: .copyMe}:clipboard: | + | `ap-northeast-1` | [arn:aws:lambda:ap-northeast-1:094274105915:layer:AWSLambdaPowertoolsTypeScript:8](#){: .copyMe}:clipboard: | + | `ap-northeast-2` | [arn:aws:lambda:ap-northeast-2:094274105915:layer:AWSLambdaPowertoolsTypeScript:8](#){: .copyMe}:clipboard: | + | `ap-northeast-3` | [arn:aws:lambda:ap-northeast-3:094274105915:layer:AWSLambdaPowertoolsTypeScript:8](#){: .copyMe}:clipboard: | + | `ap-southeast-1` | [arn:aws:lambda:ap-southeast-1:094274105915:layer:AWSLambdaPowertoolsTypeScript:8](#){: .copyMe}:clipboard: | + | `ap-southeast-2` | [arn:aws:lambda:ap-southeast-2:094274105915:layer:AWSLambdaPowertoolsTypeScript:8](#){: .copyMe}:clipboard: | + | `ap-southeast-3` | [arn:aws:lambda:ap-southeast-3:094274105915:layer:AWSLambdaPowertoolsTypeScript:8](#){: .copyMe}:clipboard: | + | `ap-southeast-4` | [arn:aws:lambda:ap-southeast-4:094274105915:layer:AWSLambdaPowertoolsTypeScript:8](#){: .copyMe}:clipboard: | + | `eu-central-1` | [arn:aws:lambda:eu-central-1:094274105915:layer:AWSLambdaPowertoolsTypeScript:8](#){: .copyMe}:clipboard: | + | `eu-central-2` | [arn:aws:lambda:eu-central-1:094274105915:layer:AWSLambdaPowertoolsTypeScript:8](#){: .copyMe}:clipboard: | + | `eu-west-1` | [arn:aws:lambda:eu-west-1:094274105915:layer:AWSLambdaPowertoolsTypeScript:8](#){: .copyMe}:clipboard: | + | `eu-west-2` | [arn:aws:lambda:eu-west-2:094274105915:layer:AWSLambdaPowertoolsTypeScript:8](#){: .copyMe}:clipboard: | + | `eu-west-3` | [arn:aws:lambda:eu-west-3:094274105915:layer:AWSLambdaPowertoolsTypeScript:8](#){: .copyMe}:clipboard: | + | `eu-north-1` | [arn:aws:lambda:eu-north-1:094274105915:layer:AWSLambdaPowertoolsTypeScript:8](#){: .copyMe}:clipboard: | + | `eu-south-1` | [arn:aws:lambda:eu-south-1:094274105915:layer:AWSLambdaPowertoolsTypeScript:8](#){: .copyMe}:clipboard: | + | `eu-south-2` | [arn:aws:lambda:eu-south-2:094274105915:layer:AWSLambdaPowertoolsTypeScript:8](#){: .copyMe}:clipboard: | + | `ca-central-1` | [arn:aws:lambda:ca-central-1:094274105915:layer:AWSLambdaPowertoolsTypeScript:8](#){: .copyMe}:clipboard: | + | `sa-east-1` | [arn:aws:lambda:sa-east-1:094274105915:layer:AWSLambdaPowertoolsTypeScript:8](#){: .copyMe}:clipboard: | + | `af-south-1` | [arn:aws:lambda:af-south-11:094274105915:layer:AWSLambdaPowertoolsTypeScript:8](#){: .copyMe}:clipboard: | + | `me-south-1` | [arn:aws:lambda:me-south-11:094274105915:layer:AWSLambdaPowertoolsTypeScript:8](#){: .copyMe}:clipboard: | ??? note "Note: Click to expand and copy code snippets for popular frameworks" @@ -66,7 +74,7 @@ You can include Lambda Powertools Lambda Layer using [AWS Lambda Console](https: Type: AWS::Serverless::Function Properties: Layers: - - !Sub arn:aws:lambda:${AWS::Region}:094274105915:layer:AWSLambdaPowertoolsTypeScript:6 + - !Sub arn:aws:lambda:${AWS::Region}:094274105915:layer:AWSLambdaPowertoolsTypeScript:8 ``` If you use `esbuild` to bundle your code, make sure to exclude `@aws-lambda-powertools` from being bundled since the packages will be already present the Layer: @@ -97,7 +105,7 @@ You can include Lambda Powertools Lambda Layer using [AWS Lambda Console](https: hello: handler: lambda_function.lambda_handler layers: - - arn:aws:lambda:${aws::region}:094274105915:layer:AWSLambdaPowertoolsTypeScript:6 + - arn:aws:lambda:${aws::region}:094274105915:layer:AWSLambdaPowertoolsTypeScript:8 ``` If you use `esbuild` to bundle your code, make sure to exclude `@aws-lambda-powertools` from being bundled since the packages will be already present the Layer: @@ -129,7 +137,7 @@ You can include Lambda Powertools Lambda Layer using [AWS Lambda Console](https: const powertoolsLayer = lambda.LayerVersion.fromLayerVersionArn( this, 'PowertoolsLayer', - `arn:aws:lambda:${cdk.Stack.of(this).region}:094274105915:layer:AWSLambdaPowertoolsTypeScript:6` + `arn:aws:lambda:${cdk.Stack.of(this).region}:094274105915:layer:AWSLambdaPowertoolsTypeScript:8` ); new lambda.Function(this, 'Function', { @@ -181,7 +189,7 @@ You can include Lambda Powertools Lambda Layer using [AWS Lambda Console](https: role = ... handler = "index.handler" runtime = "nodejs16.x" - layers = ["arn:aws:lambda:{aws::region}:094274105915:layer:AWSLambdaPowertoolsTypeScript:6"] + layers = ["arn:aws:lambda:{aws::region}:094274105915:layer:AWSLambdaPowertoolsTypeScript:8"] source_code_hash = filebase64sha256("lambda_function_payload.zip") } ``` @@ -199,7 +207,7 @@ You can include Lambda Powertools Lambda Layer using [AWS Lambda Console](https: const lambdaFunction = new aws.lambda.Function("function", { layers: [ - pulumi.interpolate`arn:aws:lambda:${aws.getRegionOutput().name}:094274105915:layer:AWSLambdaPowertoolsTypeScript:6` + pulumi.interpolate`arn:aws:lambda:${aws.getRegionOutput().name}:094274105915:layer:AWSLambdaPowertoolsTypeScript:8` ], code: new pulumi.asset.FileArchive("lambda_function_payload.zip"), tracingConfig: { @@ -223,7 +231,7 @@ You can include Lambda Powertools Lambda Layer using [AWS Lambda Console](https: ? Do you want to configure advanced settings? Yes ... ? Do you want to enable Lambda layers for this function? Yes - ? Enter up to 5 existing Lambda layer ARNs (comma-separated): arn:aws:lambda:{aws::region}:094274105915:layer:AWSLambdaPowertoolsTypeScript:6 + ? Enter up to 5 existing Lambda layer ARNs (comma-separated): arn:aws:lambda:{aws::region}:094274105915:layer:AWSLambdaPowertoolsTypeScript:8 ❯ amplify push -y # Updating an existing function and add the layer @@ -233,13 +241,13 @@ You can include Lambda Powertools Lambda Layer using [AWS Lambda Console](https: - Name: ? Which setting do you want to update? Lambda layers configuration ? Do you want to enable Lambda layers for this function? Yes - ? Enter up to 5 existing Lambda layer ARNs (comma-separated): arn:aws:lambda:{aws::region}:094274105915:layer:AWSLambdaPowertoolsTypeScript:6 + ? Enter up to 5 existing Lambda layer ARNs (comma-separated): arn:aws:lambda:{aws::region}:094274105915:layer:AWSLambdaPowertoolsTypeScript:8 ? Do you want to edit the local lambda function now? No ``` === "Get the Layer .zip contents" ```bash title="AWS CLI" - aws lambda get-layer-version-by-arn --arn arn:aws:lambda:{aws::region}:094274105915:layer:AWSLambdaPowertoolsTypeScript:6 --region {region} + aws lambda get-layer-version-by-arn --arn arn:aws:lambda:{aws::region}:094274105915:layer:AWSLambdaPowertoolsTypeScript:8 --region {region} ``` The pre-signed URL to download this Lambda Layer will be within `Location` key. @@ -272,29 +280,29 @@ If instead you want to see Powertools for TypeScript in a slightly more complex Core utilities such as Tracing, Logging, and Metrics will be available across all Lambda Powertools languages. Additional utilities are subjective to each language ecosystem and customer demand. -| Utility | Description | -| ------------------------------------------------- | ------------------------------------------------------------------------------------------------------------- | -| [Tracer](./core/tracer.md) | Decorators and utilities to trace Lambda function handlers, and both synchronous and asynchronous functions | -| [Logger](./core/logger.md) | Structured logging made easier, and a middleware to enrich structured logging with key Lambda context details | -| [Metrics](./core/metrics.md) | Custom Metrics created asynchronously via CloudWatch Embedded Metric Format (EMF) | +| Utility | Description | +| ---------------------------- | ------------------------------------------------------------------------------------------------------------- | +| [Tracer](./core/tracer.md) | Decorators and utilities to trace Lambda function handlers, and both synchronous and asynchronous functions | +| [Logger](./core/logger.md) | Structured logging made easier, and a middleware to enrich structured logging with key Lambda context details | +| [Metrics](./core/metrics.md) | Custom Metrics created asynchronously via CloudWatch Embedded Metric Format (EMF) | ## Environment variables ???+ info Explicit parameters take precedence over environment variables -| Environment variable | Description | Utility | Default | -|----------------------------------------------|----------------------------------------------------------------------------------------|---------------------------|-----------------------| -| **POWERTOOLS_SERVICE_NAME** | Sets service name used for tracing namespace, metrics dimension and structured logging | All | `service_undefined` | -| **POWERTOOLS_METRICS_NAMESPACE** | Sets namespace used for metrics | [Metrics](./core/metrics) | `default_namespace` | -| **POWERTOOLS_TRACE_ENABLED** | Explicitly disables tracing | [Tracer](./core/tracer) | `true` | -| **POWERTOOLS_TRACER_CAPTURE_RESPONSE** | Captures Lambda or method return as metadata. | [Tracer](./core/tracer) | `true` | -| **POWERTOOLS_TRACER_CAPTURE_ERROR** | Captures Lambda or method exception as metadata. | [Tracer](./core/tracer) | `true` | -| **POWERTOOLS_TRACER_CAPTURE_HTTPS_REQUESTS** | Captures HTTP(s) requests as segments. | [Tracer](./core/tracer) | `true` | -| **POWERTOOLS_LOGGER_LOG_EVENT** | Logs incoming event | [Logger](./core/logger) | `false` | -| **POWERTOOLS_LOGGER_SAMPLE_RATE** | Debug log sampling | [Logger](./core/logger) | `0` | -| **POWERTOOLS_DEV** | Increase JSON indentation to ease debugging when running functions locally or in a non-production environment | [Logger](./core/logger) | `false` | -| **LOG_LEVEL** | Sets logging level | [Logger](./core/logger) | `INFO` | +| Environment variable | Description | Utility | Default | +| -------------------------------------------- | ------------------------------------------------------------------------------------------------------------- | ------------------------- | ------------------- | +| **POWERTOOLS_SERVICE_NAME** | Sets service name used for tracing namespace, metrics dimension and structured logging | All | `service_undefined` | +| **POWERTOOLS_METRICS_NAMESPACE** | Sets namespace used for metrics | [Metrics](./core/metrics) | `default_namespace` | +| **POWERTOOLS_TRACE_ENABLED** | Explicitly disables tracing | [Tracer](./core/tracer) | `true` | +| **POWERTOOLS_TRACER_CAPTURE_RESPONSE** | Captures Lambda or method return as metadata. | [Tracer](./core/tracer) | `true` | +| **POWERTOOLS_TRACER_CAPTURE_ERROR** | Captures Lambda or method exception as metadata. | [Tracer](./core/tracer) | `true` | +| **POWERTOOLS_TRACER_CAPTURE_HTTPS_REQUESTS** | Captures HTTP(s) requests as segments. | [Tracer](./core/tracer) | `true` | +| **POWERTOOLS_LOGGER_LOG_EVENT** | Logs incoming event | [Logger](./core/logger) | `false` | +| **POWERTOOLS_LOGGER_SAMPLE_RATE** | Debug log sampling | [Logger](./core/logger) | `0` | +| **POWERTOOLS_DEV** | Increase JSON indentation to ease debugging when running functions locally or in a non-production environment | [Logger](./core/logger) | `false` | +| **LOG_LEVEL** | Sets logging level | [Logger](./core/logger) | `INFO` | Each Utility page provides information on example values and allowed values @@ -308,4 +316,4 @@ These are our core principles to guide our decision making. * **We strive for backwards compatibility**. New features and changes should keep backwards compatibility. If a breaking change cannot be avoided, the deprecation and migration process should be clearly defined. * **We work backwards from the community**. We aim to strike a balance of what would work best for 80% of customers. Emerging practices are considered and discussed via Requests for Comment (RFCs) * **Progressive**. Utilities are designed to be incrementally adoptable for customers at any stage of their Serverless journey. They follow language idioms and their community’s common practices. - \ No newline at end of file + diff --git a/docs/overrides/main.html b/docs/overrides/main.html index 540387c9a7..0d556b6813 100644 --- a/docs/overrides/main.html +++ b/docs/overrides/main.html @@ -5,13 +5,4 @@ Click here to go to latest. -{% endblock %} - -{% block announce %} -Version 1.5.0 will be the last version to support Node.js 12.
Node.js 12 has reached end-of-life and the -corresponding -AWS Lambda runtime will be deprecated at the end of March 2023. Please upgrade to Node.js 14 or later.
-Click here to read the full announcement, or join our Discord server to chime in the discussion. {% endblock %} \ No newline at end of file diff --git a/docs/requirements.txt b/docs/requirements.txt index 8a6ea54a95..9332acafa3 100644 --- a/docs/requirements.txt +++ b/docs/requirements.txt @@ -1,3 +1,4 @@ mike==1.1.2 mkdocs-material==9.0.2 -mkdocs-git-revision-date-plugin==0.3.2 \ No newline at end of file +mkdocs-git-revision-date-plugin==0.3.2 +mkdocs-exclude==1.0.2 \ No newline at end of file diff --git a/docs/snippets/logger/appendKeys.ts b/docs/snippets/logger/appendKeys.ts index 3c0d92cb40..d8d94541b6 100644 --- a/docs/snippets/logger/appendKeys.ts +++ b/docs/snippets/logger/appendKeys.ts @@ -2,15 +2,15 @@ import { Logger } from '@aws-lambda-powertools/logger'; // Add persistent log keys via the constructor const logger = new Logger({ - persistentLogAttributes: { - aws_account_id: '123456789012', - aws_region: 'eu-west-1', - logger: { - name: '@aws-lambda-powertools/logger', - version: '0.0.1', - }, - extra_key: "some-value" - } + persistentLogAttributes: { + aws_account_id: '123456789012', + aws_region: 'eu-west-1', + logger: { + name: '@aws-lambda-powertools/logger', + version: '0.0.1', + }, + extra_key: 'some-value' + } }); // OR add persistent log keys to an existing Logger instance with the appendKeys method: @@ -24,18 +24,18 @@ const logger = new Logger({ // extra_key: "some-value" // }); -export const handler = async (_event: any, _context: any): Promise => { +export const handler = async (_event: unknown, _context: unknown): Promise => { - // If you don't want to log the "extra_key" attribute in your logs, you can remove it - logger.removeKeys(["extra_key"]) + // If you don't want to log the "extra_key" attribute in your logs, you can remove it + logger.removeKeys(['extra_key']); - // This info log will print all extra custom attributes added above - // Extra attributes: logger object with name and version of the logger library, awsAccountId, awsRegion - logger.info('This is an INFO log'); - logger.info('This is another INFO log'); + // This info log will print all extra custom attributes added above + // Extra attributes: logger object with name and version of the logger library, awsAccountId, awsRegion + logger.info('This is an INFO log'); + logger.info('This is another INFO log'); - return { - foo: 'bar' - }; + return { + foo: 'bar' + }; }; \ No newline at end of file diff --git a/docs/snippets/logger/basicUsage.ts b/docs/snippets/logger/basicUsage.ts index 07d02405ae..8fbda33daf 100644 --- a/docs/snippets/logger/basicUsage.ts +++ b/docs/snippets/logger/basicUsage.ts @@ -3,5 +3,5 @@ import { Logger } from '@aws-lambda-powertools/logger'; const logger = new Logger({ serviceName: 'serverlessAirline' }); export const handler = async (_event, _context): Promise => { - // ... + logger.info('Hello World'); }; \ No newline at end of file diff --git a/docs/snippets/logger/bringYourOwnFormatterClass.ts b/docs/snippets/logger/bringYourOwnFormatterClass.ts index 0121e1bc64..ab7e207cb9 100644 --- a/docs/snippets/logger/bringYourOwnFormatterClass.ts +++ b/docs/snippets/logger/bringYourOwnFormatterClass.ts @@ -1,24 +1,37 @@ -import { Logger } from '@aws-lambda-powertools/logger'; -import { MyCompanyLogFormatter } from './utils/formatters/MyCompanyLogFormatter'; +import { LogFormatter } from '@aws-lambda-powertools/logger'; +import { + LogAttributes, + UnformattedAttributes, +} from '@aws-lambda-powertools/logger/lib/types'; -const logger = new Logger({ - logFormatter: new MyCompanyLogFormatter(), - logLevel: 'DEBUG', - serviceName: 'serverlessAirline', - sampleRateValue: 0.5, - persistentLogAttributes: { - awsAccountId: process.env.AWS_ACCOUNT_ID, - logger: { - name: '@aws-lambda-powertools/logger', - version: '0.0.1' - } - }, -}); +// Replace this line with your own type +type MyCompanyLog = LogAttributes; -export const handler = async (event, context): Promise => { +class MyCompanyLogFormatter extends LogFormatter { + public formatAttributes(attributes: UnformattedAttributes): MyCompanyLog { + return { + message: attributes.message, + service: attributes.serviceName, + environment: attributes.environment, + awsRegion: attributes.awsRegion, + correlationIds: { + awsRequestId: attributes.lambdaContext?.awsRequestId, + xRayTraceId: attributes.xRayTraceId, + }, + lambdaFunction: { + name: attributes.lambdaContext?.functionName, + arn: attributes.lambdaContext?.invokedFunctionArn, + memoryLimitInMB: attributes.lambdaContext?.memoryLimitInMB, + version: attributes.lambdaContext?.functionVersion, + coldStart: attributes.lambdaContext?.coldStart, + }, + logLevel: attributes.logLevel, + timestamp: this.formatTimestamp(attributes.timestamp), // You can extend this function + logger: { + sampleRateValue: attributes.sampleRateValue, + }, + }; + } +} - logger.addContext(context); - - logger.info('This is an INFO log', { correlationIds: { myCustomCorrelationId: 'foo-bar-baz' } }); - -}; \ No newline at end of file +export { MyCompanyLogFormatter }; diff --git a/docs/snippets/logger/bringYourOwnFormatterHandler.ts b/docs/snippets/logger/bringYourOwnFormatterHandler.ts index 0121e1bc64..b565708f9d 100644 --- a/docs/snippets/logger/bringYourOwnFormatterHandler.ts +++ b/docs/snippets/logger/bringYourOwnFormatterHandler.ts @@ -2,23 +2,23 @@ import { Logger } from '@aws-lambda-powertools/logger'; import { MyCompanyLogFormatter } from './utils/formatters/MyCompanyLogFormatter'; const logger = new Logger({ - logFormatter: new MyCompanyLogFormatter(), - logLevel: 'DEBUG', - serviceName: 'serverlessAirline', - sampleRateValue: 0.5, - persistentLogAttributes: { - awsAccountId: process.env.AWS_ACCOUNT_ID, - logger: { - name: '@aws-lambda-powertools/logger', - version: '0.0.1' - } - }, + logFormatter: new MyCompanyLogFormatter(), + logLevel: 'DEBUG', + serviceName: 'serverlessAirline', + sampleRateValue: 0.5, + persistentLogAttributes: { + awsAccountId: process.env.AWS_ACCOUNT_ID, + logger: { + name: '@aws-lambda-powertools/logger', + version: '0.0.1' + } + }, }); export const handler = async (event, context): Promise => { - logger.addContext(context); + logger.addContext(context); - logger.info('This is an INFO log', { correlationIds: { myCustomCorrelationId: 'foo-bar-baz' } }); + logger.info('This is an INFO log', { correlationIds: { myCustomCorrelationId: 'foo-bar-baz' } }); }; \ No newline at end of file diff --git a/docs/snippets/logger/clearStateDecorator.ts b/docs/snippets/logger/clearStateDecorator.ts index 8251b99fcf..359b63cc29 100644 --- a/docs/snippets/logger/clearStateDecorator.ts +++ b/docs/snippets/logger/clearStateDecorator.ts @@ -4,26 +4,26 @@ import { LambdaInterface } from '@aws-lambda-powertools/commons'; // Persistent attributes added outside the handler will be // cached across invocations const logger = new Logger({ - logLevel: 'DEBUG', - persistentLogAttributes: { - foo: "bar", - biz: "baz" - } + logLevel: 'DEBUG', + persistentLogAttributes: { + foo: 'bar', + biz: 'baz' + } }); class Lambda implements LambdaInterface { - // Enable the clear state flag - @logger.injectLambdaContext({ clearState: true }) - public async handler(_event: any, _context: any): Promise { - // Persistent attributes added inside the handler will NOT be cached - // across invocations - if (event['special_key'] === '123456'){ - logger.appendKeys({ - details: { special_key: '123456' } - }); - } - logger.debug('This is a DEBUG log'); + // Enable the clear state flag + @logger.injectLambdaContext({ clearState: true }) + public async handler(event: unknown, _context: unknown): Promise { + // Persistent attributes added inside the handler will NOT be cached + // across invocations + if (event['special_key'] === '123456'){ + logger.appendKeys({ + details: { special_key: '123456' } + }); } + logger.debug('This is a DEBUG log'); + } } diff --git a/docs/snippets/logger/clearStateMiddy.ts b/docs/snippets/logger/clearStateMiddy.ts index 2c68403d22..f9e1f55ff7 100644 --- a/docs/snippets/logger/clearStateMiddy.ts +++ b/docs/snippets/logger/clearStateMiddy.ts @@ -4,24 +4,24 @@ import middy from '@middy/core'; // Persistent attributes added outside the handler will be // cached across invocations const logger = new Logger({ - logLevel: 'DEBUG', - persistentLogAttributes: { - foo: "bar", - biz: "baz" - } + logLevel: 'DEBUG', + persistentLogAttributes: { + foo: 'bar', + biz: 'baz' + } }); -const lambdaHandler = async (event: { special_key: string }, _context: any): Promise => { - // Persistent attributes added inside the handler will NOT be cached - // across invocations - if (event['special_key'] === '123456') { - logger.appendKeys({ - details: { special_key: event['special_key'] } - }); - } - logger.debug('This is a DEBUG log'); +const lambdaHandler = async (event: { special_key: string }, _context: unknown): Promise => { + // Persistent attributes added inside the handler will NOT be cached + // across invocations + if (event['special_key'] === '123456') { + logger.appendKeys({ + details: { special_key: event['special_key'] } + }); + } + logger.debug('This is a DEBUG log'); }; // Enable the clear state flag export const handler = middy(lambdaHandler) - .use(injectLambdaContext(logger, { clearState: true })); \ No newline at end of file + .use(injectLambdaContext(logger, { clearState: true })); \ No newline at end of file diff --git a/docs/snippets/logger/createChild.ts b/docs/snippets/logger/createChild.ts index db18c5b9a3..3535c03336 100644 --- a/docs/snippets/logger/createChild.ts +++ b/docs/snippets/logger/createChild.ts @@ -1,21 +1,28 @@ import { Logger } from '@aws-lambda-powertools/logger'; -// With this logger, all the INFO logs will be printed +// This logger has a service name, some persistent attributes +// and log level set to INFO const logger = new Logger({ - logLevel: 'INFO' + serviceName: 'serverlessAirline', + logLevel: 'INFO', + persistentLogAttributes: { + aws_account_id: '123456789012', + aws_region: 'eu-west-1', + }, }); -// With this logger, only the ERROR logs will be printed +// This other logger inherits all the parent's attributes +// but the log level, which is now set to ERROR const childLogger = logger.createChild({ - logLevel: 'ERROR' + logLevel: 'ERROR' }); -export const handler = async (_event: any, _context: any): Promise => { +export const handler = async (_event: unknown, _context: unknown): Promise => { - logger.info('This is an INFO log, from the parent logger'); - logger.error('This is an ERROR log, from the parent logger'); + logger.info('This is an INFO log, from the parent logger'); + logger.error('This is an ERROR log, from the parent logger'); - childLogger.info('This is an INFO log, from the child logger'); - childLogger.error('This is an ERROR log, from the child logger'); + childLogger.info('This is an INFO log, from the child logger'); + childLogger.error('This is an ERROR log, from the child logger'); }; \ No newline at end of file diff --git a/docs/snippets/logger/decorator.ts b/docs/snippets/logger/decorator.ts index 92122a691b..0e725bd517 100644 --- a/docs/snippets/logger/decorator.ts +++ b/docs/snippets/logger/decorator.ts @@ -4,11 +4,11 @@ import { LambdaInterface } from '@aws-lambda-powertools/commons'; const logger = new Logger(); class Lambda implements LambdaInterface { - // Decorate your handler class method - @logger.injectLambdaContext() - public async handler(_event: any, _context: any): Promise { - logger.info('This is an INFO log with some context'); - } + // Decorate your handler class method + @logger.injectLambdaContext() + public async handler(_event: unknown, _context: unknown): Promise { + logger.info('This is an INFO log with some context'); + } } diff --git a/docs/snippets/logger/eventDecorator.ts b/docs/snippets/logger/eventDecorator.ts index 57d8ce927c..d99668a04b 100644 --- a/docs/snippets/logger/eventDecorator.ts +++ b/docs/snippets/logger/eventDecorator.ts @@ -4,11 +4,11 @@ import { LambdaInterface } from '@aws-lambda-powertools/commons'; const logger = new Logger(); class Lambda implements LambdaInterface { - // Set the log event flag to true - @logger.injectLambdaContext({ logEvent: true }) - public async handler(_event: any, _context: any): Promise { - logger.info('This is an INFO log with some context'); - } + // Set the log event flag to true + @logger.injectLambdaContext({ logEvent: true }) + public async handler(_event: unknown, _context: unknown): Promise { + logger.info('This is an INFO log with some context'); + } } diff --git a/docs/snippets/logger/eventMiddy.ts b/docs/snippets/logger/eventMiddy.ts index 34c68207fb..4118903d33 100644 --- a/docs/snippets/logger/eventMiddy.ts +++ b/docs/snippets/logger/eventMiddy.ts @@ -3,9 +3,9 @@ import middy from '@middy/core'; const logger = new Logger(); -const lambdaHandler = async (_event: any, _context: any): Promise => { - logger.info('This is an INFO log with some context'); +const lambdaHandler = async (_event: unknown, _context: unknown): Promise => { + logger.info('This is an INFO log with some context'); }; export const handler = middy(lambdaHandler) - .use(injectLambdaContext(logger, { logEvent: true })); \ No newline at end of file + .use(injectLambdaContext(logger, { logEvent: true })); \ No newline at end of file diff --git a/docs/snippets/logger/extraData.ts b/docs/snippets/logger/extraData.ts index fd315e3f2e..5a536307d8 100644 --- a/docs/snippets/logger/extraData.ts +++ b/docs/snippets/logger/extraData.ts @@ -2,37 +2,37 @@ import { Logger } from '@aws-lambda-powertools/logger'; const logger = new Logger(); -export const handler = async (event: any, _context: any): Promise => { +export const handler = async (event: unknown, _context: unknown): Promise => { - const myImportantVariable = { - foo: 'bar' - }; + const myImportantVariable = { + foo: 'bar' + }; - // Log additional data in single log items + // Log additional data in single log items - // As second parameter - logger.info('This is a log with an extra variable', { data: myImportantVariable }); + // As second parameter + logger.info('This is a log with an extra variable', { data: myImportantVariable }); - // You can also pass multiple parameters containing arbitrary objects - logger.info('This is a log with 3 extra objects', - { data: myImportantVariable }, - { correlationIds: { myCustomCorrelationId: 'foo-bar-baz' } }, - { lambdaEvent: event } - ); + // You can also pass multiple parameters containing arbitrary objects + logger.info('This is a log with 3 extra objects', + { data: myImportantVariable }, + { correlationIds: { myCustomCorrelationId: 'foo-bar-baz' } }, + { lambdaEvent: event } + ); - // Simply pass a string for logging additional data - logger.info('This is a log with additional string value', 'string value'); + // Simply pass a string for logging additional data + logger.info('This is a log with additional string value', 'string value'); - // Directly passing an object containing both the message and the additional info - const logObject = { - message: 'This is a log message', - additionalValue: 42 - }; + // Directly passing an object containing both the message and the additional info + const logObject = { + message: 'This is a log message', + additionalValue: 42 + }; - logger.info(logObject); + logger.info(logObject); - return { - foo: 'bar' - }; + return { + foo: 'bar' + }; }; \ No newline at end of file diff --git a/docs/snippets/logger/logError.ts b/docs/snippets/logger/logError.ts index c41c4a58a5..230fb7cbe7 100644 --- a/docs/snippets/logger/logError.ts +++ b/docs/snippets/logger/logError.ts @@ -2,20 +2,20 @@ import { Logger } from '@aws-lambda-powertools/logger'; const logger = new Logger(); -export const handler = async (_event: any, _context: any): Promise => { +export const handler = async (_event: unknown, _context: unknown): Promise => { - try { - throw new Error('Unexpected error #1'); - } catch (error) { - // Log information about the error using the default "error" key - logger.error('This is the first error', error as Error); - } + try { + throw new Error('Unexpected error #1'); + } catch (error) { + // Log information about the error using the default "error" key + logger.error('This is the first error', error as Error); + } - try { - throw new Error('Unexpected error #2'); - } catch (error) { - // Log information about the error using a custom "myCustomErrorKey" key - logger.error('This is the second error', { myCustomErrorKey: error as Error } ); - } + try { + throw new Error('Unexpected error #2'); + } catch (error) { + // Log information about the error using a custom "myCustomErrorKey" key + logger.error('This is the second error', { myCustomErrorKey: error as Error } ); + } }; \ No newline at end of file diff --git a/docs/snippets/logger/logSampling.ts b/docs/snippets/logger/logSampling.ts index eea4af5f07..4b566f33ec 100644 --- a/docs/snippets/logger/logSampling.ts +++ b/docs/snippets/logger/logSampling.ts @@ -2,23 +2,23 @@ import { Logger } from '@aws-lambda-powertools/logger'; // Notice the log level set to 'ERROR' const logger = new Logger({ - logLevel: 'ERROR', - sampleRateValue: 0.5 + logLevel: 'ERROR', + sampleRateValue: 0.5 }); -export const handler = async (_event: any, _context: any): Promise => { +export const handler = async (_event: unknown, _context: unknown): Promise => { - // This log item (equal to log level 'ERROR') will be printed to standard output - // in all Lambda invocations - logger.error('This is an ERROR log'); + // This log item (equal to log level 'ERROR') will be printed to standard output + // in all Lambda invocations + logger.error('This is an ERROR log'); - // These log items (below the log level 'ERROR') have ~50% chance - // of being printed in a Lambda invocation - logger.debug('This is a DEBUG log that has 50% chance of being printed'); - logger.info('This is an INFO log that has 50% chance of being printed'); - logger.warn('This is a WARN log that has 50% chance of being printed'); + // These log items (below the log level 'ERROR') have ~50% chance + // of being printed in a Lambda invocation + logger.debug('This is a DEBUG log that has 50% chance of being printed'); + logger.info('This is an INFO log that has 50% chance of being printed'); + logger.warn('This is a WARN log that has 50% chance of being printed'); - // Optional: refresh sample rate calculation on runtime - // logger.refreshSampleRateCalculation(); + // Optional: refresh sample rate calculation on runtime + // logger.refreshSampleRateCalculation(); }; \ No newline at end of file diff --git a/docs/snippets/logger/manual.ts b/docs/snippets/logger/manual.ts index e8544919b9..b7c271be35 100644 --- a/docs/snippets/logger/manual.ts +++ b/docs/snippets/logger/manual.ts @@ -4,8 +4,8 @@ const logger = new Logger(); export const handler = async (_event, context): Promise => { - logger.addContext(context); + logger.addContext(context); - logger.info('This is an INFO log with some context'); + logger.info('This is an INFO log with some context'); }; \ No newline at end of file diff --git a/docs/snippets/logger/middy.ts b/docs/snippets/logger/middy.ts index 5d48839133..83b723bf7f 100644 --- a/docs/snippets/logger/middy.ts +++ b/docs/snippets/logger/middy.ts @@ -3,9 +3,9 @@ import middy from '@middy/core'; const logger = new Logger(); -const lambdaHandler = async (_event: any, _context: any): Promise => { - logger.info('This is an INFO log with some context'); +const lambdaHandler = async (_event: unknown, _context: unknown): Promise => { + logger.info('This is an INFO log with some context'); }; export const handler = middy(lambdaHandler) - .use(injectLambdaContext(logger)); \ No newline at end of file + .use(injectLambdaContext(logger)); \ No newline at end of file diff --git a/docs/snippets/logger/sam.ts b/docs/snippets/logger/sam.ts index 0970b4e125..12cc9cc7eb 100644 --- a/docs/snippets/logger/sam.ts +++ b/docs/snippets/logger/sam.ts @@ -2,6 +2,7 @@ import { Logger } from '@aws-lambda-powertools/logger'; // Logger parameters fetched from the environment variables (see template.yaml tab) const logger = new Logger(); +logger.info('Hello World'); // You can also pass the parameters in the constructor // const logger = new Logger({ diff --git a/docs/snippets/logger/unitTesting.ts b/docs/snippets/logger/unitTesting.ts index b47352ab20..4c09ab7285 100644 --- a/docs/snippets/logger/unitTesting.ts +++ b/docs/snippets/logger/unitTesting.ts @@ -1,25 +1,12 @@ -const dummyContext = { - callbackWaitsForEmptyEventLoop: true, - functionVersion: '$LATEST', - functionName: 'foo-bar-function', - memoryLimitInMB: '128', - logGroupName: '/aws/lambda/foo-bar-function', - logStreamName: '2021/03/09/[$LATEST]abcdef123456abcdef123456abcdef123456', - invokedFunctionArn: 'arn:aws:lambda:eu-west-1:123456789012:function:foo-bar-function', - awsRequestId: 'c6af9ac6-7b61-11e6-9a41-93e812345678', - getRemainingTimeInMillis: () => 1234, - done: () => console.log('Done!'), - fail: () => console.log('Failed!'), - succeed: () => console.log('Succeeded!'), -}; +import { ContextExamples as dummyContext } from '@aws-lambda-powertools/commons'; describe('MyUnitTest', () => { - test('Lambda invoked successfully', async () => { + test('Lambda invoked successfully', async () => { - const testEvent = { test: 'test' }; - await handler(testEvent, dummyContext); + const testEvent = { test: 'test' }; + await handler(testEvent, dummyContext); - }); + }); }); \ No newline at end of file diff --git a/docs/snippets/metrics/addMetadata.ts b/docs/snippets/metrics/addMetadata.ts new file mode 100644 index 0000000000..adbe592b90 --- /dev/null +++ b/docs/snippets/metrics/addMetadata.ts @@ -0,0 +1,12 @@ +import { Metrics, MetricUnits, logMetrics } from '@aws-lambda-powertools/metrics'; +import middy from '@middy/core'; + +const metrics = new Metrics({ namespace: 'serverlessAirline', serviceName: 'orders' }); + +const lambdaHandler = async (_event: unknown, _context: unknown): Promise => { + metrics.addMetric('successfulBooking', MetricUnits.Count, 1); + metrics.addMetadata('bookingId', '7051cd10-6283-11ec-90d6-0242ac120003'); +}; + +export const handler = middy(lambdaHandler) + .use(logMetrics(metrics)); \ No newline at end of file diff --git a/docs/snippets/metrics/basicUsage.ts b/docs/snippets/metrics/basicUsage.ts new file mode 100644 index 0000000000..15388d2c82 --- /dev/null +++ b/docs/snippets/metrics/basicUsage.ts @@ -0,0 +1,7 @@ +import { Metrics, MetricUnits } from '@aws-lambda-powertools/metrics'; + +const metrics = new Metrics({ namespace: 'serverlessAirline', serviceName: 'orders' }); + +export const handler = async (_event, _context): Promise => { + metrics.addMetric('successfulBooking', MetricUnits.Count, 1); +}; \ No newline at end of file diff --git a/docs/snippets/metrics/captureColdStartMetricDecorator.ts b/docs/snippets/metrics/captureColdStartMetricDecorator.ts new file mode 100644 index 0000000000..8817d6a799 --- /dev/null +++ b/docs/snippets/metrics/captureColdStartMetricDecorator.ts @@ -0,0 +1,12 @@ +import { Metrics, MetricUnits } from '@aws-lambda-powertools/metrics'; +import { LambdaInterface } from '@aws-lambda-powertools/commons'; + +const metrics = new Metrics({ namespace: 'serverlessAirline', serviceName: 'orders' }); + +export class MyFunction implements LambdaInterface { + + @metrics.logMetrics({ captureColdStartMetric: true }) + public async handler(_event: unknown, _context: unknown): Promise { + metrics.addMetric('successfulBooking', MetricUnits.Count, 1); + } +} \ No newline at end of file diff --git a/docs/snippets/metrics/captureColdStartMetricMiddy.ts b/docs/snippets/metrics/captureColdStartMetricMiddy.ts new file mode 100644 index 0000000000..3b84cb7194 --- /dev/null +++ b/docs/snippets/metrics/captureColdStartMetricMiddy.ts @@ -0,0 +1,11 @@ +import { Metrics, MetricUnits, logMetrics } from '@aws-lambda-powertools/metrics'; +import middy from '@middy/core'; + +const metrics = new Metrics({ namespace: 'serverlessAirline', serviceName: 'orders' }); + +const lambdaHandler = async (_event: unknown, _context: unknown): Promise => { + metrics.addMetric('successfulBooking', MetricUnits.Count, 1); +}; + +export const handler = middy(lambdaHandler) + .use(logMetrics(metrics, { captureColdStartMetric: true })); \ No newline at end of file diff --git a/docs/snippets/metrics/createMetrics.ts b/docs/snippets/metrics/createMetrics.ts new file mode 100644 index 0000000000..640afe1ada --- /dev/null +++ b/docs/snippets/metrics/createMetrics.ts @@ -0,0 +1,8 @@ +import { Metrics, MetricUnits } from '@aws-lambda-powertools/metrics'; + +const metrics = new Metrics({ namespace: 'serverlessAirline', serviceName: 'orders' }); + +export const handler = async (_event: unknown, _context: unknown): Promise => { + metrics.addMetric('successfulBooking', MetricUnits.Count, 1); + metrics.publishStoredMetrics(); +}; \ No newline at end of file diff --git a/docs/snippets/metrics/customDimensions.ts b/docs/snippets/metrics/customDimensions.ts new file mode 100644 index 0000000000..95d25f9cab --- /dev/null +++ b/docs/snippets/metrics/customDimensions.ts @@ -0,0 +1,9 @@ +import { Metrics, MetricUnits } from '@aws-lambda-powertools/metrics'; + +const metrics = new Metrics({ namespace: 'serverlessAirline', serviceName: 'orders' }); + +export const handler = async (_event: unknown, _context: unknown): Promise => { + metrics.addDimension('environment', 'prod'); + metrics.addMetric('successfulBooking', MetricUnits.Count, 1); + metrics.publishStoredMetrics(); +}; \ No newline at end of file diff --git a/docs/snippets/metrics/decorator.ts b/docs/snippets/metrics/decorator.ts new file mode 100644 index 0000000000..f64d842d5e --- /dev/null +++ b/docs/snippets/metrics/decorator.ts @@ -0,0 +1,15 @@ +import { Metrics, MetricUnits } from '@aws-lambda-powertools/metrics'; +import { LambdaInterface } from '@aws-lambda-powertools/commons'; + +const metrics = new Metrics({ namespace: 'serverlessAirline', serviceName: 'orders' }); + +class Lambda implements LambdaInterface { + + @metrics.logMetrics() + public async handler(_event: unknown, _context: unknown): Promise { + metrics.addMetric('successfulBooking', MetricUnits.Count, 1); + } +} + +const handlerClass = new Lambda(); +export const handler = handlerClass.handler.bind(handlerClass); // (1) \ No newline at end of file diff --git a/docs/snippets/metrics/defaultDimensions.ts b/docs/snippets/metrics/defaultDimensions.ts new file mode 100644 index 0000000000..509bdda170 --- /dev/null +++ b/docs/snippets/metrics/defaultDimensions.ts @@ -0,0 +1,11 @@ +import { Metrics, MetricUnits } from '@aws-lambda-powertools/metrics'; + +const metrics = new Metrics({ + namespace: 'serverlessAirline', + serviceName: 'orders', + defaultDimensions: { 'environment': 'prod', 'foo': 'bar' } +}); + +export const handler = async (_event: unknown, _context: unknown): Promise => { + metrics.addMetric('successfulBooking', MetricUnits.Count, 1); +}; \ No newline at end of file diff --git a/docs/snippets/metrics/defaultDimensionsDecorator.ts b/docs/snippets/metrics/defaultDimensionsDecorator.ts new file mode 100644 index 0000000000..d31c8cde6b --- /dev/null +++ b/docs/snippets/metrics/defaultDimensionsDecorator.ts @@ -0,0 +1,16 @@ +import { Metrics, MetricUnits } from '@aws-lambda-powertools/metrics'; +import { LambdaInterface } from '@aws-lambda-powertools/commons'; + +const metrics = new Metrics({ namespace: 'serverlessAirline', serviceName: 'orders' }); +const DEFAULT_DIMENSIONS = { 'environment': 'prod', 'foo': 'bar' }; + +export class Lambda implements LambdaInterface { + // Decorate your handler class method + @metrics.logMetrics({ defaultDimensions: DEFAULT_DIMENSIONS }) + public async handler(_event: unknown, _context: unknown): Promise { + metrics.addMetric('successfulBooking', MetricUnits.Count, 1); + } +} + +const handlerClass = new Lambda(); +export const handler = handlerClass.handler.bind(handlerClass); // (1) \ No newline at end of file diff --git a/docs/snippets/metrics/defaultDimensionsMiddy.ts b/docs/snippets/metrics/defaultDimensionsMiddy.ts new file mode 100644 index 0000000000..dc9035e937 --- /dev/null +++ b/docs/snippets/metrics/defaultDimensionsMiddy.ts @@ -0,0 +1,13 @@ +import { Metrics, MetricUnits, logMetrics } from '@aws-lambda-powertools/metrics'; +import middy from '@middy/core'; + +const metrics = new Metrics({ namespace: 'serverlessAirline', serviceName: 'orders' }); + +const lambdaHandler = async (_event: unknown, _context: unknown): Promise => { + metrics.addMetric('successfulBooking', MetricUnits.Count, 1); +}; + +// Wrap the handler with middy +export const handler = middy(lambdaHandler) +// Use the middleware by passing the Metrics instance as a parameter + .use(logMetrics(metrics, { defaultDimensions:{ 'environment': 'prod', 'foo': 'bar' } })); \ No newline at end of file diff --git a/docs/snippets/metrics/manual.ts b/docs/snippets/metrics/manual.ts new file mode 100644 index 0000000000..7df2301fdd --- /dev/null +++ b/docs/snippets/metrics/manual.ts @@ -0,0 +1,8 @@ +import { Metrics, MetricUnits } from '@aws-lambda-powertools/metrics'; + +const metrics = new Metrics({ namespace: 'serverlessAirline', serviceName: 'orders' }); + +export const handler = async (_event: unknown, _context: unknown): Promise => { + metrics.addMetric('successfulBooking', MetricUnits.Count, 10); + metrics.publishStoredMetrics(); +}; \ No newline at end of file diff --git a/docs/snippets/metrics/middy.ts b/docs/snippets/metrics/middy.ts new file mode 100644 index 0000000000..088186002b --- /dev/null +++ b/docs/snippets/metrics/middy.ts @@ -0,0 +1,11 @@ +import { Metrics, MetricUnits, logMetrics } from '@aws-lambda-powertools/metrics'; +import middy from '@middy/core'; + +const metrics = new Metrics({ namespace: 'serverlessAirline', serviceName: 'orders' }); + +const lambdaHandler = async (_event: unknown, _context: unknown): Promise => { + metrics.addMetric('successfulBooking', MetricUnits.Count, 1); +}; + +export const handler = middy(lambdaHandler) + .use(logMetrics(metrics)); \ No newline at end of file diff --git a/docs/snippets/metrics/multiValueMetrics.ts b/docs/snippets/metrics/multiValueMetrics.ts new file mode 100644 index 0000000000..6214940c39 --- /dev/null +++ b/docs/snippets/metrics/multiValueMetrics.ts @@ -0,0 +1,9 @@ +import { Metrics, MetricUnits } from '@aws-lambda-powertools/metrics'; + +const metrics = new Metrics({ namespace:'serverlessAirline', serviceName:'orders' }); + +export const handler = async (_event: unknown, _context: unknown): Promise => { + metrics.addMetric('performedActionA', MetricUnits.Count, 2); + // do something else... + metrics.addMetric('performedActionA', MetricUnits.Count, 1); +}; \ No newline at end of file diff --git a/docs/snippets/metrics/sam.ts b/docs/snippets/metrics/sam.ts new file mode 100644 index 0000000000..8acd0b6ba5 --- /dev/null +++ b/docs/snippets/metrics/sam.ts @@ -0,0 +1,11 @@ +import { Metrics, MetricUnits } from '@aws-lambda-powertools/metrics'; + +// Metrics parameters fetched from the environment variables (see template.yaml tab) +const metrics = new Metrics(); +metrics.addMetric('successfulBooking', MetricUnits.Count, 1); + +// You can also pass the parameters in the constructor +// const metrics = new Metrics({ +// namespace: 'serverlessAirline', +// serviceName: 'orders' +// }); \ No newline at end of file diff --git a/docs/snippets/metrics/setDefaultDimensions.ts b/docs/snippets/metrics/setDefaultDimensions.ts new file mode 100644 index 0000000000..1491d709ae --- /dev/null +++ b/docs/snippets/metrics/setDefaultDimensions.ts @@ -0,0 +1,8 @@ +import { Metrics, MetricUnits } from '@aws-lambda-powertools/metrics'; + +const metrics = new Metrics({ namespace: 'serverlessAirline', serviceName: 'orders' }); +metrics.setDefaultDimensions({ 'environment': 'prod', 'foo': 'bar' }); + +export const handler = async (_event: unknown, _context: unknown): Promise => { + metrics.addMetric('successfulBooking', MetricUnits.Count, 1); +}; \ No newline at end of file diff --git a/docs/snippets/metrics/singleMetricDifferentDimsDecorator.ts b/docs/snippets/metrics/singleMetricDifferentDimsDecorator.ts new file mode 100644 index 0000000000..758a1aba2c --- /dev/null +++ b/docs/snippets/metrics/singleMetricDifferentDimsDecorator.ts @@ -0,0 +1,22 @@ +import { Metrics, MetricUnits } from '@aws-lambda-powertools/metrics'; +import { LambdaInterface } from '@aws-lambda-powertools/commons'; + +const metrics = new Metrics({ namespace: 'serverlessAirline', serviceName: 'orders' }); + +class Lambda implements LambdaInterface { + + @metrics.logMetrics() + public async handler(_event: unknown, _context: unknown): Promise { + metrics.addDimension('metricUnit', 'milliseconds'); + // This metric will have the "metricUnit" dimension, and no "metricType" dimension: + metrics.addMetric('latency', MetricUnits.Milliseconds, 56); + + const singleMetric = metrics.singleMetric(); + // This metric will have the "metricType" dimension, and no "metricUnit" dimension: + singleMetric.addDimension('metricType', 'business'); + singleMetric.addMetric('orderSubmitted', MetricUnits.Count, 1); + } +} + +const handlerClass = new Lambda(); +export const handler = handlerClass.handler.bind(handlerClass); // (1) \ No newline at end of file diff --git a/docs/snippets/metrics/singleMetricDifferentDimsMiddy.ts b/docs/snippets/metrics/singleMetricDifferentDimsMiddy.ts new file mode 100644 index 0000000000..62ed3863b7 --- /dev/null +++ b/docs/snippets/metrics/singleMetricDifferentDimsMiddy.ts @@ -0,0 +1,18 @@ +import { Metrics, MetricUnits, logMetrics } from '@aws-lambda-powertools/metrics'; +import middy from '@middy/core'; + +const metrics = new Metrics({ namespace: 'serverlessAirline', serviceName: 'orders' }); + +const lambdaHandler = async (_event: unknown, _context: unknown): Promise => { + metrics.addDimension('metricUnit', 'milliseconds'); + // This metric will have the "metricUnit" dimension, and no "metricType" dimension: + metrics.addMetric('latency', MetricUnits.Milliseconds, 56); + + const singleMetric = metrics.singleMetric(); + // This metric will have the "metricType" dimension, and no "metricUnit" dimension: + singleMetric.addDimension('metricType', 'business'); + singleMetric.addMetric('orderSubmitted', MetricUnits.Count, 1); +}; + +export const handler = middy(lambdaHandler) + .use(logMetrics(metrics)); \ No newline at end of file diff --git a/docs/snippets/metrics/throwOnEmptyMetrics.ts b/docs/snippets/metrics/throwOnEmptyMetrics.ts new file mode 100644 index 0000000000..3b9784f7b1 --- /dev/null +++ b/docs/snippets/metrics/throwOnEmptyMetrics.ts @@ -0,0 +1,11 @@ +import { Metrics, MetricUnits, logMetrics } from '@aws-lambda-powertools/metrics'; +import middy from '@middy/core'; + +const metrics = new Metrics({ namespace: 'serverlessAirline', serviceName: 'orders' }); + +const lambdaHandler = async (_event: unknown, _context: unknown): Promise => { + metrics.addMetric('successfulBooking', MetricUnits.Count, 1); +}; + +export const handler = middy(lambdaHandler) + .use(logMetrics(metrics, { throwOnEmptyMetrics: true })); \ No newline at end of file diff --git a/docs/snippets/package.json b/docs/snippets/package.json new file mode 100644 index 0000000000..8779dea179 --- /dev/null +++ b/docs/snippets/package.json @@ -0,0 +1,34 @@ +{ + "name": "docs", + "version": "0.0.1", + "description": "A collection code snippets for the AWS Lambda Powertools for TypeScript docs", + "author": { + "name": "Amazon Web Services", + "url": "https://aws.amazon.com" + }, + "scripts": { + "test": "echo 'Not Applicable'", + "test:e2e": "echo 'Not Applicable'", + "package": "echo 'Not applicable'", + "build": "echo 'Not Applicable'", + "lint": "eslint --ext .ts --no-error-on-unmatched-pattern logger tracer metrics parameters", + "lint-fix": "eslint --fix --ext .ts --no-error-on-unmatched-pattern logger tracer metrics parameters" + }, + "license": "MIT-0", + "repository": { + "type": "git", + "url": "git+https://github.com/awslabs/aws-lambda-powertools-typescript.git" + }, + "bugs": { + "url": "https://github.com/awslabs/aws-lambda-powertools-typescript/issues" + }, + "homepage": "https://github.com/awslabs/aws-lambda-powertools-typescript#readme", + "devDependencies": { + "@aws-sdk/client-appconfigdata": "^3.245.0", + "@aws-sdk/client-dynamodb": "^3.245.0", + "@aws-sdk/client-secrets-manager": "^3.250.0", + "@aws-sdk/client-ssm": "^3.245.0", + "@aws-sdk/util-dynamodb": "^3.245.0", + "axios": "^1.2.4" + } +} diff --git a/docs/snippets/tracer/accessRootTraceId.ts b/docs/snippets/tracer/accessRootTraceId.ts index c385e39b7c..f40b797346 100644 --- a/docs/snippets/tracer/accessRootTraceId.ts +++ b/docs/snippets/tracer/accessRootTraceId.ts @@ -2,17 +2,17 @@ import { Tracer } from '@aws-lambda-powertools/tracer'; const tracer = new Tracer({ serviceName: 'serverlessAirline' }); -export const handler = async (event: unknown, context: Context): Promise => { - try { +export const handler = async (_event: unknown, _context: unknown): Promise => { + try { - } catch (err) { - const rootTraceId = tracer.getRootXrayTraceId(); + } catch (err) { + const rootTraceId = tracer.getRootXrayTraceId(); - // Example of returning an error response - return { - statusCode: 500, - body: `Internal Error - Please contact support and quote the following id: ${rootTraceId}`, - headers: { '_X_AMZN_TRACE_ID': rootTraceId }, - }; - } + // Example of returning an error response + return { + statusCode: 500, + body: `Internal Error - Please contact support and quote the following id: ${rootTraceId}`, + headers: { '_X_AMZN_TRACE_ID': rootTraceId }, + }; + } }; \ No newline at end of file diff --git a/docs/snippets/tracer/basicUsage.ts b/docs/snippets/tracer/basicUsage.ts index a8c830e78b..b44814eb41 100644 --- a/docs/snippets/tracer/basicUsage.ts +++ b/docs/snippets/tracer/basicUsage.ts @@ -3,5 +3,5 @@ import { Tracer } from '@aws-lambda-powertools/tracer'; const tracer = new Tracer({ serviceName: 'serverlessAirline' }); export const handler = async (_event, _context): Promise => { - // ... + tracer.getSegment(); }; \ No newline at end of file diff --git a/docs/snippets/tracer/captureAWS.ts b/docs/snippets/tracer/captureAWS.ts index b94151c014..5155f569b9 100644 --- a/docs/snippets/tracer/captureAWS.ts +++ b/docs/snippets/tracer/captureAWS.ts @@ -2,4 +2,4 @@ import { S3 } from 'aws-sdk'; import { Tracer } from '@aws-lambda-powertools/tracer'; const tracer = new Tracer({ serviceName: 'serverlessAirline' }); -const s3 = tracer.captureAWSClient(new S3()); \ No newline at end of file +tracer.captureAWSClient(new S3()); \ No newline at end of file diff --git a/docs/snippets/tracer/captureAWSAll.ts b/docs/snippets/tracer/captureAWSAll.ts index d758e1dd7c..a5aca36989 100644 --- a/docs/snippets/tracer/captureAWSAll.ts +++ b/docs/snippets/tracer/captureAWSAll.ts @@ -1,4 +1,5 @@ import { Tracer } from '@aws-lambda-powertools/tracer'; +import AWS from 'aws-sdk'; const tracer = new Tracer({ serviceName: 'serverlessAirline' }); -const AWS = tracer.captureAWS(require('aws-sdk')); \ No newline at end of file +tracer.captureAWS(AWS); \ No newline at end of file diff --git a/docs/snippets/tracer/captureAWSv3.ts b/docs/snippets/tracer/captureAWSv3.ts index 8270d10c0a..dd1ca6870a 100644 --- a/docs/snippets/tracer/captureAWSv3.ts +++ b/docs/snippets/tracer/captureAWSv3.ts @@ -1,5 +1,5 @@ -import { S3Client } from '@aws-sdk/client-s3'; +import { SecretsManagerClient } from '@aws-sdk/client-secrets-manager'; import { Tracer } from '@aws-lambda-powertools/tracer'; const tracer = new Tracer({ serviceName: 'serverlessAirline' }); -const client = tracer.captureAWSv3Client(new S3Client({})); \ No newline at end of file +tracer.captureAWSv3Client(new SecretsManagerClient({})); \ No newline at end of file diff --git a/docs/snippets/tracer/captureHTTP.ts b/docs/snippets/tracer/captureHTTP.ts index cf4cae3cdb..15ca0adef4 100644 --- a/docs/snippets/tracer/captureHTTP.ts +++ b/docs/snippets/tracer/captureHTTP.ts @@ -3,6 +3,7 @@ import axios from 'axios'; // (1) const tracer = new Tracer({ serviceName: 'serverlessAirline' }); -export const handler = async (event: unknown, context: Context): Promise => { - await axios.get('https://httpbin.org/status/200'); +export const handler = async (_event: unknown, _context: unknown): Promise => { + const { data } = await axios.get('https://httpbin.org/status/200'); + tracer.addResponseAsMetadata(data); }; \ No newline at end of file diff --git a/docs/snippets/tracer/captureMethodDecorator.ts b/docs/snippets/tracer/captureMethodDecorator.ts index 6c580f3e5d..69b997b265 100644 --- a/docs/snippets/tracer/captureMethodDecorator.ts +++ b/docs/snippets/tracer/captureMethodDecorator.ts @@ -4,16 +4,16 @@ import { LambdaInterface } from '@aws-lambda-powertools/commons'; const tracer = new Tracer({ serviceName: 'serverlessAirline' }); class Lambda implements LambdaInterface { - // Decorate your class method - @tracer.captureMethod() // (1) - public async getChargeId(): Promise { - /* ... */ - return 'foo bar'; - } + // Decorate your class method + @tracer.captureMethod() // (1) + public async getChargeId(): Promise { + /* ... */ + return 'foo bar'; + } - public async handler(_event: any, _context: any): Promise { - /* ... */ - } + public async handler(_event: unknown, _context: unknown): Promise { + await this.getChargeId(); + } } const handlerClass = new Lambda(); diff --git a/docs/snippets/tracer/captureMethodManual.ts b/docs/snippets/tracer/captureMethodManual.ts index af8c0a1dc8..8e8a6e07ed 100644 --- a/docs/snippets/tracer/captureMethodManual.ts +++ b/docs/snippets/tracer/captureMethodManual.ts @@ -3,32 +3,31 @@ import { Tracer } from '@aws-lambda-powertools/tracer'; const tracer = new Tracer({ serviceName: 'serverlessAirline' }); const getChargeId = async (): Promise => { - const parentSubsegment = tracer.getSegment(); // This is the subsegment currently active - // Create subsegment for the function & set it as active - const subsegment = parentSubsegment.addNewSubsegment(`### chargeId`); - tracer.setSegment(subsegment); + const parentSubsegment = tracer.getSegment(); // This is the subsegment currently active + // Create subsegment for the function & set it as active + const subsegment = parentSubsegment.addNewSubsegment(`### chargeId`); + tracer.setSegment(subsegment); - let res; - try { - /* ... */ - // Add the response as metadata - tracer.addResponseAsMetadata(res, 'chargeId'); - } catch (err) { - // Add the error as metadata - tracer.addErrorAsMetadata(err as Error); - throw err; - } + let res; + try { + /* ... */ + // Add the response as metadata + tracer.addResponseAsMetadata(res, 'chargeId'); + } catch (err) { + // Add the error as metadata + tracer.addErrorAsMetadata(err as Error); + throw err; + } - // Close subsegment (the AWS Lambda one is closed automatically) - subsegment.close(); - // Set the facade segment as active again - tracer.setSegment(parentSubsegment); + // Close subsegment (the AWS Lambda one is closed automatically) + subsegment.close(); + // Set the facade segment as active again + tracer.setSegment(parentSubsegment); - return res; + return res; }; -export const handler = async (_event: any, _context: any): Promise => { - const chargeId = getChargeId(); - const payment = collectPayment(chargeId); - /* ... */ +export const handler = async (_event: unknown, _context: unknown): Promise => { + await getChargeId(); + }; \ No newline at end of file diff --git a/docs/snippets/tracer/decorator.ts b/docs/snippets/tracer/decorator.ts index 1e17ea6af0..5373433f6f 100644 --- a/docs/snippets/tracer/decorator.ts +++ b/docs/snippets/tracer/decorator.ts @@ -4,11 +4,11 @@ import { LambdaInterface } from '@aws-lambda-powertools/commons'; const tracer = new Tracer({ serviceName: 'serverlessAirline' }); class Lambda implements LambdaInterface { - // Decorate your handler class method - @tracer.captureLambdaHandler() - public async handler(_event: any, _context: any): Promise { - /* ... */ - } + // Decorate your handler class method + @tracer.captureLambdaHandler() + public async handler(_event: unknown, _context: unknown): Promise { + tracer.getSegment(); + } } const handlerClass = new Lambda(); diff --git a/docs/snippets/tracer/disableCaptureResponseHandler.ts b/docs/snippets/tracer/disableCaptureResponseHandler.ts index de9549c22c..0191f51b02 100644 --- a/docs/snippets/tracer/disableCaptureResponseHandler.ts +++ b/docs/snippets/tracer/disableCaptureResponseHandler.ts @@ -4,10 +4,10 @@ import { LambdaInterface } from '@aws-lambda-powertools/commons'; const tracer = new Tracer({ serviceName: 'serverlessAirline' }); class Lambda implements LambdaInterface { - @tracer.captureLambdaHandler({ captureResponse: false }) - async handler(_event: any, _context: any): Promise { - /* ... */ - } + @tracer.captureLambdaHandler({ captureResponse: false }) + public async handler(_event: unknown, _context: unknown): Promise { + tracer.getSegment(); + } } const handlerClass = new Lambda(); diff --git a/docs/snippets/tracer/disableCaptureResponseMethod.ts b/docs/snippets/tracer/disableCaptureResponseMethod.ts index 7386d75338..7828d3b264 100644 --- a/docs/snippets/tracer/disableCaptureResponseMethod.ts +++ b/docs/snippets/tracer/disableCaptureResponseMethod.ts @@ -1,17 +1,18 @@ +import { LambdaInterface } from '@aws-lambda-powertools/commons'; import { Tracer } from '@aws-lambda-powertools/tracer'; const tracer = new Tracer({ serviceName: 'serverlessAirline' }); class Lambda implements LambdaInterface { - @tracer.captureMethod({ captureResponse: false }) - public async getChargeId(): Promise { - /* ... */ - return 'foo bar'; - } + @tracer.captureMethod({ captureResponse: false }) + public async getChargeId(): Promise { + /* ... */ + return 'foo bar'; + } - public async handler(_event: any, _context: any): Promise { - /* ... */ - } + public async handler(_event: unknown, _context: unknown): Promise { + /* ... */ + } } const handlerClass = new Lambda(); diff --git a/docs/snippets/tracer/disableCaptureResponseMiddy.ts b/docs/snippets/tracer/disableCaptureResponseMiddy.ts index b0916d00fc..567b38036a 100644 --- a/docs/snippets/tracer/disableCaptureResponseMiddy.ts +++ b/docs/snippets/tracer/disableCaptureResponseMiddy.ts @@ -3,12 +3,12 @@ import middy from '@middy/core'; const tracer = new Tracer({ serviceName: 'serverlessAirline' }); -const lambdaHandler = async (_event: any, _context: any): Promise => { - /* ... */ +const lambdaHandler = async (_event: unknown, _context: unknown): Promise => { + /* ... */ }; // Wrap the handler with middy export const handler = middy(lambdaHandler) - // Use the middleware by passing the Tracer instance as a parameter, - // but specify the captureResponse option as false. - .use(captureLambdaHandler(tracer, { captureResponse: false })); \ No newline at end of file +// Use the middleware by passing the Tracer instance as a parameter, +// but specify the captureResponse option as false. + .use(captureLambdaHandler(tracer, { captureResponse: false })); \ No newline at end of file diff --git a/docs/snippets/tracer/manual.ts b/docs/snippets/tracer/manual.ts index de0fe064e9..a17be6a900 100644 --- a/docs/snippets/tracer/manual.ts +++ b/docs/snippets/tracer/manual.ts @@ -2,31 +2,30 @@ import { Tracer } from '@aws-lambda-powertools/tracer'; const tracer = new Tracer({ serviceName: 'serverlessAirline' }); -export const handler = async (_event: any, context: any): Promise => { - const segment = tracer.getSegment(); // This is the facade segment (the one that is created by AWS Lambda) - // Create subsegment for the function & set it as active - const subsegment = segment.addNewSubsegment(`## ${process.env._HANDLER}`); - tracer.setSegment(subsegment); +export const handler = async (_event: unknown, _context: unknown): Promise => { + const segment = tracer.getSegment(); // This is the facade segment (the one that is created by AWS Lambda) + // Create subsegment for the function & set it as active + const subsegment = segment.addNewSubsegment(`## ${process.env._HANDLER}`); + tracer.setSegment(subsegment); - // Annotate the subsegment with the cold start & serviceName - tracer.annotateColdStart(); - tracer.addServiceNameAnnotation(); + // Annotate the subsegment with the cold start & serviceName + tracer.annotateColdStart(); + tracer.addServiceNameAnnotation(); + + try { + + // Add the response as metadata + tracer.addResponseAsMetadata({}, process.env._HANDLER); + } catch (err) { + // Add the error as metadata + tracer.addErrorAsMetadata(err as Error); + throw err; + } finally { + // Close subsegment (the AWS Lambda one is closed automatically) + subsegment.close(); + // Set back the facade segment as active again + tracer.setSegment(segment); + } - let res; - try { - /* ... */ - // Add the response as metadata - tracer.addResponseAsMetadata(res, process.env._HANDLER); - } catch (err) { - // Add the error as metadata - tracer.addErrorAsMetadata(err as Error); - throw err; - } finally { - // Close subsegment (the AWS Lambda one is closed automatically) - subsegment.close(); - // Set back the facade segment as active again - tracer.setSegment(segment); - } - - return res; + return {}; }; \ No newline at end of file diff --git a/docs/snippets/tracer/middy.ts b/docs/snippets/tracer/middy.ts index 0318b099f6..0ca33cec20 100644 --- a/docs/snippets/tracer/middy.ts +++ b/docs/snippets/tracer/middy.ts @@ -3,11 +3,11 @@ import middy from '@middy/core'; // (1) const tracer = new Tracer({ serviceName: 'serverlessAirline' }); -const lambdaHandler = async (_event: any, _context: any): Promise => { - /* ... */ +const lambdaHandler = async (_event: unknown, _context: unknown): Promise => { + tracer.putAnnotation('successfulBooking', true); }; // Wrap the handler with middy export const handler = middy(lambdaHandler) - // Use the middleware by passing the Tracer instance as a parameter - .use(captureLambdaHandler(tracer)); \ No newline at end of file +// Use the middleware by passing the Tracer instance as a parameter + .use(captureLambdaHandler(tracer)); \ No newline at end of file diff --git a/docs/snippets/tracer/putAnnotation.ts b/docs/snippets/tracer/putAnnotation.ts index 5b48d831af..399049046b 100644 --- a/docs/snippets/tracer/putAnnotation.ts +++ b/docs/snippets/tracer/putAnnotation.ts @@ -2,6 +2,6 @@ import { Tracer } from '@aws-lambda-powertools/tracer'; const tracer = new Tracer({ serviceName: 'serverlessAirline' }); -export const handler = async (_event: any, _context: any): Promise => { - tracer.putAnnotation('successfulBooking', true); +export const handler = async (_event: unknown, _context: unknown): Promise => { + tracer.putAnnotation('successfulBooking', true); }; \ No newline at end of file diff --git a/docs/snippets/tracer/putMetadata.ts b/docs/snippets/tracer/putMetadata.ts index c69a307373..e9d873a632 100644 --- a/docs/snippets/tracer/putMetadata.ts +++ b/docs/snippets/tracer/putMetadata.ts @@ -2,7 +2,9 @@ import { Tracer } from '@aws-lambda-powertools/tracer'; const tracer = new Tracer({ serviceName: 'serverlessAirline' }); -export const handler = async (_event: any, _context: any): Promise => { - const res; /* ... */ - tracer.putMetadata('paymentResponse', res); +export const handler = async (_event: unknown, _context: unknown): Promise => { + + tracer.putMetadata('paymentResponse', { + 'foo': 'bar' + }); }; \ No newline at end of file diff --git a/docs/snippets/tracer/sam.ts b/docs/snippets/tracer/sam.ts index 881471c80b..407c1ac863 100644 --- a/docs/snippets/tracer/sam.ts +++ b/docs/snippets/tracer/sam.ts @@ -2,6 +2,7 @@ import { Tracer } from '@aws-lambda-powertools/tracer'; // Tracer parameter fetched from the environment variables (see template.yaml tab) const tracer = new Tracer(); +tracer.getSegment(); // You can also pass the parameter in the constructor // const tracer = new Tracer({ diff --git a/docs/utilities/parameters.md b/docs/utilities/parameters.md index 9c659e1293..c9d43e7ccc 100644 --- a/docs/utilities/parameters.md +++ b/docs/utilities/parameters.md @@ -43,7 +43,7 @@ Depending on the provider you want to use, install the library and the correspon === "DynamoDBProvider" ```bash - npm install @aws-lambda-powertools/parameters @aws-sdk/client-dynamodb + npm install @aws-lambda-powertools/parameters @aws-sdk/client-dynamodb @aws-sdk/util-dynamodb ``` ???+ tip diff --git a/examples/cdk/CHANGELOG.md b/examples/cdk/CHANGELOG.md index 3fd2ea7b7d..c740e87e5c 100644 --- a/examples/cdk/CHANGELOG.md +++ b/examples/cdk/CHANGELOG.md @@ -3,6 +3,14 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. +# [1.6.0](https://github.com/awslabs/aws-lambda-powertools-typescript/compare/v1.5.1...v1.6.0) (2023-03-02) + +**Note:** Version bump only for package cdk-sample + + + + + ## [1.5.1](https://github.com/awslabs/aws-lambda-powertools-typescript/compare/v1.5.0...v1.5.1) (2023-01-13) **Note:** Version bump only for package cdk-sample diff --git a/examples/cdk/package-lock.json b/examples/cdk/package-lock.json index 14aafa8ecb..ad83490a26 100644 --- a/examples/cdk/package-lock.json +++ b/examples/cdk/package-lock.json @@ -1,12 +1,12 @@ { "name": "cdk-sample", - "version": "1.5.1", + "version": "1.6.0", "lockfileVersion": 2, "requires": true, "packages": { "": { "name": "cdk-sample", - "version": "1.5.1", + "version": "1.6.0", "license": "MIT-0", "dependencies": { "@middy/core": "^3.6.2", @@ -20,9 +20,9 @@ "cdk-app": "bin/cdk-app.js" }, "devDependencies": { - "@aws-lambda-powertools/logger": "^1.5.0", - "@aws-lambda-powertools/metrics": "^1.5.0", - "@aws-lambda-powertools/tracer": "^1.5.0", + "@aws-lambda-powertools/logger": "^1.5.1", + "@aws-lambda-powertools/metrics": "^1.5.1", + "@aws-lambda-powertools/tracer": "^1.5.1", "@aws-sdk/lib-dynamodb": "^3.231.0", "@types/aws-lambda": "^8.10.109", "@types/jest": "^29.2.4", @@ -165,39 +165,38 @@ "peer": true }, "node_modules/@aws-lambda-powertools/commons": { - "version": "1.5.0", - "resolved": "https://registry.npmjs.org/@aws-lambda-powertools/commons/-/commons-1.5.0.tgz", - "integrity": "sha512-UDG1EzINigcBCxoDcwtiqtWR0ZDkZu3w4dZ/mCenUL3v1AUoiUfmpiZI54r0NyXXeyQOIAmvKft7VnQP2BHfJA==", + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/@aws-lambda-powertools/commons/-/commons-1.5.1.tgz", + "integrity": "sha512-qp13/WksB6M/liEHgV3301qmI/aeQKmrYk1iODB+rrkVWeKW4AJqBMuWQ26gIlbD8t82EtuUNPUFle1a2qwjIg==", "dev": true }, "node_modules/@aws-lambda-powertools/logger": { - "version": "1.5.0", - "resolved": "https://registry.npmjs.org/@aws-lambda-powertools/logger/-/logger-1.5.0.tgz", - "integrity": "sha512-BlajpUrI4fFMNfv1QBvPG9m7cCdu+5YCo8AsF+/2nM6OwEJDIIqpYvCQEr9TeQZQMMbirp43De2Z7MisV0HDyw==", + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/@aws-lambda-powertools/logger/-/logger-1.5.1.tgz", + "integrity": "sha512-dXvw7c4Z0DUEY62zEWsQ4DQZ3yf+JsEAqojQH+kw+rXVv0cjnIEbM4ZKONPG2jcPS5IMzO6gmCbu/PKB1PYgyA==", "dev": true, "dependencies": { - "@aws-lambda-powertools/commons": "^1.5.0", - "lodash.merge": "^4.6.2", - "lodash.pickby": "^4.6.0" + "@aws-lambda-powertools/commons": "^1.5.1", + "lodash.merge": "^4.6.2" } }, "node_modules/@aws-lambda-powertools/metrics": { - "version": "1.5.0", - "resolved": "https://registry.npmjs.org/@aws-lambda-powertools/metrics/-/metrics-1.5.0.tgz", - "integrity": "sha512-4x04YpKWz4OI4NSxbi2EhFQYGNjvO3kHUO9gSN/pOpa/bhrwXaTL1gIJsPKcDlKjm1VeQtLbFDutespz4kttpA==", + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/@aws-lambda-powertools/metrics/-/metrics-1.5.1.tgz", + "integrity": "sha512-kBvJR9phGdH5UqtcWyxVMQoZU57liQeVxZCFbDMSAhdlxBbW1pkPBASaKv/FLlX++Tb4TeO1Tj28dox1yL1t+w==", "dev": true, "dependencies": { - "@aws-lambda-powertools/commons": "^1.5.0" + "@aws-lambda-powertools/commons": "^1.5.1" } }, "node_modules/@aws-lambda-powertools/tracer": { - "version": "1.5.0", - "resolved": "https://registry.npmjs.org/@aws-lambda-powertools/tracer/-/tracer-1.5.0.tgz", - "integrity": "sha512-WXpMqzOsgi8PN+q+cQAWw5Y/Kf/wQ0BlAiIHcn2MSP5lurdOj9pslqUZOYywtjL1FraGOd+2ZEdo+iw6cbAz+w==", + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/@aws-lambda-powertools/tracer/-/tracer-1.5.1.tgz", + "integrity": "sha512-T/BHOzg+LbY5PF6drKuVhyk4tcAakyn8gI/lGrx8NhZ72vc0YZOCGaMhvUGbImoZ0UFyn5ApP0n70qvk1i1A/Q==", "dev": true, "dependencies": { - "@aws-lambda-powertools/commons": "^1.5.0", - "aws-xray-sdk-core": "^3.3.6" + "@aws-lambda-powertools/commons": "^1.5.1", + "aws-xray-sdk-core": "^3.4.0" } }, "node_modules/@aws-sdk/abort-controller": { @@ -6465,12 +6464,6 @@ "integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==", "dev": true }, - "node_modules/lodash.pickby": { - "version": "4.6.0", - "resolved": "https://registry.npmjs.org/lodash.pickby/-/lodash.pickby-4.6.0.tgz", - "integrity": "sha512-AZV+GsS/6ckvPOVQPXSiFFacKvKB4kOQu6ynt9wz0F3LO4R9Ij4K1ddYsIytDpSgLz88JHd9P+oaLeej5/Sl7Q==", - "dev": true - }, "node_modules/lru-cache": { "version": "6.0.0", "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", @@ -8194,39 +8187,38 @@ } }, "@aws-lambda-powertools/commons": { - "version": "1.5.0", - "resolved": "https://registry.npmjs.org/@aws-lambda-powertools/commons/-/commons-1.5.0.tgz", - "integrity": "sha512-UDG1EzINigcBCxoDcwtiqtWR0ZDkZu3w4dZ/mCenUL3v1AUoiUfmpiZI54r0NyXXeyQOIAmvKft7VnQP2BHfJA==", + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/@aws-lambda-powertools/commons/-/commons-1.5.1.tgz", + "integrity": "sha512-qp13/WksB6M/liEHgV3301qmI/aeQKmrYk1iODB+rrkVWeKW4AJqBMuWQ26gIlbD8t82EtuUNPUFle1a2qwjIg==", "dev": true }, "@aws-lambda-powertools/logger": { - "version": "1.5.0", - "resolved": "https://registry.npmjs.org/@aws-lambda-powertools/logger/-/logger-1.5.0.tgz", - "integrity": "sha512-BlajpUrI4fFMNfv1QBvPG9m7cCdu+5YCo8AsF+/2nM6OwEJDIIqpYvCQEr9TeQZQMMbirp43De2Z7MisV0HDyw==", + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/@aws-lambda-powertools/logger/-/logger-1.5.1.tgz", + "integrity": "sha512-dXvw7c4Z0DUEY62zEWsQ4DQZ3yf+JsEAqojQH+kw+rXVv0cjnIEbM4ZKONPG2jcPS5IMzO6gmCbu/PKB1PYgyA==", "dev": true, "requires": { - "@aws-lambda-powertools/commons": "^1.5.0", - "lodash.merge": "^4.6.2", - "lodash.pickby": "^4.6.0" + "@aws-lambda-powertools/commons": "^1.5.1", + "lodash.merge": "^4.6.2" } }, "@aws-lambda-powertools/metrics": { - "version": "1.5.0", - "resolved": "https://registry.npmjs.org/@aws-lambda-powertools/metrics/-/metrics-1.5.0.tgz", - "integrity": "sha512-4x04YpKWz4OI4NSxbi2EhFQYGNjvO3kHUO9gSN/pOpa/bhrwXaTL1gIJsPKcDlKjm1VeQtLbFDutespz4kttpA==", + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/@aws-lambda-powertools/metrics/-/metrics-1.5.1.tgz", + "integrity": "sha512-kBvJR9phGdH5UqtcWyxVMQoZU57liQeVxZCFbDMSAhdlxBbW1pkPBASaKv/FLlX++Tb4TeO1Tj28dox1yL1t+w==", "dev": true, "requires": { - "@aws-lambda-powertools/commons": "^1.5.0" + "@aws-lambda-powertools/commons": "^1.5.1" } }, "@aws-lambda-powertools/tracer": { - "version": "1.5.0", - "resolved": "https://registry.npmjs.org/@aws-lambda-powertools/tracer/-/tracer-1.5.0.tgz", - "integrity": "sha512-WXpMqzOsgi8PN+q+cQAWw5Y/Kf/wQ0BlAiIHcn2MSP5lurdOj9pslqUZOYywtjL1FraGOd+2ZEdo+iw6cbAz+w==", + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/@aws-lambda-powertools/tracer/-/tracer-1.5.1.tgz", + "integrity": "sha512-T/BHOzg+LbY5PF6drKuVhyk4tcAakyn8gI/lGrx8NhZ72vc0YZOCGaMhvUGbImoZ0UFyn5ApP0n70qvk1i1A/Q==", "dev": true, "requires": { - "@aws-lambda-powertools/commons": "^1.5.0", - "aws-xray-sdk-core": "^3.3.6" + "@aws-lambda-powertools/commons": "^1.5.1", + "aws-xray-sdk-core": "^3.4.0" } }, "@aws-sdk/abort-controller": { @@ -12885,12 +12877,6 @@ "integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==", "dev": true }, - "lodash.pickby": { - "version": "4.6.0", - "resolved": "https://registry.npmjs.org/lodash.pickby/-/lodash.pickby-4.6.0.tgz", - "integrity": "sha512-AZV+GsS/6ckvPOVQPXSiFFacKvKB4kOQu6ynt9wz0F3LO4R9Ij4K1ddYsIytDpSgLz88JHd9P+oaLeej5/Sl7Q==", - "dev": true - }, "lru-cache": { "version": "6.0.0", "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", diff --git a/examples/cdk/package.json b/examples/cdk/package.json index 8d08eba7a9..e0c57ab26b 100644 --- a/examples/cdk/package.json +++ b/examples/cdk/package.json @@ -1,6 +1,6 @@ { "name": "cdk-sample", - "version": "1.5.1", + "version": "1.6.0", "author": { "name": "Amazon Web Services", "url": "https://aws.amazon.com" @@ -24,9 +24,9 @@ "cdk": "cdk" }, "devDependencies": { - "@aws-lambda-powertools/logger": "^1.5.0", - "@aws-lambda-powertools/metrics": "^1.5.0", - "@aws-lambda-powertools/tracer": "^1.5.0", + "@aws-lambda-powertools/logger": "^1.5.1", + "@aws-lambda-powertools/metrics": "^1.5.1", + "@aws-lambda-powertools/tracer": "^1.5.1", "@aws-sdk/lib-dynamodb": "^3.231.0", "@types/aws-lambda": "^8.10.109", "@types/jest": "^29.2.4", diff --git a/examples/sam/CHANGELOG.md b/examples/sam/CHANGELOG.md index 4842af911c..880873e218 100644 --- a/examples/sam/CHANGELOG.md +++ b/examples/sam/CHANGELOG.md @@ -3,6 +3,14 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. +# [1.6.0](https://github.com/awslabs/aws-lambda-powertools-typescript/compare/v1.5.1...v1.6.0) (2023-03-02) + +**Note:** Version bump only for package sam-example + + + + + ## [1.5.1](https://github.com/awslabs/aws-lambda-powertools-typescript/compare/v1.5.0...v1.5.1) (2023-01-13) **Note:** Version bump only for package sam-example diff --git a/examples/sam/README.md b/examples/sam/README.md index 9c7f88077f..bf8c45af66 100644 --- a/examples/sam/README.md +++ b/examples/sam/README.md @@ -23,7 +23,8 @@ Before deploying this example install the npm dependencies: npm i ``` -In addition to the [recommended setup for this project](https://github.com/awslabs/aws-lambda-powertools-typescript/blob/main/CONTRIBUTING.md#setup), you'll need the [SAM CLI](https://docs.aws.amazon.com/serverless-application-model/latest/developerguide/serverless-sam-cli-install.html). +> **Note** +> In order to run this example you'll need [AWS SAM CLI version 1.65 or later](https://docs.aws.amazon.com/serverless-application-model/latest/developerguide/serverless-sam-cli-install.html). If you have an older version of the AWS SAM CLI, see [Upgrading the AWS SAM CLI](https://docs.aws.amazon.com/serverless-application-model/latest/developerguide/manage-sam-cli-versions.html#manage-sam-cli-versions-upgrade). ## Deploy the sample application diff --git a/examples/sam/package-lock.json b/examples/sam/package-lock.json index 5e8c80a513..87988d76c1 100644 --- a/examples/sam/package-lock.json +++ b/examples/sam/package-lock.json @@ -1,17 +1,17 @@ { "name": "sam-example", - "version": "1.5.1", + "version": "1.6.0", "lockfileVersion": 2, "requires": true, "packages": { "": { "name": "sam-example", - "version": "1.5.1", + "version": "1.6.0", "license": "MIT-0", "dependencies": { - "@aws-lambda-powertools/logger": "^1.5.0", - "@aws-lambda-powertools/metrics": "^1.5.0", - "@aws-lambda-powertools/tracer": "^1.5.0", + "@aws-lambda-powertools/logger": "^1.5.1", + "@aws-lambda-powertools/metrics": "^1.5.1", + "@aws-lambda-powertools/tracer": "^1.5.1", "@aws-sdk/client-dynamodb": "^3.231.0", "@aws-sdk/lib-dynamodb": "^3.231.0", "@middy/core": "^3.6.2", @@ -124,35 +124,34 @@ "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==" }, "node_modules/@aws-lambda-powertools/commons": { - "version": "1.5.0", - "resolved": "https://registry.npmjs.org/@aws-lambda-powertools/commons/-/commons-1.5.0.tgz", - "integrity": "sha512-UDG1EzINigcBCxoDcwtiqtWR0ZDkZu3w4dZ/mCenUL3v1AUoiUfmpiZI54r0NyXXeyQOIAmvKft7VnQP2BHfJA==" + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/@aws-lambda-powertools/commons/-/commons-1.5.1.tgz", + "integrity": "sha512-qp13/WksB6M/liEHgV3301qmI/aeQKmrYk1iODB+rrkVWeKW4AJqBMuWQ26gIlbD8t82EtuUNPUFle1a2qwjIg==" }, "node_modules/@aws-lambda-powertools/logger": { - "version": "1.5.0", - "resolved": "https://registry.npmjs.org/@aws-lambda-powertools/logger/-/logger-1.5.0.tgz", - "integrity": "sha512-BlajpUrI4fFMNfv1QBvPG9m7cCdu+5YCo8AsF+/2nM6OwEJDIIqpYvCQEr9TeQZQMMbirp43De2Z7MisV0HDyw==", + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/@aws-lambda-powertools/logger/-/logger-1.5.1.tgz", + "integrity": "sha512-dXvw7c4Z0DUEY62zEWsQ4DQZ3yf+JsEAqojQH+kw+rXVv0cjnIEbM4ZKONPG2jcPS5IMzO6gmCbu/PKB1PYgyA==", "dependencies": { - "@aws-lambda-powertools/commons": "^1.5.0", - "lodash.merge": "^4.6.2", - "lodash.pickby": "^4.6.0" + "@aws-lambda-powertools/commons": "^1.5.1", + "lodash.merge": "^4.6.2" } }, "node_modules/@aws-lambda-powertools/metrics": { - "version": "1.5.0", - "resolved": "https://registry.npmjs.org/@aws-lambda-powertools/metrics/-/metrics-1.5.0.tgz", - "integrity": "sha512-4x04YpKWz4OI4NSxbi2EhFQYGNjvO3kHUO9gSN/pOpa/bhrwXaTL1gIJsPKcDlKjm1VeQtLbFDutespz4kttpA==", + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/@aws-lambda-powertools/metrics/-/metrics-1.5.1.tgz", + "integrity": "sha512-kBvJR9phGdH5UqtcWyxVMQoZU57liQeVxZCFbDMSAhdlxBbW1pkPBASaKv/FLlX++Tb4TeO1Tj28dox1yL1t+w==", "dependencies": { - "@aws-lambda-powertools/commons": "^1.5.0" + "@aws-lambda-powertools/commons": "^1.5.1" } }, "node_modules/@aws-lambda-powertools/tracer": { - "version": "1.5.0", - "resolved": "https://registry.npmjs.org/@aws-lambda-powertools/tracer/-/tracer-1.5.0.tgz", - "integrity": "sha512-WXpMqzOsgi8PN+q+cQAWw5Y/Kf/wQ0BlAiIHcn2MSP5lurdOj9pslqUZOYywtjL1FraGOd+2ZEdo+iw6cbAz+w==", + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/@aws-lambda-powertools/tracer/-/tracer-1.5.1.tgz", + "integrity": "sha512-T/BHOzg+LbY5PF6drKuVhyk4tcAakyn8gI/lGrx8NhZ72vc0YZOCGaMhvUGbImoZ0UFyn5ApP0n70qvk1i1A/Q==", "dependencies": { - "@aws-lambda-powertools/commons": "^1.5.0", - "aws-xray-sdk-core": "^3.3.6" + "@aws-lambda-powertools/commons": "^1.5.1", + "aws-xray-sdk-core": "^3.4.0" } }, "node_modules/@aws-sdk/abort-controller": { @@ -5880,11 +5879,6 @@ "resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz", "integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==" }, - "node_modules/lodash.pickby": { - "version": "4.6.0", - "resolved": "https://registry.npmjs.org/lodash.pickby/-/lodash.pickby-4.6.0.tgz", - "integrity": "sha512-AZV+GsS/6ckvPOVQPXSiFFacKvKB4kOQu6ynt9wz0F3LO4R9Ij4K1ddYsIytDpSgLz88JHd9P+oaLeej5/Sl7Q==" - }, "node_modules/lru-cache": { "version": "6.0.0", "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", @@ -7478,35 +7472,34 @@ } }, "@aws-lambda-powertools/commons": { - "version": "1.5.0", - "resolved": "https://registry.npmjs.org/@aws-lambda-powertools/commons/-/commons-1.5.0.tgz", - "integrity": "sha512-UDG1EzINigcBCxoDcwtiqtWR0ZDkZu3w4dZ/mCenUL3v1AUoiUfmpiZI54r0NyXXeyQOIAmvKft7VnQP2BHfJA==" + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/@aws-lambda-powertools/commons/-/commons-1.5.1.tgz", + "integrity": "sha512-qp13/WksB6M/liEHgV3301qmI/aeQKmrYk1iODB+rrkVWeKW4AJqBMuWQ26gIlbD8t82EtuUNPUFle1a2qwjIg==" }, "@aws-lambda-powertools/logger": { - "version": "1.5.0", - "resolved": "https://registry.npmjs.org/@aws-lambda-powertools/logger/-/logger-1.5.0.tgz", - "integrity": "sha512-BlajpUrI4fFMNfv1QBvPG9m7cCdu+5YCo8AsF+/2nM6OwEJDIIqpYvCQEr9TeQZQMMbirp43De2Z7MisV0HDyw==", + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/@aws-lambda-powertools/logger/-/logger-1.5.1.tgz", + "integrity": "sha512-dXvw7c4Z0DUEY62zEWsQ4DQZ3yf+JsEAqojQH+kw+rXVv0cjnIEbM4ZKONPG2jcPS5IMzO6gmCbu/PKB1PYgyA==", "requires": { - "@aws-lambda-powertools/commons": "^1.5.0", - "lodash.merge": "^4.6.2", - "lodash.pickby": "^4.6.0" + "@aws-lambda-powertools/commons": "^1.5.1", + "lodash.merge": "^4.6.2" } }, "@aws-lambda-powertools/metrics": { - "version": "1.5.0", - "resolved": "https://registry.npmjs.org/@aws-lambda-powertools/metrics/-/metrics-1.5.0.tgz", - "integrity": "sha512-4x04YpKWz4OI4NSxbi2EhFQYGNjvO3kHUO9gSN/pOpa/bhrwXaTL1gIJsPKcDlKjm1VeQtLbFDutespz4kttpA==", + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/@aws-lambda-powertools/metrics/-/metrics-1.5.1.tgz", + "integrity": "sha512-kBvJR9phGdH5UqtcWyxVMQoZU57liQeVxZCFbDMSAhdlxBbW1pkPBASaKv/FLlX++Tb4TeO1Tj28dox1yL1t+w==", "requires": { - "@aws-lambda-powertools/commons": "^1.5.0" + "@aws-lambda-powertools/commons": "^1.5.1" } }, "@aws-lambda-powertools/tracer": { - "version": "1.5.0", - "resolved": "https://registry.npmjs.org/@aws-lambda-powertools/tracer/-/tracer-1.5.0.tgz", - "integrity": "sha512-WXpMqzOsgi8PN+q+cQAWw5Y/Kf/wQ0BlAiIHcn2MSP5lurdOj9pslqUZOYywtjL1FraGOd+2ZEdo+iw6cbAz+w==", + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/@aws-lambda-powertools/tracer/-/tracer-1.5.1.tgz", + "integrity": "sha512-T/BHOzg+LbY5PF6drKuVhyk4tcAakyn8gI/lGrx8NhZ72vc0YZOCGaMhvUGbImoZ0UFyn5ApP0n70qvk1i1A/Q==", "requires": { - "@aws-lambda-powertools/commons": "^1.5.0", - "aws-xray-sdk-core": "^3.3.6" + "@aws-lambda-powertools/commons": "^1.5.1", + "aws-xray-sdk-core": "^3.4.0" } }, "@aws-sdk/abort-controller": { @@ -11752,11 +11745,6 @@ "resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz", "integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==" }, - "lodash.pickby": { - "version": "4.6.0", - "resolved": "https://registry.npmjs.org/lodash.pickby/-/lodash.pickby-4.6.0.tgz", - "integrity": "sha512-AZV+GsS/6ckvPOVQPXSiFFacKvKB4kOQu6ynt9wz0F3LO4R9Ij4K1ddYsIytDpSgLz88JHd9P+oaLeej5/Sl7Q==" - }, "lru-cache": { "version": "6.0.0", "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", diff --git a/examples/sam/package.json b/examples/sam/package.json index cfe0386814..dcc566393d 100644 --- a/examples/sam/package.json +++ b/examples/sam/package.json @@ -1,6 +1,6 @@ { "name": "sam-example", - "version": "1.5.1", + "version": "1.6.0", "author": { "name": "Amazon Web Services", "url": "https://aws.amazon.com" @@ -35,9 +35,9 @@ "typescript": "^4.9.4" }, "dependencies": { - "@aws-lambda-powertools/logger": "^1.5.0", - "@aws-lambda-powertools/metrics": "^1.5.0", - "@aws-lambda-powertools/tracer": "^1.5.0", + "@aws-lambda-powertools/logger": "^1.5.1", + "@aws-lambda-powertools/metrics": "^1.5.1", + "@aws-lambda-powertools/tracer": "^1.5.1", "@aws-sdk/client-dynamodb": "^3.231.0", "@aws-sdk/lib-dynamodb": "^3.231.0", "@middy/core": "^3.6.2", diff --git a/layer-publisher/jest.config.js b/layer-publisher/jest.config.js deleted file mode 100644 index e3795fc8b4..0000000000 --- a/layer-publisher/jest.config.js +++ /dev/null @@ -1,8 +0,0 @@ -module.exports = { - testEnvironment: 'node', - roots: ['/tests'], - testMatch: ['**/*.test.ts'], - transform: { - '^.+\\.tsx?$': 'ts-jest' - } -}; diff --git a/layer-publisher/package-lock.json b/layer-publisher/package-lock.json deleted file mode 100644 index 8d8402857d..0000000000 --- a/layer-publisher/package-lock.json +++ /dev/null @@ -1,11347 +0,0 @@ -{ - "name": "layer-publisher", - "version": "1.5.1", - "lockfileVersion": 2, - "requires": true, - "packages": { - "": { - "name": "layer-publisher", - "version": "1.5.0", - "dependencies": { - "aws-cdk-lib": "^2.55.0", - "constructs": "^10.1.190", - "if-node-version": "^1.1.1", - "source-map-support": "^0.5.21", - "ts-md5": "^1.3.1" - }, - "bin": { - "layer-publisher": "bin/layer-publisher.js" - }, - "devDependencies": { - "@aws-cdk/cloudformation-diff": "^2.55.0", - "@aws-cdk/cx-api": "^2.55.0", - "@types/jest": "^29.2.4", - "@types/node": "18.11.15", - "@typescript-eslint/eslint-plugin": "^5.46.1", - "@typescript-eslint/parser": "^5.46.1", - "aws-cdk": "^2.55.0", - "eslint": "^8.29.0", - "eslint-import-resolver-node": "^0.3.6", - "eslint-import-resolver-typescript": "^3.5.2", - "eslint-plugin-import": "^2.26.0", - "jest": "^29.3.1", - "ts-jest": "^29.0.3", - "ts-node": "10.9.1", - "typescript": "4.9.4" - } - }, - "node_modules/@ampproject/remapping": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/@ampproject/remapping/-/remapping-2.2.0.tgz", - "integrity": "sha512-qRmjj8nj9qmLTQXXmaR1cck3UXSRMPrbsLJAasZpF+t3riI71BXed5ebIOYwQntykeZuhjsdweEc9BxH5Jc26w==", - "dev": true, - "dependencies": { - "@jridgewell/gen-mapping": "^0.1.0", - "@jridgewell/trace-mapping": "^0.3.9" - }, - "engines": { - "node": ">=6.0.0" - } - }, - "node_modules/@aws-cdk/asset-awscli-v1": { - "version": "2.2.49", - "resolved": "https://registry.npmjs.org/@aws-cdk/asset-awscli-v1/-/asset-awscli-v1-2.2.49.tgz", - "integrity": "sha512-Qd5bdLlC/sphWQQPNn7etKXWCh+fij7DWxtkIwvhhZ+LM6UEApGLS8sBLBQcRO2ZQdEuNb+zeClUy+3DNojfeg==" - }, - "node_modules/@aws-cdk/asset-kubectl-v20": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/@aws-cdk/asset-kubectl-v20/-/asset-kubectl-v20-2.1.1.tgz", - "integrity": "sha512-U1ntiX8XiMRRRH5J1IdC+1t5CE89015cwyt5U63Cpk0GnMlN5+h9WsWMlKlPXZR4rdq/m806JRlBMRpBUB2Dhw==" - }, - "node_modules/@aws-cdk/asset-node-proxy-agent-v5": { - "version": "2.0.38", - "resolved": "https://registry.npmjs.org/@aws-cdk/asset-node-proxy-agent-v5/-/asset-node-proxy-agent-v5-2.0.38.tgz", - "integrity": "sha512-BBwAjORhuUkTGO3CxGS5Evcp5n20h9v06Sftn2R1DuSm8zIoUlPsNlI1HUk8XqYuoEI4aD7IKRQBLglv09ciJQ==" - }, - "node_modules/@aws-cdk/cfnspec": { - "version": "2.55.1", - "resolved": "https://registry.npmjs.org/@aws-cdk/cfnspec/-/cfnspec-2.55.1.tgz", - "integrity": "sha512-jJCaEV9pTLFft2eYkwmblfxUBQeJSH4KbMteiVQdp6wkYbzoj/sjyFInfKHgtfIOeqjNtPZ74Dhl5fRJsOpBDw==", - "dev": true, - "dependencies": { - "fs-extra": "^9.1.0", - "md5": "^2.3.0" - } - }, - "node_modules/@aws-cdk/cloud-assembly-schema": { - "version": "2.55.1", - "resolved": "https://registry.npmjs.org/@aws-cdk/cloud-assembly-schema/-/cloud-assembly-schema-2.55.1.tgz", - "integrity": "sha512-VVVQaqHP2PsNGRwfPsq1RxoOfyC54DO8RH+2nHqCyPIfSmrIH6Ux5Uk7KAURyXKdb3SjKra66bxPOzvXHOaBXg==", - "bundleDependencies": [ - "jsonschema", - "semver" - ], - "dev": true, - "dependencies": { - "jsonschema": "^1.4.1", - "semver": "^7.3.8" - }, - "engines": { - "node": ">= 14.15.0" - } - }, - "node_modules/@aws-cdk/cloud-assembly-schema/node_modules/jsonschema": { - "version": "1.4.1", - "dev": true, - "inBundle": true, - "license": "MIT", - "engines": { - "node": "*" - } - }, - "node_modules/@aws-cdk/cloud-assembly-schema/node_modules/lru-cache": { - "version": "6.0.0", - "dev": true, - "inBundle": true, - "license": "ISC", - "dependencies": { - "yallist": "^4.0.0" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/@aws-cdk/cloud-assembly-schema/node_modules/semver": { - "version": "7.3.8", - "dev": true, - "inBundle": true, - "license": "ISC", - "dependencies": { - "lru-cache": "^6.0.0" - }, - "bin": { - "semver": "bin/semver.js" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/@aws-cdk/cloud-assembly-schema/node_modules/yallist": { - "version": "4.0.0", - "dev": true, - "inBundle": true, - "license": "ISC" - }, - "node_modules/@aws-cdk/cloudformation-diff": { - "version": "2.55.1", - "resolved": "https://registry.npmjs.org/@aws-cdk/cloudformation-diff/-/cloudformation-diff-2.55.1.tgz", - "integrity": "sha512-WgLubFXoQFGZuOkm7YtJx+kS8EN6rX9K6s257qFR7yNGpKBANSPVvWmlWX2qSvg++AkNSxKsuaZi+4V50TNbdA==", - "dev": true, - "dependencies": { - "@aws-cdk/cfnspec": "2.55.1", - "@types/node": "^14.18.34", - "chalk": "^4", - "diff": "^5.1.0", - "fast-deep-equal": "^3.1.3", - "string-width": "^4.2.3", - "table": "^6.8.1" - }, - "engines": { - "node": ">= 14.15.0" - } - }, - "node_modules/@aws-cdk/cloudformation-diff/node_modules/@types/node": { - "version": "14.18.36", - "resolved": "https://registry.npmjs.org/@types/node/-/node-14.18.36.tgz", - "integrity": "sha512-FXKWbsJ6a1hIrRxv+FoukuHnGTgEzKYGi7kilfMae96AL9UNkPFNWJEEYWzdRI9ooIkbr4AKldyuSTLql06vLQ==", - "dev": true - }, - "node_modules/@aws-cdk/cx-api": { - "version": "2.55.1", - "resolved": "https://registry.npmjs.org/@aws-cdk/cx-api/-/cx-api-2.55.1.tgz", - "integrity": "sha512-gWQCn/9gaayf2ev0HjCMQleY1gWJZGImLhsUF8kneYnOPCm/r0qpIzy3BxiWiDFLPh9gykDvHQhpH6EG0aXnGA==", - "bundleDependencies": [ - "semver" - ], - "dev": true, - "dependencies": { - "@aws-cdk/cloud-assembly-schema": "2.55.1", - "semver": "^7.3.8" - }, - "engines": { - "node": ">= 14.15.0" - }, - "peerDependencies": { - "@aws-cdk/cloud-assembly-schema": "2.55.1" - } - }, - "node_modules/@aws-cdk/cx-api/node_modules/lru-cache": { - "version": "6.0.0", - "dev": true, - "inBundle": true, - "license": "ISC", - "dependencies": { - "yallist": "^4.0.0" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/@aws-cdk/cx-api/node_modules/semver": { - "version": "7.3.8", - "dev": true, - "inBundle": true, - "license": "ISC", - "dependencies": { - "lru-cache": "^6.0.0" - }, - "bin": { - "semver": "bin/semver.js" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/@aws-cdk/cx-api/node_modules/yallist": { - "version": "4.0.0", - "dev": true, - "inBundle": true, - "license": "ISC" - }, - "node_modules/@babel/code-frame": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.18.6.tgz", - "integrity": "sha512-TDCmlK5eOvH+eH7cdAFlNXeVJqWIQ7gW9tY1GJIpUtFb6CmjVyq2VM3u71bOyR8CRihcCgMUYoDNyLXao3+70Q==", - "dev": true, - "dependencies": { - "@babel/highlight": "^7.18.6" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/compat-data": { - "version": "7.20.10", - "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.20.10.tgz", - "integrity": "sha512-sEnuDPpOJR/fcafHMjpcpGN5M2jbUGUHwmuWKM/YdPzeEDJg8bgmbcWQFUfE32MQjti1koACvoPVsDe8Uq+idg==", - "dev": true, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/core": { - "version": "7.20.12", - "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.20.12.tgz", - "integrity": "sha512-XsMfHovsUYHFMdrIHkZphTN/2Hzzi78R08NuHfDBehym2VsPDL6Zn/JAD/JQdnRvbSsbQc4mVaU1m6JgtTEElg==", - "dev": true, - "dependencies": { - "@ampproject/remapping": "^2.1.0", - "@babel/code-frame": "^7.18.6", - "@babel/generator": "^7.20.7", - "@babel/helper-compilation-targets": "^7.20.7", - "@babel/helper-module-transforms": "^7.20.11", - "@babel/helpers": "^7.20.7", - "@babel/parser": "^7.20.7", - "@babel/template": "^7.20.7", - "@babel/traverse": "^7.20.12", - "@babel/types": "^7.20.7", - "convert-source-map": "^1.7.0", - "debug": "^4.1.0", - "gensync": "^1.0.0-beta.2", - "json5": "^2.2.2", - "semver": "^6.3.0" - }, - "engines": { - "node": ">=6.9.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/babel" - } - }, - "node_modules/@babel/core/node_modules/convert-source-map": { - "version": "1.9.0", - "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-1.9.0.tgz", - "integrity": "sha512-ASFBup0Mz1uyiIjANan1jzLQami9z1PoYSZCiiYW2FczPbenXc45FZdBZLzOT+r6+iciuEModtmCti+hjaAk0A==", - "dev": true - }, - "node_modules/@babel/core/node_modules/semver": { - "version": "6.3.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", - "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", - "dev": true, - "bin": { - "semver": "bin/semver.js" - } - }, - "node_modules/@babel/generator": { - "version": "7.20.7", - "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.20.7.tgz", - "integrity": "sha512-7wqMOJq8doJMZmP4ApXTzLxSr7+oO2jroJURrVEp6XShrQUObV8Tq/D0NCcoYg2uHqUrjzO0zwBjoYzelxK+sw==", - "dev": true, - "dependencies": { - "@babel/types": "^7.20.7", - "@jridgewell/gen-mapping": "^0.3.2", - "jsesc": "^2.5.1" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/generator/node_modules/@jridgewell/gen-mapping": { - "version": "0.3.2", - "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.2.tgz", - "integrity": "sha512-mh65xKQAzI6iBcFzwv28KVWSmCkdRBWoOh+bYQGW3+6OZvbbN3TqMGo5hqYxQniRcH9F2VZIoJCm4pa3BPDK/A==", - "dev": true, - "dependencies": { - "@jridgewell/set-array": "^1.0.1", - "@jridgewell/sourcemap-codec": "^1.4.10", - "@jridgewell/trace-mapping": "^0.3.9" - }, - "engines": { - "node": ">=6.0.0" - } - }, - "node_modules/@babel/helper-compilation-targets": { - "version": "7.20.7", - "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.20.7.tgz", - "integrity": "sha512-4tGORmfQcrc+bvrjb5y3dG9Mx1IOZjsHqQVUz7XCNHO+iTmqxWnVg3KRygjGmpRLJGdQSKuvFinbIb0CnZwHAQ==", - "dev": true, - "dependencies": { - "@babel/compat-data": "^7.20.5", - "@babel/helper-validator-option": "^7.18.6", - "browserslist": "^4.21.3", - "lru-cache": "^5.1.1", - "semver": "^6.3.0" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0" - } - }, - "node_modules/@babel/helper-compilation-targets/node_modules/semver": { - "version": "6.3.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", - "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", - "dev": true, - "bin": { - "semver": "bin/semver.js" - } - }, - "node_modules/@babel/helper-environment-visitor": { - "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" - } - }, - "node_modules/@babel/helper-function-name": { - "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.10", - "@babel/types": "^7.19.0" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-hoist-variables": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/helper-hoist-variables/-/helper-hoist-variables-7.18.6.tgz", - "integrity": "sha512-UlJQPkFqFULIcyW5sbzgbkxn2FKRgwWiRexcuaR8RNJRy8+LLveqPjwZV/bwrLZCN0eUHD/x8D0heK1ozuoo6Q==", - "dev": true, - "dependencies": { - "@babel/types": "^7.18.6" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-module-imports": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.18.6.tgz", - "integrity": "sha512-0NFvs3VkuSYbFi1x2Vd6tKrywq+z/cLeYC/RJNFrIX/30Bf5aiGYbtvGXolEktzJH8o5E5KJ3tT+nkxuuZFVlA==", - "dev": true, - "dependencies": { - "@babel/types": "^7.18.6" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-module-transforms": { - "version": "7.20.11", - "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.20.11.tgz", - "integrity": "sha512-uRy78kN4psmji1s2QtbtcCSaj/LILFDp0f/ymhpQH5QY3nljUZCaNWz9X1dEj/8MBdBEFECs7yRhKn8i7NjZgg==", - "dev": true, - "dependencies": { - "@babel/helper-environment-visitor": "^7.18.9", - "@babel/helper-module-imports": "^7.18.6", - "@babel/helper-simple-access": "^7.20.2", - "@babel/helper-split-export-declaration": "^7.18.6", - "@babel/helper-validator-identifier": "^7.19.1", - "@babel/template": "^7.20.7", - "@babel/traverse": "^7.20.10", - "@babel/types": "^7.20.7" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-plugin-utils": { - "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-simple-access": { - "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.20.2" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-split-export-declaration": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.18.6.tgz", - "integrity": "sha512-bde1etTx6ZyTmobl9LLMMQsaizFVZrquTEHOqKeQESMKo4PlObf+8+JA25ZsIpZhT/WEd39+vOdLXAFG/nELpA==", - "dev": true, - "dependencies": { - "@babel/types": "^7.18.6" - }, - "engines": { - "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.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" - } - }, - "node_modules/@babel/helper-validator-option": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.18.6.tgz", - "integrity": "sha512-XO7gESt5ouv/LRJdrVjkShckw6STTaB7l9BrpBaAHDeF5YZT+01PCwmR0SJHnkW6i8OwW/EVWRShfi4j2x+KQw==", - "dev": true, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helpers": { - "version": "7.20.7", - "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.20.7.tgz", - "integrity": "sha512-PBPjs5BppzsGaxHQCDKnZ6Gd9s6xl8bBCluz3vEInLGRJmnZan4F6BYCeqtyXqkk4W5IlPmjK4JlOuZkpJ3xZA==", - "dev": true, - "dependencies": { - "@babel/template": "^7.20.7", - "@babel/traverse": "^7.20.7", - "@babel/types": "^7.20.7" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/highlight": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.18.6.tgz", - "integrity": "sha512-u7stbOuYjaPezCuLj29hNW1v64M2Md2qupEKP1fHc7WdOA3DgLh37suiSrZYY7haUB7iBeQZ9P1uiRF359do3g==", - "dev": true, - "dependencies": { - "@babel/helper-validator-identifier": "^7.18.6", - "chalk": "^2.0.0", - "js-tokens": "^4.0.0" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/highlight/node_modules/ansi-styles": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", - "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", - "dev": true, - "dependencies": { - "color-convert": "^1.9.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/@babel/highlight/node_modules/chalk": { - "version": "2.4.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", - "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", - "dev": true, - "dependencies": { - "ansi-styles": "^3.2.1", - "escape-string-regexp": "^1.0.5", - "supports-color": "^5.3.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/@babel/highlight/node_modules/color-convert": { - "version": "1.9.3", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", - "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", - "dev": true, - "dependencies": { - "color-name": "1.1.3" - } - }, - "node_modules/@babel/highlight/node_modules/color-name": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", - "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==", - "dev": true - }, - "node_modules/@babel/highlight/node_modules/escape-string-regexp": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", - "integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==", - "dev": true, - "engines": { - "node": ">=0.8.0" - } - }, - "node_modules/@babel/highlight/node_modules/has-flag": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", - "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==", - "dev": true, - "engines": { - "node": ">=4" - } - }, - "node_modules/@babel/highlight/node_modules/supports-color": { - "version": "5.5.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", - "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", - "dev": true, - "dependencies": { - "has-flag": "^3.0.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/@babel/parser": { - "version": "7.20.7", - "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.20.7.tgz", - "integrity": "sha512-T3Z9oHybU+0vZlY9CiDSJQTD5ZapcW18ZctFMi0MOAl/4BjFF4ul7NVSARLdbGO5vDqy9eQiGTV0LtKfvCYvcg==", - "dev": true, - "bin": { - "parser": "bin/babel-parser.js" - }, - "engines": { - "node": ">=6.0.0" - } - }, - "node_modules/@babel/plugin-syntax-async-generators": { - "version": "7.8.4", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-async-generators/-/plugin-syntax-async-generators-7.8.4.tgz", - "integrity": "sha512-tycmZxkGfZaxhMRbXlPXuVFpdWlXpir2W4AMhSJgRKzk/eDlIXOhb2LHWoLpDF7TEHylV5zNhykX6KAgHJmTNw==", - "dev": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.8.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-syntax-bigint": { - "version": "7.8.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-bigint/-/plugin-syntax-bigint-7.8.3.tgz", - "integrity": "sha512-wnTnFlG+YxQm3vDxpGE57Pj0srRU4sHE/mDkt1qv2YJJSeUAec2ma4WLUnUPeKjyrfntVwe/N6dCXpU+zL3Npg==", - "dev": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.8.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-syntax-class-properties": { - "version": "7.12.13", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-class-properties/-/plugin-syntax-class-properties-7.12.13.tgz", - "integrity": "sha512-fm4idjKla0YahUNgFNLCB0qySdsoPiZP3iQE3rky0mBUtMZ23yDJ9SJdg6dXTSDnulOVqiF3Hgr9nbXvXTQZYA==", - "dev": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.12.13" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-syntax-import-meta": { - "version": "7.10.4", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-import-meta/-/plugin-syntax-import-meta-7.10.4.tgz", - "integrity": "sha512-Yqfm+XDx0+Prh3VSeEQCPU81yC+JWZ2pDPFSS4ZdpfZhp4MkFMaDC1UqseovEKwSUpnIL7+vK+Clp7bfh0iD7g==", - "dev": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.10.4" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-syntax-json-strings": { - "version": "7.8.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-json-strings/-/plugin-syntax-json-strings-7.8.3.tgz", - "integrity": "sha512-lY6kdGpWHvjoe2vk4WrAapEuBR69EMxZl+RoGRhrFGNYVK8mOPAW8VfbT/ZgrFbXlDNiiaxQnAtgVCZ6jv30EA==", - "dev": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.8.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-syntax-jsx": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-jsx/-/plugin-syntax-jsx-7.18.6.tgz", - "integrity": "sha512-6mmljtAedFGTWu2p/8WIORGwy+61PLgOMPOdazc7YoJ9ZCWUyFy3A6CpPkRKLKD1ToAesxX8KGEViAiLo9N+7Q==", - "dev": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.18.6" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-syntax-logical-assignment-operators": { - "version": "7.10.4", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-logical-assignment-operators/-/plugin-syntax-logical-assignment-operators-7.10.4.tgz", - "integrity": "sha512-d8waShlpFDinQ5MtvGU9xDAOzKH47+FFoney2baFIoMr952hKOLp1HR7VszoZvOsV/4+RRszNY7D17ba0te0ig==", - "dev": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.10.4" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-syntax-nullish-coalescing-operator": { - "version": "7.8.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-nullish-coalescing-operator/-/plugin-syntax-nullish-coalescing-operator-7.8.3.tgz", - "integrity": "sha512-aSff4zPII1u2QD7y+F8oDsz19ew4IGEJg9SVW+bqwpwtfFleiQDMdzA/R+UlWDzfnHFCxxleFT0PMIrR36XLNQ==", - "dev": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.8.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-syntax-numeric-separator": { - "version": "7.10.4", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-numeric-separator/-/plugin-syntax-numeric-separator-7.10.4.tgz", - "integrity": "sha512-9H6YdfkcK/uOnY/K7/aA2xpzaAgkQn37yzWUMRK7OaPOqOpGS1+n0H5hxT9AUw9EsSjPW8SVyMJwYRtWs3X3ug==", - "dev": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.10.4" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-syntax-object-rest-spread": { - "version": "7.8.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-object-rest-spread/-/plugin-syntax-object-rest-spread-7.8.3.tgz", - "integrity": "sha512-XoqMijGZb9y3y2XskN+P1wUGiVwWZ5JmoDRwx5+3GmEplNyVM2s2Dg8ILFQm8rWM48orGy5YpI5Bl8U1y7ydlA==", - "dev": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.8.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-syntax-optional-catch-binding": { - "version": "7.8.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-optional-catch-binding/-/plugin-syntax-optional-catch-binding-7.8.3.tgz", - "integrity": "sha512-6VPD0Pc1lpTqw0aKoeRTMiB+kWhAoT24PA+ksWSBrFtl5SIRVpZlwN3NNPQjehA2E/91FV3RjLWoVTglWcSV3Q==", - "dev": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.8.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-syntax-optional-chaining": { - "version": "7.8.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-optional-chaining/-/plugin-syntax-optional-chaining-7.8.3.tgz", - "integrity": "sha512-KoK9ErH1MBlCPxV0VANkXW2/dw4vlbGDrFgz8bmUsBGYkFRcbRwMh6cIJubdPrkxRwuGdtCk0v/wPTKbQgBjkg==", - "dev": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.8.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-syntax-top-level-await": { - "version": "7.14.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-top-level-await/-/plugin-syntax-top-level-await-7.14.5.tgz", - "integrity": "sha512-hx++upLv5U1rgYfwe1xBQUhRmU41NEvpUvrp8jkrSCdvGSnM5/qdRMtylJ6PG5OFkBaHkbTAKTnd3/YyESRHFw==", - "dev": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.14.5" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-syntax-typescript": { - "version": "7.20.0", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-typescript/-/plugin-syntax-typescript-7.20.0.tgz", - "integrity": "sha512-rd9TkG+u1CExzS4SM1BlMEhMXwFLKVjOAFFCDx9PbX5ycJWDoWMcwdJH9RhkPu1dOgn5TrxLot/Gx6lWFuAUNQ==", - "dev": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.19.0" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/template": { - "version": "7.20.7", - "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.20.7.tgz", - "integrity": "sha512-8SegXApWe6VoNw0r9JHpSteLKTpTiLZ4rMlGIm9JQ18KiCtyQiAMEazujAHrUS5flrcqYZa75ukev3P6QmUwUw==", - "dev": true, - "dependencies": { - "@babel/code-frame": "^7.18.6", - "@babel/parser": "^7.20.7", - "@babel/types": "^7.20.7" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/traverse": { - "version": "7.20.12", - "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.20.12.tgz", - "integrity": "sha512-MsIbFN0u+raeja38qboyF8TIT7K0BFzz/Yd/77ta4MsUsmP2RAnidIlwq7d5HFQrH/OZJecGV6B71C4zAgpoSQ==", - "dev": true, - "dependencies": { - "@babel/code-frame": "^7.18.6", - "@babel/generator": "^7.20.7", - "@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.20.7", - "@babel/types": "^7.20.7", - "debug": "^4.1.0", - "globals": "^11.1.0" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/traverse/node_modules/globals": { - "version": "11.12.0", - "resolved": "https://registry.npmjs.org/globals/-/globals-11.12.0.tgz", - "integrity": "sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==", - "dev": true, - "engines": { - "node": ">=4" - } - }, - "node_modules/@babel/types": { - "version": "7.20.7", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.20.7.tgz", - "integrity": "sha512-69OnhBxSSgK0OzTJai4kyPDiKTIe3j+ctaHdIGVbRahTLAT7L3R9oeXHC2aVSuGYt3cVnoAMDmOCgJ2yaiLMvg==", - "dev": true, - "dependencies": { - "@babel/helper-string-parser": "^7.19.4", - "@babel/helper-validator-identifier": "^7.19.1", - "to-fast-properties": "^2.0.0" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@bcoe/v8-coverage": { - "version": "0.2.3", - "resolved": "https://registry.npmjs.org/@bcoe/v8-coverage/-/v8-coverage-0.2.3.tgz", - "integrity": "sha512-0hYQ8SB4Db5zvZB4axdMHGwEaQjkZzFjQiN9LVYvIFB2nSUHW9tYpxWriPrWDASIxiaXax83REcLxuSdnGPZtw==", - "dev": true - }, - "node_modules/@cspotcode/source-map-support": { - "version": "0.8.1", - "resolved": "https://registry.npmjs.org/@cspotcode/source-map-support/-/source-map-support-0.8.1.tgz", - "integrity": "sha512-IchNf6dN4tHoMFIn/7OE8LWZ19Y6q/67Bmf6vnGREv8RSbBVb9LPJxEcnwrcwX6ixSvaiGoomAUvu4YSxXrVgw==", - "dev": true, - "dependencies": { - "@jridgewell/trace-mapping": "0.3.9" - }, - "engines": { - "node": ">=12" - } - }, - "node_modules/@cspotcode/source-map-support/node_modules/@jridgewell/trace-mapping": { - "version": "0.3.9", - "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.9.tgz", - "integrity": "sha512-3Belt6tdc8bPgAtbcmdtNJlirVoTmEb5e2gC94PnkwEW9jI6CAHUeoG85tjWP5WquqfavoMtMwiG4P926ZKKuQ==", - "dev": true, - "dependencies": { - "@jridgewell/resolve-uri": "^3.0.3", - "@jridgewell/sourcemap-codec": "^1.4.10" - } - }, - "node_modules/@eslint/eslintrc": { - "version": "1.4.1", - "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-1.4.1.tgz", - "integrity": "sha512-XXrH9Uarn0stsyldqDYq8r++mROmWRI1xKMXa640Bb//SY1+ECYX6VzT6Lcx5frD0V30XieqJ0oX9I2Xj5aoMA==", - "dev": true, - "dependencies": { - "ajv": "^6.12.4", - "debug": "^4.3.2", - "espree": "^9.4.0", - "globals": "^13.19.0", - "ignore": "^5.2.0", - "import-fresh": "^3.2.1", - "js-yaml": "^4.1.0", - "minimatch": "^3.1.2", - "strip-json-comments": "^3.1.1" - }, - "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - }, - "funding": { - "url": "https://opencollective.com/eslint" - } - }, - "node_modules/@humanwhocodes/config-array": { - "version": "0.11.8", - "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.11.8.tgz", - "integrity": "sha512-UybHIJzJnR5Qc/MsD9Kr+RpO2h+/P1GhOwdiLPXK5TWk5sgTdu88bTD9UP+CKbPPh5Rni1u0GjAdYQLemG8g+g==", - "dev": true, - "dependencies": { - "@humanwhocodes/object-schema": "^1.2.1", - "debug": "^4.1.1", - "minimatch": "^3.0.5" - }, - "engines": { - "node": ">=10.10.0" - } - }, - "node_modules/@humanwhocodes/module-importer": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/@humanwhocodes/module-importer/-/module-importer-1.0.1.tgz", - "integrity": "sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA==", - "dev": true, - "engines": { - "node": ">=12.22" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/nzakas" - } - }, - "node_modules/@humanwhocodes/object-schema": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/@humanwhocodes/object-schema/-/object-schema-1.2.1.tgz", - "integrity": "sha512-ZnQMnLV4e7hDlUvw8H+U8ASL02SS2Gn6+9Ac3wGGLIe7+je2AeAOxPY+izIPJDfFDb7eDjev0Us8MO1iFRN8hA==", - "dev": true - }, - "node_modules/@istanbuljs/load-nyc-config": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/@istanbuljs/load-nyc-config/-/load-nyc-config-1.1.0.tgz", - "integrity": "sha512-VjeHSlIzpv/NyD3N0YuHfXOPDIixcA1q2ZV98wsMqcYlPmv2n3Yb2lYP9XMElnaFVXg5A7YLTeLu6V84uQDjmQ==", - "dev": true, - "dependencies": { - "camelcase": "^5.3.1", - "find-up": "^4.1.0", - "get-package-type": "^0.1.0", - "js-yaml": "^3.13.1", - "resolve-from": "^5.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/@istanbuljs/load-nyc-config/node_modules/argparse": { - "version": "1.0.10", - "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz", - "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==", - "dev": true, - "dependencies": { - "sprintf-js": "~1.0.2" - } - }, - "node_modules/@istanbuljs/load-nyc-config/node_modules/find-up": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz", - "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==", - "dev": true, - "dependencies": { - "locate-path": "^5.0.0", - "path-exists": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "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/locate-path": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz", - "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==", - "dev": true, - "dependencies": { - "p-locate": "^4.1.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/@istanbuljs/load-nyc-config/node_modules/p-limit": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz", - "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==", - "dev": true, - "dependencies": { - "p-try": "^2.0.0" - }, - "engines": { - "node": ">=6" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/@istanbuljs/load-nyc-config/node_modules/p-locate": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz", - "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==", - "dev": true, - "dependencies": { - "p-limit": "^2.2.0" - }, - "engines": { - "node": ">=8" - } - }, - "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", - "integrity": "sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/@istanbuljs/schema": { - "version": "0.1.3", - "resolved": "https://registry.npmjs.org/@istanbuljs/schema/-/schema-0.1.3.tgz", - "integrity": "sha512-ZXRY4jNvVgSVQ8DL3LTcakaAtXwTVUxE81hslsyD2AtoXW/wVob10HkOJ1X/pAlcI7D+2YoZKg5do8G/w6RYgA==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/@jest/console": { - "version": "29.3.1", - "resolved": "https://registry.npmjs.org/@jest/console/-/console-29.3.1.tgz", - "integrity": "sha512-IRE6GD47KwcqA09RIWrabKdHPiKDGgtAL31xDxbi/RjQMsr+lY+ppxmHwY0dUEV3qvvxZzoe5Hl0RXZJOjQNUg==", - "dev": true, - "dependencies": { - "@jest/types": "^29.3.1", - "@types/node": "*", - "chalk": "^4.0.0", - "jest-message-util": "^29.3.1", - "jest-util": "^29.3.1", - "slash": "^3.0.0" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/@jest/core": { - "version": "29.3.1", - "resolved": "https://registry.npmjs.org/@jest/core/-/core-29.3.1.tgz", - "integrity": "sha512-0ohVjjRex985w5MmO5L3u5GR1O30DexhBSpuwx2P+9ftyqHdJXnk7IUWiP80oHMvt7ubHCJHxV0a0vlKVuZirw==", - "dev": true, - "dependencies": { - "@jest/console": "^29.3.1", - "@jest/reporters": "^29.3.1", - "@jest/test-result": "^29.3.1", - "@jest/transform": "^29.3.1", - "@jest/types": "^29.3.1", - "@types/node": "*", - "ansi-escapes": "^4.2.1", - "chalk": "^4.0.0", - "ci-info": "^3.2.0", - "exit": "^0.1.2", - "graceful-fs": "^4.2.9", - "jest-changed-files": "^29.2.0", - "jest-config": "^29.3.1", - "jest-haste-map": "^29.3.1", - "jest-message-util": "^29.3.1", - "jest-regex-util": "^29.2.0", - "jest-resolve": "^29.3.1", - "jest-resolve-dependencies": "^29.3.1", - "jest-runner": "^29.3.1", - "jest-runtime": "^29.3.1", - "jest-snapshot": "^29.3.1", - "jest-util": "^29.3.1", - "jest-validate": "^29.3.1", - "jest-watcher": "^29.3.1", - "micromatch": "^4.0.4", - "pretty-format": "^29.3.1", - "slash": "^3.0.0", - "strip-ansi": "^6.0.0" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - }, - "peerDependencies": { - "node-notifier": "^8.0.1 || ^9.0.0 || ^10.0.0" - }, - "peerDependenciesMeta": { - "node-notifier": { - "optional": true - } - } - }, - "node_modules/@jest/environment": { - "version": "29.3.1", - "resolved": "https://registry.npmjs.org/@jest/environment/-/environment-29.3.1.tgz", - "integrity": "sha512-pMmvfOPmoa1c1QpfFW0nXYtNLpofqo4BrCIk6f2kW4JFeNlHV2t3vd+3iDLf31e2ot2Mec0uqZfmI+U0K2CFag==", - "dev": true, - "dependencies": { - "@jest/fake-timers": "^29.3.1", - "@jest/types": "^29.3.1", - "@types/node": "*", - "jest-mock": "^29.3.1" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/@jest/expect": { - "version": "29.3.1", - "resolved": "https://registry.npmjs.org/@jest/expect/-/expect-29.3.1.tgz", - "integrity": "sha512-QivM7GlSHSsIAWzgfyP8dgeExPRZ9BIe2LsdPyEhCGkZkoyA+kGsoIzbKAfZCvvRzfZioKwPtCZIt5SaoxYCvg==", - "dev": true, - "dependencies": { - "expect": "^29.3.1", - "jest-snapshot": "^29.3.1" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/@jest/expect-utils": { - "version": "29.3.1", - "resolved": "https://registry.npmjs.org/@jest/expect-utils/-/expect-utils-29.3.1.tgz", - "integrity": "sha512-wlrznINZI5sMjwvUoLVk617ll/UYfGIZNxmbU+Pa7wmkL4vYzhV9R2pwVqUh4NWWuLQWkI8+8mOkxs//prKQ3g==", - "dev": true, - "dependencies": { - "jest-get-type": "^29.2.0" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/@jest/fake-timers": { - "version": "29.3.1", - "resolved": "https://registry.npmjs.org/@jest/fake-timers/-/fake-timers-29.3.1.tgz", - "integrity": "sha512-iHTL/XpnDlFki9Tq0Q1GGuVeQ8BHZGIYsvCO5eN/O/oJaRzofG9Xndd9HuSDBI/0ZS79pg0iwn07OMTQ7ngF2A==", - "dev": true, - "dependencies": { - "@jest/types": "^29.3.1", - "@sinonjs/fake-timers": "^9.1.2", - "@types/node": "*", - "jest-message-util": "^29.3.1", - "jest-mock": "^29.3.1", - "jest-util": "^29.3.1" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/@jest/globals": { - "version": "29.3.1", - "resolved": "https://registry.npmjs.org/@jest/globals/-/globals-29.3.1.tgz", - "integrity": "sha512-cTicd134vOcwO59OPaB6AmdHQMCtWOe+/DitpTZVxWgMJ+YvXL1HNAmPyiGbSHmF/mXVBkvlm8YYtQhyHPnV6Q==", - "dev": true, - "dependencies": { - "@jest/environment": "^29.3.1", - "@jest/expect": "^29.3.1", - "@jest/types": "^29.3.1", - "jest-mock": "^29.3.1" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/@jest/reporters": { - "version": "29.3.1", - "resolved": "https://registry.npmjs.org/@jest/reporters/-/reporters-29.3.1.tgz", - "integrity": "sha512-GhBu3YFuDrcAYW/UESz1JphEAbvUjaY2vShRZRoRY1mxpCMB3yGSJ4j9n0GxVlEOdCf7qjvUfBCrTUUqhVfbRA==", - "dev": true, - "dependencies": { - "@bcoe/v8-coverage": "^0.2.3", - "@jest/console": "^29.3.1", - "@jest/test-result": "^29.3.1", - "@jest/transform": "^29.3.1", - "@jest/types": "^29.3.1", - "@jridgewell/trace-mapping": "^0.3.15", - "@types/node": "*", - "chalk": "^4.0.0", - "collect-v8-coverage": "^1.0.0", - "exit": "^0.1.2", - "glob": "^7.1.3", - "graceful-fs": "^4.2.9", - "istanbul-lib-coverage": "^3.0.0", - "istanbul-lib-instrument": "^5.1.0", - "istanbul-lib-report": "^3.0.0", - "istanbul-lib-source-maps": "^4.0.0", - "istanbul-reports": "^3.1.3", - "jest-message-util": "^29.3.1", - "jest-util": "^29.3.1", - "jest-worker": "^29.3.1", - "slash": "^3.0.0", - "string-length": "^4.0.1", - "strip-ansi": "^6.0.0", - "v8-to-istanbul": "^9.0.1" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - }, - "peerDependencies": { - "node-notifier": "^8.0.1 || ^9.0.0 || ^10.0.0" - }, - "peerDependenciesMeta": { - "node-notifier": { - "optional": true - } - } - }, - "node_modules/@jest/schemas": { - "version": "29.0.0", - "resolved": "https://registry.npmjs.org/@jest/schemas/-/schemas-29.0.0.tgz", - "integrity": "sha512-3Ab5HgYIIAnS0HjqJHQYZS+zXc4tUmTmBH3z83ajI6afXp8X3ZtdLX+nXx+I7LNkJD7uN9LAVhgnjDgZa2z0kA==", - "dev": true, - "dependencies": { - "@sinclair/typebox": "^0.24.1" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/@jest/source-map": { - "version": "29.2.0", - "resolved": "https://registry.npmjs.org/@jest/source-map/-/source-map-29.2.0.tgz", - "integrity": "sha512-1NX9/7zzI0nqa6+kgpSdKPK+WU1p+SJk3TloWZf5MzPbxri9UEeXX5bWZAPCzbQcyuAzubcdUHA7hcNznmRqWQ==", - "dev": true, - "dependencies": { - "@jridgewell/trace-mapping": "^0.3.15", - "callsites": "^3.0.0", - "graceful-fs": "^4.2.9" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/@jest/test-result": { - "version": "29.3.1", - "resolved": "https://registry.npmjs.org/@jest/test-result/-/test-result-29.3.1.tgz", - "integrity": "sha512-qeLa6qc0ddB0kuOZyZIhfN5q0e2htngokyTWsGriedsDhItisW7SDYZ7ceOe57Ii03sL988/03wAcBh3TChMGw==", - "dev": true, - "dependencies": { - "@jest/console": "^29.3.1", - "@jest/types": "^29.3.1", - "@types/istanbul-lib-coverage": "^2.0.0", - "collect-v8-coverage": "^1.0.0" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/@jest/test-sequencer": { - "version": "29.3.1", - "resolved": "https://registry.npmjs.org/@jest/test-sequencer/-/test-sequencer-29.3.1.tgz", - "integrity": "sha512-IqYvLbieTv20ArgKoAMyhLHNrVHJfzO6ARZAbQRlY4UGWfdDnLlZEF0BvKOMd77uIiIjSZRwq3Jb3Fa3I8+2UA==", - "dev": true, - "dependencies": { - "@jest/test-result": "^29.3.1", - "graceful-fs": "^4.2.9", - "jest-haste-map": "^29.3.1", - "slash": "^3.0.0" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/@jest/transform": { - "version": "29.3.1", - "resolved": "https://registry.npmjs.org/@jest/transform/-/transform-29.3.1.tgz", - "integrity": "sha512-8wmCFBTVGYqFNLWfcOWoVuMuKYPUBTnTMDkdvFtAYELwDOl9RGwOsvQWGPFxDJ8AWY9xM/8xCXdqmPK3+Q5Lug==", - "dev": true, - "dependencies": { - "@babel/core": "^7.11.6", - "@jest/types": "^29.3.1", - "@jridgewell/trace-mapping": "^0.3.15", - "babel-plugin-istanbul": "^6.1.1", - "chalk": "^4.0.0", - "convert-source-map": "^2.0.0", - "fast-json-stable-stringify": "^2.1.0", - "graceful-fs": "^4.2.9", - "jest-haste-map": "^29.3.1", - "jest-regex-util": "^29.2.0", - "jest-util": "^29.3.1", - "micromatch": "^4.0.4", - "pirates": "^4.0.4", - "slash": "^3.0.0", - "write-file-atomic": "^4.0.1" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/@jest/types": { - "version": "29.3.1", - "resolved": "https://registry.npmjs.org/@jest/types/-/types-29.3.1.tgz", - "integrity": "sha512-d0S0jmmTpjnhCmNpApgX3jrUZgZ22ivKJRvL2lli5hpCRoNnp1f85r2/wpKfXuYu8E7Jjh1hGfhPyup1NM5AmA==", - "dev": true, - "dependencies": { - "@jest/schemas": "^29.0.0", - "@types/istanbul-lib-coverage": "^2.0.0", - "@types/istanbul-reports": "^3.0.0", - "@types/node": "*", - "@types/yargs": "^17.0.8", - "chalk": "^4.0.0" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/@jridgewell/gen-mapping": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.1.1.tgz", - "integrity": "sha512-sQXCasFk+U8lWYEe66WxRDOE9PjVz4vSM51fTu3Hw+ClTpUSQb718772vH3pyS5pShp6lvQM7SxgIDXXXmOX7w==", - "dev": true, - "dependencies": { - "@jridgewell/set-array": "^1.0.0", - "@jridgewell/sourcemap-codec": "^1.4.10" - }, - "engines": { - "node": ">=6.0.0" - } - }, - "node_modules/@jridgewell/resolve-uri": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.0.tgz", - "integrity": "sha512-F2msla3tad+Mfht5cJq7LSXcdudKTWCVYUgw6pLFOOHSTtZlj6SWNYAp+AhuqLmWdBO2X5hPrLcu8cVP8fy28w==", - "dev": true, - "engines": { - "node": ">=6.0.0" - } - }, - "node_modules/@jridgewell/set-array": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/@jridgewell/set-array/-/set-array-1.1.2.tgz", - "integrity": "sha512-xnkseuNADM0gt2bs+BvhO0p78Mk762YnZdsuzFV018NoG1Sj1SCQvpSqa7XUaTam5vAGasABV9qXASMKnFMwMw==", - "dev": true, - "engines": { - "node": ">=6.0.0" - } - }, - "node_modules/@jridgewell/sourcemap-codec": { - "version": "1.4.14", - "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.14.tgz", - "integrity": "sha512-XPSJHWmi394fuUuzDnGz1wiKqWfo1yXecHQMRf2l6hztTO+nPru658AyDngaBe7isIxEkRsPR3FZh+s7iVa4Uw==", - "dev": true - }, - "node_modules/@jridgewell/trace-mapping": { - "version": "0.3.17", - "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.17.tgz", - "integrity": "sha512-MCNzAp77qzKca9+W/+I0+sEpaUnZoeasnghNeVc41VZCEKaCH73Vq3BZZ/SzWIgrqE4H4ceI+p+b6C0mHf9T4g==", - "dev": true, - "dependencies": { - "@jridgewell/resolve-uri": "3.1.0", - "@jridgewell/sourcemap-codec": "1.4.14" - } - }, - "node_modules/@nodelib/fs.scandir": { - "version": "2.1.5", - "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", - "integrity": "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==", - "dev": true, - "dependencies": { - "@nodelib/fs.stat": "2.0.5", - "run-parallel": "^1.1.9" - }, - "engines": { - "node": ">= 8" - } - }, - "node_modules/@nodelib/fs.stat": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz", - "integrity": "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==", - "dev": true, - "engines": { - "node": ">= 8" - } - }, - "node_modules/@nodelib/fs.walk": { - "version": "1.2.8", - "resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz", - "integrity": "sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==", - "dev": true, - "dependencies": { - "@nodelib/fs.scandir": "2.1.5", - "fastq": "^1.6.0" - }, - "engines": { - "node": ">= 8" - } - }, - "node_modules/@pkgr/utils": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/@pkgr/utils/-/utils-2.3.1.tgz", - "integrity": "sha512-wfzX8kc1PMyUILA+1Z/EqoE4UCXGy0iRGMhPwdfae1+f0OXlLqCk+By+aMzgJBzR9AzS4CDizioG6Ss1gvAFJw==", - "dev": true, - "dependencies": { - "cross-spawn": "^7.0.3", - "is-glob": "^4.0.3", - "open": "^8.4.0", - "picocolors": "^1.0.0", - "tiny-glob": "^0.2.9", - "tslib": "^2.4.0" - }, - "engines": { - "node": "^12.20.0 || ^14.18.0 || >=16.0.0" - }, - "funding": { - "url": "https://opencollective.com/unts" - } - }, - "node_modules/@sinclair/typebox": { - "version": "0.24.51", - "resolved": "https://registry.npmjs.org/@sinclair/typebox/-/typebox-0.24.51.tgz", - "integrity": "sha512-1P1OROm/rdubP5aFDSZQILU0vrLCJ4fvHt6EoqHEM+2D/G5MK3bIaymUKLit8Js9gbns5UyJnkP/TZROLw4tUA==", - "dev": true - }, - "node_modules/@sinonjs/commons": { - "version": "1.8.6", - "resolved": "https://registry.npmjs.org/@sinonjs/commons/-/commons-1.8.6.tgz", - "integrity": "sha512-Ky+XkAkqPZSm3NLBeUng77EBQl3cmeJhITaGHdYH8kjVB+aun3S4XBRti2zt17mtt0mIUDiNxYeoJm6drVvBJQ==", - "dev": true, - "dependencies": { - "type-detect": "4.0.8" - } - }, - "node_modules/@sinonjs/fake-timers": { - "version": "9.1.2", - "resolved": "https://registry.npmjs.org/@sinonjs/fake-timers/-/fake-timers-9.1.2.tgz", - "integrity": "sha512-BPS4ynJW/o92PUR4wgriz2Ud5gpST5vz6GQfMixEDK0Z8ZCUv2M7SkBLykH56T++Xs+8ln9zTGbOvNGIe02/jw==", - "dev": true, - "dependencies": { - "@sinonjs/commons": "^1.7.0" - } - }, - "node_modules/@tsconfig/node10": { - "version": "1.0.9", - "resolved": "https://registry.npmjs.org/@tsconfig/node10/-/node10-1.0.9.tgz", - "integrity": "sha512-jNsYVVxU8v5g43Erja32laIDHXeoNvFEpX33OK4d6hljo3jDhCBDhx5dhCCTMWUojscpAagGiRkBKxpdl9fxqA==", - "dev": true - }, - "node_modules/@tsconfig/node12": { - "version": "1.0.11", - "resolved": "https://registry.npmjs.org/@tsconfig/node12/-/node12-1.0.11.tgz", - "integrity": "sha512-cqefuRsh12pWyGsIoBKJA9luFu3mRxCA+ORZvA4ktLSzIuCUtWVxGIuXigEwO5/ywWFMZ2QEGKWvkZG1zDMTag==", - "dev": true - }, - "node_modules/@tsconfig/node14": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/@tsconfig/node14/-/node14-1.0.3.tgz", - "integrity": "sha512-ysT8mhdixWK6Hw3i1V2AeRqZ5WfXg1G43mqoYlM2nc6388Fq5jcXyr5mRsqViLx/GJYdoL0bfXD8nmF+Zn/Iow==", - "dev": true - }, - "node_modules/@tsconfig/node16": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/@tsconfig/node16/-/node16-1.0.3.tgz", - "integrity": "sha512-yOlFc+7UtL/89t2ZhjPvvB/DeAr3r+Dq58IgzsFkOAvVC6NMJXmCGjbptdXdR9qsX7pKcTL+s87FtYREi2dEEQ==", - "dev": true - }, - "node_modules/@types/babel__core": { - "version": "7.1.20", - "resolved": "https://registry.npmjs.org/@types/babel__core/-/babel__core-7.1.20.tgz", - "integrity": "sha512-PVb6Bg2QuscZ30FvOU7z4guG6c926D9YRvOxEaelzndpMsvP+YM74Q/dAFASpg2l6+XLalxSGxcq/lrgYWZtyQ==", - "dev": true, - "dependencies": { - "@babel/parser": "^7.1.0", - "@babel/types": "^7.0.0", - "@types/babel__generator": "*", - "@types/babel__template": "*", - "@types/babel__traverse": "*" - } - }, - "node_modules/@types/babel__generator": { - "version": "7.6.4", - "resolved": "https://registry.npmjs.org/@types/babel__generator/-/babel__generator-7.6.4.tgz", - "integrity": "sha512-tFkciB9j2K755yrTALxD44McOrk+gfpIpvC3sxHjRawj6PfnQxrse4Clq5y/Rq+G3mrBurMax/lG8Qn2t9mSsg==", - "dev": true, - "dependencies": { - "@babel/types": "^7.0.0" - } - }, - "node_modules/@types/babel__template": { - "version": "7.4.1", - "resolved": "https://registry.npmjs.org/@types/babel__template/-/babel__template-7.4.1.tgz", - "integrity": "sha512-azBFKemX6kMg5Io+/rdGT0dkGreboUVR0Cdm3fz9QJWpaQGJRQXl7C+6hOTCZcMll7KFyEQpgbYI2lHdsS4U7g==", - "dev": true, - "dependencies": { - "@babel/parser": "^7.1.0", - "@babel/types": "^7.0.0" - } - }, - "node_modules/@types/babel__traverse": { - "version": "7.18.3", - "resolved": "https://registry.npmjs.org/@types/babel__traverse/-/babel__traverse-7.18.3.tgz", - "integrity": "sha512-1kbcJ40lLB7MHsj39U4Sh1uTd2E7rLEa79kmDpI6cy+XiXsteB3POdQomoq4FxszMrO3ZYchkhYJw7A2862b3w==", - "dev": true, - "dependencies": { - "@babel/types": "^7.3.0" - } - }, - "node_modules/@types/graceful-fs": { - "version": "4.1.6", - "resolved": "https://registry.npmjs.org/@types/graceful-fs/-/graceful-fs-4.1.6.tgz", - "integrity": "sha512-Sig0SNORX9fdW+bQuTEovKj3uHcUL6LQKbCrrqb1X7J6/ReAbhCXRAhc+SMejhLELFj2QcyuxmUooZ4bt5ReSw==", - "dev": true, - "dependencies": { - "@types/node": "*" - } - }, - "node_modules/@types/istanbul-lib-coverage": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/@types/istanbul-lib-coverage/-/istanbul-lib-coverage-2.0.4.tgz", - "integrity": "sha512-z/QT1XN4K4KYuslS23k62yDIDLwLFkzxOuMplDtObz0+y7VqJCaO2o+SPwHCvLFZh7xazvvoor2tA/hPz9ee7g==", - "dev": true - }, - "node_modules/@types/istanbul-lib-report": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/@types/istanbul-lib-report/-/istanbul-lib-report-3.0.0.tgz", - "integrity": "sha512-plGgXAPfVKFoYfa9NpYDAkseG+g6Jr294RqeqcqDixSbU34MZVJRi/P+7Y8GDpzkEwLaGZZOpKIEmeVZNtKsrg==", - "dev": true, - "dependencies": { - "@types/istanbul-lib-coverage": "*" - } - }, - "node_modules/@types/istanbul-reports": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/@types/istanbul-reports/-/istanbul-reports-3.0.1.tgz", - "integrity": "sha512-c3mAZEuK0lvBp8tmuL74XRKn1+y2dcwOUpH7x4WrF6gk1GIgiluDRgMYQtw2OFcBvAJWlt6ASU3tSqxp0Uu0Aw==", - "dev": true, - "dependencies": { - "@types/istanbul-lib-report": "*" - } - }, - "node_modules/@types/jest": { - "version": "29.2.5", - "resolved": "https://registry.npmjs.org/@types/jest/-/jest-29.2.5.tgz", - "integrity": "sha512-H2cSxkKgVmqNHXP7TC2L/WUorrZu8ZigyRywfVzv6EyBlxj39n4C00hjXYQWsbwqgElaj/CiAeSRmk5GoaKTgw==", - "dev": true, - "dependencies": { - "expect": "^29.0.0", - "pretty-format": "^29.0.0" - } - }, - "node_modules/@types/json-schema": { - "version": "7.0.11", - "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.11.tgz", - "integrity": "sha512-wOuvG1SN4Us4rez+tylwwwCV1psiNVOkJeM3AUWUNWg/jDQY2+HE/444y5gc+jBmRqASOm2Oeh5c1axHobwRKQ==", - "dev": true - }, - "node_modules/@types/json5": { - "version": "0.0.29", - "resolved": "https://registry.npmjs.org/@types/json5/-/json5-0.0.29.tgz", - "integrity": "sha512-dRLjCWHYg4oaA77cxO64oO+7JwCwnIzkZPdrrC71jQmQtlhM556pwKo5bUzqvZndkVbeFLIIi+9TC40JNF5hNQ==", - "dev": true - }, - "node_modules/@types/node": { - "version": "18.11.15", - "resolved": "https://registry.npmjs.org/@types/node/-/node-18.11.15.tgz", - "integrity": "sha512-VkhBbVo2+2oozlkdHXLrb3zjsRkpdnaU2bXmX8Wgle3PUi569eLRaHGlgETQHR7lLL1w7GiG3h9SnePhxNDecw==", - "dev": true - }, - "node_modules/@types/prettier": { - "version": "2.7.2", - "resolved": "https://registry.npmjs.org/@types/prettier/-/prettier-2.7.2.tgz", - "integrity": "sha512-KufADq8uQqo1pYKVIYzfKbJfBAc0sOeXqGbFaSpv8MRmC/zXgowNZmFcbngndGk922QDmOASEXUZCaY48gs4cg==", - "dev": true - }, - "node_modules/@types/semver": { - "version": "7.3.13", - "resolved": "https://registry.npmjs.org/@types/semver/-/semver-7.3.13.tgz", - "integrity": "sha512-21cFJr9z3g5dW8B0CVI9g2O9beqaThGQ6ZFBqHfwhzLDKUxaqTIy3vnfah/UPkfOiF2pLq+tGz+W8RyCskuslw==", - "dev": true - }, - "node_modules/@types/stack-utils": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/@types/stack-utils/-/stack-utils-2.0.1.tgz", - "integrity": "sha512-Hl219/BT5fLAaz6NDkSuhzasy49dwQS/DSdu4MdggFB8zcXv7vflBI3xp7FEmkmdDkBUI2bPUNeMttp2knYdxw==", - "dev": true - }, - "node_modules/@types/yargs": { - "version": "17.0.19", - "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-17.0.19.tgz", - "integrity": "sha512-cAx3qamwaYX9R0fzOIZAlFpo4A+1uBVCxqpKz9D26uTF4srRXaGTTsikQmaotCtNdbhzyUH7ft6p9ktz9s6UNQ==", - "dev": true, - "dependencies": { - "@types/yargs-parser": "*" - } - }, - "node_modules/@types/yargs-parser": { - "version": "21.0.0", - "resolved": "https://registry.npmjs.org/@types/yargs-parser/-/yargs-parser-21.0.0.tgz", - "integrity": "sha512-iO9ZQHkZxHn4mSakYV0vFHAVDyEOIJQrV2uZ06HxEPcx+mt8swXoZHIbaaJ2crJYFfErySgktuTZ3BeLz+XmFA==", - "dev": true - }, - "node_modules/@typescript-eslint/eslint-plugin": { - "version": "5.48.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-5.48.1.tgz", - "integrity": "sha512-9nY5K1Rp2ppmpb9s9S2aBiF3xo5uExCehMDmYmmFqqyxgenbHJ3qbarcLt4ITgaD6r/2ypdlcFRdcuVPnks+fQ==", - "dev": true, - "dependencies": { - "@typescript-eslint/scope-manager": "5.48.1", - "@typescript-eslint/type-utils": "5.48.1", - "@typescript-eslint/utils": "5.48.1", - "debug": "^4.3.4", - "ignore": "^5.2.0", - "natural-compare-lite": "^1.4.0", - "regexpp": "^3.2.0", - "semver": "^7.3.7", - "tsutils": "^3.21.0" - }, - "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - }, - "peerDependencies": { - "@typescript-eslint/parser": "^5.0.0", - "eslint": "^6.0.0 || ^7.0.0 || ^8.0.0" - }, - "peerDependenciesMeta": { - "typescript": { - "optional": true - } - } - }, - "node_modules/@typescript-eslint/parser": { - "version": "5.48.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-5.48.1.tgz", - "integrity": "sha512-4yg+FJR/V1M9Xoq56SF9Iygqm+r5LMXvheo6DQ7/yUWynQ4YfCRnsKuRgqH4EQ5Ya76rVwlEpw4Xu+TgWQUcdA==", - "dev": true, - "dependencies": { - "@typescript-eslint/scope-manager": "5.48.1", - "@typescript-eslint/types": "5.48.1", - "@typescript-eslint/typescript-estree": "5.48.1", - "debug": "^4.3.4" - }, - "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - }, - "peerDependencies": { - "eslint": "^6.0.0 || ^7.0.0 || ^8.0.0" - }, - "peerDependenciesMeta": { - "typescript": { - "optional": true - } - } - }, - "node_modules/@typescript-eslint/scope-manager": { - "version": "5.48.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-5.48.1.tgz", - "integrity": "sha512-S035ueRrbxRMKvSTv9vJKIWgr86BD8s3RqoRZmsSh/s8HhIs90g6UlK8ZabUSjUZQkhVxt7nmZ63VJ9dcZhtDQ==", - "dev": true, - "dependencies": { - "@typescript-eslint/types": "5.48.1", - "@typescript-eslint/visitor-keys": "5.48.1" - }, - "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - } - }, - "node_modules/@typescript-eslint/type-utils": { - "version": "5.48.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-5.48.1.tgz", - "integrity": "sha512-Hyr8HU8Alcuva1ppmqSYtM/Gp0q4JOp1F+/JH5D1IZm/bUBrV0edoewQZiEc1r6I8L4JL21broddxK8HAcZiqQ==", - "dev": true, - "dependencies": { - "@typescript-eslint/typescript-estree": "5.48.1", - "@typescript-eslint/utils": "5.48.1", - "debug": "^4.3.4", - "tsutils": "^3.21.0" - }, - "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - }, - "peerDependencies": { - "eslint": "*" - }, - "peerDependenciesMeta": { - "typescript": { - "optional": true - } - } - }, - "node_modules/@typescript-eslint/types": { - "version": "5.48.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-5.48.1.tgz", - "integrity": "sha512-xHyDLU6MSuEEdIlzrrAerCGS3T7AA/L8Hggd0RCYBi0w3JMvGYxlLlXHeg50JI9Tfg5MrtsfuNxbS/3zF1/ATg==", - "dev": true, - "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - } - }, - "node_modules/@typescript-eslint/typescript-estree": { - "version": "5.48.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-5.48.1.tgz", - "integrity": "sha512-Hut+Osk5FYr+sgFh8J/FHjqX6HFcDzTlWLrFqGoK5kVUN3VBHF/QzZmAsIXCQ8T/W9nQNBTqalxi1P3LSqWnRA==", - "dev": true, - "dependencies": { - "@typescript-eslint/types": "5.48.1", - "@typescript-eslint/visitor-keys": "5.48.1", - "debug": "^4.3.4", - "globby": "^11.1.0", - "is-glob": "^4.0.3", - "semver": "^7.3.7", - "tsutils": "^3.21.0" - }, - "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - }, - "peerDependenciesMeta": { - "typescript": { - "optional": true - } - } - }, - "node_modules/@typescript-eslint/utils": { - "version": "5.48.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-5.48.1.tgz", - "integrity": "sha512-SmQuSrCGUOdmGMwivW14Z0Lj8dxG1mOFZ7soeJ0TQZEJcs3n5Ndgkg0A4bcMFzBELqLJ6GTHnEU+iIoaD6hFGA==", - "dev": true, - "dependencies": { - "@types/json-schema": "^7.0.9", - "@types/semver": "^7.3.12", - "@typescript-eslint/scope-manager": "5.48.1", - "@typescript-eslint/types": "5.48.1", - "@typescript-eslint/typescript-estree": "5.48.1", - "eslint-scope": "^5.1.1", - "eslint-utils": "^3.0.0", - "semver": "^7.3.7" - }, - "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - }, - "peerDependencies": { - "eslint": "^6.0.0 || ^7.0.0 || ^8.0.0" - } - }, - "node_modules/@typescript-eslint/visitor-keys": { - "version": "5.48.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-5.48.1.tgz", - "integrity": "sha512-Ns0XBwmfuX7ZknznfXozgnydyR8F6ev/KEGePP4i74uL3ArsKbEhJ7raeKr1JSa997DBDwol/4a0Y+At82c9dA==", - "dev": true, - "dependencies": { - "@typescript-eslint/types": "5.48.1", - "eslint-visitor-keys": "^3.3.0" - }, - "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - } - }, - "node_modules/acorn": { - "version": "8.8.1", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.8.1.tgz", - "integrity": "sha512-7zFpHzhnqYKrkYdUjF1HI1bzd0VygEGX8lFk4k5zVMqHEoES+P+7TKI+EvLO9WVMJ8eekdO0aDEK044xTXwPPA==", - "dev": true, - "bin": { - "acorn": "bin/acorn" - }, - "engines": { - "node": ">=0.4.0" - } - }, - "node_modules/acorn-jsx": { - "version": "5.3.2", - "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.2.tgz", - "integrity": "sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==", - "dev": true, - "peerDependencies": { - "acorn": "^6.0.0 || ^7.0.0 || ^8.0.0" - } - }, - "node_modules/acorn-walk": { - "version": "8.2.0", - "resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-8.2.0.tgz", - "integrity": "sha512-k+iyHEuPgSw6SbuDpGQM+06HQUa04DZ3o+F6CSzXMvvI5KMvnaEqXe+YVe555R9nn6GPt404fos4wcgpw12SDA==", - "dev": true, - "engines": { - "node": ">=0.4.0" - } - }, - "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/ansi-escapes": { - "version": "4.3.2", - "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-4.3.2.tgz", - "integrity": "sha512-gKXj5ALrKWQLsYG9jlTRmR/xKluxHV+Z9QEwNIgCfM1/uwPMCuzVVnh5mwTd+OuBZcwSIMbqssNWRm1lE51QaQ==", - "dev": true, - "dependencies": { - "type-fest": "^0.21.3" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/ansi-escapes/node_modules/type-fest": { - "version": "0.21.3", - "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.21.3.tgz", - "integrity": "sha512-t0rzBq87m3fVcduHDUFhKmyyX+9eo6WQjZvf51Ea/M0Q7+T374Jp1aUiyUl0GKxp8M/OETVHSDvmkyPgvX+X2w==", - "dev": true, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/ansi-regex": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", - "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "dev": true, - "dependencies": { - "color-convert": "^2.0.1" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" - } - }, - "node_modules/anymatch": { - "version": "3.1.3", - "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.3.tgz", - "integrity": "sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==", - "dev": true, - "dependencies": { - "normalize-path": "^3.0.0", - "picomatch": "^2.0.4" - }, - "engines": { - "node": ">= 8" - } - }, - "node_modules/arg": { - "version": "4.1.3", - "resolved": "https://registry.npmjs.org/arg/-/arg-4.1.3.tgz", - "integrity": "sha512-58S9QDqG0Xx27YwPSt9fJxivjYl432YCwfDMfZ+71RAqUrZef7LrKQZ3LHLOwCS4FLNBplP533Zx895SeOCHvA==", - "dev": true - }, - "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/array-includes": { - "version": "3.1.6", - "resolved": "https://registry.npmjs.org/array-includes/-/array-includes-3.1.6.tgz", - "integrity": "sha512-sgTbLvL6cNnw24FnbaDyjmvddQ2ML8arZsgaJhoABMoplz/4QRhtrYS+alr1BUM1Bwp6dhx8vVCBSLG+StwOFw==", - "dev": true, - "dependencies": { - "call-bind": "^1.0.2", - "define-properties": "^1.1.4", - "es-abstract": "^1.20.4", - "get-intrinsic": "^1.1.3", - "is-string": "^1.0.7" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/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, - "engines": { - "node": ">=8" - } - }, - "node_modules/array.prototype.flat": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/array.prototype.flat/-/array.prototype.flat-1.3.1.tgz", - "integrity": "sha512-roTU0KWIOmJ4DRLmwKd19Otg0/mT3qPNt0Qb3GWW8iObuZXxrjB/pzn0R3hqpRSWg4HCwqx+0vwOnWnvlOyeIA==", - "dev": true, - "dependencies": { - "call-bind": "^1.0.2", - "define-properties": "^1.1.4", - "es-abstract": "^1.20.4", - "es-shim-unscopables": "^1.0.0" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/astral-regex": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/astral-regex/-/astral-regex-2.0.0.tgz", - "integrity": "sha512-Z7tMw1ytTXt5jqMcOP+OQteU1VuNK9Y02uuJtKQ1Sv69jXQKKg5cibLwGJow8yzZP+eAc18EmLGPal0bp36rvQ==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/at-least-node": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/at-least-node/-/at-least-node-1.0.0.tgz", - "integrity": "sha512-+q/t7Ekv1EDY2l6Gda6LLiX14rU9TV20Wa3ofeQmwPFZbOMo9DXrLbOjFaaclkXKWidIaopwAObQDqwWtGUjqg==", - "engines": { - "node": ">= 4.0.0" - } - }, - "node_modules/available-typed-arrays": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/available-typed-arrays/-/available-typed-arrays-1.0.5.tgz", - "integrity": "sha512-DMD0KiN46eipeziST1LPP/STfDU0sufISXmjSgvVsoU2tqxctQeASejWcfNtxYKqETM1UxQ8sp2OrSBWpHY6sw==", - "dev": true, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/aws-cdk": { - "version": "2.55.1", - "resolved": "https://registry.npmjs.org/aws-cdk/-/aws-cdk-2.55.1.tgz", - "integrity": "sha512-M/d4lO7rLMvPedNj7pEQtwyxn7nVLluiHggftXlYHOIeaoMG1QCbH1zTuZtMZZxdRRD4ZiOEHvvPYFU/HMcrPQ==", - "dev": true, - "bin": { - "cdk": "bin/cdk" - }, - "engines": { - "node": ">= 14.15.0" - }, - "optionalDependencies": { - "fsevents": "2.3.2" - } - }, - "node_modules/aws-cdk-lib": { - "version": "2.55.1", - "resolved": "https://registry.npmjs.org/aws-cdk-lib/-/aws-cdk-lib-2.55.1.tgz", - "integrity": "sha512-v0MhL6RqazQ2HKj9TXJvXKQcQNIDYeRzcOJ2xB2Usz56xodArc2goLu2P51X5J84xOO4w2AgNaWMCBzd7MbyOQ==", - "bundleDependencies": [ - "@balena/dockerignore", - "case", - "fs-extra", - "ignore", - "jsonschema", - "minimatch", - "punycode", - "semver", - "yaml" - ], - "dependencies": { - "@aws-cdk/asset-awscli-v1": "^2.2.30", - "@aws-cdk/asset-kubectl-v20": "^2.1.1", - "@aws-cdk/asset-node-proxy-agent-v5": "^2.0.38", - "@balena/dockerignore": "^1.0.2", - "case": "1.6.3", - "fs-extra": "^9.1.0", - "ignore": "^5.2.1", - "jsonschema": "^1.4.1", - "minimatch": "^3.1.2", - "punycode": "^2.1.1", - "semver": "^7.3.8", - "yaml": "1.10.2" - }, - "engines": { - "node": ">= 14.15.0" - }, - "peerDependencies": { - "constructs": "^10.0.0" - } - }, - "node_modules/aws-cdk-lib/node_modules/@balena/dockerignore": { - "version": "1.0.2", - "inBundle": true, - "license": "Apache-2.0" - }, - "node_modules/aws-cdk-lib/node_modules/at-least-node": { - "version": "1.0.0", - "inBundle": true, - "license": "ISC", - "engines": { - "node": ">= 4.0.0" - } - }, - "node_modules/aws-cdk-lib/node_modules/balanced-match": { - "version": "1.0.2", - "inBundle": true, - "license": "MIT" - }, - "node_modules/aws-cdk-lib/node_modules/brace-expansion": { - "version": "1.1.11", - "inBundle": true, - "license": "MIT", - "dependencies": { - "balanced-match": "^1.0.0", - "concat-map": "0.0.1" - } - }, - "node_modules/aws-cdk-lib/node_modules/case": { - "version": "1.6.3", - "inBundle": true, - "license": "(MIT OR GPL-3.0-or-later)", - "engines": { - "node": ">= 0.8.0" - } - }, - "node_modules/aws-cdk-lib/node_modules/concat-map": { - "version": "0.0.1", - "inBundle": true, - "license": "MIT" - }, - "node_modules/aws-cdk-lib/node_modules/fs-extra": { - "version": "9.1.0", - "inBundle": true, - "license": "MIT", - "dependencies": { - "at-least-node": "^1.0.0", - "graceful-fs": "^4.2.0", - "jsonfile": "^6.0.1", - "universalify": "^2.0.0" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/aws-cdk-lib/node_modules/graceful-fs": { - "version": "4.2.10", - "inBundle": true, - "license": "ISC" - }, - "node_modules/aws-cdk-lib/node_modules/ignore": { - "version": "5.2.1", - "inBundle": true, - "license": "MIT", - "engines": { - "node": ">= 4" - } - }, - "node_modules/aws-cdk-lib/node_modules/jsonfile": { - "version": "6.1.0", - "inBundle": true, - "license": "MIT", - "dependencies": { - "universalify": "^2.0.0" - }, - "optionalDependencies": { - "graceful-fs": "^4.1.6" - } - }, - "node_modules/aws-cdk-lib/node_modules/jsonschema": { - "version": "1.4.1", - "inBundle": true, - "license": "MIT", - "engines": { - "node": "*" - } - }, - "node_modules/aws-cdk-lib/node_modules/lru-cache": { - "version": "6.0.0", - "inBundle": true, - "license": "ISC", - "dependencies": { - "yallist": "^4.0.0" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/aws-cdk-lib/node_modules/minimatch": { - "version": "3.1.2", - "inBundle": true, - "license": "ISC", - "dependencies": { - "brace-expansion": "^1.1.7" - }, - "engines": { - "node": "*" - } - }, - "node_modules/aws-cdk-lib/node_modules/punycode": { - "version": "2.1.1", - "inBundle": true, - "license": "MIT", - "engines": { - "node": ">=6" - } - }, - "node_modules/aws-cdk-lib/node_modules/semver": { - "version": "7.3.8", - "inBundle": true, - "license": "ISC", - "dependencies": { - "lru-cache": "^6.0.0" - }, - "bin": { - "semver": "bin/semver.js" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/aws-cdk-lib/node_modules/universalify": { - "version": "2.0.0", - "inBundle": true, - "license": "MIT", - "engines": { - "node": ">= 10.0.0" - } - }, - "node_modules/aws-cdk-lib/node_modules/yallist": { - "version": "4.0.0", - "inBundle": true, - "license": "ISC" - }, - "node_modules/aws-cdk-lib/node_modules/yaml": { - "version": "1.10.2", - "inBundle": true, - "license": "ISC", - "engines": { - "node": ">= 6" - } - }, - "node_modules/babel-jest": { - "version": "29.3.1", - "resolved": "https://registry.npmjs.org/babel-jest/-/babel-jest-29.3.1.tgz", - "integrity": "sha512-aard+xnMoxgjwV70t0L6wkW/3HQQtV+O0PEimxKgzNqCJnbYmroPojdP2tqKSOAt8QAKV/uSZU8851M7B5+fcA==", - "dev": true, - "dependencies": { - "@jest/transform": "^29.3.1", - "@types/babel__core": "^7.1.14", - "babel-plugin-istanbul": "^6.1.1", - "babel-preset-jest": "^29.2.0", - "chalk": "^4.0.0", - "graceful-fs": "^4.2.9", - "slash": "^3.0.0" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - }, - "peerDependencies": { - "@babel/core": "^7.8.0" - } - }, - "node_modules/babel-plugin-istanbul": { - "version": "6.1.1", - "resolved": "https://registry.npmjs.org/babel-plugin-istanbul/-/babel-plugin-istanbul-6.1.1.tgz", - "integrity": "sha512-Y1IQok9821cC9onCx5otgFfRm7Lm+I+wwxOx738M/WLPZ9Q42m4IG5W0FNX8WLL2gYMZo3JkuXIH2DOpWM+qwA==", - "dev": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.0.0", - "@istanbuljs/load-nyc-config": "^1.0.0", - "@istanbuljs/schema": "^0.1.2", - "istanbul-lib-instrument": "^5.0.4", - "test-exclude": "^6.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/babel-plugin-jest-hoist": { - "version": "29.2.0", - "resolved": "https://registry.npmjs.org/babel-plugin-jest-hoist/-/babel-plugin-jest-hoist-29.2.0.tgz", - "integrity": "sha512-TnspP2WNiR3GLfCsUNHqeXw0RoQ2f9U5hQ5L3XFpwuO8htQmSrhh8qsB6vi5Yi8+kuynN1yjDjQsPfkebmB6ZA==", - "dev": true, - "dependencies": { - "@babel/template": "^7.3.3", - "@babel/types": "^7.3.3", - "@types/babel__core": "^7.1.14", - "@types/babel__traverse": "^7.0.6" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/babel-preset-current-node-syntax": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/babel-preset-current-node-syntax/-/babel-preset-current-node-syntax-1.0.1.tgz", - "integrity": "sha512-M7LQ0bxarkxQoN+vz5aJPsLBn77n8QgTFmo8WK0/44auK2xlCXrYcUxHFxgU7qW5Yzw/CjmLRK2uJzaCd7LvqQ==", - "dev": true, - "dependencies": { - "@babel/plugin-syntax-async-generators": "^7.8.4", - "@babel/plugin-syntax-bigint": "^7.8.3", - "@babel/plugin-syntax-class-properties": "^7.8.3", - "@babel/plugin-syntax-import-meta": "^7.8.3", - "@babel/plugin-syntax-json-strings": "^7.8.3", - "@babel/plugin-syntax-logical-assignment-operators": "^7.8.3", - "@babel/plugin-syntax-nullish-coalescing-operator": "^7.8.3", - "@babel/plugin-syntax-numeric-separator": "^7.8.3", - "@babel/plugin-syntax-object-rest-spread": "^7.8.3", - "@babel/plugin-syntax-optional-catch-binding": "^7.8.3", - "@babel/plugin-syntax-optional-chaining": "^7.8.3", - "@babel/plugin-syntax-top-level-await": "^7.8.3" - }, - "peerDependencies": { - "@babel/core": "^7.0.0" - } - }, - "node_modules/babel-preset-jest": { - "version": "29.2.0", - "resolved": "https://registry.npmjs.org/babel-preset-jest/-/babel-preset-jest-29.2.0.tgz", - "integrity": "sha512-z9JmMJppMxNv8N7fNRHvhMg9cvIkMxQBXgFkane3yKVEvEOP+kB50lk8DFRvF9PGqbyXxlmebKWhuDORO8RgdA==", - "dev": true, - "dependencies": { - "babel-plugin-jest-hoist": "^29.2.0", - "babel-preset-current-node-syntax": "^1.0.0" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0" - } - }, - "node_modules/balanced-match": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", - "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==" - }, - "node_modules/brace-expansion": { - "version": "1.1.11", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", - "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", - "dependencies": { - "balanced-match": "^1.0.0", - "concat-map": "0.0.1" - } - }, - "node_modules/braces": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz", - "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==", - "dev": true, - "dependencies": { - "fill-range": "^7.0.1" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/browserslist": { - "version": "4.21.4", - "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.21.4.tgz", - "integrity": "sha512-CBHJJdDmgjl3daYjN5Cp5kbTf1mUhZoS+beLklHIvkOWscs83YAhLlF3Wsh/lciQYAcbBJgTOD44VtG31ZM4Hw==", - "dev": true, - "funding": [ - { - "type": "opencollective", - "url": "https://opencollective.com/browserslist" - }, - { - "type": "tidelift", - "url": "https://tidelift.com/funding/github/npm/browserslist" - } - ], - "dependencies": { - "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" - }, - "engines": { - "node": "^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7" - } - }, - "node_modules/bs-logger": { - "version": "0.2.6", - "resolved": "https://registry.npmjs.org/bs-logger/-/bs-logger-0.2.6.tgz", - "integrity": "sha512-pd8DCoxmbgc7hyPKOvxtqNcjYoOsABPQdcCUjGp3d42VR2CX1ORhk2A87oqqu5R1kk+76nsxZupkmyd+MVtCog==", - "dev": true, - "dependencies": { - "fast-json-stable-stringify": "2.x" - }, - "engines": { - "node": ">= 6" - } - }, - "node_modules/bser": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/bser/-/bser-2.1.1.tgz", - "integrity": "sha512-gQxTNE/GAfIIrmHLUE3oJyp5FO6HRBfhjnw4/wMmA63ZGDJnWBmgY/lyQBpnDUkGmAhbSe39tx2d/iTOAfglwQ==", - "dev": true, - "dependencies": { - "node-int64": "^0.4.0" - } - }, - "node_modules/buffer-from": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.2.tgz", - "integrity": "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==" - }, - "node_modules/call-bind": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.2.tgz", - "integrity": "sha512-7O+FbCihrB5WGbFYesctwmTKae6rOiIzmz1icreWJ+0aA7LJfuqhEso2T9ncpcFtzMQtzXf2QGGueWJGTYsqrA==", - "dev": true, - "dependencies": { - "function-bind": "^1.1.1", - "get-intrinsic": "^1.0.2" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/callsites": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", - "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==", - "dev": true, - "engines": { - "node": ">=6" - } - }, - "node_modules/camelcase": { - "version": "5.3.1", - "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz", - "integrity": "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==", - "dev": true, - "engines": { - "node": ">=6" - } - }, - "node_modules/caniuse-lite": { - "version": "1.0.30001442", - "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001442.tgz", - "integrity": "sha512-239m03Pqy0hwxYPYR5JwOIxRJfLTWtle9FV8zosfV5pHg+/51uD4nxcUlM8+mWWGfwKtt8lJNHnD3cWw9VZ6ow==", - "dev": true, - "funding": [ - { - "type": "opencollective", - "url": "https://opencollective.com/browserslist" - }, - { - "type": "tidelift", - "url": "https://tidelift.com/funding/github/npm/caniuse-lite" - } - ] - }, - "node_modules/chalk": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", - "dev": true, - "dependencies": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/chalk?sponsor=1" - } - }, - "node_modules/char-regex": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/char-regex/-/char-regex-1.0.2.tgz", - "integrity": "sha512-kWWXztvZ5SBQV+eRgKFeh8q5sLuZY2+8WUIzlxWVTg+oGwY14qylx1KbKzHd8P6ZYkAg0xyIDU9JMHhyJMZ1jw==", - "dev": true, - "engines": { - "node": ">=10" - } - }, - "node_modules/charenc": { - "version": "0.0.2", - "resolved": "https://registry.npmjs.org/charenc/-/charenc-0.0.2.tgz", - "integrity": "sha512-yrLQ/yVUFXkzg7EDQsPieE/53+0RlaWTs+wBrvW36cyilJ2SaDWfl4Yj7MtLTXleV9uEKefbAGUPv2/iWSooRA==", - "dev": true, - "engines": { - "node": "*" - } - }, - "node_modules/ci-info": { - "version": "3.7.1", - "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-3.7.1.tgz", - "integrity": "sha512-4jYS4MOAaCIStSRwiuxc4B8MYhIe676yO1sYGzARnjXkWpmzZMMYxY6zu8WYWDhSuth5zhrQ1rhNSibyyvv4/w==", - "dev": true, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/sibiraj-s" - } - ], - "engines": { - "node": ">=8" - } - }, - "node_modules/cjs-module-lexer": { - "version": "1.2.2", - "resolved": "https://registry.npmjs.org/cjs-module-lexer/-/cjs-module-lexer-1.2.2.tgz", - "integrity": "sha512-cOU9usZw8/dXIXKtwa8pM0OTJQuJkxMN6w30csNRUerHfeQ5R6U3kkU/FtJeIf3M202OHfY2U8ccInBG7/xogA==", - "dev": true - }, - "node_modules/cliui": { - "version": "8.0.1", - "resolved": "https://registry.npmjs.org/cliui/-/cliui-8.0.1.tgz", - "integrity": "sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ==", - "dev": true, - "dependencies": { - "string-width": "^4.2.0", - "strip-ansi": "^6.0.1", - "wrap-ansi": "^7.0.0" - }, - "engines": { - "node": ">=12" - } - }, - "node_modules/co": { - "version": "4.6.0", - "resolved": "https://registry.npmjs.org/co/-/co-4.6.0.tgz", - "integrity": "sha512-QVb0dM5HvG+uaxitm8wONl7jltx8dqhfU33DcqtOZcLSVIKSDDLDi7+0LbAKiyI8hD9u42m2YxXSkMGWThaecQ==", - "dev": true, - "engines": { - "iojs": ">= 1.0.0", - "node": ">= 0.12.0" - } - }, - "node_modules/collect-v8-coverage": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/collect-v8-coverage/-/collect-v8-coverage-1.0.1.tgz", - "integrity": "sha512-iBPtljfCNcTKNAto0KEtDfZ3qzjJvqE3aTGZsbhjSBlorqpXJlaWWtPO35D+ZImoC3KWejX64o+yPGxhWSTzfg==", - "dev": true - }, - "node_modules/color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "dev": true, - "dependencies": { - "color-name": "~1.1.4" - }, - "engines": { - "node": ">=7.0.0" - } - }, - "node_modules/color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true - }, - "node_modules/concat-map": { - "version": "0.0.1", - "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", - "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==" - }, - "node_modules/constructs": { - "version": "10.1.216", - "resolved": "https://registry.npmjs.org/constructs/-/constructs-10.1.216.tgz", - "integrity": "sha512-Nx/Pzuyy46Bc5LFu3XPSmTKNcjN4ChQ/R3syOb7bJLfQ5VhJn+o0aCKBVwnbuF1av0YCG6IaDz8fdtWhjefJjA==", - "engines": { - "node": ">= 14.17.0" - } - }, - "node_modules/convert-source-map": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-2.0.0.tgz", - "integrity": "sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==", - "dev": true - }, - "node_modules/create-require": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/create-require/-/create-require-1.1.1.tgz", - "integrity": "sha512-dcKFX3jn0MpIaXjisoRvexIJVEKzaq7z2rZKxf+MSr9TkdmHmsU4m2lcLojrj/FHl8mk5VxMmYA+ftRkP/3oKQ==", - "dev": true - }, - "node_modules/cross-spawn": { - "version": "7.0.3", - "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz", - "integrity": "sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==", - "dev": true, - "dependencies": { - "path-key": "^3.1.0", - "shebang-command": "^2.0.0", - "which": "^2.0.1" - }, - "engines": { - "node": ">= 8" - } - }, - "node_modules/crypt": { - "version": "0.0.2", - "resolved": "https://registry.npmjs.org/crypt/-/crypt-0.0.2.tgz", - "integrity": "sha512-mCxBlsHFYh9C+HVpiEacem8FEBnMXgU9gy4zmNC+SXAZNB/1idgp/aulFJ4FgCi7GPEVbfyng092GqL2k2rmow==", - "dev": true, - "engines": { - "node": "*" - } - }, - "node_modules/debug": { - "version": "4.3.4", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", - "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", - "dev": true, - "dependencies": { - "ms": "2.1.2" - }, - "engines": { - "node": ">=6.0" - }, - "peerDependenciesMeta": { - "supports-color": { - "optional": true - } - } - }, - "node_modules/dedent": { - "version": "0.7.0", - "resolved": "https://registry.npmjs.org/dedent/-/dedent-0.7.0.tgz", - "integrity": "sha512-Q6fKUPqnAHAyhiUgFU7BUzLiv0kd8saH9al7tnu5Q/okj6dnupxyTgFIBjVzJATdfIAm9NAsvXNzjaKa+bxVyA==", - "dev": true - }, - "node_modules/deep-is": { - "version": "0.1.4", - "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.4.tgz", - "integrity": "sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==", - "dev": true - }, - "node_modules/deepmerge": { - "version": "4.2.2", - "resolved": "https://registry.npmjs.org/deepmerge/-/deepmerge-4.2.2.tgz", - "integrity": "sha512-FJ3UgI4gIl+PHZm53knsuSFpE+nESMr7M4v9QcgB7S63Kj/6WqMiFQJpBBYz1Pt+66bZpP3Q7Lye0Oo9MPKEdg==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/define-lazy-prop": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/define-lazy-prop/-/define-lazy-prop-2.0.0.tgz", - "integrity": "sha512-Ds09qNh8yw3khSjiJjiUInaGX9xlqZDY7JVryGxdxV7NPeuqQfplOpQ66yJFZut3jLa5zOwkXw1g9EI2uKh4Og==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/define-properties": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.1.4.tgz", - "integrity": "sha512-uckOqKcfaVvtBdsVkdPv3XjveQJsNQqmhXgRi8uhvWWuPYZCNlzT8qAyblUgNoXdHdjMTzAqeGjAoli8f+bzPA==", - "dev": true, - "dependencies": { - "has-property-descriptors": "^1.0.0", - "object-keys": "^1.1.1" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/detect-newline": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/detect-newline/-/detect-newline-3.1.0.tgz", - "integrity": "sha512-TLz+x/vEXm/Y7P7wn1EJFNLxYpUD4TgMosxY6fAVJUnJMbupHBOncxyWUG9OpTaH9EBD7uFI5LfEgmMOc54DsA==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/diff": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/diff/-/diff-5.1.0.tgz", - "integrity": "sha512-D+mk+qE8VC/PAUrlAU34N+VfXev0ghe5ywmpqrawphmVZc1bEfn56uo9qpyGp1p4xpzOHkSW4ztBd6L7Xx4ACw==", - "dev": true, - "engines": { - "node": ">=0.3.1" - } - }, - "node_modules/diff-sequences": { - "version": "29.3.1", - "resolved": "https://registry.npmjs.org/diff-sequences/-/diff-sequences-29.3.1.tgz", - "integrity": "sha512-hlM3QR272NXCi4pq+N4Kok4kOp6EsgOM3ZSpJI7Da3UAs+Ttsi8MRmB6trM/lhyzUxGfOgnpkHtgqm5Q/CTcfQ==", - "dev": true, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/dir-glob": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/dir-glob/-/dir-glob-3.0.1.tgz", - "integrity": "sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA==", - "dev": true, - "dependencies": { - "path-type": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/doctrine": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-3.0.0.tgz", - "integrity": "sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w==", - "dev": true, - "dependencies": { - "esutils": "^2.0.2" - }, - "engines": { - "node": ">=6.0.0" - } - }, - "node_modules/electron-to-chromium": { - "version": "1.4.284", - "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.284.tgz", - "integrity": "sha512-M8WEXFuKXMYMVr45fo8mq0wUrrJHheiKZf6BArTKk9ZBYCKJEOU5H8cdWgDT+qCVZf7Na4lVUaZsA+h6uA9+PA==", - "dev": true - }, - "node_modules/emittery": { - "version": "0.13.1", - "resolved": "https://registry.npmjs.org/emittery/-/emittery-0.13.1.tgz", - "integrity": "sha512-DeWwawk6r5yR9jFgnDKYt4sLS0LmHJJi3ZOnb5/JdbYwj3nW+FxQnHIjhBKz8YLC7oRNPVM9NQ47I3CVx34eqQ==", - "dev": true, - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/sindresorhus/emittery?sponsor=1" - } - }, - "node_modules/emoji-regex": { - "version": "8.0.0", - "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", - "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", - "dev": true - }, - "node_modules/enhanced-resolve": { - "version": "5.12.0", - "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.12.0.tgz", - "integrity": "sha512-QHTXI/sZQmko1cbDoNAa3mJ5qhWUUNAq3vR0/YiD379fWQrcfuoX1+HW2S0MTt7XmoPLapdaDKUtelUSPic7hQ==", - "dev": true, - "dependencies": { - "graceful-fs": "^4.2.4", - "tapable": "^2.2.0" - }, - "engines": { - "node": ">=10.13.0" - } - }, - "node_modules/error-ex": { - "version": "1.3.2", - "resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.2.tgz", - "integrity": "sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g==", - "dev": true, - "dependencies": { - "is-arrayish": "^0.2.1" - } - }, - "node_modules/es-abstract": { - "version": "1.21.1", - "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.21.1.tgz", - "integrity": "sha512-QudMsPOz86xYz/1dG1OuGBKOELjCh99IIWHLzy5znUB6j8xG2yMA7bfTV86VSqKF+Y/H08vQPR+9jyXpuC6hfg==", - "dev": true, - "dependencies": { - "available-typed-arrays": "^1.0.5", - "call-bind": "^1.0.2", - "es-set-tostringtag": "^2.0.1", - "es-to-primitive": "^1.2.1", - "function-bind": "^1.1.1", - "function.prototype.name": "^1.1.5", - "get-intrinsic": "^1.1.3", - "get-symbol-description": "^1.0.0", - "globalthis": "^1.0.3", - "gopd": "^1.0.1", - "has": "^1.0.3", - "has-property-descriptors": "^1.0.0", - "has-proto": "^1.0.1", - "has-symbols": "^1.0.3", - "internal-slot": "^1.0.4", - "is-array-buffer": "^3.0.1", - "is-callable": "^1.2.7", - "is-negative-zero": "^2.0.2", - "is-regex": "^1.1.4", - "is-shared-array-buffer": "^1.0.2", - "is-string": "^1.0.7", - "is-typed-array": "^1.1.10", - "is-weakref": "^1.0.2", - "object-inspect": "^1.12.2", - "object-keys": "^1.1.1", - "object.assign": "^4.1.4", - "regexp.prototype.flags": "^1.4.3", - "safe-regex-test": "^1.0.0", - "string.prototype.trimend": "^1.0.6", - "string.prototype.trimstart": "^1.0.6", - "typed-array-length": "^1.0.4", - "unbox-primitive": "^1.0.2", - "which-typed-array": "^1.1.9" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/es-set-tostringtag": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/es-set-tostringtag/-/es-set-tostringtag-2.0.1.tgz", - "integrity": "sha512-g3OMbtlwY3QewlqAiMLI47KywjWZoEytKr8pf6iTC8uJq5bIAH52Z9pnQ8pVL6whrCto53JZDuUIsifGeLorTg==", - "dev": true, - "dependencies": { - "get-intrinsic": "^1.1.3", - "has": "^1.0.3", - "has-tostringtag": "^1.0.0" - }, - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/es-shim-unscopables": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/es-shim-unscopables/-/es-shim-unscopables-1.0.0.tgz", - "integrity": "sha512-Jm6GPcCdC30eMLbZ2x8z2WuRwAws3zTBBKuusffYVUrNj/GVSUAZ+xKMaUpfNDR5IbyNA5LJbaecoUVbmUcB1w==", - "dev": true, - "dependencies": { - "has": "^1.0.3" - } - }, - "node_modules/es-to-primitive": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/es-to-primitive/-/es-to-primitive-1.2.1.tgz", - "integrity": "sha512-QCOllgZJtaUo9miYBcLChTUaHNjJF3PYs1VidD7AwiEj1kYxKeQTctLAezAOH5ZKRH0g2IgPn6KwB4IT8iRpvA==", - "dev": true, - "dependencies": { - "is-callable": "^1.1.4", - "is-date-object": "^1.0.1", - "is-symbol": "^1.0.2" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/escalade": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.1.tgz", - "integrity": "sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw==", - "dev": true, - "engines": { - "node": ">=6" - } - }, - "node_modules/escape-string-regexp": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", - "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", - "dev": true, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/eslint": { - "version": "8.31.0", - "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.31.0.tgz", - "integrity": "sha512-0tQQEVdmPZ1UtUKXjX7EMm9BlgJ08G90IhWh0PKDCb3ZLsgAOHI8fYSIzYVZej92zsgq+ft0FGsxhJ3xo2tbuA==", - "dev": true, - "dependencies": { - "@eslint/eslintrc": "^1.4.1", - "@humanwhocodes/config-array": "^0.11.8", - "@humanwhocodes/module-importer": "^1.0.1", - "@nodelib/fs.walk": "^1.2.8", - "ajv": "^6.10.0", - "chalk": "^4.0.0", - "cross-spawn": "^7.0.2", - "debug": "^4.3.2", - "doctrine": "^3.0.0", - "escape-string-regexp": "^4.0.0", - "eslint-scope": "^7.1.1", - "eslint-utils": "^3.0.0", - "eslint-visitor-keys": "^3.3.0", - "espree": "^9.4.0", - "esquery": "^1.4.0", - "esutils": "^2.0.2", - "fast-deep-equal": "^3.1.3", - "file-entry-cache": "^6.0.1", - "find-up": "^5.0.0", - "glob-parent": "^6.0.2", - "globals": "^13.19.0", - "grapheme-splitter": "^1.0.4", - "ignore": "^5.2.0", - "import-fresh": "^3.0.0", - "imurmurhash": "^0.1.4", - "is-glob": "^4.0.0", - "is-path-inside": "^3.0.3", - "js-sdsl": "^4.1.4", - "js-yaml": "^4.1.0", - "json-stable-stringify-without-jsonify": "^1.0.1", - "levn": "^0.4.1", - "lodash.merge": "^4.6.2", - "minimatch": "^3.1.2", - "natural-compare": "^1.4.0", - "optionator": "^0.9.1", - "regexpp": "^3.2.0", - "strip-ansi": "^6.0.1", - "strip-json-comments": "^3.1.0", - "text-table": "^0.2.0" - }, - "bin": { - "eslint": "bin/eslint.js" - }, - "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - }, - "funding": { - "url": "https://opencollective.com/eslint" - } - }, - "node_modules/eslint-import-resolver-node": { - "version": "0.3.6", - "resolved": "https://registry.npmjs.org/eslint-import-resolver-node/-/eslint-import-resolver-node-0.3.6.tgz", - "integrity": "sha512-0En0w03NRVMn9Uiyn8YRPDKvWjxCWkslUEhGNTdGx15RvPJYQ+lbOlqrlNI2vEAs4pDYK4f/HN2TbDmk5TP0iw==", - "dev": true, - "dependencies": { - "debug": "^3.2.7", - "resolve": "^1.20.0" - } - }, - "node_modules/eslint-import-resolver-node/node_modules/debug": { - "version": "3.2.7", - "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", - "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", - "dev": true, - "dependencies": { - "ms": "^2.1.1" - } - }, - "node_modules/eslint-import-resolver-typescript": { - "version": "3.5.3", - "resolved": "https://registry.npmjs.org/eslint-import-resolver-typescript/-/eslint-import-resolver-typescript-3.5.3.tgz", - "integrity": "sha512-njRcKYBc3isE42LaTcJNVANR3R99H9bAxBDMNDr2W7yq5gYPxbU3MkdhsQukxZ/Xg9C2vcyLlDsbKfRDg0QvCQ==", - "dev": true, - "dependencies": { - "debug": "^4.3.4", - "enhanced-resolve": "^5.10.0", - "get-tsconfig": "^4.2.0", - "globby": "^13.1.2", - "is-core-module": "^2.10.0", - "is-glob": "^4.0.3", - "synckit": "^0.8.4" - }, - "engines": { - "node": "^14.18.0 || >=16.0.0" - }, - "funding": { - "url": "https://opencollective.com/unts/projects/eslint-import-resolver-ts" - }, - "peerDependencies": { - "eslint": "*", - "eslint-plugin-import": "*" - } - }, - "node_modules/eslint-import-resolver-typescript/node_modules/globby": { - "version": "13.1.3", - "resolved": "https://registry.npmjs.org/globby/-/globby-13.1.3.tgz", - "integrity": "sha512-8krCNHXvlCgHDpegPzleMq07yMYTO2sXKASmZmquEYWEmCx6J5UTRbp5RwMJkTJGtcQ44YpiUYUiN0b9mzy8Bw==", - "dev": true, - "dependencies": { - "dir-glob": "^3.0.1", - "fast-glob": "^3.2.11", - "ignore": "^5.2.0", - "merge2": "^1.4.1", - "slash": "^4.0.0" - }, - "engines": { - "node": "^12.20.0 || ^14.13.1 || >=16.0.0" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/eslint-import-resolver-typescript/node_modules/slash": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/slash/-/slash-4.0.0.tgz", - "integrity": "sha512-3dOsAHXXUkQTpOYcoAxLIorMTp4gIQr5IW3iVb7A7lFIp0VHhnynm9izx6TssdrIcVIESAlVjtnO2K8bg+Coew==", - "dev": true, - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/eslint-module-utils": { - "version": "2.7.4", - "resolved": "https://registry.npmjs.org/eslint-module-utils/-/eslint-module-utils-2.7.4.tgz", - "integrity": "sha512-j4GT+rqzCoRKHwURX7pddtIPGySnX9Si/cgMI5ztrcqOPtk5dDEeZ34CQVPphnqkJytlc97Vuk05Um2mJ3gEQA==", - "dev": true, - "dependencies": { - "debug": "^3.2.7" - }, - "engines": { - "node": ">=4" - }, - "peerDependenciesMeta": { - "eslint": { - "optional": true - } - } - }, - "node_modules/eslint-module-utils/node_modules/debug": { - "version": "3.2.7", - "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", - "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", - "dev": true, - "dependencies": { - "ms": "^2.1.1" - } - }, - "node_modules/eslint-plugin-import": { - "version": "2.26.0", - "resolved": "https://registry.npmjs.org/eslint-plugin-import/-/eslint-plugin-import-2.26.0.tgz", - "integrity": "sha512-hYfi3FXaM8WPLf4S1cikh/r4IxnO6zrhZbEGz2b660EJRbuxgpDS5gkCuYgGWg2xxh2rBuIr4Pvhve/7c31koA==", - "dev": true, - "dependencies": { - "array-includes": "^3.1.4", - "array.prototype.flat": "^1.2.5", - "debug": "^2.6.9", - "doctrine": "^2.1.0", - "eslint-import-resolver-node": "^0.3.6", - "eslint-module-utils": "^2.7.3", - "has": "^1.0.3", - "is-core-module": "^2.8.1", - "is-glob": "^4.0.3", - "minimatch": "^3.1.2", - "object.values": "^1.1.5", - "resolve": "^1.22.0", - "tsconfig-paths": "^3.14.1" - }, - "engines": { - "node": ">=4" - }, - "peerDependencies": { - "eslint": "^2 || ^3 || ^4 || ^5 || ^6 || ^7.2.0 || ^8" - } - }, - "node_modules/eslint-plugin-import/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/eslint-plugin-import/node_modules/doctrine": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-2.1.0.tgz", - "integrity": "sha512-35mSku4ZXK0vfCuHEDAwt55dg2jNajHZ1odvF+8SSr82EsZY4QmXfuWso8oEd8zRhVObSN18aM0CjSdoBX7zIw==", - "dev": true, - "dependencies": { - "esutils": "^2.0.2" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/eslint-plugin-import/node_modules/ms": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", - "dev": true - }, - "node_modules/eslint-scope": { - "version": "5.1.1", - "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-5.1.1.tgz", - "integrity": "sha512-2NxwbF/hZ0KpepYN0cNbo+FN6XoK7GaHlQhgx/hIZl6Va0bF45RQOOwhLIy8lQDbuCiadSLCBnH2CFYquit5bw==", - "dev": true, - "dependencies": { - "esrecurse": "^4.3.0", - "estraverse": "^4.1.1" - }, - "engines": { - "node": ">=8.0.0" - } - }, - "node_modules/eslint-utils": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/eslint-utils/-/eslint-utils-3.0.0.tgz", - "integrity": "sha512-uuQC43IGctw68pJA1RgbQS8/NP7rch6Cwd4j3ZBtgo4/8Flj4eGE7ZYSZRN3iq5pVUv6GPdW5Z1RFleo84uLDA==", - "dev": true, - "dependencies": { - "eslint-visitor-keys": "^2.0.0" - }, - "engines": { - "node": "^10.0.0 || ^12.0.0 || >= 14.0.0" - }, - "funding": { - "url": "https://github.com/sponsors/mysticatea" - }, - "peerDependencies": { - "eslint": ">=5" - } - }, - "node_modules/eslint-utils/node_modules/eslint-visitor-keys": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-2.1.0.tgz", - "integrity": "sha512-0rSmRBzXgDzIsD6mGdJgevzgezI534Cer5L/vyMX0kHzT/jiB43jRhd9YUlMGYLQy2zprNmoT8qasCGtY+QaKw==", - "dev": true, - "engines": { - "node": ">=10" - } - }, - "node_modules/eslint-visitor-keys": { - "version": "3.3.0", - "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.3.0.tgz", - "integrity": "sha512-mQ+suqKJVyeuwGYHAdjMFqjCyfl8+Ldnxuyp3ldiMBFKkvytrXUZWaiPCEav8qDHKty44bD+qV1IP4T+w+xXRA==", - "dev": true, - "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - } - }, - "node_modules/eslint/node_modules/eslint-scope": { - "version": "7.1.1", - "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-7.1.1.tgz", - "integrity": "sha512-QKQM/UXpIiHcLqJ5AOyIW7XZmzjkzQXYE54n1++wb0u9V/abW3l9uQnxX8Z5Xd18xyKIMTUAyQ0k1e8pz6LUrw==", - "dev": true, - "dependencies": { - "esrecurse": "^4.3.0", - "estraverse": "^5.2.0" - }, - "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - } - }, - "node_modules/eslint/node_modules/estraverse": { - "version": "5.3.0", - "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", - "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", - "dev": true, - "engines": { - "node": ">=4.0" - } - }, - "node_modules/espree": { - "version": "9.4.1", - "resolved": "https://registry.npmjs.org/espree/-/espree-9.4.1.tgz", - "integrity": "sha512-XwctdmTO6SIvCzd9810yyNzIrOrqNYV9Koizx4C/mRhf9uq0o4yHoCEU/670pOxOL/MSraektvSAji79kX90Vg==", - "dev": true, - "dependencies": { - "acorn": "^8.8.0", - "acorn-jsx": "^5.3.2", - "eslint-visitor-keys": "^3.3.0" - }, - "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - }, - "funding": { - "url": "https://opencollective.com/eslint" - } - }, - "node_modules/esprima": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz", - "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==", - "dev": true, - "bin": { - "esparse": "bin/esparse.js", - "esvalidate": "bin/esvalidate.js" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/esquery": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.4.0.tgz", - "integrity": "sha512-cCDispWt5vHHtwMY2YrAQ4ibFkAL8RbH5YGBnZBc90MolvvfkkQcJro/aZiAQUlQ3qgrYS6D6v8Gc5G5CQsc9w==", - "dev": true, - "dependencies": { - "estraverse": "^5.1.0" - }, - "engines": { - "node": ">=0.10" - } - }, - "node_modules/esquery/node_modules/estraverse": { - "version": "5.3.0", - "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", - "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", - "dev": true, - "engines": { - "node": ">=4.0" - } - }, - "node_modules/esrecurse": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.3.0.tgz", - "integrity": "sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==", - "dev": true, - "dependencies": { - "estraverse": "^5.2.0" - }, - "engines": { - "node": ">=4.0" - } - }, - "node_modules/esrecurse/node_modules/estraverse": { - "version": "5.3.0", - "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", - "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", - "dev": true, - "engines": { - "node": ">=4.0" - } - }, - "node_modules/estraverse": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.3.0.tgz", - "integrity": "sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==", - "dev": true, - "engines": { - "node": ">=4.0" - } - }, - "node_modules/esutils": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz", - "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/execa": { - "version": "5.1.1", - "resolved": "https://registry.npmjs.org/execa/-/execa-5.1.1.tgz", - "integrity": "sha512-8uSpZZocAZRBAPIEINJj3Lo9HyGitllczc27Eh5YYojjMFMn8yHMDMaUHE2Jqfq05D/wucwI4JGURyXt1vchyg==", - "dev": true, - "dependencies": { - "cross-spawn": "^7.0.3", - "get-stream": "^6.0.0", - "human-signals": "^2.1.0", - "is-stream": "^2.0.0", - "merge-stream": "^2.0.0", - "npm-run-path": "^4.0.1", - "onetime": "^5.1.2", - "signal-exit": "^3.0.3", - "strip-final-newline": "^2.0.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sindresorhus/execa?sponsor=1" - } - }, - "node_modules/exit": { - "version": "0.1.2", - "resolved": "https://registry.npmjs.org/exit/-/exit-0.1.2.tgz", - "integrity": "sha512-Zk/eNKV2zbjpKzrsQ+n1G6poVbErQxJ0LBOJXaKZ1EViLzH+hrLu9cdXI4zw9dBQJslwBEpbQ2P1oS7nDxs6jQ==", - "dev": true, - "engines": { - "node": ">= 0.8.0" - } - }, - "node_modules/expect": { - "version": "29.3.1", - "resolved": "https://registry.npmjs.org/expect/-/expect-29.3.1.tgz", - "integrity": "sha512-gGb1yTgU30Q0O/tQq+z30KBWv24ApkMgFUpvKBkyLUBL68Wv8dHdJxTBZFl/iT8K/bqDHvUYRH6IIN3rToopPA==", - "dev": true, - "dependencies": { - "@jest/expect-utils": "^29.3.1", - "jest-get-type": "^29.2.0", - "jest-matcher-utils": "^29.3.1", - "jest-message-util": "^29.3.1", - "jest-util": "^29.3.1" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/fast-deep-equal": { - "version": "3.1.3", - "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", - "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==", - "dev": true - }, - "node_modules/fast-glob": { - "version": "3.2.12", - "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.2.12.tgz", - "integrity": "sha512-DVj4CQIYYow0BlaelwK1pHl5n5cRSJfM60UA0zK891sVInoPri2Ekj7+e1CT3/3qxXenpI+nBBmQAcJPJgaj4w==", - "dev": true, - "dependencies": { - "@nodelib/fs.stat": "^2.0.2", - "@nodelib/fs.walk": "^1.2.3", - "glob-parent": "^5.1.2", - "merge2": "^1.3.0", - "micromatch": "^4.0.4" - }, - "engines": { - "node": ">=8.6.0" - } - }, - "node_modules/fast-glob/node_modules/glob-parent": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", - "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", - "dev": true, - "dependencies": { - "is-glob": "^4.0.1" - }, - "engines": { - "node": ">= 6" - } - }, - "node_modules/fast-json-stable-stringify": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz", - "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==", - "dev": true - }, - "node_modules/fast-levenshtein": { - "version": "2.0.6", - "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz", - "integrity": "sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==", - "dev": true - }, - "node_modules/fastq": { - "version": "1.15.0", - "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.15.0.tgz", - "integrity": "sha512-wBrocU2LCXXa+lWBt8RoIRD89Fi8OdABODa/kEnyeyjS5aZO5/GNvI5sEINADqP/h8M29UHTHUb53sUu5Ihqdw==", - "dev": true, - "dependencies": { - "reusify": "^1.0.4" - } - }, - "node_modules/fb-watchman": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/fb-watchman/-/fb-watchman-2.0.2.tgz", - "integrity": "sha512-p5161BqbuCaSnB8jIbzQHOlpgsPmK5rJVDfDKO91Axs5NC1uu3HRQm6wt9cd9/+GtQQIO53JdGXXoyDpTAsgYA==", - "dev": true, - "dependencies": { - "bser": "2.1.1" - } - }, - "node_modules/file-entry-cache": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-6.0.1.tgz", - "integrity": "sha512-7Gps/XWymbLk2QLYK4NzpMOrYjMhdIxXuIvy2QBsLE6ljuodKvdkWs/cpyJJ3CVIVpH0Oi1Hvg1ovbMzLdFBBg==", - "dev": true, - "dependencies": { - "flat-cache": "^3.0.4" - }, - "engines": { - "node": "^10.12.0 || >=12.0.0" - } - }, - "node_modules/fill-range": { - "version": "7.0.1", - "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz", - "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==", - "dev": true, - "dependencies": { - "to-regex-range": "^5.0.1" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/find-up": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz", - "integrity": "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==", - "dev": true, - "dependencies": { - "locate-path": "^6.0.0", - "path-exists": "^4.0.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/flat-cache": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-3.0.4.tgz", - "integrity": "sha512-dm9s5Pw7Jc0GvMYbshN6zchCA9RgQlzzEZX3vylR9IqFfS8XciblUXOKfW6SiuJ0e13eDYZoZV5wdrev7P3Nwg==", - "dev": true, - "dependencies": { - "flatted": "^3.1.0", - "rimraf": "^3.0.2" - }, - "engines": { - "node": "^10.12.0 || >=12.0.0" - } - }, - "node_modules/flatted": { - "version": "3.2.7", - "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.2.7.tgz", - "integrity": "sha512-5nqDSxl8nn5BSNxyR3n4I6eDmbolI6WT+QqR547RwxQapgjQBmtktdP+HTBb/a/zLsbzERTONyUB5pefh5TtjQ==", - "dev": true - }, - "node_modules/for-each": { - "version": "0.3.3", - "resolved": "https://registry.npmjs.org/for-each/-/for-each-0.3.3.tgz", - "integrity": "sha512-jqYfLp7mo9vIyQf8ykW2v7A+2N4QjeCeI5+Dz9XraiO1ign81wjiH7Fb9vSOWvQfNtmSa4H2RoQTrrXivdUZmw==", - "dev": true, - "dependencies": { - "is-callable": "^1.1.3" - } - }, - "node_modules/fs-extra": { - "version": "9.1.0", - "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-9.1.0.tgz", - "integrity": "sha512-hcg3ZmepS30/7BSFqRvoo3DOMQu7IjqxO5nCDt+zM9XWjb33Wg7ziNT+Qvqbuc3+gWpzO02JubVyk2G4Zvo1OQ==", - "dependencies": { - "at-least-node": "^1.0.0", - "graceful-fs": "^4.2.0", - "jsonfile": "^6.0.1", - "universalify": "^2.0.0" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/fs.realpath": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", - "integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==", - "dev": true - }, - "node_modules/fsevents": { - "version": "2.3.2", - "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.2.tgz", - "integrity": "sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==", - "dev": true, - "hasInstallScript": true, - "optional": true, - "os": [ - "darwin" - ], - "engines": { - "node": "^8.16.0 || ^10.6.0 || >=11.0.0" - } - }, - "node_modules/function-bind": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz", - "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==", - "dev": true - }, - "node_modules/function.prototype.name": { - "version": "1.1.5", - "resolved": "https://registry.npmjs.org/function.prototype.name/-/function.prototype.name-1.1.5.tgz", - "integrity": "sha512-uN7m/BzVKQnCUF/iW8jYea67v++2u7m5UgENbHRtdDVclOUP+FMPlCNdmk0h/ysGyo2tavMJEDqJAkJdRa1vMA==", - "dev": true, - "dependencies": { - "call-bind": "^1.0.2", - "define-properties": "^1.1.3", - "es-abstract": "^1.19.0", - "functions-have-names": "^1.2.2" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/functions-have-names": { - "version": "1.2.3", - "resolved": "https://registry.npmjs.org/functions-have-names/-/functions-have-names-1.2.3.tgz", - "integrity": "sha512-xckBUXyTIqT97tq2x2AMb+g163b5JFysYk0x4qxNFwbfQkmNZoiRHb6sPzI9/QV33WeuvVYBUIiD4NzNIyqaRQ==", - "dev": true, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/gensync": { - "version": "1.0.0-beta.2", - "resolved": "https://registry.npmjs.org/gensync/-/gensync-1.0.0-beta.2.tgz", - "integrity": "sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==", - "dev": true, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/get-caller-file": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz", - "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==", - "dev": true, - "engines": { - "node": "6.* || 8.* || >= 10.*" - } - }, - "node_modules/get-intrinsic": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.1.3.tgz", - "integrity": "sha512-QJVz1Tj7MS099PevUG5jvnt9tSkXN8K14dxQlikJuPt4uD9hHAHjLyLBiLR5zELelBdD9QNRAXZzsJx0WaDL9A==", - "dev": true, - "dependencies": { - "function-bind": "^1.1.1", - "has": "^1.0.3", - "has-symbols": "^1.0.3" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/get-package-type": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/get-package-type/-/get-package-type-0.1.0.tgz", - "integrity": "sha512-pjzuKtY64GYfWizNAJ0fr9VqttZkNiK2iS430LtIHzjBEr6bX8Am2zm4sW4Ro5wjWW5cAlRL1qAMTcXbjNAO2Q==", - "dev": true, - "engines": { - "node": ">=8.0.0" - } - }, - "node_modules/get-stream": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-6.0.1.tgz", - "integrity": "sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg==", - "dev": true, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/get-symbol-description": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/get-symbol-description/-/get-symbol-description-1.0.0.tgz", - "integrity": "sha512-2EmdH1YvIQiZpltCNgkuiUnyukzxM/R6NDJX31Ke3BG1Nq5b0S2PhX59UKi9vZpPDQVdqn+1IcaAwnzTT5vCjw==", - "dev": true, - "dependencies": { - "call-bind": "^1.0.2", - "get-intrinsic": "^1.1.1" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/get-tsconfig": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/get-tsconfig/-/get-tsconfig-4.3.0.tgz", - "integrity": "sha512-YCcF28IqSay3fqpIu5y3Krg/utCBHBeoflkZyHj/QcqI2nrLPC3ZegS9CmIo+hJb8K7aiGsuUl7PwWVjNG2HQQ==", - "dev": true, - "funding": { - "url": "https://github.com/privatenumber/get-tsconfig?sponsor=1" - } - }, - "node_modules/glob": { - "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.1.1", - "once": "^1.3.0", - "path-is-absolute": "^1.0.0" - }, - "engines": { - "node": "*" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/glob-parent": { - "version": "6.0.2", - "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz", - "integrity": "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==", - "dev": true, - "dependencies": { - "is-glob": "^4.0.3" - }, - "engines": { - "node": ">=10.13.0" - } - }, - "node_modules/globals": { - "version": "13.19.0", - "resolved": "https://registry.npmjs.org/globals/-/globals-13.19.0.tgz", - "integrity": "sha512-dkQ957uSRWHw7CFXLUtUHQI3g3aWApYhfNR2O6jn/907riyTYKVBmxYVROkBcY614FSSeSJh7Xm7SrUWCxvJMQ==", - "dev": true, - "dependencies": { - "type-fest": "^0.20.2" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/globalthis": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/globalthis/-/globalthis-1.0.3.tgz", - "integrity": "sha512-sFdI5LyBiNTHjRd7cGPWapiHWMOXKyuBNX/cWJ3NfzrZQVa8GI/8cofCl74AOVqq9W5kNmguTIzJ/1s2gyI9wA==", - "dev": true, - "dependencies": { - "define-properties": "^1.1.3" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/globalyzer": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/globalyzer/-/globalyzer-0.1.0.tgz", - "integrity": "sha512-40oNTM9UfG6aBmuKxk/giHn5nQ8RVz/SS4Ir6zgzOv9/qC3kKZ9v4etGTcJbEl/NyVQH7FGU7d+X1egr57Md2Q==", - "dev": true - }, - "node_modules/globby": { - "version": "11.1.0", - "resolved": "https://registry.npmjs.org/globby/-/globby-11.1.0.tgz", - "integrity": "sha512-jhIXaOzy1sb8IyocaruWSn1TjmnBVs8Ayhcy83rmxNJ8q2uWKCAj3CnJY+KpGSXCueAPc0i05kVvVKtP1t9S3g==", - "dev": true, - "dependencies": { - "array-union": "^2.1.0", - "dir-glob": "^3.0.1", - "fast-glob": "^3.2.9", - "ignore": "^5.2.0", - "merge2": "^1.4.1", - "slash": "^3.0.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/globrex": { - "version": "0.1.2", - "resolved": "https://registry.npmjs.org/globrex/-/globrex-0.1.2.tgz", - "integrity": "sha512-uHJgbwAMwNFf5mLst7IWLNg14x1CkeqglJb/K3doi4dw6q2IvAAmM/Y81kevy83wP+Sst+nutFTYOGg3d1lsxg==", - "dev": true - }, - "node_modules/gopd": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.0.1.tgz", - "integrity": "sha512-d65bNlIadxvpb/A2abVdlqKqV563juRnZ1Wtk6s1sIR8uNsXR70xqIzVqxVf1eTqDunwT2MkczEeaezCKTZhwA==", - "dev": true, - "dependencies": { - "get-intrinsic": "^1.1.3" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/graceful-fs": { - "version": "4.2.10", - "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.10.tgz", - "integrity": "sha512-9ByhssR2fPVsNZj478qUUbKfmL0+t5BDVyjShtyZZLiK7ZDAArFFfopyOTj0M05wE2tJPisA4iTnnXl2YoPvOA==" - }, - "node_modules/grapheme-splitter": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/grapheme-splitter/-/grapheme-splitter-1.0.4.tgz", - "integrity": "sha512-bzh50DW9kTPM00T8y4o8vQg89Di9oLJVLW/KaOGIXJWP/iqCN6WKYkbNOF04vFLJhwcpYUh9ydh/+5vpOqV4YQ==", - "dev": true - }, - "node_modules/has": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz", - "integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==", - "dev": true, - "dependencies": { - "function-bind": "^1.1.1" - }, - "engines": { - "node": ">= 0.4.0" - } - }, - "node_modules/has-bigints": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/has-bigints/-/has-bigints-1.0.2.tgz", - "integrity": "sha512-tSvCKtBr9lkF0Ex0aQiP9N+OpV4zi2r/Nee5VkRDbaqv35RLYMzbwQfFSZZH0kR+Rd6302UJZ2p/bJCEoR3VoQ==", - "dev": true, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/has-property-descriptors": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/has-property-descriptors/-/has-property-descriptors-1.0.0.tgz", - "integrity": "sha512-62DVLZGoiEBDHQyqG4w9xCuZ7eJEwNmJRWw2VY84Oedb7WFcA27fiEVe8oUQx9hAUJ4ekurquucTGwsyO1XGdQ==", - "dev": true, - "dependencies": { - "get-intrinsic": "^1.1.1" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/has-proto": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/has-proto/-/has-proto-1.0.1.tgz", - "integrity": "sha512-7qE+iP+O+bgF9clE5+UoBFzE65mlBiVj3tKCrlNQ0Ogwm0BjpT/gK4SlLYDMybDh5I3TCTKnPPa0oMG7JDYrhg==", - "dev": true, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/has-symbols": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.3.tgz", - "integrity": "sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A==", - "dev": true, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/has-tostringtag": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/has-tostringtag/-/has-tostringtag-1.0.0.tgz", - "integrity": "sha512-kFjcSNhnlGV1kyoGk7OXKSawH5JOb/LzUc5w9B02hOTO0dfFRjbHQKvg1d6cf3HbeUmtU9VbbV3qzZ2Teh97WQ==", - "dev": true, - "dependencies": { - "has-symbols": "^1.0.2" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/html-escaper": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/html-escaper/-/html-escaper-2.0.2.tgz", - "integrity": "sha512-H2iMtd0I4Mt5eYiapRdIDjp+XzelXQ0tFE4JS7YFwFevXXMmOp9myNrUvCg0D6ws8iqkRPBfKHgbwig1SmlLfg==", - "dev": true - }, - "node_modules/human-signals": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/human-signals/-/human-signals-2.1.0.tgz", - "integrity": "sha512-B4FFZ6q/T2jhhksgkbEW3HBvWIfDW85snkQgawt07S7J5QXTk6BkNV+0yAeZrM5QpMAdYlocGoljn0sJ/WQkFw==", - "dev": true, - "engines": { - "node": ">=10.17.0" - } - }, - "node_modules/if-node-version": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/if-node-version/-/if-node-version-1.1.1.tgz", - "integrity": "sha512-qMcJD7ftbSWlf+6w8nzZAWKOELmG3xH5Gu5XYW2+f9uaYj1t9JX5KNWxnvNMGhu8f+uIUgnqFHLlwyKTHaLWWA==", - "dependencies": { - "cross-spawn": "^5.0.1", - "semver": "^5.2.0" - }, - "bin": { - "if-node-version": "bin/index.js" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/if-node-version/node_modules/cross-spawn": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-5.1.0.tgz", - "integrity": "sha512-pTgQJ5KC0d2hcY8eyL1IzlBPYjTkyH72XRZPnLyKus2mBfNjQs3klqbJU2VILqZryAZUt9JOb3h/mWMy23/f5A==", - "dependencies": { - "lru-cache": "^4.0.1", - "shebang-command": "^1.2.0", - "which": "^1.2.9" - } - }, - "node_modules/if-node-version/node_modules/lru-cache": { - "version": "4.1.5", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-4.1.5.tgz", - "integrity": "sha512-sWZlbEP2OsHNkXrMl5GYk/jKk70MBng6UU4YI/qGDYbgf6YbP4EvmqISbXCoJiRKs+1bSpFHVgQxvJ17F2li5g==", - "dependencies": { - "pseudomap": "^1.0.2", - "yallist": "^2.1.2" - } - }, - "node_modules/if-node-version/node_modules/semver": { - "version": "5.7.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", - "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==", - "bin": { - "semver": "bin/semver" - } - }, - "node_modules/if-node-version/node_modules/shebang-command": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-1.2.0.tgz", - "integrity": "sha512-EV3L1+UQWGor21OmnvojK36mhg+TyIKDh3iFBKBohr5xeXIhNBcx8oWdgkTEEQ+BEFFYdLRuqMfd5L84N1V5Vg==", - "dependencies": { - "shebang-regex": "^1.0.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/if-node-version/node_modules/shebang-regex": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-1.0.0.tgz", - "integrity": "sha512-wpoSFAxys6b2a2wHZ1XpDSgD7N9iVjg29Ph9uV/uaP9Ex/KXlkTZTeddxDPSYQpgvzKLGJke2UU0AzoGCjNIvQ==", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/if-node-version/node_modules/which": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/which/-/which-1.3.1.tgz", - "integrity": "sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ==", - "dependencies": { - "isexe": "^2.0.0" - }, - "bin": { - "which": "bin/which" - } - }, - "node_modules/if-node-version/node_modules/yallist": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-2.1.2.tgz", - "integrity": "sha512-ncTzHV7NvsQZkYe1DW7cbDLm0YpzHmZF5r/iyP3ZnQtMiJ+pjzisCiMNI+Sj+xQF5pXhSHxSB3uDbsBTzY/c2A==" - }, - "node_modules/ignore": { - "version": "5.2.4", - "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.2.4.tgz", - "integrity": "sha512-MAb38BcSbH0eHNBxn7ql2NH/kX33OkB3lZ1BNdh7ENeRChHTYsTvWrMubiIAMNS2llXEEgZ1MUOBtXChP3kaFQ==", - "engines": { - "node": ">= 4" - } - }, - "node_modules/import-fresh": { - "version": "3.3.0", - "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.0.tgz", - "integrity": "sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw==", - "dev": true, - "dependencies": { - "parent-module": "^1.0.0", - "resolve-from": "^4.0.0" - }, - "engines": { - "node": ">=6" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/import-local": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/import-local/-/import-local-3.1.0.tgz", - "integrity": "sha512-ASB07uLtnDs1o6EHjKpX34BKYDSqnFerfTOJL2HvMqF70LnxpjkzDB8J44oT9pu4AMPkQwf8jl6szgvNd2tRIg==", - "dev": true, - "dependencies": { - "pkg-dir": "^4.2.0", - "resolve-cwd": "^3.0.0" - }, - "bin": { - "import-local-fixture": "fixtures/cli.js" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/imurmurhash": { - "version": "0.1.4", - "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", - "integrity": "sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==", - "dev": true, - "engines": { - "node": ">=0.8.19" - } - }, - "node_modules/inflight": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", - "integrity": "sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==", - "dev": true, - "dependencies": { - "once": "^1.3.0", - "wrappy": "1" - } - }, - "node_modules/inherits": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", - "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", - "dev": true - }, - "node_modules/internal-slot": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/internal-slot/-/internal-slot-1.0.4.tgz", - "integrity": "sha512-tA8URYccNzMo94s5MQZgH8NB/XTa6HsOo0MLfXTKKEnHVVdegzaQoFZ7Jp44bdvLvY2waT5dc+j5ICEswhi7UQ==", - "dev": true, - "dependencies": { - "get-intrinsic": "^1.1.3", - "has": "^1.0.3", - "side-channel": "^1.0.4" - }, - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/is-array-buffer": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/is-array-buffer/-/is-array-buffer-3.0.1.tgz", - "integrity": "sha512-ASfLknmY8Xa2XtB4wmbz13Wu202baeA18cJBCeCy0wXUHZF0IPyVEXqKEcd+t2fNSLLL1vC6k7lxZEojNbISXQ==", - "dev": true, - "dependencies": { - "call-bind": "^1.0.2", - "get-intrinsic": "^1.1.3", - "is-typed-array": "^1.1.10" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-arrayish": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz", - "integrity": "sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg==", - "dev": true - }, - "node_modules/is-bigint": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/is-bigint/-/is-bigint-1.0.4.tgz", - "integrity": "sha512-zB9CruMamjym81i2JZ3UMn54PKGsQzsJeo6xvN3HJJ4CAsQNB6iRutp2To77OfCNuoxspsIhzaPoO1zyCEhFOg==", - "dev": true, - "dependencies": { - "has-bigints": "^1.0.1" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-boolean-object": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/is-boolean-object/-/is-boolean-object-1.1.2.tgz", - "integrity": "sha512-gDYaKHJmnj4aWxyj6YHyXVpdQawtVLHU5cb+eztPGczf6cjuTdwve5ZIEfgXqH4e57An1D1AKf8CZ3kYrQRqYA==", - "dev": true, - "dependencies": { - "call-bind": "^1.0.2", - "has-tostringtag": "^1.0.0" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "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.7", - "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.2.7.tgz", - "integrity": "sha512-1BC0BVFhS/p0qtw6enp8e+8OD0UrK0oFLztSjNzhcKA3WDuJxxAPXzPuPtKkjEY9UUoEWlX/8fgKeu2S8i9JTA==", - "dev": true, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-core-module": { - "version": "2.11.0", - "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.11.0.tgz", - "integrity": "sha512-RRjxlvLDkD1YJwDbroBHMb+cukurkDWNyHx7D3oNB5x9rb5ogcksMC5wHCadcXoo67gVr/+3GFySh3134zi6rw==", - "dev": true, - "dependencies": { - "has": "^1.0.3" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-date-object": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/is-date-object/-/is-date-object-1.0.5.tgz", - "integrity": "sha512-9YQaSxsAiSwcvS33MBk3wTCVnWK+HhF8VZR2jRxehM16QcVOdHqPn4VPHmRK4lSr38n9JriurInLcP90xsYNfQ==", - "dev": true, - "dependencies": { - "has-tostringtag": "^1.0.0" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-docker": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/is-docker/-/is-docker-2.2.1.tgz", - "integrity": "sha512-F+i2BKsFrH66iaUFc0woD8sLy8getkwTwtOBjvs56Cx4CgJDeKQeqfz8wAYiSb8JOprWhHH5p77PbmYCvvUuXQ==", - "dev": true, - "bin": { - "is-docker": "cli.js" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/is-extglob": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", - "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/is-fullwidth-code-point": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", - "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/is-generator-fn": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/is-generator-fn/-/is-generator-fn-2.1.0.tgz", - "integrity": "sha512-cTIB4yPYL/Grw0EaSzASzg6bBy9gqCofvWN8okThAYIxKJZC+udlRAmGbM0XLeniEJSs8uEgHPGuHSe1XsOLSQ==", - "dev": true, - "engines": { - "node": ">=6" - } - }, - "node_modules/is-glob": { - "version": "4.0.3", - "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", - "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", - "dev": true, - "dependencies": { - "is-extglob": "^2.1.1" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/is-negative-zero": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/is-negative-zero/-/is-negative-zero-2.0.2.tgz", - "integrity": "sha512-dqJvarLawXsFbNDeJW7zAz8ItJ9cd28YufuuFzh0G8pNHjJMnY08Dv7sYX2uF5UpQOwieAeOExEYAWWfu7ZZUA==", - "dev": true, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-number": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", - "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", - "dev": true, - "engines": { - "node": ">=0.12.0" - } - }, - "node_modules/is-number-object": { - "version": "1.0.7", - "resolved": "https://registry.npmjs.org/is-number-object/-/is-number-object-1.0.7.tgz", - "integrity": "sha512-k1U0IRzLMo7ZlYIfzRu23Oh6MiIFasgpb9X76eqfFZAqwH44UI4KTBvBYIZ1dSL9ZzChTB9ShHfLkR4pdW5krQ==", - "dev": true, - "dependencies": { - "has-tostringtag": "^1.0.0" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-path-inside": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/is-path-inside/-/is-path-inside-3.0.3.tgz", - "integrity": "sha512-Fd4gABb+ycGAmKou8eMftCupSir5lRxqf4aD/vd0cD2qc4HL07OjCeuHMr8Ro4CoMaeCKDB0/ECBOVWjTwUvPQ==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/is-regex": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.1.4.tgz", - "integrity": "sha512-kvRdxDsxZjhzUX07ZnLydzS1TU/TJlTUHHY4YLL87e37oUA49DfkLqgy+VjFocowy29cKvcSiu+kIv728jTTVg==", - "dev": true, - "dependencies": { - "call-bind": "^1.0.2", - "has-tostringtag": "^1.0.0" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-shared-array-buffer": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/is-shared-array-buffer/-/is-shared-array-buffer-1.0.2.tgz", - "integrity": "sha512-sqN2UDu1/0y6uvXyStCOzyhAjCSlHceFoMKJW8W9EU9cvic/QdsZ0kEU93HEy3IUEFZIiH/3w+AH/UQbPHNdhA==", - "dev": true, - "dependencies": { - "call-bind": "^1.0.2" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-stream": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-2.0.1.tgz", - "integrity": "sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==", - "dev": true, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/is-string": { - "version": "1.0.7", - "resolved": "https://registry.npmjs.org/is-string/-/is-string-1.0.7.tgz", - "integrity": "sha512-tE2UXzivje6ofPW7l23cjDOMa09gb7xlAqG6jG5ej6uPV32TlWP3NKPigtaGeHNu9fohccRYvIiZMfOOnOYUtg==", - "dev": true, - "dependencies": { - "has-tostringtag": "^1.0.0" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-symbol": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/is-symbol/-/is-symbol-1.0.4.tgz", - "integrity": "sha512-C/CPBqKWnvdcxqIARxyOh4v1UUEOCHpgDa0WYgpKDFMszcrPcffg5uhwSgPCLD2WWxmq6isisz87tzT01tuGhg==", - "dev": true, - "dependencies": { - "has-symbols": "^1.0.2" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-typed-array": { - "version": "1.1.10", - "resolved": "https://registry.npmjs.org/is-typed-array/-/is-typed-array-1.1.10.tgz", - "integrity": "sha512-PJqgEHiWZvMpaFZ3uTc8kHPM4+4ADTlDniuQL7cU/UDA0Ql7F70yGfHph3cLNe+c9toaigv+DFzTJKhc2CtO6A==", - "dev": true, - "dependencies": { - "available-typed-arrays": "^1.0.5", - "call-bind": "^1.0.2", - "for-each": "^0.3.3", - "gopd": "^1.0.1", - "has-tostringtag": "^1.0.0" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-weakref": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/is-weakref/-/is-weakref-1.0.2.tgz", - "integrity": "sha512-qctsuLZmIQ0+vSSMfoVvyFe2+GSEvnmZ2ezTup1SBse9+twCCeial6EEi3Nc2KFcf6+qz2FBPnjXsk8xhKSaPQ==", - "dev": true, - "dependencies": { - "call-bind": "^1.0.2" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-wsl": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/is-wsl/-/is-wsl-2.2.0.tgz", - "integrity": "sha512-fKzAra0rGJUUBwGBgNkHZuToZcn+TtXHpeCgmkMJMMYx1sQDYaCSyjJBSCa2nH1DGm7s3n1oBnohoVTBaN7Lww==", - "dev": true, - "dependencies": { - "is-docker": "^2.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/isexe": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", - "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==" - }, - "node_modules/istanbul-lib-coverage": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/istanbul-lib-coverage/-/istanbul-lib-coverage-3.2.0.tgz", - "integrity": "sha512-eOeJ5BHCmHYvQK7xt9GkdHuzuCGS1Y6g9Gvnx3Ym33fz/HpLRYxiS0wHNr+m/MBC8B647Xt608vCDEvhl9c6Mw==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/istanbul-lib-instrument": { - "version": "5.2.1", - "resolved": "https://registry.npmjs.org/istanbul-lib-instrument/-/istanbul-lib-instrument-5.2.1.tgz", - "integrity": "sha512-pzqtp31nLv/XFOzXGuvhCb8qhjmTVo5vjVk19XE4CRlSWz0KoeJ3bw9XsA7nOp9YBf4qHjwBxkDzKcME/J29Yg==", - "dev": true, - "dependencies": { - "@babel/core": "^7.12.3", - "@babel/parser": "^7.14.7", - "@istanbuljs/schema": "^0.1.2", - "istanbul-lib-coverage": "^3.2.0", - "semver": "^6.3.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/istanbul-lib-instrument/node_modules/semver": { - "version": "6.3.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", - "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", - "dev": true, - "bin": { - "semver": "bin/semver.js" - } - }, - "node_modules/istanbul-lib-report": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/istanbul-lib-report/-/istanbul-lib-report-3.0.0.tgz", - "integrity": "sha512-wcdi+uAKzfiGT2abPpKZ0hSU1rGQjUQnLvtY5MpQ7QCTahD3VODhcu4wcfY1YtkGaDD5yuydOLINXsfbus9ROw==", - "dev": true, - "dependencies": { - "istanbul-lib-coverage": "^3.0.0", - "make-dir": "^3.0.0", - "supports-color": "^7.1.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/istanbul-lib-source-maps": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/istanbul-lib-source-maps/-/istanbul-lib-source-maps-4.0.1.tgz", - "integrity": "sha512-n3s8EwkdFIJCG3BPKBYvskgXGoy88ARzvegkitk60NxRdwltLOTaH7CUiMRXvwYorl0Q712iEjcWB+fK/MrWVw==", - "dev": true, - "dependencies": { - "debug": "^4.1.1", - "istanbul-lib-coverage": "^3.0.0", - "source-map": "^0.6.1" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/istanbul-reports": { - "version": "3.1.5", - "resolved": "https://registry.npmjs.org/istanbul-reports/-/istanbul-reports-3.1.5.tgz", - "integrity": "sha512-nUsEMa9pBt/NOHqbcbeJEgqIlY/K7rVWUX6Lql2orY5e9roQOthbR3vtY4zzf2orPELg80fnxxk9zUyPlgwD1w==", - "dev": true, - "dependencies": { - "html-escaper": "^2.0.0", - "istanbul-lib-report": "^3.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/jest": { - "version": "29.3.1", - "resolved": "https://registry.npmjs.org/jest/-/jest-29.3.1.tgz", - "integrity": "sha512-6iWfL5DTT0Np6UYs/y5Niu7WIfNv/wRTtN5RSXt2DIEft3dx3zPuw/3WJQBCJfmEzvDiEKwoqMbGD9n49+qLSA==", - "dev": true, - "dependencies": { - "@jest/core": "^29.3.1", - "@jest/types": "^29.3.1", - "import-local": "^3.0.2", - "jest-cli": "^29.3.1" - }, - "bin": { - "jest": "bin/jest.js" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - }, - "peerDependencies": { - "node-notifier": "^8.0.1 || ^9.0.0 || ^10.0.0" - }, - "peerDependenciesMeta": { - "node-notifier": { - "optional": true - } - } - }, - "node_modules/jest-changed-files": { - "version": "29.2.0", - "resolved": "https://registry.npmjs.org/jest-changed-files/-/jest-changed-files-29.2.0.tgz", - "integrity": "sha512-qPVmLLyBmvF5HJrY7krDisx6Voi8DmlV3GZYX0aFNbaQsZeoz1hfxcCMbqDGuQCxU1dJy9eYc2xscE8QrCCYaA==", - "dev": true, - "dependencies": { - "execa": "^5.0.0", - "p-limit": "^3.1.0" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/jest-circus": { - "version": "29.3.1", - "resolved": "https://registry.npmjs.org/jest-circus/-/jest-circus-29.3.1.tgz", - "integrity": "sha512-wpr26sEvwb3qQQbdlmei+gzp6yoSSoSL6GsLPxnuayZSMrSd5Ka7IjAvatpIernBvT2+Ic6RLTg+jSebScmasg==", - "dev": true, - "dependencies": { - "@jest/environment": "^29.3.1", - "@jest/expect": "^29.3.1", - "@jest/test-result": "^29.3.1", - "@jest/types": "^29.3.1", - "@types/node": "*", - "chalk": "^4.0.0", - "co": "^4.6.0", - "dedent": "^0.7.0", - "is-generator-fn": "^2.0.0", - "jest-each": "^29.3.1", - "jest-matcher-utils": "^29.3.1", - "jest-message-util": "^29.3.1", - "jest-runtime": "^29.3.1", - "jest-snapshot": "^29.3.1", - "jest-util": "^29.3.1", - "p-limit": "^3.1.0", - "pretty-format": "^29.3.1", - "slash": "^3.0.0", - "stack-utils": "^2.0.3" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/jest-cli": { - "version": "29.3.1", - "resolved": "https://registry.npmjs.org/jest-cli/-/jest-cli-29.3.1.tgz", - "integrity": "sha512-TO/ewvwyvPOiBBuWZ0gm04z3WWP8TIK8acgPzE4IxgsLKQgb377NYGrQLc3Wl/7ndWzIH2CDNNsUjGxwLL43VQ==", - "dev": true, - "dependencies": { - "@jest/core": "^29.3.1", - "@jest/test-result": "^29.3.1", - "@jest/types": "^29.3.1", - "chalk": "^4.0.0", - "exit": "^0.1.2", - "graceful-fs": "^4.2.9", - "import-local": "^3.0.2", - "jest-config": "^29.3.1", - "jest-util": "^29.3.1", - "jest-validate": "^29.3.1", - "prompts": "^2.0.1", - "yargs": "^17.3.1" - }, - "bin": { - "jest": "bin/jest.js" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - }, - "peerDependencies": { - "node-notifier": "^8.0.1 || ^9.0.0 || ^10.0.0" - }, - "peerDependenciesMeta": { - "node-notifier": { - "optional": true - } - } - }, - "node_modules/jest-config": { - "version": "29.3.1", - "resolved": "https://registry.npmjs.org/jest-config/-/jest-config-29.3.1.tgz", - "integrity": "sha512-y0tFHdj2WnTEhxmGUK1T7fgLen7YK4RtfvpLFBXfQkh2eMJAQq24Vx9472lvn5wg0MAO6B+iPfJfzdR9hJYalg==", - "dev": true, - "dependencies": { - "@babel/core": "^7.11.6", - "@jest/test-sequencer": "^29.3.1", - "@jest/types": "^29.3.1", - "babel-jest": "^29.3.1", - "chalk": "^4.0.0", - "ci-info": "^3.2.0", - "deepmerge": "^4.2.2", - "glob": "^7.1.3", - "graceful-fs": "^4.2.9", - "jest-circus": "^29.3.1", - "jest-environment-node": "^29.3.1", - "jest-get-type": "^29.2.0", - "jest-regex-util": "^29.2.0", - "jest-resolve": "^29.3.1", - "jest-runner": "^29.3.1", - "jest-util": "^29.3.1", - "jest-validate": "^29.3.1", - "micromatch": "^4.0.4", - "parse-json": "^5.2.0", - "pretty-format": "^29.3.1", - "slash": "^3.0.0", - "strip-json-comments": "^3.1.1" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - }, - "peerDependencies": { - "@types/node": "*", - "ts-node": ">=9.0.0" - }, - "peerDependenciesMeta": { - "@types/node": { - "optional": true - }, - "ts-node": { - "optional": true - } - } - }, - "node_modules/jest-diff": { - "version": "29.3.1", - "resolved": "https://registry.npmjs.org/jest-diff/-/jest-diff-29.3.1.tgz", - "integrity": "sha512-vU8vyiO7568tmin2lA3r2DP8oRvzhvRcD4DjpXc6uGveQodyk7CKLhQlCSiwgx3g0pFaE88/KLZ0yaTWMc4Uiw==", - "dev": true, - "dependencies": { - "chalk": "^4.0.0", - "diff-sequences": "^29.3.1", - "jest-get-type": "^29.2.0", - "pretty-format": "^29.3.1" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/jest-docblock": { - "version": "29.2.0", - "resolved": "https://registry.npmjs.org/jest-docblock/-/jest-docblock-29.2.0.tgz", - "integrity": "sha512-bkxUsxTgWQGbXV5IENmfiIuqZhJcyvF7tU4zJ/7ioTutdz4ToB5Yx6JOFBpgI+TphRY4lhOyCWGNH/QFQh5T6A==", - "dev": true, - "dependencies": { - "detect-newline": "^3.0.0" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/jest-each": { - "version": "29.3.1", - "resolved": "https://registry.npmjs.org/jest-each/-/jest-each-29.3.1.tgz", - "integrity": "sha512-qrZH7PmFB9rEzCSl00BWjZYuS1BSOH8lLuC0azQE9lQrAx3PWGKHTDudQiOSwIy5dGAJh7KA0ScYlCP7JxvFYA==", - "dev": true, - "dependencies": { - "@jest/types": "^29.3.1", - "chalk": "^4.0.0", - "jest-get-type": "^29.2.0", - "jest-util": "^29.3.1", - "pretty-format": "^29.3.1" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/jest-environment-node": { - "version": "29.3.1", - "resolved": "https://registry.npmjs.org/jest-environment-node/-/jest-environment-node-29.3.1.tgz", - "integrity": "sha512-xm2THL18Xf5sIHoU7OThBPtuH6Lerd+Y1NLYiZJlkE3hbE+7N7r8uvHIl/FkZ5ymKXJe/11SQuf3fv4v6rUMag==", - "dev": true, - "dependencies": { - "@jest/environment": "^29.3.1", - "@jest/fake-timers": "^29.3.1", - "@jest/types": "^29.3.1", - "@types/node": "*", - "jest-mock": "^29.3.1", - "jest-util": "^29.3.1" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/jest-get-type": { - "version": "29.2.0", - "resolved": "https://registry.npmjs.org/jest-get-type/-/jest-get-type-29.2.0.tgz", - "integrity": "sha512-uXNJlg8hKFEnDgFsrCjznB+sTxdkuqiCL6zMgA75qEbAJjJYTs9XPrvDctrEig2GDow22T/LvHgO57iJhXB/UA==", - "dev": true, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/jest-haste-map": { - "version": "29.3.1", - "resolved": "https://registry.npmjs.org/jest-haste-map/-/jest-haste-map-29.3.1.tgz", - "integrity": "sha512-/FFtvoG1xjbbPXQLFef+WSU4yrc0fc0Dds6aRPBojUid7qlPqZvxdUBA03HW0fnVHXVCnCdkuoghYItKNzc/0A==", - "dev": true, - "dependencies": { - "@jest/types": "^29.3.1", - "@types/graceful-fs": "^4.1.3", - "@types/node": "*", - "anymatch": "^3.0.3", - "fb-watchman": "^2.0.0", - "graceful-fs": "^4.2.9", - "jest-regex-util": "^29.2.0", - "jest-util": "^29.3.1", - "jest-worker": "^29.3.1", - "micromatch": "^4.0.4", - "walker": "^1.0.8" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - }, - "optionalDependencies": { - "fsevents": "^2.3.2" - } - }, - "node_modules/jest-leak-detector": { - "version": "29.3.1", - "resolved": "https://registry.npmjs.org/jest-leak-detector/-/jest-leak-detector-29.3.1.tgz", - "integrity": "sha512-3DA/VVXj4zFOPagGkuqHnSQf1GZBmmlagpguxEERO6Pla2g84Q1MaVIB3YMxgUaFIaYag8ZnTyQgiZ35YEqAQA==", - "dev": true, - "dependencies": { - "jest-get-type": "^29.2.0", - "pretty-format": "^29.3.1" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/jest-matcher-utils": { - "version": "29.3.1", - "resolved": "https://registry.npmjs.org/jest-matcher-utils/-/jest-matcher-utils-29.3.1.tgz", - "integrity": "sha512-fkRMZUAScup3txIKfMe3AIZZmPEjWEdsPJFK3AIy5qRohWqQFg1qrmKfYXR9qEkNc7OdAu2N4KPHibEmy4HPeQ==", - "dev": true, - "dependencies": { - "chalk": "^4.0.0", - "jest-diff": "^29.3.1", - "jest-get-type": "^29.2.0", - "pretty-format": "^29.3.1" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/jest-message-util": { - "version": "29.3.1", - "resolved": "https://registry.npmjs.org/jest-message-util/-/jest-message-util-29.3.1.tgz", - "integrity": "sha512-lMJTbgNcDm5z+6KDxWtqOFWlGQxD6XaYwBqHR8kmpkP+WWWG90I35kdtQHY67Ay5CSuydkTBbJG+tH9JShFCyA==", - "dev": true, - "dependencies": { - "@babel/code-frame": "^7.12.13", - "@jest/types": "^29.3.1", - "@types/stack-utils": "^2.0.0", - "chalk": "^4.0.0", - "graceful-fs": "^4.2.9", - "micromatch": "^4.0.4", - "pretty-format": "^29.3.1", - "slash": "^3.0.0", - "stack-utils": "^2.0.3" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/jest-mock": { - "version": "29.3.1", - "resolved": "https://registry.npmjs.org/jest-mock/-/jest-mock-29.3.1.tgz", - "integrity": "sha512-H8/qFDtDVMFvFP4X8NuOT3XRDzOUTz+FeACjufHzsOIBAxivLqkB1PoLCaJx9iPPQ8dZThHPp/G3WRWyMgA3JA==", - "dev": true, - "dependencies": { - "@jest/types": "^29.3.1", - "@types/node": "*", - "jest-util": "^29.3.1" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/jest-pnp-resolver": { - "version": "1.2.3", - "resolved": "https://registry.npmjs.org/jest-pnp-resolver/-/jest-pnp-resolver-1.2.3.tgz", - "integrity": "sha512-+3NpwQEnRoIBtx4fyhblQDPgJI0H1IEIkX7ShLUjPGA7TtUTvI1oiKi3SR4oBR0hQhQR80l4WAe5RrXBwWMA8w==", - "dev": true, - "engines": { - "node": ">=6" - }, - "peerDependencies": { - "jest-resolve": "*" - }, - "peerDependenciesMeta": { - "jest-resolve": { - "optional": true - } - } - }, - "node_modules/jest-regex-util": { - "version": "29.2.0", - "resolved": "https://registry.npmjs.org/jest-regex-util/-/jest-regex-util-29.2.0.tgz", - "integrity": "sha512-6yXn0kg2JXzH30cr2NlThF+70iuO/3irbaB4mh5WyqNIvLLP+B6sFdluO1/1RJmslyh/f9osnefECflHvTbwVA==", - "dev": true, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/jest-resolve": { - "version": "29.3.1", - "resolved": "https://registry.npmjs.org/jest-resolve/-/jest-resolve-29.3.1.tgz", - "integrity": "sha512-amXJgH/Ng712w3Uz5gqzFBBjxV8WFLSmNjoreBGMqxgCz5cH7swmBZzgBaCIOsvb0NbpJ0vgaSFdJqMdT+rADw==", - "dev": true, - "dependencies": { - "chalk": "^4.0.0", - "graceful-fs": "^4.2.9", - "jest-haste-map": "^29.3.1", - "jest-pnp-resolver": "^1.2.2", - "jest-util": "^29.3.1", - "jest-validate": "^29.3.1", - "resolve": "^1.20.0", - "resolve.exports": "^1.1.0", - "slash": "^3.0.0" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/jest-resolve-dependencies": { - "version": "29.3.1", - "resolved": "https://registry.npmjs.org/jest-resolve-dependencies/-/jest-resolve-dependencies-29.3.1.tgz", - "integrity": "sha512-Vk0cYq0byRw2WluNmNWGqPeRnZ3p3hHmjJMp2dyyZeYIfiBskwq4rpiuGFR6QGAdbj58WC7HN4hQHjf2mpvrLA==", - "dev": true, - "dependencies": { - "jest-regex-util": "^29.2.0", - "jest-snapshot": "^29.3.1" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/jest-runner": { - "version": "29.3.1", - "resolved": "https://registry.npmjs.org/jest-runner/-/jest-runner-29.3.1.tgz", - "integrity": "sha512-oFvcwRNrKMtE6u9+AQPMATxFcTySyKfLhvso7Sdk/rNpbhg4g2GAGCopiInk1OP4q6gz3n6MajW4+fnHWlU3bA==", - "dev": true, - "dependencies": { - "@jest/console": "^29.3.1", - "@jest/environment": "^29.3.1", - "@jest/test-result": "^29.3.1", - "@jest/transform": "^29.3.1", - "@jest/types": "^29.3.1", - "@types/node": "*", - "chalk": "^4.0.0", - "emittery": "^0.13.1", - "graceful-fs": "^4.2.9", - "jest-docblock": "^29.2.0", - "jest-environment-node": "^29.3.1", - "jest-haste-map": "^29.3.1", - "jest-leak-detector": "^29.3.1", - "jest-message-util": "^29.3.1", - "jest-resolve": "^29.3.1", - "jest-runtime": "^29.3.1", - "jest-util": "^29.3.1", - "jest-watcher": "^29.3.1", - "jest-worker": "^29.3.1", - "p-limit": "^3.1.0", - "source-map-support": "0.5.13" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/jest-runner/node_modules/source-map-support": { - "version": "0.5.13", - "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.13.tgz", - "integrity": "sha512-SHSKFHadjVA5oR4PPqhtAVdcBWwRYVd6g6cAXnIbRiIwc2EhPrTuKUBdSLvlEKyIP3GCf89fltvcZiP9MMFA1w==", - "dev": true, - "dependencies": { - "buffer-from": "^1.0.0", - "source-map": "^0.6.0" - } - }, - "node_modules/jest-runtime": { - "version": "29.3.1", - "resolved": "https://registry.npmjs.org/jest-runtime/-/jest-runtime-29.3.1.tgz", - "integrity": "sha512-jLzkIxIqXwBEOZx7wx9OO9sxoZmgT2NhmQKzHQm1xwR1kNW/dn0OjxR424VwHHf1SPN6Qwlb5pp1oGCeFTQ62A==", - "dev": true, - "dependencies": { - "@jest/environment": "^29.3.1", - "@jest/fake-timers": "^29.3.1", - "@jest/globals": "^29.3.1", - "@jest/source-map": "^29.2.0", - "@jest/test-result": "^29.3.1", - "@jest/transform": "^29.3.1", - "@jest/types": "^29.3.1", - "@types/node": "*", - "chalk": "^4.0.0", - "cjs-module-lexer": "^1.0.0", - "collect-v8-coverage": "^1.0.0", - "glob": "^7.1.3", - "graceful-fs": "^4.2.9", - "jest-haste-map": "^29.3.1", - "jest-message-util": "^29.3.1", - "jest-mock": "^29.3.1", - "jest-regex-util": "^29.2.0", - "jest-resolve": "^29.3.1", - "jest-snapshot": "^29.3.1", - "jest-util": "^29.3.1", - "slash": "^3.0.0", - "strip-bom": "^4.0.0" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/jest-snapshot": { - "version": "29.3.1", - "resolved": "https://registry.npmjs.org/jest-snapshot/-/jest-snapshot-29.3.1.tgz", - "integrity": "sha512-+3JOc+s28upYLI2OJM4PWRGK9AgpsMs/ekNryUV0yMBClT9B1DF2u2qay8YxcQd338PPYSFNb0lsar1B49sLDA==", - "dev": true, - "dependencies": { - "@babel/core": "^7.11.6", - "@babel/generator": "^7.7.2", - "@babel/plugin-syntax-jsx": "^7.7.2", - "@babel/plugin-syntax-typescript": "^7.7.2", - "@babel/traverse": "^7.7.2", - "@babel/types": "^7.3.3", - "@jest/expect-utils": "^29.3.1", - "@jest/transform": "^29.3.1", - "@jest/types": "^29.3.1", - "@types/babel__traverse": "^7.0.6", - "@types/prettier": "^2.1.5", - "babel-preset-current-node-syntax": "^1.0.0", - "chalk": "^4.0.0", - "expect": "^29.3.1", - "graceful-fs": "^4.2.9", - "jest-diff": "^29.3.1", - "jest-get-type": "^29.2.0", - "jest-haste-map": "^29.3.1", - "jest-matcher-utils": "^29.3.1", - "jest-message-util": "^29.3.1", - "jest-util": "^29.3.1", - "natural-compare": "^1.4.0", - "pretty-format": "^29.3.1", - "semver": "^7.3.5" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/jest-util": { - "version": "29.3.1", - "resolved": "https://registry.npmjs.org/jest-util/-/jest-util-29.3.1.tgz", - "integrity": "sha512-7YOVZaiX7RJLv76ZfHt4nbNEzzTRiMW/IiOG7ZOKmTXmoGBxUDefgMAxQubu6WPVqP5zSzAdZG0FfLcC7HOIFQ==", - "dev": true, - "dependencies": { - "@jest/types": "^29.3.1", - "@types/node": "*", - "chalk": "^4.0.0", - "ci-info": "^3.2.0", - "graceful-fs": "^4.2.9", - "picomatch": "^2.2.3" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/jest-validate": { - "version": "29.3.1", - "resolved": "https://registry.npmjs.org/jest-validate/-/jest-validate-29.3.1.tgz", - "integrity": "sha512-N9Lr3oYR2Mpzuelp1F8negJR3YE+L1ebk1rYA5qYo9TTY3f9OWdptLoNSPP9itOCBIRBqjt/S5XHlzYglLN67g==", - "dev": true, - "dependencies": { - "@jest/types": "^29.3.1", - "camelcase": "^6.2.0", - "chalk": "^4.0.0", - "jest-get-type": "^29.2.0", - "leven": "^3.1.0", - "pretty-format": "^29.3.1" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/jest-validate/node_modules/camelcase": { - "version": "6.3.0", - "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-6.3.0.tgz", - "integrity": "sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA==", - "dev": true, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/jest-watcher": { - "version": "29.3.1", - "resolved": "https://registry.npmjs.org/jest-watcher/-/jest-watcher-29.3.1.tgz", - "integrity": "sha512-RspXG2BQFDsZSRKGCT/NiNa8RkQ1iKAjrO0//soTMWx/QUt+OcxMqMSBxz23PYGqUuWm2+m2mNNsmj0eIoOaFg==", - "dev": true, - "dependencies": { - "@jest/test-result": "^29.3.1", - "@jest/types": "^29.3.1", - "@types/node": "*", - "ansi-escapes": "^4.2.1", - "chalk": "^4.0.0", - "emittery": "^0.13.1", - "jest-util": "^29.3.1", - "string-length": "^4.0.1" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/jest-worker": { - "version": "29.3.1", - "resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-29.3.1.tgz", - "integrity": "sha512-lY4AnnmsEWeiXirAIA0c9SDPbuCBq8IYuDVL8PMm0MZ2PEs2yPvRA/J64QBXuZp7CYKrDM/rmNrc9/i3KJQncw==", - "dev": true, - "dependencies": { - "@types/node": "*", - "jest-util": "^29.3.1", - "merge-stream": "^2.0.0", - "supports-color": "^8.0.0" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/jest-worker/node_modules/supports-color": { - "version": "8.1.1", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz", - "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==", - "dev": true, - "dependencies": { - "has-flag": "^4.0.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/supports-color?sponsor=1" - } - }, - "node_modules/js-sdsl": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/js-sdsl/-/js-sdsl-4.2.0.tgz", - "integrity": "sha512-dyBIzQBDkCqCu+0upx25Y2jGdbTGxE9fshMsCdK0ViOongpV+n5tXRcZY9v7CaVQ79AGS9KA1KHtojxiM7aXSQ==", - "dev": true, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/js-sdsl" - } - }, - "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==", - "dev": true - }, - "node_modules/js-yaml": { - "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": "^2.0.1" - }, - "bin": { - "js-yaml": "bin/js-yaml.js" - } - }, - "node_modules/jsesc": { - "version": "2.5.2", - "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-2.5.2.tgz", - "integrity": "sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA==", - "dev": true, - "bin": { - "jsesc": "bin/jsesc" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/json-parse-even-better-errors": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/json-parse-even-better-errors/-/json-parse-even-better-errors-2.3.1.tgz", - "integrity": "sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==", - "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==", - "dev": true - }, - "node_modules/json-stable-stringify-without-jsonify": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz", - "integrity": "sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==", - "dev": true - }, - "node_modules/json5": { - "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" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/jsonfile": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-6.1.0.tgz", - "integrity": "sha512-5dgndWOriYSm5cnYaJNhalLNDKOqFwyDB/rr1E9ZsGciGvKPs8R2xYGCacuf3z6K1YKDz182fd+fY3cn3pMqXQ==", - "dependencies": { - "universalify": "^2.0.0" - }, - "optionalDependencies": { - "graceful-fs": "^4.1.6" - } - }, - "node_modules/kleur": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/kleur/-/kleur-3.0.3.tgz", - "integrity": "sha512-eTIzlVOSUR+JxdDFepEYcBMtZ9Qqdef+rnzWdRZuMbOywu5tO2w2N7rqjoANZ5k9vywhL6Br1VRjUIgTQx4E8w==", - "dev": true, - "engines": { - "node": ">=6" - } - }, - "node_modules/leven": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/leven/-/leven-3.1.0.tgz", - "integrity": "sha512-qsda+H8jTaUaN/x5vzW2rzc+8Rw4TAQ/4KjB46IwK5VH+IlVeeeje/EoZRpiXvIqjFgK84QffqPztGI3VBLG1A==", - "dev": true, - "engines": { - "node": ">=6" - } - }, - "node_modules/levn": { - "version": "0.4.1", - "resolved": "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz", - "integrity": "sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==", - "dev": true, - "dependencies": { - "prelude-ls": "^1.2.1", - "type-check": "~0.4.0" - }, - "engines": { - "node": ">= 0.8.0" - } - }, - "node_modules/lines-and-columns": { - "version": "1.2.4", - "resolved": "https://registry.npmjs.org/lines-and-columns/-/lines-and-columns-1.2.4.tgz", - "integrity": "sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==", - "dev": true - }, - "node_modules/locate-path": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz", - "integrity": "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==", - "dev": true, - "dependencies": { - "p-locate": "^5.0.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/lodash.memoize": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/lodash.memoize/-/lodash.memoize-4.1.2.tgz", - "integrity": "sha512-t7j+NzmgnQzTAYXcsHYLgimltOV1MXHtlOWf6GjL9Kj8GK5FInw5JotxvbOs+IvV1/Dzo04/fCGfLVs7aXb4Ag==", - "dev": true - }, - "node_modules/lodash.merge": { - "version": "4.6.2", - "resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz", - "integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==", - "dev": true - }, - "node_modules/lodash.truncate": { - "version": "4.4.2", - "resolved": "https://registry.npmjs.org/lodash.truncate/-/lodash.truncate-4.4.2.tgz", - "integrity": "sha512-jttmRe7bRse52OsWIMDLaXxWqRAmtIUccAQ3garviCqJjafXOfNMO0yMfNpdD6zbGaTU0P5Nz7e7gAT6cKmJRw==", - "dev": true - }, - "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==", - "dev": true, - "dependencies": { - "yallist": "^3.0.2" - } - }, - "node_modules/make-dir": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-3.1.0.tgz", - "integrity": "sha512-g3FeP20LNwhALb/6Cz6Dd4F2ngze0jz7tbzrD2wAV+o9FeNHe4rL+yK2md0J/fiSf1sa1ADhXqi5+oVwOM/eGw==", - "dev": true, - "dependencies": { - "semver": "^6.0.0" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/make-dir/node_modules/semver": { - "version": "6.3.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", - "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", - "dev": true, - "bin": { - "semver": "bin/semver.js" - } - }, - "node_modules/make-error": { - "version": "1.3.6", - "resolved": "https://registry.npmjs.org/make-error/-/make-error-1.3.6.tgz", - "integrity": "sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw==", - "dev": true - }, - "node_modules/makeerror": { - "version": "1.0.12", - "resolved": "https://registry.npmjs.org/makeerror/-/makeerror-1.0.12.tgz", - "integrity": "sha512-JmqCvUhmt43madlpFzG4BQzG2Z3m6tvQDNKdClZnO3VbIudJYmxsT0FNJMeiB2+JTSlTQTSbU8QdesVmwJcmLg==", - "dev": true, - "dependencies": { - "tmpl": "1.0.5" - } - }, - "node_modules/md5": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/md5/-/md5-2.3.0.tgz", - "integrity": "sha512-T1GITYmFaKuO91vxyoQMFETst+O71VUPEU3ze5GNzDm0OWdP8v1ziTaAEPUr/3kLsY3Sftgz242A1SetQiDL7g==", - "dev": true, - "dependencies": { - "charenc": "0.0.2", - "crypt": "0.0.2", - "is-buffer": "~1.1.6" - } - }, - "node_modules/merge-stream": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/merge-stream/-/merge-stream-2.0.0.tgz", - "integrity": "sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==", - "dev": true - }, - "node_modules/merge2": { - "version": "1.4.1", - "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz", - "integrity": "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==", - "dev": true, - "engines": { - "node": ">= 8" - } - }, - "node_modules/micromatch": { - "version": "4.0.5", - "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.5.tgz", - "integrity": "sha512-DMy+ERcEW2q8Z2Po+WNXuw3c5YaUSFjAO5GsJqfEl7UjvtIuFKO6ZrKvcItdy98dwFI2N1tg3zNIdKaQT+aNdA==", - "dev": true, - "dependencies": { - "braces": "^3.0.2", - "picomatch": "^2.3.1" - }, - "engines": { - "node": ">=8.6" - } - }, - "node_modules/mimic-fn": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-2.1.0.tgz", - "integrity": "sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==", - "dev": true, - "engines": { - "node": ">=6" - } - }, - "node_modules/minimatch": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", - "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", - "dependencies": { - "brace-expansion": "^1.1.7" - }, - "engines": { - "node": "*" - } - }, - "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/ms": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", - "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", - "dev": true - }, - "node_modules/natural-compare": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz", - "integrity": "sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==", - "dev": true - }, - "node_modules/natural-compare-lite": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/natural-compare-lite/-/natural-compare-lite-1.4.0.tgz", - "integrity": "sha512-Tj+HTDSJJKaZnfiuw+iaF9skdPpTo2GtEly5JHnWV/hfv2Qj/9RKsGISQtLh2ox3l5EAGw487hnBee0sIJ6v2g==", - "dev": true - }, - "node_modules/node-int64": { - "version": "0.4.0", - "resolved": "https://registry.npmjs.org/node-int64/-/node-int64-0.4.0.tgz", - "integrity": "sha512-O5lz91xSOeoXP6DulyHfllpq+Eg00MWitZIbtPfoSEvqIHdl5gfcY6hYzDWnj0qD5tz52PI08u9qUvSVeUBeHw==", - "dev": true - }, - "node_modules/node-releases": { - "version": "2.0.8", - "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.8.tgz", - "integrity": "sha512-dFSmB8fFHEH/s81Xi+Y/15DQY6VHW81nXRj86EMSL3lmuTmK1e+aT4wrFCkTbm+gSwkw4KpX+rT/pMM2c1mF+A==", - "dev": true - }, - "node_modules/normalize-path": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", - "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/npm-run-path": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-4.0.1.tgz", - "integrity": "sha512-S48WzZW777zhNIrn7gxOlISNAqi9ZC/uQFnRdbeIHhZhCA6UqpkOT8T1G7BvfdgP4Er8gF4sUbaS0i7QvIfCWw==", - "dev": true, - "dependencies": { - "path-key": "^3.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/object-inspect": { - "version": "1.12.2", - "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.12.2.tgz", - "integrity": "sha512-z+cPxW0QGUp0mcqcsgQyLVRDoXFQbXOwBaqyF7VIgI4TWNQsDHrBpUQslRmIfAoYWdYzs6UlKJtB2XJpTaNSpQ==", - "dev": true, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/object-keys": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/object-keys/-/object-keys-1.1.1.tgz", - "integrity": "sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==", - "dev": true, - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/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==", - "dev": true, - "dependencies": { - "call-bind": "^1.0.2", - "define-properties": "^1.1.4", - "has-symbols": "^1.0.3", - "object-keys": "^1.1.1" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/object.values": { - "version": "1.1.6", - "resolved": "https://registry.npmjs.org/object.values/-/object.values-1.1.6.tgz", - "integrity": "sha512-FVVTkD1vENCsAcwNs9k6jea2uHC/X0+JcjG8YA60FN5CMaJmG95wT9jek/xX9nornqGRrBkKtzuAu2wuHpKqvw==", - "dev": true, - "dependencies": { - "call-bind": "^1.0.2", - "define-properties": "^1.1.4", - "es-abstract": "^1.20.4" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/once": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", - "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==", - "dev": true, - "dependencies": { - "wrappy": "1" - } - }, - "node_modules/onetime": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/onetime/-/onetime-5.1.2.tgz", - "integrity": "sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg==", - "dev": true, - "dependencies": { - "mimic-fn": "^2.1.0" - }, - "engines": { - "node": ">=6" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/open": { - "version": "8.4.0", - "resolved": "https://registry.npmjs.org/open/-/open-8.4.0.tgz", - "integrity": "sha512-XgFPPM+B28FtCCgSb9I+s9szOC1vZRSwgWsRUA5ylIxRTgKozqjOCrVOqGsYABPYK5qnfqClxZTFBa8PKt2v6Q==", - "dev": true, - "dependencies": { - "define-lazy-prop": "^2.0.0", - "is-docker": "^2.1.1", - "is-wsl": "^2.2.0" - }, - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/optionator": { - "version": "0.9.1", - "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.1.tgz", - "integrity": "sha512-74RlY5FCnhq4jRxVUPKDaRwrVNXMqsGsiW6AJw4XK8hmtm10wC0ypZBLw5IIp85NZMr91+qd1RvvENwg7jjRFw==", - "dev": true, - "dependencies": { - "deep-is": "^0.1.3", - "fast-levenshtein": "^2.0.6", - "levn": "^0.4.1", - "prelude-ls": "^1.2.1", - "type-check": "^0.4.0", - "word-wrap": "^1.2.3" - }, - "engines": { - "node": ">= 0.8.0" - } - }, - "node_modules/p-limit": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz", - "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==", - "dev": true, - "dependencies": { - "yocto-queue": "^0.1.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/p-locate": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-5.0.0.tgz", - "integrity": "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==", - "dev": true, - "dependencies": { - "p-limit": "^3.0.2" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/p-try": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz", - "integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==", - "dev": true, - "engines": { - "node": ">=6" - } - }, - "node_modules/parent-module": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz", - "integrity": "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==", - "dev": true, - "dependencies": { - "callsites": "^3.0.0" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/parse-json": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-5.2.0.tgz", - "integrity": "sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg==", - "dev": true, - "dependencies": { - "@babel/code-frame": "^7.0.0", - "error-ex": "^1.3.1", - "json-parse-even-better-errors": "^2.3.0", - "lines-and-columns": "^1.1.6" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/path-exists": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", - "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/path-is-absolute": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", - "integrity": "sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/path-key": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", - "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/path-parse": { - "version": "1.0.7", - "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz", - "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==", - "dev": true - }, - "node_modules/path-type": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/path-type/-/path-type-4.0.0.tgz", - "integrity": "sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/picocolors": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.0.0.tgz", - "integrity": "sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ==", - "dev": true - }, - "node_modules/picomatch": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", - "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", - "dev": true, - "engines": { - "node": ">=8.6" - }, - "funding": { - "url": "https://github.com/sponsors/jonschlinkert" - } - }, - "node_modules/pirates": { - "version": "4.0.5", - "resolved": "https://registry.npmjs.org/pirates/-/pirates-4.0.5.tgz", - "integrity": "sha512-8V9+HQPupnaXMA23c5hvl69zXvTwTzyAYasnkb0Tts4XvO4CliqONMOnvlq26rkhLC3nWDFBJf73LU1e1VZLaQ==", - "dev": true, - "engines": { - "node": ">= 6" - } - }, - "node_modules/pkg-dir": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-4.2.0.tgz", - "integrity": "sha512-HRDzbaKjC+AOWVXxAU/x54COGeIv9eb+6CkDSQoNTt4XyWoIJvuPsXizxu/Fr23EiekbtZwmh1IcIG/l/a10GQ==", - "dev": true, - "dependencies": { - "find-up": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/pkg-dir/node_modules/find-up": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz", - "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==", - "dev": true, - "dependencies": { - "locate-path": "^5.0.0", - "path-exists": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/pkg-dir/node_modules/locate-path": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz", - "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==", - "dev": true, - "dependencies": { - "p-locate": "^4.1.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/pkg-dir/node_modules/p-limit": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz", - "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==", - "dev": true, - "dependencies": { - "p-try": "^2.0.0" - }, - "engines": { - "node": ">=6" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/pkg-dir/node_modules/p-locate": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz", - "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==", - "dev": true, - "dependencies": { - "p-limit": "^2.2.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/prelude-ls": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz", - "integrity": "sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==", - "dev": true, - "engines": { - "node": ">= 0.8.0" - } - }, - "node_modules/pretty-format": { - "version": "29.3.1", - "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-29.3.1.tgz", - "integrity": "sha512-FyLnmb1cYJV8biEIiRyzRFvs2lry7PPIvOqKVe1GCUEYg4YGmlx1qG9EJNMxArYm7piII4qb8UV1Pncq5dxmcg==", - "dev": true, - "dependencies": { - "@jest/schemas": "^29.0.0", - "ansi-styles": "^5.0.0", - "react-is": "^18.0.0" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/pretty-format/node_modules/ansi-styles": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-5.2.0.tgz", - "integrity": "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==", - "dev": true, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" - } - }, - "node_modules/prompts": { - "version": "2.4.2", - "resolved": "https://registry.npmjs.org/prompts/-/prompts-2.4.2.tgz", - "integrity": "sha512-NxNv/kLguCA7p3jE8oL2aEBsrJWgAakBpgmgK6lpPWV+WuOmY6r2/zbAVnP+T8bQlA0nzHXSJSJW0Hq7ylaD2Q==", - "dev": true, - "dependencies": { - "kleur": "^3.0.3", - "sisteransi": "^1.0.5" - }, - "engines": { - "node": ">= 6" - } - }, - "node_modules/pseudomap": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/pseudomap/-/pseudomap-1.0.2.tgz", - "integrity": "sha512-b/YwNhb8lk1Zz2+bXXpS/LK9OisiZZ1SNsSLxN1x2OXVEhW2Ckr/7mWE5vrC1ZTiJlD9g19jWszTmJsB+oEpFQ==" - }, - "node_modules/punycode": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.2.0.tgz", - "integrity": "sha512-LN6QV1IJ9ZhxWTNdktaPClrNfp8xdSAYS0Zk2ddX7XsXZAxckMHPCBcHRo0cTcEIgYPRiGEkmji3Idkh2yFtYw==", - "engines": { - "node": ">=6" - } - }, - "node_modules/queue-microtask": { - "version": "1.2.3", - "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz", - "integrity": "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==", - "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/react-is": { - "version": "18.2.0", - "resolved": "https://registry.npmjs.org/react-is/-/react-is-18.2.0.tgz", - "integrity": "sha512-xWGDIW6x921xtzPkhiULtthJHoJvBbF3q26fzloPCK0hsvxtPVelvftw3zjbHWSkR2km9Z+4uxbDDK/6Zw9B8w==", - "dev": true - }, - "node_modules/regexp.prototype.flags": { - "version": "1.4.3", - "resolved": "https://registry.npmjs.org/regexp.prototype.flags/-/regexp.prototype.flags-1.4.3.tgz", - "integrity": "sha512-fjggEOO3slI6Wvgjwflkc4NFRCTZAu5CnNfBd5qOMYhWdn67nJBBu34/TkD++eeFmd8C9r9jfXJ27+nSiRkSUA==", - "dev": true, - "dependencies": { - "call-bind": "^1.0.2", - "define-properties": "^1.1.3", - "functions-have-names": "^1.2.2" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/regexpp": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/regexpp/-/regexpp-3.2.0.tgz", - "integrity": "sha512-pq2bWo9mVD43nbts2wGv17XLiNLya+GklZ8kaDLV2Z08gDCsGpnKn9BFMepvWuHCbyVvY7J5o5+BVvoQbmlJLg==", - "dev": true, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/mysticatea" - } - }, - "node_modules/require-directory": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", - "integrity": "sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/require-from-string": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/require-from-string/-/require-from-string-2.0.2.tgz", - "integrity": "sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/resolve": { - "version": "1.22.1", - "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.1.tgz", - "integrity": "sha512-nBpuuYuY5jFsli/JIs1oldw6fOQCBioohqWZg/2hiaOybXOft4lonv85uDOKXdf8rhyK159cxU5cDcK/NKk8zw==", - "dev": true, - "dependencies": { - "is-core-module": "^2.9.0", - "path-parse": "^1.0.7", - "supports-preserve-symlinks-flag": "^1.0.0" - }, - "bin": { - "resolve": "bin/resolve" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/resolve-cwd": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/resolve-cwd/-/resolve-cwd-3.0.0.tgz", - "integrity": "sha512-OrZaX2Mb+rJCpH/6CpSqt9xFVpN++x01XnN2ie9g6P5/3xelLAkXWVADpdz1IHD/KFfEXyE6V0U01OQ3UO2rEg==", - "dev": true, - "dependencies": { - "resolve-from": "^5.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/resolve-cwd/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/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, - "engines": { - "node": ">=4" - } - }, - "node_modules/resolve.exports": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/resolve.exports/-/resolve.exports-1.1.0.tgz", - "integrity": "sha512-J1l+Zxxp4XK3LUDZ9m60LRJF/mAe4z6a4xyabPHk7pvK5t35dACV32iIjJDFeWZFfZlO29w6SZ67knR0tHzJtQ==", - "dev": true, - "engines": { - "node": ">=10" - } - }, - "node_modules/reusify": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.0.4.tgz", - "integrity": "sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==", - "dev": true, - "engines": { - "iojs": ">=1.0.0", - "node": ">=0.10.0" - } - }, - "node_modules/rimraf": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz", - "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==", - "dev": true, - "dependencies": { - "glob": "^7.1.3" - }, - "bin": { - "rimraf": "bin.js" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/run-parallel": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz", - "integrity": "sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==", - "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": { - "queue-microtask": "^1.2.2" - } - }, - "node_modules/safe-regex-test": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/safe-regex-test/-/safe-regex-test-1.0.0.tgz", - "integrity": "sha512-JBUUzyOgEwXQY1NuPtvcj/qcBDbDmEvWufhlnXZIm75DEHp+afM1r1ujJpJsV/gSM4t59tpDyPi1sd6ZaPFfsA==", - "dev": true, - "dependencies": { - "call-bind": "^1.0.2", - "get-intrinsic": "^1.1.3", - "is-regex": "^1.1.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/semver": { - "version": "7.3.8", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.8.tgz", - "integrity": "sha512-NB1ctGL5rlHrPJtFDVIVzTyQylMLu9N9VICA6HSFJo8MCGVTMW6gfpicwKmmK/dAjTOrqu5l63JJOpDSrAis3A==", - "dependencies": { - "lru-cache": "^6.0.0" - }, - "bin": { - "semver": "bin/semver.js" - }, - "engines": { - "node": ">=10" - } - }, - "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==", - "dependencies": { - "yallist": "^4.0.0" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/semver/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/shebang-command": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", - "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", - "dev": true, - "dependencies": { - "shebang-regex": "^3.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/shebang-regex": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", - "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/side-channel": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.0.4.tgz", - "integrity": "sha512-q5XPytqFEIKHkGdiMIrY10mvLRvnQh42/+GoBlFW3b2LXLE2xxJpZFdm94we0BaoV3RwJyGqg5wS7epxTv0Zvw==", - "dev": true, - "dependencies": { - "call-bind": "^1.0.0", - "get-intrinsic": "^1.0.2", - "object-inspect": "^1.9.0" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/signal-exit": { - "version": "3.0.7", - "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz", - "integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==", - "dev": true - }, - "node_modules/sisteransi": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/sisteransi/-/sisteransi-1.0.5.tgz", - "integrity": "sha512-bLGGlR1QxBcynn2d5YmDX4MGjlZvy2MRBDRNHLJ8VI6l6+9FUiyTFNJ0IveOSP0bcXgVDPRcfGqA0pjaqUpfVg==", - "dev": true - }, - "node_modules/slash": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz", - "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/slice-ansi": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-4.0.0.tgz", - "integrity": "sha512-qMCMfhY040cVHT43K9BFygqYbUPFZKHOg7K73mtTWJRb8pyP3fzf4Ixd5SzdEJQ6MRUg/WBnOLxghZtKKurENQ==", - "dev": true, - "dependencies": { - "ansi-styles": "^4.0.0", - "astral-regex": "^2.0.0", - "is-fullwidth-code-point": "^3.0.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/slice-ansi?sponsor=1" - } - }, - "node_modules/source-map": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/source-map-support": { - "version": "0.5.21", - "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.21.tgz", - "integrity": "sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w==", - "dependencies": { - "buffer-from": "^1.0.0", - "source-map": "^0.6.0" - } - }, - "node_modules/sprintf-js": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz", - "integrity": "sha512-D9cPgkvLlV3t3IzL0D0YLvGA9Ahk4PcvVwUbN0dSGr1aP0Nrt4AEnTUbuGvquEC0mA64Gqt1fzirlRs5ibXx8g==", - "dev": true - }, - "node_modules/stack-utils": { - "version": "2.0.6", - "resolved": "https://registry.npmjs.org/stack-utils/-/stack-utils-2.0.6.tgz", - "integrity": "sha512-XlkWvfIm6RmsWtNJx+uqtKLS8eqFbxUg0ZzLXqY0caEy9l7hruX8IpiDnjsLavoBgqCCR71TqWO8MaXYheJ3RQ==", - "dev": true, - "dependencies": { - "escape-string-regexp": "^2.0.0" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/stack-utils/node_modules/escape-string-regexp": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-2.0.0.tgz", - "integrity": "sha512-UpzcLCXolUWcNu5HtVMHYdXJjArjsF9C0aNnquZYY4uW/Vu0miy5YoWvbV345HauVvcAUnpRuhMMcqTcGOY2+w==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/string-length": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/string-length/-/string-length-4.0.2.tgz", - "integrity": "sha512-+l6rNN5fYHNhZZy41RXsYptCjA2Igmq4EG7kZAYFQI1E1VTXarr6ZPXBg6eq7Y6eK4FEhY6AJlyuFIb/v/S0VQ==", - "dev": true, - "dependencies": { - "char-regex": "^1.0.2", - "strip-ansi": "^6.0.0" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/string-width": { - "version": "4.2.3", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", - "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", - "dev": true, - "dependencies": { - "emoji-regex": "^8.0.0", - "is-fullwidth-code-point": "^3.0.0", - "strip-ansi": "^6.0.1" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/string.prototype.trimend": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/string.prototype.trimend/-/string.prototype.trimend-1.0.6.tgz", - "integrity": "sha512-JySq+4mrPf9EsDBEDYMOb/lM7XQLulwg5R/m1r0PXEFqrV0qHvl58sdTilSXtKOflCsK2E8jxf+GKC0T07RWwQ==", - "dev": true, - "dependencies": { - "call-bind": "^1.0.2", - "define-properties": "^1.1.4", - "es-abstract": "^1.20.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/string.prototype.trimstart": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/string.prototype.trimstart/-/string.prototype.trimstart-1.0.6.tgz", - "integrity": "sha512-omqjMDaY92pbn5HOX7f9IccLA+U1tA9GvtU4JrodiXFfYB7jPzzHpRzpglLAjtUV6bB557zwClJezTqnAiYnQA==", - "dev": true, - "dependencies": { - "call-bind": "^1.0.2", - "define-properties": "^1.1.4", - "es-abstract": "^1.20.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/strip-ansi": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", - "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", - "dev": true, - "dependencies": { - "ansi-regex": "^5.0.1" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/strip-bom": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-4.0.0.tgz", - "integrity": "sha512-3xurFv5tEgii33Zi8Jtp55wEIILR9eh34FAW00PZf+JnSsTmV/ioewSgQl97JHvgjoRGwPShsWm+IdrxB35d0w==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/strip-final-newline": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/strip-final-newline/-/strip-final-newline-2.0.0.tgz", - "integrity": "sha512-BrpvfNAE3dcvq7ll3xVumzjKjZQ5tI1sEUIKr3Uoks0XUl45St3FlatVqef9prk4jRDzhW6WZg+3bk93y6pLjA==", - "dev": true, - "engines": { - "node": ">=6" - } - }, - "node_modules/strip-json-comments": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz", - "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==", - "dev": true, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", - "dev": true, - "dependencies": { - "has-flag": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/supports-preserve-symlinks-flag": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz", - "integrity": "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==", - "dev": true, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/synckit": { - "version": "0.8.4", - "resolved": "https://registry.npmjs.org/synckit/-/synckit-0.8.4.tgz", - "integrity": "sha512-Dn2ZkzMdSX827QbowGbU/4yjWuvNaCoScLLoMo/yKbu+P4GBR6cRGKZH27k6a9bRzdqcyd1DE96pQtQ6uNkmyw==", - "dev": true, - "dependencies": { - "@pkgr/utils": "^2.3.1", - "tslib": "^2.4.0" - }, - "engines": { - "node": "^14.18.0 || >=16.0.0" - }, - "funding": { - "url": "https://opencollective.com/unts" - } - }, - "node_modules/table": { - "version": "6.8.1", - "resolved": "https://registry.npmjs.org/table/-/table-6.8.1.tgz", - "integrity": "sha512-Y4X9zqrCftUhMeH2EptSSERdVKt/nEdijTOacGD/97EKjhQ/Qs8RTlEGABSJNNN8lac9kheH+af7yAkEWlgneA==", - "dev": true, - "dependencies": { - "ajv": "^8.0.1", - "lodash.truncate": "^4.4.2", - "slice-ansi": "^4.0.0", - "string-width": "^4.2.3", - "strip-ansi": "^6.0.1" - }, - "engines": { - "node": ">=10.0.0" - } - }, - "node_modules/table/node_modules/ajv": { - "version": "8.12.0", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.12.0.tgz", - "integrity": "sha512-sRu1kpcO9yLtYxBKvqfTeh9KzZEwO3STyX1HT+4CaDzC6HpTGYhIhPIzj9XuKU7KYDwnaeh5hcOwjy1QuJzBPA==", - "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/table/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/tapable": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/tapable/-/tapable-2.2.1.tgz", - "integrity": "sha512-GNzQvQTOIP6RyTfE2Qxb8ZVlNmw0n88vp1szwWRimP02mnTsx3Wtn5qRdqY9w2XduFNUgvOwhNnQsjwCp+kqaQ==", - "dev": true, - "engines": { - "node": ">=6" - } - }, - "node_modules/test-exclude": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/test-exclude/-/test-exclude-6.0.0.tgz", - "integrity": "sha512-cAGWPIyOHU6zlmg88jwm7VRyXnMN7iV68OGAbYDk/Mh/xC/pzVPlQtY6ngoIH/5/tciuhGfvESU8GrHrcxD56w==", - "dev": true, - "dependencies": { - "@istanbuljs/schema": "^0.1.2", - "glob": "^7.1.4", - "minimatch": "^3.0.4" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/text-table": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz", - "integrity": "sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw==", - "dev": true - }, - "node_modules/tiny-glob": { - "version": "0.2.9", - "resolved": "https://registry.npmjs.org/tiny-glob/-/tiny-glob-0.2.9.tgz", - "integrity": "sha512-g/55ssRPUjShh+xkfx9UPDXqhckHEsHr4Vd9zX55oSdGZc/MD0m3sferOkwWtp98bv+kcVfEHtRJgBVJzelrzg==", - "dev": true, - "dependencies": { - "globalyzer": "0.1.0", - "globrex": "^0.1.2" - } - }, - "node_modules/tmpl": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/tmpl/-/tmpl-1.0.5.tgz", - "integrity": "sha512-3f0uOEAQwIqGuWW2MVzYg8fV/QNnc/IpuJNG837rLuczAaLVHslWHZQj4IGiEl5Hs3kkbhwL9Ab7Hrsmuj+Smw==", - "dev": true - }, - "node_modules/to-fast-properties": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/to-fast-properties/-/to-fast-properties-2.0.0.tgz", - "integrity": "sha512-/OaKK0xYrs3DmxRYqL/yDc+FxFUVYhDlXMhRmv3z915w2HF1tnN1omB354j8VUGO/hbRzyD6Y3sA7v7GS/ceog==", - "dev": true, - "engines": { - "node": ">=4" - } - }, - "node_modules/to-regex-range": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", - "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", - "dev": true, - "dependencies": { - "is-number": "^7.0.0" - }, - "engines": { - "node": ">=8.0" - } - }, - "node_modules/ts-jest": { - "version": "29.0.3", - "resolved": "https://registry.npmjs.org/ts-jest/-/ts-jest-29.0.3.tgz", - "integrity": "sha512-Ibygvmuyq1qp/z3yTh9QTwVVAbFdDy/+4BtIQR2sp6baF2SJU/8CKK/hhnGIDY2L90Az2jIqTwZPnN2p+BweiQ==", - "dev": true, - "dependencies": { - "bs-logger": "0.x", - "fast-json-stable-stringify": "2.x", - "jest-util": "^29.0.0", - "json5": "^2.2.1", - "lodash.memoize": "4.x", - "make-error": "1.x", - "semver": "7.x", - "yargs-parser": "^21.0.1" - }, - "bin": { - "ts-jest": "cli.js" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - }, - "peerDependencies": { - "@babel/core": ">=7.0.0-beta.0 <8", - "@jest/types": "^29.0.0", - "babel-jest": "^29.0.0", - "jest": "^29.0.0", - "typescript": ">=4.3" - }, - "peerDependenciesMeta": { - "@babel/core": { - "optional": true - }, - "@jest/types": { - "optional": true - }, - "babel-jest": { - "optional": true - }, - "esbuild": { - "optional": true - } - } - }, - "node_modules/ts-md5": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/ts-md5/-/ts-md5-1.3.1.tgz", - "integrity": "sha512-DiwiXfwvcTeZ5wCE0z+2A9EseZsztaiZtGrtSaY5JOD7ekPnR/GoIVD5gXZAlK9Na9Kvpo9Waz5rW64WKAWApg==", - "engines": { - "node": ">=12" - } - }, - "node_modules/ts-node": { - "version": "10.9.1", - "resolved": "https://registry.npmjs.org/ts-node/-/ts-node-10.9.1.tgz", - "integrity": "sha512-NtVysVPkxxrwFGUUxGYhfux8k78pQB3JqYBXlLRZgdGUqTO5wU/UyHop5p70iEbGhB7q5KmiZiU0Y3KlJrScEw==", - "dev": true, - "dependencies": { - "@cspotcode/source-map-support": "^0.8.0", - "@tsconfig/node10": "^1.0.7", - "@tsconfig/node12": "^1.0.7", - "@tsconfig/node14": "^1.0.0", - "@tsconfig/node16": "^1.0.2", - "acorn": "^8.4.1", - "acorn-walk": "^8.1.1", - "arg": "^4.1.0", - "create-require": "^1.1.0", - "diff": "^4.0.1", - "make-error": "^1.1.1", - "v8-compile-cache-lib": "^3.0.1", - "yn": "3.1.1" - }, - "bin": { - "ts-node": "dist/bin.js", - "ts-node-cwd": "dist/bin-cwd.js", - "ts-node-esm": "dist/bin-esm.js", - "ts-node-script": "dist/bin-script.js", - "ts-node-transpile-only": "dist/bin-transpile.js", - "ts-script": "dist/bin-script-deprecated.js" - }, - "peerDependencies": { - "@swc/core": ">=1.2.50", - "@swc/wasm": ">=1.2.50", - "@types/node": "*", - "typescript": ">=2.7" - }, - "peerDependenciesMeta": { - "@swc/core": { - "optional": true - }, - "@swc/wasm": { - "optional": true - } - } - }, - "node_modules/ts-node/node_modules/diff": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/diff/-/diff-4.0.2.tgz", - "integrity": "sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A==", - "dev": true, - "engines": { - "node": ">=0.3.1" - } - }, - "node_modules/tsconfig-paths": { - "version": "3.14.1", - "resolved": "https://registry.npmjs.org/tsconfig-paths/-/tsconfig-paths-3.14.1.tgz", - "integrity": "sha512-fxDhWnFSLt3VuTwtvJt5fpwxBHg5AdKWMsgcPOOIilyjymcYVZoCQF8fvFRezCNfblEXmi+PcM1eYHeOAgXCOQ==", - "dev": true, - "dependencies": { - "@types/json5": "^0.0.29", - "json5": "^1.0.1", - "minimist": "^1.2.6", - "strip-bom": "^3.0.0" - } - }, - "node_modules/tsconfig-paths/node_modules/json5": { - "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" - }, - "bin": { - "json5": "lib/cli.js" - } - }, - "node_modules/tsconfig-paths/node_modules/strip-bom": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-3.0.0.tgz", - "integrity": "sha512-vavAMRXOgBVNF6nyEEmL3DBK19iRpDcoIwW+swQ+CbGiu7lju6t+JklA1MHweoWtadgt4ISVUsXLyDq34ddcwA==", - "dev": true, - "engines": { - "node": ">=4" - } - }, - "node_modules/tslib": { - "version": "2.4.1", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.4.1.tgz", - "integrity": "sha512-tGyy4dAjRIEwI7BzsB0lynWgOpfqjUdq91XXAlIWD2OwKBH7oCl/GZG/HT4BOHrTlPMOASlMQ7veyTqpmRcrNA==", - "dev": true - }, - "node_modules/tsutils": { - "version": "3.21.0", - "resolved": "https://registry.npmjs.org/tsutils/-/tsutils-3.21.0.tgz", - "integrity": "sha512-mHKK3iUXL+3UF6xL5k0PEhKRUBKPBCv/+RkEOpjRWxxx27KKRBmmA60A9pgOUvMi8GKhRMPEmjBRPzs2W7O1OA==", - "dev": true, - "dependencies": { - "tslib": "^1.8.1" - }, - "engines": { - "node": ">= 6" - }, - "peerDependencies": { - "typescript": ">=2.8.0 || >= 3.2.0-dev || >= 3.3.0-dev || >= 3.4.0-dev || >= 3.5.0-dev || >= 3.6.0-dev || >= 3.6.0-beta || >= 3.7.0-dev || >= 3.7.0-beta" - } - }, - "node_modules/tsutils/node_modules/tslib": { - "version": "1.14.1", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", - "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==", - "dev": true - }, - "node_modules/type-check": { - "version": "0.4.0", - "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz", - "integrity": "sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==", - "dev": true, - "dependencies": { - "prelude-ls": "^1.2.1" - }, - "engines": { - "node": ">= 0.8.0" - } - }, - "node_modules/type-detect": { - "version": "4.0.8", - "resolved": "https://registry.npmjs.org/type-detect/-/type-detect-4.0.8.tgz", - "integrity": "sha512-0fr/mIH1dlO+x7TlcMy+bIDqKPsw/70tVyeHW787goQjhmqaZe10uwLujubK9q9Lg6Fiho1KUKDYz0Z7k7g5/g==", - "dev": true, - "engines": { - "node": ">=4" - } - }, - "node_modules/type-fest": { - "version": "0.20.2", - "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.20.2.tgz", - "integrity": "sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==", - "dev": true, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/typed-array-length": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/typed-array-length/-/typed-array-length-1.0.4.tgz", - "integrity": "sha512-KjZypGq+I/H7HI5HlOoGHkWUUGq+Q0TPhQurLbyrVrvnKTBgzLhIJ7j6J/XTQOi0d1RjyZ0wdas8bKs2p0x3Ng==", - "dev": true, - "dependencies": { - "call-bind": "^1.0.2", - "for-each": "^0.3.3", - "is-typed-array": "^1.1.9" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/typescript": { - "version": "4.9.4", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.9.4.tgz", - "integrity": "sha512-Uz+dTXYzxXXbsFpM86Wh3dKCxrQqUcVMxwU54orwlJjOpO3ao8L7j5lH+dWfTwgCwIuM9GQ2kvVotzYJMXTBZg==", - "dev": true, - "bin": { - "tsc": "bin/tsc", - "tsserver": "bin/tsserver" - }, - "engines": { - "node": ">=4.2.0" - } - }, - "node_modules/unbox-primitive": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/unbox-primitive/-/unbox-primitive-1.0.2.tgz", - "integrity": "sha512-61pPlCD9h51VoreyJ0BReideM3MDKMKnh6+V9L08331ipq6Q8OFXZYiqP6n/tbHx4s5I9uRhcye6BrbkizkBDw==", - "dev": true, - "dependencies": { - "call-bind": "^1.0.2", - "has-bigints": "^1.0.2", - "has-symbols": "^1.0.3", - "which-boxed-primitive": "^1.0.2" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/universalify": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/universalify/-/universalify-2.0.0.tgz", - "integrity": "sha512-hAZsKq7Yy11Zu1DE0OzWjw7nnLZmJZYTDZZyEFHZdUhV8FkH5MCfoU1XMaxXovpyW5nq5scPqq0ZDP9Zyl04oQ==", - "engines": { - "node": ">= 10.0.0" - } - }, - "node_modules/update-browserslist-db": { - "version": "1.0.10", - "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.0.10.tgz", - "integrity": "sha512-OztqDenkfFkbSG+tRxBeAnCVPckDBcvibKd35yDONx6OU8N7sqgwc7rCbkJ/WcYtVRZ4ba68d6byhC21GFh7sQ==", - "dev": true, - "funding": [ - { - "type": "opencollective", - "url": "https://opencollective.com/browserslist" - }, - { - "type": "tidelift", - "url": "https://tidelift.com/funding/github/npm/browserslist" - } - ], - "dependencies": { - "escalade": "^3.1.1", - "picocolors": "^1.0.0" - }, - "bin": { - "browserslist-lint": "cli.js" - }, - "peerDependencies": { - "browserslist": ">= 4.21.0" - } - }, - "node_modules/uri-js": { - "version": "4.4.1", - "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz", - "integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==", - "dev": true, - "dependencies": { - "punycode": "^2.1.0" - } - }, - "node_modules/v8-compile-cache-lib": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/v8-compile-cache-lib/-/v8-compile-cache-lib-3.0.1.tgz", - "integrity": "sha512-wa7YjyUGfNZngI/vtK0UHAN+lgDCxBPCylVXGp0zu59Fz5aiGtNXaq3DhIov063MorB+VfufLh3JlF2KdTK3xg==", - "dev": true - }, - "node_modules/v8-to-istanbul": { - "version": "9.0.1", - "resolved": "https://registry.npmjs.org/v8-to-istanbul/-/v8-to-istanbul-9.0.1.tgz", - "integrity": "sha512-74Y4LqY74kLE6IFyIjPtkSTWzUZmj8tdHT9Ii/26dvQ6K9Dl2NbEfj0XgU2sHCtKgt5VupqhlO/5aWuqS+IY1w==", - "dev": true, - "dependencies": { - "@jridgewell/trace-mapping": "^0.3.12", - "@types/istanbul-lib-coverage": "^2.0.1", - "convert-source-map": "^1.6.0" - }, - "engines": { - "node": ">=10.12.0" - } - }, - "node_modules/v8-to-istanbul/node_modules/convert-source-map": { - "version": "1.9.0", - "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-1.9.0.tgz", - "integrity": "sha512-ASFBup0Mz1uyiIjANan1jzLQami9z1PoYSZCiiYW2FczPbenXc45FZdBZLzOT+r6+iciuEModtmCti+hjaAk0A==", - "dev": true - }, - "node_modules/walker": { - "version": "1.0.8", - "resolved": "https://registry.npmjs.org/walker/-/walker-1.0.8.tgz", - "integrity": "sha512-ts/8E8l5b7kY0vlWLewOkDXMmPdLcVV4GmOQLyxuSswIJsweeFZtAsMF7k1Nszz+TYBQrlYRmzOnr398y1JemQ==", - "dev": true, - "dependencies": { - "makeerror": "1.0.12" - } - }, - "node_modules/which": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", - "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", - "dev": true, - "dependencies": { - "isexe": "^2.0.0" - }, - "bin": { - "node-which": "bin/node-which" - }, - "engines": { - "node": ">= 8" - } - }, - "node_modules/which-boxed-primitive": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/which-boxed-primitive/-/which-boxed-primitive-1.0.2.tgz", - "integrity": "sha512-bwZdv0AKLpplFY2KZRX6TvyuN7ojjr7lwkg6ml0roIy9YeuSr7JS372qlNW18UQYzgYK9ziGcerWqZOmEn9VNg==", - "dev": true, - "dependencies": { - "is-bigint": "^1.0.1", - "is-boolean-object": "^1.1.0", - "is-number-object": "^1.0.4", - "is-string": "^1.0.5", - "is-symbol": "^1.0.3" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/which-typed-array": { - "version": "1.1.9", - "resolved": "https://registry.npmjs.org/which-typed-array/-/which-typed-array-1.1.9.tgz", - "integrity": "sha512-w9c4xkx6mPidwp7180ckYWfMmvxpjlZuIudNtDf4N/tTAUB8VJbX25qZoAsrtGuYNnGw3pa0AXgbGKRB8/EceA==", - "dev": true, - "dependencies": { - "available-typed-arrays": "^1.0.5", - "call-bind": "^1.0.2", - "for-each": "^0.3.3", - "gopd": "^1.0.1", - "has-tostringtag": "^1.0.0", - "is-typed-array": "^1.1.10" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/word-wrap": { - "version": "1.2.3", - "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.3.tgz", - "integrity": "sha512-Hz/mrNwitNRh/HUAtM/VT/5VH+ygD6DV7mYKZAtHOrbs8U7lvPS6xf7EJKMF0uW1KJCl0H701g3ZGus+muE5vQ==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/wrap-ansi": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", - "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", - "dev": true, - "dependencies": { - "ansi-styles": "^4.0.0", - "string-width": "^4.1.0", - "strip-ansi": "^6.0.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/wrap-ansi?sponsor=1" - } - }, - "node_modules/wrappy": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", - "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==", - "dev": true - }, - "node_modules/write-file-atomic": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/write-file-atomic/-/write-file-atomic-4.0.2.tgz", - "integrity": "sha512-7KxauUdBmSdWnmpaGFg+ppNjKF8uNLry8LyzjauQDOVONfFLNKrKvQOxZ/VuTIcS/gge/YNahf5RIIQWTSarlg==", - "dev": true, - "dependencies": { - "imurmurhash": "^0.1.4", - "signal-exit": "^3.0.7" - }, - "engines": { - "node": "^12.13.0 || ^14.15.0 || >=16.0.0" - } - }, - "node_modules/y18n": { - "version": "5.0.8", - "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz", - "integrity": "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==", - "dev": true, - "engines": { - "node": ">=10" - } - }, - "node_modules/yallist": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz", - "integrity": "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==", - "dev": true - }, - "node_modules/yargs": { - "version": "17.6.2", - "resolved": "https://registry.npmjs.org/yargs/-/yargs-17.6.2.tgz", - "integrity": "sha512-1/9UrdHjDZc0eOU0HxOHoS78C69UD3JRMvzlJ7S79S2nTaWRA/whGCTV8o9e/N/1Va9YIV7Q4sOxD8VV4pCWOw==", - "dev": true, - "dependencies": { - "cliui": "^8.0.1", - "escalade": "^3.1.1", - "get-caller-file": "^2.0.5", - "require-directory": "^2.1.1", - "string-width": "^4.2.3", - "y18n": "^5.0.5", - "yargs-parser": "^21.1.1" - }, - "engines": { - "node": ">=12" - } - }, - "node_modules/yargs-parser": { - "version": "21.1.1", - "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-21.1.1.tgz", - "integrity": "sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==", - "dev": true, - "engines": { - "node": ">=12" - } - }, - "node_modules/yn": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/yn/-/yn-3.1.1.tgz", - "integrity": "sha512-Ux4ygGWsu2c7isFWe8Yu1YluJmqVhxqK2cLXNQA5AcC3QfbGNpM7fu0Y8b/z16pXLnFxZYvWhd3fhBY9DLmC6Q==", - "dev": true, - "engines": { - "node": ">=6" - } - }, - "node_modules/yocto-queue": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz", - "integrity": "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==", - "dev": true, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - } - }, - "dependencies": { - "@ampproject/remapping": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/@ampproject/remapping/-/remapping-2.2.0.tgz", - "integrity": "sha512-qRmjj8nj9qmLTQXXmaR1cck3UXSRMPrbsLJAasZpF+t3riI71BXed5ebIOYwQntykeZuhjsdweEc9BxH5Jc26w==", - "dev": true, - "requires": { - "@jridgewell/gen-mapping": "^0.1.0", - "@jridgewell/trace-mapping": "^0.3.9" - } - }, - "@aws-cdk/asset-awscli-v1": { - "version": "2.2.49", - "resolved": "https://registry.npmjs.org/@aws-cdk/asset-awscli-v1/-/asset-awscli-v1-2.2.49.tgz", - "integrity": "sha512-Qd5bdLlC/sphWQQPNn7etKXWCh+fij7DWxtkIwvhhZ+LM6UEApGLS8sBLBQcRO2ZQdEuNb+zeClUy+3DNojfeg==" - }, - "@aws-cdk/asset-kubectl-v20": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/@aws-cdk/asset-kubectl-v20/-/asset-kubectl-v20-2.1.1.tgz", - "integrity": "sha512-U1ntiX8XiMRRRH5J1IdC+1t5CE89015cwyt5U63Cpk0GnMlN5+h9WsWMlKlPXZR4rdq/m806JRlBMRpBUB2Dhw==" - }, - "@aws-cdk/asset-node-proxy-agent-v5": { - "version": "2.0.38", - "resolved": "https://registry.npmjs.org/@aws-cdk/asset-node-proxy-agent-v5/-/asset-node-proxy-agent-v5-2.0.38.tgz", - "integrity": "sha512-BBwAjORhuUkTGO3CxGS5Evcp5n20h9v06Sftn2R1DuSm8zIoUlPsNlI1HUk8XqYuoEI4aD7IKRQBLglv09ciJQ==" - }, - "@aws-cdk/cfnspec": { - "version": "2.55.1", - "resolved": "https://registry.npmjs.org/@aws-cdk/cfnspec/-/cfnspec-2.55.1.tgz", - "integrity": "sha512-jJCaEV9pTLFft2eYkwmblfxUBQeJSH4KbMteiVQdp6wkYbzoj/sjyFInfKHgtfIOeqjNtPZ74Dhl5fRJsOpBDw==", - "dev": true, - "requires": { - "fs-extra": "^9.1.0", - "md5": "^2.3.0" - } - }, - "@aws-cdk/cloud-assembly-schema": { - "version": "2.55.1", - "resolved": "https://registry.npmjs.org/@aws-cdk/cloud-assembly-schema/-/cloud-assembly-schema-2.55.1.tgz", - "integrity": "sha512-VVVQaqHP2PsNGRwfPsq1RxoOfyC54DO8RH+2nHqCyPIfSmrIH6Ux5Uk7KAURyXKdb3SjKra66bxPOzvXHOaBXg==", - "dev": true, - "requires": { - "jsonschema": "^1.4.1", - "semver": "^7.3.8" - }, - "dependencies": { - "jsonschema": { - "version": "1.4.1", - "bundled": true, - "dev": true - }, - "lru-cache": { - "version": "6.0.0", - "bundled": true, - "dev": true, - "requires": { - "yallist": "^4.0.0" - } - }, - "semver": { - "version": "7.3.8", - "bundled": true, - "dev": true, - "requires": { - "lru-cache": "^6.0.0" - } - }, - "yallist": { - "version": "4.0.0", - "bundled": true, - "dev": true - } - } - }, - "@aws-cdk/cloudformation-diff": { - "version": "2.55.1", - "resolved": "https://registry.npmjs.org/@aws-cdk/cloudformation-diff/-/cloudformation-diff-2.55.1.tgz", - "integrity": "sha512-WgLubFXoQFGZuOkm7YtJx+kS8EN6rX9K6s257qFR7yNGpKBANSPVvWmlWX2qSvg++AkNSxKsuaZi+4V50TNbdA==", - "dev": true, - "requires": { - "@aws-cdk/cfnspec": "2.55.1", - "@types/node": "^14.18.34", - "chalk": "^4", - "diff": "^5.1.0", - "fast-deep-equal": "^3.1.3", - "string-width": "^4.2.3", - "table": "^6.8.1" - }, - "dependencies": { - "@types/node": { - "version": "14.18.36", - "resolved": "https://registry.npmjs.org/@types/node/-/node-14.18.36.tgz", - "integrity": "sha512-FXKWbsJ6a1hIrRxv+FoukuHnGTgEzKYGi7kilfMae96AL9UNkPFNWJEEYWzdRI9ooIkbr4AKldyuSTLql06vLQ==", - "dev": true - } - } - }, - "@aws-cdk/cx-api": { - "version": "2.55.1", - "resolved": "https://registry.npmjs.org/@aws-cdk/cx-api/-/cx-api-2.55.1.tgz", - "integrity": "sha512-gWQCn/9gaayf2ev0HjCMQleY1gWJZGImLhsUF8kneYnOPCm/r0qpIzy3BxiWiDFLPh9gykDvHQhpH6EG0aXnGA==", - "dev": true, - "requires": { - "@aws-cdk/cloud-assembly-schema": "2.55.1", - "semver": "^7.3.8" - }, - "dependencies": { - "lru-cache": { - "version": "6.0.0", - "bundled": true, - "dev": true, - "requires": { - "yallist": "^4.0.0" - } - }, - "semver": { - "version": "7.3.8", - "bundled": true, - "dev": true, - "requires": { - "lru-cache": "^6.0.0" - } - }, - "yallist": { - "version": "4.0.0", - "bundled": true, - "dev": true - } - } - }, - "@babel/code-frame": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.18.6.tgz", - "integrity": "sha512-TDCmlK5eOvH+eH7cdAFlNXeVJqWIQ7gW9tY1GJIpUtFb6CmjVyq2VM3u71bOyR8CRihcCgMUYoDNyLXao3+70Q==", - "dev": true, - "requires": { - "@babel/highlight": "^7.18.6" - } - }, - "@babel/compat-data": { - "version": "7.20.10", - "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.20.10.tgz", - "integrity": "sha512-sEnuDPpOJR/fcafHMjpcpGN5M2jbUGUHwmuWKM/YdPzeEDJg8bgmbcWQFUfE32MQjti1koACvoPVsDe8Uq+idg==", - "dev": true - }, - "@babel/core": { - "version": "7.20.12", - "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.20.12.tgz", - "integrity": "sha512-XsMfHovsUYHFMdrIHkZphTN/2Hzzi78R08NuHfDBehym2VsPDL6Zn/JAD/JQdnRvbSsbQc4mVaU1m6JgtTEElg==", - "dev": true, - "requires": { - "@ampproject/remapping": "^2.1.0", - "@babel/code-frame": "^7.18.6", - "@babel/generator": "^7.20.7", - "@babel/helper-compilation-targets": "^7.20.7", - "@babel/helper-module-transforms": "^7.20.11", - "@babel/helpers": "^7.20.7", - "@babel/parser": "^7.20.7", - "@babel/template": "^7.20.7", - "@babel/traverse": "^7.20.12", - "@babel/types": "^7.20.7", - "convert-source-map": "^1.7.0", - "debug": "^4.1.0", - "gensync": "^1.0.0-beta.2", - "json5": "^2.2.2", - "semver": "^6.3.0" - }, - "dependencies": { - "convert-source-map": { - "version": "1.9.0", - "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-1.9.0.tgz", - "integrity": "sha512-ASFBup0Mz1uyiIjANan1jzLQami9z1PoYSZCiiYW2FczPbenXc45FZdBZLzOT+r6+iciuEModtmCti+hjaAk0A==", - "dev": true - }, - "semver": { - "version": "6.3.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", - "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", - "dev": true - } - } - }, - "@babel/generator": { - "version": "7.20.7", - "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.20.7.tgz", - "integrity": "sha512-7wqMOJq8doJMZmP4ApXTzLxSr7+oO2jroJURrVEp6XShrQUObV8Tq/D0NCcoYg2uHqUrjzO0zwBjoYzelxK+sw==", - "dev": true, - "requires": { - "@babel/types": "^7.20.7", - "@jridgewell/gen-mapping": "^0.3.2", - "jsesc": "^2.5.1" - }, - "dependencies": { - "@jridgewell/gen-mapping": { - "version": "0.3.2", - "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.2.tgz", - "integrity": "sha512-mh65xKQAzI6iBcFzwv28KVWSmCkdRBWoOh+bYQGW3+6OZvbbN3TqMGo5hqYxQniRcH9F2VZIoJCm4pa3BPDK/A==", - "dev": true, - "requires": { - "@jridgewell/set-array": "^1.0.1", - "@jridgewell/sourcemap-codec": "^1.4.10", - "@jridgewell/trace-mapping": "^0.3.9" - } - } - } - }, - "@babel/helper-compilation-targets": { - "version": "7.20.7", - "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.20.7.tgz", - "integrity": "sha512-4tGORmfQcrc+bvrjb5y3dG9Mx1IOZjsHqQVUz7XCNHO+iTmqxWnVg3KRygjGmpRLJGdQSKuvFinbIb0CnZwHAQ==", - "dev": true, - "requires": { - "@babel/compat-data": "^7.20.5", - "@babel/helper-validator-option": "^7.18.6", - "browserslist": "^4.21.3", - "lru-cache": "^5.1.1", - "semver": "^6.3.0" - }, - "dependencies": { - "semver": { - "version": "6.3.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", - "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", - "dev": true - } - } - }, - "@babel/helper-environment-visitor": { - "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-function-name": { - "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.10", - "@babel/types": "^7.19.0" - } - }, - "@babel/helper-hoist-variables": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/helper-hoist-variables/-/helper-hoist-variables-7.18.6.tgz", - "integrity": "sha512-UlJQPkFqFULIcyW5sbzgbkxn2FKRgwWiRexcuaR8RNJRy8+LLveqPjwZV/bwrLZCN0eUHD/x8D0heK1ozuoo6Q==", - "dev": true, - "requires": { - "@babel/types": "^7.18.6" - } - }, - "@babel/helper-module-imports": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.18.6.tgz", - "integrity": "sha512-0NFvs3VkuSYbFi1x2Vd6tKrywq+z/cLeYC/RJNFrIX/30Bf5aiGYbtvGXolEktzJH8o5E5KJ3tT+nkxuuZFVlA==", - "dev": true, - "requires": { - "@babel/types": "^7.18.6" - } - }, - "@babel/helper-module-transforms": { - "version": "7.20.11", - "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.20.11.tgz", - "integrity": "sha512-uRy78kN4psmji1s2QtbtcCSaj/LILFDp0f/ymhpQH5QY3nljUZCaNWz9X1dEj/8MBdBEFECs7yRhKn8i7NjZgg==", - "dev": true, - "requires": { - "@babel/helper-environment-visitor": "^7.18.9", - "@babel/helper-module-imports": "^7.18.6", - "@babel/helper-simple-access": "^7.20.2", - "@babel/helper-split-export-declaration": "^7.18.6", - "@babel/helper-validator-identifier": "^7.19.1", - "@babel/template": "^7.20.7", - "@babel/traverse": "^7.20.10", - "@babel/types": "^7.20.7" - } - }, - "@babel/helper-plugin-utils": { - "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-simple-access": { - "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.20.2" - } - }, - "@babel/helper-split-export-declaration": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.18.6.tgz", - "integrity": "sha512-bde1etTx6ZyTmobl9LLMMQsaizFVZrquTEHOqKeQESMKo4PlObf+8+JA25ZsIpZhT/WEd39+vOdLXAFG/nELpA==", - "dev": true, - "requires": { - "@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.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": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.18.6.tgz", - "integrity": "sha512-XO7gESt5ouv/LRJdrVjkShckw6STTaB7l9BrpBaAHDeF5YZT+01PCwmR0SJHnkW6i8OwW/EVWRShfi4j2x+KQw==", - "dev": true - }, - "@babel/helpers": { - "version": "7.20.7", - "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.20.7.tgz", - "integrity": "sha512-PBPjs5BppzsGaxHQCDKnZ6Gd9s6xl8bBCluz3vEInLGRJmnZan4F6BYCeqtyXqkk4W5IlPmjK4JlOuZkpJ3xZA==", - "dev": true, - "requires": { - "@babel/template": "^7.20.7", - "@babel/traverse": "^7.20.7", - "@babel/types": "^7.20.7" - } - }, - "@babel/highlight": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.18.6.tgz", - "integrity": "sha512-u7stbOuYjaPezCuLj29hNW1v64M2Md2qupEKP1fHc7WdOA3DgLh37suiSrZYY7haUB7iBeQZ9P1uiRF359do3g==", - "dev": true, - "requires": { - "@babel/helper-validator-identifier": "^7.18.6", - "chalk": "^2.0.0", - "js-tokens": "^4.0.0" - }, - "dependencies": { - "ansi-styles": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", - "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", - "dev": true, - "requires": { - "color-convert": "^1.9.0" - } - }, - "chalk": { - "version": "2.4.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", - "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", - "dev": true, - "requires": { - "ansi-styles": "^3.2.1", - "escape-string-regexp": "^1.0.5", - "supports-color": "^5.3.0" - } - }, - "color-convert": { - "version": "1.9.3", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", - "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", - "dev": true, - "requires": { - "color-name": "1.1.3" - } - }, - "color-name": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", - "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==", - "dev": true - }, - "escape-string-regexp": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", - "integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==", - "dev": true - }, - "has-flag": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", - "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==", - "dev": true - }, - "supports-color": { - "version": "5.5.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", - "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", - "dev": true, - "requires": { - "has-flag": "^3.0.0" - } - } - } - }, - "@babel/parser": { - "version": "7.20.7", - "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.20.7.tgz", - "integrity": "sha512-T3Z9oHybU+0vZlY9CiDSJQTD5ZapcW18ZctFMi0MOAl/4BjFF4ul7NVSARLdbGO5vDqy9eQiGTV0LtKfvCYvcg==", - "dev": true - }, - "@babel/plugin-syntax-async-generators": { - "version": "7.8.4", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-async-generators/-/plugin-syntax-async-generators-7.8.4.tgz", - "integrity": "sha512-tycmZxkGfZaxhMRbXlPXuVFpdWlXpir2W4AMhSJgRKzk/eDlIXOhb2LHWoLpDF7TEHylV5zNhykX6KAgHJmTNw==", - "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.8.0" - } - }, - "@babel/plugin-syntax-bigint": { - "version": "7.8.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-bigint/-/plugin-syntax-bigint-7.8.3.tgz", - "integrity": "sha512-wnTnFlG+YxQm3vDxpGE57Pj0srRU4sHE/mDkt1qv2YJJSeUAec2ma4WLUnUPeKjyrfntVwe/N6dCXpU+zL3Npg==", - "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.8.0" - } - }, - "@babel/plugin-syntax-class-properties": { - "version": "7.12.13", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-class-properties/-/plugin-syntax-class-properties-7.12.13.tgz", - "integrity": "sha512-fm4idjKla0YahUNgFNLCB0qySdsoPiZP3iQE3rky0mBUtMZ23yDJ9SJdg6dXTSDnulOVqiF3Hgr9nbXvXTQZYA==", - "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.12.13" - } - }, - "@babel/plugin-syntax-import-meta": { - "version": "7.10.4", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-import-meta/-/plugin-syntax-import-meta-7.10.4.tgz", - "integrity": "sha512-Yqfm+XDx0+Prh3VSeEQCPU81yC+JWZ2pDPFSS4ZdpfZhp4MkFMaDC1UqseovEKwSUpnIL7+vK+Clp7bfh0iD7g==", - "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.10.4" - } - }, - "@babel/plugin-syntax-json-strings": { - "version": "7.8.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-json-strings/-/plugin-syntax-json-strings-7.8.3.tgz", - "integrity": "sha512-lY6kdGpWHvjoe2vk4WrAapEuBR69EMxZl+RoGRhrFGNYVK8mOPAW8VfbT/ZgrFbXlDNiiaxQnAtgVCZ6jv30EA==", - "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.8.0" - } - }, - "@babel/plugin-syntax-jsx": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-jsx/-/plugin-syntax-jsx-7.18.6.tgz", - "integrity": "sha512-6mmljtAedFGTWu2p/8WIORGwy+61PLgOMPOdazc7YoJ9ZCWUyFy3A6CpPkRKLKD1ToAesxX8KGEViAiLo9N+7Q==", - "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.18.6" - } - }, - "@babel/plugin-syntax-logical-assignment-operators": { - "version": "7.10.4", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-logical-assignment-operators/-/plugin-syntax-logical-assignment-operators-7.10.4.tgz", - "integrity": "sha512-d8waShlpFDinQ5MtvGU9xDAOzKH47+FFoney2baFIoMr952hKOLp1HR7VszoZvOsV/4+RRszNY7D17ba0te0ig==", - "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.10.4" - } - }, - "@babel/plugin-syntax-nullish-coalescing-operator": { - "version": "7.8.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-nullish-coalescing-operator/-/plugin-syntax-nullish-coalescing-operator-7.8.3.tgz", - "integrity": "sha512-aSff4zPII1u2QD7y+F8oDsz19ew4IGEJg9SVW+bqwpwtfFleiQDMdzA/R+UlWDzfnHFCxxleFT0PMIrR36XLNQ==", - "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.8.0" - } - }, - "@babel/plugin-syntax-numeric-separator": { - "version": "7.10.4", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-numeric-separator/-/plugin-syntax-numeric-separator-7.10.4.tgz", - "integrity": "sha512-9H6YdfkcK/uOnY/K7/aA2xpzaAgkQn37yzWUMRK7OaPOqOpGS1+n0H5hxT9AUw9EsSjPW8SVyMJwYRtWs3X3ug==", - "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.10.4" - } - }, - "@babel/plugin-syntax-object-rest-spread": { - "version": "7.8.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-object-rest-spread/-/plugin-syntax-object-rest-spread-7.8.3.tgz", - "integrity": "sha512-XoqMijGZb9y3y2XskN+P1wUGiVwWZ5JmoDRwx5+3GmEplNyVM2s2Dg8ILFQm8rWM48orGy5YpI5Bl8U1y7ydlA==", - "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.8.0" - } - }, - "@babel/plugin-syntax-optional-catch-binding": { - "version": "7.8.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-optional-catch-binding/-/plugin-syntax-optional-catch-binding-7.8.3.tgz", - "integrity": "sha512-6VPD0Pc1lpTqw0aKoeRTMiB+kWhAoT24PA+ksWSBrFtl5SIRVpZlwN3NNPQjehA2E/91FV3RjLWoVTglWcSV3Q==", - "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.8.0" - } - }, - "@babel/plugin-syntax-optional-chaining": { - "version": "7.8.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-optional-chaining/-/plugin-syntax-optional-chaining-7.8.3.tgz", - "integrity": "sha512-KoK9ErH1MBlCPxV0VANkXW2/dw4vlbGDrFgz8bmUsBGYkFRcbRwMh6cIJubdPrkxRwuGdtCk0v/wPTKbQgBjkg==", - "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.8.0" - } - }, - "@babel/plugin-syntax-top-level-await": { - "version": "7.14.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-top-level-await/-/plugin-syntax-top-level-await-7.14.5.tgz", - "integrity": "sha512-hx++upLv5U1rgYfwe1xBQUhRmU41NEvpUvrp8jkrSCdvGSnM5/qdRMtylJ6PG5OFkBaHkbTAKTnd3/YyESRHFw==", - "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.14.5" - } - }, - "@babel/plugin-syntax-typescript": { - "version": "7.20.0", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-typescript/-/plugin-syntax-typescript-7.20.0.tgz", - "integrity": "sha512-rd9TkG+u1CExzS4SM1BlMEhMXwFLKVjOAFFCDx9PbX5ycJWDoWMcwdJH9RhkPu1dOgn5TrxLot/Gx6lWFuAUNQ==", - "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.19.0" - } - }, - "@babel/template": { - "version": "7.20.7", - "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.20.7.tgz", - "integrity": "sha512-8SegXApWe6VoNw0r9JHpSteLKTpTiLZ4rMlGIm9JQ18KiCtyQiAMEazujAHrUS5flrcqYZa75ukev3P6QmUwUw==", - "dev": true, - "requires": { - "@babel/code-frame": "^7.18.6", - "@babel/parser": "^7.20.7", - "@babel/types": "^7.20.7" - } - }, - "@babel/traverse": { - "version": "7.20.12", - "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.20.12.tgz", - "integrity": "sha512-MsIbFN0u+raeja38qboyF8TIT7K0BFzz/Yd/77ta4MsUsmP2RAnidIlwq7d5HFQrH/OZJecGV6B71C4zAgpoSQ==", - "dev": true, - "requires": { - "@babel/code-frame": "^7.18.6", - "@babel/generator": "^7.20.7", - "@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.20.7", - "@babel/types": "^7.20.7", - "debug": "^4.1.0", - "globals": "^11.1.0" - }, - "dependencies": { - "globals": { - "version": "11.12.0", - "resolved": "https://registry.npmjs.org/globals/-/globals-11.12.0.tgz", - "integrity": "sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==", - "dev": true - } - } - }, - "@babel/types": { - "version": "7.20.7", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.20.7.tgz", - "integrity": "sha512-69OnhBxSSgK0OzTJai4kyPDiKTIe3j+ctaHdIGVbRahTLAT7L3R9oeXHC2aVSuGYt3cVnoAMDmOCgJ2yaiLMvg==", - "dev": true, - "requires": { - "@babel/helper-string-parser": "^7.19.4", - "@babel/helper-validator-identifier": "^7.19.1", - "to-fast-properties": "^2.0.0" - } - }, - "@bcoe/v8-coverage": { - "version": "0.2.3", - "resolved": "https://registry.npmjs.org/@bcoe/v8-coverage/-/v8-coverage-0.2.3.tgz", - "integrity": "sha512-0hYQ8SB4Db5zvZB4axdMHGwEaQjkZzFjQiN9LVYvIFB2nSUHW9tYpxWriPrWDASIxiaXax83REcLxuSdnGPZtw==", - "dev": true - }, - "@cspotcode/source-map-support": { - "version": "0.8.1", - "resolved": "https://registry.npmjs.org/@cspotcode/source-map-support/-/source-map-support-0.8.1.tgz", - "integrity": "sha512-IchNf6dN4tHoMFIn/7OE8LWZ19Y6q/67Bmf6vnGREv8RSbBVb9LPJxEcnwrcwX6ixSvaiGoomAUvu4YSxXrVgw==", - "dev": true, - "requires": { - "@jridgewell/trace-mapping": "0.3.9" - }, - "dependencies": { - "@jridgewell/trace-mapping": { - "version": "0.3.9", - "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.9.tgz", - "integrity": "sha512-3Belt6tdc8bPgAtbcmdtNJlirVoTmEb5e2gC94PnkwEW9jI6CAHUeoG85tjWP5WquqfavoMtMwiG4P926ZKKuQ==", - "dev": true, - "requires": { - "@jridgewell/resolve-uri": "^3.0.3", - "@jridgewell/sourcemap-codec": "^1.4.10" - } - } - } - }, - "@eslint/eslintrc": { - "version": "1.4.1", - "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-1.4.1.tgz", - "integrity": "sha512-XXrH9Uarn0stsyldqDYq8r++mROmWRI1xKMXa640Bb//SY1+ECYX6VzT6Lcx5frD0V30XieqJ0oX9I2Xj5aoMA==", - "dev": true, - "requires": { - "ajv": "^6.12.4", - "debug": "^4.3.2", - "espree": "^9.4.0", - "globals": "^13.19.0", - "ignore": "^5.2.0", - "import-fresh": "^3.2.1", - "js-yaml": "^4.1.0", - "minimatch": "^3.1.2", - "strip-json-comments": "^3.1.1" - } - }, - "@humanwhocodes/config-array": { - "version": "0.11.8", - "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.11.8.tgz", - "integrity": "sha512-UybHIJzJnR5Qc/MsD9Kr+RpO2h+/P1GhOwdiLPXK5TWk5sgTdu88bTD9UP+CKbPPh5Rni1u0GjAdYQLemG8g+g==", - "dev": true, - "requires": { - "@humanwhocodes/object-schema": "^1.2.1", - "debug": "^4.1.1", - "minimatch": "^3.0.5" - } - }, - "@humanwhocodes/module-importer": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/@humanwhocodes/module-importer/-/module-importer-1.0.1.tgz", - "integrity": "sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA==", - "dev": true - }, - "@humanwhocodes/object-schema": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/@humanwhocodes/object-schema/-/object-schema-1.2.1.tgz", - "integrity": "sha512-ZnQMnLV4e7hDlUvw8H+U8ASL02SS2Gn6+9Ac3wGGLIe7+je2AeAOxPY+izIPJDfFDb7eDjev0Us8MO1iFRN8hA==", - "dev": true - }, - "@istanbuljs/load-nyc-config": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/@istanbuljs/load-nyc-config/-/load-nyc-config-1.1.0.tgz", - "integrity": "sha512-VjeHSlIzpv/NyD3N0YuHfXOPDIixcA1q2ZV98wsMqcYlPmv2n3Yb2lYP9XMElnaFVXg5A7YLTeLu6V84uQDjmQ==", - "dev": true, - "requires": { - "camelcase": "^5.3.1", - "find-up": "^4.1.0", - "get-package-type": "^0.1.0", - "js-yaml": "^3.13.1", - "resolve-from": "^5.0.0" - }, - "dependencies": { - "argparse": { - "version": "1.0.10", - "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz", - "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==", - "dev": true, - "requires": { - "sprintf-js": "~1.0.2" - } - }, - "find-up": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz", - "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==", - "dev": true, - "requires": { - "locate-path": "^5.0.0", - "path-exists": "^4.0.0" - } - }, - "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" - } - }, - "locate-path": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz", - "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==", - "dev": true, - "requires": { - "p-locate": "^4.1.0" - } - }, - "p-limit": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz", - "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==", - "dev": true, - "requires": { - "p-try": "^2.0.0" - } - }, - "p-locate": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz", - "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==", - "dev": true, - "requires": { - "p-limit": "^2.2.0" - } - }, - "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 - } - } - }, - "@istanbuljs/schema": { - "version": "0.1.3", - "resolved": "https://registry.npmjs.org/@istanbuljs/schema/-/schema-0.1.3.tgz", - "integrity": "sha512-ZXRY4jNvVgSVQ8DL3LTcakaAtXwTVUxE81hslsyD2AtoXW/wVob10HkOJ1X/pAlcI7D+2YoZKg5do8G/w6RYgA==", - "dev": true - }, - "@jest/console": { - "version": "29.3.1", - "resolved": "https://registry.npmjs.org/@jest/console/-/console-29.3.1.tgz", - "integrity": "sha512-IRE6GD47KwcqA09RIWrabKdHPiKDGgtAL31xDxbi/RjQMsr+lY+ppxmHwY0dUEV3qvvxZzoe5Hl0RXZJOjQNUg==", - "dev": true, - "requires": { - "@jest/types": "^29.3.1", - "@types/node": "*", - "chalk": "^4.0.0", - "jest-message-util": "^29.3.1", - "jest-util": "^29.3.1", - "slash": "^3.0.0" - } - }, - "@jest/core": { - "version": "29.3.1", - "resolved": "https://registry.npmjs.org/@jest/core/-/core-29.3.1.tgz", - "integrity": "sha512-0ohVjjRex985w5MmO5L3u5GR1O30DexhBSpuwx2P+9ftyqHdJXnk7IUWiP80oHMvt7ubHCJHxV0a0vlKVuZirw==", - "dev": true, - "requires": { - "@jest/console": "^29.3.1", - "@jest/reporters": "^29.3.1", - "@jest/test-result": "^29.3.1", - "@jest/transform": "^29.3.1", - "@jest/types": "^29.3.1", - "@types/node": "*", - "ansi-escapes": "^4.2.1", - "chalk": "^4.0.0", - "ci-info": "^3.2.0", - "exit": "^0.1.2", - "graceful-fs": "^4.2.9", - "jest-changed-files": "^29.2.0", - "jest-config": "^29.3.1", - "jest-haste-map": "^29.3.1", - "jest-message-util": "^29.3.1", - "jest-regex-util": "^29.2.0", - "jest-resolve": "^29.3.1", - "jest-resolve-dependencies": "^29.3.1", - "jest-runner": "^29.3.1", - "jest-runtime": "^29.3.1", - "jest-snapshot": "^29.3.1", - "jest-util": "^29.3.1", - "jest-validate": "^29.3.1", - "jest-watcher": "^29.3.1", - "micromatch": "^4.0.4", - "pretty-format": "^29.3.1", - "slash": "^3.0.0", - "strip-ansi": "^6.0.0" - } - }, - "@jest/environment": { - "version": "29.3.1", - "resolved": "https://registry.npmjs.org/@jest/environment/-/environment-29.3.1.tgz", - "integrity": "sha512-pMmvfOPmoa1c1QpfFW0nXYtNLpofqo4BrCIk6f2kW4JFeNlHV2t3vd+3iDLf31e2ot2Mec0uqZfmI+U0K2CFag==", - "dev": true, - "requires": { - "@jest/fake-timers": "^29.3.1", - "@jest/types": "^29.3.1", - "@types/node": "*", - "jest-mock": "^29.3.1" - } - }, - "@jest/expect": { - "version": "29.3.1", - "resolved": "https://registry.npmjs.org/@jest/expect/-/expect-29.3.1.tgz", - "integrity": "sha512-QivM7GlSHSsIAWzgfyP8dgeExPRZ9BIe2LsdPyEhCGkZkoyA+kGsoIzbKAfZCvvRzfZioKwPtCZIt5SaoxYCvg==", - "dev": true, - "requires": { - "expect": "^29.3.1", - "jest-snapshot": "^29.3.1" - } - }, - "@jest/expect-utils": { - "version": "29.3.1", - "resolved": "https://registry.npmjs.org/@jest/expect-utils/-/expect-utils-29.3.1.tgz", - "integrity": "sha512-wlrznINZI5sMjwvUoLVk617ll/UYfGIZNxmbU+Pa7wmkL4vYzhV9R2pwVqUh4NWWuLQWkI8+8mOkxs//prKQ3g==", - "dev": true, - "requires": { - "jest-get-type": "^29.2.0" - } - }, - "@jest/fake-timers": { - "version": "29.3.1", - "resolved": "https://registry.npmjs.org/@jest/fake-timers/-/fake-timers-29.3.1.tgz", - "integrity": "sha512-iHTL/XpnDlFki9Tq0Q1GGuVeQ8BHZGIYsvCO5eN/O/oJaRzofG9Xndd9HuSDBI/0ZS79pg0iwn07OMTQ7ngF2A==", - "dev": true, - "requires": { - "@jest/types": "^29.3.1", - "@sinonjs/fake-timers": "^9.1.2", - "@types/node": "*", - "jest-message-util": "^29.3.1", - "jest-mock": "^29.3.1", - "jest-util": "^29.3.1" - } - }, - "@jest/globals": { - "version": "29.3.1", - "resolved": "https://registry.npmjs.org/@jest/globals/-/globals-29.3.1.tgz", - "integrity": "sha512-cTicd134vOcwO59OPaB6AmdHQMCtWOe+/DitpTZVxWgMJ+YvXL1HNAmPyiGbSHmF/mXVBkvlm8YYtQhyHPnV6Q==", - "dev": true, - "requires": { - "@jest/environment": "^29.3.1", - "@jest/expect": "^29.3.1", - "@jest/types": "^29.3.1", - "jest-mock": "^29.3.1" - } - }, - "@jest/reporters": { - "version": "29.3.1", - "resolved": "https://registry.npmjs.org/@jest/reporters/-/reporters-29.3.1.tgz", - "integrity": "sha512-GhBu3YFuDrcAYW/UESz1JphEAbvUjaY2vShRZRoRY1mxpCMB3yGSJ4j9n0GxVlEOdCf7qjvUfBCrTUUqhVfbRA==", - "dev": true, - "requires": { - "@bcoe/v8-coverage": "^0.2.3", - "@jest/console": "^29.3.1", - "@jest/test-result": "^29.3.1", - "@jest/transform": "^29.3.1", - "@jest/types": "^29.3.1", - "@jridgewell/trace-mapping": "^0.3.15", - "@types/node": "*", - "chalk": "^4.0.0", - "collect-v8-coverage": "^1.0.0", - "exit": "^0.1.2", - "glob": "^7.1.3", - "graceful-fs": "^4.2.9", - "istanbul-lib-coverage": "^3.0.0", - "istanbul-lib-instrument": "^5.1.0", - "istanbul-lib-report": "^3.0.0", - "istanbul-lib-source-maps": "^4.0.0", - "istanbul-reports": "^3.1.3", - "jest-message-util": "^29.3.1", - "jest-util": "^29.3.1", - "jest-worker": "^29.3.1", - "slash": "^3.0.0", - "string-length": "^4.0.1", - "strip-ansi": "^6.0.0", - "v8-to-istanbul": "^9.0.1" - } - }, - "@jest/schemas": { - "version": "29.0.0", - "resolved": "https://registry.npmjs.org/@jest/schemas/-/schemas-29.0.0.tgz", - "integrity": "sha512-3Ab5HgYIIAnS0HjqJHQYZS+zXc4tUmTmBH3z83ajI6afXp8X3ZtdLX+nXx+I7LNkJD7uN9LAVhgnjDgZa2z0kA==", - "dev": true, - "requires": { - "@sinclair/typebox": "^0.24.1" - } - }, - "@jest/source-map": { - "version": "29.2.0", - "resolved": "https://registry.npmjs.org/@jest/source-map/-/source-map-29.2.0.tgz", - "integrity": "sha512-1NX9/7zzI0nqa6+kgpSdKPK+WU1p+SJk3TloWZf5MzPbxri9UEeXX5bWZAPCzbQcyuAzubcdUHA7hcNznmRqWQ==", - "dev": true, - "requires": { - "@jridgewell/trace-mapping": "^0.3.15", - "callsites": "^3.0.0", - "graceful-fs": "^4.2.9" - } - }, - "@jest/test-result": { - "version": "29.3.1", - "resolved": "https://registry.npmjs.org/@jest/test-result/-/test-result-29.3.1.tgz", - "integrity": "sha512-qeLa6qc0ddB0kuOZyZIhfN5q0e2htngokyTWsGriedsDhItisW7SDYZ7ceOe57Ii03sL988/03wAcBh3TChMGw==", - "dev": true, - "requires": { - "@jest/console": "^29.3.1", - "@jest/types": "^29.3.1", - "@types/istanbul-lib-coverage": "^2.0.0", - "collect-v8-coverage": "^1.0.0" - } - }, - "@jest/test-sequencer": { - "version": "29.3.1", - "resolved": "https://registry.npmjs.org/@jest/test-sequencer/-/test-sequencer-29.3.1.tgz", - "integrity": "sha512-IqYvLbieTv20ArgKoAMyhLHNrVHJfzO6ARZAbQRlY4UGWfdDnLlZEF0BvKOMd77uIiIjSZRwq3Jb3Fa3I8+2UA==", - "dev": true, - "requires": { - "@jest/test-result": "^29.3.1", - "graceful-fs": "^4.2.9", - "jest-haste-map": "^29.3.1", - "slash": "^3.0.0" - } - }, - "@jest/transform": { - "version": "29.3.1", - "resolved": "https://registry.npmjs.org/@jest/transform/-/transform-29.3.1.tgz", - "integrity": "sha512-8wmCFBTVGYqFNLWfcOWoVuMuKYPUBTnTMDkdvFtAYELwDOl9RGwOsvQWGPFxDJ8AWY9xM/8xCXdqmPK3+Q5Lug==", - "dev": true, - "requires": { - "@babel/core": "^7.11.6", - "@jest/types": "^29.3.1", - "@jridgewell/trace-mapping": "^0.3.15", - "babel-plugin-istanbul": "^6.1.1", - "chalk": "^4.0.0", - "convert-source-map": "^2.0.0", - "fast-json-stable-stringify": "^2.1.0", - "graceful-fs": "^4.2.9", - "jest-haste-map": "^29.3.1", - "jest-regex-util": "^29.2.0", - "jest-util": "^29.3.1", - "micromatch": "^4.0.4", - "pirates": "^4.0.4", - "slash": "^3.0.0", - "write-file-atomic": "^4.0.1" - } - }, - "@jest/types": { - "version": "29.3.1", - "resolved": "https://registry.npmjs.org/@jest/types/-/types-29.3.1.tgz", - "integrity": "sha512-d0S0jmmTpjnhCmNpApgX3jrUZgZ22ivKJRvL2lli5hpCRoNnp1f85r2/wpKfXuYu8E7Jjh1hGfhPyup1NM5AmA==", - "dev": true, - "requires": { - "@jest/schemas": "^29.0.0", - "@types/istanbul-lib-coverage": "^2.0.0", - "@types/istanbul-reports": "^3.0.0", - "@types/node": "*", - "@types/yargs": "^17.0.8", - "chalk": "^4.0.0" - } - }, - "@jridgewell/gen-mapping": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.1.1.tgz", - "integrity": "sha512-sQXCasFk+U8lWYEe66WxRDOE9PjVz4vSM51fTu3Hw+ClTpUSQb718772vH3pyS5pShp6lvQM7SxgIDXXXmOX7w==", - "dev": true, - "requires": { - "@jridgewell/set-array": "^1.0.0", - "@jridgewell/sourcemap-codec": "^1.4.10" - } - }, - "@jridgewell/resolve-uri": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.0.tgz", - "integrity": "sha512-F2msla3tad+Mfht5cJq7LSXcdudKTWCVYUgw6pLFOOHSTtZlj6SWNYAp+AhuqLmWdBO2X5hPrLcu8cVP8fy28w==", - "dev": true - }, - "@jridgewell/set-array": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/@jridgewell/set-array/-/set-array-1.1.2.tgz", - "integrity": "sha512-xnkseuNADM0gt2bs+BvhO0p78Mk762YnZdsuzFV018NoG1Sj1SCQvpSqa7XUaTam5vAGasABV9qXASMKnFMwMw==", - "dev": true - }, - "@jridgewell/sourcemap-codec": { - "version": "1.4.14", - "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.14.tgz", - "integrity": "sha512-XPSJHWmi394fuUuzDnGz1wiKqWfo1yXecHQMRf2l6hztTO+nPru658AyDngaBe7isIxEkRsPR3FZh+s7iVa4Uw==", - "dev": true - }, - "@jridgewell/trace-mapping": { - "version": "0.3.17", - "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.17.tgz", - "integrity": "sha512-MCNzAp77qzKca9+W/+I0+sEpaUnZoeasnghNeVc41VZCEKaCH73Vq3BZZ/SzWIgrqE4H4ceI+p+b6C0mHf9T4g==", - "dev": true, - "requires": { - "@jridgewell/resolve-uri": "3.1.0", - "@jridgewell/sourcemap-codec": "1.4.14" - } - }, - "@nodelib/fs.scandir": { - "version": "2.1.5", - "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", - "integrity": "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==", - "dev": true, - "requires": { - "@nodelib/fs.stat": "2.0.5", - "run-parallel": "^1.1.9" - } - }, - "@nodelib/fs.stat": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz", - "integrity": "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==", - "dev": true - }, - "@nodelib/fs.walk": { - "version": "1.2.8", - "resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz", - "integrity": "sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==", - "dev": true, - "requires": { - "@nodelib/fs.scandir": "2.1.5", - "fastq": "^1.6.0" - } - }, - "@pkgr/utils": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/@pkgr/utils/-/utils-2.3.1.tgz", - "integrity": "sha512-wfzX8kc1PMyUILA+1Z/EqoE4UCXGy0iRGMhPwdfae1+f0OXlLqCk+By+aMzgJBzR9AzS4CDizioG6Ss1gvAFJw==", - "dev": true, - "requires": { - "cross-spawn": "^7.0.3", - "is-glob": "^4.0.3", - "open": "^8.4.0", - "picocolors": "^1.0.0", - "tiny-glob": "^0.2.9", - "tslib": "^2.4.0" - } - }, - "@sinclair/typebox": { - "version": "0.24.51", - "resolved": "https://registry.npmjs.org/@sinclair/typebox/-/typebox-0.24.51.tgz", - "integrity": "sha512-1P1OROm/rdubP5aFDSZQILU0vrLCJ4fvHt6EoqHEM+2D/G5MK3bIaymUKLit8Js9gbns5UyJnkP/TZROLw4tUA==", - "dev": true - }, - "@sinonjs/commons": { - "version": "1.8.6", - "resolved": "https://registry.npmjs.org/@sinonjs/commons/-/commons-1.8.6.tgz", - "integrity": "sha512-Ky+XkAkqPZSm3NLBeUng77EBQl3cmeJhITaGHdYH8kjVB+aun3S4XBRti2zt17mtt0mIUDiNxYeoJm6drVvBJQ==", - "dev": true, - "requires": { - "type-detect": "4.0.8" - } - }, - "@sinonjs/fake-timers": { - "version": "9.1.2", - "resolved": "https://registry.npmjs.org/@sinonjs/fake-timers/-/fake-timers-9.1.2.tgz", - "integrity": "sha512-BPS4ynJW/o92PUR4wgriz2Ud5gpST5vz6GQfMixEDK0Z8ZCUv2M7SkBLykH56T++Xs+8ln9zTGbOvNGIe02/jw==", - "dev": true, - "requires": { - "@sinonjs/commons": "^1.7.0" - } - }, - "@tsconfig/node10": { - "version": "1.0.9", - "resolved": "https://registry.npmjs.org/@tsconfig/node10/-/node10-1.0.9.tgz", - "integrity": "sha512-jNsYVVxU8v5g43Erja32laIDHXeoNvFEpX33OK4d6hljo3jDhCBDhx5dhCCTMWUojscpAagGiRkBKxpdl9fxqA==", - "dev": true - }, - "@tsconfig/node12": { - "version": "1.0.11", - "resolved": "https://registry.npmjs.org/@tsconfig/node12/-/node12-1.0.11.tgz", - "integrity": "sha512-cqefuRsh12pWyGsIoBKJA9luFu3mRxCA+ORZvA4ktLSzIuCUtWVxGIuXigEwO5/ywWFMZ2QEGKWvkZG1zDMTag==", - "dev": true - }, - "@tsconfig/node14": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/@tsconfig/node14/-/node14-1.0.3.tgz", - "integrity": "sha512-ysT8mhdixWK6Hw3i1V2AeRqZ5WfXg1G43mqoYlM2nc6388Fq5jcXyr5mRsqViLx/GJYdoL0bfXD8nmF+Zn/Iow==", - "dev": true - }, - "@tsconfig/node16": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/@tsconfig/node16/-/node16-1.0.3.tgz", - "integrity": "sha512-yOlFc+7UtL/89t2ZhjPvvB/DeAr3r+Dq58IgzsFkOAvVC6NMJXmCGjbptdXdR9qsX7pKcTL+s87FtYREi2dEEQ==", - "dev": true - }, - "@types/babel__core": { - "version": "7.1.20", - "resolved": "https://registry.npmjs.org/@types/babel__core/-/babel__core-7.1.20.tgz", - "integrity": "sha512-PVb6Bg2QuscZ30FvOU7z4guG6c926D9YRvOxEaelzndpMsvP+YM74Q/dAFASpg2l6+XLalxSGxcq/lrgYWZtyQ==", - "dev": true, - "requires": { - "@babel/parser": "^7.1.0", - "@babel/types": "^7.0.0", - "@types/babel__generator": "*", - "@types/babel__template": "*", - "@types/babel__traverse": "*" - } - }, - "@types/babel__generator": { - "version": "7.6.4", - "resolved": "https://registry.npmjs.org/@types/babel__generator/-/babel__generator-7.6.4.tgz", - "integrity": "sha512-tFkciB9j2K755yrTALxD44McOrk+gfpIpvC3sxHjRawj6PfnQxrse4Clq5y/Rq+G3mrBurMax/lG8Qn2t9mSsg==", - "dev": true, - "requires": { - "@babel/types": "^7.0.0" - } - }, - "@types/babel__template": { - "version": "7.4.1", - "resolved": "https://registry.npmjs.org/@types/babel__template/-/babel__template-7.4.1.tgz", - "integrity": "sha512-azBFKemX6kMg5Io+/rdGT0dkGreboUVR0Cdm3fz9QJWpaQGJRQXl7C+6hOTCZcMll7KFyEQpgbYI2lHdsS4U7g==", - "dev": true, - "requires": { - "@babel/parser": "^7.1.0", - "@babel/types": "^7.0.0" - } - }, - "@types/babel__traverse": { - "version": "7.18.3", - "resolved": "https://registry.npmjs.org/@types/babel__traverse/-/babel__traverse-7.18.3.tgz", - "integrity": "sha512-1kbcJ40lLB7MHsj39U4Sh1uTd2E7rLEa79kmDpI6cy+XiXsteB3POdQomoq4FxszMrO3ZYchkhYJw7A2862b3w==", - "dev": true, - "requires": { - "@babel/types": "^7.3.0" - } - }, - "@types/graceful-fs": { - "version": "4.1.6", - "resolved": "https://registry.npmjs.org/@types/graceful-fs/-/graceful-fs-4.1.6.tgz", - "integrity": "sha512-Sig0SNORX9fdW+bQuTEovKj3uHcUL6LQKbCrrqb1X7J6/ReAbhCXRAhc+SMejhLELFj2QcyuxmUooZ4bt5ReSw==", - "dev": true, - "requires": { - "@types/node": "*" - } - }, - "@types/istanbul-lib-coverage": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/@types/istanbul-lib-coverage/-/istanbul-lib-coverage-2.0.4.tgz", - "integrity": "sha512-z/QT1XN4K4KYuslS23k62yDIDLwLFkzxOuMplDtObz0+y7VqJCaO2o+SPwHCvLFZh7xazvvoor2tA/hPz9ee7g==", - "dev": true - }, - "@types/istanbul-lib-report": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/@types/istanbul-lib-report/-/istanbul-lib-report-3.0.0.tgz", - "integrity": "sha512-plGgXAPfVKFoYfa9NpYDAkseG+g6Jr294RqeqcqDixSbU34MZVJRi/P+7Y8GDpzkEwLaGZZOpKIEmeVZNtKsrg==", - "dev": true, - "requires": { - "@types/istanbul-lib-coverage": "*" - } - }, - "@types/istanbul-reports": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/@types/istanbul-reports/-/istanbul-reports-3.0.1.tgz", - "integrity": "sha512-c3mAZEuK0lvBp8tmuL74XRKn1+y2dcwOUpH7x4WrF6gk1GIgiluDRgMYQtw2OFcBvAJWlt6ASU3tSqxp0Uu0Aw==", - "dev": true, - "requires": { - "@types/istanbul-lib-report": "*" - } - }, - "@types/jest": { - "version": "29.2.5", - "resolved": "https://registry.npmjs.org/@types/jest/-/jest-29.2.5.tgz", - "integrity": "sha512-H2cSxkKgVmqNHXP7TC2L/WUorrZu8ZigyRywfVzv6EyBlxj39n4C00hjXYQWsbwqgElaj/CiAeSRmk5GoaKTgw==", - "dev": true, - "requires": { - "expect": "^29.0.0", - "pretty-format": "^29.0.0" - } - }, - "@types/json-schema": { - "version": "7.0.11", - "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.11.tgz", - "integrity": "sha512-wOuvG1SN4Us4rez+tylwwwCV1psiNVOkJeM3AUWUNWg/jDQY2+HE/444y5gc+jBmRqASOm2Oeh5c1axHobwRKQ==", - "dev": true - }, - "@types/json5": { - "version": "0.0.29", - "resolved": "https://registry.npmjs.org/@types/json5/-/json5-0.0.29.tgz", - "integrity": "sha512-dRLjCWHYg4oaA77cxO64oO+7JwCwnIzkZPdrrC71jQmQtlhM556pwKo5bUzqvZndkVbeFLIIi+9TC40JNF5hNQ==", - "dev": true - }, - "@types/node": { - "version": "18.11.15", - "resolved": "https://registry.npmjs.org/@types/node/-/node-18.11.15.tgz", - "integrity": "sha512-VkhBbVo2+2oozlkdHXLrb3zjsRkpdnaU2bXmX8Wgle3PUi569eLRaHGlgETQHR7lLL1w7GiG3h9SnePhxNDecw==", - "dev": true - }, - "@types/prettier": { - "version": "2.7.2", - "resolved": "https://registry.npmjs.org/@types/prettier/-/prettier-2.7.2.tgz", - "integrity": "sha512-KufADq8uQqo1pYKVIYzfKbJfBAc0sOeXqGbFaSpv8MRmC/zXgowNZmFcbngndGk922QDmOASEXUZCaY48gs4cg==", - "dev": true - }, - "@types/semver": { - "version": "7.3.13", - "resolved": "https://registry.npmjs.org/@types/semver/-/semver-7.3.13.tgz", - "integrity": "sha512-21cFJr9z3g5dW8B0CVI9g2O9beqaThGQ6ZFBqHfwhzLDKUxaqTIy3vnfah/UPkfOiF2pLq+tGz+W8RyCskuslw==", - "dev": true - }, - "@types/stack-utils": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/@types/stack-utils/-/stack-utils-2.0.1.tgz", - "integrity": "sha512-Hl219/BT5fLAaz6NDkSuhzasy49dwQS/DSdu4MdggFB8zcXv7vflBI3xp7FEmkmdDkBUI2bPUNeMttp2knYdxw==", - "dev": true - }, - "@types/yargs": { - "version": "17.0.19", - "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-17.0.19.tgz", - "integrity": "sha512-cAx3qamwaYX9R0fzOIZAlFpo4A+1uBVCxqpKz9D26uTF4srRXaGTTsikQmaotCtNdbhzyUH7ft6p9ktz9s6UNQ==", - "dev": true, - "requires": { - "@types/yargs-parser": "*" - } - }, - "@types/yargs-parser": { - "version": "21.0.0", - "resolved": "https://registry.npmjs.org/@types/yargs-parser/-/yargs-parser-21.0.0.tgz", - "integrity": "sha512-iO9ZQHkZxHn4mSakYV0vFHAVDyEOIJQrV2uZ06HxEPcx+mt8swXoZHIbaaJ2crJYFfErySgktuTZ3BeLz+XmFA==", - "dev": true - }, - "@typescript-eslint/eslint-plugin": { - "version": "5.48.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-5.48.1.tgz", - "integrity": "sha512-9nY5K1Rp2ppmpb9s9S2aBiF3xo5uExCehMDmYmmFqqyxgenbHJ3qbarcLt4ITgaD6r/2ypdlcFRdcuVPnks+fQ==", - "dev": true, - "requires": { - "@typescript-eslint/scope-manager": "5.48.1", - "@typescript-eslint/type-utils": "5.48.1", - "@typescript-eslint/utils": "5.48.1", - "debug": "^4.3.4", - "ignore": "^5.2.0", - "natural-compare-lite": "^1.4.0", - "regexpp": "^3.2.0", - "semver": "^7.3.7", - "tsutils": "^3.21.0" - } - }, - "@typescript-eslint/parser": { - "version": "5.48.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-5.48.1.tgz", - "integrity": "sha512-4yg+FJR/V1M9Xoq56SF9Iygqm+r5LMXvheo6DQ7/yUWynQ4YfCRnsKuRgqH4EQ5Ya76rVwlEpw4Xu+TgWQUcdA==", - "dev": true, - "requires": { - "@typescript-eslint/scope-manager": "5.48.1", - "@typescript-eslint/types": "5.48.1", - "@typescript-eslint/typescript-estree": "5.48.1", - "debug": "^4.3.4" - } - }, - "@typescript-eslint/scope-manager": { - "version": "5.48.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-5.48.1.tgz", - "integrity": "sha512-S035ueRrbxRMKvSTv9vJKIWgr86BD8s3RqoRZmsSh/s8HhIs90g6UlK8ZabUSjUZQkhVxt7nmZ63VJ9dcZhtDQ==", - "dev": true, - "requires": { - "@typescript-eslint/types": "5.48.1", - "@typescript-eslint/visitor-keys": "5.48.1" - } - }, - "@typescript-eslint/type-utils": { - "version": "5.48.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-5.48.1.tgz", - "integrity": "sha512-Hyr8HU8Alcuva1ppmqSYtM/Gp0q4JOp1F+/JH5D1IZm/bUBrV0edoewQZiEc1r6I8L4JL21broddxK8HAcZiqQ==", - "dev": true, - "requires": { - "@typescript-eslint/typescript-estree": "5.48.1", - "@typescript-eslint/utils": "5.48.1", - "debug": "^4.3.4", - "tsutils": "^3.21.0" - } - }, - "@typescript-eslint/types": { - "version": "5.48.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-5.48.1.tgz", - "integrity": "sha512-xHyDLU6MSuEEdIlzrrAerCGS3T7AA/L8Hggd0RCYBi0w3JMvGYxlLlXHeg50JI9Tfg5MrtsfuNxbS/3zF1/ATg==", - "dev": true - }, - "@typescript-eslint/typescript-estree": { - "version": "5.48.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-5.48.1.tgz", - "integrity": "sha512-Hut+Osk5FYr+sgFh8J/FHjqX6HFcDzTlWLrFqGoK5kVUN3VBHF/QzZmAsIXCQ8T/W9nQNBTqalxi1P3LSqWnRA==", - "dev": true, - "requires": { - "@typescript-eslint/types": "5.48.1", - "@typescript-eslint/visitor-keys": "5.48.1", - "debug": "^4.3.4", - "globby": "^11.1.0", - "is-glob": "^4.0.3", - "semver": "^7.3.7", - "tsutils": "^3.21.0" - } - }, - "@typescript-eslint/utils": { - "version": "5.48.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-5.48.1.tgz", - "integrity": "sha512-SmQuSrCGUOdmGMwivW14Z0Lj8dxG1mOFZ7soeJ0TQZEJcs3n5Ndgkg0A4bcMFzBELqLJ6GTHnEU+iIoaD6hFGA==", - "dev": true, - "requires": { - "@types/json-schema": "^7.0.9", - "@types/semver": "^7.3.12", - "@typescript-eslint/scope-manager": "5.48.1", - "@typescript-eslint/types": "5.48.1", - "@typescript-eslint/typescript-estree": "5.48.1", - "eslint-scope": "^5.1.1", - "eslint-utils": "^3.0.0", - "semver": "^7.3.7" - } - }, - "@typescript-eslint/visitor-keys": { - "version": "5.48.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-5.48.1.tgz", - "integrity": "sha512-Ns0XBwmfuX7ZknznfXozgnydyR8F6ev/KEGePP4i74uL3ArsKbEhJ7raeKr1JSa997DBDwol/4a0Y+At82c9dA==", - "dev": true, - "requires": { - "@typescript-eslint/types": "5.48.1", - "eslint-visitor-keys": "^3.3.0" - } - }, - "acorn": { - "version": "8.8.1", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.8.1.tgz", - "integrity": "sha512-7zFpHzhnqYKrkYdUjF1HI1bzd0VygEGX8lFk4k5zVMqHEoES+P+7TKI+EvLO9WVMJ8eekdO0aDEK044xTXwPPA==", - "dev": true - }, - "acorn-jsx": { - "version": "5.3.2", - "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.2.tgz", - "integrity": "sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==", - "dev": true, - "requires": {} - }, - "acorn-walk": { - "version": "8.2.0", - "resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-8.2.0.tgz", - "integrity": "sha512-k+iyHEuPgSw6SbuDpGQM+06HQUa04DZ3o+F6CSzXMvvI5KMvnaEqXe+YVe555R9nn6GPt404fos4wcgpw12SDA==", - "dev": true - }, - "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-escapes": { - "version": "4.3.2", - "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-4.3.2.tgz", - "integrity": "sha512-gKXj5ALrKWQLsYG9jlTRmR/xKluxHV+Z9QEwNIgCfM1/uwPMCuzVVnh5mwTd+OuBZcwSIMbqssNWRm1lE51QaQ==", - "dev": true, - "requires": { - "type-fest": "^0.21.3" - }, - "dependencies": { - "type-fest": { - "version": "0.21.3", - "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.21.3.tgz", - "integrity": "sha512-t0rzBq87m3fVcduHDUFhKmyyX+9eo6WQjZvf51Ea/M0Q7+T374Jp1aUiyUl0GKxp8M/OETVHSDvmkyPgvX+X2w==", - "dev": true - } - } - }, - "ansi-regex": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", - "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", - "dev": true - }, - "ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "dev": true, - "requires": { - "color-convert": "^2.0.1" - } - }, - "anymatch": { - "version": "3.1.3", - "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.3.tgz", - "integrity": "sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==", - "dev": true, - "requires": { - "normalize-path": "^3.0.0", - "picomatch": "^2.0.4" - } - }, - "arg": { - "version": "4.1.3", - "resolved": "https://registry.npmjs.org/arg/-/arg-4.1.3.tgz", - "integrity": "sha512-58S9QDqG0Xx27YwPSt9fJxivjYl432YCwfDMfZ+71RAqUrZef7LrKQZ3LHLOwCS4FLNBplP533Zx895SeOCHvA==", - "dev": true - }, - "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 - }, - "array-includes": { - "version": "3.1.6", - "resolved": "https://registry.npmjs.org/array-includes/-/array-includes-3.1.6.tgz", - "integrity": "sha512-sgTbLvL6cNnw24FnbaDyjmvddQ2ML8arZsgaJhoABMoplz/4QRhtrYS+alr1BUM1Bwp6dhx8vVCBSLG+StwOFw==", - "dev": true, - "requires": { - "call-bind": "^1.0.2", - "define-properties": "^1.1.4", - "es-abstract": "^1.20.4", - "get-intrinsic": "^1.1.3", - "is-string": "^1.0.7" - } - }, - "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.prototype.flat": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/array.prototype.flat/-/array.prototype.flat-1.3.1.tgz", - "integrity": "sha512-roTU0KWIOmJ4DRLmwKd19Otg0/mT3qPNt0Qb3GWW8iObuZXxrjB/pzn0R3hqpRSWg4HCwqx+0vwOnWnvlOyeIA==", - "dev": true, - "requires": { - "call-bind": "^1.0.2", - "define-properties": "^1.1.4", - "es-abstract": "^1.20.4", - "es-shim-unscopables": "^1.0.0" - } - }, - "astral-regex": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/astral-regex/-/astral-regex-2.0.0.tgz", - "integrity": "sha512-Z7tMw1ytTXt5jqMcOP+OQteU1VuNK9Y02uuJtKQ1Sv69jXQKKg5cibLwGJow8yzZP+eAc18EmLGPal0bp36rvQ==", - "dev": true - }, - "at-least-node": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/at-least-node/-/at-least-node-1.0.0.tgz", - "integrity": "sha512-+q/t7Ekv1EDY2l6Gda6LLiX14rU9TV20Wa3ofeQmwPFZbOMo9DXrLbOjFaaclkXKWidIaopwAObQDqwWtGUjqg==" - }, - "available-typed-arrays": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/available-typed-arrays/-/available-typed-arrays-1.0.5.tgz", - "integrity": "sha512-DMD0KiN46eipeziST1LPP/STfDU0sufISXmjSgvVsoU2tqxctQeASejWcfNtxYKqETM1UxQ8sp2OrSBWpHY6sw==", - "dev": true - }, - "aws-cdk": { - "version": "2.55.1", - "resolved": "https://registry.npmjs.org/aws-cdk/-/aws-cdk-2.55.1.tgz", - "integrity": "sha512-M/d4lO7rLMvPedNj7pEQtwyxn7nVLluiHggftXlYHOIeaoMG1QCbH1zTuZtMZZxdRRD4ZiOEHvvPYFU/HMcrPQ==", - "dev": true, - "requires": { - "fsevents": "2.3.2" - } - }, - "aws-cdk-lib": { - "version": "2.55.1", - "resolved": "https://registry.npmjs.org/aws-cdk-lib/-/aws-cdk-lib-2.55.1.tgz", - "integrity": "sha512-v0MhL6RqazQ2HKj9TXJvXKQcQNIDYeRzcOJ2xB2Usz56xodArc2goLu2P51X5J84xOO4w2AgNaWMCBzd7MbyOQ==", - "requires": { - "@aws-cdk/asset-awscli-v1": "^2.2.30", - "@aws-cdk/asset-kubectl-v20": "^2.1.1", - "@aws-cdk/asset-node-proxy-agent-v5": "^2.0.38", - "@balena/dockerignore": "^1.0.2", - "case": "1.6.3", - "fs-extra": "^9.1.0", - "ignore": "^5.2.1", - "jsonschema": "^1.4.1", - "minimatch": "^3.1.2", - "punycode": "^2.1.1", - "semver": "^7.3.8", - "yaml": "1.10.2" - }, - "dependencies": { - "@balena/dockerignore": { - "version": "1.0.2", - "bundled": true - }, - "at-least-node": { - "version": "1.0.0", - "bundled": true - }, - "balanced-match": { - "version": "1.0.2", - "bundled": true - }, - "brace-expansion": { - "version": "1.1.11", - "bundled": true, - "requires": { - "balanced-match": "^1.0.0", - "concat-map": "0.0.1" - } - }, - "case": { - "version": "1.6.3", - "bundled": true - }, - "concat-map": { - "version": "0.0.1", - "bundled": true - }, - "fs-extra": { - "version": "9.1.0", - "bundled": true, - "requires": { - "at-least-node": "^1.0.0", - "graceful-fs": "^4.2.0", - "jsonfile": "^6.0.1", - "universalify": "^2.0.0" - } - }, - "graceful-fs": { - "version": "4.2.10", - "bundled": true - }, - "ignore": { - "version": "5.2.1", - "bundled": true - }, - "jsonfile": { - "version": "6.1.0", - "bundled": true, - "requires": { - "graceful-fs": "^4.1.6", - "universalify": "^2.0.0" - } - }, - "jsonschema": { - "version": "1.4.1", - "bundled": true - }, - "lru-cache": { - "version": "6.0.0", - "bundled": true, - "requires": { - "yallist": "^4.0.0" - } - }, - "minimatch": { - "version": "3.1.2", - "bundled": true, - "requires": { - "brace-expansion": "^1.1.7" - } - }, - "punycode": { - "version": "2.1.1", - "bundled": true - }, - "semver": { - "version": "7.3.8", - "bundled": true, - "requires": { - "lru-cache": "^6.0.0" - } - }, - "universalify": { - "version": "2.0.0", - "bundled": true - }, - "yallist": { - "version": "4.0.0", - "bundled": true - }, - "yaml": { - "version": "1.10.2", - "bundled": true - } - } - }, - "babel-jest": { - "version": "29.3.1", - "resolved": "https://registry.npmjs.org/babel-jest/-/babel-jest-29.3.1.tgz", - "integrity": "sha512-aard+xnMoxgjwV70t0L6wkW/3HQQtV+O0PEimxKgzNqCJnbYmroPojdP2tqKSOAt8QAKV/uSZU8851M7B5+fcA==", - "dev": true, - "requires": { - "@jest/transform": "^29.3.1", - "@types/babel__core": "^7.1.14", - "babel-plugin-istanbul": "^6.1.1", - "babel-preset-jest": "^29.2.0", - "chalk": "^4.0.0", - "graceful-fs": "^4.2.9", - "slash": "^3.0.0" - } - }, - "babel-plugin-istanbul": { - "version": "6.1.1", - "resolved": "https://registry.npmjs.org/babel-plugin-istanbul/-/babel-plugin-istanbul-6.1.1.tgz", - "integrity": "sha512-Y1IQok9821cC9onCx5otgFfRm7Lm+I+wwxOx738M/WLPZ9Q42m4IG5W0FNX8WLL2gYMZo3JkuXIH2DOpWM+qwA==", - "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.0.0", - "@istanbuljs/load-nyc-config": "^1.0.0", - "@istanbuljs/schema": "^0.1.2", - "istanbul-lib-instrument": "^5.0.4", - "test-exclude": "^6.0.0" - } - }, - "babel-plugin-jest-hoist": { - "version": "29.2.0", - "resolved": "https://registry.npmjs.org/babel-plugin-jest-hoist/-/babel-plugin-jest-hoist-29.2.0.tgz", - "integrity": "sha512-TnspP2WNiR3GLfCsUNHqeXw0RoQ2f9U5hQ5L3XFpwuO8htQmSrhh8qsB6vi5Yi8+kuynN1yjDjQsPfkebmB6ZA==", - "dev": true, - "requires": { - "@babel/template": "^7.3.3", - "@babel/types": "^7.3.3", - "@types/babel__core": "^7.1.14", - "@types/babel__traverse": "^7.0.6" - } - }, - "babel-preset-current-node-syntax": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/babel-preset-current-node-syntax/-/babel-preset-current-node-syntax-1.0.1.tgz", - "integrity": "sha512-M7LQ0bxarkxQoN+vz5aJPsLBn77n8QgTFmo8WK0/44auK2xlCXrYcUxHFxgU7qW5Yzw/CjmLRK2uJzaCd7LvqQ==", - "dev": true, - "requires": { - "@babel/plugin-syntax-async-generators": "^7.8.4", - "@babel/plugin-syntax-bigint": "^7.8.3", - "@babel/plugin-syntax-class-properties": "^7.8.3", - "@babel/plugin-syntax-import-meta": "^7.8.3", - "@babel/plugin-syntax-json-strings": "^7.8.3", - "@babel/plugin-syntax-logical-assignment-operators": "^7.8.3", - "@babel/plugin-syntax-nullish-coalescing-operator": "^7.8.3", - "@babel/plugin-syntax-numeric-separator": "^7.8.3", - "@babel/plugin-syntax-object-rest-spread": "^7.8.3", - "@babel/plugin-syntax-optional-catch-binding": "^7.8.3", - "@babel/plugin-syntax-optional-chaining": "^7.8.3", - "@babel/plugin-syntax-top-level-await": "^7.8.3" - } - }, - "babel-preset-jest": { - "version": "29.2.0", - "resolved": "https://registry.npmjs.org/babel-preset-jest/-/babel-preset-jest-29.2.0.tgz", - "integrity": "sha512-z9JmMJppMxNv8N7fNRHvhMg9cvIkMxQBXgFkane3yKVEvEOP+kB50lk8DFRvF9PGqbyXxlmebKWhuDORO8RgdA==", - "dev": true, - "requires": { - "babel-plugin-jest-hoist": "^29.2.0", - "babel-preset-current-node-syntax": "^1.0.0" - } - }, - "balanced-match": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", - "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==" - }, - "brace-expansion": { - "version": "1.1.11", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", - "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", - "requires": { - "balanced-match": "^1.0.0", - "concat-map": "0.0.1" - } - }, - "braces": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz", - "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==", - "dev": true, - "requires": { - "fill-range": "^7.0.1" - } - }, - "browserslist": { - "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.30001400", - "electron-to-chromium": "^1.4.251", - "node-releases": "^2.0.6", - "update-browserslist-db": "^1.0.9" - } - }, - "bs-logger": { - "version": "0.2.6", - "resolved": "https://registry.npmjs.org/bs-logger/-/bs-logger-0.2.6.tgz", - "integrity": "sha512-pd8DCoxmbgc7hyPKOvxtqNcjYoOsABPQdcCUjGp3d42VR2CX1ORhk2A87oqqu5R1kk+76nsxZupkmyd+MVtCog==", - "dev": true, - "requires": { - "fast-json-stable-stringify": "2.x" - } - }, - "bser": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/bser/-/bser-2.1.1.tgz", - "integrity": "sha512-gQxTNE/GAfIIrmHLUE3oJyp5FO6HRBfhjnw4/wMmA63ZGDJnWBmgY/lyQBpnDUkGmAhbSe39tx2d/iTOAfglwQ==", - "dev": true, - "requires": { - "node-int64": "^0.4.0" - } - }, - "buffer-from": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.2.tgz", - "integrity": "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==" - }, - "call-bind": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.2.tgz", - "integrity": "sha512-7O+FbCihrB5WGbFYesctwmTKae6rOiIzmz1icreWJ+0aA7LJfuqhEso2T9ncpcFtzMQtzXf2QGGueWJGTYsqrA==", - "dev": true, - "requires": { - "function-bind": "^1.1.1", - "get-intrinsic": "^1.0.2" - } - }, - "callsites": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", - "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==", - "dev": true - }, - "camelcase": { - "version": "5.3.1", - "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz", - "integrity": "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==", - "dev": true - }, - "caniuse-lite": { - "version": "1.0.30001442", - "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001442.tgz", - "integrity": "sha512-239m03Pqy0hwxYPYR5JwOIxRJfLTWtle9FV8zosfV5pHg+/51uD4nxcUlM8+mWWGfwKtt8lJNHnD3cWw9VZ6ow==", - "dev": true - }, - "chalk": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", - "dev": true, - "requires": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - } - }, - "char-regex": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/char-regex/-/char-regex-1.0.2.tgz", - "integrity": "sha512-kWWXztvZ5SBQV+eRgKFeh8q5sLuZY2+8WUIzlxWVTg+oGwY14qylx1KbKzHd8P6ZYkAg0xyIDU9JMHhyJMZ1jw==", - "dev": true - }, - "charenc": { - "version": "0.0.2", - "resolved": "https://registry.npmjs.org/charenc/-/charenc-0.0.2.tgz", - "integrity": "sha512-yrLQ/yVUFXkzg7EDQsPieE/53+0RlaWTs+wBrvW36cyilJ2SaDWfl4Yj7MtLTXleV9uEKefbAGUPv2/iWSooRA==", - "dev": true - }, - "ci-info": { - "version": "3.7.1", - "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-3.7.1.tgz", - "integrity": "sha512-4jYS4MOAaCIStSRwiuxc4B8MYhIe676yO1sYGzARnjXkWpmzZMMYxY6zu8WYWDhSuth5zhrQ1rhNSibyyvv4/w==", - "dev": true - }, - "cjs-module-lexer": { - "version": "1.2.2", - "resolved": "https://registry.npmjs.org/cjs-module-lexer/-/cjs-module-lexer-1.2.2.tgz", - "integrity": "sha512-cOU9usZw8/dXIXKtwa8pM0OTJQuJkxMN6w30csNRUerHfeQ5R6U3kkU/FtJeIf3M202OHfY2U8ccInBG7/xogA==", - "dev": true - }, - "cliui": { - "version": "8.0.1", - "resolved": "https://registry.npmjs.org/cliui/-/cliui-8.0.1.tgz", - "integrity": "sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ==", - "dev": true, - "requires": { - "string-width": "^4.2.0", - "strip-ansi": "^6.0.1", - "wrap-ansi": "^7.0.0" - } - }, - "co": { - "version": "4.6.0", - "resolved": "https://registry.npmjs.org/co/-/co-4.6.0.tgz", - "integrity": "sha512-QVb0dM5HvG+uaxitm8wONl7jltx8dqhfU33DcqtOZcLSVIKSDDLDi7+0LbAKiyI8hD9u42m2YxXSkMGWThaecQ==", - "dev": true - }, - "collect-v8-coverage": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/collect-v8-coverage/-/collect-v8-coverage-1.0.1.tgz", - "integrity": "sha512-iBPtljfCNcTKNAto0KEtDfZ3qzjJvqE3aTGZsbhjSBlorqpXJlaWWtPO35D+ZImoC3KWejX64o+yPGxhWSTzfg==", - "dev": true - }, - "color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "dev": true, - "requires": { - "color-name": "~1.1.4" - } - }, - "color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true - }, - "concat-map": { - "version": "0.0.1", - "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", - "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==" - }, - "constructs": { - "version": "10.1.216", - "resolved": "https://registry.npmjs.org/constructs/-/constructs-10.1.216.tgz", - "integrity": "sha512-Nx/Pzuyy46Bc5LFu3XPSmTKNcjN4ChQ/R3syOb7bJLfQ5VhJn+o0aCKBVwnbuF1av0YCG6IaDz8fdtWhjefJjA==" - }, - "convert-source-map": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-2.0.0.tgz", - "integrity": "sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==", - "dev": true - }, - "create-require": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/create-require/-/create-require-1.1.1.tgz", - "integrity": "sha512-dcKFX3jn0MpIaXjisoRvexIJVEKzaq7z2rZKxf+MSr9TkdmHmsU4m2lcLojrj/FHl8mk5VxMmYA+ftRkP/3oKQ==", - "dev": true - }, - "cross-spawn": { - "version": "7.0.3", - "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz", - "integrity": "sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==", - "dev": true, - "requires": { - "path-key": "^3.1.0", - "shebang-command": "^2.0.0", - "which": "^2.0.1" - } - }, - "crypt": { - "version": "0.0.2", - "resolved": "https://registry.npmjs.org/crypt/-/crypt-0.0.2.tgz", - "integrity": "sha512-mCxBlsHFYh9C+HVpiEacem8FEBnMXgU9gy4zmNC+SXAZNB/1idgp/aulFJ4FgCi7GPEVbfyng092GqL2k2rmow==", - "dev": true - }, - "debug": { - "version": "4.3.4", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", - "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", - "dev": true, - "requires": { - "ms": "2.1.2" - } - }, - "dedent": { - "version": "0.7.0", - "resolved": "https://registry.npmjs.org/dedent/-/dedent-0.7.0.tgz", - "integrity": "sha512-Q6fKUPqnAHAyhiUgFU7BUzLiv0kd8saH9al7tnu5Q/okj6dnupxyTgFIBjVzJATdfIAm9NAsvXNzjaKa+bxVyA==", - "dev": true - }, - "deep-is": { - "version": "0.1.4", - "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.4.tgz", - "integrity": "sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==", - "dev": true - }, - "deepmerge": { - "version": "4.2.2", - "resolved": "https://registry.npmjs.org/deepmerge/-/deepmerge-4.2.2.tgz", - "integrity": "sha512-FJ3UgI4gIl+PHZm53knsuSFpE+nESMr7M4v9QcgB7S63Kj/6WqMiFQJpBBYz1Pt+66bZpP3Q7Lye0Oo9MPKEdg==", - "dev": true - }, - "define-lazy-prop": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/define-lazy-prop/-/define-lazy-prop-2.0.0.tgz", - "integrity": "sha512-Ds09qNh8yw3khSjiJjiUInaGX9xlqZDY7JVryGxdxV7NPeuqQfplOpQ66yJFZut3jLa5zOwkXw1g9EI2uKh4Og==", - "dev": true - }, - "define-properties": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.1.4.tgz", - "integrity": "sha512-uckOqKcfaVvtBdsVkdPv3XjveQJsNQqmhXgRi8uhvWWuPYZCNlzT8qAyblUgNoXdHdjMTzAqeGjAoli8f+bzPA==", - "dev": true, - "requires": { - "has-property-descriptors": "^1.0.0", - "object-keys": "^1.1.1" - } - }, - "detect-newline": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/detect-newline/-/detect-newline-3.1.0.tgz", - "integrity": "sha512-TLz+x/vEXm/Y7P7wn1EJFNLxYpUD4TgMosxY6fAVJUnJMbupHBOncxyWUG9OpTaH9EBD7uFI5LfEgmMOc54DsA==", - "dev": true - }, - "diff": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/diff/-/diff-5.1.0.tgz", - "integrity": "sha512-D+mk+qE8VC/PAUrlAU34N+VfXev0ghe5ywmpqrawphmVZc1bEfn56uo9qpyGp1p4xpzOHkSW4ztBd6L7Xx4ACw==", - "dev": true - }, - "diff-sequences": { - "version": "29.3.1", - "resolved": "https://registry.npmjs.org/diff-sequences/-/diff-sequences-29.3.1.tgz", - "integrity": "sha512-hlM3QR272NXCi4pq+N4Kok4kOp6EsgOM3ZSpJI7Da3UAs+Ttsi8MRmB6trM/lhyzUxGfOgnpkHtgqm5Q/CTcfQ==", - "dev": true - }, - "dir-glob": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/dir-glob/-/dir-glob-3.0.1.tgz", - "integrity": "sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA==", - "dev": true, - "requires": { - "path-type": "^4.0.0" - } - }, - "doctrine": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-3.0.0.tgz", - "integrity": "sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w==", - "dev": true, - "requires": { - "esutils": "^2.0.2" - } - }, - "electron-to-chromium": { - "version": "1.4.284", - "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.284.tgz", - "integrity": "sha512-M8WEXFuKXMYMVr45fo8mq0wUrrJHheiKZf6BArTKk9ZBYCKJEOU5H8cdWgDT+qCVZf7Na4lVUaZsA+h6uA9+PA==", - "dev": true - }, - "emittery": { - "version": "0.13.1", - "resolved": "https://registry.npmjs.org/emittery/-/emittery-0.13.1.tgz", - "integrity": "sha512-DeWwawk6r5yR9jFgnDKYt4sLS0LmHJJi3ZOnb5/JdbYwj3nW+FxQnHIjhBKz8YLC7oRNPVM9NQ47I3CVx34eqQ==", - "dev": true - }, - "emoji-regex": { - "version": "8.0.0", - "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", - "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", - "dev": true - }, - "enhanced-resolve": { - "version": "5.12.0", - "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.12.0.tgz", - "integrity": "sha512-QHTXI/sZQmko1cbDoNAa3mJ5qhWUUNAq3vR0/YiD379fWQrcfuoX1+HW2S0MTt7XmoPLapdaDKUtelUSPic7hQ==", - "dev": true, - "requires": { - "graceful-fs": "^4.2.4", - "tapable": "^2.2.0" - } - }, - "error-ex": { - "version": "1.3.2", - "resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.2.tgz", - "integrity": "sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g==", - "dev": true, - "requires": { - "is-arrayish": "^0.2.1" - } - }, - "es-abstract": { - "version": "1.21.1", - "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.21.1.tgz", - "integrity": "sha512-QudMsPOz86xYz/1dG1OuGBKOELjCh99IIWHLzy5znUB6j8xG2yMA7bfTV86VSqKF+Y/H08vQPR+9jyXpuC6hfg==", - "dev": true, - "requires": { - "available-typed-arrays": "^1.0.5", - "call-bind": "^1.0.2", - "es-set-tostringtag": "^2.0.1", - "es-to-primitive": "^1.2.1", - "function-bind": "^1.1.1", - "function.prototype.name": "^1.1.5", - "get-intrinsic": "^1.1.3", - "get-symbol-description": "^1.0.0", - "globalthis": "^1.0.3", - "gopd": "^1.0.1", - "has": "^1.0.3", - "has-property-descriptors": "^1.0.0", - "has-proto": "^1.0.1", - "has-symbols": "^1.0.3", - "internal-slot": "^1.0.4", - "is-array-buffer": "^3.0.1", - "is-callable": "^1.2.7", - "is-negative-zero": "^2.0.2", - "is-regex": "^1.1.4", - "is-shared-array-buffer": "^1.0.2", - "is-string": "^1.0.7", - "is-typed-array": "^1.1.10", - "is-weakref": "^1.0.2", - "object-inspect": "^1.12.2", - "object-keys": "^1.1.1", - "object.assign": "^4.1.4", - "regexp.prototype.flags": "^1.4.3", - "safe-regex-test": "^1.0.0", - "string.prototype.trimend": "^1.0.6", - "string.prototype.trimstart": "^1.0.6", - "typed-array-length": "^1.0.4", - "unbox-primitive": "^1.0.2", - "which-typed-array": "^1.1.9" - } - }, - "es-set-tostringtag": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/es-set-tostringtag/-/es-set-tostringtag-2.0.1.tgz", - "integrity": "sha512-g3OMbtlwY3QewlqAiMLI47KywjWZoEytKr8pf6iTC8uJq5bIAH52Z9pnQ8pVL6whrCto53JZDuUIsifGeLorTg==", - "dev": true, - "requires": { - "get-intrinsic": "^1.1.3", - "has": "^1.0.3", - "has-tostringtag": "^1.0.0" - } - }, - "es-shim-unscopables": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/es-shim-unscopables/-/es-shim-unscopables-1.0.0.tgz", - "integrity": "sha512-Jm6GPcCdC30eMLbZ2x8z2WuRwAws3zTBBKuusffYVUrNj/GVSUAZ+xKMaUpfNDR5IbyNA5LJbaecoUVbmUcB1w==", - "dev": true, - "requires": { - "has": "^1.0.3" - } - }, - "es-to-primitive": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/es-to-primitive/-/es-to-primitive-1.2.1.tgz", - "integrity": "sha512-QCOllgZJtaUo9miYBcLChTUaHNjJF3PYs1VidD7AwiEj1kYxKeQTctLAezAOH5ZKRH0g2IgPn6KwB4IT8iRpvA==", - "dev": true, - "requires": { - "is-callable": "^1.1.4", - "is-date-object": "^1.0.1", - "is-symbol": "^1.0.2" - } - }, - "escalade": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.1.tgz", - "integrity": "sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw==", - "dev": true - }, - "escape-string-regexp": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", - "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", - "dev": true - }, - "eslint": { - "version": "8.31.0", - "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.31.0.tgz", - "integrity": "sha512-0tQQEVdmPZ1UtUKXjX7EMm9BlgJ08G90IhWh0PKDCb3ZLsgAOHI8fYSIzYVZej92zsgq+ft0FGsxhJ3xo2tbuA==", - "dev": true, - "requires": { - "@eslint/eslintrc": "^1.4.1", - "@humanwhocodes/config-array": "^0.11.8", - "@humanwhocodes/module-importer": "^1.0.1", - "@nodelib/fs.walk": "^1.2.8", - "ajv": "^6.10.0", - "chalk": "^4.0.0", - "cross-spawn": "^7.0.2", - "debug": "^4.3.2", - "doctrine": "^3.0.0", - "escape-string-regexp": "^4.0.0", - "eslint-scope": "^7.1.1", - "eslint-utils": "^3.0.0", - "eslint-visitor-keys": "^3.3.0", - "espree": "^9.4.0", - "esquery": "^1.4.0", - "esutils": "^2.0.2", - "fast-deep-equal": "^3.1.3", - "file-entry-cache": "^6.0.1", - "find-up": "^5.0.0", - "glob-parent": "^6.0.2", - "globals": "^13.19.0", - "grapheme-splitter": "^1.0.4", - "ignore": "^5.2.0", - "import-fresh": "^3.0.0", - "imurmurhash": "^0.1.4", - "is-glob": "^4.0.0", - "is-path-inside": "^3.0.3", - "js-sdsl": "^4.1.4", - "js-yaml": "^4.1.0", - "json-stable-stringify-without-jsonify": "^1.0.1", - "levn": "^0.4.1", - "lodash.merge": "^4.6.2", - "minimatch": "^3.1.2", - "natural-compare": "^1.4.0", - "optionator": "^0.9.1", - "regexpp": "^3.2.0", - "strip-ansi": "^6.0.1", - "strip-json-comments": "^3.1.0", - "text-table": "^0.2.0" - }, - "dependencies": { - "eslint-scope": { - "version": "7.1.1", - "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-7.1.1.tgz", - "integrity": "sha512-QKQM/UXpIiHcLqJ5AOyIW7XZmzjkzQXYE54n1++wb0u9V/abW3l9uQnxX8Z5Xd18xyKIMTUAyQ0k1e8pz6LUrw==", - "dev": true, - "requires": { - "esrecurse": "^4.3.0", - "estraverse": "^5.2.0" - } - }, - "estraverse": { - "version": "5.3.0", - "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", - "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", - "dev": true - } - } - }, - "eslint-import-resolver-node": { - "version": "0.3.6", - "resolved": "https://registry.npmjs.org/eslint-import-resolver-node/-/eslint-import-resolver-node-0.3.6.tgz", - "integrity": "sha512-0En0w03NRVMn9Uiyn8YRPDKvWjxCWkslUEhGNTdGx15RvPJYQ+lbOlqrlNI2vEAs4pDYK4f/HN2TbDmk5TP0iw==", - "dev": true, - "requires": { - "debug": "^3.2.7", - "resolve": "^1.20.0" - }, - "dependencies": { - "debug": { - "version": "3.2.7", - "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", - "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", - "dev": true, - "requires": { - "ms": "^2.1.1" - } - } - } - }, - "eslint-import-resolver-typescript": { - "version": "3.5.3", - "resolved": "https://registry.npmjs.org/eslint-import-resolver-typescript/-/eslint-import-resolver-typescript-3.5.3.tgz", - "integrity": "sha512-njRcKYBc3isE42LaTcJNVANR3R99H9bAxBDMNDr2W7yq5gYPxbU3MkdhsQukxZ/Xg9C2vcyLlDsbKfRDg0QvCQ==", - "dev": true, - "requires": { - "debug": "^4.3.4", - "enhanced-resolve": "^5.10.0", - "get-tsconfig": "^4.2.0", - "globby": "^13.1.2", - "is-core-module": "^2.10.0", - "is-glob": "^4.0.3", - "synckit": "^0.8.4" - }, - "dependencies": { - "globby": { - "version": "13.1.3", - "resolved": "https://registry.npmjs.org/globby/-/globby-13.1.3.tgz", - "integrity": "sha512-8krCNHXvlCgHDpegPzleMq07yMYTO2sXKASmZmquEYWEmCx6J5UTRbp5RwMJkTJGtcQ44YpiUYUiN0b9mzy8Bw==", - "dev": true, - "requires": { - "dir-glob": "^3.0.1", - "fast-glob": "^3.2.11", - "ignore": "^5.2.0", - "merge2": "^1.4.1", - "slash": "^4.0.0" - } - }, - "slash": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/slash/-/slash-4.0.0.tgz", - "integrity": "sha512-3dOsAHXXUkQTpOYcoAxLIorMTp4gIQr5IW3iVb7A7lFIp0VHhnynm9izx6TssdrIcVIESAlVjtnO2K8bg+Coew==", - "dev": true - } - } - }, - "eslint-module-utils": { - "version": "2.7.4", - "resolved": "https://registry.npmjs.org/eslint-module-utils/-/eslint-module-utils-2.7.4.tgz", - "integrity": "sha512-j4GT+rqzCoRKHwURX7pddtIPGySnX9Si/cgMI5ztrcqOPtk5dDEeZ34CQVPphnqkJytlc97Vuk05Um2mJ3gEQA==", - "dev": true, - "requires": { - "debug": "^3.2.7" - }, - "dependencies": { - "debug": { - "version": "3.2.7", - "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", - "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", - "dev": true, - "requires": { - "ms": "^2.1.1" - } - } - } - }, - "eslint-plugin-import": { - "version": "2.26.0", - "resolved": "https://registry.npmjs.org/eslint-plugin-import/-/eslint-plugin-import-2.26.0.tgz", - "integrity": "sha512-hYfi3FXaM8WPLf4S1cikh/r4IxnO6zrhZbEGz2b660EJRbuxgpDS5gkCuYgGWg2xxh2rBuIr4Pvhve/7c31koA==", - "dev": true, - "requires": { - "array-includes": "^3.1.4", - "array.prototype.flat": "^1.2.5", - "debug": "^2.6.9", - "doctrine": "^2.1.0", - "eslint-import-resolver-node": "^0.3.6", - "eslint-module-utils": "^2.7.3", - "has": "^1.0.3", - "is-core-module": "^2.8.1", - "is-glob": "^4.0.3", - "minimatch": "^3.1.2", - "object.values": "^1.1.5", - "resolve": "^1.22.0", - "tsconfig-paths": "^3.14.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" - } - }, - "doctrine": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-2.1.0.tgz", - "integrity": "sha512-35mSku4ZXK0vfCuHEDAwt55dg2jNajHZ1odvF+8SSr82EsZY4QmXfuWso8oEd8zRhVObSN18aM0CjSdoBX7zIw==", - "dev": true, - "requires": { - "esutils": "^2.0.2" - } - }, - "ms": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", - "dev": true - } - } - }, - "eslint-scope": { - "version": "5.1.1", - "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-5.1.1.tgz", - "integrity": "sha512-2NxwbF/hZ0KpepYN0cNbo+FN6XoK7GaHlQhgx/hIZl6Va0bF45RQOOwhLIy8lQDbuCiadSLCBnH2CFYquit5bw==", - "dev": true, - "requires": { - "esrecurse": "^4.3.0", - "estraverse": "^4.1.1" - } - }, - "eslint-utils": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/eslint-utils/-/eslint-utils-3.0.0.tgz", - "integrity": "sha512-uuQC43IGctw68pJA1RgbQS8/NP7rch6Cwd4j3ZBtgo4/8Flj4eGE7ZYSZRN3iq5pVUv6GPdW5Z1RFleo84uLDA==", - "dev": true, - "requires": { - "eslint-visitor-keys": "^2.0.0" - }, - "dependencies": { - "eslint-visitor-keys": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-2.1.0.tgz", - "integrity": "sha512-0rSmRBzXgDzIsD6mGdJgevzgezI534Cer5L/vyMX0kHzT/jiB43jRhd9YUlMGYLQy2zprNmoT8qasCGtY+QaKw==", - "dev": true - } - } - }, - "eslint-visitor-keys": { - "version": "3.3.0", - "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.3.0.tgz", - "integrity": "sha512-mQ+suqKJVyeuwGYHAdjMFqjCyfl8+Ldnxuyp3ldiMBFKkvytrXUZWaiPCEav8qDHKty44bD+qV1IP4T+w+xXRA==", - "dev": true - }, - "espree": { - "version": "9.4.1", - "resolved": "https://registry.npmjs.org/espree/-/espree-9.4.1.tgz", - "integrity": "sha512-XwctdmTO6SIvCzd9810yyNzIrOrqNYV9Koizx4C/mRhf9uq0o4yHoCEU/670pOxOL/MSraektvSAji79kX90Vg==", - "dev": true, - "requires": { - "acorn": "^8.8.0", - "acorn-jsx": "^5.3.2", - "eslint-visitor-keys": "^3.3.0" - } - }, - "esprima": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz", - "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==", - "dev": true - }, - "esquery": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.4.0.tgz", - "integrity": "sha512-cCDispWt5vHHtwMY2YrAQ4ibFkAL8RbH5YGBnZBc90MolvvfkkQcJro/aZiAQUlQ3qgrYS6D6v8Gc5G5CQsc9w==", - "dev": true, - "requires": { - "estraverse": "^5.1.0" - }, - "dependencies": { - "estraverse": { - "version": "5.3.0", - "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", - "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", - "dev": true - } - } - }, - "esrecurse": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.3.0.tgz", - "integrity": "sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==", - "dev": true, - "requires": { - "estraverse": "^5.2.0" - }, - "dependencies": { - "estraverse": { - "version": "5.3.0", - "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", - "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", - "dev": true - } - } - }, - "estraverse": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.3.0.tgz", - "integrity": "sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==", - "dev": true - }, - "esutils": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz", - "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==", - "dev": true - }, - "execa": { - "version": "5.1.1", - "resolved": "https://registry.npmjs.org/execa/-/execa-5.1.1.tgz", - "integrity": "sha512-8uSpZZocAZRBAPIEINJj3Lo9HyGitllczc27Eh5YYojjMFMn8yHMDMaUHE2Jqfq05D/wucwI4JGURyXt1vchyg==", - "dev": true, - "requires": { - "cross-spawn": "^7.0.3", - "get-stream": "^6.0.0", - "human-signals": "^2.1.0", - "is-stream": "^2.0.0", - "merge-stream": "^2.0.0", - "npm-run-path": "^4.0.1", - "onetime": "^5.1.2", - "signal-exit": "^3.0.3", - "strip-final-newline": "^2.0.0" - } - }, - "exit": { - "version": "0.1.2", - "resolved": "https://registry.npmjs.org/exit/-/exit-0.1.2.tgz", - "integrity": "sha512-Zk/eNKV2zbjpKzrsQ+n1G6poVbErQxJ0LBOJXaKZ1EViLzH+hrLu9cdXI4zw9dBQJslwBEpbQ2P1oS7nDxs6jQ==", - "dev": true - }, - "expect": { - "version": "29.3.1", - "resolved": "https://registry.npmjs.org/expect/-/expect-29.3.1.tgz", - "integrity": "sha512-gGb1yTgU30Q0O/tQq+z30KBWv24ApkMgFUpvKBkyLUBL68Wv8dHdJxTBZFl/iT8K/bqDHvUYRH6IIN3rToopPA==", - "dev": true, - "requires": { - "@jest/expect-utils": "^29.3.1", - "jest-get-type": "^29.2.0", - "jest-matcher-utils": "^29.3.1", - "jest-message-util": "^29.3.1", - "jest-util": "^29.3.1" - } - }, - "fast-deep-equal": { - "version": "3.1.3", - "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", - "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==", - "dev": true - }, - "fast-glob": { - "version": "3.2.12", - "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.2.12.tgz", - "integrity": "sha512-DVj4CQIYYow0BlaelwK1pHl5n5cRSJfM60UA0zK891sVInoPri2Ekj7+e1CT3/3qxXenpI+nBBmQAcJPJgaj4w==", - "dev": true, - "requires": { - "@nodelib/fs.stat": "^2.0.2", - "@nodelib/fs.walk": "^1.2.3", - "glob-parent": "^5.1.2", - "merge2": "^1.3.0", - "micromatch": "^4.0.4" - }, - "dependencies": { - "glob-parent": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", - "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", - "dev": true, - "requires": { - "is-glob": "^4.0.1" - } - } - } - }, - "fast-json-stable-stringify": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz", - "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==", - "dev": true - }, - "fast-levenshtein": { - "version": "2.0.6", - "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz", - "integrity": "sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==", - "dev": true - }, - "fastq": { - "version": "1.15.0", - "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.15.0.tgz", - "integrity": "sha512-wBrocU2LCXXa+lWBt8RoIRD89Fi8OdABODa/kEnyeyjS5aZO5/GNvI5sEINADqP/h8M29UHTHUb53sUu5Ihqdw==", - "dev": true, - "requires": { - "reusify": "^1.0.4" - } - }, - "fb-watchman": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/fb-watchman/-/fb-watchman-2.0.2.tgz", - "integrity": "sha512-p5161BqbuCaSnB8jIbzQHOlpgsPmK5rJVDfDKO91Axs5NC1uu3HRQm6wt9cd9/+GtQQIO53JdGXXoyDpTAsgYA==", - "dev": true, - "requires": { - "bser": "2.1.1" - } - }, - "file-entry-cache": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-6.0.1.tgz", - "integrity": "sha512-7Gps/XWymbLk2QLYK4NzpMOrYjMhdIxXuIvy2QBsLE6ljuodKvdkWs/cpyJJ3CVIVpH0Oi1Hvg1ovbMzLdFBBg==", - "dev": true, - "requires": { - "flat-cache": "^3.0.4" - } - }, - "fill-range": { - "version": "7.0.1", - "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz", - "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==", - "dev": true, - "requires": { - "to-regex-range": "^5.0.1" - } - }, - "find-up": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz", - "integrity": "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==", - "dev": true, - "requires": { - "locate-path": "^6.0.0", - "path-exists": "^4.0.0" - } - }, - "flat-cache": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-3.0.4.tgz", - "integrity": "sha512-dm9s5Pw7Jc0GvMYbshN6zchCA9RgQlzzEZX3vylR9IqFfS8XciblUXOKfW6SiuJ0e13eDYZoZV5wdrev7P3Nwg==", - "dev": true, - "requires": { - "flatted": "^3.1.0", - "rimraf": "^3.0.2" - } - }, - "flatted": { - "version": "3.2.7", - "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.2.7.tgz", - "integrity": "sha512-5nqDSxl8nn5BSNxyR3n4I6eDmbolI6WT+QqR547RwxQapgjQBmtktdP+HTBb/a/zLsbzERTONyUB5pefh5TtjQ==", - "dev": true - }, - "for-each": { - "version": "0.3.3", - "resolved": "https://registry.npmjs.org/for-each/-/for-each-0.3.3.tgz", - "integrity": "sha512-jqYfLp7mo9vIyQf8ykW2v7A+2N4QjeCeI5+Dz9XraiO1ign81wjiH7Fb9vSOWvQfNtmSa4H2RoQTrrXivdUZmw==", - "dev": true, - "requires": { - "is-callable": "^1.1.3" - } - }, - "fs-extra": { - "version": "9.1.0", - "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-9.1.0.tgz", - "integrity": "sha512-hcg3ZmepS30/7BSFqRvoo3DOMQu7IjqxO5nCDt+zM9XWjb33Wg7ziNT+Qvqbuc3+gWpzO02JubVyk2G4Zvo1OQ==", - "requires": { - "at-least-node": "^1.0.0", - "graceful-fs": "^4.2.0", - "jsonfile": "^6.0.1", - "universalify": "^2.0.0" - } - }, - "fs.realpath": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", - "integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==", - "dev": true - }, - "fsevents": { - "version": "2.3.2", - "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.2.tgz", - "integrity": "sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==", - "dev": true, - "optional": true - }, - "function-bind": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz", - "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==", - "dev": true - }, - "function.prototype.name": { - "version": "1.1.5", - "resolved": "https://registry.npmjs.org/function.prototype.name/-/function.prototype.name-1.1.5.tgz", - "integrity": "sha512-uN7m/BzVKQnCUF/iW8jYea67v++2u7m5UgENbHRtdDVclOUP+FMPlCNdmk0h/ysGyo2tavMJEDqJAkJdRa1vMA==", - "dev": true, - "requires": { - "call-bind": "^1.0.2", - "define-properties": "^1.1.3", - "es-abstract": "^1.19.0", - "functions-have-names": "^1.2.2" - } - }, - "functions-have-names": { - "version": "1.2.3", - "resolved": "https://registry.npmjs.org/functions-have-names/-/functions-have-names-1.2.3.tgz", - "integrity": "sha512-xckBUXyTIqT97tq2x2AMb+g163b5JFysYk0x4qxNFwbfQkmNZoiRHb6sPzI9/QV33WeuvVYBUIiD4NzNIyqaRQ==", - "dev": true - }, - "gensync": { - "version": "1.0.0-beta.2", - "resolved": "https://registry.npmjs.org/gensync/-/gensync-1.0.0-beta.2.tgz", - "integrity": "sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==", - "dev": true - }, - "get-caller-file": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz", - "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==", - "dev": true - }, - "get-intrinsic": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.1.3.tgz", - "integrity": "sha512-QJVz1Tj7MS099PevUG5jvnt9tSkXN8K14dxQlikJuPt4uD9hHAHjLyLBiLR5zELelBdD9QNRAXZzsJx0WaDL9A==", - "dev": true, - "requires": { - "function-bind": "^1.1.1", - "has": "^1.0.3", - "has-symbols": "^1.0.3" - } - }, - "get-package-type": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/get-package-type/-/get-package-type-0.1.0.tgz", - "integrity": "sha512-pjzuKtY64GYfWizNAJ0fr9VqttZkNiK2iS430LtIHzjBEr6bX8Am2zm4sW4Ro5wjWW5cAlRL1qAMTcXbjNAO2Q==", - "dev": true - }, - "get-stream": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-6.0.1.tgz", - "integrity": "sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg==", - "dev": true - }, - "get-symbol-description": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/get-symbol-description/-/get-symbol-description-1.0.0.tgz", - "integrity": "sha512-2EmdH1YvIQiZpltCNgkuiUnyukzxM/R6NDJX31Ke3BG1Nq5b0S2PhX59UKi9vZpPDQVdqn+1IcaAwnzTT5vCjw==", - "dev": true, - "requires": { - "call-bind": "^1.0.2", - "get-intrinsic": "^1.1.1" - } - }, - "get-tsconfig": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/get-tsconfig/-/get-tsconfig-4.3.0.tgz", - "integrity": "sha512-YCcF28IqSay3fqpIu5y3Krg/utCBHBeoflkZyHj/QcqI2nrLPC3ZegS9CmIo+hJb8K7aiGsuUl7PwWVjNG2HQQ==", - "dev": true - }, - "glob": { - "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.1.1", - "once": "^1.3.0", - "path-is-absolute": "^1.0.0" - } - }, - "glob-parent": { - "version": "6.0.2", - "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz", - "integrity": "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==", - "dev": true, - "requires": { - "is-glob": "^4.0.3" - } - }, - "globals": { - "version": "13.19.0", - "resolved": "https://registry.npmjs.org/globals/-/globals-13.19.0.tgz", - "integrity": "sha512-dkQ957uSRWHw7CFXLUtUHQI3g3aWApYhfNR2O6jn/907riyTYKVBmxYVROkBcY614FSSeSJh7Xm7SrUWCxvJMQ==", - "dev": true, - "requires": { - "type-fest": "^0.20.2" - } - }, - "globalthis": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/globalthis/-/globalthis-1.0.3.tgz", - "integrity": "sha512-sFdI5LyBiNTHjRd7cGPWapiHWMOXKyuBNX/cWJ3NfzrZQVa8GI/8cofCl74AOVqq9W5kNmguTIzJ/1s2gyI9wA==", - "dev": true, - "requires": { - "define-properties": "^1.1.3" - } - }, - "globalyzer": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/globalyzer/-/globalyzer-0.1.0.tgz", - "integrity": "sha512-40oNTM9UfG6aBmuKxk/giHn5nQ8RVz/SS4Ir6zgzOv9/qC3kKZ9v4etGTcJbEl/NyVQH7FGU7d+X1egr57Md2Q==", - "dev": true - }, - "globby": { - "version": "11.1.0", - "resolved": "https://registry.npmjs.org/globby/-/globby-11.1.0.tgz", - "integrity": "sha512-jhIXaOzy1sb8IyocaruWSn1TjmnBVs8Ayhcy83rmxNJ8q2uWKCAj3CnJY+KpGSXCueAPc0i05kVvVKtP1t9S3g==", - "dev": true, - "requires": { - "array-union": "^2.1.0", - "dir-glob": "^3.0.1", - "fast-glob": "^3.2.9", - "ignore": "^5.2.0", - "merge2": "^1.4.1", - "slash": "^3.0.0" - } - }, - "globrex": { - "version": "0.1.2", - "resolved": "https://registry.npmjs.org/globrex/-/globrex-0.1.2.tgz", - "integrity": "sha512-uHJgbwAMwNFf5mLst7IWLNg14x1CkeqglJb/K3doi4dw6q2IvAAmM/Y81kevy83wP+Sst+nutFTYOGg3d1lsxg==", - "dev": true - }, - "gopd": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.0.1.tgz", - "integrity": "sha512-d65bNlIadxvpb/A2abVdlqKqV563juRnZ1Wtk6s1sIR8uNsXR70xqIzVqxVf1eTqDunwT2MkczEeaezCKTZhwA==", - "dev": true, - "requires": { - "get-intrinsic": "^1.1.3" - } - }, - "graceful-fs": { - "version": "4.2.10", - "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.10.tgz", - "integrity": "sha512-9ByhssR2fPVsNZj478qUUbKfmL0+t5BDVyjShtyZZLiK7ZDAArFFfopyOTj0M05wE2tJPisA4iTnnXl2YoPvOA==" - }, - "grapheme-splitter": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/grapheme-splitter/-/grapheme-splitter-1.0.4.tgz", - "integrity": "sha512-bzh50DW9kTPM00T8y4o8vQg89Di9oLJVLW/KaOGIXJWP/iqCN6WKYkbNOF04vFLJhwcpYUh9ydh/+5vpOqV4YQ==", - "dev": true - }, - "has": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz", - "integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==", - "dev": true, - "requires": { - "function-bind": "^1.1.1" - } - }, - "has-bigints": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/has-bigints/-/has-bigints-1.0.2.tgz", - "integrity": "sha512-tSvCKtBr9lkF0Ex0aQiP9N+OpV4zi2r/Nee5VkRDbaqv35RLYMzbwQfFSZZH0kR+Rd6302UJZ2p/bJCEoR3VoQ==", - "dev": true - }, - "has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "dev": true - }, - "has-property-descriptors": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/has-property-descriptors/-/has-property-descriptors-1.0.0.tgz", - "integrity": "sha512-62DVLZGoiEBDHQyqG4w9xCuZ7eJEwNmJRWw2VY84Oedb7WFcA27fiEVe8oUQx9hAUJ4ekurquucTGwsyO1XGdQ==", - "dev": true, - "requires": { - "get-intrinsic": "^1.1.1" - } - }, - "has-proto": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/has-proto/-/has-proto-1.0.1.tgz", - "integrity": "sha512-7qE+iP+O+bgF9clE5+UoBFzE65mlBiVj3tKCrlNQ0Ogwm0BjpT/gK4SlLYDMybDh5I3TCTKnPPa0oMG7JDYrhg==", - "dev": true - }, - "has-symbols": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.3.tgz", - "integrity": "sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A==", - "dev": true - }, - "has-tostringtag": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/has-tostringtag/-/has-tostringtag-1.0.0.tgz", - "integrity": "sha512-kFjcSNhnlGV1kyoGk7OXKSawH5JOb/LzUc5w9B02hOTO0dfFRjbHQKvg1d6cf3HbeUmtU9VbbV3qzZ2Teh97WQ==", - "dev": true, - "requires": { - "has-symbols": "^1.0.2" - } - }, - "html-escaper": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/html-escaper/-/html-escaper-2.0.2.tgz", - "integrity": "sha512-H2iMtd0I4Mt5eYiapRdIDjp+XzelXQ0tFE4JS7YFwFevXXMmOp9myNrUvCg0D6ws8iqkRPBfKHgbwig1SmlLfg==", - "dev": true - }, - "human-signals": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/human-signals/-/human-signals-2.1.0.tgz", - "integrity": "sha512-B4FFZ6q/T2jhhksgkbEW3HBvWIfDW85snkQgawt07S7J5QXTk6BkNV+0yAeZrM5QpMAdYlocGoljn0sJ/WQkFw==", - "dev": true - }, - "if-node-version": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/if-node-version/-/if-node-version-1.1.1.tgz", - "integrity": "sha512-qMcJD7ftbSWlf+6w8nzZAWKOELmG3xH5Gu5XYW2+f9uaYj1t9JX5KNWxnvNMGhu8f+uIUgnqFHLlwyKTHaLWWA==", - "requires": { - "cross-spawn": "^5.0.1", - "semver": "^5.2.0" - }, - "dependencies": { - "cross-spawn": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-5.1.0.tgz", - "integrity": "sha512-pTgQJ5KC0d2hcY8eyL1IzlBPYjTkyH72XRZPnLyKus2mBfNjQs3klqbJU2VILqZryAZUt9JOb3h/mWMy23/f5A==", - "requires": { - "lru-cache": "^4.0.1", - "shebang-command": "^1.2.0", - "which": "^1.2.9" - } - }, - "lru-cache": { - "version": "4.1.5", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-4.1.5.tgz", - "integrity": "sha512-sWZlbEP2OsHNkXrMl5GYk/jKk70MBng6UU4YI/qGDYbgf6YbP4EvmqISbXCoJiRKs+1bSpFHVgQxvJ17F2li5g==", - "requires": { - "pseudomap": "^1.0.2", - "yallist": "^2.1.2" - } - }, - "semver": { - "version": "5.7.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", - "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==" - }, - "shebang-command": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-1.2.0.tgz", - "integrity": "sha512-EV3L1+UQWGor21OmnvojK36mhg+TyIKDh3iFBKBohr5xeXIhNBcx8oWdgkTEEQ+BEFFYdLRuqMfd5L84N1V5Vg==", - "requires": { - "shebang-regex": "^1.0.0" - } - }, - "shebang-regex": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-1.0.0.tgz", - "integrity": "sha512-wpoSFAxys6b2a2wHZ1XpDSgD7N9iVjg29Ph9uV/uaP9Ex/KXlkTZTeddxDPSYQpgvzKLGJke2UU0AzoGCjNIvQ==" - }, - "which": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/which/-/which-1.3.1.tgz", - "integrity": "sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ==", - "requires": { - "isexe": "^2.0.0" - } - }, - "yallist": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-2.1.2.tgz", - "integrity": "sha512-ncTzHV7NvsQZkYe1DW7cbDLm0YpzHmZF5r/iyP3ZnQtMiJ+pjzisCiMNI+Sj+xQF5pXhSHxSB3uDbsBTzY/c2A==" - } - } - }, - "ignore": { - "version": "5.2.4", - "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.2.4.tgz", - "integrity": "sha512-MAb38BcSbH0eHNBxn7ql2NH/kX33OkB3lZ1BNdh7ENeRChHTYsTvWrMubiIAMNS2llXEEgZ1MUOBtXChP3kaFQ==" - }, - "import-fresh": { - "version": "3.3.0", - "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.0.tgz", - "integrity": "sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw==", - "dev": true, - "requires": { - "parent-module": "^1.0.0", - "resolve-from": "^4.0.0" - } - }, - "import-local": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/import-local/-/import-local-3.1.0.tgz", - "integrity": "sha512-ASB07uLtnDs1o6EHjKpX34BKYDSqnFerfTOJL2HvMqF70LnxpjkzDB8J44oT9pu4AMPkQwf8jl6szgvNd2tRIg==", - "dev": true, - "requires": { - "pkg-dir": "^4.2.0", - "resolve-cwd": "^3.0.0" - } - }, - "imurmurhash": { - "version": "0.1.4", - "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", - "integrity": "sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==", - "dev": true - }, - "inflight": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", - "integrity": "sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==", - "dev": true, - "requires": { - "once": "^1.3.0", - "wrappy": "1" - } - }, - "inherits": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", - "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", - "dev": true - }, - "internal-slot": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/internal-slot/-/internal-slot-1.0.4.tgz", - "integrity": "sha512-tA8URYccNzMo94s5MQZgH8NB/XTa6HsOo0MLfXTKKEnHVVdegzaQoFZ7Jp44bdvLvY2waT5dc+j5ICEswhi7UQ==", - "dev": true, - "requires": { - "get-intrinsic": "^1.1.3", - "has": "^1.0.3", - "side-channel": "^1.0.4" - } - }, - "is-array-buffer": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/is-array-buffer/-/is-array-buffer-3.0.1.tgz", - "integrity": "sha512-ASfLknmY8Xa2XtB4wmbz13Wu202baeA18cJBCeCy0wXUHZF0IPyVEXqKEcd+t2fNSLLL1vC6k7lxZEojNbISXQ==", - "dev": true, - "requires": { - "call-bind": "^1.0.2", - "get-intrinsic": "^1.1.3", - "is-typed-array": "^1.1.10" - } - }, - "is-arrayish": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz", - "integrity": "sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg==", - "dev": true - }, - "is-bigint": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/is-bigint/-/is-bigint-1.0.4.tgz", - "integrity": "sha512-zB9CruMamjym81i2JZ3UMn54PKGsQzsJeo6xvN3HJJ4CAsQNB6iRutp2To77OfCNuoxspsIhzaPoO1zyCEhFOg==", - "dev": true, - "requires": { - "has-bigints": "^1.0.1" - } - }, - "is-boolean-object": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/is-boolean-object/-/is-boolean-object-1.1.2.tgz", - "integrity": "sha512-gDYaKHJmnj4aWxyj6YHyXVpdQawtVLHU5cb+eztPGczf6cjuTdwve5ZIEfgXqH4e57An1D1AKf8CZ3kYrQRqYA==", - "dev": true, - "requires": { - "call-bind": "^1.0.2", - "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.7", - "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.2.7.tgz", - "integrity": "sha512-1BC0BVFhS/p0qtw6enp8e+8OD0UrK0oFLztSjNzhcKA3WDuJxxAPXzPuPtKkjEY9UUoEWlX/8fgKeu2S8i9JTA==", - "dev": true - }, - "is-core-module": { - "version": "2.11.0", - "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.11.0.tgz", - "integrity": "sha512-RRjxlvLDkD1YJwDbroBHMb+cukurkDWNyHx7D3oNB5x9rb5ogcksMC5wHCadcXoo67gVr/+3GFySh3134zi6rw==", - "dev": true, - "requires": { - "has": "^1.0.3" - } - }, - "is-date-object": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/is-date-object/-/is-date-object-1.0.5.tgz", - "integrity": "sha512-9YQaSxsAiSwcvS33MBk3wTCVnWK+HhF8VZR2jRxehM16QcVOdHqPn4VPHmRK4lSr38n9JriurInLcP90xsYNfQ==", - "dev": true, - "requires": { - "has-tostringtag": "^1.0.0" - } - }, - "is-docker": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/is-docker/-/is-docker-2.2.1.tgz", - "integrity": "sha512-F+i2BKsFrH66iaUFc0woD8sLy8getkwTwtOBjvs56Cx4CgJDeKQeqfz8wAYiSb8JOprWhHH5p77PbmYCvvUuXQ==", - "dev": true - }, - "is-extglob": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", - "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==", - "dev": true - }, - "is-fullwidth-code-point": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", - "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", - "dev": true - }, - "is-generator-fn": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/is-generator-fn/-/is-generator-fn-2.1.0.tgz", - "integrity": "sha512-cTIB4yPYL/Grw0EaSzASzg6bBy9gqCofvWN8okThAYIxKJZC+udlRAmGbM0XLeniEJSs8uEgHPGuHSe1XsOLSQ==", - "dev": true - }, - "is-glob": { - "version": "4.0.3", - "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", - "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", - "dev": true, - "requires": { - "is-extglob": "^2.1.1" - } - }, - "is-negative-zero": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/is-negative-zero/-/is-negative-zero-2.0.2.tgz", - "integrity": "sha512-dqJvarLawXsFbNDeJW7zAz8ItJ9cd28YufuuFzh0G8pNHjJMnY08Dv7sYX2uF5UpQOwieAeOExEYAWWfu7ZZUA==", - "dev": true - }, - "is-number": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", - "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", - "dev": true - }, - "is-number-object": { - "version": "1.0.7", - "resolved": "https://registry.npmjs.org/is-number-object/-/is-number-object-1.0.7.tgz", - "integrity": "sha512-k1U0IRzLMo7ZlYIfzRu23Oh6MiIFasgpb9X76eqfFZAqwH44UI4KTBvBYIZ1dSL9ZzChTB9ShHfLkR4pdW5krQ==", - "dev": true, - "requires": { - "has-tostringtag": "^1.0.0" - } - }, - "is-path-inside": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/is-path-inside/-/is-path-inside-3.0.3.tgz", - "integrity": "sha512-Fd4gABb+ycGAmKou8eMftCupSir5lRxqf4aD/vd0cD2qc4HL07OjCeuHMr8Ro4CoMaeCKDB0/ECBOVWjTwUvPQ==", - "dev": true - }, - "is-regex": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.1.4.tgz", - "integrity": "sha512-kvRdxDsxZjhzUX07ZnLydzS1TU/TJlTUHHY4YLL87e37oUA49DfkLqgy+VjFocowy29cKvcSiu+kIv728jTTVg==", - "dev": true, - "requires": { - "call-bind": "^1.0.2", - "has-tostringtag": "^1.0.0" - } - }, - "is-shared-array-buffer": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/is-shared-array-buffer/-/is-shared-array-buffer-1.0.2.tgz", - "integrity": "sha512-sqN2UDu1/0y6uvXyStCOzyhAjCSlHceFoMKJW8W9EU9cvic/QdsZ0kEU93HEy3IUEFZIiH/3w+AH/UQbPHNdhA==", - "dev": true, - "requires": { - "call-bind": "^1.0.2" - } - }, - "is-stream": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-2.0.1.tgz", - "integrity": "sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==", - "dev": true - }, - "is-string": { - "version": "1.0.7", - "resolved": "https://registry.npmjs.org/is-string/-/is-string-1.0.7.tgz", - "integrity": "sha512-tE2UXzivje6ofPW7l23cjDOMa09gb7xlAqG6jG5ej6uPV32TlWP3NKPigtaGeHNu9fohccRYvIiZMfOOnOYUtg==", - "dev": true, - "requires": { - "has-tostringtag": "^1.0.0" - } - }, - "is-symbol": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/is-symbol/-/is-symbol-1.0.4.tgz", - "integrity": "sha512-C/CPBqKWnvdcxqIARxyOh4v1UUEOCHpgDa0WYgpKDFMszcrPcffg5uhwSgPCLD2WWxmq6isisz87tzT01tuGhg==", - "dev": true, - "requires": { - "has-symbols": "^1.0.2" - } - }, - "is-typed-array": { - "version": "1.1.10", - "resolved": "https://registry.npmjs.org/is-typed-array/-/is-typed-array-1.1.10.tgz", - "integrity": "sha512-PJqgEHiWZvMpaFZ3uTc8kHPM4+4ADTlDniuQL7cU/UDA0Ql7F70yGfHph3cLNe+c9toaigv+DFzTJKhc2CtO6A==", - "dev": true, - "requires": { - "available-typed-arrays": "^1.0.5", - "call-bind": "^1.0.2", - "for-each": "^0.3.3", - "gopd": "^1.0.1", - "has-tostringtag": "^1.0.0" - } - }, - "is-weakref": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/is-weakref/-/is-weakref-1.0.2.tgz", - "integrity": "sha512-qctsuLZmIQ0+vSSMfoVvyFe2+GSEvnmZ2ezTup1SBse9+twCCeial6EEi3Nc2KFcf6+qz2FBPnjXsk8xhKSaPQ==", - "dev": true, - "requires": { - "call-bind": "^1.0.2" - } - }, - "is-wsl": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/is-wsl/-/is-wsl-2.2.0.tgz", - "integrity": "sha512-fKzAra0rGJUUBwGBgNkHZuToZcn+TtXHpeCgmkMJMMYx1sQDYaCSyjJBSCa2nH1DGm7s3n1oBnohoVTBaN7Lww==", - "dev": true, - "requires": { - "is-docker": "^2.0.0" - } - }, - "isexe": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", - "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==" - }, - "istanbul-lib-coverage": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/istanbul-lib-coverage/-/istanbul-lib-coverage-3.2.0.tgz", - "integrity": "sha512-eOeJ5BHCmHYvQK7xt9GkdHuzuCGS1Y6g9Gvnx3Ym33fz/HpLRYxiS0wHNr+m/MBC8B647Xt608vCDEvhl9c6Mw==", - "dev": true - }, - "istanbul-lib-instrument": { - "version": "5.2.1", - "resolved": "https://registry.npmjs.org/istanbul-lib-instrument/-/istanbul-lib-instrument-5.2.1.tgz", - "integrity": "sha512-pzqtp31nLv/XFOzXGuvhCb8qhjmTVo5vjVk19XE4CRlSWz0KoeJ3bw9XsA7nOp9YBf4qHjwBxkDzKcME/J29Yg==", - "dev": true, - "requires": { - "@babel/core": "^7.12.3", - "@babel/parser": "^7.14.7", - "@istanbuljs/schema": "^0.1.2", - "istanbul-lib-coverage": "^3.2.0", - "semver": "^6.3.0" - }, - "dependencies": { - "semver": { - "version": "6.3.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", - "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", - "dev": true - } - } - }, - "istanbul-lib-report": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/istanbul-lib-report/-/istanbul-lib-report-3.0.0.tgz", - "integrity": "sha512-wcdi+uAKzfiGT2abPpKZ0hSU1rGQjUQnLvtY5MpQ7QCTahD3VODhcu4wcfY1YtkGaDD5yuydOLINXsfbus9ROw==", - "dev": true, - "requires": { - "istanbul-lib-coverage": "^3.0.0", - "make-dir": "^3.0.0", - "supports-color": "^7.1.0" - } - }, - "istanbul-lib-source-maps": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/istanbul-lib-source-maps/-/istanbul-lib-source-maps-4.0.1.tgz", - "integrity": "sha512-n3s8EwkdFIJCG3BPKBYvskgXGoy88ARzvegkitk60NxRdwltLOTaH7CUiMRXvwYorl0Q712iEjcWB+fK/MrWVw==", - "dev": true, - "requires": { - "debug": "^4.1.1", - "istanbul-lib-coverage": "^3.0.0", - "source-map": "^0.6.1" - } - }, - "istanbul-reports": { - "version": "3.1.5", - "resolved": "https://registry.npmjs.org/istanbul-reports/-/istanbul-reports-3.1.5.tgz", - "integrity": "sha512-nUsEMa9pBt/NOHqbcbeJEgqIlY/K7rVWUX6Lql2orY5e9roQOthbR3vtY4zzf2orPELg80fnxxk9zUyPlgwD1w==", - "dev": true, - "requires": { - "html-escaper": "^2.0.0", - "istanbul-lib-report": "^3.0.0" - } - }, - "jest": { - "version": "29.3.1", - "resolved": "https://registry.npmjs.org/jest/-/jest-29.3.1.tgz", - "integrity": "sha512-6iWfL5DTT0Np6UYs/y5Niu7WIfNv/wRTtN5RSXt2DIEft3dx3zPuw/3WJQBCJfmEzvDiEKwoqMbGD9n49+qLSA==", - "dev": true, - "requires": { - "@jest/core": "^29.3.1", - "@jest/types": "^29.3.1", - "import-local": "^3.0.2", - "jest-cli": "^29.3.1" - } - }, - "jest-changed-files": { - "version": "29.2.0", - "resolved": "https://registry.npmjs.org/jest-changed-files/-/jest-changed-files-29.2.0.tgz", - "integrity": "sha512-qPVmLLyBmvF5HJrY7krDisx6Voi8DmlV3GZYX0aFNbaQsZeoz1hfxcCMbqDGuQCxU1dJy9eYc2xscE8QrCCYaA==", - "dev": true, - "requires": { - "execa": "^5.0.0", - "p-limit": "^3.1.0" - } - }, - "jest-circus": { - "version": "29.3.1", - "resolved": "https://registry.npmjs.org/jest-circus/-/jest-circus-29.3.1.tgz", - "integrity": "sha512-wpr26sEvwb3qQQbdlmei+gzp6yoSSoSL6GsLPxnuayZSMrSd5Ka7IjAvatpIernBvT2+Ic6RLTg+jSebScmasg==", - "dev": true, - "requires": { - "@jest/environment": "^29.3.1", - "@jest/expect": "^29.3.1", - "@jest/test-result": "^29.3.1", - "@jest/types": "^29.3.1", - "@types/node": "*", - "chalk": "^4.0.0", - "co": "^4.6.0", - "dedent": "^0.7.0", - "is-generator-fn": "^2.0.0", - "jest-each": "^29.3.1", - "jest-matcher-utils": "^29.3.1", - "jest-message-util": "^29.3.1", - "jest-runtime": "^29.3.1", - "jest-snapshot": "^29.3.1", - "jest-util": "^29.3.1", - "p-limit": "^3.1.0", - "pretty-format": "^29.3.1", - "slash": "^3.0.0", - "stack-utils": "^2.0.3" - } - }, - "jest-cli": { - "version": "29.3.1", - "resolved": "https://registry.npmjs.org/jest-cli/-/jest-cli-29.3.1.tgz", - "integrity": "sha512-TO/ewvwyvPOiBBuWZ0gm04z3WWP8TIK8acgPzE4IxgsLKQgb377NYGrQLc3Wl/7ndWzIH2CDNNsUjGxwLL43VQ==", - "dev": true, - "requires": { - "@jest/core": "^29.3.1", - "@jest/test-result": "^29.3.1", - "@jest/types": "^29.3.1", - "chalk": "^4.0.0", - "exit": "^0.1.2", - "graceful-fs": "^4.2.9", - "import-local": "^3.0.2", - "jest-config": "^29.3.1", - "jest-util": "^29.3.1", - "jest-validate": "^29.3.1", - "prompts": "^2.0.1", - "yargs": "^17.3.1" - } - }, - "jest-config": { - "version": "29.3.1", - "resolved": "https://registry.npmjs.org/jest-config/-/jest-config-29.3.1.tgz", - "integrity": "sha512-y0tFHdj2WnTEhxmGUK1T7fgLen7YK4RtfvpLFBXfQkh2eMJAQq24Vx9472lvn5wg0MAO6B+iPfJfzdR9hJYalg==", - "dev": true, - "requires": { - "@babel/core": "^7.11.6", - "@jest/test-sequencer": "^29.3.1", - "@jest/types": "^29.3.1", - "babel-jest": "^29.3.1", - "chalk": "^4.0.0", - "ci-info": "^3.2.0", - "deepmerge": "^4.2.2", - "glob": "^7.1.3", - "graceful-fs": "^4.2.9", - "jest-circus": "^29.3.1", - "jest-environment-node": "^29.3.1", - "jest-get-type": "^29.2.0", - "jest-regex-util": "^29.2.0", - "jest-resolve": "^29.3.1", - "jest-runner": "^29.3.1", - "jest-util": "^29.3.1", - "jest-validate": "^29.3.1", - "micromatch": "^4.0.4", - "parse-json": "^5.2.0", - "pretty-format": "^29.3.1", - "slash": "^3.0.0", - "strip-json-comments": "^3.1.1" - } - }, - "jest-diff": { - "version": "29.3.1", - "resolved": "https://registry.npmjs.org/jest-diff/-/jest-diff-29.3.1.tgz", - "integrity": "sha512-vU8vyiO7568tmin2lA3r2DP8oRvzhvRcD4DjpXc6uGveQodyk7CKLhQlCSiwgx3g0pFaE88/KLZ0yaTWMc4Uiw==", - "dev": true, - "requires": { - "chalk": "^4.0.0", - "diff-sequences": "^29.3.1", - "jest-get-type": "^29.2.0", - "pretty-format": "^29.3.1" - } - }, - "jest-docblock": { - "version": "29.2.0", - "resolved": "https://registry.npmjs.org/jest-docblock/-/jest-docblock-29.2.0.tgz", - "integrity": "sha512-bkxUsxTgWQGbXV5IENmfiIuqZhJcyvF7tU4zJ/7ioTutdz4ToB5Yx6JOFBpgI+TphRY4lhOyCWGNH/QFQh5T6A==", - "dev": true, - "requires": { - "detect-newline": "^3.0.0" - } - }, - "jest-each": { - "version": "29.3.1", - "resolved": "https://registry.npmjs.org/jest-each/-/jest-each-29.3.1.tgz", - "integrity": "sha512-qrZH7PmFB9rEzCSl00BWjZYuS1BSOH8lLuC0azQE9lQrAx3PWGKHTDudQiOSwIy5dGAJh7KA0ScYlCP7JxvFYA==", - "dev": true, - "requires": { - "@jest/types": "^29.3.1", - "chalk": "^4.0.0", - "jest-get-type": "^29.2.0", - "jest-util": "^29.3.1", - "pretty-format": "^29.3.1" - } - }, - "jest-environment-node": { - "version": "29.3.1", - "resolved": "https://registry.npmjs.org/jest-environment-node/-/jest-environment-node-29.3.1.tgz", - "integrity": "sha512-xm2THL18Xf5sIHoU7OThBPtuH6Lerd+Y1NLYiZJlkE3hbE+7N7r8uvHIl/FkZ5ymKXJe/11SQuf3fv4v6rUMag==", - "dev": true, - "requires": { - "@jest/environment": "^29.3.1", - "@jest/fake-timers": "^29.3.1", - "@jest/types": "^29.3.1", - "@types/node": "*", - "jest-mock": "^29.3.1", - "jest-util": "^29.3.1" - } - }, - "jest-get-type": { - "version": "29.2.0", - "resolved": "https://registry.npmjs.org/jest-get-type/-/jest-get-type-29.2.0.tgz", - "integrity": "sha512-uXNJlg8hKFEnDgFsrCjznB+sTxdkuqiCL6zMgA75qEbAJjJYTs9XPrvDctrEig2GDow22T/LvHgO57iJhXB/UA==", - "dev": true - }, - "jest-haste-map": { - "version": "29.3.1", - "resolved": "https://registry.npmjs.org/jest-haste-map/-/jest-haste-map-29.3.1.tgz", - "integrity": "sha512-/FFtvoG1xjbbPXQLFef+WSU4yrc0fc0Dds6aRPBojUid7qlPqZvxdUBA03HW0fnVHXVCnCdkuoghYItKNzc/0A==", - "dev": true, - "requires": { - "@jest/types": "^29.3.1", - "@types/graceful-fs": "^4.1.3", - "@types/node": "*", - "anymatch": "^3.0.3", - "fb-watchman": "^2.0.0", - "fsevents": "^2.3.2", - "graceful-fs": "^4.2.9", - "jest-regex-util": "^29.2.0", - "jest-util": "^29.3.1", - "jest-worker": "^29.3.1", - "micromatch": "^4.0.4", - "walker": "^1.0.8" - } - }, - "jest-leak-detector": { - "version": "29.3.1", - "resolved": "https://registry.npmjs.org/jest-leak-detector/-/jest-leak-detector-29.3.1.tgz", - "integrity": "sha512-3DA/VVXj4zFOPagGkuqHnSQf1GZBmmlagpguxEERO6Pla2g84Q1MaVIB3YMxgUaFIaYag8ZnTyQgiZ35YEqAQA==", - "dev": true, - "requires": { - "jest-get-type": "^29.2.0", - "pretty-format": "^29.3.1" - } - }, - "jest-matcher-utils": { - "version": "29.3.1", - "resolved": "https://registry.npmjs.org/jest-matcher-utils/-/jest-matcher-utils-29.3.1.tgz", - "integrity": "sha512-fkRMZUAScup3txIKfMe3AIZZmPEjWEdsPJFK3AIy5qRohWqQFg1qrmKfYXR9qEkNc7OdAu2N4KPHibEmy4HPeQ==", - "dev": true, - "requires": { - "chalk": "^4.0.0", - "jest-diff": "^29.3.1", - "jest-get-type": "^29.2.0", - "pretty-format": "^29.3.1" - } - }, - "jest-message-util": { - "version": "29.3.1", - "resolved": "https://registry.npmjs.org/jest-message-util/-/jest-message-util-29.3.1.tgz", - "integrity": "sha512-lMJTbgNcDm5z+6KDxWtqOFWlGQxD6XaYwBqHR8kmpkP+WWWG90I35kdtQHY67Ay5CSuydkTBbJG+tH9JShFCyA==", - "dev": true, - "requires": { - "@babel/code-frame": "^7.12.13", - "@jest/types": "^29.3.1", - "@types/stack-utils": "^2.0.0", - "chalk": "^4.0.0", - "graceful-fs": "^4.2.9", - "micromatch": "^4.0.4", - "pretty-format": "^29.3.1", - "slash": "^3.0.0", - "stack-utils": "^2.0.3" - } - }, - "jest-mock": { - "version": "29.3.1", - "resolved": "https://registry.npmjs.org/jest-mock/-/jest-mock-29.3.1.tgz", - "integrity": "sha512-H8/qFDtDVMFvFP4X8NuOT3XRDzOUTz+FeACjufHzsOIBAxivLqkB1PoLCaJx9iPPQ8dZThHPp/G3WRWyMgA3JA==", - "dev": true, - "requires": { - "@jest/types": "^29.3.1", - "@types/node": "*", - "jest-util": "^29.3.1" - } - }, - "jest-pnp-resolver": { - "version": "1.2.3", - "resolved": "https://registry.npmjs.org/jest-pnp-resolver/-/jest-pnp-resolver-1.2.3.tgz", - "integrity": "sha512-+3NpwQEnRoIBtx4fyhblQDPgJI0H1IEIkX7ShLUjPGA7TtUTvI1oiKi3SR4oBR0hQhQR80l4WAe5RrXBwWMA8w==", - "dev": true, - "requires": {} - }, - "jest-regex-util": { - "version": "29.2.0", - "resolved": "https://registry.npmjs.org/jest-regex-util/-/jest-regex-util-29.2.0.tgz", - "integrity": "sha512-6yXn0kg2JXzH30cr2NlThF+70iuO/3irbaB4mh5WyqNIvLLP+B6sFdluO1/1RJmslyh/f9osnefECflHvTbwVA==", - "dev": true - }, - "jest-resolve": { - "version": "29.3.1", - "resolved": "https://registry.npmjs.org/jest-resolve/-/jest-resolve-29.3.1.tgz", - "integrity": "sha512-amXJgH/Ng712w3Uz5gqzFBBjxV8WFLSmNjoreBGMqxgCz5cH7swmBZzgBaCIOsvb0NbpJ0vgaSFdJqMdT+rADw==", - "dev": true, - "requires": { - "chalk": "^4.0.0", - "graceful-fs": "^4.2.9", - "jest-haste-map": "^29.3.1", - "jest-pnp-resolver": "^1.2.2", - "jest-util": "^29.3.1", - "jest-validate": "^29.3.1", - "resolve": "^1.20.0", - "resolve.exports": "^1.1.0", - "slash": "^3.0.0" - } - }, - "jest-resolve-dependencies": { - "version": "29.3.1", - "resolved": "https://registry.npmjs.org/jest-resolve-dependencies/-/jest-resolve-dependencies-29.3.1.tgz", - "integrity": "sha512-Vk0cYq0byRw2WluNmNWGqPeRnZ3p3hHmjJMp2dyyZeYIfiBskwq4rpiuGFR6QGAdbj58WC7HN4hQHjf2mpvrLA==", - "dev": true, - "requires": { - "jest-regex-util": "^29.2.0", - "jest-snapshot": "^29.3.1" - } - }, - "jest-runner": { - "version": "29.3.1", - "resolved": "https://registry.npmjs.org/jest-runner/-/jest-runner-29.3.1.tgz", - "integrity": "sha512-oFvcwRNrKMtE6u9+AQPMATxFcTySyKfLhvso7Sdk/rNpbhg4g2GAGCopiInk1OP4q6gz3n6MajW4+fnHWlU3bA==", - "dev": true, - "requires": { - "@jest/console": "^29.3.1", - "@jest/environment": "^29.3.1", - "@jest/test-result": "^29.3.1", - "@jest/transform": "^29.3.1", - "@jest/types": "^29.3.1", - "@types/node": "*", - "chalk": "^4.0.0", - "emittery": "^0.13.1", - "graceful-fs": "^4.2.9", - "jest-docblock": "^29.2.0", - "jest-environment-node": "^29.3.1", - "jest-haste-map": "^29.3.1", - "jest-leak-detector": "^29.3.1", - "jest-message-util": "^29.3.1", - "jest-resolve": "^29.3.1", - "jest-runtime": "^29.3.1", - "jest-util": "^29.3.1", - "jest-watcher": "^29.3.1", - "jest-worker": "^29.3.1", - "p-limit": "^3.1.0", - "source-map-support": "0.5.13" - }, - "dependencies": { - "source-map-support": { - "version": "0.5.13", - "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.13.tgz", - "integrity": "sha512-SHSKFHadjVA5oR4PPqhtAVdcBWwRYVd6g6cAXnIbRiIwc2EhPrTuKUBdSLvlEKyIP3GCf89fltvcZiP9MMFA1w==", - "dev": true, - "requires": { - "buffer-from": "^1.0.0", - "source-map": "^0.6.0" - } - } - } - }, - "jest-runtime": { - "version": "29.3.1", - "resolved": "https://registry.npmjs.org/jest-runtime/-/jest-runtime-29.3.1.tgz", - "integrity": "sha512-jLzkIxIqXwBEOZx7wx9OO9sxoZmgT2NhmQKzHQm1xwR1kNW/dn0OjxR424VwHHf1SPN6Qwlb5pp1oGCeFTQ62A==", - "dev": true, - "requires": { - "@jest/environment": "^29.3.1", - "@jest/fake-timers": "^29.3.1", - "@jest/globals": "^29.3.1", - "@jest/source-map": "^29.2.0", - "@jest/test-result": "^29.3.1", - "@jest/transform": "^29.3.1", - "@jest/types": "^29.3.1", - "@types/node": "*", - "chalk": "^4.0.0", - "cjs-module-lexer": "^1.0.0", - "collect-v8-coverage": "^1.0.0", - "glob": "^7.1.3", - "graceful-fs": "^4.2.9", - "jest-haste-map": "^29.3.1", - "jest-message-util": "^29.3.1", - "jest-mock": "^29.3.1", - "jest-regex-util": "^29.2.0", - "jest-resolve": "^29.3.1", - "jest-snapshot": "^29.3.1", - "jest-util": "^29.3.1", - "slash": "^3.0.0", - "strip-bom": "^4.0.0" - } - }, - "jest-snapshot": { - "version": "29.3.1", - "resolved": "https://registry.npmjs.org/jest-snapshot/-/jest-snapshot-29.3.1.tgz", - "integrity": "sha512-+3JOc+s28upYLI2OJM4PWRGK9AgpsMs/ekNryUV0yMBClT9B1DF2u2qay8YxcQd338PPYSFNb0lsar1B49sLDA==", - "dev": true, - "requires": { - "@babel/core": "^7.11.6", - "@babel/generator": "^7.7.2", - "@babel/plugin-syntax-jsx": "^7.7.2", - "@babel/plugin-syntax-typescript": "^7.7.2", - "@babel/traverse": "^7.7.2", - "@babel/types": "^7.3.3", - "@jest/expect-utils": "^29.3.1", - "@jest/transform": "^29.3.1", - "@jest/types": "^29.3.1", - "@types/babel__traverse": "^7.0.6", - "@types/prettier": "^2.1.5", - "babel-preset-current-node-syntax": "^1.0.0", - "chalk": "^4.0.0", - "expect": "^29.3.1", - "graceful-fs": "^4.2.9", - "jest-diff": "^29.3.1", - "jest-get-type": "^29.2.0", - "jest-haste-map": "^29.3.1", - "jest-matcher-utils": "^29.3.1", - "jest-message-util": "^29.3.1", - "jest-util": "^29.3.1", - "natural-compare": "^1.4.0", - "pretty-format": "^29.3.1", - "semver": "^7.3.5" - } - }, - "jest-util": { - "version": "29.3.1", - "resolved": "https://registry.npmjs.org/jest-util/-/jest-util-29.3.1.tgz", - "integrity": "sha512-7YOVZaiX7RJLv76ZfHt4nbNEzzTRiMW/IiOG7ZOKmTXmoGBxUDefgMAxQubu6WPVqP5zSzAdZG0FfLcC7HOIFQ==", - "dev": true, - "requires": { - "@jest/types": "^29.3.1", - "@types/node": "*", - "chalk": "^4.0.0", - "ci-info": "^3.2.0", - "graceful-fs": "^4.2.9", - "picomatch": "^2.2.3" - } - }, - "jest-validate": { - "version": "29.3.1", - "resolved": "https://registry.npmjs.org/jest-validate/-/jest-validate-29.3.1.tgz", - "integrity": "sha512-N9Lr3oYR2Mpzuelp1F8negJR3YE+L1ebk1rYA5qYo9TTY3f9OWdptLoNSPP9itOCBIRBqjt/S5XHlzYglLN67g==", - "dev": true, - "requires": { - "@jest/types": "^29.3.1", - "camelcase": "^6.2.0", - "chalk": "^4.0.0", - "jest-get-type": "^29.2.0", - "leven": "^3.1.0", - "pretty-format": "^29.3.1" - }, - "dependencies": { - "camelcase": { - "version": "6.3.0", - "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-6.3.0.tgz", - "integrity": "sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA==", - "dev": true - } - } - }, - "jest-watcher": { - "version": "29.3.1", - "resolved": "https://registry.npmjs.org/jest-watcher/-/jest-watcher-29.3.1.tgz", - "integrity": "sha512-RspXG2BQFDsZSRKGCT/NiNa8RkQ1iKAjrO0//soTMWx/QUt+OcxMqMSBxz23PYGqUuWm2+m2mNNsmj0eIoOaFg==", - "dev": true, - "requires": { - "@jest/test-result": "^29.3.1", - "@jest/types": "^29.3.1", - "@types/node": "*", - "ansi-escapes": "^4.2.1", - "chalk": "^4.0.0", - "emittery": "^0.13.1", - "jest-util": "^29.3.1", - "string-length": "^4.0.1" - } - }, - "jest-worker": { - "version": "29.3.1", - "resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-29.3.1.tgz", - "integrity": "sha512-lY4AnnmsEWeiXirAIA0c9SDPbuCBq8IYuDVL8PMm0MZ2PEs2yPvRA/J64QBXuZp7CYKrDM/rmNrc9/i3KJQncw==", - "dev": true, - "requires": { - "@types/node": "*", - "jest-util": "^29.3.1", - "merge-stream": "^2.0.0", - "supports-color": "^8.0.0" - }, - "dependencies": { - "supports-color": { - "version": "8.1.1", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz", - "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==", - "dev": true, - "requires": { - "has-flag": "^4.0.0" - } - } - } - }, - "js-sdsl": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/js-sdsl/-/js-sdsl-4.2.0.tgz", - "integrity": "sha512-dyBIzQBDkCqCu+0upx25Y2jGdbTGxE9fshMsCdK0ViOongpV+n5tXRcZY9v7CaVQ79AGS9KA1KHtojxiM7aXSQ==", - "dev": true - }, - "js-tokens": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", - "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==", - "dev": true - }, - "js-yaml": { - "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": "^2.0.1" - } - }, - "jsesc": { - "version": "2.5.2", - "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-2.5.2.tgz", - "integrity": "sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA==", - "dev": true - }, - "json-parse-even-better-errors": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/json-parse-even-better-errors/-/json-parse-even-better-errors-2.3.1.tgz", - "integrity": "sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==", - "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 - }, - "json-stable-stringify-without-jsonify": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz", - "integrity": "sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==", - "dev": true - }, - "json5": { - "version": "2.2.3", - "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.3.tgz", - "integrity": "sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==", - "dev": true - }, - "jsonfile": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-6.1.0.tgz", - "integrity": "sha512-5dgndWOriYSm5cnYaJNhalLNDKOqFwyDB/rr1E9ZsGciGvKPs8R2xYGCacuf3z6K1YKDz182fd+fY3cn3pMqXQ==", - "requires": { - "graceful-fs": "^4.1.6", - "universalify": "^2.0.0" - } - }, - "kleur": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/kleur/-/kleur-3.0.3.tgz", - "integrity": "sha512-eTIzlVOSUR+JxdDFepEYcBMtZ9Qqdef+rnzWdRZuMbOywu5tO2w2N7rqjoANZ5k9vywhL6Br1VRjUIgTQx4E8w==", - "dev": true - }, - "leven": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/leven/-/leven-3.1.0.tgz", - "integrity": "sha512-qsda+H8jTaUaN/x5vzW2rzc+8Rw4TAQ/4KjB46IwK5VH+IlVeeeje/EoZRpiXvIqjFgK84QffqPztGI3VBLG1A==", - "dev": true - }, - "levn": { - "version": "0.4.1", - "resolved": "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz", - "integrity": "sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==", - "dev": true, - "requires": { - "prelude-ls": "^1.2.1", - "type-check": "~0.4.0" - } - }, - "lines-and-columns": { - "version": "1.2.4", - "resolved": "https://registry.npmjs.org/lines-and-columns/-/lines-and-columns-1.2.4.tgz", - "integrity": "sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==", - "dev": true - }, - "locate-path": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz", - "integrity": "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==", - "dev": true, - "requires": { - "p-locate": "^5.0.0" - } - }, - "lodash.memoize": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/lodash.memoize/-/lodash.memoize-4.1.2.tgz", - "integrity": "sha512-t7j+NzmgnQzTAYXcsHYLgimltOV1MXHtlOWf6GjL9Kj8GK5FInw5JotxvbOs+IvV1/Dzo04/fCGfLVs7aXb4Ag==", - "dev": true - }, - "lodash.merge": { - "version": "4.6.2", - "resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz", - "integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==", - "dev": true - }, - "lodash.truncate": { - "version": "4.4.2", - "resolved": "https://registry.npmjs.org/lodash.truncate/-/lodash.truncate-4.4.2.tgz", - "integrity": "sha512-jttmRe7bRse52OsWIMDLaXxWqRAmtIUccAQ3garviCqJjafXOfNMO0yMfNpdD6zbGaTU0P5Nz7e7gAT6cKmJRw==", - "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==", - "dev": true, - "requires": { - "yallist": "^3.0.2" - } - }, - "make-dir": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-3.1.0.tgz", - "integrity": "sha512-g3FeP20LNwhALb/6Cz6Dd4F2ngze0jz7tbzrD2wAV+o9FeNHe4rL+yK2md0J/fiSf1sa1ADhXqi5+oVwOM/eGw==", - "dev": true, - "requires": { - "semver": "^6.0.0" - }, - "dependencies": { - "semver": { - "version": "6.3.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", - "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", - "dev": true - } - } - }, - "make-error": { - "version": "1.3.6", - "resolved": "https://registry.npmjs.org/make-error/-/make-error-1.3.6.tgz", - "integrity": "sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw==", - "dev": true - }, - "makeerror": { - "version": "1.0.12", - "resolved": "https://registry.npmjs.org/makeerror/-/makeerror-1.0.12.tgz", - "integrity": "sha512-JmqCvUhmt43madlpFzG4BQzG2Z3m6tvQDNKdClZnO3VbIudJYmxsT0FNJMeiB2+JTSlTQTSbU8QdesVmwJcmLg==", - "dev": true, - "requires": { - "tmpl": "1.0.5" - } - }, - "md5": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/md5/-/md5-2.3.0.tgz", - "integrity": "sha512-T1GITYmFaKuO91vxyoQMFETst+O71VUPEU3ze5GNzDm0OWdP8v1ziTaAEPUr/3kLsY3Sftgz242A1SetQiDL7g==", - "dev": true, - "requires": { - "charenc": "0.0.2", - "crypt": "0.0.2", - "is-buffer": "~1.1.6" - } - }, - "merge-stream": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/merge-stream/-/merge-stream-2.0.0.tgz", - "integrity": "sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==", - "dev": true - }, - "merge2": { - "version": "1.4.1", - "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz", - "integrity": "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==", - "dev": true - }, - "micromatch": { - "version": "4.0.5", - "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.5.tgz", - "integrity": "sha512-DMy+ERcEW2q8Z2Po+WNXuw3c5YaUSFjAO5GsJqfEl7UjvtIuFKO6ZrKvcItdy98dwFI2N1tg3zNIdKaQT+aNdA==", - "dev": true, - "requires": { - "braces": "^3.0.2", - "picomatch": "^2.3.1" - } - }, - "mimic-fn": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-2.1.0.tgz", - "integrity": "sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==", - "dev": true - }, - "minimatch": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", - "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", - "requires": { - "brace-expansion": "^1.1.7" - } - }, - "minimist": { - "version": "1.2.7", - "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.7.tgz", - "integrity": "sha512-bzfL1YUZsP41gmu/qjrEk0Q6i2ix/cVeAhbCbqH9u3zYutS1cLg00qhrD0M2MVdCcx4Sc0UpP2eBWo9rotpq6g==", - "dev": true - }, - "ms": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", - "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", - "dev": true - }, - "natural-compare": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz", - "integrity": "sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==", - "dev": true - }, - "natural-compare-lite": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/natural-compare-lite/-/natural-compare-lite-1.4.0.tgz", - "integrity": "sha512-Tj+HTDSJJKaZnfiuw+iaF9skdPpTo2GtEly5JHnWV/hfv2Qj/9RKsGISQtLh2ox3l5EAGw487hnBee0sIJ6v2g==", - "dev": true - }, - "node-int64": { - "version": "0.4.0", - "resolved": "https://registry.npmjs.org/node-int64/-/node-int64-0.4.0.tgz", - "integrity": "sha512-O5lz91xSOeoXP6DulyHfllpq+Eg00MWitZIbtPfoSEvqIHdl5gfcY6hYzDWnj0qD5tz52PI08u9qUvSVeUBeHw==", - "dev": true - }, - "node-releases": { - "version": "2.0.8", - "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.8.tgz", - "integrity": "sha512-dFSmB8fFHEH/s81Xi+Y/15DQY6VHW81nXRj86EMSL3lmuTmK1e+aT4wrFCkTbm+gSwkw4KpX+rT/pMM2c1mF+A==", - "dev": true - }, - "normalize-path": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", - "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==", - "dev": true - }, - "npm-run-path": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-4.0.1.tgz", - "integrity": "sha512-S48WzZW777zhNIrn7gxOlISNAqi9ZC/uQFnRdbeIHhZhCA6UqpkOT8T1G7BvfdgP4Er8gF4sUbaS0i7QvIfCWw==", - "dev": true, - "requires": { - "path-key": "^3.0.0" - } - }, - "object-inspect": { - "version": "1.12.2", - "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.12.2.tgz", - "integrity": "sha512-z+cPxW0QGUp0mcqcsgQyLVRDoXFQbXOwBaqyF7VIgI4TWNQsDHrBpUQslRmIfAoYWdYzs6UlKJtB2XJpTaNSpQ==", - "dev": true - }, - "object-keys": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/object-keys/-/object-keys-1.1.1.tgz", - "integrity": "sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==", - "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==", - "dev": true, - "requires": { - "call-bind": "^1.0.2", - "define-properties": "^1.1.4", - "has-symbols": "^1.0.3", - "object-keys": "^1.1.1" - } - }, - "object.values": { - "version": "1.1.6", - "resolved": "https://registry.npmjs.org/object.values/-/object.values-1.1.6.tgz", - "integrity": "sha512-FVVTkD1vENCsAcwNs9k6jea2uHC/X0+JcjG8YA60FN5CMaJmG95wT9jek/xX9nornqGRrBkKtzuAu2wuHpKqvw==", - "dev": true, - "requires": { - "call-bind": "^1.0.2", - "define-properties": "^1.1.4", - "es-abstract": "^1.20.4" - } - }, - "once": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", - "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==", - "dev": true, - "requires": { - "wrappy": "1" - } - }, - "onetime": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/onetime/-/onetime-5.1.2.tgz", - "integrity": "sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg==", - "dev": true, - "requires": { - "mimic-fn": "^2.1.0" - } - }, - "open": { - "version": "8.4.0", - "resolved": "https://registry.npmjs.org/open/-/open-8.4.0.tgz", - "integrity": "sha512-XgFPPM+B28FtCCgSb9I+s9szOC1vZRSwgWsRUA5ylIxRTgKozqjOCrVOqGsYABPYK5qnfqClxZTFBa8PKt2v6Q==", - "dev": true, - "requires": { - "define-lazy-prop": "^2.0.0", - "is-docker": "^2.1.1", - "is-wsl": "^2.2.0" - } - }, - "optionator": { - "version": "0.9.1", - "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.1.tgz", - "integrity": "sha512-74RlY5FCnhq4jRxVUPKDaRwrVNXMqsGsiW6AJw4XK8hmtm10wC0ypZBLw5IIp85NZMr91+qd1RvvENwg7jjRFw==", - "dev": true, - "requires": { - "deep-is": "^0.1.3", - "fast-levenshtein": "^2.0.6", - "levn": "^0.4.1", - "prelude-ls": "^1.2.1", - "type-check": "^0.4.0", - "word-wrap": "^1.2.3" - } - }, - "p-limit": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz", - "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==", - "dev": true, - "requires": { - "yocto-queue": "^0.1.0" - } - }, - "p-locate": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-5.0.0.tgz", - "integrity": "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==", - "dev": true, - "requires": { - "p-limit": "^3.0.2" - } - }, - "p-try": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz", - "integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==", - "dev": true - }, - "parent-module": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz", - "integrity": "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==", - "dev": true, - "requires": { - "callsites": "^3.0.0" - } - }, - "parse-json": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-5.2.0.tgz", - "integrity": "sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg==", - "dev": true, - "requires": { - "@babel/code-frame": "^7.0.0", - "error-ex": "^1.3.1", - "json-parse-even-better-errors": "^2.3.0", - "lines-and-columns": "^1.1.6" - } - }, - "path-exists": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", - "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", - "dev": true - }, - "path-is-absolute": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", - "integrity": "sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==", - "dev": true - }, - "path-key": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", - "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", - "dev": true - }, - "path-parse": { - "version": "1.0.7", - "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz", - "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==", - "dev": true - }, - "path-type": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/path-type/-/path-type-4.0.0.tgz", - "integrity": "sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==", - "dev": true - }, - "picocolors": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.0.0.tgz", - "integrity": "sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ==", - "dev": true - }, - "picomatch": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", - "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", - "dev": true - }, - "pirates": { - "version": "4.0.5", - "resolved": "https://registry.npmjs.org/pirates/-/pirates-4.0.5.tgz", - "integrity": "sha512-8V9+HQPupnaXMA23c5hvl69zXvTwTzyAYasnkb0Tts4XvO4CliqONMOnvlq26rkhLC3nWDFBJf73LU1e1VZLaQ==", - "dev": true - }, - "pkg-dir": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-4.2.0.tgz", - "integrity": "sha512-HRDzbaKjC+AOWVXxAU/x54COGeIv9eb+6CkDSQoNTt4XyWoIJvuPsXizxu/Fr23EiekbtZwmh1IcIG/l/a10GQ==", - "dev": true, - "requires": { - "find-up": "^4.0.0" - }, - "dependencies": { - "find-up": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz", - "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==", - "dev": true, - "requires": { - "locate-path": "^5.0.0", - "path-exists": "^4.0.0" - } - }, - "locate-path": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz", - "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==", - "dev": true, - "requires": { - "p-locate": "^4.1.0" - } - }, - "p-limit": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz", - "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==", - "dev": true, - "requires": { - "p-try": "^2.0.0" - } - }, - "p-locate": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz", - "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==", - "dev": true, - "requires": { - "p-limit": "^2.2.0" - } - } - } - }, - "prelude-ls": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz", - "integrity": "sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==", - "dev": true - }, - "pretty-format": { - "version": "29.3.1", - "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-29.3.1.tgz", - "integrity": "sha512-FyLnmb1cYJV8biEIiRyzRFvs2lry7PPIvOqKVe1GCUEYg4YGmlx1qG9EJNMxArYm7piII4qb8UV1Pncq5dxmcg==", - "dev": true, - "requires": { - "@jest/schemas": "^29.0.0", - "ansi-styles": "^5.0.0", - "react-is": "^18.0.0" - }, - "dependencies": { - "ansi-styles": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-5.2.0.tgz", - "integrity": "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==", - "dev": true - } - } - }, - "prompts": { - "version": "2.4.2", - "resolved": "https://registry.npmjs.org/prompts/-/prompts-2.4.2.tgz", - "integrity": "sha512-NxNv/kLguCA7p3jE8oL2aEBsrJWgAakBpgmgK6lpPWV+WuOmY6r2/zbAVnP+T8bQlA0nzHXSJSJW0Hq7ylaD2Q==", - "dev": true, - "requires": { - "kleur": "^3.0.3", - "sisteransi": "^1.0.5" - } - }, - "pseudomap": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/pseudomap/-/pseudomap-1.0.2.tgz", - "integrity": "sha512-b/YwNhb8lk1Zz2+bXXpS/LK9OisiZZ1SNsSLxN1x2OXVEhW2Ckr/7mWE5vrC1ZTiJlD9g19jWszTmJsB+oEpFQ==" - }, - "punycode": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.2.0.tgz", - "integrity": "sha512-LN6QV1IJ9ZhxWTNdktaPClrNfp8xdSAYS0Zk2ddX7XsXZAxckMHPCBcHRo0cTcEIgYPRiGEkmji3Idkh2yFtYw==" - }, - "queue-microtask": { - "version": "1.2.3", - "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz", - "integrity": "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==", - "dev": true - }, - "react-is": { - "version": "18.2.0", - "resolved": "https://registry.npmjs.org/react-is/-/react-is-18.2.0.tgz", - "integrity": "sha512-xWGDIW6x921xtzPkhiULtthJHoJvBbF3q26fzloPCK0hsvxtPVelvftw3zjbHWSkR2km9Z+4uxbDDK/6Zw9B8w==", - "dev": true - }, - "regexp.prototype.flags": { - "version": "1.4.3", - "resolved": "https://registry.npmjs.org/regexp.prototype.flags/-/regexp.prototype.flags-1.4.3.tgz", - "integrity": "sha512-fjggEOO3slI6Wvgjwflkc4NFRCTZAu5CnNfBd5qOMYhWdn67nJBBu34/TkD++eeFmd8C9r9jfXJ27+nSiRkSUA==", - "dev": true, - "requires": { - "call-bind": "^1.0.2", - "define-properties": "^1.1.3", - "functions-have-names": "^1.2.2" - } - }, - "regexpp": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/regexpp/-/regexpp-3.2.0.tgz", - "integrity": "sha512-pq2bWo9mVD43nbts2wGv17XLiNLya+GklZ8kaDLV2Z08gDCsGpnKn9BFMepvWuHCbyVvY7J5o5+BVvoQbmlJLg==", - "dev": true - }, - "require-directory": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", - "integrity": "sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==", - "dev": true - }, - "require-from-string": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/require-from-string/-/require-from-string-2.0.2.tgz", - "integrity": "sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==", - "dev": true - }, - "resolve": { - "version": "1.22.1", - "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.1.tgz", - "integrity": "sha512-nBpuuYuY5jFsli/JIs1oldw6fOQCBioohqWZg/2hiaOybXOft4lonv85uDOKXdf8rhyK159cxU5cDcK/NKk8zw==", - "dev": true, - "requires": { - "is-core-module": "^2.9.0", - "path-parse": "^1.0.7", - "supports-preserve-symlinks-flag": "^1.0.0" - } - }, - "resolve-cwd": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/resolve-cwd/-/resolve-cwd-3.0.0.tgz", - "integrity": "sha512-OrZaX2Mb+rJCpH/6CpSqt9xFVpN++x01XnN2ie9g6P5/3xelLAkXWVADpdz1IHD/KFfEXyE6V0U01OQ3UO2rEg==", - "dev": true, - "requires": { - "resolve-from": "^5.0.0" - }, - "dependencies": { - "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 - } - } - }, - "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.exports": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/resolve.exports/-/resolve.exports-1.1.0.tgz", - "integrity": "sha512-J1l+Zxxp4XK3LUDZ9m60LRJF/mAe4z6a4xyabPHk7pvK5t35dACV32iIjJDFeWZFfZlO29w6SZ67knR0tHzJtQ==", - "dev": true - }, - "reusify": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.0.4.tgz", - "integrity": "sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==", - "dev": true - }, - "rimraf": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz", - "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==", - "dev": true, - "requires": { - "glob": "^7.1.3" - } - }, - "run-parallel": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz", - "integrity": "sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==", - "dev": true, - "requires": { - "queue-microtask": "^1.2.2" - } - }, - "safe-regex-test": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/safe-regex-test/-/safe-regex-test-1.0.0.tgz", - "integrity": "sha512-JBUUzyOgEwXQY1NuPtvcj/qcBDbDmEvWufhlnXZIm75DEHp+afM1r1ujJpJsV/gSM4t59tpDyPi1sd6ZaPFfsA==", - "dev": true, - "requires": { - "call-bind": "^1.0.2", - "get-intrinsic": "^1.1.3", - "is-regex": "^1.1.4" - } - }, - "semver": { - "version": "7.3.8", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.8.tgz", - "integrity": "sha512-NB1ctGL5rlHrPJtFDVIVzTyQylMLu9N9VICA6HSFJo8MCGVTMW6gfpicwKmmK/dAjTOrqu5l63JJOpDSrAis3A==", - "requires": { - "lru-cache": "^6.0.0" - }, - "dependencies": { - "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==", - "requires": { - "yallist": "^4.0.0" - } - }, - "yallist": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", - "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==" - } - } - }, - "shebang-command": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", - "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", - "dev": true, - "requires": { - "shebang-regex": "^3.0.0" - } - }, - "shebang-regex": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", - "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", - "dev": true - }, - "side-channel": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.0.4.tgz", - "integrity": "sha512-q5XPytqFEIKHkGdiMIrY10mvLRvnQh42/+GoBlFW3b2LXLE2xxJpZFdm94we0BaoV3RwJyGqg5wS7epxTv0Zvw==", - "dev": true, - "requires": { - "call-bind": "^1.0.0", - "get-intrinsic": "^1.0.2", - "object-inspect": "^1.9.0" - } - }, - "signal-exit": { - "version": "3.0.7", - "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz", - "integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==", - "dev": true - }, - "sisteransi": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/sisteransi/-/sisteransi-1.0.5.tgz", - "integrity": "sha512-bLGGlR1QxBcynn2d5YmDX4MGjlZvy2MRBDRNHLJ8VI6l6+9FUiyTFNJ0IveOSP0bcXgVDPRcfGqA0pjaqUpfVg==", - "dev": true - }, - "slash": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz", - "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==", - "dev": true - }, - "slice-ansi": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-4.0.0.tgz", - "integrity": "sha512-qMCMfhY040cVHT43K9BFygqYbUPFZKHOg7K73mtTWJRb8pyP3fzf4Ixd5SzdEJQ6MRUg/WBnOLxghZtKKurENQ==", - "dev": true, - "requires": { - "ansi-styles": "^4.0.0", - "astral-regex": "^2.0.0", - "is-fullwidth-code-point": "^3.0.0" - } - }, - "source-map": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==" - }, - "source-map-support": { - "version": "0.5.21", - "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.21.tgz", - "integrity": "sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w==", - "requires": { - "buffer-from": "^1.0.0", - "source-map": "^0.6.0" - } - }, - "sprintf-js": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz", - "integrity": "sha512-D9cPgkvLlV3t3IzL0D0YLvGA9Ahk4PcvVwUbN0dSGr1aP0Nrt4AEnTUbuGvquEC0mA64Gqt1fzirlRs5ibXx8g==", - "dev": true - }, - "stack-utils": { - "version": "2.0.6", - "resolved": "https://registry.npmjs.org/stack-utils/-/stack-utils-2.0.6.tgz", - "integrity": "sha512-XlkWvfIm6RmsWtNJx+uqtKLS8eqFbxUg0ZzLXqY0caEy9l7hruX8IpiDnjsLavoBgqCCR71TqWO8MaXYheJ3RQ==", - "dev": true, - "requires": { - "escape-string-regexp": "^2.0.0" - }, - "dependencies": { - "escape-string-regexp": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-2.0.0.tgz", - "integrity": "sha512-UpzcLCXolUWcNu5HtVMHYdXJjArjsF9C0aNnquZYY4uW/Vu0miy5YoWvbV345HauVvcAUnpRuhMMcqTcGOY2+w==", - "dev": true - } - } - }, - "string-length": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/string-length/-/string-length-4.0.2.tgz", - "integrity": "sha512-+l6rNN5fYHNhZZy41RXsYptCjA2Igmq4EG7kZAYFQI1E1VTXarr6ZPXBg6eq7Y6eK4FEhY6AJlyuFIb/v/S0VQ==", - "dev": true, - "requires": { - "char-regex": "^1.0.2", - "strip-ansi": "^6.0.0" - } - }, - "string-width": { - "version": "4.2.3", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", - "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", - "dev": true, - "requires": { - "emoji-regex": "^8.0.0", - "is-fullwidth-code-point": "^3.0.0", - "strip-ansi": "^6.0.1" - } - }, - "string.prototype.trimend": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/string.prototype.trimend/-/string.prototype.trimend-1.0.6.tgz", - "integrity": "sha512-JySq+4mrPf9EsDBEDYMOb/lM7XQLulwg5R/m1r0PXEFqrV0qHvl58sdTilSXtKOflCsK2E8jxf+GKC0T07RWwQ==", - "dev": true, - "requires": { - "call-bind": "^1.0.2", - "define-properties": "^1.1.4", - "es-abstract": "^1.20.4" - } - }, - "string.prototype.trimstart": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/string.prototype.trimstart/-/string.prototype.trimstart-1.0.6.tgz", - "integrity": "sha512-omqjMDaY92pbn5HOX7f9IccLA+U1tA9GvtU4JrodiXFfYB7jPzzHpRzpglLAjtUV6bB557zwClJezTqnAiYnQA==", - "dev": true, - "requires": { - "call-bind": "^1.0.2", - "define-properties": "^1.1.4", - "es-abstract": "^1.20.4" - } - }, - "strip-ansi": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", - "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", - "dev": true, - "requires": { - "ansi-regex": "^5.0.1" - } - }, - "strip-bom": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-4.0.0.tgz", - "integrity": "sha512-3xurFv5tEgii33Zi8Jtp55wEIILR9eh34FAW00PZf+JnSsTmV/ioewSgQl97JHvgjoRGwPShsWm+IdrxB35d0w==", - "dev": true - }, - "strip-final-newline": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/strip-final-newline/-/strip-final-newline-2.0.0.tgz", - "integrity": "sha512-BrpvfNAE3dcvq7ll3xVumzjKjZQ5tI1sEUIKr3Uoks0XUl45St3FlatVqef9prk4jRDzhW6WZg+3bk93y6pLjA==", - "dev": true - }, - "strip-json-comments": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz", - "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==", - "dev": true - }, - "supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", - "dev": true, - "requires": { - "has-flag": "^4.0.0" - } - }, - "supports-preserve-symlinks-flag": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz", - "integrity": "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==", - "dev": true - }, - "synckit": { - "version": "0.8.4", - "resolved": "https://registry.npmjs.org/synckit/-/synckit-0.8.4.tgz", - "integrity": "sha512-Dn2ZkzMdSX827QbowGbU/4yjWuvNaCoScLLoMo/yKbu+P4GBR6cRGKZH27k6a9bRzdqcyd1DE96pQtQ6uNkmyw==", - "dev": true, - "requires": { - "@pkgr/utils": "^2.3.1", - "tslib": "^2.4.0" - } - }, - "table": { - "version": "6.8.1", - "resolved": "https://registry.npmjs.org/table/-/table-6.8.1.tgz", - "integrity": "sha512-Y4X9zqrCftUhMeH2EptSSERdVKt/nEdijTOacGD/97EKjhQ/Qs8RTlEGABSJNNN8lac9kheH+af7yAkEWlgneA==", - "dev": true, - "requires": { - "ajv": "^8.0.1", - "lodash.truncate": "^4.4.2", - "slice-ansi": "^4.0.0", - "string-width": "^4.2.3", - "strip-ansi": "^6.0.1" - }, - "dependencies": { - "ajv": { - "version": "8.12.0", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.12.0.tgz", - "integrity": "sha512-sRu1kpcO9yLtYxBKvqfTeh9KzZEwO3STyX1HT+4CaDzC6HpTGYhIhPIzj9XuKU7KYDwnaeh5hcOwjy1QuJzBPA==", - "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==", - "dev": true - } - } - }, - "tapable": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/tapable/-/tapable-2.2.1.tgz", - "integrity": "sha512-GNzQvQTOIP6RyTfE2Qxb8ZVlNmw0n88vp1szwWRimP02mnTsx3Wtn5qRdqY9w2XduFNUgvOwhNnQsjwCp+kqaQ==", - "dev": true - }, - "test-exclude": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/test-exclude/-/test-exclude-6.0.0.tgz", - "integrity": "sha512-cAGWPIyOHU6zlmg88jwm7VRyXnMN7iV68OGAbYDk/Mh/xC/pzVPlQtY6ngoIH/5/tciuhGfvESU8GrHrcxD56w==", - "dev": true, - "requires": { - "@istanbuljs/schema": "^0.1.2", - "glob": "^7.1.4", - "minimatch": "^3.0.4" - } - }, - "text-table": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz", - "integrity": "sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw==", - "dev": true - }, - "tiny-glob": { - "version": "0.2.9", - "resolved": "https://registry.npmjs.org/tiny-glob/-/tiny-glob-0.2.9.tgz", - "integrity": "sha512-g/55ssRPUjShh+xkfx9UPDXqhckHEsHr4Vd9zX55oSdGZc/MD0m3sferOkwWtp98bv+kcVfEHtRJgBVJzelrzg==", - "dev": true, - "requires": { - "globalyzer": "0.1.0", - "globrex": "^0.1.2" - } - }, - "tmpl": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/tmpl/-/tmpl-1.0.5.tgz", - "integrity": "sha512-3f0uOEAQwIqGuWW2MVzYg8fV/QNnc/IpuJNG837rLuczAaLVHslWHZQj4IGiEl5Hs3kkbhwL9Ab7Hrsmuj+Smw==", - "dev": true - }, - "to-fast-properties": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/to-fast-properties/-/to-fast-properties-2.0.0.tgz", - "integrity": "sha512-/OaKK0xYrs3DmxRYqL/yDc+FxFUVYhDlXMhRmv3z915w2HF1tnN1omB354j8VUGO/hbRzyD6Y3sA7v7GS/ceog==", - "dev": true - }, - "to-regex-range": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", - "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", - "dev": true, - "requires": { - "is-number": "^7.0.0" - } - }, - "ts-jest": { - "version": "29.0.3", - "resolved": "https://registry.npmjs.org/ts-jest/-/ts-jest-29.0.3.tgz", - "integrity": "sha512-Ibygvmuyq1qp/z3yTh9QTwVVAbFdDy/+4BtIQR2sp6baF2SJU/8CKK/hhnGIDY2L90Az2jIqTwZPnN2p+BweiQ==", - "dev": true, - "requires": { - "bs-logger": "0.x", - "fast-json-stable-stringify": "2.x", - "jest-util": "^29.0.0", - "json5": "^2.2.1", - "lodash.memoize": "4.x", - "make-error": "1.x", - "semver": "7.x", - "yargs-parser": "^21.0.1" - } - }, - "ts-md5": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/ts-md5/-/ts-md5-1.3.1.tgz", - "integrity": "sha512-DiwiXfwvcTeZ5wCE0z+2A9EseZsztaiZtGrtSaY5JOD7ekPnR/GoIVD5gXZAlK9Na9Kvpo9Waz5rW64WKAWApg==" - }, - "ts-node": { - "version": "10.9.1", - "resolved": "https://registry.npmjs.org/ts-node/-/ts-node-10.9.1.tgz", - "integrity": "sha512-NtVysVPkxxrwFGUUxGYhfux8k78pQB3JqYBXlLRZgdGUqTO5wU/UyHop5p70iEbGhB7q5KmiZiU0Y3KlJrScEw==", - "dev": true, - "requires": { - "@cspotcode/source-map-support": "^0.8.0", - "@tsconfig/node10": "^1.0.7", - "@tsconfig/node12": "^1.0.7", - "@tsconfig/node14": "^1.0.0", - "@tsconfig/node16": "^1.0.2", - "acorn": "^8.4.1", - "acorn-walk": "^8.1.1", - "arg": "^4.1.0", - "create-require": "^1.1.0", - "diff": "^4.0.1", - "make-error": "^1.1.1", - "v8-compile-cache-lib": "^3.0.1", - "yn": "3.1.1" - }, - "dependencies": { - "diff": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/diff/-/diff-4.0.2.tgz", - "integrity": "sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A==", - "dev": true - } - } - }, - "tsconfig-paths": { - "version": "3.14.1", - "resolved": "https://registry.npmjs.org/tsconfig-paths/-/tsconfig-paths-3.14.1.tgz", - "integrity": "sha512-fxDhWnFSLt3VuTwtvJt5fpwxBHg5AdKWMsgcPOOIilyjymcYVZoCQF8fvFRezCNfblEXmi+PcM1eYHeOAgXCOQ==", - "dev": true, - "requires": { - "@types/json5": "^0.0.29", - "json5": "^1.0.1", - "minimist": "^1.2.6", - "strip-bom": "^3.0.0" - }, - "dependencies": { - "json5": { - "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" - } - }, - "strip-bom": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-3.0.0.tgz", - "integrity": "sha512-vavAMRXOgBVNF6nyEEmL3DBK19iRpDcoIwW+swQ+CbGiu7lju6t+JklA1MHweoWtadgt4ISVUsXLyDq34ddcwA==", - "dev": true - } - } - }, - "tslib": { - "version": "2.4.1", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.4.1.tgz", - "integrity": "sha512-tGyy4dAjRIEwI7BzsB0lynWgOpfqjUdq91XXAlIWD2OwKBH7oCl/GZG/HT4BOHrTlPMOASlMQ7veyTqpmRcrNA==", - "dev": true - }, - "tsutils": { - "version": "3.21.0", - "resolved": "https://registry.npmjs.org/tsutils/-/tsutils-3.21.0.tgz", - "integrity": "sha512-mHKK3iUXL+3UF6xL5k0PEhKRUBKPBCv/+RkEOpjRWxxx27KKRBmmA60A9pgOUvMi8GKhRMPEmjBRPzs2W7O1OA==", - "dev": true, - "requires": { - "tslib": "^1.8.1" - }, - "dependencies": { - "tslib": { - "version": "1.14.1", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", - "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==", - "dev": true - } - } - }, - "type-check": { - "version": "0.4.0", - "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz", - "integrity": "sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==", - "dev": true, - "requires": { - "prelude-ls": "^1.2.1" - } - }, - "type-detect": { - "version": "4.0.8", - "resolved": "https://registry.npmjs.org/type-detect/-/type-detect-4.0.8.tgz", - "integrity": "sha512-0fr/mIH1dlO+x7TlcMy+bIDqKPsw/70tVyeHW787goQjhmqaZe10uwLujubK9q9Lg6Fiho1KUKDYz0Z7k7g5/g==", - "dev": true - }, - "type-fest": { - "version": "0.20.2", - "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.20.2.tgz", - "integrity": "sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==", - "dev": true - }, - "typed-array-length": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/typed-array-length/-/typed-array-length-1.0.4.tgz", - "integrity": "sha512-KjZypGq+I/H7HI5HlOoGHkWUUGq+Q0TPhQurLbyrVrvnKTBgzLhIJ7j6J/XTQOi0d1RjyZ0wdas8bKs2p0x3Ng==", - "dev": true, - "requires": { - "call-bind": "^1.0.2", - "for-each": "^0.3.3", - "is-typed-array": "^1.1.9" - } - }, - "typescript": { - "version": "4.9.4", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.9.4.tgz", - "integrity": "sha512-Uz+dTXYzxXXbsFpM86Wh3dKCxrQqUcVMxwU54orwlJjOpO3ao8L7j5lH+dWfTwgCwIuM9GQ2kvVotzYJMXTBZg==", - "dev": true - }, - "unbox-primitive": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/unbox-primitive/-/unbox-primitive-1.0.2.tgz", - "integrity": "sha512-61pPlCD9h51VoreyJ0BReideM3MDKMKnh6+V9L08331ipq6Q8OFXZYiqP6n/tbHx4s5I9uRhcye6BrbkizkBDw==", - "dev": true, - "requires": { - "call-bind": "^1.0.2", - "has-bigints": "^1.0.2", - "has-symbols": "^1.0.3", - "which-boxed-primitive": "^1.0.2" - } - }, - "universalify": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/universalify/-/universalify-2.0.0.tgz", - "integrity": "sha512-hAZsKq7Yy11Zu1DE0OzWjw7nnLZmJZYTDZZyEFHZdUhV8FkH5MCfoU1XMaxXovpyW5nq5scPqq0ZDP9Zyl04oQ==" - }, - "update-browserslist-db": { - "version": "1.0.10", - "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.0.10.tgz", - "integrity": "sha512-OztqDenkfFkbSG+tRxBeAnCVPckDBcvibKd35yDONx6OU8N7sqgwc7rCbkJ/WcYtVRZ4ba68d6byhC21GFh7sQ==", - "dev": true, - "requires": { - "escalade": "^3.1.1", - "picocolors": "^1.0.0" - } - }, - "uri-js": { - "version": "4.4.1", - "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz", - "integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==", - "dev": true, - "requires": { - "punycode": "^2.1.0" - } - }, - "v8-compile-cache-lib": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/v8-compile-cache-lib/-/v8-compile-cache-lib-3.0.1.tgz", - "integrity": "sha512-wa7YjyUGfNZngI/vtK0UHAN+lgDCxBPCylVXGp0zu59Fz5aiGtNXaq3DhIov063MorB+VfufLh3JlF2KdTK3xg==", - "dev": true - }, - "v8-to-istanbul": { - "version": "9.0.1", - "resolved": "https://registry.npmjs.org/v8-to-istanbul/-/v8-to-istanbul-9.0.1.tgz", - "integrity": "sha512-74Y4LqY74kLE6IFyIjPtkSTWzUZmj8tdHT9Ii/26dvQ6K9Dl2NbEfj0XgU2sHCtKgt5VupqhlO/5aWuqS+IY1w==", - "dev": true, - "requires": { - "@jridgewell/trace-mapping": "^0.3.12", - "@types/istanbul-lib-coverage": "^2.0.1", - "convert-source-map": "^1.6.0" - }, - "dependencies": { - "convert-source-map": { - "version": "1.9.0", - "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-1.9.0.tgz", - "integrity": "sha512-ASFBup0Mz1uyiIjANan1jzLQami9z1PoYSZCiiYW2FczPbenXc45FZdBZLzOT+r6+iciuEModtmCti+hjaAk0A==", - "dev": true - } - } - }, - "walker": { - "version": "1.0.8", - "resolved": "https://registry.npmjs.org/walker/-/walker-1.0.8.tgz", - "integrity": "sha512-ts/8E8l5b7kY0vlWLewOkDXMmPdLcVV4GmOQLyxuSswIJsweeFZtAsMF7k1Nszz+TYBQrlYRmzOnr398y1JemQ==", - "dev": true, - "requires": { - "makeerror": "1.0.12" - } - }, - "which": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", - "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", - "dev": true, - "requires": { - "isexe": "^2.0.0" - } - }, - "which-boxed-primitive": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/which-boxed-primitive/-/which-boxed-primitive-1.0.2.tgz", - "integrity": "sha512-bwZdv0AKLpplFY2KZRX6TvyuN7ojjr7lwkg6ml0roIy9YeuSr7JS372qlNW18UQYzgYK9ziGcerWqZOmEn9VNg==", - "dev": true, - "requires": { - "is-bigint": "^1.0.1", - "is-boolean-object": "^1.1.0", - "is-number-object": "^1.0.4", - "is-string": "^1.0.5", - "is-symbol": "^1.0.3" - } - }, - "which-typed-array": { - "version": "1.1.9", - "resolved": "https://registry.npmjs.org/which-typed-array/-/which-typed-array-1.1.9.tgz", - "integrity": "sha512-w9c4xkx6mPidwp7180ckYWfMmvxpjlZuIudNtDf4N/tTAUB8VJbX25qZoAsrtGuYNnGw3pa0AXgbGKRB8/EceA==", - "dev": true, - "requires": { - "available-typed-arrays": "^1.0.5", - "call-bind": "^1.0.2", - "for-each": "^0.3.3", - "gopd": "^1.0.1", - "has-tostringtag": "^1.0.0", - "is-typed-array": "^1.1.10" - } - }, - "word-wrap": { - "version": "1.2.3", - "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.3.tgz", - "integrity": "sha512-Hz/mrNwitNRh/HUAtM/VT/5VH+ygD6DV7mYKZAtHOrbs8U7lvPS6xf7EJKMF0uW1KJCl0H701g3ZGus+muE5vQ==", - "dev": true - }, - "wrap-ansi": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", - "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", - "dev": true, - "requires": { - "ansi-styles": "^4.0.0", - "string-width": "^4.1.0", - "strip-ansi": "^6.0.0" - } - }, - "wrappy": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", - "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==", - "dev": true - }, - "write-file-atomic": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/write-file-atomic/-/write-file-atomic-4.0.2.tgz", - "integrity": "sha512-7KxauUdBmSdWnmpaGFg+ppNjKF8uNLry8LyzjauQDOVONfFLNKrKvQOxZ/VuTIcS/gge/YNahf5RIIQWTSarlg==", - "dev": true, - "requires": { - "imurmurhash": "^0.1.4", - "signal-exit": "^3.0.7" - } - }, - "y18n": { - "version": "5.0.8", - "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz", - "integrity": "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==", - "dev": true - }, - "yallist": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz", - "integrity": "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==", - "dev": true - }, - "yargs": { - "version": "17.6.2", - "resolved": "https://registry.npmjs.org/yargs/-/yargs-17.6.2.tgz", - "integrity": "sha512-1/9UrdHjDZc0eOU0HxOHoS78C69UD3JRMvzlJ7S79S2nTaWRA/whGCTV8o9e/N/1Va9YIV7Q4sOxD8VV4pCWOw==", - "dev": true, - "requires": { - "cliui": "^8.0.1", - "escalade": "^3.1.1", - "get-caller-file": "^2.0.5", - "require-directory": "^2.1.1", - "string-width": "^4.2.3", - "y18n": "^5.0.5", - "yargs-parser": "^21.1.1" - } - }, - "yargs-parser": { - "version": "21.1.1", - "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-21.1.1.tgz", - "integrity": "sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==", - "dev": true - }, - "yn": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/yn/-/yn-3.1.1.tgz", - "integrity": "sha512-Ux4ygGWsu2c7isFWe8Yu1YluJmqVhxqK2cLXNQA5AcC3QfbGNpM7fu0Y8b/z16pXLnFxZYvWhd3fhBY9DLmC6Q==", - "dev": true - }, - "yocto-queue": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz", - "integrity": "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==", - "dev": true - } - } -} diff --git a/layer-publisher/package.json b/layer-publisher/package.json deleted file mode 100644 index 4acf379284..0000000000 --- a/layer-publisher/package.json +++ /dev/null @@ -1,42 +0,0 @@ -{ - "name": "layer-publisher", - "version": "1.5.1", - "bin": { - "layer-publisher": "bin/layer-publisher.js" - }, - "scripts": { - "build": "tsc", - "watch": "tsc -w", - "test": "npm run test:unit", - "cdk": "cdk", - "package": "echo 'Not applicable'", - "lint": "eslint --ext .ts --no-error-on-unmatched-pattern src tests --resolve-plugins-relative-to .", - "lint-fix": "eslint --fix --ext .ts --fix --no-error-on-unmatched-pattern src tests --resolve-plugins-relative-to .", - "test:unit": "if-node-version '>12' jest --testPathPattern=unit -u", - "test:e2e": "if-node-version '>12' jest --testPathPattern=e2e" - }, - "devDependencies": { - "@aws-cdk/cloudformation-diff": "^2.55.0", - "@aws-cdk/cx-api": "^2.55.0", - "@types/jest": "^29.2.4", - "@types/node": "18.11.15", - "@typescript-eslint/eslint-plugin": "^5.46.1", - "@typescript-eslint/parser": "^5.46.1", - "aws-cdk": "^2.55.0", - "eslint": "^8.29.0", - "eslint-import-resolver-node": "^0.3.6", - "eslint-import-resolver-typescript": "^3.5.2", - "eslint-plugin-import": "^2.26.0", - "jest": "^29.3.1", - "ts-jest": "^29.0.3", - "ts-node": "10.9.1", - "typescript": "4.9.4" - }, - "dependencies": { - "aws-cdk-lib": "^2.55.0", - "constructs": "^10.1.190", - "if-node-version": "^1.1.1", - "source-map-support": "^0.5.21", - "ts-md5": "^1.3.1" - } -} diff --git a/layer-publisher/src/powertools-typescript-layer.ts b/layer-publisher/src/powertools-typescript-layer.ts deleted file mode 100644 index bbdd602ac6..0000000000 --- a/layer-publisher/src/powertools-typescript-layer.ts +++ /dev/null @@ -1,63 +0,0 @@ -import * as path from 'path'; -import { aws_lambda as lambda } from 'aws-cdk-lib'; -import { Construct } from 'constructs'; -import { execSync } from 'child_process'; -import { Md5 } from 'ts-md5'; - -export interface PowerToolsTypeScriptLayerProps { - /** - * The powertools package version from npm repository. - */ - readonly version?: string - - /** - * the name of the layer, will be randomised by cdk if empty - */ - readonly layerVersionName?: string -} - -export class PowerToolsTypeScriptLayer extends lambda.LayerVersion { - public constructor(scope: Construct, id: string, props?: PowerToolsTypeScriptLayerProps) { - const version = props?.version ?? 'latest'; - console.log(`publishing layer ${props?.layerVersionName} version : ${version}`); - - const commands = [ - 'mkdir nodejs', - 'cd nodejs', - 'npm init -y', - `npm install --save \ - @aws-lambda-powertools/commons@${version} \ - @aws-lambda-powertools/logger@${version} \ - @aws-lambda-powertools/metrics@${version} \ - @aws-lambda-powertools/tracer@${version}`, - 'rm -rf node_modules/@types', - 'rm package.json package-lock.json', - ]; - const commandJoined = commands.join(' && '); - - super(scope, id, { - layerVersionName: props?.layerVersionName, - description: `Lambda Powertools for TypeScript version ${props?.version}`, - compatibleRuntimes: [ lambda.Runtime.NODEJS_14_X, lambda.Runtime.NODEJS_16_X, lambda.Runtime.NODEJS_18_X ], - code: lambda.Code.fromAsset(path.join(__dirname, '.'), { - assetHash: Md5.hashStr(commandJoined), - bundling: { - image: lambda.Runtime.NODEJS_14_X.bundlingImage, - local: { - tryBundle(outputDir: string) { - try { - execSync('npm --version && zip --version'); - } catch { - return false; - } - - execSync(commandJoined, { cwd: outputDir }); - - return true; - }, - }, - }, - }), - }); - } -} diff --git a/layer-publisher/tests/e2e/happy-case.test.lambda.ts b/layer-publisher/tests/e2e/happy-case.test.lambda.ts deleted file mode 100644 index f454713f79..0000000000 --- a/layer-publisher/tests/e2e/happy-case.test.lambda.ts +++ /dev/null @@ -1,40 +0,0 @@ -import { Logger } from '@aws-lambda-powertools/logger'; -import { Metrics } from '@aws-lambda-powertools/metrics'; -import { Tracer } from '@aws-lambda-powertools/tracer'; -import fs from 'fs'; - -const SERVICE_NAME = 'e2e-tests-layer-consumer'; -const logger = new Logger({ serviceName: SERVICE_NAME, logLevel: 'DEBUG' }); -const metrics = new Metrics({ serviceName: SERVICE_NAME }); -const tracer = new Tracer({ serviceName: SERVICE_NAME }); - -exports.handler = function (_event: never, _ctx: unknown): void { - // check logger lib access - logger.injectLambdaContext(); - logger.debug('Hello World!'); - // Check version - try { - const packageJSON = JSON.parse( - fs.readFileSync('/opt/nodejs/node_modules/@aws-lambda-powertools/logger/package.json', { - encoding: 'utf8', - flag: 'r', - }) - ); - metrics.captureColdStartMetric(); - const segment = tracer.getSegment(); - - const handlerSegment = segment.addNewSubsegment('Handler'); - - tracer.setSegment(handlerSegment); - - tracer.annotateColdStart(); - - if (packageJSON.version != process.env.POWERTOOLS_PACKAGE_VERSION) { - throw new Error( - `Package version mismatch: ${packageJSON.version} != ${process.env.POWERTOOLS_PACKAGE_VERSION}` - ); - } - } catch (error) { - logger.error(error); - } -}; diff --git a/layer-publisher/tests/e2e/happy-case.test.ts b/layer-publisher/tests/e2e/happy-case.test.ts deleted file mode 100644 index 7bdc2c6234..0000000000 --- a/layer-publisher/tests/e2e/happy-case.test.ts +++ /dev/null @@ -1,88 +0,0 @@ -/** - * Test layer - * - * @group e2e - * - */ - -import * as cdk from 'aws-cdk-lib'; -import { Stack } from 'aws-cdk-lib'; -import * as lambda from 'aws-cdk-lib/aws-lambda'; -import * as nodejs from 'aws-cdk-lib/aws-lambda-nodejs'; -import * as LayerPublisher from '../../src/layer-publisher-stack'; -import { deployStack, destroyStack } from '../../../packages/commons/tests/utils/cdk-cli'; -import { generateUniqueName, invokeFunction } from '../../../packages/commons/tests/utils/e2eUtils'; -import { LEVEL } from '../../../packages/commons/tests/utils/InvocationLogs'; - -const runtime = lambda.Runtime.ALL.find((r) => r.name === process.env.RUNTIME) ?? lambda.Runtime.NODEJS_14_X; - -const powerToolsPackageVersion = '1.0.1'; - -const e2eTestLayerPublicationApp = new cdk.App(); - -const layerStack = new LayerPublisher.LayerPublisherStack( - e2eTestLayerPublicationApp, - `E2ELayerPublisherStack-${runtime.name.split('.')[0]}`, - { - layerName: `e2e-tests-layer-${runtime.name.split('.')[0]}`, - powerToolsPackageVersion: powerToolsPackageVersion, - ssmParameterLayerArn: `/e2e-tests-layertools-layer-arn-${runtime.name.split('.')[0]}`, - } -); - -test(`The layer Created is usable with ${runtime} runtime lambda`, async () => { - // GIVEN - const { consumerStack, functionName } = createSampleLambda(runtime); - - await deployStack(e2eTestLayerPublicationApp, layerStack); - await deployStack(e2eTestLayerPublicationApp, consumerStack); - - // WHEN - const invocationLogs = await invokeFunction(functionName); - - // THEN - try { - const errorLogs = invocationLogs[0].getFunctionLogs(LEVEL.ERROR); - expect(errorLogs.length).toBe(0); - - const warningLogs = invocationLogs[0].getFunctionLogs(LEVEL.WARN); - expect(warningLogs.length).toBe(1); // the missing namespace warning - - const infoLogs = invocationLogs[0].getFunctionLogs(LEVEL.INFO); - expect(infoLogs.length).toBe(1); // the coldstart metric one - - const debugLogs = invocationLogs[0].getFunctionLogs(LEVEL.DEBUG); - expect(debugLogs.length).toBe(1); // the Hello World! message - } catch (error) { - console.log(JSON.stringify(invocationLogs[0].getFunctionLogs())); - throw error; - } - finally { - await destroyStack(e2eTestLayerPublicationApp, consumerStack); - } -}, 900000); - -const createSampleLambda = (runtime: cdk.aws_lambda.Runtime): { consumerStack: cdk.Stack; functionName: string } => { - const functionName = generateUniqueName('E2ETest', 'Layer', runtime.name.split('.')[0], 'Consumer'); - - const consumerStack = new Stack(e2eTestLayerPublicationApp, `${runtime.name.split('.')[0]}ConsumerStack`); - new nodejs.NodejsFunction(consumerStack, 'lambda', { - handler: 'handler', - functionName, - runtime: runtime, - bundling: { - externalModules: [ - '@aws-lambda-powertools/commons', - '@aws-lambda-powertools/logger', - '@aws-lambda-powertools/metrics', - '@aws-lambda-powertools/tracer' - ] - }, - environment: { - POWERTOOLS_PACKAGE_VERSION: powerToolsPackageVersion, - }, - layers: [layerStack.lambdaLayerVersion], - }); - - return { consumerStack, functionName }; -}; diff --git a/layer-publisher/tests/unit/__snapshots__/layer-publisher.test.ts.snap b/layer-publisher/tests/unit/__snapshots__/layer-publisher.test.ts.snap deleted file mode 100644 index 9e6b8f7ad7..0000000000 --- a/layer-publisher/tests/unit/__snapshots__/layer-publisher.test.ts.snap +++ /dev/null @@ -1,94 +0,0 @@ -// Jest Snapshot v1, https://goo.gl/fbAQLP - -exports[`Layer Created 1`] = ` -Object { - "Outputs": Object { - "LatestLayerArn": Object { - "Export": Object { - "Name": "AWSLambdaPowertoolsTypeScript", - }, - "Value": Object { - "Ref": "LambdaPowertoolsLayer733361E9", - }, - }, - }, - "Parameters": Object { - "BootstrapVersion": Object { - "Default": "/cdk-bootstrap/hnb659fds/version", - "Description": "Version of the CDK Bootstrap resources in this environment, automatically retrieved from SSM Parameter Store. [cdk:skip]", - "Type": "AWS::SSM::Parameter::Value", - }, - }, - "Resources": Object { - "LambdaPowertoolsLayer733361E9": Object { - "DeletionPolicy": "Retain", - "Properties": Object { - "CompatibleRuntimes": Array [ - "nodejs12.x", - "nodejs14.x", - "nodejs16.x", - ], - "Content": Object { - "S3Bucket": Object { - "Fn::Sub": "cdk-hnb659fds-assets-\${AWS::AccountId}-\${AWS::Region}", - }, - "S3Key": "dbdb3f66eaeed03649521bf73dbcdd95a713086afccbac3f57fa407ffb76bdaa.zip", - }, - "Description": "Lambda Powertools for TypeScript version 1.0.1", - "LayerName": "AWSLambdaPowertoolsTypeScript", - }, - "Type": "AWS::Lambda::LayerVersion", - "UpdateReplacePolicy": "Retain", - }, - "PublicLayerAccess": Object { - "DeletionPolicy": "Retain", - "Properties": Object { - "Action": "lambda:GetLayerVersion", - "LayerVersionArn": Object { - "Ref": "LambdaPowertoolsLayer733361E9", - }, - "Principal": "*", - }, - "Type": "AWS::Lambda::LayerVersionPermission", - "UpdateReplacePolicy": "Retain", - }, - "VersionArn99E177D3": Object { - "Properties": Object { - "Name": "/layers/powertools-layer-arn", - "Type": "String", - "Value": Object { - "Ref": "LambdaPowertoolsLayer733361E9", - }, - }, - "Type": "AWS::SSM::Parameter", - }, - }, - "Rules": Object { - "CheckBootstrapVersion": Object { - "Assertions": Array [ - Object { - "Assert": Object { - "Fn::Not": Array [ - Object { - "Fn::Contains": Array [ - Array [ - "1", - "2", - "3", - "4", - "5", - ], - Object { - "Ref": "BootstrapVersion", - }, - ], - }, - ], - }, - "AssertDescription": "CDK bootstrap stack version 6 required. Please run 'cdk bootstrap' with a recent version of the CDK CLI.", - }, - ], - }, - }, -} -`; diff --git a/layer-publisher/tests/unit/layer-publisher.test.ts b/layer-publisher/tests/unit/layer-publisher.test.ts deleted file mode 100644 index 876325f255..0000000000 --- a/layer-publisher/tests/unit/layer-publisher.test.ts +++ /dev/null @@ -1,24 +0,0 @@ -/** - * Test layer publisher - * - * @group unit/layer-publisher - */ - -import * as cdk from 'aws-cdk-lib'; -import { Template } from 'aws-cdk-lib/assertions'; -import * as LayerPublisher from '../../src/layer-publisher-stack'; - -test('Layer Created', () => { - const app = new cdk.App(); - // WHEN - const stack = new LayerPublisher.LayerPublisherStack(app, 'MyTestStack', { - layerName: 'AWSLambdaPowertoolsTypeScript', - powerToolsPackageVersion: '1.0.1', - ssmParameterLayerArn: '/layers/powertools-layer-arn', - }); - - // THEN - const template = Template.fromStack(stack); - - expect(template).toMatchSnapshot(); -}); diff --git a/layer-publisher/.eslintrc.js b/layers/.eslintrc.js similarity index 100% rename from layer-publisher/.eslintrc.js rename to layers/.eslintrc.js diff --git a/layer-publisher/.gitignore b/layers/.gitignore similarity index 100% rename from layer-publisher/.gitignore rename to layers/.gitignore diff --git a/layer-publisher/.npmignore b/layers/.npmignore similarity index 100% rename from layer-publisher/.npmignore rename to layers/.npmignore diff --git a/layer-publisher/CHANGELOG.md b/layers/CHANGELOG.md similarity index 100% rename from layer-publisher/CHANGELOG.md rename to layers/CHANGELOG.md diff --git a/layer-publisher/README.md b/layers/README.md similarity index 50% rename from layer-publisher/README.md rename to layers/README.md index 5a49b01293..1a3f5602b9 100644 --- a/layer-publisher/README.md +++ b/layers/README.md @@ -35,4 +35,23 @@ PS: You can force * the Powertools version with VERSION env variable ```sh RUNTIME=node12.x VERSION=0.9.0 npm run test:e2e -``` \ No newline at end of file +``` + +# How to add new region + +* Activate new region in your TEST and PROD accounts +* Bootstrap a CDKToolkit stack in the new region +```shell + cdk bootstrap aws://AWS_ACCOUNT/NEW_REGION +``` +* Build the layer folder from the project root directory +```shell +bash ./.github/scripts/setup_tmp_layer_files.sh +``` +* Deploy the first layer version to the new region, make sure to set the NEW_REGION in your AWS CLI configuration correctly, otherwise you will deploy to the wrong region +```shell +npm run cdk -w layers -- deploy --app cdk.out --context region=NEW_REGION 'LayerPublisherStack' --require-approval never --verbose +``` +* Run the bumper script to bring all layers to the same version across all regions +* Add new region to the worklflow in `./github/workflows/reusable_deploy_layer_stack.yml` +* Document new region in `docs/index.md` \ No newline at end of file diff --git a/layer-publisher/bin/layer-publisher.ts b/layers/bin/layers.ts similarity index 73% rename from layer-publisher/bin/layer-publisher.ts rename to layers/bin/layers.ts index 4c9c9bf2af..e5eea801e4 100644 --- a/layer-publisher/bin/layer-publisher.ts +++ b/layers/bin/layers.ts @@ -1,13 +1,14 @@ #!/usr/bin/env node import 'source-map-support/register'; -import * as cdk from 'aws-cdk-lib'; +import { App } from 'aws-cdk-lib'; import { LayerPublisherStack } from '../src/layer-publisher-stack'; const SSM_PARAM_LAYER_ARN = '/layers/powertools-layer-arn'; -const app = new cdk.App(); +const app = new App(); + new LayerPublisherStack(app, 'LayerPublisherStack', { - powerToolsPackageVersion: app.node.tryGetContext('PowerToolsPackageVersion'), + powertoolsPackageVersion: app.node.tryGetContext('PowertoolsPackageVersion'), layerName: 'AWSLambdaPowertoolsTypeScript', ssmParameterLayerArn: SSM_PARAM_LAYER_ARN, }); \ No newline at end of file diff --git a/layer-publisher/cdk.json b/layers/cdk.json similarity index 92% rename from layer-publisher/cdk.json rename to layers/cdk.json index 4d1a4ba742..4ca6aac30e 100644 --- a/layer-publisher/cdk.json +++ b/layers/cdk.json @@ -1,5 +1,5 @@ { - "app": "npx ts-node --prefer-ts-exts bin/layer-publisher.ts", + "app": "npx ts-node --prefer-ts-exts bin/layers.ts", "watch": { "include": [ "**" diff --git a/layers/jest.config.js b/layers/jest.config.js new file mode 100644 index 0000000000..4c5e481d90 --- /dev/null +++ b/layers/jest.config.js @@ -0,0 +1,45 @@ +module.exports = { + displayName: { + name: 'AWS Lambda Powertools utility: LAYERS', + color: 'black', + }, + runner: 'groups', + preset: 'ts-jest', + transform: { + '^.+\\.ts?$': 'ts-jest', + }, + moduleFileExtensions: [ 'js', 'ts' ], + 'collectCoverageFrom': [ + '**/src/**/*.ts', + '!**/node_modules/**', + ], + 'testMatch': ['**/?(*.)+(spec|test).ts'], + 'roots': [ + '/src', + '/tests', + ], + 'testPathIgnorePatterns': [ + '/node_modules/', + ], + 'testEnvironment': 'node', + 'coveragePathIgnorePatterns': [ + '/node_modules/', + '/types/', + ], + 'coverageThreshold': { + 'global': { + 'statements': 100, + 'branches': 100, + 'functions': 100, + 'lines': 100, + }, + }, + 'coverageReporters': [ + 'json-summary', + 'text', + 'lcov' + ], + 'setupFiles': [ + '/tests/helpers/populateEnvironmentVariables.ts' + ] +}; \ No newline at end of file diff --git a/layers/package.json b/layers/package.json new file mode 100644 index 0000000000..b8803973df --- /dev/null +++ b/layers/package.json @@ -0,0 +1,35 @@ +{ + "name": "layers", + "version": "1.5.1", + "bin": { + "layer": "bin/layers.js" + }, + "description": "This CDK app is meant to be used to publish Powertools for TypeScript Lambda Layer. It is composed of a single stack deploying the Layer into the target account.", + "scripts": { + "build": "tsc", + "watch": "tsc -w", + "test": "echo 'Not applicable'", + "cdk": "cdk", + "package": "echo 'Not applicable'", + "lint": "eslint --ext .ts --no-error-on-unmatched-pattern src tests", + "lint-fix": "eslint --fix --ext .ts --fix --no-error-on-unmatched-pattern src tests", + "test:unit": "jest --group=unit", + "test:e2e": "RUNTIME=nodejs14x jest --group=e2e" + }, + "repository": { + "type": "git", + "url": "git+https://github.com/awslabs/aws-lambda-powertools-typescript.git" + }, + "author": { + "name": "Amazon Web Services", + "url": "https://aws.amazon.com" + }, + "license": "MIT-0", + "bugs": { + "url": "https://github.com/awslabs/aws-lambda-powertools-typescript/issues" + }, + "homepage": "https://github.com/awslabs/aws-lambda-powertools-typescript#readme", + "devDependencies": { + "source-map-support": "^0.5.21" + } +} \ No newline at end of file diff --git a/layer-publisher/src/layer-publisher-stack.ts b/layers/src/layer-publisher-stack.ts similarity index 60% rename from layer-publisher/src/layer-publisher-stack.ts rename to layers/src/layer-publisher-stack.ts index 47708b30af..875bbd4abf 100644 --- a/layer-publisher/src/layer-publisher-stack.ts +++ b/layers/src/layer-publisher-stack.ts @@ -1,24 +1,42 @@ -import { CfnOutput, RemovalPolicy, Stack, StackProps } from 'aws-cdk-lib'; +import { + CfnOutput, + RemovalPolicy, + Stack, + StackProps +} from 'aws-cdk-lib'; import { Construct } from 'constructs'; -import * as lambda from 'aws-cdk-lib/aws-lambda'; +import { + LayerVersion, + Code, + Runtime, + CfnLayerVersionPermission +} from 'aws-cdk-lib/aws-lambda'; import { StringParameter } from 'aws-cdk-lib/aws-ssm'; -import { CfnLayerVersionPermission } from 'aws-cdk-lib/aws-lambda'; -import { PowerToolsTypeScriptLayer } from './powertools-typescript-layer'; export interface LayerPublisherStackProps extends StackProps { readonly layerName?: string - readonly powerToolsPackageVersion?: string + readonly powertoolsPackageVersion?: string readonly ssmParameterLayerArn: string } export class LayerPublisherStack extends Stack { - public readonly lambdaLayerVersion: lambda.LayerVersion; + public readonly lambdaLayerVersion: LayerVersion; public constructor(scope: Construct, id: string, props: LayerPublisherStackProps) { super(scope, id, props); - this.lambdaLayerVersion = new PowerToolsTypeScriptLayer(this, 'LambdaPowertoolsLayer', { + const { layerName, powertoolsPackageVersion } = props; + + console.log(`publishing layer ${layerName} version : ${powertoolsPackageVersion}`); + + this.lambdaLayerVersion = new LayerVersion(this, 'LambdaPowertoolsLayer', { layerVersionName: props?.layerName, - version: props?.powerToolsPackageVersion, + description: `AWS Lambda Powertools for TypeScript version ${powertoolsPackageVersion}`, + compatibleRuntimes: [ + Runtime.NODEJS_14_X, + Runtime.NODEJS_16_X, + Runtime.NODEJS_18_X + ], + code: Code.fromAsset('../tmp'), }); const layerPermission = new CfnLayerVersionPermission(this, 'PublicLayerAccess', { diff --git a/layers/tests/e2e/constants.ts b/layers/tests/e2e/constants.ts new file mode 100644 index 0000000000..268910c49b --- /dev/null +++ b/layers/tests/e2e/constants.ts @@ -0,0 +1,5 @@ +export const RESOURCE_NAME_PREFIX = 'Layers-E2E'; +export const ONE_MINUTE = 60 * 1000; +export const TEST_CASE_TIMEOUT = 3 * ONE_MINUTE; +export const SETUP_TIMEOUT = 5 * ONE_MINUTE; +export const TEARDOWN_TIMEOUT = 5 * ONE_MINUTE; \ No newline at end of file diff --git a/layers/tests/e2e/layerPublisher.class.test.functionCode.ts b/layers/tests/e2e/layerPublisher.class.test.functionCode.ts new file mode 100644 index 0000000000..aaee959338 --- /dev/null +++ b/layers/tests/e2e/layerPublisher.class.test.functionCode.ts @@ -0,0 +1,46 @@ +import { readFileSync } from 'node:fs'; +import { Logger } from '@aws-lambda-powertools/logger'; +import { Metrics } from '@aws-lambda-powertools/metrics'; +import { Tracer } from '@aws-lambda-powertools/tracer'; + +const logger = new Logger({ + logLevel: 'DEBUG' +}); +const metrics = new Metrics(); +const tracer = new Tracer(); + +export const handler = (): void => { + + // Check that the packages version matches the expected one + try { + const packageJSON = JSON.parse( + readFileSync('/opt/nodejs/node_modules/@aws-lambda-powertools/logger/package.json', { + encoding: 'utf8', + flag: 'r', + }) + ); + + if (packageJSON.version != process.env.POWERTOOLS_PACKAGE_VERSION) { + throw new Error( + `Package version mismatch: ${packageJSON.version} != ${process.env.POWERTOOLS_PACKAGE_VERSION}` + ); + } + } catch (error) { + console.error(error); + } + + // Check that the logger is working + logger.debug('Hello World!'); + + // Check that the metrics is working + metrics.captureColdStartMetric(); + + // Check that the tracer is working + const segment = tracer.getSegment(); + const handlerSegment = segment.addNewSubsegment('### index.handler'); + tracer.setSegment(handlerSegment); + tracer.annotateColdStart(); + handlerSegment.close(); + tracer.setSegment(segment); + +}; \ No newline at end of file diff --git a/layers/tests/e2e/layerPublisher.test.ts b/layers/tests/e2e/layerPublisher.test.ts new file mode 100644 index 0000000000..378bfab1a2 --- /dev/null +++ b/layers/tests/e2e/layerPublisher.test.ts @@ -0,0 +1,147 @@ +/** + * Test LayerPublisherStack class + * + * @group e2e/layers/all + */ +import { App, Stack } from 'aws-cdk-lib'; +import { Tracing } from 'aws-cdk-lib/aws-lambda'; +import { LayerPublisherStack } from '../../src/layer-publisher-stack'; +import { + deployStack, + destroyStack +} from '../../../packages/commons/tests/utils/cdk-cli'; +import { + generateUniqueName, + invokeFunction, + isValidRuntimeKey, + createStackWithLambdaFunction +} from '../../../packages/commons/tests/utils/e2eUtils'; +import { + RESOURCE_NAME_PREFIX, + SETUP_TIMEOUT, + TEARDOWN_TIMEOUT, + TEST_CASE_TIMEOUT +} from './constants'; +import { + LEVEL, + InvocationLogs +} from '../../../packages/commons/tests/utils/InvocationLogs'; +import { v4 } from 'uuid'; +import path from 'path'; +import packageJson from '../../package.json'; + +const runtime: string = process.env.RUNTIME || 'nodejs1x'; + +if (!isValidRuntimeKey(runtime)) { + throw new Error(`Invalid runtime key: ${runtime}`); +} + +describe(`layers E2E tests (LayerPublisherStack) for runtime: ${runtime}`, () => { + + const uuid = v4(); + let invocationLogs: InvocationLogs[]; + const stackNameLayers = generateUniqueName(RESOURCE_NAME_PREFIX, uuid, runtime, 'layerStack'); + const stackNameFunction = generateUniqueName(RESOURCE_NAME_PREFIX, uuid, runtime, 'functionStack'); + const functionName = generateUniqueName(RESOURCE_NAME_PREFIX, uuid, runtime, 'function'); + const ssmParameterLayerName = generateUniqueName(RESOURCE_NAME_PREFIX, uuid, runtime, 'parameter'); + const lambdaFunctionCodeFile = 'layerPublisher.class.test.functionCode.ts'; + + const invocationCount = 1; + + const integTestApp = new App(); + let stackLayer: LayerPublisherStack; + let stackFunction: Stack; + + const powerToolsPackageVersion = packageJson.version; + + beforeAll(async () => { + + const layerName = generateUniqueName(RESOURCE_NAME_PREFIX, uuid, runtime, 'layer'); + + stackLayer = new LayerPublisherStack( + integTestApp, + stackNameLayers, + { + layerName: layerName, + powertoolsPackageVersion: powerToolsPackageVersion, + ssmParameterLayerArn: ssmParameterLayerName, + } + ); + + stackFunction = createStackWithLambdaFunction({ + app: integTestApp, + stackName: stackNameFunction, + functionName: functionName, + functionEntry: path.join(__dirname, lambdaFunctionCodeFile), + tracing: Tracing.ACTIVE, + environment: { + UUID: uuid, + POWERTOOLS_PACKAGE_VERSION: powerToolsPackageVersion, + POWERTOOLS_SERVICE_NAME: 'LayerPublisherStack', + }, + runtime: runtime, + bundling: { + externalModules: [ + '@aws-lambda-powertools/commons', + '@aws-lambda-powertools/logger', + '@aws-lambda-powertools/metrics', + '@aws-lambda-powertools/tracer' + ] + }, + layers: [stackLayer.lambdaLayerVersion], + }); + + await deployStack(integTestApp, stackLayer); + await deployStack(integTestApp, stackFunction); + + invocationLogs = await invokeFunction(functionName, invocationCount, 'SEQUENTIAL'); + + }, SETUP_TIMEOUT); + + describe('LayerPublisherStack usage', () => { + + it('should have no errors in the logs, which indicates the pacakges version matches the expected one', () => { + + const logs = invocationLogs[0].getFunctionLogs(LEVEL.ERROR); + + expect(logs.length).toBe(0); + + }, TEST_CASE_TIMEOUT); + + it('should have one warning related to missing Metrics namespace', () => { + + const logs = invocationLogs[0].getFunctionLogs(LEVEL.WARN); + + expect(logs.length).toBe(1); + expect(logs[0]).toContain('Namespace should be defined, default used'); + + }, TEST_CASE_TIMEOUT); + + it('should have one info log related to coldstart metric', () => { + + const logs = invocationLogs[0].getFunctionLogs(LEVEL.INFO); + + expect(logs.length).toBe(1); + expect(logs[0]).toContain('ColdStart'); + + }, TEST_CASE_TIMEOUT); + + it('should have one debug log that says Hello World!', () => { + + const logs = invocationLogs[0].getFunctionLogs(LEVEL.DEBUG); + + expect(logs.length).toBe(1); + expect(logs[0]).toContain('Hello World!'); + + }, TEST_CASE_TIMEOUT); + + }); + + afterAll(async () => { + if (!process.env.DISABLE_TEARDOWN) { + await destroyStack(integTestApp, stackFunction); + await destroyStack(integTestApp, stackLayer); + } + }, TEARDOWN_TIMEOUT); + +}); \ No newline at end of file diff --git a/layers/tests/helpers/populateEnvironmentVariables.ts b/layers/tests/helpers/populateEnvironmentVariables.ts new file mode 100644 index 0000000000..7ff0774273 --- /dev/null +++ b/layers/tests/helpers/populateEnvironmentVariables.ts @@ -0,0 +1,7 @@ +// Reserved variables +process.env._X_AMZN_TRACE_ID = 'Root=1-5759e988-bd862e3fe1be46a994272793;Parent=557abcec3ee5a047;Sampled=1'; +process.env.AWS_LAMBDA_FUNCTION_NAME = 'my-lambda-function'; +process.env.AWS_LAMBDA_FUNCTION_MEMORY_SIZE = '128'; +if (process.env.AWS_REGION === undefined && process.env.CDK_DEFAULT_REGION === undefined) { + process.env.AWS_REGION = 'eu-west-1'; +} diff --git a/layers/tests/unit/layer-publisher.test.ts b/layers/tests/unit/layer-publisher.test.ts new file mode 100644 index 0000000000..d8df7773db --- /dev/null +++ b/layers/tests/unit/layer-publisher.test.ts @@ -0,0 +1,53 @@ +/** + * Test LayerPublisherStack class + * + * @group unit/layers/all + */ + +import { App } from 'aws-cdk-lib'; +import { Template } from 'aws-cdk-lib/assertions'; +import { + LayerPublisherStack +} from '../../src/layer-publisher-stack'; + +describe('Class: LayerPublisherStack', () => { + + it('creates the stack with a layer in it', () => { + + // Prepare + const app = new App(); + const stack = new LayerPublisherStack(app, 'MyTestStack', { + layerName: 'AWSLambdaPowertoolsTypeScript', + powertoolsPackageVersion: '1.0.1', + ssmParameterLayerArn: '/layers/powertools-layer-arn', + }); + + // Act + const template = Template.fromStack(stack); + + // Assess + template.resourceCountIs('AWS::Lambda::LayerVersion', 1); + template.hasResourceProperties('AWS::Lambda::LayerVersion', { + CompatibleRuntimes: [ + 'nodejs14.x', + 'nodejs16.x', + 'nodejs18.x' + ], + Description: 'AWS Lambda Powertools for TypeScript version 1.0.1', + LayerName: 'AWSLambdaPowertoolsTypeScript', + }); + + template.resourceCountIs('AWS::Lambda::LayerVersionPermission', 1); + template.hasResourceProperties('AWS::Lambda::LayerVersionPermission', { + Action: 'lambda:GetLayerVersion', + Principal: '*', + }); + + template.resourceCountIs('AWS::SSM::Parameter', 1); + template.hasResourceProperties('AWS::SSM::Parameter', { + Name: '/layers/powertools-layer-arn', + Type: 'String', + }); + }); + +}); \ No newline at end of file diff --git a/layer-publisher/tsconfig.es.json b/layers/tsconfig.es.json similarity index 100% rename from layer-publisher/tsconfig.es.json rename to layers/tsconfig.es.json diff --git a/layer-publisher/tsconfig.json b/layers/tsconfig.json similarity index 100% rename from layer-publisher/tsconfig.json rename to layers/tsconfig.json diff --git a/lerna.json b/lerna.json index f22b860fc8..7b3656a4c6 100644 --- a/lerna.json +++ b/lerna.json @@ -8,7 +8,7 @@ "examples/sam", "layer-publisher" ], - "version": "1.5.1", + "version": "1.6.0", "npmClient": "npm", "message": "chore(release): %s [skip ci]" } \ No newline at end of file diff --git a/mkdocs.yml b/mkdocs.yml index 8bdae60ca0..bab9c616bb 100644 --- a/mkdocs.yml +++ b/mkdocs.yml @@ -79,6 +79,10 @@ copyright: Copyright © 2023 Amazon Web Services plugins: - git-revision-date - search + - exclude: + glob: + - snippets/node_modules/* + - snippets/package.json extra_css: - stylesheets/extra.css diff --git a/package-lock.json b/package-lock.json index 5988ec4416..02918f21f8 100644 --- a/package-lock.json +++ b/package-lock.json @@ -14,7 +14,9 @@ "packages/metrics", "packages/tracer", "packages/parameters", - "packages/idempotency" + "packages/idempotency", + "docs/snippets", + "layers" ], "dependencies": { "hosted-git-info": "^6.1.1" @@ -58,6 +60,51 @@ "node": ">=14" } }, + "docs/snippets": { + "name": "docs", + "version": "0.0.1", + "license": "MIT-0", + "devDependencies": { + "@aws-sdk/client-appconfigdata": "^3.245.0", + "@aws-sdk/client-dynamodb": "^3.245.0", + "@aws-sdk/client-secrets-manager": "^3.250.0", + "@aws-sdk/client-ssm": "^3.245.0", + "@aws-sdk/util-dynamodb": "^3.245.0", + "axios": "^1.2.4" + } + }, + "docs/snippets/node_modules/@aws-sdk/util-dynamodb": { + "version": "3.245.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/util-dynamodb/-/util-dynamodb-3.245.0.tgz", + "integrity": "sha512-Wx06Ey92DRRSQTFfpQs1DkHSoajcwVu2TLWTg07yHXgGxdi6EveJPNqh111ot5yzHGmzPIHas/IPZe3hDttzcw==", + "dev": true, + "dependencies": { + "tslib": "^2.3.1" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "layers": { + "version": "1.5.1", + "license": "MIT-0", + "bin": { + "layer": "bin/layers.js" + }, + "devDependencies": { + "source-map-support": "^0.5.21" + } + }, + "layers/node_modules/source-map-support": { + "version": "0.5.21", + "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.21.tgz", + "integrity": "sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w==", + "dev": true, + "dependencies": { + "buffer-from": "^1.0.0", + "source-map": "^0.6.0" + } + }, "node_modules/@ampproject/remapping": { "version": "2.2.0", "resolved": "https://registry.npmjs.org/@ampproject/remapping/-/remapping-2.2.0.tgz", @@ -347,16 +394,16 @@ } }, "node_modules/@aws-sdk/client-appconfigdata": { - "version": "3.241.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/client-appconfigdata/-/client-appconfigdata-3.241.0.tgz", - "integrity": "sha512-5AVfSc6ZQ17dF0cdIrmpEe0H6vmGumBvsFGn89e2clSPtqqtsFDpBeAsS5jCMbxO9pakkCM0RPAh+sci6MnlYg==", + "version": "3.245.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/client-appconfigdata/-/client-appconfigdata-3.245.0.tgz", + "integrity": "sha512-XxyUEEYcL6xvFUnrd10sVtmWaqYTHwn9IfScqyqz2K8wrAnbHPeaWc197UulqhIXYfz11foOAEleiUBKM1kHdw==", "dev": true, "dependencies": { "@aws-crypto/sha256-browser": "2.0.0", "@aws-crypto/sha256-js": "2.0.0", - "@aws-sdk/client-sts": "3.241.0", + "@aws-sdk/client-sts": "3.245.0", "@aws-sdk/config-resolver": "3.234.0", - "@aws-sdk/credential-provider-node": "3.241.0", + "@aws-sdk/credential-provider-node": "3.245.0", "@aws-sdk/fetch-http-handler": "3.226.0", "@aws-sdk/hash-node": "3.226.0", "@aws-sdk/invalid-dependency": "3.226.0", @@ -381,7 +428,7 @@ "@aws-sdk/util-body-length-node": "3.208.0", "@aws-sdk/util-defaults-mode-browser": "3.234.0", "@aws-sdk/util-defaults-mode-node": "3.234.0", - "@aws-sdk/util-endpoints": "3.241.0", + "@aws-sdk/util-endpoints": "3.245.0", "@aws-sdk/util-retry": "3.229.0", "@aws-sdk/util-user-agent-browser": "3.226.0", "@aws-sdk/util-user-agent-node": "3.226.0", @@ -393,25 +440,28 @@ "node": ">=14.0.0" } }, - "node_modules/@aws-sdk/client-appconfigdata/node_modules/@aws-sdk/client-sso": { - "version": "3.241.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/client-sso/-/client-sso-3.241.0.tgz", - "integrity": "sha512-Jm4HR+RYAqKMEYZvvWaq0NYUKKonyInOeubObXH4BLXZpmUBSdYCSjjLdNJY3jkQoxbDVPVMIurVNh5zT5SMRw==", - "dev": true, + "node_modules/@aws-sdk/client-dynamodb": { + "version": "3.245.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/client-dynamodb/-/client-dynamodb-3.245.0.tgz", + "integrity": "sha512-k9zPoUXQ6o91iAIceaDyz1p1tXhA3gcmw4R0oB6gREDGc9bkIqBzwS6+Zu8m4B2PPhZQIl9uMpktHw9NPyMRxA==", "dependencies": { "@aws-crypto/sha256-browser": "2.0.0", "@aws-crypto/sha256-js": "2.0.0", + "@aws-sdk/client-sts": "3.245.0", "@aws-sdk/config-resolver": "3.234.0", + "@aws-sdk/credential-provider-node": "3.245.0", "@aws-sdk/fetch-http-handler": "3.226.0", "@aws-sdk/hash-node": "3.226.0", "@aws-sdk/invalid-dependency": "3.226.0", "@aws-sdk/middleware-content-length": "3.226.0", "@aws-sdk/middleware-endpoint": "3.226.0", + "@aws-sdk/middleware-endpoint-discovery": "3.234.0", "@aws-sdk/middleware-host-header": "3.226.0", "@aws-sdk/middleware-logger": "3.226.0", "@aws-sdk/middleware-recursion-detection": "3.226.0", "@aws-sdk/middleware-retry": "3.235.0", "@aws-sdk/middleware-serde": "3.226.0", + "@aws-sdk/middleware-signing": "3.226.0", "@aws-sdk/middleware-stack": "3.226.0", "@aws-sdk/middleware-user-agent": "3.226.0", "@aws-sdk/node-config-provider": "3.226.0", @@ -425,27 +475,39 @@ "@aws-sdk/util-body-length-node": "3.208.0", "@aws-sdk/util-defaults-mode-browser": "3.234.0", "@aws-sdk/util-defaults-mode-node": "3.234.0", - "@aws-sdk/util-endpoints": "3.241.0", + "@aws-sdk/util-endpoints": "3.245.0", "@aws-sdk/util-retry": "3.229.0", "@aws-sdk/util-user-agent-browser": "3.226.0", "@aws-sdk/util-user-agent-node": "3.226.0", "@aws-sdk/util-utf8-browser": "3.188.0", "@aws-sdk/util-utf8-node": "3.208.0", - "tslib": "^2.3.1" + "@aws-sdk/util-waiter": "3.226.0", + "tslib": "^2.3.1", + "uuid": "^8.3.2" }, "engines": { "node": ">=14.0.0" } }, - "node_modules/@aws-sdk/client-appconfigdata/node_modules/@aws-sdk/client-sso-oidc": { - "version": "3.241.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/client-sso-oidc/-/client-sso-oidc-3.241.0.tgz", - "integrity": "sha512-/Ml2QBGpGfUEeBrPzBZhSTBkHuXFD2EAZEIHGCBH4tKaURDI6/FoGI8P1Rl4BzoFt+II/Cr91Eox6YT9EwChsQ==", + "node_modules/@aws-sdk/client-dynamodb/node_modules/uuid": { + "version": "8.3.2", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz", + "integrity": "sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==", + "bin": { + "uuid": "dist/bin/uuid" + } + }, + "node_modules/@aws-sdk/client-secrets-manager": { + "version": "3.250.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/client-secrets-manager/-/client-secrets-manager-3.250.0.tgz", + "integrity": "sha512-CB4OcFJPpAuW3rRXBxgOtF9RXHBixEvJSDkh8RsCAamt37Fw61+e+CsdXixSWA4rzQA+3PQuts7zlwhcxobbJg==", "dev": true, "dependencies": { "@aws-crypto/sha256-browser": "2.0.0", "@aws-crypto/sha256-js": "2.0.0", + "@aws-sdk/client-sts": "3.245.0", "@aws-sdk/config-resolver": "3.234.0", + "@aws-sdk/credential-provider-node": "3.245.0", "@aws-sdk/fetch-http-handler": "3.226.0", "@aws-sdk/hash-node": "3.226.0", "@aws-sdk/invalid-dependency": "3.226.0", @@ -456,6 +518,7 @@ "@aws-sdk/middleware-recursion-detection": "3.226.0", "@aws-sdk/middleware-retry": "3.235.0", "@aws-sdk/middleware-serde": "3.226.0", + "@aws-sdk/middleware-signing": "3.226.0", "@aws-sdk/middleware-stack": "3.226.0", "@aws-sdk/middleware-user-agent": "3.226.0", "@aws-sdk/node-config-provider": "3.226.0", @@ -469,28 +532,39 @@ "@aws-sdk/util-body-length-node": "3.208.0", "@aws-sdk/util-defaults-mode-browser": "3.234.0", "@aws-sdk/util-defaults-mode-node": "3.234.0", - "@aws-sdk/util-endpoints": "3.241.0", + "@aws-sdk/util-endpoints": "3.245.0", "@aws-sdk/util-retry": "3.229.0", "@aws-sdk/util-user-agent-browser": "3.226.0", "@aws-sdk/util-user-agent-node": "3.226.0", "@aws-sdk/util-utf8-browser": "3.188.0", "@aws-sdk/util-utf8-node": "3.208.0", - "tslib": "^2.3.1" + "tslib": "^2.3.1", + "uuid": "^8.3.2" }, "engines": { "node": ">=14.0.0" } }, - "node_modules/@aws-sdk/client-appconfigdata/node_modules/@aws-sdk/client-sts": { - "version": "3.241.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/client-sts/-/client-sts-3.241.0.tgz", - "integrity": "sha512-vmlG8cJzRf8skCtTJbA2wBvD2c3NQ5gZryzJvTKDS06KzBzcEpnjlLseuTekcnOiRNekbFUX5hRu5Zj3N2ReLg==", + "node_modules/@aws-sdk/client-secrets-manager/node_modules/uuid": { + "version": "8.3.2", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz", + "integrity": "sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==", + "dev": true, + "bin": { + "uuid": "dist/bin/uuid" + } + }, + "node_modules/@aws-sdk/client-ssm": { + "version": "3.245.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/client-ssm/-/client-ssm-3.245.0.tgz", + "integrity": "sha512-btn2aBWH8QgkOiwIVcCF94fTmfiAdq5usE+YNSGG1QkvEQlkOQQHOY+UeusG7U+zqLjwa0Kbeqa2Uy023IzYWg==", "dev": true, "dependencies": { "@aws-crypto/sha256-browser": "2.0.0", "@aws-crypto/sha256-js": "2.0.0", + "@aws-sdk/client-sts": "3.245.0", "@aws-sdk/config-resolver": "3.234.0", - "@aws-sdk/credential-provider-node": "3.241.0", + "@aws-sdk/credential-provider-node": "3.245.0", "@aws-sdk/fetch-http-handler": "3.226.0", "@aws-sdk/hash-node": "3.226.0", "@aws-sdk/invalid-dependency": "3.226.0", @@ -500,7 +574,6 @@ "@aws-sdk/middleware-logger": "3.226.0", "@aws-sdk/middleware-recursion-detection": "3.226.0", "@aws-sdk/middleware-retry": "3.235.0", - "@aws-sdk/middleware-sdk-sts": "3.226.0", "@aws-sdk/middleware-serde": "3.226.0", "@aws-sdk/middleware-signing": "3.226.0", "@aws-sdk/middleware-stack": "3.226.0", @@ -516,104 +589,13 @@ "@aws-sdk/util-body-length-node": "3.208.0", "@aws-sdk/util-defaults-mode-browser": "3.234.0", "@aws-sdk/util-defaults-mode-node": "3.234.0", - "@aws-sdk/util-endpoints": "3.241.0", + "@aws-sdk/util-endpoints": "3.245.0", "@aws-sdk/util-retry": "3.229.0", "@aws-sdk/util-user-agent-browser": "3.226.0", "@aws-sdk/util-user-agent-node": "3.226.0", "@aws-sdk/util-utf8-browser": "3.188.0", "@aws-sdk/util-utf8-node": "3.208.0", - "fast-xml-parser": "4.0.11", - "tslib": "^2.3.1" - }, - "engines": { - "node": ">=14.0.0" - } - }, - "node_modules/@aws-sdk/client-appconfigdata/node_modules/@aws-sdk/config-resolver": { - "version": "3.234.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/config-resolver/-/config-resolver-3.234.0.tgz", - "integrity": "sha512-uZxy4wzllfvgCQxVc+Iqhde0NGAnfmV2hWR6ejadJaAFTuYNvQiRg9IqJy3pkyDPqXySiJ8Bom5PoJfgn55J/A==", - "dev": true, - "dependencies": { - "@aws-sdk/signature-v4": "3.226.0", - "@aws-sdk/types": "3.226.0", - "@aws-sdk/util-config-provider": "3.208.0", - "@aws-sdk/util-middleware": "3.226.0", - "tslib": "^2.3.1" - }, - "engines": { - "node": ">=14.0.0" - } - }, - "node_modules/@aws-sdk/client-appconfigdata/node_modules/@aws-sdk/credential-provider-ini": { - "version": "3.241.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-ini/-/credential-provider-ini-3.241.0.tgz", - "integrity": "sha512-CI+mu6h74Kzmscw35TvNkc/wYHsHPGAwP7humSHoWw53H9mVw21Ggft/dT1iFQQZWQ8BNXkzuXlNo1IlqwMgOA==", - "dev": true, - "dependencies": { - "@aws-sdk/credential-provider-env": "3.226.0", - "@aws-sdk/credential-provider-imds": "3.226.0", - "@aws-sdk/credential-provider-process": "3.226.0", - "@aws-sdk/credential-provider-sso": "3.241.0", - "@aws-sdk/credential-provider-web-identity": "3.226.0", - "@aws-sdk/property-provider": "3.226.0", - "@aws-sdk/shared-ini-file-loader": "3.226.0", - "@aws-sdk/types": "3.226.0", - "tslib": "^2.3.1" - }, - "engines": { - "node": ">=14.0.0" - } - }, - "node_modules/@aws-sdk/client-appconfigdata/node_modules/@aws-sdk/credential-provider-node": { - "version": "3.241.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-node/-/credential-provider-node-3.241.0.tgz", - "integrity": "sha512-08zPQcD5o9brQmzEipWHeHgU85aQcEF8MWLfpeyjO6e1/l7ysQ35NsS+PYtv77nLpGCx/X+ZuW/KXWoRrbw77w==", - "dev": true, - "dependencies": { - "@aws-sdk/credential-provider-env": "3.226.0", - "@aws-sdk/credential-provider-imds": "3.226.0", - "@aws-sdk/credential-provider-ini": "3.241.0", - "@aws-sdk/credential-provider-process": "3.226.0", - "@aws-sdk/credential-provider-sso": "3.241.0", - "@aws-sdk/credential-provider-web-identity": "3.226.0", - "@aws-sdk/property-provider": "3.226.0", - "@aws-sdk/shared-ini-file-loader": "3.226.0", - "@aws-sdk/types": "3.226.0", - "tslib": "^2.3.1" - }, - "engines": { - "node": ">=14.0.0" - } - }, - "node_modules/@aws-sdk/client-appconfigdata/node_modules/@aws-sdk/credential-provider-sso": { - "version": "3.241.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-sso/-/credential-provider-sso-3.241.0.tgz", - "integrity": "sha512-6Bjd6eEIrVomRTrPrM4dlxusQm+KMJ9hLYKECCpFkwDKIK+pTgZNLRtQdalHyzwneHJPdimrm8cOv1kUQ8hPoA==", - "dev": true, - "dependencies": { - "@aws-sdk/client-sso": "3.241.0", - "@aws-sdk/property-provider": "3.226.0", - "@aws-sdk/shared-ini-file-loader": "3.226.0", - "@aws-sdk/token-providers": "3.241.0", - "@aws-sdk/types": "3.226.0", - "tslib": "^2.3.1" - }, - "engines": { - "node": ">=14.0.0" - } - }, - "node_modules/@aws-sdk/client-appconfigdata/node_modules/@aws-sdk/middleware-retry": { - "version": "3.235.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-retry/-/middleware-retry-3.235.0.tgz", - "integrity": "sha512-50WHbJGpD3SNp9763MAlHqIhXil++JdQbKejNpHg7HsJne/ao3ub+fDOfx//mMBjpzBV25BGd5UlfL6blrClSg==", - "dev": true, - "dependencies": { - "@aws-sdk/protocol-http": "3.226.0", - "@aws-sdk/service-error-classification": "3.229.0", - "@aws-sdk/types": "3.226.0", - "@aws-sdk/util-middleware": "3.226.0", - "@aws-sdk/util-retry": "3.229.0", + "@aws-sdk/util-waiter": "3.226.0", "tslib": "^2.3.1", "uuid": "^8.3.2" }, @@ -621,82 +603,7 @@ "node": ">=14.0.0" } }, - "node_modules/@aws-sdk/client-appconfigdata/node_modules/@aws-sdk/smithy-client": { - "version": "3.234.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/smithy-client/-/smithy-client-3.234.0.tgz", - "integrity": "sha512-8AtR/k4vsFvjXeQbIzq/Wy7Nbk48Ou0wUEeVYPHWHPSU8QamFWORkOwmKtKMfHAyZvmqiAPeQqHFkq+UJhWyyQ==", - "dev": true, - "dependencies": { - "@aws-sdk/middleware-stack": "3.226.0", - "@aws-sdk/types": "3.226.0", - "tslib": "^2.3.1" - }, - "engines": { - "node": ">=14.0.0" - } - }, - "node_modules/@aws-sdk/client-appconfigdata/node_modules/@aws-sdk/token-providers": { - "version": "3.241.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/token-providers/-/token-providers-3.241.0.tgz", - "integrity": "sha512-79okvuOS7V559OIL/RalIPG98wzmWxeFOChFnbEjn2pKOyGQ6FJRwLPYZaVRtNdAtnkBNgRpmFq9dX843QxhtQ==", - "dev": true, - "dependencies": { - "@aws-sdk/client-sso-oidc": "3.241.0", - "@aws-sdk/property-provider": "3.226.0", - "@aws-sdk/shared-ini-file-loader": "3.226.0", - "@aws-sdk/types": "3.226.0", - "tslib": "^2.3.1" - }, - "engines": { - "node": ">=14.0.0" - } - }, - "node_modules/@aws-sdk/client-appconfigdata/node_modules/@aws-sdk/util-defaults-mode-browser": { - "version": "3.234.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/util-defaults-mode-browser/-/util-defaults-mode-browser-3.234.0.tgz", - "integrity": "sha512-IHMKXjTbOD8XMz5+2oCOsVP94BYb9YyjXdns0aAXr2NAo7k2+RCzXQ2DebJXppGda1F6opFutoKwyVSN0cmbMw==", - "dev": true, - "dependencies": { - "@aws-sdk/property-provider": "3.226.0", - "@aws-sdk/types": "3.226.0", - "bowser": "^2.11.0", - "tslib": "^2.3.1" - }, - "engines": { - "node": ">= 10.0.0" - } - }, - "node_modules/@aws-sdk/client-appconfigdata/node_modules/@aws-sdk/util-defaults-mode-node": { - "version": "3.234.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/util-defaults-mode-node/-/util-defaults-mode-node-3.234.0.tgz", - "integrity": "sha512-UGjQ+OjBYYhxFVtUY+jtr0ZZgzZh6OHtYwRhFt8IHewJXFCfZTyfsbX20szBj5y1S4HRIUJ7cwBLIytTqMbI5w==", - "dev": true, - "dependencies": { - "@aws-sdk/config-resolver": "3.234.0", - "@aws-sdk/credential-provider-imds": "3.226.0", - "@aws-sdk/node-config-provider": "3.226.0", - "@aws-sdk/property-provider": "3.226.0", - "@aws-sdk/types": "3.226.0", - "tslib": "^2.3.1" - }, - "engines": { - "node": ">= 10.0.0" - } - }, - "node_modules/@aws-sdk/client-appconfigdata/node_modules/@aws-sdk/util-endpoints": { - "version": "3.241.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/util-endpoints/-/util-endpoints-3.241.0.tgz", - "integrity": "sha512-jVf8bKrN22Ey0xLmj75sL7EUvm5HFpuOMkXsZkuXycKhCwLBcEUWlvtJYtRjOU1zScPQv9GMJd2QXQglp34iOQ==", - "dev": true, - "dependencies": { - "@aws-sdk/types": "3.226.0", - "tslib": "^2.3.1" - }, - "engines": { - "node": ">=14.0.0" - } - }, - "node_modules/@aws-sdk/client-appconfigdata/node_modules/uuid": { + "node_modules/@aws-sdk/client-ssm/node_modules/uuid": { "version": "8.3.2", "resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz", "integrity": "sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==", @@ -705,28 +612,24 @@ "uuid": "dist/bin/uuid" } }, - "node_modules/@aws-sdk/client-dynamodb": { + "node_modules/@aws-sdk/client-sso": { "version": "3.245.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/client-dynamodb/-/client-dynamodb-3.245.0.tgz", - "integrity": "sha512-k9zPoUXQ6o91iAIceaDyz1p1tXhA3gcmw4R0oB6gREDGc9bkIqBzwS6+Zu8m4B2PPhZQIl9uMpktHw9NPyMRxA==", + "resolved": "https://registry.npmjs.org/@aws-sdk/client-sso/-/client-sso-3.245.0.tgz", + "integrity": "sha512-dxzRwRo55ZNQ4hQigC+cishxLSWlBrbr3iszG0FLviavLDOlnVG5UUxWpOIGvwr8pYiSfM4jnfMxiwYwiCLg1g==", "dependencies": { "@aws-crypto/sha256-browser": "2.0.0", "@aws-crypto/sha256-js": "2.0.0", - "@aws-sdk/client-sts": "3.245.0", "@aws-sdk/config-resolver": "3.234.0", - "@aws-sdk/credential-provider-node": "3.245.0", "@aws-sdk/fetch-http-handler": "3.226.0", "@aws-sdk/hash-node": "3.226.0", "@aws-sdk/invalid-dependency": "3.226.0", "@aws-sdk/middleware-content-length": "3.226.0", "@aws-sdk/middleware-endpoint": "3.226.0", - "@aws-sdk/middleware-endpoint-discovery": "3.234.0", "@aws-sdk/middleware-host-header": "3.226.0", "@aws-sdk/middleware-logger": "3.226.0", "@aws-sdk/middleware-recursion-detection": "3.226.0", "@aws-sdk/middleware-retry": "3.235.0", "@aws-sdk/middleware-serde": "3.226.0", - "@aws-sdk/middleware-signing": "3.226.0", "@aws-sdk/middleware-stack": "3.226.0", "@aws-sdk/middleware-user-agent": "3.226.0", "@aws-sdk/node-config-provider": "3.226.0", @@ -746,180 +649,20 @@ "@aws-sdk/util-user-agent-node": "3.226.0", "@aws-sdk/util-utf8-browser": "3.188.0", "@aws-sdk/util-utf8-node": "3.208.0", - "@aws-sdk/util-waiter": "3.226.0", - "tslib": "^2.3.1", - "uuid": "^8.3.2" + "tslib": "^2.3.1" }, "engines": { "node": ">=14.0.0" } }, - "node_modules/@aws-sdk/client-dynamodb/node_modules/@aws-sdk/util-endpoints": { + "node_modules/@aws-sdk/client-sso-oidc": { "version": "3.245.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/util-endpoints/-/util-endpoints-3.245.0.tgz", - "integrity": "sha512-UNOFquB1tKx+8RT8n82Zb5tIwDyZHVPBg/m0LB0RsLETjr6krien5ASpqWezsXKIR1hftN9uaxN4bvf2dZrWHg==", - "dependencies": { - "@aws-sdk/types": "3.226.0", - "tslib": "^2.3.1" - }, - "engines": { - "node": ">=14.0.0" - } - }, - "node_modules/@aws-sdk/client-dynamodb/node_modules/uuid": { - "version": "8.3.2", - "resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz", - "integrity": "sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==", - "bin": { - "uuid": "dist/bin/uuid" - } - }, - "node_modules/@aws-sdk/client-secrets-manager": { - "version": "3.238.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/client-secrets-manager/-/client-secrets-manager-3.238.0.tgz", - "integrity": "sha512-J3lmceh2txILEh8tWf4ldp8ThAh2WJBSa1t8oJhW58KuE+1a7cwOpgWO6MsSvOrGtp7qzTr8GMBUf7KLdv7wOg==", - "dev": true, - "dependencies": { - "@aws-crypto/sha256-browser": "2.0.0", - "@aws-crypto/sha256-js": "2.0.0", - "@aws-sdk/client-sts": "3.238.0", - "@aws-sdk/config-resolver": "3.234.0", - "@aws-sdk/credential-provider-node": "3.238.0", - "@aws-sdk/fetch-http-handler": "3.226.0", - "@aws-sdk/hash-node": "3.226.0", - "@aws-sdk/invalid-dependency": "3.226.0", - "@aws-sdk/middleware-content-length": "3.226.0", - "@aws-sdk/middleware-endpoint": "3.226.0", - "@aws-sdk/middleware-host-header": "3.226.0", - "@aws-sdk/middleware-logger": "3.226.0", - "@aws-sdk/middleware-recursion-detection": "3.226.0", - "@aws-sdk/middleware-retry": "3.235.0", - "@aws-sdk/middleware-serde": "3.226.0", - "@aws-sdk/middleware-signing": "3.226.0", - "@aws-sdk/middleware-stack": "3.226.0", - "@aws-sdk/middleware-user-agent": "3.226.0", - "@aws-sdk/node-config-provider": "3.226.0", - "@aws-sdk/node-http-handler": "3.226.0", - "@aws-sdk/protocol-http": "3.226.0", - "@aws-sdk/smithy-client": "3.234.0", - "@aws-sdk/types": "3.226.0", - "@aws-sdk/url-parser": "3.226.0", - "@aws-sdk/util-base64": "3.208.0", - "@aws-sdk/util-body-length-browser": "3.188.0", - "@aws-sdk/util-body-length-node": "3.208.0", - "@aws-sdk/util-defaults-mode-browser": "3.234.0", - "@aws-sdk/util-defaults-mode-node": "3.234.0", - "@aws-sdk/util-endpoints": "3.226.0", - "@aws-sdk/util-retry": "3.229.0", - "@aws-sdk/util-user-agent-browser": "3.226.0", - "@aws-sdk/util-user-agent-node": "3.226.0", - "@aws-sdk/util-utf8-browser": "3.188.0", - "@aws-sdk/util-utf8-node": "3.208.0", - "tslib": "^2.3.1", - "uuid": "^8.3.2" - }, - "engines": { - "node": ">=14.0.0" - } - }, - "node_modules/@aws-sdk/client-secrets-manager/node_modules/@aws-sdk/client-sso": { - "version": "3.238.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/client-sso/-/client-sso-3.238.0.tgz", - "integrity": "sha512-KHJJWP7hBDa9KLYiU5+hOb+3AAba93PhWebXkpKyQ/Bs+e7ECCreyLCwuME6uWTV01NDuFDpwZ6zUMpyNIcP6Q==", - "dev": true, - "dependencies": { - "@aws-crypto/sha256-browser": "2.0.0", - "@aws-crypto/sha256-js": "2.0.0", - "@aws-sdk/config-resolver": "3.234.0", - "@aws-sdk/fetch-http-handler": "3.226.0", - "@aws-sdk/hash-node": "3.226.0", - "@aws-sdk/invalid-dependency": "3.226.0", - "@aws-sdk/middleware-content-length": "3.226.0", - "@aws-sdk/middleware-endpoint": "3.226.0", - "@aws-sdk/middleware-host-header": "3.226.0", - "@aws-sdk/middleware-logger": "3.226.0", - "@aws-sdk/middleware-recursion-detection": "3.226.0", - "@aws-sdk/middleware-retry": "3.235.0", - "@aws-sdk/middleware-serde": "3.226.0", - "@aws-sdk/middleware-stack": "3.226.0", - "@aws-sdk/middleware-user-agent": "3.226.0", - "@aws-sdk/node-config-provider": "3.226.0", - "@aws-sdk/node-http-handler": "3.226.0", - "@aws-sdk/protocol-http": "3.226.0", - "@aws-sdk/smithy-client": "3.234.0", - "@aws-sdk/types": "3.226.0", - "@aws-sdk/url-parser": "3.226.0", - "@aws-sdk/util-base64": "3.208.0", - "@aws-sdk/util-body-length-browser": "3.188.0", - "@aws-sdk/util-body-length-node": "3.208.0", - "@aws-sdk/util-defaults-mode-browser": "3.234.0", - "@aws-sdk/util-defaults-mode-node": "3.234.0", - "@aws-sdk/util-endpoints": "3.226.0", - "@aws-sdk/util-retry": "3.229.0", - "@aws-sdk/util-user-agent-browser": "3.226.0", - "@aws-sdk/util-user-agent-node": "3.226.0", - "@aws-sdk/util-utf8-browser": "3.188.0", - "@aws-sdk/util-utf8-node": "3.208.0", - "tslib": "^2.3.1" - }, - "engines": { - "node": ">=14.0.0" - } - }, - "node_modules/@aws-sdk/client-secrets-manager/node_modules/@aws-sdk/client-sso-oidc": { - "version": "3.238.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/client-sso-oidc/-/client-sso-oidc-3.238.0.tgz", - "integrity": "sha512-kazcA2Kp+cXQRtaZi5/T5YFfU9J3nzu1tXJsh0xAm+J3S9LS1ertY1bSX6KBed2xuxx2mfum8JRqli0TJad/pA==", - "dev": true, - "dependencies": { - "@aws-crypto/sha256-browser": "2.0.0", - "@aws-crypto/sha256-js": "2.0.0", - "@aws-sdk/config-resolver": "3.234.0", - "@aws-sdk/fetch-http-handler": "3.226.0", - "@aws-sdk/hash-node": "3.226.0", - "@aws-sdk/invalid-dependency": "3.226.0", - "@aws-sdk/middleware-content-length": "3.226.0", - "@aws-sdk/middleware-endpoint": "3.226.0", - "@aws-sdk/middleware-host-header": "3.226.0", - "@aws-sdk/middleware-logger": "3.226.0", - "@aws-sdk/middleware-recursion-detection": "3.226.0", - "@aws-sdk/middleware-retry": "3.235.0", - "@aws-sdk/middleware-serde": "3.226.0", - "@aws-sdk/middleware-stack": "3.226.0", - "@aws-sdk/middleware-user-agent": "3.226.0", - "@aws-sdk/node-config-provider": "3.226.0", - "@aws-sdk/node-http-handler": "3.226.0", - "@aws-sdk/protocol-http": "3.226.0", - "@aws-sdk/smithy-client": "3.234.0", - "@aws-sdk/types": "3.226.0", - "@aws-sdk/url-parser": "3.226.0", - "@aws-sdk/util-base64": "3.208.0", - "@aws-sdk/util-body-length-browser": "3.188.0", - "@aws-sdk/util-body-length-node": "3.208.0", - "@aws-sdk/util-defaults-mode-browser": "3.234.0", - "@aws-sdk/util-defaults-mode-node": "3.234.0", - "@aws-sdk/util-endpoints": "3.226.0", - "@aws-sdk/util-retry": "3.229.0", - "@aws-sdk/util-user-agent-browser": "3.226.0", - "@aws-sdk/util-user-agent-node": "3.226.0", - "@aws-sdk/util-utf8-browser": "3.188.0", - "@aws-sdk/util-utf8-node": "3.208.0", - "tslib": "^2.3.1" - }, - "engines": { - "node": ">=14.0.0" - } - }, - "node_modules/@aws-sdk/client-secrets-manager/node_modules/@aws-sdk/client-sts": { - "version": "3.238.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/client-sts/-/client-sts-3.238.0.tgz", - "integrity": "sha512-jQNwHqxWUGvWCN4o8KUFYQES8r41Oobu7x1KZOMrPhPxy27FUcDjBq/h85VoD2/AZlETSCZLiCnKV3KBh5pT5w==", - "dev": true, + "resolved": "https://registry.npmjs.org/@aws-sdk/client-sso-oidc/-/client-sso-oidc-3.245.0.tgz", + "integrity": "sha512-0pGPA00kEsu2Yq1Ul+OwftHxws5YVllm4iZrPtGnqmXr7wmf6B9lOtrMQF44y7Tfw53po6+bKz08OKTEWkkjUA==", "dependencies": { "@aws-crypto/sha256-browser": "2.0.0", "@aws-crypto/sha256-js": "2.0.0", "@aws-sdk/config-resolver": "3.234.0", - "@aws-sdk/credential-provider-node": "3.238.0", "@aws-sdk/fetch-http-handler": "3.226.0", "@aws-sdk/hash-node": "3.226.0", "@aws-sdk/invalid-dependency": "3.226.0", @@ -929,323 +672,26 @@ "@aws-sdk/middleware-logger": "3.226.0", "@aws-sdk/middleware-recursion-detection": "3.226.0", "@aws-sdk/middleware-retry": "3.235.0", - "@aws-sdk/middleware-sdk-sts": "3.226.0", "@aws-sdk/middleware-serde": "3.226.0", - "@aws-sdk/middleware-signing": "3.226.0", "@aws-sdk/middleware-stack": "3.226.0", "@aws-sdk/middleware-user-agent": "3.226.0", "@aws-sdk/node-config-provider": "3.226.0", "@aws-sdk/node-http-handler": "3.226.0", - "@aws-sdk/protocol-http": "3.226.0", - "@aws-sdk/smithy-client": "3.234.0", - "@aws-sdk/types": "3.226.0", - "@aws-sdk/url-parser": "3.226.0", - "@aws-sdk/util-base64": "3.208.0", - "@aws-sdk/util-body-length-browser": "3.188.0", - "@aws-sdk/util-body-length-node": "3.208.0", - "@aws-sdk/util-defaults-mode-browser": "3.234.0", - "@aws-sdk/util-defaults-mode-node": "3.234.0", - "@aws-sdk/util-endpoints": "3.226.0", - "@aws-sdk/util-retry": "3.229.0", - "@aws-sdk/util-user-agent-browser": "3.226.0", - "@aws-sdk/util-user-agent-node": "3.226.0", - "@aws-sdk/util-utf8-browser": "3.188.0", - "@aws-sdk/util-utf8-node": "3.208.0", - "fast-xml-parser": "4.0.11", - "tslib": "^2.3.1" - }, - "engines": { - "node": ">=14.0.0" - } - }, - "node_modules/@aws-sdk/client-secrets-manager/node_modules/@aws-sdk/config-resolver": { - "version": "3.234.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/config-resolver/-/config-resolver-3.234.0.tgz", - "integrity": "sha512-uZxy4wzllfvgCQxVc+Iqhde0NGAnfmV2hWR6ejadJaAFTuYNvQiRg9IqJy3pkyDPqXySiJ8Bom5PoJfgn55J/A==", - "dev": true, - "dependencies": { - "@aws-sdk/signature-v4": "3.226.0", - "@aws-sdk/types": "3.226.0", - "@aws-sdk/util-config-provider": "3.208.0", - "@aws-sdk/util-middleware": "3.226.0", - "tslib": "^2.3.1" - }, - "engines": { - "node": ">=14.0.0" - } - }, - "node_modules/@aws-sdk/client-secrets-manager/node_modules/@aws-sdk/credential-provider-ini": { - "version": "3.238.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-ini/-/credential-provider-ini-3.238.0.tgz", - "integrity": "sha512-WmPNtIYyUasjV7VQxvPNq7ihmx0vFsiKAtjNjjakdrt5TPoma4nUYb9tIG9SuG+kcp4DJIgRLJAgZtXbCcVimg==", - "dev": true, - "dependencies": { - "@aws-sdk/credential-provider-env": "3.226.0", - "@aws-sdk/credential-provider-imds": "3.226.0", - "@aws-sdk/credential-provider-process": "3.226.0", - "@aws-sdk/credential-provider-sso": "3.238.0", - "@aws-sdk/credential-provider-web-identity": "3.226.0", - "@aws-sdk/property-provider": "3.226.0", - "@aws-sdk/shared-ini-file-loader": "3.226.0", - "@aws-sdk/types": "3.226.0", - "tslib": "^2.3.1" - }, - "engines": { - "node": ">=14.0.0" - } - }, - "node_modules/@aws-sdk/client-secrets-manager/node_modules/@aws-sdk/credential-provider-node": { - "version": "3.238.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-node/-/credential-provider-node-3.238.0.tgz", - "integrity": "sha512-/RN5EyGfgdIIJdFzv+O0nSaHX1/F3anQjTIBeVg8GJ+82m+bDxMdALsG+NzkYnLilN9Uhc1lSNjLBCoPa5DSEg==", - "dev": true, - "dependencies": { - "@aws-sdk/credential-provider-env": "3.226.0", - "@aws-sdk/credential-provider-imds": "3.226.0", - "@aws-sdk/credential-provider-ini": "3.238.0", - "@aws-sdk/credential-provider-process": "3.226.0", - "@aws-sdk/credential-provider-sso": "3.238.0", - "@aws-sdk/credential-provider-web-identity": "3.226.0", - "@aws-sdk/property-provider": "3.226.0", - "@aws-sdk/shared-ini-file-loader": "3.226.0", - "@aws-sdk/types": "3.226.0", - "tslib": "^2.3.1" - }, - "engines": { - "node": ">=14.0.0" - } - }, - "node_modules/@aws-sdk/client-secrets-manager/node_modules/@aws-sdk/credential-provider-sso": { - "version": "3.238.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-sso/-/credential-provider-sso-3.238.0.tgz", - "integrity": "sha512-i70V4bFlCVYey3QARJ6XxKEg/4YuoFRnePV2oK37UHOGpEn49uXKwVZqLjzJgFHln7BPlC06cWDqrHUQIMvYrQ==", - "dev": true, - "dependencies": { - "@aws-sdk/client-sso": "3.238.0", - "@aws-sdk/property-provider": "3.226.0", - "@aws-sdk/shared-ini-file-loader": "3.226.0", - "@aws-sdk/token-providers": "3.238.0", - "@aws-sdk/types": "3.226.0", - "tslib": "^2.3.1" - }, - "engines": { - "node": ">=14.0.0" - } - }, - "node_modules/@aws-sdk/client-secrets-manager/node_modules/@aws-sdk/smithy-client": { - "version": "3.234.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/smithy-client/-/smithy-client-3.234.0.tgz", - "integrity": "sha512-8AtR/k4vsFvjXeQbIzq/Wy7Nbk48Ou0wUEeVYPHWHPSU8QamFWORkOwmKtKMfHAyZvmqiAPeQqHFkq+UJhWyyQ==", - "dev": true, - "dependencies": { - "@aws-sdk/middleware-stack": "3.226.0", - "@aws-sdk/types": "3.226.0", - "tslib": "^2.3.1" - }, - "engines": { - "node": ">=14.0.0" - } - }, - "node_modules/@aws-sdk/client-secrets-manager/node_modules/@aws-sdk/token-providers": { - "version": "3.238.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/token-providers/-/token-providers-3.238.0.tgz", - "integrity": "sha512-vYUwmy0kTzA99mJCVvad+/5RDlWve/xxnppT8DJK3JIdAgskp+rULY+joVnq2NSl489UAioUnFGs57vUxi8Pog==", - "dev": true, - "dependencies": { - "@aws-sdk/client-sso-oidc": "3.238.0", - "@aws-sdk/property-provider": "3.226.0", - "@aws-sdk/shared-ini-file-loader": "3.226.0", - "@aws-sdk/types": "3.226.0", - "tslib": "^2.3.1" - }, - "engines": { - "node": ">=14.0.0" - } - }, - "node_modules/@aws-sdk/client-secrets-manager/node_modules/uuid": { - "version": "8.3.2", - "resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz", - "integrity": "sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==", - "dev": true, - "bin": { - "uuid": "dist/bin/uuid" - } - }, - "node_modules/@aws-sdk/client-ssm": { - "version": "3.245.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/client-ssm/-/client-ssm-3.245.0.tgz", - "integrity": "sha512-btn2aBWH8QgkOiwIVcCF94fTmfiAdq5usE+YNSGG1QkvEQlkOQQHOY+UeusG7U+zqLjwa0Kbeqa2Uy023IzYWg==", - "dev": true, - "dependencies": { - "@aws-crypto/sha256-browser": "2.0.0", - "@aws-crypto/sha256-js": "2.0.0", - "@aws-sdk/client-sts": "3.245.0", - "@aws-sdk/config-resolver": "3.234.0", - "@aws-sdk/credential-provider-node": "3.245.0", - "@aws-sdk/fetch-http-handler": "3.226.0", - "@aws-sdk/hash-node": "3.226.0", - "@aws-sdk/invalid-dependency": "3.226.0", - "@aws-sdk/middleware-content-length": "3.226.0", - "@aws-sdk/middleware-endpoint": "3.226.0", - "@aws-sdk/middleware-host-header": "3.226.0", - "@aws-sdk/middleware-logger": "3.226.0", - "@aws-sdk/middleware-recursion-detection": "3.226.0", - "@aws-sdk/middleware-retry": "3.235.0", - "@aws-sdk/middleware-serde": "3.226.0", - "@aws-sdk/middleware-signing": "3.226.0", - "@aws-sdk/middleware-stack": "3.226.0", - "@aws-sdk/middleware-user-agent": "3.226.0", - "@aws-sdk/node-config-provider": "3.226.0", - "@aws-sdk/node-http-handler": "3.226.0", - "@aws-sdk/protocol-http": "3.226.0", - "@aws-sdk/smithy-client": "3.234.0", - "@aws-sdk/types": "3.226.0", - "@aws-sdk/url-parser": "3.226.0", - "@aws-sdk/util-base64": "3.208.0", - "@aws-sdk/util-body-length-browser": "3.188.0", - "@aws-sdk/util-body-length-node": "3.208.0", - "@aws-sdk/util-defaults-mode-browser": "3.234.0", - "@aws-sdk/util-defaults-mode-node": "3.234.0", - "@aws-sdk/util-endpoints": "3.245.0", - "@aws-sdk/util-retry": "3.229.0", - "@aws-sdk/util-user-agent-browser": "3.226.0", - "@aws-sdk/util-user-agent-node": "3.226.0", - "@aws-sdk/util-utf8-browser": "3.188.0", - "@aws-sdk/util-utf8-node": "3.208.0", - "@aws-sdk/util-waiter": "3.226.0", - "tslib": "^2.3.1", - "uuid": "^8.3.2" - }, - "engines": { - "node": ">=14.0.0" - } - }, - "node_modules/@aws-sdk/client-ssm/node_modules/@aws-sdk/util-endpoints": { - "version": "3.245.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/util-endpoints/-/util-endpoints-3.245.0.tgz", - "integrity": "sha512-UNOFquB1tKx+8RT8n82Zb5tIwDyZHVPBg/m0LB0RsLETjr6krien5ASpqWezsXKIR1hftN9uaxN4bvf2dZrWHg==", - "dev": true, - "dependencies": { - "@aws-sdk/types": "3.226.0", - "tslib": "^2.3.1" - }, - "engines": { - "node": ">=14.0.0" - } - }, - "node_modules/@aws-sdk/client-ssm/node_modules/uuid": { - "version": "8.3.2", - "resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz", - "integrity": "sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==", - "dev": true, - "bin": { - "uuid": "dist/bin/uuid" - } - }, - "node_modules/@aws-sdk/client-sso": { - "version": "3.245.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/client-sso/-/client-sso-3.245.0.tgz", - "integrity": "sha512-dxzRwRo55ZNQ4hQigC+cishxLSWlBrbr3iszG0FLviavLDOlnVG5UUxWpOIGvwr8pYiSfM4jnfMxiwYwiCLg1g==", - "dependencies": { - "@aws-crypto/sha256-browser": "2.0.0", - "@aws-crypto/sha256-js": "2.0.0", - "@aws-sdk/config-resolver": "3.234.0", - "@aws-sdk/fetch-http-handler": "3.226.0", - "@aws-sdk/hash-node": "3.226.0", - "@aws-sdk/invalid-dependency": "3.226.0", - "@aws-sdk/middleware-content-length": "3.226.0", - "@aws-sdk/middleware-endpoint": "3.226.0", - "@aws-sdk/middleware-host-header": "3.226.0", - "@aws-sdk/middleware-logger": "3.226.0", - "@aws-sdk/middleware-recursion-detection": "3.226.0", - "@aws-sdk/middleware-retry": "3.235.0", - "@aws-sdk/middleware-serde": "3.226.0", - "@aws-sdk/middleware-stack": "3.226.0", - "@aws-sdk/middleware-user-agent": "3.226.0", - "@aws-sdk/node-config-provider": "3.226.0", - "@aws-sdk/node-http-handler": "3.226.0", - "@aws-sdk/protocol-http": "3.226.0", - "@aws-sdk/smithy-client": "3.234.0", - "@aws-sdk/types": "3.226.0", - "@aws-sdk/url-parser": "3.226.0", - "@aws-sdk/util-base64": "3.208.0", - "@aws-sdk/util-body-length-browser": "3.188.0", - "@aws-sdk/util-body-length-node": "3.208.0", - "@aws-sdk/util-defaults-mode-browser": "3.234.0", - "@aws-sdk/util-defaults-mode-node": "3.234.0", - "@aws-sdk/util-endpoints": "3.245.0", - "@aws-sdk/util-retry": "3.229.0", - "@aws-sdk/util-user-agent-browser": "3.226.0", - "@aws-sdk/util-user-agent-node": "3.226.0", - "@aws-sdk/util-utf8-browser": "3.188.0", - "@aws-sdk/util-utf8-node": "3.208.0", - "tslib": "^2.3.1" - }, - "engines": { - "node": ">=14.0.0" - } - }, - "node_modules/@aws-sdk/client-sso-oidc": { - "version": "3.245.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/client-sso-oidc/-/client-sso-oidc-3.245.0.tgz", - "integrity": "sha512-0pGPA00kEsu2Yq1Ul+OwftHxws5YVllm4iZrPtGnqmXr7wmf6B9lOtrMQF44y7Tfw53po6+bKz08OKTEWkkjUA==", - "dependencies": { - "@aws-crypto/sha256-browser": "2.0.0", - "@aws-crypto/sha256-js": "2.0.0", - "@aws-sdk/config-resolver": "3.234.0", - "@aws-sdk/fetch-http-handler": "3.226.0", - "@aws-sdk/hash-node": "3.226.0", - "@aws-sdk/invalid-dependency": "3.226.0", - "@aws-sdk/middleware-content-length": "3.226.0", - "@aws-sdk/middleware-endpoint": "3.226.0", - "@aws-sdk/middleware-host-header": "3.226.0", - "@aws-sdk/middleware-logger": "3.226.0", - "@aws-sdk/middleware-recursion-detection": "3.226.0", - "@aws-sdk/middleware-retry": "3.235.0", - "@aws-sdk/middleware-serde": "3.226.0", - "@aws-sdk/middleware-stack": "3.226.0", - "@aws-sdk/middleware-user-agent": "3.226.0", - "@aws-sdk/node-config-provider": "3.226.0", - "@aws-sdk/node-http-handler": "3.226.0", - "@aws-sdk/protocol-http": "3.226.0", - "@aws-sdk/smithy-client": "3.234.0", - "@aws-sdk/types": "3.226.0", - "@aws-sdk/url-parser": "3.226.0", - "@aws-sdk/util-base64": "3.208.0", - "@aws-sdk/util-body-length-browser": "3.188.0", - "@aws-sdk/util-body-length-node": "3.208.0", - "@aws-sdk/util-defaults-mode-browser": "3.234.0", - "@aws-sdk/util-defaults-mode-node": "3.234.0", - "@aws-sdk/util-endpoints": "3.245.0", - "@aws-sdk/util-retry": "3.229.0", - "@aws-sdk/util-user-agent-browser": "3.226.0", - "@aws-sdk/util-user-agent-node": "3.226.0", - "@aws-sdk/util-utf8-browser": "3.188.0", - "@aws-sdk/util-utf8-node": "3.208.0", - "tslib": "^2.3.1" - }, - "engines": { - "node": ">=14.0.0" - } - }, - "node_modules/@aws-sdk/client-sso-oidc/node_modules/@aws-sdk/util-endpoints": { - "version": "3.245.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/util-endpoints/-/util-endpoints-3.245.0.tgz", - "integrity": "sha512-UNOFquB1tKx+8RT8n82Zb5tIwDyZHVPBg/m0LB0RsLETjr6krien5ASpqWezsXKIR1hftN9uaxN4bvf2dZrWHg==", - "dependencies": { - "@aws-sdk/types": "3.226.0", - "tslib": "^2.3.1" - }, - "engines": { - "node": ">=14.0.0" - } - }, - "node_modules/@aws-sdk/client-sso/node_modules/@aws-sdk/util-endpoints": { - "version": "3.245.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/util-endpoints/-/util-endpoints-3.245.0.tgz", - "integrity": "sha512-UNOFquB1tKx+8RT8n82Zb5tIwDyZHVPBg/m0LB0RsLETjr6krien5ASpqWezsXKIR1hftN9uaxN4bvf2dZrWHg==", - "dependencies": { + "@aws-sdk/protocol-http": "3.226.0", + "@aws-sdk/smithy-client": "3.234.0", "@aws-sdk/types": "3.226.0", + "@aws-sdk/url-parser": "3.226.0", + "@aws-sdk/util-base64": "3.208.0", + "@aws-sdk/util-body-length-browser": "3.188.0", + "@aws-sdk/util-body-length-node": "3.208.0", + "@aws-sdk/util-defaults-mode-browser": "3.234.0", + "@aws-sdk/util-defaults-mode-node": "3.234.0", + "@aws-sdk/util-endpoints": "3.245.0", + "@aws-sdk/util-retry": "3.229.0", + "@aws-sdk/util-user-agent-browser": "3.226.0", + "@aws-sdk/util-user-agent-node": "3.226.0", + "@aws-sdk/util-utf8-browser": "3.188.0", + "@aws-sdk/util-utf8-node": "3.208.0", "tslib": "^2.3.1" }, "engines": { @@ -1299,18 +745,6 @@ "node": ">=14.0.0" } }, - "node_modules/@aws-sdk/client-sts/node_modules/@aws-sdk/util-endpoints": { - "version": "3.245.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/util-endpoints/-/util-endpoints-3.245.0.tgz", - "integrity": "sha512-UNOFquB1tKx+8RT8n82Zb5tIwDyZHVPBg/m0LB0RsLETjr6krien5ASpqWezsXKIR1hftN9uaxN4bvf2dZrWHg==", - "dependencies": { - "@aws-sdk/types": "3.226.0", - "tslib": "^2.3.1" - }, - "engines": { - "node": ">=14.0.0" - } - }, "node_modules/@aws-sdk/config-resolver": { "version": "3.234.0", "resolved": "https://registry.npmjs.org/@aws-sdk/config-resolver/-/config-resolver-3.234.0.tgz", @@ -1862,6 +1296,19 @@ "node": ">=14.0.0" } }, + "node_modules/@aws-sdk/util-base64-node": { + "version": "3.209.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/util-base64-node/-/util-base64-node-3.209.0.tgz", + "integrity": "sha512-U6pjb6uF/BameQLmzoSrqeiTxu5otwwGV7fO+TyE/3SJm/lyIsBaO+wr0qsoK0ae1VqggR+KCsUG13pWhdltpw==", + "deprecated": "The package @aws-sdk/util-base64-node has been renamed to @aws-sdk/util-base64. Please install the renamed package.", + "dependencies": { + "@aws-sdk/util-buffer-from": "3.208.0", + "tslib": "^2.3.1" + }, + "engines": { + "node": ">=14.0.0" + } + }, "node_modules/@aws-sdk/util-body-length-browser": { "version": "3.188.0", "resolved": "https://registry.npmjs.org/@aws-sdk/util-body-length-browser/-/util-body-length-browser-3.188.0.tgz", @@ -1946,10 +1393,9 @@ } }, "node_modules/@aws-sdk/util-endpoints": { - "version": "3.226.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/util-endpoints/-/util-endpoints-3.226.0.tgz", - "integrity": "sha512-iqOkac/zLmyPBUJd7SLN0PeZMkOmlGgD5PHmmekTClOkce2eUjK9SNX1PzL73aXPoPTyhg9QGLH8uEZEQ8YUzg==", - "dev": true, + "version": "3.245.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/util-endpoints/-/util-endpoints-3.245.0.tgz", + "integrity": "sha512-UNOFquB1tKx+8RT8n82Zb5tIwDyZHVPBg/m0LB0RsLETjr6krien5ASpqWezsXKIR1hftN9uaxN4bvf2dZrWHg==", "dependencies": { "@aws-sdk/types": "3.226.0", "tslib": "^2.3.1" @@ -6381,9 +5827,9 @@ } }, "node_modules/aws-sdk": { - "version": "2.1279.0", - "resolved": "https://registry.npmjs.org/aws-sdk/-/aws-sdk-2.1279.0.tgz", - "integrity": "sha512-52NbHEZTLlrld6XDLvVaOwEI0p4nYTYVuninX8s4kdkBXeTezaBahsufWT7LmeYh10gp70dnwaUxvja1TjmeRA==", + "version": "2.1302.0", + "resolved": "https://registry.npmjs.org/aws-sdk/-/aws-sdk-2.1302.0.tgz", + "integrity": "sha512-OeP31meLGCcBJel2Re1yRsrjqDT3FvLFMQwPVtKHkXnws6QpgVg1FPiEjz4emEREUi6NfbqGNVExOGLsKiz0YA==", "dev": true, "dependencies": { "buffer": "4.9.2", @@ -6653,9 +6099,9 @@ "dev": true }, "node_modules/axios": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/axios/-/axios-1.2.1.tgz", - "integrity": "sha512-I88cFiGu9ryt/tfVEi4kX2SITsvDddTajXTOFmt2uK1ZVA8LytjtdeyefdQWEf5PU8w+4SSJDoYnggflB5tW4A==", + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/axios/-/axios-1.2.4.tgz", + "integrity": "sha512-lIQuCfBJvZB/Bv7+RWUqEJqNShGOVpk9v7P0ZWx5Ip0qY6u7JBAU6dzQPMLasU9vHL2uD8av/1FDJXj7n6c39w==", "dev": true, "dependencies": { "follow-redirects": "^1.15.0", @@ -8765,6 +8211,10 @@ "node": ">=8" } }, + "node_modules/docs": { + "resolved": "docs/snippets", + "link": true + }, "node_modules/doctrine": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-3.0.0.tgz", @@ -10666,9 +10116,9 @@ "dev": true }, "node_modules/http-cache-semantics": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/http-cache-semantics/-/http-cache-semantics-4.1.0.tgz", - "integrity": "sha512-carPklcUh7ROWRK7Cv27RPtdhYhUsela/ue5/jKzjegVvXDqM2ILE9Q2BGn9JZJh1g87cp56su/FgQSzcWS8cQ==", + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/http-cache-semantics/-/http-cache-semantics-4.1.1.tgz", + "integrity": "sha512-er295DKPVsV82j5kw1Gjt+ADA/XYHsajl82cGNQG2eyoPkvgUhX+nDIyelzhIWbbsXP39EHcI6l5tYs2FYqYXQ==", "dev": true }, "node_modules/http-errors": { @@ -12232,6 +11682,10 @@ "node": ">=6" } }, + "node_modules/layers": { + "resolved": "layers", + "link": true + }, "node_modules/lazystream": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/lazystream/-/lazystream-1.0.1.tgz", @@ -17195,7 +16649,7 @@ }, "packages/commons": { "name": "@aws-lambda-powertools/commons", - "version": "1.5.0", + "version": "1.5.1", "license": "MIT-0" }, "packages/idempotency": { @@ -17213,10 +16667,10 @@ }, "packages/logger": { "name": "@aws-lambda-powertools/logger", - "version": "1.5.0", + "version": "1.5.1", "license": "MIT", "dependencies": { - "@aws-lambda-powertools/commons": "^1.5.0", + "@aws-lambda-powertools/commons": "^1.5.1", "lodash.merge": "^4.6.2" }, "devDependencies": { @@ -17225,10 +16679,10 @@ }, "packages/metrics": { "name": "@aws-lambda-powertools/metrics", - "version": "1.5.0", + "version": "1.5.1", "license": "MIT-0", "dependencies": { - "@aws-lambda-powertools/commons": "^1.5.0" + "@aws-lambda-powertools/commons": "^1.5.1" }, "devDependencies": { "@types/promise-retry": "^1.1.3", @@ -17240,7 +16694,7 @@ "version": "1.5.0", "license": "MIT-0", "dependencies": { - "@aws-sdk/util-base64": "^3.208.0" + "@aws-sdk/util-base64-node": "^3.209.0" }, "devDependencies": { "@aws-sdk/client-appconfigdata": "^3.241.0", @@ -17266,10 +16720,10 @@ }, "packages/tracer": { "name": "@aws-lambda-powertools/tracer", - "version": "1.5.0", + "version": "1.5.1", "license": "MIT-0", "dependencies": { - "@aws-lambda-powertools/commons": "^1.5.0", + "@aws-lambda-powertools/commons": "^1.5.1", "aws-xray-sdk-core": "^3.4.0" }, "devDependencies": { @@ -17515,7 +16969,7 @@ "@aws-lambda-powertools/logger": { "version": "file:packages/logger", "requires": { - "@aws-lambda-powertools/commons": "^1.5.0", + "@aws-lambda-powertools/commons": "^1.5.1", "@types/lodash.merge": "^4.6.7", "lodash.merge": "^4.6.2" } @@ -17523,7 +16977,7 @@ "@aws-lambda-powertools/metrics": { "version": "file:packages/metrics", "requires": { - "@aws-lambda-powertools/commons": "^1.5.0", + "@aws-lambda-powertools/commons": "^1.5.1", "@types/promise-retry": "^1.1.3", "promise-retry": "^2.0.1" } @@ -17532,11 +16986,11 @@ "version": "file:packages/parameters", "requires": { "@aws-sdk/client-appconfigdata": "^3.241.0", - "@aws-sdk/client-dynamodb": "*", + "@aws-sdk/client-dynamodb": "^3.245.0", "@aws-sdk/client-secrets-manager": "^3.238.0", "@aws-sdk/client-ssm": "^3.244.0", - "@aws-sdk/util-base64": "^3.208.0", - "@aws-sdk/util-dynamodb": "*", + "@aws-sdk/util-base64-node": "^3.209.0", + "@aws-sdk/util-dynamodb": "^3.245.0", "aws-sdk-client-mock": "^2.0.1", "aws-sdk-client-mock-jest": "^2.0.1" }, @@ -17555,7 +17009,7 @@ "@aws-lambda-powertools/tracer": { "version": "file:packages/tracer", "requires": { - "@aws-lambda-powertools/commons": "^1.5.0", + "@aws-lambda-powertools/commons": "^1.5.1", "@aws-sdk/client-dynamodb": "^3.231.0", "@types/promise-retry": "^1.1.3", "aws-sdk": "^2.1276.0", @@ -17574,16 +17028,16 @@ } }, "@aws-sdk/client-appconfigdata": { - "version": "3.241.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/client-appconfigdata/-/client-appconfigdata-3.241.0.tgz", - "integrity": "sha512-5AVfSc6ZQ17dF0cdIrmpEe0H6vmGumBvsFGn89e2clSPtqqtsFDpBeAsS5jCMbxO9pakkCM0RPAh+sci6MnlYg==", + "version": "3.245.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/client-appconfigdata/-/client-appconfigdata-3.245.0.tgz", + "integrity": "sha512-XxyUEEYcL6xvFUnrd10sVtmWaqYTHwn9IfScqyqz2K8wrAnbHPeaWc197UulqhIXYfz11foOAEleiUBKM1kHdw==", "dev": true, "requires": { "@aws-crypto/sha256-browser": "2.0.0", "@aws-crypto/sha256-js": "2.0.0", - "@aws-sdk/client-sts": "3.241.0", + "@aws-sdk/client-sts": "3.245.0", "@aws-sdk/config-resolver": "3.234.0", - "@aws-sdk/credential-provider-node": "3.241.0", + "@aws-sdk/credential-provider-node": "3.245.0", "@aws-sdk/fetch-http-handler": "3.226.0", "@aws-sdk/hash-node": "3.226.0", "@aws-sdk/invalid-dependency": "3.226.0", @@ -17608,285 +17062,13 @@ "@aws-sdk/util-body-length-node": "3.208.0", "@aws-sdk/util-defaults-mode-browser": "3.234.0", "@aws-sdk/util-defaults-mode-node": "3.234.0", - "@aws-sdk/util-endpoints": "3.241.0", + "@aws-sdk/util-endpoints": "3.245.0", "@aws-sdk/util-retry": "3.229.0", "@aws-sdk/util-user-agent-browser": "3.226.0", "@aws-sdk/util-user-agent-node": "3.226.0", "@aws-sdk/util-utf8-browser": "3.188.0", "@aws-sdk/util-utf8-node": "3.208.0", "tslib": "^2.3.1" - }, - "dependencies": { - "@aws-sdk/client-sso": { - "version": "3.241.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/client-sso/-/client-sso-3.241.0.tgz", - "integrity": "sha512-Jm4HR+RYAqKMEYZvvWaq0NYUKKonyInOeubObXH4BLXZpmUBSdYCSjjLdNJY3jkQoxbDVPVMIurVNh5zT5SMRw==", - "dev": true, - "requires": { - "@aws-crypto/sha256-browser": "2.0.0", - "@aws-crypto/sha256-js": "2.0.0", - "@aws-sdk/config-resolver": "3.234.0", - "@aws-sdk/fetch-http-handler": "3.226.0", - "@aws-sdk/hash-node": "3.226.0", - "@aws-sdk/invalid-dependency": "3.226.0", - "@aws-sdk/middleware-content-length": "3.226.0", - "@aws-sdk/middleware-endpoint": "3.226.0", - "@aws-sdk/middleware-host-header": "3.226.0", - "@aws-sdk/middleware-logger": "3.226.0", - "@aws-sdk/middleware-recursion-detection": "3.226.0", - "@aws-sdk/middleware-retry": "3.235.0", - "@aws-sdk/middleware-serde": "3.226.0", - "@aws-sdk/middleware-stack": "3.226.0", - "@aws-sdk/middleware-user-agent": "3.226.0", - "@aws-sdk/node-config-provider": "3.226.0", - "@aws-sdk/node-http-handler": "3.226.0", - "@aws-sdk/protocol-http": "3.226.0", - "@aws-sdk/smithy-client": "3.234.0", - "@aws-sdk/types": "3.226.0", - "@aws-sdk/url-parser": "3.226.0", - "@aws-sdk/util-base64": "3.208.0", - "@aws-sdk/util-body-length-browser": "3.188.0", - "@aws-sdk/util-body-length-node": "3.208.0", - "@aws-sdk/util-defaults-mode-browser": "3.234.0", - "@aws-sdk/util-defaults-mode-node": "3.234.0", - "@aws-sdk/util-endpoints": "3.241.0", - "@aws-sdk/util-retry": "3.229.0", - "@aws-sdk/util-user-agent-browser": "3.226.0", - "@aws-sdk/util-user-agent-node": "3.226.0", - "@aws-sdk/util-utf8-browser": "3.188.0", - "@aws-sdk/util-utf8-node": "3.208.0", - "tslib": "^2.3.1" - } - }, - "@aws-sdk/client-sso-oidc": { - "version": "3.241.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/client-sso-oidc/-/client-sso-oidc-3.241.0.tgz", - "integrity": "sha512-/Ml2QBGpGfUEeBrPzBZhSTBkHuXFD2EAZEIHGCBH4tKaURDI6/FoGI8P1Rl4BzoFt+II/Cr91Eox6YT9EwChsQ==", - "dev": true, - "requires": { - "@aws-crypto/sha256-browser": "2.0.0", - "@aws-crypto/sha256-js": "2.0.0", - "@aws-sdk/config-resolver": "3.234.0", - "@aws-sdk/fetch-http-handler": "3.226.0", - "@aws-sdk/hash-node": "3.226.0", - "@aws-sdk/invalid-dependency": "3.226.0", - "@aws-sdk/middleware-content-length": "3.226.0", - "@aws-sdk/middleware-endpoint": "3.226.0", - "@aws-sdk/middleware-host-header": "3.226.0", - "@aws-sdk/middleware-logger": "3.226.0", - "@aws-sdk/middleware-recursion-detection": "3.226.0", - "@aws-sdk/middleware-retry": "3.235.0", - "@aws-sdk/middleware-serde": "3.226.0", - "@aws-sdk/middleware-stack": "3.226.0", - "@aws-sdk/middleware-user-agent": "3.226.0", - "@aws-sdk/node-config-provider": "3.226.0", - "@aws-sdk/node-http-handler": "3.226.0", - "@aws-sdk/protocol-http": "3.226.0", - "@aws-sdk/smithy-client": "3.234.0", - "@aws-sdk/types": "3.226.0", - "@aws-sdk/url-parser": "3.226.0", - "@aws-sdk/util-base64": "3.208.0", - "@aws-sdk/util-body-length-browser": "3.188.0", - "@aws-sdk/util-body-length-node": "3.208.0", - "@aws-sdk/util-defaults-mode-browser": "3.234.0", - "@aws-sdk/util-defaults-mode-node": "3.234.0", - "@aws-sdk/util-endpoints": "3.241.0", - "@aws-sdk/util-retry": "3.229.0", - "@aws-sdk/util-user-agent-browser": "3.226.0", - "@aws-sdk/util-user-agent-node": "3.226.0", - "@aws-sdk/util-utf8-browser": "3.188.0", - "@aws-sdk/util-utf8-node": "3.208.0", - "tslib": "^2.3.1" - } - }, - "@aws-sdk/client-sts": { - "version": "3.241.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/client-sts/-/client-sts-3.241.0.tgz", - "integrity": "sha512-vmlG8cJzRf8skCtTJbA2wBvD2c3NQ5gZryzJvTKDS06KzBzcEpnjlLseuTekcnOiRNekbFUX5hRu5Zj3N2ReLg==", - "dev": true, - "requires": { - "@aws-crypto/sha256-browser": "2.0.0", - "@aws-crypto/sha256-js": "2.0.0", - "@aws-sdk/config-resolver": "3.234.0", - "@aws-sdk/credential-provider-node": "3.241.0", - "@aws-sdk/fetch-http-handler": "3.226.0", - "@aws-sdk/hash-node": "3.226.0", - "@aws-sdk/invalid-dependency": "3.226.0", - "@aws-sdk/middleware-content-length": "3.226.0", - "@aws-sdk/middleware-endpoint": "3.226.0", - "@aws-sdk/middleware-host-header": "3.226.0", - "@aws-sdk/middleware-logger": "3.226.0", - "@aws-sdk/middleware-recursion-detection": "3.226.0", - "@aws-sdk/middleware-retry": "3.235.0", - "@aws-sdk/middleware-sdk-sts": "3.226.0", - "@aws-sdk/middleware-serde": "3.226.0", - "@aws-sdk/middleware-signing": "3.226.0", - "@aws-sdk/middleware-stack": "3.226.0", - "@aws-sdk/middleware-user-agent": "3.226.0", - "@aws-sdk/node-config-provider": "3.226.0", - "@aws-sdk/node-http-handler": "3.226.0", - "@aws-sdk/protocol-http": "3.226.0", - "@aws-sdk/smithy-client": "3.234.0", - "@aws-sdk/types": "3.226.0", - "@aws-sdk/url-parser": "3.226.0", - "@aws-sdk/util-base64": "3.208.0", - "@aws-sdk/util-body-length-browser": "3.188.0", - "@aws-sdk/util-body-length-node": "3.208.0", - "@aws-sdk/util-defaults-mode-browser": "3.234.0", - "@aws-sdk/util-defaults-mode-node": "3.234.0", - "@aws-sdk/util-endpoints": "3.241.0", - "@aws-sdk/util-retry": "3.229.0", - "@aws-sdk/util-user-agent-browser": "3.226.0", - "@aws-sdk/util-user-agent-node": "3.226.0", - "@aws-sdk/util-utf8-browser": "3.188.0", - "@aws-sdk/util-utf8-node": "3.208.0", - "fast-xml-parser": "4.0.11", - "tslib": "^2.3.1" - } - }, - "@aws-sdk/config-resolver": { - "version": "3.234.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/config-resolver/-/config-resolver-3.234.0.tgz", - "integrity": "sha512-uZxy4wzllfvgCQxVc+Iqhde0NGAnfmV2hWR6ejadJaAFTuYNvQiRg9IqJy3pkyDPqXySiJ8Bom5PoJfgn55J/A==", - "dev": true, - "requires": { - "@aws-sdk/signature-v4": "3.226.0", - "@aws-sdk/types": "3.226.0", - "@aws-sdk/util-config-provider": "3.208.0", - "@aws-sdk/util-middleware": "3.226.0", - "tslib": "^2.3.1" - } - }, - "@aws-sdk/credential-provider-ini": { - "version": "3.241.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-ini/-/credential-provider-ini-3.241.0.tgz", - "integrity": "sha512-CI+mu6h74Kzmscw35TvNkc/wYHsHPGAwP7humSHoWw53H9mVw21Ggft/dT1iFQQZWQ8BNXkzuXlNo1IlqwMgOA==", - "dev": true, - "requires": { - "@aws-sdk/credential-provider-env": "3.226.0", - "@aws-sdk/credential-provider-imds": "3.226.0", - "@aws-sdk/credential-provider-process": "3.226.0", - "@aws-sdk/credential-provider-sso": "3.241.0", - "@aws-sdk/credential-provider-web-identity": "3.226.0", - "@aws-sdk/property-provider": "3.226.0", - "@aws-sdk/shared-ini-file-loader": "3.226.0", - "@aws-sdk/types": "3.226.0", - "tslib": "^2.3.1" - } - }, - "@aws-sdk/credential-provider-node": { - "version": "3.241.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-node/-/credential-provider-node-3.241.0.tgz", - "integrity": "sha512-08zPQcD5o9brQmzEipWHeHgU85aQcEF8MWLfpeyjO6e1/l7ysQ35NsS+PYtv77nLpGCx/X+ZuW/KXWoRrbw77w==", - "dev": true, - "requires": { - "@aws-sdk/credential-provider-env": "3.226.0", - "@aws-sdk/credential-provider-imds": "3.226.0", - "@aws-sdk/credential-provider-ini": "3.241.0", - "@aws-sdk/credential-provider-process": "3.226.0", - "@aws-sdk/credential-provider-sso": "3.241.0", - "@aws-sdk/credential-provider-web-identity": "3.226.0", - "@aws-sdk/property-provider": "3.226.0", - "@aws-sdk/shared-ini-file-loader": "3.226.0", - "@aws-sdk/types": "3.226.0", - "tslib": "^2.3.1" - } - }, - "@aws-sdk/credential-provider-sso": { - "version": "3.241.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-sso/-/credential-provider-sso-3.241.0.tgz", - "integrity": "sha512-6Bjd6eEIrVomRTrPrM4dlxusQm+KMJ9hLYKECCpFkwDKIK+pTgZNLRtQdalHyzwneHJPdimrm8cOv1kUQ8hPoA==", - "dev": true, - "requires": { - "@aws-sdk/client-sso": "3.241.0", - "@aws-sdk/property-provider": "3.226.0", - "@aws-sdk/shared-ini-file-loader": "3.226.0", - "@aws-sdk/token-providers": "3.241.0", - "@aws-sdk/types": "3.226.0", - "tslib": "^2.3.1" - } - }, - "@aws-sdk/middleware-retry": { - "version": "3.235.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-retry/-/middleware-retry-3.235.0.tgz", - "integrity": "sha512-50WHbJGpD3SNp9763MAlHqIhXil++JdQbKejNpHg7HsJne/ao3ub+fDOfx//mMBjpzBV25BGd5UlfL6blrClSg==", - "dev": true, - "requires": { - "@aws-sdk/protocol-http": "3.226.0", - "@aws-sdk/service-error-classification": "3.229.0", - "@aws-sdk/types": "3.226.0", - "@aws-sdk/util-middleware": "3.226.0", - "@aws-sdk/util-retry": "3.229.0", - "tslib": "^2.3.1", - "uuid": "^8.3.2" - } - }, - "@aws-sdk/smithy-client": { - "version": "3.234.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/smithy-client/-/smithy-client-3.234.0.tgz", - "integrity": "sha512-8AtR/k4vsFvjXeQbIzq/Wy7Nbk48Ou0wUEeVYPHWHPSU8QamFWORkOwmKtKMfHAyZvmqiAPeQqHFkq+UJhWyyQ==", - "dev": true, - "requires": { - "@aws-sdk/middleware-stack": "3.226.0", - "@aws-sdk/types": "3.226.0", - "tslib": "^2.3.1" - } - }, - "@aws-sdk/token-providers": { - "version": "3.241.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/token-providers/-/token-providers-3.241.0.tgz", - "integrity": "sha512-79okvuOS7V559OIL/RalIPG98wzmWxeFOChFnbEjn2pKOyGQ6FJRwLPYZaVRtNdAtnkBNgRpmFq9dX843QxhtQ==", - "dev": true, - "requires": { - "@aws-sdk/client-sso-oidc": "3.241.0", - "@aws-sdk/property-provider": "3.226.0", - "@aws-sdk/shared-ini-file-loader": "3.226.0", - "@aws-sdk/types": "3.226.0", - "tslib": "^2.3.1" - } - }, - "@aws-sdk/util-defaults-mode-browser": { - "version": "3.234.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/util-defaults-mode-browser/-/util-defaults-mode-browser-3.234.0.tgz", - "integrity": "sha512-IHMKXjTbOD8XMz5+2oCOsVP94BYb9YyjXdns0aAXr2NAo7k2+RCzXQ2DebJXppGda1F6opFutoKwyVSN0cmbMw==", - "dev": true, - "requires": { - "@aws-sdk/property-provider": "3.226.0", - "@aws-sdk/types": "3.226.0", - "bowser": "^2.11.0", - "tslib": "^2.3.1" - } - }, - "@aws-sdk/util-defaults-mode-node": { - "version": "3.234.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/util-defaults-mode-node/-/util-defaults-mode-node-3.234.0.tgz", - "integrity": "sha512-UGjQ+OjBYYhxFVtUY+jtr0ZZgzZh6OHtYwRhFt8IHewJXFCfZTyfsbX20szBj5y1S4HRIUJ7cwBLIytTqMbI5w==", - "dev": true, - "requires": { - "@aws-sdk/config-resolver": "3.234.0", - "@aws-sdk/credential-provider-imds": "3.226.0", - "@aws-sdk/node-config-provider": "3.226.0", - "@aws-sdk/property-provider": "3.226.0", - "@aws-sdk/types": "3.226.0", - "tslib": "^2.3.1" - } - }, - "@aws-sdk/util-endpoints": { - "version": "3.241.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/util-endpoints/-/util-endpoints-3.241.0.tgz", - "integrity": "sha512-jVf8bKrN22Ey0xLmj75sL7EUvm5HFpuOMkXsZkuXycKhCwLBcEUWlvtJYtRjOU1zScPQv9GMJd2QXQglp34iOQ==", - "dev": true, - "requires": { - "@aws-sdk/types": "3.226.0", - "tslib": "^2.3.1" - } - }, - "uuid": { - "version": "8.3.2", - "resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz", - "integrity": "sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==", - "dev": true - } } }, "@aws-sdk/client-dynamodb": { @@ -17935,15 +17117,6 @@ "uuid": "^8.3.2" }, "dependencies": { - "@aws-sdk/util-endpoints": { - "version": "3.245.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/util-endpoints/-/util-endpoints-3.245.0.tgz", - "integrity": "sha512-UNOFquB1tKx+8RT8n82Zb5tIwDyZHVPBg/m0LB0RsLETjr6krien5ASpqWezsXKIR1hftN9uaxN4bvf2dZrWHg==", - "requires": { - "@aws-sdk/types": "3.226.0", - "tslib": "^2.3.1" - } - }, "uuid": { "version": "8.3.2", "resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz", @@ -17952,16 +17125,16 @@ } }, "@aws-sdk/client-secrets-manager": { - "version": "3.238.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/client-secrets-manager/-/client-secrets-manager-3.238.0.tgz", - "integrity": "sha512-J3lmceh2txILEh8tWf4ldp8ThAh2WJBSa1t8oJhW58KuE+1a7cwOpgWO6MsSvOrGtp7qzTr8GMBUf7KLdv7wOg==", + "version": "3.250.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/client-secrets-manager/-/client-secrets-manager-3.250.0.tgz", + "integrity": "sha512-CB4OcFJPpAuW3rRXBxgOtF9RXHBixEvJSDkh8RsCAamt37Fw61+e+CsdXixSWA4rzQA+3PQuts7zlwhcxobbJg==", "dev": true, "requires": { "@aws-crypto/sha256-browser": "2.0.0", "@aws-crypto/sha256-js": "2.0.0", - "@aws-sdk/client-sts": "3.238.0", + "@aws-sdk/client-sts": "3.245.0", "@aws-sdk/config-resolver": "3.234.0", - "@aws-sdk/credential-provider-node": "3.238.0", + "@aws-sdk/credential-provider-node": "3.245.0", "@aws-sdk/fetch-http-handler": "3.226.0", "@aws-sdk/hash-node": "3.226.0", "@aws-sdk/invalid-dependency": "3.226.0", @@ -17986,7 +17159,7 @@ "@aws-sdk/util-body-length-node": "3.208.0", "@aws-sdk/util-defaults-mode-browser": "3.234.0", "@aws-sdk/util-defaults-mode-node": "3.234.0", - "@aws-sdk/util-endpoints": "3.226.0", + "@aws-sdk/util-endpoints": "3.245.0", "@aws-sdk/util-retry": "3.229.0", "@aws-sdk/util-user-agent-browser": "3.226.0", "@aws-sdk/util-user-agent-node": "3.226.0", @@ -17996,219 +17169,6 @@ "uuid": "^8.3.2" }, "dependencies": { - "@aws-sdk/client-sso": { - "version": "3.238.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/client-sso/-/client-sso-3.238.0.tgz", - "integrity": "sha512-KHJJWP7hBDa9KLYiU5+hOb+3AAba93PhWebXkpKyQ/Bs+e7ECCreyLCwuME6uWTV01NDuFDpwZ6zUMpyNIcP6Q==", - "dev": true, - "requires": { - "@aws-crypto/sha256-browser": "2.0.0", - "@aws-crypto/sha256-js": "2.0.0", - "@aws-sdk/config-resolver": "3.234.0", - "@aws-sdk/fetch-http-handler": "3.226.0", - "@aws-sdk/hash-node": "3.226.0", - "@aws-sdk/invalid-dependency": "3.226.0", - "@aws-sdk/middleware-content-length": "3.226.0", - "@aws-sdk/middleware-endpoint": "3.226.0", - "@aws-sdk/middleware-host-header": "3.226.0", - "@aws-sdk/middleware-logger": "3.226.0", - "@aws-sdk/middleware-recursion-detection": "3.226.0", - "@aws-sdk/middleware-retry": "3.235.0", - "@aws-sdk/middleware-serde": "3.226.0", - "@aws-sdk/middleware-stack": "3.226.0", - "@aws-sdk/middleware-user-agent": "3.226.0", - "@aws-sdk/node-config-provider": "3.226.0", - "@aws-sdk/node-http-handler": "3.226.0", - "@aws-sdk/protocol-http": "3.226.0", - "@aws-sdk/smithy-client": "3.234.0", - "@aws-sdk/types": "3.226.0", - "@aws-sdk/url-parser": "3.226.0", - "@aws-sdk/util-base64": "3.208.0", - "@aws-sdk/util-body-length-browser": "3.188.0", - "@aws-sdk/util-body-length-node": "3.208.0", - "@aws-sdk/util-defaults-mode-browser": "3.234.0", - "@aws-sdk/util-defaults-mode-node": "3.234.0", - "@aws-sdk/util-endpoints": "3.226.0", - "@aws-sdk/util-retry": "3.229.0", - "@aws-sdk/util-user-agent-browser": "3.226.0", - "@aws-sdk/util-user-agent-node": "3.226.0", - "@aws-sdk/util-utf8-browser": "3.188.0", - "@aws-sdk/util-utf8-node": "3.208.0", - "tslib": "^2.3.1" - } - }, - "@aws-sdk/client-sso-oidc": { - "version": "3.238.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/client-sso-oidc/-/client-sso-oidc-3.238.0.tgz", - "integrity": "sha512-kazcA2Kp+cXQRtaZi5/T5YFfU9J3nzu1tXJsh0xAm+J3S9LS1ertY1bSX6KBed2xuxx2mfum8JRqli0TJad/pA==", - "dev": true, - "requires": { - "@aws-crypto/sha256-browser": "2.0.0", - "@aws-crypto/sha256-js": "2.0.0", - "@aws-sdk/config-resolver": "3.234.0", - "@aws-sdk/fetch-http-handler": "3.226.0", - "@aws-sdk/hash-node": "3.226.0", - "@aws-sdk/invalid-dependency": "3.226.0", - "@aws-sdk/middleware-content-length": "3.226.0", - "@aws-sdk/middleware-endpoint": "3.226.0", - "@aws-sdk/middleware-host-header": "3.226.0", - "@aws-sdk/middleware-logger": "3.226.0", - "@aws-sdk/middleware-recursion-detection": "3.226.0", - "@aws-sdk/middleware-retry": "3.235.0", - "@aws-sdk/middleware-serde": "3.226.0", - "@aws-sdk/middleware-stack": "3.226.0", - "@aws-sdk/middleware-user-agent": "3.226.0", - "@aws-sdk/node-config-provider": "3.226.0", - "@aws-sdk/node-http-handler": "3.226.0", - "@aws-sdk/protocol-http": "3.226.0", - "@aws-sdk/smithy-client": "3.234.0", - "@aws-sdk/types": "3.226.0", - "@aws-sdk/url-parser": "3.226.0", - "@aws-sdk/util-base64": "3.208.0", - "@aws-sdk/util-body-length-browser": "3.188.0", - "@aws-sdk/util-body-length-node": "3.208.0", - "@aws-sdk/util-defaults-mode-browser": "3.234.0", - "@aws-sdk/util-defaults-mode-node": "3.234.0", - "@aws-sdk/util-endpoints": "3.226.0", - "@aws-sdk/util-retry": "3.229.0", - "@aws-sdk/util-user-agent-browser": "3.226.0", - "@aws-sdk/util-user-agent-node": "3.226.0", - "@aws-sdk/util-utf8-browser": "3.188.0", - "@aws-sdk/util-utf8-node": "3.208.0", - "tslib": "^2.3.1" - } - }, - "@aws-sdk/client-sts": { - "version": "3.238.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/client-sts/-/client-sts-3.238.0.tgz", - "integrity": "sha512-jQNwHqxWUGvWCN4o8KUFYQES8r41Oobu7x1KZOMrPhPxy27FUcDjBq/h85VoD2/AZlETSCZLiCnKV3KBh5pT5w==", - "dev": true, - "requires": { - "@aws-crypto/sha256-browser": "2.0.0", - "@aws-crypto/sha256-js": "2.0.0", - "@aws-sdk/config-resolver": "3.234.0", - "@aws-sdk/credential-provider-node": "3.238.0", - "@aws-sdk/fetch-http-handler": "3.226.0", - "@aws-sdk/hash-node": "3.226.0", - "@aws-sdk/invalid-dependency": "3.226.0", - "@aws-sdk/middleware-content-length": "3.226.0", - "@aws-sdk/middleware-endpoint": "3.226.0", - "@aws-sdk/middleware-host-header": "3.226.0", - "@aws-sdk/middleware-logger": "3.226.0", - "@aws-sdk/middleware-recursion-detection": "3.226.0", - "@aws-sdk/middleware-retry": "3.235.0", - "@aws-sdk/middleware-sdk-sts": "3.226.0", - "@aws-sdk/middleware-serde": "3.226.0", - "@aws-sdk/middleware-signing": "3.226.0", - "@aws-sdk/middleware-stack": "3.226.0", - "@aws-sdk/middleware-user-agent": "3.226.0", - "@aws-sdk/node-config-provider": "3.226.0", - "@aws-sdk/node-http-handler": "3.226.0", - "@aws-sdk/protocol-http": "3.226.0", - "@aws-sdk/smithy-client": "3.234.0", - "@aws-sdk/types": "3.226.0", - "@aws-sdk/url-parser": "3.226.0", - "@aws-sdk/util-base64": "3.208.0", - "@aws-sdk/util-body-length-browser": "3.188.0", - "@aws-sdk/util-body-length-node": "3.208.0", - "@aws-sdk/util-defaults-mode-browser": "3.234.0", - "@aws-sdk/util-defaults-mode-node": "3.234.0", - "@aws-sdk/util-endpoints": "3.226.0", - "@aws-sdk/util-retry": "3.229.0", - "@aws-sdk/util-user-agent-browser": "3.226.0", - "@aws-sdk/util-user-agent-node": "3.226.0", - "@aws-sdk/util-utf8-browser": "3.188.0", - "@aws-sdk/util-utf8-node": "3.208.0", - "fast-xml-parser": "4.0.11", - "tslib": "^2.3.1" - } - }, - "@aws-sdk/config-resolver": { - "version": "3.234.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/config-resolver/-/config-resolver-3.234.0.tgz", - "integrity": "sha512-uZxy4wzllfvgCQxVc+Iqhde0NGAnfmV2hWR6ejadJaAFTuYNvQiRg9IqJy3pkyDPqXySiJ8Bom5PoJfgn55J/A==", - "dev": true, - "requires": { - "@aws-sdk/signature-v4": "3.226.0", - "@aws-sdk/types": "3.226.0", - "@aws-sdk/util-config-provider": "3.208.0", - "@aws-sdk/util-middleware": "3.226.0", - "tslib": "^2.3.1" - } - }, - "@aws-sdk/credential-provider-ini": { - "version": "3.238.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-ini/-/credential-provider-ini-3.238.0.tgz", - "integrity": "sha512-WmPNtIYyUasjV7VQxvPNq7ihmx0vFsiKAtjNjjakdrt5TPoma4nUYb9tIG9SuG+kcp4DJIgRLJAgZtXbCcVimg==", - "dev": true, - "requires": { - "@aws-sdk/credential-provider-env": "3.226.0", - "@aws-sdk/credential-provider-imds": "3.226.0", - "@aws-sdk/credential-provider-process": "3.226.0", - "@aws-sdk/credential-provider-sso": "3.238.0", - "@aws-sdk/credential-provider-web-identity": "3.226.0", - "@aws-sdk/property-provider": "3.226.0", - "@aws-sdk/shared-ini-file-loader": "3.226.0", - "@aws-sdk/types": "3.226.0", - "tslib": "^2.3.1" - } - }, - "@aws-sdk/credential-provider-node": { - "version": "3.238.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-node/-/credential-provider-node-3.238.0.tgz", - "integrity": "sha512-/RN5EyGfgdIIJdFzv+O0nSaHX1/F3anQjTIBeVg8GJ+82m+bDxMdALsG+NzkYnLilN9Uhc1lSNjLBCoPa5DSEg==", - "dev": true, - "requires": { - "@aws-sdk/credential-provider-env": "3.226.0", - "@aws-sdk/credential-provider-imds": "3.226.0", - "@aws-sdk/credential-provider-ini": "3.238.0", - "@aws-sdk/credential-provider-process": "3.226.0", - "@aws-sdk/credential-provider-sso": "3.238.0", - "@aws-sdk/credential-provider-web-identity": "3.226.0", - "@aws-sdk/property-provider": "3.226.0", - "@aws-sdk/shared-ini-file-loader": "3.226.0", - "@aws-sdk/types": "3.226.0", - "tslib": "^2.3.1" - } - }, - "@aws-sdk/credential-provider-sso": { - "version": "3.238.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-sso/-/credential-provider-sso-3.238.0.tgz", - "integrity": "sha512-i70V4bFlCVYey3QARJ6XxKEg/4YuoFRnePV2oK37UHOGpEn49uXKwVZqLjzJgFHln7BPlC06cWDqrHUQIMvYrQ==", - "dev": true, - "requires": { - "@aws-sdk/client-sso": "3.238.0", - "@aws-sdk/property-provider": "3.226.0", - "@aws-sdk/shared-ini-file-loader": "3.226.0", - "@aws-sdk/token-providers": "3.238.0", - "@aws-sdk/types": "3.226.0", - "tslib": "^2.3.1" - } - }, - "@aws-sdk/smithy-client": { - "version": "3.234.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/smithy-client/-/smithy-client-3.234.0.tgz", - "integrity": "sha512-8AtR/k4vsFvjXeQbIzq/Wy7Nbk48Ou0wUEeVYPHWHPSU8QamFWORkOwmKtKMfHAyZvmqiAPeQqHFkq+UJhWyyQ==", - "dev": true, - "requires": { - "@aws-sdk/middleware-stack": "3.226.0", - "@aws-sdk/types": "3.226.0", - "tslib": "^2.3.1" - } - }, - "@aws-sdk/token-providers": { - "version": "3.238.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/token-providers/-/token-providers-3.238.0.tgz", - "integrity": "sha512-vYUwmy0kTzA99mJCVvad+/5RDlWve/xxnppT8DJK3JIdAgskp+rULY+joVnq2NSl489UAioUnFGs57vUxi8Pog==", - "dev": true, - "requires": { - "@aws-sdk/client-sso-oidc": "3.238.0", - "@aws-sdk/property-provider": "3.226.0", - "@aws-sdk/shared-ini-file-loader": "3.226.0", - "@aws-sdk/types": "3.226.0", - "tslib": "^2.3.1" - } - }, "uuid": { "version": "8.3.2", "resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz", @@ -18263,16 +17223,6 @@ "uuid": "^8.3.2" }, "dependencies": { - "@aws-sdk/util-endpoints": { - "version": "3.245.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/util-endpoints/-/util-endpoints-3.245.0.tgz", - "integrity": "sha512-UNOFquB1tKx+8RT8n82Zb5tIwDyZHVPBg/m0LB0RsLETjr6krien5ASpqWezsXKIR1hftN9uaxN4bvf2dZrWHg==", - "dev": true, - "requires": { - "@aws-sdk/types": "3.226.0", - "tslib": "^2.3.1" - } - }, "uuid": { "version": "8.3.2", "resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz", @@ -18319,17 +17269,6 @@ "@aws-sdk/util-utf8-browser": "3.188.0", "@aws-sdk/util-utf8-node": "3.208.0", "tslib": "^2.3.1" - }, - "dependencies": { - "@aws-sdk/util-endpoints": { - "version": "3.245.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/util-endpoints/-/util-endpoints-3.245.0.tgz", - "integrity": "sha512-UNOFquB1tKx+8RT8n82Zb5tIwDyZHVPBg/m0LB0RsLETjr6krien5ASpqWezsXKIR1hftN9uaxN4bvf2dZrWHg==", - "requires": { - "@aws-sdk/types": "3.226.0", - "tslib": "^2.3.1" - } - } } }, "@aws-sdk/client-sso-oidc": { @@ -18370,17 +17309,6 @@ "@aws-sdk/util-utf8-browser": "3.188.0", "@aws-sdk/util-utf8-node": "3.208.0", "tslib": "^2.3.1" - }, - "dependencies": { - "@aws-sdk/util-endpoints": { - "version": "3.245.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/util-endpoints/-/util-endpoints-3.245.0.tgz", - "integrity": "sha512-UNOFquB1tKx+8RT8n82Zb5tIwDyZHVPBg/m0LB0RsLETjr6krien5ASpqWezsXKIR1hftN9uaxN4bvf2dZrWHg==", - "requires": { - "@aws-sdk/types": "3.226.0", - "tslib": "^2.3.1" - } - } } }, "@aws-sdk/client-sts": { @@ -18425,17 +17353,6 @@ "@aws-sdk/util-utf8-node": "3.208.0", "fast-xml-parser": "4.0.11", "tslib": "^2.3.1" - }, - "dependencies": { - "@aws-sdk/util-endpoints": { - "version": "3.245.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/util-endpoints/-/util-endpoints-3.245.0.tgz", - "integrity": "sha512-UNOFquB1tKx+8RT8n82Zb5tIwDyZHVPBg/m0LB0RsLETjr6krien5ASpqWezsXKIR1hftN9uaxN4bvf2dZrWHg==", - "requires": { - "@aws-sdk/types": "3.226.0", - "tslib": "^2.3.1" - } - } } }, "@aws-sdk/config-resolver": { @@ -18872,6 +17789,15 @@ "tslib": "^2.3.1" } }, + "@aws-sdk/util-base64-node": { + "version": "3.209.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/util-base64-node/-/util-base64-node-3.209.0.tgz", + "integrity": "sha512-U6pjb6uF/BameQLmzoSrqeiTxu5otwwGV7fO+TyE/3SJm/lyIsBaO+wr0qsoK0ae1VqggR+KCsUG13pWhdltpw==", + "requires": { + "@aws-sdk/util-buffer-from": "3.208.0", + "tslib": "^2.3.1" + } + }, "@aws-sdk/util-body-length-browser": { "version": "3.188.0", "resolved": "https://registry.npmjs.org/@aws-sdk/util-body-length-browser/-/util-body-length-browser-3.188.0.tgz", @@ -18938,10 +17864,9 @@ } }, "@aws-sdk/util-endpoints": { - "version": "3.226.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/util-endpoints/-/util-endpoints-3.226.0.tgz", - "integrity": "sha512-iqOkac/zLmyPBUJd7SLN0PeZMkOmlGgD5PHmmekTClOkce2eUjK9SNX1PzL73aXPoPTyhg9QGLH8uEZEQ8YUzg==", - "dev": true, + "version": "3.245.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/util-endpoints/-/util-endpoints-3.245.0.tgz", + "integrity": "sha512-UNOFquB1tKx+8RT8n82Zb5tIwDyZHVPBg/m0LB0RsLETjr6krien5ASpqWezsXKIR1hftN9uaxN4bvf2dZrWHg==", "requires": { "@aws-sdk/types": "3.226.0", "tslib": "^2.3.1" @@ -22342,9 +21267,9 @@ } }, "aws-sdk": { - "version": "2.1279.0", - "resolved": "https://registry.npmjs.org/aws-sdk/-/aws-sdk-2.1279.0.tgz", - "integrity": "sha512-52NbHEZTLlrld6XDLvVaOwEI0p4nYTYVuninX8s4kdkBXeTezaBahsufWT7LmeYh10gp70dnwaUxvja1TjmeRA==", + "version": "2.1302.0", + "resolved": "https://registry.npmjs.org/aws-sdk/-/aws-sdk-2.1302.0.tgz", + "integrity": "sha512-OeP31meLGCcBJel2Re1yRsrjqDT3FvLFMQwPVtKHkXnws6QpgVg1FPiEjz4emEREUi6NfbqGNVExOGLsKiz0YA==", "dev": true, "requires": { "buffer": "4.9.2", @@ -22563,9 +21488,9 @@ "dev": true }, "axios": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/axios/-/axios-1.2.1.tgz", - "integrity": "sha512-I88cFiGu9ryt/tfVEi4kX2SITsvDddTajXTOFmt2uK1ZVA8LytjtdeyefdQWEf5PU8w+4SSJDoYnggflB5tW4A==", + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/axios/-/axios-1.2.4.tgz", + "integrity": "sha512-lIQuCfBJvZB/Bv7+RWUqEJqNShGOVpk9v7P0ZWx5Ip0qY6u7JBAU6dzQPMLasU9vHL2uD8av/1FDJXj7n6c39w==", "dev": true, "requires": { "follow-redirects": "^1.15.0", @@ -24370,6 +23295,28 @@ "path-type": "^4.0.0" } }, + "docs": { + "version": "file:docs/snippets", + "requires": { + "@aws-sdk/client-appconfigdata": "^3.245.0", + "@aws-sdk/client-dynamodb": "^3.245.0", + "@aws-sdk/client-secrets-manager": "^3.250.0", + "@aws-sdk/client-ssm": "^3.245.0", + "@aws-sdk/util-dynamodb": "^3.245.0", + "axios": "^1.2.4" + }, + "dependencies": { + "@aws-sdk/util-dynamodb": { + "version": "3.245.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/util-dynamodb/-/util-dynamodb-3.245.0.tgz", + "integrity": "sha512-Wx06Ey92DRRSQTFfpQs1DkHSoajcwVu2TLWTg07yHXgGxdi6EveJPNqh111ot5yzHGmzPIHas/IPZe3hDttzcw==", + "dev": true, + "requires": { + "tslib": "^2.3.1" + } + } + } + }, "doctrine": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-3.0.0.tgz", @@ -25851,9 +24798,9 @@ "dev": true }, "http-cache-semantics": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/http-cache-semantics/-/http-cache-semantics-4.1.0.tgz", - "integrity": "sha512-carPklcUh7ROWRK7Cv27RPtdhYhUsela/ue5/jKzjegVvXDqM2ILE9Q2BGn9JZJh1g87cp56su/FgQSzcWS8cQ==", + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/http-cache-semantics/-/http-cache-semantics-4.1.1.tgz", + "integrity": "sha512-er295DKPVsV82j5kw1Gjt+ADA/XYHsajl82cGNQG2eyoPkvgUhX+nDIyelzhIWbbsXP39EHcI6l5tYs2FYqYXQ==", "dev": true }, "http-errors": { @@ -27030,6 +25977,24 @@ "integrity": "sha512-eTIzlVOSUR+JxdDFepEYcBMtZ9Qqdef+rnzWdRZuMbOywu5tO2w2N7rqjoANZ5k9vywhL6Br1VRjUIgTQx4E8w==", "dev": true }, + "layers": { + "version": "file:layers", + "requires": { + "source-map-support": "^0.5.21" + }, + "dependencies": { + "source-map-support": { + "version": "0.5.21", + "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.21.tgz", + "integrity": "sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w==", + "dev": true, + "requires": { + "buffer-from": "^1.0.0", + "source-map": "^0.6.0" + } + } + } + }, "lazystream": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/lazystream/-/lazystream-1.0.1.tgz", diff --git a/package.json b/package.json index 456dce9a21..d9db61efa2 100644 --- a/package.json +++ b/package.json @@ -10,19 +10,21 @@ "packages/metrics", "packages/tracer", "packages/parameters", - "packages/idempotency" + "packages/idempotency", + "docs/snippets", + "layers" ], "scripts": { "init-environment": "husky install", "test": "npm t -ws", "commit": "commit", - "package": "npm run package", - "setup-local": "export PROJECT_ROOT=$(pwd) && npm ci --foreground-scripts && cd $PROJECT_ROOT/examples/cdk && npm ci && cd $PROJECT_ROOT/examples/sam && npm ci && cd $PROJECT_ROOT/layer-publisher && npm ci && cd $PROJECT_ROOT/ && npm run init-environment", + "package": "npm run package -ws", + "setup-local": "export PROJECT_ROOT=$(pwd) && npm ci --foreground-scripts && cd $PROJECT_ROOT/examples/cdk && npm ci && cd $PROJECT_ROOT/examples/sam && npm ci && cd $PROJECT_ROOT/ && npm run init-environment", "build": "npm run build -ws", "postversion": "git push && git push --tags", "docs-website-build-run": "npm run docs-buildDockerImage && npm run docs-runLocalDocker", - "docs-buildDockerImage": "docker build -t powertool-typescript/docs ./docs/", - "docs-runLocalDocker": "docker run --rm -it -p 8000:8000 -v ${PWD}:/docs powertool-typescript/docs", + "docs-buildDockerImage": "docker build -t powertools-typescript/docs ./docs/", + "docs-runLocalDocker": "docker run --rm -it -p 8000:8000 -v ${PWD}:/docs powertools-typescript/docs", "docs-api-build-run": "npm run docs-generateApiDoc && npx live-server api", "docs-generateApiDoc": "typedoc .", "docs-runLocalApiDoc": "npx live-server api" @@ -85,4 +87,4 @@ "dependencies": { "hosted-git-info": "^6.1.1" } -} +} \ No newline at end of file diff --git a/packages/commons/CHANGELOG.md b/packages/commons/CHANGELOG.md index d1f406818d..961dc25a13 100644 --- a/packages/commons/CHANGELOG.md +++ b/packages/commons/CHANGELOG.md @@ -3,6 +3,14 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. +# [1.6.0](https://github.com/awslabs/aws-lambda-powertools-typescript/compare/v1.5.1...v1.6.0) (2023-03-02) + +**Note:** Version bump only for package @aws-lambda-powertools/commons + + + + + ## [1.5.1](https://github.com/awslabs/aws-lambda-powertools-typescript/compare/v1.5.0...v1.5.1) (2023-01-13) **Note:** Version bump only for package @aws-lambda-powertools/commons diff --git a/packages/commons/README.md b/packages/commons/README.md index 184439883a..c319faf205 100644 --- a/packages/commons/README.md +++ b/packages/commons/README.md @@ -1,6 +1,6 @@ # AWS Lambda Powertools for TypeScript -A suite of utilities for AWS Lambda functions to ease the adoption of best practices such as tracing, structured logging, custom metrics, and more. +Powertools is a developer toolkit to implement Serverless [best practices and increase developer velocity](https://awslabs.github.io/aws-lambda-powertools-typescript/latest/#features). You can use the library in both TypeScript and JavaScript code bases. @@ -82,4 +82,4 @@ Credits for the Lambda Powertools idea go to [DAZN](https://github.com/getndazn) ## License -This library is licensed under the MIT-0 License. See the LICENSE file. \ No newline at end of file +This library is licensed under the MIT-0 License. See the LICENSE file. diff --git a/packages/commons/jest.config.js b/packages/commons/jest.config.js index 6fbaae512f..c60b4837dc 100644 --- a/packages/commons/jest.config.js +++ b/packages/commons/jest.config.js @@ -1,4 +1,8 @@ module.exports = { + displayName: { + name: 'AWS Lambda Powertools utility: COMMONS', + color: 'red', + }, 'preset': 'ts-jest', 'transform': { '^.+\\.ts?$': 'ts-jest', diff --git a/packages/commons/package.json b/packages/commons/package.json index 701198d398..912313b58b 100644 --- a/packages/commons/package.json +++ b/packages/commons/package.json @@ -1,6 +1,6 @@ { "name": "@aws-lambda-powertools/commons", - "version": "1.5.1", + "version": "1.6.0", "description": "A shared utility package for AWS Lambda Powertools for TypeScript libraries", "author": { "name": "Amazon Web Services", @@ -23,7 +23,7 @@ "prepare": "npm run build", "postversion": "git push --tags" }, - "homepage": "https://github.com/awslabs/aws-lambda-powertools-typescript/tree/master/packages/metrics#readme", + "homepage": "https://github.com/awslabs/aws-lambda-powertools-typescript/tree/main/packages/metrics#readme", "license": "MIT-0", "main": "./lib/index.js", "types": "./lib/index.d.ts", diff --git a/packages/commons/tests/utils/InvocationLogs.ts b/packages/commons/tests/utils/InvocationLogs.ts index 730e6f8e87..fd2b9f3e4c 100644 --- a/packages/commons/tests/utils/InvocationLogs.ts +++ b/packages/commons/tests/utils/InvocationLogs.ts @@ -69,28 +69,30 @@ export class InvocationLogs { * @returns {number} index of the log that contains END RequestId */ public static getEndLogIndex(logs: string[]): number { - return logs.findIndex((log) => log.includes('END RequestId')); + return logs.findIndex((log) => log.startsWith('END RequestId')); } /** - * Return only logs from function, exclude START, END, REPORT, and XRay log generated by Lambda service - * @param levelToFilter level to filter - * @returns Array of function logs + * Return only logs from function, exclude START, END, REPORT, + * and X-Ray log generated by the Lambda service. + * + * @param {LEVEL} [levelToFilter] - Level to filter the logs + * @returns Array of function logs, filtered by level if provided */ public getFunctionLogs(levelToFilter?: LEVEL): string[] { + const startLogIndex = InvocationLogs.getStartLogIndex(this.logs); const endLogIndex = InvocationLogs.getEndLogIndex(this.logs); - let filteredLogs = this.logs.slice(1, endLogIndex); + let filteredLogs = this.logs.slice(startLogIndex + 1, endLogIndex); if (levelToFilter) { filteredLogs = filteredLogs.filter((log) => { try { - const parsedLog = JSON.parse(log); - if (parsedLog.level == levelToFilter) return parsedLog; - else return; + const parsedLog = InvocationLogs.parseFunctionLog(log); + + return parsedLog.level == levelToFilter; } catch (error) { // If log is not from structured logging : such as metrics one. - if (log.split('\t')[2] == levelToFilter) return log; - else return; + return log.split('\t')[2] == levelToFilter; } }); } @@ -98,6 +100,10 @@ export class InvocationLogs { return filteredLogs; } + public static getStartLogIndex(logs: string[]): number { + return logs.findIndex((log) => log.startsWith('START RequestId')); + } + /** * Each of log message contains a JSON with the structured Log object (e.g. {\"cold_start\":true, ..}) * @param log diff --git a/packages/commons/tests/utils/e2eUtils.ts b/packages/commons/tests/utils/e2eUtils.ts index 8c94cb7b6f..5d2e75f4a5 100644 --- a/packages/commons/tests/utils/e2eUtils.ts +++ b/packages/commons/tests/utils/e2eUtils.ts @@ -6,8 +6,12 @@ * to interact with services. */ import { App, CfnOutput, Stack } from 'aws-cdk-lib'; -import * as lambda from 'aws-cdk-lib/aws-lambda-nodejs'; +import { + NodejsFunction, + NodejsFunctionProps +} from 'aws-cdk-lib/aws-lambda-nodejs'; import { Runtime, Tracing } from 'aws-cdk-lib/aws-lambda'; +import { RetentionDays } from 'aws-cdk-lib/aws-logs'; import * as AWS from 'aws-sdk'; import { InvocationLogs } from './InvocationLogs'; @@ -31,6 +35,8 @@ export type StackWithLambdaFunctionOptions = { environment: {[key: string]: string} logGroupOutputKey?: string runtime: string + bundling?: NodejsFunctionProps['bundling'] + layers?: NodejsFunctionProps['layers'] }; type FunctionPayload = {[key: string]: string | boolean | number}; @@ -40,12 +46,15 @@ export const isValidRuntimeKey = (runtime: string): runtime is TestRuntimesKey = export const createStackWithLambdaFunction = (params: StackWithLambdaFunctionOptions): Stack => { const stack = new Stack(params.app, params.stackName); - const testFunction = new lambda.NodejsFunction(stack, `testFunction`, { + const testFunction = new NodejsFunction(stack, `testFunction`, { functionName: params.functionName, entry: params.functionEntry, tracing: params.tracing, environment: params.environment, runtime: TEST_RUNTIMES[params.runtime as TestRuntimesKey], + bundling: params.bundling, + layers: params.layers, + logRetention: RetentionDays.ONE_DAY, }); if (params.logGroupOutputKey) { diff --git a/packages/idempotency/README.md b/packages/idempotency/README.md index 848588fe31..98355a19e5 100644 --- a/packages/idempotency/README.md +++ b/packages/idempotency/README.md @@ -1,6 +1,6 @@ # AWS Lambda Powertools for TypeScript -A suite of utilities for AWS Lambda functions to ease the adoption of best practices such as tracing, structured logging, custom metrics, and more. +Powertools is a developer toolkit to implement Serverless [best practices and increase developer velocity](https://awslabs.github.io/aws-lambda-powertools-typescript/latest/#features). You can use the library in both TypeScript and JavaScript code bases. @@ -80,4 +80,4 @@ Credits for the Lambda Powertools idea go to [DAZN](https://github.com/getndazn) ## License -This library is licensed under the MIT-0 License. See the LICENSE file. \ No newline at end of file +This library is licensed under the MIT-0 License. See the LICENSE file. diff --git a/packages/idempotency/jest.config.js b/packages/idempotency/jest.config.js index c33c7e13fc..aa65679554 100644 --- a/packages/idempotency/jest.config.js +++ b/packages/idempotency/jest.config.js @@ -1,7 +1,7 @@ module.exports = { displayName: { name: 'AWS Lambda Powertools utility: IDEMPOTENCY', - color: 'blue', + color: 'yellow', }, 'runner': 'groups', 'preset': 'ts-jest', diff --git a/packages/idempotency/package.json b/packages/idempotency/package.json index 5d5fc5e0ba..762e57dffb 100644 --- a/packages/idempotency/package.json +++ b/packages/idempotency/package.json @@ -26,7 +26,7 @@ "prepare": "npm run build", "postversion": "echo \"Not implemented\"" }, - "homepage": "https://github.com/awslabs/aws-lambda-powertools-typescript/tree/master/packages/idempotency#readme", + "homepage": "https://github.com/awslabs/aws-lambda-powertools-typescript/tree/main/packages/idempotency#readme", "license": "MIT", "main": "./lib/index.js", "types": "./lib/index.d.ts", diff --git a/packages/idempotency/src/Exceptions.ts b/packages/idempotency/src/Exceptions.ts index 405a59aa66..d39a01b37e 100644 --- a/packages/idempotency/src/Exceptions.ts +++ b/packages/idempotency/src/Exceptions.ts @@ -10,8 +10,23 @@ class IdempotencyInvalidStatusError extends Error { } +class IdempotencyInconsistentStateError extends Error { + +} + +class IdempotencyAlreadyInProgressError extends Error { + +} + +class IdempotencyPersistenceLayerError extends Error { + +} + export { IdempotencyItemNotFoundError, IdempotencyItemAlreadyExistsError, - IdempotencyInvalidStatusError + IdempotencyInvalidStatusError, + IdempotencyInconsistentStateError, + IdempotencyAlreadyInProgressError, + IdempotencyPersistenceLayerError }; \ No newline at end of file diff --git a/packages/idempotency/src/IdempotencyHandler.ts b/packages/idempotency/src/IdempotencyHandler.ts new file mode 100644 index 0000000000..e629fa917b --- /dev/null +++ b/packages/idempotency/src/IdempotencyHandler.ts @@ -0,0 +1,39 @@ +/* eslint-disable @typescript-eslint/no-explicit-any */ + +import { AnyFunctionWithRecord, IdempotencyRecordStatus } from './types'; +import { IdempotencyOptions } from './types/IdempotencyOptions'; +import { IdempotencyRecord } from 'persistence'; +import { IdempotencyInconsistentStateError, IdempotencyItemAlreadyExistsError, IdempotencyAlreadyInProgressError, IdempotencyPersistenceLayerError } from './Exceptions'; + +export class IdempotencyHandler { + + public constructor(private functionToMakeIdempotent: AnyFunctionWithRecord, private functionPayloadToBeHashed: unknown, + private idempotencyOptions: IdempotencyOptions, private fullFunctionPayload: Record) {} + + public determineResultFromIdempotencyRecord(idempotencyRecord: IdempotencyRecord): Promise | U{ + if (idempotencyRecord.getStatus() === IdempotencyRecordStatus.EXPIRED) { + throw new IdempotencyInconsistentStateError('Item has expired during processing and may not longer be valid.'); + } else if (idempotencyRecord.getStatus() === IdempotencyRecordStatus.INPROGRESS){ + throw new IdempotencyAlreadyInProgressError(`There is already an execution in progress with idempotency key: ${idempotencyRecord.idempotencyKey}`); + } else { + // Currently recalling the method as this fulfills FR1. FR3 will address using the previously stored value https://github.com/awslabs/aws-lambda-powertools-typescript/issues/447 + return this.functionToMakeIdempotent(this.fullFunctionPayload); + } + } + + public async processIdempotency(): Promise { + try { + await this.idempotencyOptions.persistenceStore.saveInProgress(this.functionPayloadToBeHashed); + } catch (e) { + if (e instanceof IdempotencyItemAlreadyExistsError) { + const idempotencyRecord: IdempotencyRecord = await this.idempotencyOptions.persistenceStore.getRecord(this.functionPayloadToBeHashed); + + return this.determineResultFromIdempotencyRecord(idempotencyRecord); + } else { + throw new IdempotencyPersistenceLayerError(); + } + } + + return this.functionToMakeIdempotent(this.fullFunctionPayload); + } +} \ No newline at end of file diff --git a/packages/idempotency/src/idempotentDecorator.ts b/packages/idempotency/src/idempotentDecorator.ts new file mode 100644 index 0000000000..51e387b428 --- /dev/null +++ b/packages/idempotency/src/idempotentDecorator.ts @@ -0,0 +1,19 @@ +/* eslint-disable @typescript-eslint/no-explicit-any */ +import { IdempotencyOptions } from './types/IdempotencyOptions'; +import { IdempotencyHandler } from './IdempotencyHandler'; + +const idempotent = function (options: IdempotencyOptions) { + return function (_target: any, _propertyKey: string, descriptor: PropertyDescriptor) { + const childFunction = descriptor.value; + descriptor.value = function(record: Record){ + const idempotencyHandler: IdempotencyHandler = new IdempotencyHandler(childFunction, record[options.dataKeywordArgument], options, record); + + return idempotencyHandler.processIdempotency(); + }; + + return descriptor; + }; +}; + +export { idempotent }; + \ No newline at end of file diff --git a/packages/idempotency/src/makeFunctionIdempotent.ts b/packages/idempotency/src/makeFunctionIdempotent.ts index 40b6e52acf..fd416ccfc5 100644 --- a/packages/idempotency/src/makeFunctionIdempotent.ts +++ b/packages/idempotency/src/makeFunctionIdempotent.ts @@ -1,11 +1,19 @@ -import type { AnyFunction } from './types/AnyFunction'; -import type { IdempotencyOptions } from './types/IdempotencyOptions'; - -const makeFunctionIdempotent = ( - fn: AnyFunction, - _options: IdempotencyOptions - // TODO: revisit this with a more specific type if possible - /* eslint-disable @typescript-eslint/no-explicit-any */ -): (...args: Array) => Promise => (...args) => fn(...args); +/* eslint-disable @typescript-eslint/no-explicit-any */ +import { AnyFunctionWithRecord, AnyIdempotentFunction } from './types/AnyFunction'; +import { IdempotencyOptions } from './types/IdempotencyOptions'; +import { IdempotencyHandler } from './IdempotencyHandler'; + +const makeFunctionIdempotent = function ( + fn: AnyFunctionWithRecord, + options: IdempotencyOptions +): AnyIdempotentFunction { + const wrappedFn: AnyIdempotentFunction = function (record: Record): Promise { + const idempotencyHandler: IdempotencyHandler = new IdempotencyHandler(fn, record[options.dataKeywordArgument], options, record); + + return idempotencyHandler.processIdempotency(); + }; + + return wrappedFn; +}; export { makeFunctionIdempotent }; diff --git a/packages/idempotency/src/types/AnyFunction.ts b/packages/idempotency/src/types/AnyFunction.ts index bddcd8fc15..4b2a894a13 100644 --- a/packages/idempotency/src/types/AnyFunction.ts +++ b/packages/idempotency/src/types/AnyFunction.ts @@ -1,6 +1,11 @@ // eslint-disable-next-line @typescript-eslint/no-explicit-any -type AnyFunction = (...args: Array) => Promise; +type AnyFunctionWithRecord = (record: Record) => Promise | U; + +// eslint-disable-next-line @typescript-eslint/no-explicit-any +type AnyIdempotentFunction = (record: Record) => Promise; export { - AnyFunction + // AnyFunction, + AnyFunctionWithRecord, + AnyIdempotentFunction }; \ No newline at end of file diff --git a/packages/idempotency/src/types/index.ts b/packages/idempotency/src/types/index.ts index 307c6bc093..c725c5a6ba 100644 --- a/packages/idempotency/src/types/index.ts +++ b/packages/idempotency/src/types/index.ts @@ -1,3 +1,4 @@ export * from './AnyFunction'; export * from './IdempotencyRecordStatus'; -export * from './PersistenceLayer'; \ No newline at end of file +export * from './IdempotencyRecordOptions'; +export * from './PersistenceLayer'; diff --git a/packages/idempotency/tests/helpers/populateEnvironmentVariables.ts b/packages/idempotency/tests/helpers/populateEnvironmentVariables.ts index d38651b714..cac6f99929 100644 --- a/packages/idempotency/tests/helpers/populateEnvironmentVariables.ts +++ b/packages/idempotency/tests/helpers/populateEnvironmentVariables.ts @@ -3,5 +3,7 @@ process.env._X_AMZN_TRACE_ID = '1-abcdef12-3456abcdef123456abcdef12'; process.env.AWS_LAMBDA_FUNCTION_NAME = 'my-lambda-function'; process.env.AWS_EXECUTION_ENV = 'nodejs16.x'; process.env.AWS_LAMBDA_FUNCTION_MEMORY_SIZE = '128'; -process.env.AWS_REGION = 'eu-west-1'; -process.env._HANDLER = 'index.handler'; \ No newline at end of file +if (process.env.AWS_REGION === undefined && process.env.CDK_DEFAULT_REGION === undefined) { + process.env.AWS_REGION = 'eu-west-1'; +} +process.env._HANDLER = 'index.handler'; diff --git a/packages/idempotency/tests/unit/idempotentDecorator.test.ts b/packages/idempotency/tests/unit/idempotentDecorator.test.ts new file mode 100644 index 0000000000..3df2689116 --- /dev/null +++ b/packages/idempotency/tests/unit/idempotentDecorator.test.ts @@ -0,0 +1,163 @@ +/** + * Test Function Wrapper + * + * @group unit/idempotency/all + */ + +import { IdempotencyOptions } from '../../src/types/IdempotencyOptions'; +import { PersistenceLayer, IdempotencyRecord } from '../../src/persistence'; +import { idempotent } from '../../src/idempotentDecorator'; +import { IdempotencyRecordStatus, IdempotencyRecordOptions } from '../../src/types'; +import { IdempotencyItemAlreadyExistsError, IdempotencyAlreadyInProgressError, IdempotencyInconsistentStateError, IdempotencyPersistenceLayerError } from '../../src/Exceptions'; + +const mockSaveInProgress = jest.spyOn(PersistenceLayer.prototype, 'saveInProgress').mockImplementation(); +const mockGetRecord = jest.spyOn(PersistenceLayer.prototype, 'getRecord').mockImplementation(); + +class PersistenceLayerTestClass extends PersistenceLayer { + protected _deleteRecord = jest.fn(); + protected _getRecord = jest.fn(); + protected _putRecord = jest.fn(); + protected _updateRecord = jest.fn(); +} + +const options: IdempotencyOptions = { persistenceStore: new PersistenceLayerTestClass(), dataKeywordArgument: 'testingKey' }; +const functionalityToDecorate = jest.fn(); + +class TestingClass { + @idempotent(options) + public testing(record: Record): string { + functionalityToDecorate(record); + + return 'Hi'; + } +} + +describe('Given a class with a function to decorate', (classWithFunction = new TestingClass()) => { + const keyValueToBeSaved = 'thisWillBeSaved'; + const inputRecord = { testingKey: keyValueToBeSaved, otherKey: 'thisWillNot' }; + beforeEach(()=> jest.clearAllMocks()); + describe('When wrapping a function with no previous executions', () => { + beforeEach(async () => { + classWithFunction.testing(inputRecord); + }); + + test('Then it will save the record to INPROGRESS', () => { + expect(mockSaveInProgress).toBeCalledWith(keyValueToBeSaved); + }); + + test('Then it will call the function that was decorated', () => { + expect(functionalityToDecorate).toBeCalledWith(inputRecord); + }); + }); + + describe('When decorating a function with previous execution that is INPROGRESS', () => { + let resultingError: Error; + beforeEach(async () => { + mockSaveInProgress.mockRejectedValue(new IdempotencyItemAlreadyExistsError()); + const idempotencyOptions: IdempotencyRecordOptions = { + idempotencyKey: 'key', + status: IdempotencyRecordStatus.INPROGRESS + }; + mockGetRecord.mockResolvedValue(new IdempotencyRecord(idempotencyOptions)); + try { + await classWithFunction.testing(inputRecord); + } catch (e) { + resultingError = e as Error; + } + }); + + test('Then it will attempt to save the record to INPROGRESS', () => { + expect(mockSaveInProgress).toBeCalledWith(keyValueToBeSaved); + }); + + test('Then it will get the previous execution record', () => { + expect(mockGetRecord).toBeCalledWith(keyValueToBeSaved); + }); + + test('Then it will not call the function that was decorated', () => { + expect(functionalityToDecorate).not.toBeCalled(); + }); + + test('Then an IdempotencyAlreadyInProgressError is thrown', () => { + expect(resultingError).toBeInstanceOf(IdempotencyAlreadyInProgressError); + }); + }); + + describe('When decorating a function with previous execution that is EXPIRED', () => { + let resultingError: Error; + beforeEach(async () => { + mockSaveInProgress.mockRejectedValue(new IdempotencyItemAlreadyExistsError()); + const idempotencyOptions: IdempotencyRecordOptions = { + idempotencyKey: 'key', + status: IdempotencyRecordStatus.EXPIRED + }; + mockGetRecord.mockResolvedValue(new IdempotencyRecord(idempotencyOptions)); + try { + await classWithFunction.testing(inputRecord); + } catch (e) { + resultingError = e as Error; + } + }); + + test('Then it will attempt to save the record to INPROGRESS', () => { + expect(mockSaveInProgress).toBeCalledWith(keyValueToBeSaved); + }); + + test('Then it will get the previous execution record', () => { + expect(mockGetRecord).toBeCalledWith(keyValueToBeSaved); + }); + + test('Then it will not call the function that was decorated', () => { + expect(functionalityToDecorate).not.toBeCalled(); + }); + + test('Then an IdempotencyInconsistentStateError is thrown', () => { + expect(resultingError).toBeInstanceOf(IdempotencyInconsistentStateError); + }); + }); + + describe('When wrapping a function with previous execution that is COMPLETED', () => { + beforeEach(async () => { + mockSaveInProgress.mockRejectedValue(new IdempotencyItemAlreadyExistsError()); + const idempotencyOptions: IdempotencyRecordOptions = { + idempotencyKey: 'key', + status: IdempotencyRecordStatus.COMPLETED + }; + mockGetRecord.mockResolvedValue(new IdempotencyRecord(idempotencyOptions)); + await classWithFunction.testing(inputRecord); + }); + + test('Then it will attempt to save the record to INPROGRESS', () => { + expect(mockSaveInProgress).toBeCalledWith(keyValueToBeSaved); + }); + + test('Then it will get the previous execution record', () => { + expect(mockGetRecord).toBeCalledWith(keyValueToBeSaved); + }); + + //This should be the saved record once FR3 is complete https://github.com/awslabs/aws-lambda-powertools-typescript/issues/447 + test('Then it will call the function that was decorated with the whole input record', () => { + expect(functionalityToDecorate).toBeCalledWith(inputRecord); + }); + }); + + describe('When wrapping a function with issues saving the record', () => { + let resultingError: Error; + beforeEach(async () => { + mockSaveInProgress.mockRejectedValue(new Error('RandomError')); + try { + await classWithFunction.testing(inputRecord); + } catch (e) { + resultingError = e as Error; + } + }); + + test('Then it will attempt to save the record to INPROGRESS', () => { + expect(mockSaveInProgress).toBeCalledWith(keyValueToBeSaved); + }); + + test('Then an IdempotencyPersistenceLayerError is thrown', () => { + expect(resultingError).toBeInstanceOf(IdempotencyPersistenceLayerError); + }); + }); +}); \ No newline at end of file diff --git a/packages/idempotency/tests/unit/makeFunctionIdempotent.test.ts b/packages/idempotency/tests/unit/makeFunctionIdempotent.test.ts new file mode 100644 index 0000000000..95fc50b068 --- /dev/null +++ b/packages/idempotency/tests/unit/makeFunctionIdempotent.test.ts @@ -0,0 +1,163 @@ +/** + * Test Function Wrapper + * + * @group unit/idempotency/all + */ + +import { IdempotencyOptions } from '../../src/types/IdempotencyOptions'; +import { IdempotencyRecord, PersistenceLayer } from '../../src/persistence'; +import { makeFunctionIdempotent } from '../../src/makeFunctionIdempotent'; +import { AnyIdempotentFunction, IdempotencyRecordStatus, IdempotencyRecordOptions } from '../../src/types'; +import { IdempotencyItemAlreadyExistsError, IdempotencyAlreadyInProgressError, IdempotencyInconsistentStateError, IdempotencyPersistenceLayerError } from '../../src/Exceptions'; + +const mockSaveInProgress = jest.spyOn(PersistenceLayer.prototype, 'saveInProgress').mockImplementation(); +const mockGetRecord = jest.spyOn(PersistenceLayer.prototype, 'getRecord').mockImplementation(); + +class PersistenceLayerTestClass extends PersistenceLayer { + protected _deleteRecord = jest.fn(); + protected _getRecord = jest.fn(); + protected _putRecord = jest.fn(); + protected _updateRecord = jest.fn(); +} + +describe('Given a function to wrap', (functionToWrap = jest.fn()) => { + beforeEach(()=> jest.clearAllMocks()); + describe('Given options for idempotency', (options: IdempotencyOptions = { persistenceStore: new PersistenceLayerTestClass(), dataKeywordArgument: 'testingKey' }) => { + const keyValueToBeSaved = 'thisWillBeSaved'; + const inputRecord = { testingKey: keyValueToBeSaved, otherKey: 'thisWillNot' }; + describe('When wrapping a function with no previous executions', () => { + let resultingFunction: AnyIdempotentFunction; + beforeEach(async () => { + resultingFunction = makeFunctionIdempotent(functionToWrap, options); + await resultingFunction(inputRecord); + }); + + test('Then it will save the record to INPROGRESS', () => { + expect(mockSaveInProgress).toBeCalledWith(keyValueToBeSaved); + }); + + test('Then it will call the function that was wrapped with the whole input record', () => { + expect(functionToWrap).toBeCalledWith(inputRecord); + }); + }); + + describe('When wrapping a function with previous execution that is INPROGRESS', () => { + let resultingFunction: AnyIdempotentFunction; + let resultingError: Error; + beforeEach(async () => { + mockSaveInProgress.mockRejectedValue(new IdempotencyItemAlreadyExistsError()); + const idempotencyOptions: IdempotencyRecordOptions = { + idempotencyKey: 'key', + status: IdempotencyRecordStatus.INPROGRESS + }; + mockGetRecord.mockResolvedValue(new IdempotencyRecord(idempotencyOptions)); + resultingFunction = makeFunctionIdempotent(functionToWrap, options); + try { + await resultingFunction(inputRecord); + } catch (e) { + resultingError = e as Error; + } + }); + + test('Then it will attempt to save the record to INPROGRESS', () => { + expect(mockSaveInProgress).toBeCalledWith(keyValueToBeSaved); + }); + + test('Then it will get the previous execution record', () => { + expect(mockGetRecord).toBeCalledWith(keyValueToBeSaved); + }); + + test('Then the function that was wrapped is not called again', () => { + expect(functionToWrap).not.toBeCalled(); + }); + + test('Then an IdempotencyAlreadyInProgressError is thrown', ()=> { + expect(resultingError).toBeInstanceOf(IdempotencyAlreadyInProgressError); + }); + }); + + describe('When wrapping a function with previous execution that is EXPIRED', () => { + let resultingFunction: AnyIdempotentFunction; + let resultingError: Error; + beforeEach(async () => { + mockSaveInProgress.mockRejectedValue(new IdempotencyItemAlreadyExistsError()); + const idempotencyOptions: IdempotencyRecordOptions = { + idempotencyKey: 'key', + status: IdempotencyRecordStatus.EXPIRED + }; + mockGetRecord.mockResolvedValue(new IdempotencyRecord(idempotencyOptions)); + resultingFunction = makeFunctionIdempotent(functionToWrap, options); + try { + await resultingFunction(inputRecord); + } catch (e) { + resultingError = e as Error; + } + }); + + test('Then it will attempt to save the record to INPROGRESS', () => { + expect(mockSaveInProgress).toBeCalledWith(keyValueToBeSaved); + }); + + test('Then it will get the previous execution record', () => { + expect(mockGetRecord).toBeCalledWith(keyValueToBeSaved); + }); + + test('Then the function that was wrapped is not called again', () => { + expect(functionToWrap).not.toBeCalled(); + }); + + test('Then an IdempotencyInconsistentStateError is thrown', ()=> { + expect(resultingError).toBeInstanceOf(IdempotencyInconsistentStateError); + }); + }); + + describe('When wrapping a function with previous execution that is COMPLETED', () => { + let resultingFunction: AnyIdempotentFunction; + beforeEach(async () => { + mockSaveInProgress.mockRejectedValue(new IdempotencyItemAlreadyExistsError()); + const idempotencyOptions: IdempotencyRecordOptions = { + idempotencyKey: 'key', + status: IdempotencyRecordStatus.COMPLETED + }; + mockGetRecord.mockResolvedValue(new IdempotencyRecord(idempotencyOptions)); + resultingFunction = makeFunctionIdempotent(functionToWrap, options); + await resultingFunction(inputRecord); + }); + + test('Then it will attempt to save the record to INPROGRESS', () => { + expect(mockSaveInProgress).toBeCalledWith(keyValueToBeSaved); + }); + + test('Then it will get the previous execution record', () => { + expect(mockGetRecord).toBeCalledWith(keyValueToBeSaved); + }); + + //This should be the saved record once FR3 is complete https://github.com/awslabs/aws-lambda-powertools-typescript/issues/447 + test('Then it will call the function that was wrapped with the whole input record', () => { + expect(functionToWrap).toBeCalledWith(inputRecord); + }); + }); + + describe('When wrapping a function with issues saving the record', () => { + let resultingFunction: AnyIdempotentFunction; + let resultingError: Error; + beforeEach(async () => { + mockSaveInProgress.mockRejectedValue(new Error('RandomError')); + resultingFunction = makeFunctionIdempotent(functionToWrap, options); + try { + await resultingFunction(inputRecord); + } catch (e) { + resultingError = e as Error; + } + }); + + test('Then it will attempt to save the record to INPROGRESS', () => { + expect(mockSaveInProgress).toBeCalledWith(keyValueToBeSaved); + }); + + test('Then an IdempotencyPersistenceLayerError is thrown', ()=> { + expect(resultingError).toBeInstanceOf(IdempotencyPersistenceLayerError); + }); + }); + }); +}); \ No newline at end of file diff --git a/packages/idempotency/tests/unit/persistence/DynamoDbPersistenceLayer.test.ts b/packages/idempotency/tests/unit/persistence/DynamoDbPersistenceLayer.test.ts index 46d3b3e23d..8d95de55e2 100644 --- a/packages/idempotency/tests/unit/persistence/DynamoDbPersistenceLayer.test.ts +++ b/packages/idempotency/tests/unit/persistence/DynamoDbPersistenceLayer.test.ts @@ -34,7 +34,6 @@ describe('Class: DynamoDBPersistenceLayer', () => { public _updateRecord(record: IdempotencyRecord): Promise { return super._updateRecord(record); } - } beforeEach(() => { diff --git a/packages/logger/CHANGELOG.md b/packages/logger/CHANGELOG.md index eeb6fd8122..c20096bb3c 100644 --- a/packages/logger/CHANGELOG.md +++ b/packages/logger/CHANGELOG.md @@ -3,6 +3,23 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. +# [1.6.0](https://github.com/awslabs/aws-lambda-powertools-typescript/compare/v1.5.1...v1.6.0) (2023-03-02) + + +### Bug Fixes + +* **logger:** createChild not passing all parent's attributes ([#1267](https://github.com/awslabs/aws-lambda-powertools-typescript/issues/1267)) ([84ab4b9](https://github.com/awslabs/aws-lambda-powertools-typescript/commit/84ab4b911d17d687bdbe60ded31f1e2b6860feb3)) +* **logger:** middleware stores initial persistent attributes correctly ([#1329](https://github.com/awslabs/aws-lambda-powertools-typescript/issues/1329)) ([6b32304](https://github.com/awslabs/aws-lambda-powertools-typescript/commit/6b3230489895dc1abdfc6ad56daeeb555fda529f)) + + +### Features + +* **logger:** make loglevel types stricter ([#1313](https://github.com/awslabs/aws-lambda-powertools-typescript/issues/1313)) ([5af51d3](https://github.com/awslabs/aws-lambda-powertools-typescript/commit/5af51d319dee68d7a7ba832721580d7a6e655249)) + + + + + ## [1.5.1](https://github.com/awslabs/aws-lambda-powertools-typescript/compare/v1.5.0...v1.5.1) (2023-01-13) diff --git a/packages/logger/README.md b/packages/logger/README.md index 80f5122041..972bd4af2f 100644 --- a/packages/logger/README.md +++ b/packages/logger/README.md @@ -1,6 +1,6 @@ # AWS Lambda Powertools for TypeScript -A suite of utilities for AWS Lambda functions to ease the adoption of best practices such as tracing, structured logging, custom metrics, and more. +Powertools is a developer toolkit to implement Serverless [best practices and increase developer velocity](https://awslabs.github.io/aws-lambda-powertools-typescript/latest/#features). You can use the library in both TypeScript and JavaScript code bases. @@ -81,4 +81,4 @@ Credits for the Lambda Powertools idea go to [DAZN](https://github.com/getndazn) ## License -This library is licensed under the MIT-0 License. See the LICENSE file. \ No newline at end of file +This library is licensed under the MIT-0 License. See the LICENSE file. diff --git a/packages/logger/package.json b/packages/logger/package.json index af2d580bfe..fd35e423d3 100644 --- a/packages/logger/package.json +++ b/packages/logger/package.json @@ -1,6 +1,6 @@ { "name": "@aws-lambda-powertools/logger", - "version": "1.5.1", + "version": "1.6.0", "description": "The logging package for the AWS Lambda Powertools for TypeScript library", "author": { "name": "Amazon Web Services", @@ -26,7 +26,7 @@ "prepare": "npm run build", "postversion": "git push --tags" }, - "homepage": "https://github.com/awslabs/aws-lambda-powertools-typescript/tree/master/packages/logging#readme", + "homepage": "https://github.com/awslabs/aws-lambda-powertools-typescript/tree/main/packages/logging#readme", "license": "MIT", "main": "./lib/index.js", "types": "./lib/index.d.ts", @@ -45,7 +45,7 @@ "url": "https://github.com/awslabs/aws-lambda-powertools-typescript/issues" }, "dependencies": { - "@aws-lambda-powertools/commons": "^1.5.1", + "@aws-lambda-powertools/commons": "^1.6.0", "lodash.merge": "^4.6.2" }, "keywords": [ diff --git a/packages/logger/src/Logger.ts b/packages/logger/src/Logger.ts index a8ef03c8b5..663ce2bd37 100644 --- a/packages/logger/src/Logger.ts +++ b/packages/logger/src/Logger.ts @@ -117,7 +117,7 @@ class Logger extends Utility implements ClassThatLogs { private customConfigService?: ConfigServiceInterface; - private static readonly defaultLogLevel: LogLevel = 'INFO'; + private static readonly defaultLogLevel: Uppercase = 'INFO'; // envVarsService is always initialized in the constructor in setOptions() private envVarsService!: EnvironmentVariablesService; @@ -128,7 +128,7 @@ class Logger extends Utility implements ClassThatLogs { private logIndentation: number = LogJsonIndent.COMPACT; - private logLevel?: LogLevel; + private logLevel?: Uppercase; private readonly logLevelThresholds: LogLevelThresholds = { DEBUG: 8, @@ -203,8 +203,13 @@ class Logger extends Utility implements ClassThatLogs { * @returns {Logger} */ public createChild(options: ConstructorOptions = {}): Logger { + const parentsOptions = { + logLevel: this.getLogLevel(), + customConfigService: this.getCustomConfigService(), + logFormatter: this.getLogFormatter(), + }; const parentsPowertoolsLogData = this.getPowertoolLogData(); - const childLogger = new Logger(merge({}, parentsPowertoolsLogData, options)); + const childLogger = new Logger(merge(parentsOptions, parentsPowertoolsLogData, options)); const parentsPersistentLogAttributes = this.getPersistentLogAttributes(); childLogger.addPersistentLogAttributes(parentsPersistentLogAttributes); @@ -549,12 +554,16 @@ class Logger extends Utility implements ClassThatLogs { /** * It returns the log level set for the Logger instance. + * + * Even though logLevel starts as undefined, it will always be set to a value + * during the Logger instance's initialization. So, we can safely use the non-null + * assertion operator here. * * @private * @returns {LogLevel} */ - private getLogLevel(): LogLevel { - return this.logLevel; + private getLogLevel(): Uppercase { + return this.logLevel!; } /** @@ -614,14 +623,14 @@ class Logger extends Utility implements ClassThatLogs { } /** - * It returns true if the provided log level is valid. + * It returns true and type guards the log level if a given log level is valid. * * @param {LogLevel} logLevel * @private * @returns {boolean} */ - private isValidLogLevel(logLevel?: LogLevel): boolean { - return typeof logLevel === 'string' && logLevel.toUpperCase() in this.logLevelThresholds; + private isValidLogLevel(logLevel?: LogLevel | string): logLevel is Uppercase { + return typeof logLevel === 'string' && logLevel in this.logLevelThresholds; } /** @@ -642,11 +651,12 @@ class Logger extends Utility implements ClassThatLogs { /** * It prints a given log with given log level. * - * @param {LogLevel} logLevel - * @param {LogItem} log + * @param {Uppercase} logLevel + * @param {LogItemMessage} input + * @param {LogItemExtraInput} extraInput * @private */ - private processLogItem(logLevel: LogLevel, input: LogItemMessage, extraInput: LogItemExtraInput): void { + private processLogItem(logLevel: Uppercase, input: LogItemMessage, extraInput: LogItemExtraInput): void { if (!this.shouldPrint(logLevel)) { return; } @@ -738,20 +748,25 @@ class Logger extends Utility implements ClassThatLogs { * @returns {void} */ private setLogLevel(logLevel?: LogLevel): void { - if (this.isValidLogLevel(logLevel)) { - this.logLevel = (logLevel).toUpperCase(); + const constructorLogLevel = logLevel?.toUpperCase(); + if (this.isValidLogLevel(constructorLogLevel)) { + this.logLevel = constructorLogLevel; return; } - const customConfigValue = this.getCustomConfigService()?.getLogLevel(); + const customConfigValue = this.getCustomConfigService() + ?.getLogLevel() + ?.toUpperCase(); if (this.isValidLogLevel(customConfigValue)) { - this.logLevel = (customConfigValue).toUpperCase(); + this.logLevel = customConfigValue; return; } - const envVarsValue = this.getEnvVarsService().getLogLevel(); + const envVarsValue = this.getEnvVarsService() + ?.getLogLevel() + ?.toUpperCase(); if (this.isValidLogLevel(envVarsValue)) { - this.logLevel = (envVarsValue).toUpperCase(); + this.logLevel = envVarsValue; return; } @@ -840,14 +855,15 @@ class Logger extends Utility implements ClassThatLogs { /** * It checks whether the current log item should/can be printed. * - * @param {string} serviceName - * @param {Environment} environment - * @param {LogAttributes} persistentLogAttributes + * @param {Uppercase} logLevel * @private * @returns {boolean} */ - private shouldPrint(logLevel: LogLevel): boolean { - if (this.logLevelThresholds[logLevel] >= this.logLevelThresholds[this.getLogLevel()]) { + private shouldPrint(logLevel: Uppercase): boolean { + if ( + this.logLevelThresholds[logLevel] >= + this.logLevelThresholds[this.getLogLevel()] + ) { return true; } diff --git a/packages/logger/src/middleware/middy.ts b/packages/logger/src/middleware/middy.ts index d0c622aaf5..9b0140a76f 100644 --- a/packages/logger/src/middleware/middy.ts +++ b/packages/logger/src/middleware/middy.ts @@ -35,9 +35,9 @@ const injectLambdaContext = (target: Logger | Logger[], options?: HandlerOptions const persistentAttributes: LogAttributes[] = []; const injectLambdaContextBefore = async (request: MiddyLikeRequest): Promise => { - loggers.forEach((logger: Logger) => { + loggers.forEach((logger: Logger, index: number) => { if (options && options.clearState === true) { - persistentAttributes.push({ ...logger.getPersistentLogAttributes() }); + persistentAttributes[index] = ({ ...logger.getPersistentLogAttributes() }); } Logger.injectLambdaContextBefore(logger, request.event, request.context, options); }); diff --git a/packages/logger/src/types/Log.ts b/packages/logger/src/types/Log.ts index 0b7cd5d30f..020b9cf200 100644 --- a/packages/logger/src/types/Log.ts +++ b/packages/logger/src/types/Log.ts @@ -3,10 +3,10 @@ type LogLevelInfo = 'INFO'; type LogLevelWarn = 'WARN'; type LogLevelError = 'ERROR'; -type LogLevel = LogLevelDebug | LogLevelInfo | LogLevelWarn | LogLevelError | string; +type LogLevel = LogLevelDebug | Lowercase | LogLevelInfo | Lowercase | LogLevelWarn | Lowercase | LogLevelError | Lowercase; type LogLevelThresholds = { - [key in LogLevel]: number; + [key in Uppercase]: number; }; type LogAttributeValue = unknown; diff --git a/packages/logger/tests/e2e/basicFeatures.middy.test.FunctionCode.ts b/packages/logger/tests/e2e/basicFeatures.middy.test.FunctionCode.ts index c434a7892a..116424e395 100644 --- a/packages/logger/tests/e2e/basicFeatures.middy.test.FunctionCode.ts +++ b/packages/logger/tests/e2e/basicFeatures.middy.test.FunctionCode.ts @@ -1,73 +1,66 @@ import { injectLambdaContext, Logger } from '../../src'; import { Context, APIGatewayAuthorizerResult } from 'aws-lambda'; +import { TestEvent, TestOutput } from '../helpers/types'; import middy from '@middy/core'; -const PERSISTENT_KEY = process.env.PERSISTENT_KEY; -const PERSISTENT_KEY_FIRST_INVOCATION_ONLY = process.env.PERSISTENT_KEY_FIRST_INVOCATION_ONLY; -const PERSISTENT_VALUE = process.env.PERSISTENT_VALUE; -const REMOVABLE_KEY = process.env.REMOVABLE_KEY; -const REMOVABLE_VALUE = process.env.REMOVABLE_VALUE; +const PERSISTENT_KEY = process.env.PERSISTENT_KEY || 'persistentKey'; +const PERSISTENT_VALUE = process.env.PERSISTENT_VALUE || 'persistentValue'; +const REMOVABLE_KEY = process.env.REMOVABLE_KEY || 'removableKey'; +const REMOVABLE_VALUE = process.env.REMOVABLE_VALUE || 'remvovableValue'; const ERROR_MSG = process.env.ERROR_MSG || 'error'; -const SINGLE_LOG_ITEM_KEY = process.env.SINGLE_LOG_ITEM_KEY; -const SINGLE_LOG_ITEM_VALUE = process.env.SINGLE_LOG_ITEM_VALUE; -const ARBITRARY_OBJECT_KEY = process.env.ARBITRARY_OBJECT_KEY; -const ARBITRARY_OBJECT_DATA = process.env.ARBITRARY_OBJECT_DATA; - -type LambdaEvent = { - invocation: number -}; +const RUNTIME_ADDED_KEY = process.env.RUNTIME_ADDED_KEY || 'runtimeAddedKey'; +const SINGLE_LOG_ITEM_KEY = process.env.SINGLE_LOG_ITEM_KEY || 'keyForSingleLogItem'; +const SINGLE_LOG_ITEM_VALUE = process.env.SINGLE_LOG_ITEM_VALUE || 'valueForSingleLogItem'; +const ARBITRARY_OBJECT_KEY = process.env.ARBITRARY_OBJECT_KEY || 'keyForArbitraryObject'; +const ARBITRARY_OBJECT_DATA = process.env.ARBITRARY_OBJECT_DATA || 'arbitrary object data'; const logger = new Logger({ persistentLogAttributes: { - [PERSISTENT_KEY]: PERSISTENT_VALUE, - [REMOVABLE_KEY]: REMOVABLE_VALUE, + [PERSISTENT_KEY]: PERSISTENT_VALUE, // This key-value pair will be added to every log + [REMOVABLE_KEY]: REMOVABLE_VALUE, // This other one will be removed at runtime and not displayed in any log }, }); -const testFunction = async (event: LambdaEvent, context: Context): Promise<{requestId: string}> => { - // Test feature 1: Log level filtering - // Test feature 2: Context data - // Test feature 3: Add and remove persistent additional log keys and value - // Test feature 4: X-Ray Trace ID injection - logger.removeKeys([REMOVABLE_KEY]); - - const specialValue = event.invocation; - if (specialValue === 0) { - logger.appendKeys({ - [PERSISTENT_KEY_FIRST_INVOCATION_ONLY]: specialValue - }); - } - +const testFunction = async (event: TestEvent, context: Context): TestOutput => { + // Test feature 1: Context data injection (all logs should have the same context data) + // Test feature 2: Event log (this log should have the event data) + // Test feature 3: Log level filtering (log level is set to INFO) logger.debug('##### This should not appear'); - logger.info('This is an INFO log with context and persistent key'); + + // Test feature 4: Add and remove persistent additional log keys and value + logger.removeKeys([REMOVABLE_KEY]); // This key should not appear in any log (except the event log) + logger.appendKeys({ // This key-value pair should appear in every log (except the event log) + [RUNTIME_ADDED_KEY]: event.invocation, + }); // Test feature 5: One-time additional log keys and values logger.info('This is an one-time log with an additional key-value', { [SINGLE_LOG_ITEM_KEY]: SINGLE_LOG_ITEM_VALUE, }); - // Test feature 6: Logging an error object + // Test feature 6: Error logging try { throw new Error(ERROR_MSG); } catch (e) { logger.error(ERROR_MSG, e as Error); } - // Test feature 7: Logging an arbitrary object + // Test feature 7: Arbitrary object logging const obj: APIGatewayAuthorizerResult = { principalId: ARBITRARY_OBJECT_DATA, policyDocument: { - Version: 'Version' + ARBITRARY_OBJECT_DATA, + Version: 'Version 1', Statement: [{ - Effect: 'Effect' + ARBITRARY_OBJECT_DATA, - Action: 'Action' + ARBITRARY_OBJECT_DATA, - Resource: 'Resource' + ARBITRARY_OBJECT_DATA + Effect: 'Allow', + Action: 'geo:*', + Resource: '*', }] } }; - logger.info('A log entry with an object', { [ARBITRARY_OBJECT_KEY]: obj }); + // Test feature 8: X-Ray Trace ID injection (all logs should have the same X-Ray Trace ID) + return { requestId: context.awsRequestId, }; diff --git a/packages/logger/tests/e2e/basicFeatures.middy.test.ts b/packages/logger/tests/e2e/basicFeatures.middy.test.ts index d12583b84a..04757def04 100644 --- a/packages/logger/tests/e2e/basicFeatures.middy.test.ts +++ b/packages/logger/tests/e2e/basicFeatures.middy.test.ts @@ -1,12 +1,8 @@ -// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. -// SPDX-License-Identifier: MIT-0 - /** * Test logger basic features * * @group e2e/logger/basicFeatures */ - import path from 'path'; import { App, Stack } from 'aws-cdk-lib'; import { APIGatewayAuthorizerResult } from 'aws-lambda'; @@ -24,7 +20,8 @@ import { STACK_OUTPUT_LOG_GROUP, SETUP_TIMEOUT, TEST_CASE_TIMEOUT, - TEARDOWN_TIMEOUT + TEARDOWN_TIMEOUT, + XRAY_TRACE_ID_REGEX, } from './constants'; const runtime: string = process.env.RUNTIME || 'nodejs18x'; @@ -40,17 +37,19 @@ const stackName = generateUniqueName(RESOURCE_NAME_PREFIX, uuid, runtime, 'Basic const functionName = generateUniqueName(RESOURCE_NAME_PREFIX, uuid, runtime, 'BasicFeatures-Middy'); const lambdaFunctionCodeFile = 'basicFeatures.middy.test.FunctionCode.ts'; +const invocationCount = 3; + // Text to be used by Logger in the Lambda function const PERSISTENT_KEY = 'persistentKey'; -const PERSISTENT_KEY_FIRST_INVOCATION_ONLY = 'specialKey'; -const PERSISTENT_VALUE = `a persistent value that will be put in every log ${uuid}`; +const RUNTIME_ADDED_KEY = 'invocation'; +const PERSISTENT_VALUE = uuid; const REMOVABLE_KEY = 'removableKey'; -const REMOVABLE_VALUE = `a persistent value that will be removed and not displayed in any log ${uuid}`; -const SINGLE_LOG_ITEM_KEY = `keyForSingleLogItem${uuid}`; -const SINGLE_LOG_ITEM_VALUE = `a value for a single log item${uuid}`; -const ERROR_MSG = `error-${uuid}`; -const ARBITRARY_OBJECT_KEY = `keyForArbitraryObject${uuid}`; -const ARBITRARY_OBJECT_DATA = `arbitrary object data ${uuid}`; +const REMOVABLE_VALUE = 'removedValue'; +const SINGLE_LOG_ITEM_KEY = 'singleKey'; +const SINGLE_LOG_ITEM_VALUE = 'singleValue'; +const ERROR_MSG = 'error'; +const ARBITRARY_OBJECT_KEY = 'arbitraryObjectKey'; +const ARBITRARY_OBJECT_DATA = 'arbitraryObjectData'; const integTestApp = new App(); let logGroupName: string; // We do not know it until deployment @@ -74,8 +73,8 @@ describe(`logger E2E tests basic functionalities (middy) for runtime: ${runtime} // Text to be used by Logger in the Lambda function PERSISTENT_KEY, - PERSISTENT_KEY_FIRST_INVOCATION_ONLY, PERSISTENT_VALUE, + RUNTIME_ADDED_KEY, REMOVABLE_KEY, REMOVABLE_VALUE, SINGLE_LOG_ITEM_KEY, @@ -91,171 +90,261 @@ describe(`logger E2E tests basic functionalities (middy) for runtime: ${runtime} const result = await deployStack(integTestApp, stack); logGroupName = result.outputs[STACK_OUTPUT_LOG_GROUP]; - // Invoke the function twice (one for cold start, another for warm start) - invocationLogs = await invokeFunction(functionName, 2, 'SEQUENTIAL'); + // Invoke the function three time (one for cold start, then two for warm start) + invocationLogs = await invokeFunction(functionName, invocationCount, 'SEQUENTIAL'); console.log('logGroupName', logGroupName); }, SETUP_TIMEOUT); describe('Log level filtering', () => { + it('should filter log based on LOG_LEVEL (INFO) environment variable in Lambda', async () => { - const debugLogs = invocationLogs[0].getFunctionLogs(LEVEL.DEBUG); - expect(debugLogs.length).toBe(0); + + for (let i = 0; i < invocationCount; i++) { + // Get log messages of the invocation and filter by level + const debugLogs = invocationLogs[i].getFunctionLogs(LEVEL.DEBUG); + // Check that no log message below INFO level is logged + expect(debugLogs.length).toBe(0); + } + }, TEST_CASE_TIMEOUT); }); describe('Context data', () => { - it('should log context information of the function', async () => { - const logMessages = invocationLogs[0].getFunctionLogs(); - - for (const message of logMessages) { - expect(message).toContain('function_arn'); - expect(message).toContain('function_memory_size'); - expect(message).toContain('function_name'); - expect(message).toContain('function_request_id'); - expect(message).toContain('timestamp'); - } - }, TEST_CASE_TIMEOUT); - it('should include cold start equal to TRUE only on the first invocation', async () => { - const coldStartLogMessages = invocationLogs[0].getFunctionLogs(LEVEL.INFO); - for (const message of coldStartLogMessages) { - expect(message).toContain(`"cold_start":true`); + it('should inject context info in each log', async () => { + + for (let i = 0; i < invocationCount; i++) { + // Get log messages of the invocation + const logMessages = invocationLogs[i].getFunctionLogs(); + // Check that the context is logged on every log + for (const message of logMessages) { + const log = InvocationLogs.parseFunctionLog(message); + expect(log).toHaveProperty('function_arn'); + expect(log).toHaveProperty('function_memory_size'); + expect(log).toHaveProperty('function_name'); + expect(log).toHaveProperty('function_request_id'); + expect(log).toHaveProperty('timestamp'); + } } - const normalLogMessages = invocationLogs[1].getFunctionLogs(LEVEL.INFO); - for (const message of normalLogMessages) { - expect(message).not.toContain(`"cold_start":true`); - } }, TEST_CASE_TIMEOUT); - it('should log context information in every log', async () => { - const logMessages = invocationLogs[0].getFunctionLogs(); - - for (const message of logMessages) { - expect(message).toContain('function_arn'); - expect(message).toContain('function_memory_size'); - expect(message).toContain('function_name'); - expect(message).toContain('function_request_id'); - expect(message).toContain('timestamp'); + it('should include coldStart equal to TRUE only on the first invocation, FALSE otherwise', async () => { + + for (let i = 0; i < invocationCount; i++) { + // Get log messages of the invocation + const logMessages = invocationLogs[i].getFunctionLogs(); + // Check that cold start is logged correctly on every log + for (const message of logMessages) { + const log = InvocationLogs.parseFunctionLog(message); + if (i === 0) { + expect(log.cold_start).toBe(true); + } else { + expect(log.cold_start).toBe(false); + } + } } + }, TEST_CASE_TIMEOUT); + }); describe('Log event', () => { - it('should log the event on the first invocation', async () => { - const firstInvocationMessages = invocationLogs[0].getAllFunctionLogs(); - let eventLoggedInFirstInvocation = false; - for (const message of firstInvocationMessages) { - if (message.includes(`event`)) { - eventLoggedInFirstInvocation = true; - expect(message).toContain(`"event":{"invocation":0}`); + it('should log the event as the first log of each invocation only', async () => { + + for (let i = 0; i < invocationCount; i++) { + // Get log messages of the invocation + const logMessages = invocationLogs[i].getFunctionLogs(); + + for (const [ index, message ] of logMessages.entries()) { + const log = InvocationLogs.parseFunctionLog(message); + // Check that the event is logged on the first log + if (index === 0) { + expect(log).toHaveProperty('event'); + expect(log.event).toStrictEqual( + expect.objectContaining({ invocation: i }) + ); + // Check that the event is not logged again on the rest of the logs + } else { + expect(log).not.toHaveProperty('event'); + } } } - const secondInvocationMessages = invocationLogs[1].getAllFunctionLogs(); - let eventLoggedInSecondInvocation = false; - for (const message of secondInvocationMessages) { - if (message.includes(`event`)) { - eventLoggedInSecondInvocation = true; - expect(message).toContain(`"event":{"invocation":1}`); - } - } - - expect(eventLoggedInFirstInvocation).toBe(true); - expect(eventLoggedInSecondInvocation).toBe(true); - }, TEST_CASE_TIMEOUT); }); describe('Persistent additional log keys and values', () => { + it('should contain persistent value in every log', async () => { - const logMessages = invocationLogs[0].getFunctionLogs(); - for (const message of logMessages) { - expect(message).toContain(`"${PERSISTENT_KEY}":"${PERSISTENT_VALUE}"`); + for (let i = 0; i < invocationCount; i++) { + // Get log messages of the invocation + const logMessages = invocationLogs[i].getFunctionLogs(); + + for (const message of logMessages) { + const log = InvocationLogs.parseFunctionLog(message); + // Check that the persistent key is present in every log + expect(log).toHaveProperty(PERSISTENT_KEY); + expect(log[PERSISTENT_KEY]).toBe(PERSISTENT_VALUE); + } } + }, TEST_CASE_TIMEOUT); it('should not contain persistent keys that were removed on runtime', async () => { - const logMessages = invocationLogs[0].getFunctionLogs(); - for (const message of logMessages) { - expect(message).not.toContain(`"${REMOVABLE_KEY}":"${REMOVABLE_VALUE}"`); + for (let i = 0; i < invocationCount; i++) { + // Get log messages of the invocation + const logMessages = invocationLogs[i].getFunctionLogs(); + + for (const [ index, message ] of logMessages.entries()) { + const log = InvocationLogs.parseFunctionLog(message); + // Check that at the time of logging the event, which happens before the handler, + // the key was still present + if (index === 0) { + expect(log).toHaveProperty(REMOVABLE_KEY); + expect(log[REMOVABLE_KEY]).toBe(REMOVABLE_VALUE); + // Check that all other logs that happen at runtime do not contain the key + } else { + expect(log).not.toHaveProperty(REMOVABLE_KEY); + } + } } + }, TEST_CASE_TIMEOUT); - it('with clear state enabled, should not persist keys across invocations', async () => { - const firstInvocationMessages = invocationLogs[0].getFunctionLogs(); - for (const message of firstInvocationMessages) { - expect(message).toContain(`"${PERSISTENT_KEY_FIRST_INVOCATION_ONLY}":0`); + it('should not leak any persistent keys added runtime since clearState is enabled', async () => { + + for (let i = 0; i < invocationCount; i++) { + // Get log messages of the invocation + const logMessages = invocationLogs[i].getFunctionLogs(); + + for (const [ index, message ] of logMessages.entries()) { + const log = InvocationLogs.parseFunctionLog(message); + // Check that at the time of logging the event, which happens before the handler, + // the key is NOT present + if (index === 0) { + expect(log).not.toHaveProperty(RUNTIME_ADDED_KEY); + } else { + // Check that all other logs that happen at runtime do contain the key + expect(log).toHaveProperty(RUNTIME_ADDED_KEY); + // Check that the value is the same for all logs (it should be the index of the invocation) + expect(log[RUNTIME_ADDED_KEY]).toEqual(i); + } + } } - const secondInvocationMessages = invocationLogs[1].getFunctionLogs(); - for (const message of secondInvocationMessages) { - expect(message).not.toContain(`"${PERSISTENT_KEY_FIRST_INVOCATION_ONLY}":0`); - } }, TEST_CASE_TIMEOUT); }); - describe('X-Ray Trace ID injection', () => { - it('should inject & parse X-Ray Trace ID into every log', async () => { - const logMessages = invocationLogs[0].getFunctionLogs(); + describe('One-time additional log keys and values', () => { + + it('should log additional keys and value only once', async () => { - for (const message of logMessages) { - expect(message).toContain('xray_trace_id'); + for (let i = 0; i < invocationCount; i++) { + // Get log messages of the invocation + const logMessages = invocationLogs[i].getFunctionLogs(); + // Check that the additional log is logged only once + const logMessagesWithAdditionalLog = logMessages.filter( + log => log.includes(SINGLE_LOG_ITEM_KEY) + ); + expect(logMessagesWithAdditionalLog).toHaveLength(1); + // Check that the additional log is logged correctly + const parsedLog = InvocationLogs + .parseFunctionLog(logMessagesWithAdditionalLog[0]); + expect(parsedLog[SINGLE_LOG_ITEM_KEY]).toBe(SINGLE_LOG_ITEM_VALUE); } + }, TEST_CASE_TIMEOUT); + }); - describe('One-time additional log keys and values', () => { - it('should log additional keys and value only once', async () => { - const logMessages = invocationLogs[0].getFunctionLogs() - .filter(message => message.includes(`"${SINGLE_LOG_ITEM_KEY}":"${SINGLE_LOG_ITEM_VALUE}"`)); + describe('Error logging', () => { + + it('should log error only once', async () => { + + for (let i = 0; i < invocationCount; i++) { + // Get log messages of the invocation filtered by error level + const logMessages = invocationLogs[i].getFunctionLogs(LEVEL.ERROR); + + // Check that the error is logged only once + expect(logMessages).toHaveLength(1); + + // Check that the error is logged correctly + const errorLog = InvocationLogs.parseFunctionLog(logMessages[0]); + expect(errorLog).toHaveProperty('error'); + expect(errorLog.error).toStrictEqual( + expect.objectContaining({ + location: expect.any(String), + name: 'Error', + message: ERROR_MSG, + stack: expect.anything() + }) + ); + + } - expect(logMessages).toHaveLength(1); }, TEST_CASE_TIMEOUT); + }); + + describe('Arbitrary object logging', () => { + it('should log additional arbitrary object only once', async () => { - const logMessages = invocationLogs[0].getFunctionLogs() - .filter(message => message.includes(ARBITRARY_OBJECT_DATA)); - - expect(logMessages).toHaveLength(1); - - const logObject = InvocationLogs.parseFunctionLog(logMessages[0]); - expect(logObject).toHaveProperty(ARBITRARY_OBJECT_KEY); - const arbitrary = logObject[ARBITRARY_OBJECT_KEY] as APIGatewayAuthorizerResult; - expect(arbitrary.principalId).toBe(ARBITRARY_OBJECT_DATA); - expect(arbitrary.policyDocument).toEqual(expect.objectContaining( - { - Version: 'Version' + ARBITRARY_OBJECT_DATA, - Statement: [{ - Effect: 'Effect' + ARBITRARY_OBJECT_DATA, - Action: 'Action' + ARBITRARY_OBJECT_DATA, - Resource: 'Resource' + ARBITRARY_OBJECT_DATA - }] - } - )); + + for (let i = 0; i < invocationCount; i++) { + // Get log messages of the invocation + const logMessages = invocationLogs[i].getFunctionLogs(); + // Get the log messages that contains the arbitrary object + const filteredLogs = logMessages + .filter(log => log.includes(ARBITRARY_OBJECT_DATA)); + // Check that the arbitrary object is logged only once + expect(filteredLogs).toHaveLength(1); + const logObject = InvocationLogs.parseFunctionLog(filteredLogs[0]); + // Check that the arbitrary object is logged correctly + expect(logObject).toHaveProperty(ARBITRARY_OBJECT_KEY); + const arbitrary = logObject[ARBITRARY_OBJECT_KEY] as APIGatewayAuthorizerResult; + expect(arbitrary.principalId).toBe(ARBITRARY_OBJECT_DATA); + expect(arbitrary.policyDocument).toEqual(expect.objectContaining( + { + Version: 'Version 1', + Statement: [{ + Effect: 'Allow', + Action: 'geo:*', + Resource: '*' + }] + } + )); + } + }, TEST_CASE_TIMEOUT); }); - describe('Logging an error object', () => { - it('should log error only once', async () => { - const logMessages = invocationLogs[0].getFunctionLogs(LEVEL.ERROR) - .filter(message => message.includes(ERROR_MSG)); - - expect(logMessages).toHaveLength(1); + describe('X-Ray Trace ID injection', () => { - const logObject = InvocationLogs.parseFunctionLog(logMessages[0]); - const errorObj = logObject.error; + it('should inject & parse the X-Ray Trace ID of the current invocation into every log', async () => { + + for (let i = 0; i < invocationCount; i++) { + // Get log messages of the invocation + const logMessages = invocationLogs[i].getFunctionLogs(); + + // Check that the X-Ray Trace ID is logged on every log + const traceIds: string[] = []; + for (const message of logMessages) { + const log = InvocationLogs.parseFunctionLog(message); + expect(log).toHaveProperty('xray_trace_id'); + expect(log.xray_trace_id).toMatch(XRAY_TRACE_ID_REGEX); + traceIds.push(log.xray_trace_id as string); + } + } - expect(errorObj.name).toBe('Error'); - expect(errorObj.message).toBe(ERROR_MSG); - expect(errorObj.stack).toBeDefined(); }, TEST_CASE_TIMEOUT); + }); afterAll(async () => { diff --git a/packages/logger/tests/e2e/childLogger.manual.test.FunctionCode.ts b/packages/logger/tests/e2e/childLogger.manual.test.FunctionCode.ts index a738eb6888..c4e0fd8ec3 100644 --- a/packages/logger/tests/e2e/childLogger.manual.test.FunctionCode.ts +++ b/packages/logger/tests/e2e/childLogger.manual.test.FunctionCode.ts @@ -1,15 +1,17 @@ import { Logger } from '../../src'; -import { APIGatewayProxyEvent, Context } from 'aws-lambda'; +import { Context } from 'aws-lambda'; +import { LogLevel } from '../../src/types'; +import { TestEvent, TestOutput } from '../helpers/types'; -const PARENT_PERSISTENT_KEY = process.env.PARENT_PERSISTENT_KEY; -const PARENT_PERSISTENT_VALUE = process.env.PARENT_PERSISTENT_VALUE; -const PARENT_LOG_MSG = process.env.PARENT_LOG_MSG; -const CHILD_LOG_MSG = process.env.PARENT_LOG_MSG; -const CHILD_LOG_LEVEL = process.env.CHILD_LOG_LEVEL; +const PERSISTENT_KEY = process.env.PERSISTENT_KEY || 'persistentKey'; +const PERSISTENT_VALUE = process.env.ERSISTENT_VALUE || 'persistentValue'; +const PARENT_LOG_MSG = process.env.PARENT_LOG_MSG || 'parent-only-log-msg'; +const CHILD_LOG_MSG = process.env.CHILD_LOG_MSG || 'child-only-log-msg'; +const CHILD_LOG_LEVEL = (process.env.CHILD_LOG_LEVEL || 'warn') as LogLevel; const parentLogger = new Logger({ persistentLogAttributes: { - [PARENT_PERSISTENT_KEY]: PARENT_PERSISTENT_VALUE, + [PERSISTENT_KEY]: PERSISTENT_VALUE, } }); @@ -18,7 +20,7 @@ const childLogger = parentLogger.createChild({ logLevel: CHILD_LOG_LEVEL, }); -export const handler = async (event: APIGatewayProxyEvent, context: Context): Promise<{requestId: string}> => { +export const handler = async (_event: TestEvent, context: Context): TestOutput => { parentLogger.addContext(context); childLogger.info(CHILD_LOG_MSG); diff --git a/packages/logger/tests/e2e/childLogger.manual.test.ts b/packages/logger/tests/e2e/childLogger.manual.test.ts index 5bce0bb4f5..1e11d52b0b 100644 --- a/packages/logger/tests/e2e/childLogger.manual.test.ts +++ b/packages/logger/tests/e2e/childLogger.manual.test.ts @@ -1,12 +1,8 @@ -// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. -// SPDX-License-Identifier: MIT-0 - /** * Test logger child logger * * @group e2e/logger/childLogger */ - import path from 'path'; import { App, Stack } from 'aws-cdk-lib'; import { v4 } from 'uuid'; @@ -39,16 +35,19 @@ const stackName = generateUniqueName(RESOURCE_NAME_PREFIX, uuid, runtime, 'Child const functionName = generateUniqueName(RESOURCE_NAME_PREFIX, uuid, runtime, 'ChildLogger-Manual'); const lambdaFunctionCodeFile = 'childLogger.manual.test.FunctionCode.ts'; +const invocationCount = 3; + // Parameters to be used by Logger in the Lambda function -const PARENT_PERSISTENT_KEY = 'persistentKey'; -const PARENT_PERSISTENT_VALUE = `a persistent value that will be put in prent only ${uuid}`; -const PARENT_LOG_MSG = `only PARENT logger will log with this message ${uuid}`; -const CHILD_LOG_MSG = `only CHILD logger will log with this message ${uuid}`; -const CHILD_LOG_LEVEL = LEVEL.ERROR.toString(); +const PERSISTENT_KEY = 'persistentKey'; +const PERSISTENT_VALUE = 'persistentValue'; +const PARENT_LOG_MSG = 'parent-only-log-msg'; +const CHILD_LOG_MSG = 'child-only-log-msg'; +const CHILD_LOG_LEVEL = LEVEL.ERROR; const integTestApp = new App(); let logGroupName: string; // We do not know it until deployment let stack: Stack; + describe(`logger E2E tests child logger functionalities (manual) for runtime: ${runtime}`, () => { let invocationLogs: InvocationLogs[]; @@ -67,8 +66,8 @@ describe(`logger E2E tests child logger functionalities (manual) for runtime: ${ UUID: uuid, // Text to be used by Logger in the Lambda function - PARENT_PERSISTENT_KEY, - PARENT_PERSISTENT_VALUE, + PERSISTENT_KEY, + PERSISTENT_VALUE, PARENT_LOG_MSG, CHILD_LOG_MSG, CHILD_LOG_LEVEL, @@ -79,55 +78,89 @@ describe(`logger E2E tests child logger functionalities (manual) for runtime: ${ const result = await deployStack(integTestApp, stack); logGroupName = result.outputs[STACK_OUTPUT_LOG_GROUP]; - // Invoke the function once - invocationLogs = await invokeFunction(functionName, 1); + // Invoke the function three time (one for cold start, then two for warm start) + invocationLogs = await invokeFunction(functionName, invocationCount); console.log('logGroupName', logGroupName); }, SETUP_TIMEOUT); - const getAllChildLogs = (): string[] => invocationLogs[0].getFunctionLogs() - .filter(message => message.includes(CHILD_LOG_MSG)); - describe('Child logger', () => { - it('should not log at parent log level', async () => { - // Only parents log will appear at info level - const allInfoLogs = invocationLogs[0].getFunctionLogs(LEVEL.INFO); - const parentInfoLogs = allInfoLogs.filter(message => message.includes(PARENT_LOG_MSG)); - const childInfoLogs = allInfoLogs.filter(message => message.includes(CHILD_LOG_MSG)); - - expect(parentInfoLogs).toHaveLength(allInfoLogs.length); - expect(childInfoLogs).toHaveLength(0); + + it('should not log at same level of parent because of its own logLevel', async () => { + + for (let i = 0; i < invocationCount; i++) { + // Get log messages of the invocation and filter by level + const infoLogs = invocationLogs[i].getFunctionLogs(LEVEL.INFO); + + const parentInfoLogs = infoLogs + .filter(message => message.includes(PARENT_LOG_MSG)); + const childInfoLogs = infoLogs + .filter(message => message.includes(CHILD_LOG_MSG)); + + expect(parentInfoLogs).toHaveLength(infoLogs.length); + expect(childInfoLogs).toHaveLength(0); + } + }, TEST_CASE_TIMEOUT); it('should log only level passed to a child', async () => { - const allChildLogs = getAllChildLogs(); - const errorChildLogs = allChildLogs.filter(message => message.includes(LEVEL.ERROR.toString())); - expect(errorChildLogs).toHaveLength(allChildLogs.length); + for (let i = 0; i < invocationCount; i++) { + // Get log messages of the invocation + const logMessages = invocationLogs[i].getFunctionLogs(); + + // Filter child logs by level + const errorChildLogs = logMessages + .filter( + message => message.includes(LEVEL.ERROR.toString()) && + message.includes(CHILD_LOG_MSG) + ); + + // Check that the child logger only logged once (the other) + // log was filtered out by the child logger because of its logLevel + expect(errorChildLogs).toHaveLength(1); + } + }, TEST_CASE_TIMEOUT); it('should NOT inject context into the child logger', async () => { - // Only parent has injected context. - const allChildLogs = getAllChildLogs(); - - for (const log of allChildLogs) { - expect(log).not.toContain('function_arn'); - expect(log).not.toContain('function_memory_size'); - expect(log).not.toContain('function_name'); - expect(log).not.toContain('function_request_id'); - expect(log).not.toContain('timestamp'); + + for (let i = 0; i < invocationCount; i++) { + // Get log messages of the invocation + const logMessages = invocationLogs[i].getFunctionLogs(); + + // Filter child logs by level + const childLogMessages = logMessages + .filter(message => message.includes(CHILD_LOG_MSG)); + + // Check that the context is not present in any of the child logs + for (const message of childLogMessages) { + const log = InvocationLogs.parseFunctionLog(message); + expect(log).not.toHaveProperty('function_arn'); + expect(log).not.toHaveProperty('function_memory_size'); + expect(log).not.toHaveProperty('function_name'); + expect(log).not.toHaveProperty('function_request_id'); + } } + }, TEST_CASE_TIMEOUT); - it('should NOT have parent logger persistent key/value', async () => { - // Only parent has injected context. - const allChildLogs = getAllChildLogs(); + it('both logger instances should have the same persistent key/value', async () => { + + for (let i = 0; i < invocationCount; i++) { + // Get log messages of the invocation + const logMessages = invocationLogs[i].getFunctionLogs(); - for (const log of allChildLogs) { - expect(log).not.toContain(`"${PARENT_PERSISTENT_KEY}":"${PARENT_PERSISTENT_VALUE}"`); + // Check that all logs have the persistent key/value + for (const message of logMessages) { + const log = InvocationLogs.parseFunctionLog(message); + expect(log).toHaveProperty(PERSISTENT_KEY); + } } + }, TEST_CASE_TIMEOUT); + }); afterAll(async () => { diff --git a/packages/logger/tests/e2e/constants.ts b/packages/logger/tests/e2e/constants.ts index 79eb64e5aa..25c928e0c1 100644 --- a/packages/logger/tests/e2e/constants.ts +++ b/packages/logger/tests/e2e/constants.ts @@ -3,4 +3,5 @@ export const ONE_MINUTE = 60 * 1000; export const TEST_CASE_TIMEOUT = ONE_MINUTE; export const SETUP_TIMEOUT = 5 * ONE_MINUTE; export const TEARDOWN_TIMEOUT = 5 * ONE_MINUTE; -export const STACK_OUTPUT_LOG_GROUP = 'LogGroupName'; \ No newline at end of file +export const STACK_OUTPUT_LOG_GROUP = 'LogGroupName'; +export const XRAY_TRACE_ID_REGEX = /^1-[0-9a-f]{8}-[0-9a-f]{24}$/; \ No newline at end of file diff --git a/packages/logger/tests/e2e/logEventEnvVarSetting.middy.test.FunctionCode.ts b/packages/logger/tests/e2e/logEventEnvVarSetting.middy.test.FunctionCode.ts index 6d412daf06..6fdcd1ec62 100644 --- a/packages/logger/tests/e2e/logEventEnvVarSetting.middy.test.FunctionCode.ts +++ b/packages/logger/tests/e2e/logEventEnvVarSetting.middy.test.FunctionCode.ts @@ -1,16 +1,14 @@ import { injectLambdaContext, Logger } from '../../src'; +import { TestEvent, TestOutput } from '../helpers/types'; import { Context } from 'aws-lambda'; import middy from '@middy/core'; -type LambdaEvent = { - invocation: number -}; - const logger = new Logger(); -const testFunction = async (event: LambdaEvent, context: Context): Promise<{requestId: string}> => ({ +const testFunction = async (_event: TestEvent, context: Context): TestOutput => ({ requestId: context.awsRequestId, }); export const handler = middy(testFunction) - .use(injectLambdaContext(logger)); + // The event should be logged because POWERTOOLS_LOGGER_LOG_EVENT is set to true + .use(injectLambdaContext(logger)); diff --git a/packages/logger/tests/e2e/logEventEnvVarSetting.middy.test.ts b/packages/logger/tests/e2e/logEventEnvVarSetting.middy.test.ts index 147d838c95..fc49c31a8c 100644 --- a/packages/logger/tests/e2e/logEventEnvVarSetting.middy.test.ts +++ b/packages/logger/tests/e2e/logEventEnvVarSetting.middy.test.ts @@ -1,12 +1,8 @@ -// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. -// SPDX-License-Identifier: MIT-0 - /** * Test logger basic features * * @group e2e/logger/logEventEnvVarSetting */ - import path from 'path'; import { App, Stack } from 'aws-cdk-lib'; import { v4 } from 'uuid'; @@ -37,6 +33,8 @@ const stackName = generateUniqueName(RESOURCE_NAME_PREFIX, uuid, runtime, 'LogEv const functionName = generateUniqueName(RESOURCE_NAME_PREFIX, uuid, runtime, 'LogEventEnvVarSetting-Middy'); const lambdaFunctionCodeFile = 'logEventEnvVarSetting.middy.test.FunctionCode.ts'; +const invocationCount = 3; + const integTestApp = new App(); let logGroupName: string; // We do not know it until deployment let stack: Stack; @@ -67,8 +65,8 @@ describe(`logger E2E tests log event via env var setting (middy) for runtime: ${ const result = await deployStack(integTestApp, stack); logGroupName = result.outputs[STACK_OUTPUT_LOG_GROUP]; - // Invoke the function twice (one for cold start, another for warm start) - invocationLogs = await invokeFunction(functionName, 2, 'SEQUENTIAL'); + // Invoke the function three time (one for cold start, then two for warm start) + invocationLogs = await invokeFunction(functionName, invocationCount, 'SEQUENTIAL'); console.log('logGroupName', logGroupName); @@ -76,28 +74,27 @@ describe(`logger E2E tests log event via env var setting (middy) for runtime: ${ describe('Log event', () => { - it('should log the event at both invocations', async () => { - const firstInvocationMessages = invocationLogs[0].getAllFunctionLogs(); - let eventLoggedInFirstInvocation = false; - for (const message of firstInvocationMessages) { - if (message.includes(`event`)) { - eventLoggedInFirstInvocation = true; - expect(message).toContain(`"event":{"invocation":0}`); + it('should log the event as the first log of each invocation only', async () => { + + for (let i = 0; i < invocationCount; i++) { + // Get log messages of the invocation + const logMessages = invocationLogs[i].getFunctionLogs(); + + for (const [ index, message ] of logMessages.entries()) { + const log = InvocationLogs.parseFunctionLog(message); + // Check that the event is logged on the first log + if (index === 0) { + expect(log).toHaveProperty('event'); + expect(log.event).toStrictEqual( + expect.objectContaining({ invocation: i }) + ); + // Check that the event is not logged again on the rest of the logs + } else { + expect(log).not.toHaveProperty('event'); + } } } - const secondInvocationMessages = invocationLogs[1].getAllFunctionLogs(); - let eventLoggedInSecondInvocation = false; - for (const message of secondInvocationMessages) { - if (message.includes(`event`)) { - eventLoggedInSecondInvocation = true; - expect(message).toContain(`"event":{"invocation":1}`); - } - } - - expect(eventLoggedInFirstInvocation).toBe(true); - expect(eventLoggedInSecondInvocation).toBe(true); - }, TEST_CASE_TIMEOUT); }); diff --git a/packages/logger/tests/e2e/sampleRate.decorator.test.FunctionCode.ts b/packages/logger/tests/e2e/sampleRate.decorator.test.FunctionCode.ts index 72c13f07b4..ba4b7f8895 100644 --- a/packages/logger/tests/e2e/sampleRate.decorator.test.FunctionCode.ts +++ b/packages/logger/tests/e2e/sampleRate.decorator.test.FunctionCode.ts @@ -1,5 +1,6 @@ import { Logger } from '../../src'; -import { APIGatewayProxyEvent, Context } from 'aws-lambda'; +import { TestEvent, TestOutput } from '../helpers/types'; +import { Context } from 'aws-lambda'; import { LambdaInterface } from '@aws-lambda-powertools/commons'; const SAMPLE_RATE = parseFloat(process.env.SAMPLE_RATE || '0.1'); @@ -20,7 +21,7 @@ class Lambda implements LambdaInterface { @logger.injectLambdaContext() // eslint-disable-next-line @typescript-eslint/ban-ts-comment // @ts-ignore - public async handler(event: APIGatewayProxyEvent, context: Context): Promise<{requestId: string}> { + public async handler(event: TestEvent, context: Context): TestOutput { this.printLogInAllLevels(); return { diff --git a/packages/logger/tests/e2e/sampleRate.decorator.test.ts b/packages/logger/tests/e2e/sampleRate.decorator.test.ts index f803deae79..1955b20f46 100644 --- a/packages/logger/tests/e2e/sampleRate.decorator.test.ts +++ b/packages/logger/tests/e2e/sampleRate.decorator.test.ts @@ -1,12 +1,8 @@ -// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. -// SPDX-License-Identifier: MIT-0 - /** * Test logger sample rate feature * * @group e2e/logger/sampleRate */ - import path from 'path'; import { App, Stack } from 'aws-cdk-lib'; import { v4 } from 'uuid'; @@ -39,16 +35,18 @@ const stackName = generateUniqueName(RESOURCE_NAME_PREFIX, uuid, runtime, 'Sampl const functionName = generateUniqueName(RESOURCE_NAME_PREFIX, uuid, runtime, 'SampleRate-Decorator'); const lambdaFunctionCodeFile = 'sampleRate.decorator.test.FunctionCode.ts'; +const invocationCount = 20; + // Parameters to be used by Logger in the Lambda function const LOG_MSG = `Log message ${uuid}`; const SAMPLE_RATE = '0.5'; -const LOG_LEVEL = LEVEL.ERROR.toString(); +const LOG_LEVEL = LEVEL.ERROR; const integTestApp = new App(); let stack: Stack; let logGroupName: string; // We do not know the exact name until deployment -describe(`logger E2E tests sample rate and injectLambdaContext() for runtime: ${runtime}`, () => { +describe(`logger E2E tests sample rate and injectLambdaContext() for runtime: nodejs18x`, () => { let invocationLogs: InvocationLogs[]; @@ -75,7 +73,7 @@ describe(`logger E2E tests sample rate and injectLambdaContext() for runtime: ${ const result = await deployStack(integTestApp, stack); logGroupName = result.outputs[STACK_OUTPUT_LOG_GROUP]; - invocationLogs = await invokeFunction(functionName, 20); + invocationLogs = await invokeFunction(functionName, invocationCount); console.log('logGroupName', logGroupName); @@ -86,23 +84,23 @@ describe(`logger E2E tests sample rate and injectLambdaContext() for runtime: ${ // Fetch log streams from all invocations let countSampled = 0; let countNotSampled = 0; - for (const invocationLog of invocationLogs) { - const logs = invocationLog.getFunctionLogs(); - if (logs.length === 1 && logs[0].includes(LEVEL.ERROR.toString())) { + + for (let i = 0; i < invocationCount; i++) { + // Get log messages of the invocation + const logMessages = invocationLogs[i].getFunctionLogs(); + + if (logMessages.length === 1 && logMessages[0].includes(LEVEL.ERROR)) { countNotSampled++; - } else if (logs.length === 4) { + } else if (logMessages.length === 4) { countSampled++; } else { - // TODO: To be investigate if this is Lambda service's issue. This happens once every 10-20 e2e tests runs. The symptoms I found are: - // 1. Warning and error logs disappear (in sampled case) - // 2. Error log disappears (in non-sampled case) - // I reviewed Logger code but it is not possible that the first case could happen because we use the same "logsSampled" flag. console.error(`Log group ${logGroupName} contains missing log`); throw new Error('Sampled log should have either 1 error log or 4 logs of all levels'); } } - // Given that we set rate to 0.5. The chance that we get all invocations sampled (or not sampled) is less than 0.5^20 + // Given that we set rate to 0.5. The chance that we get all invocations sampled + // (or not sampled) is less than 0.5^20 expect(countSampled).toBeGreaterThan(0); expect(countNotSampled).toBeGreaterThan(0); @@ -110,15 +108,21 @@ describe(`logger E2E tests sample rate and injectLambdaContext() for runtime: ${ }); describe('Decorator injectLambdaContext()', () => { - it('should inject Lambda context into the log', async () => { - const logMessages = invocationLogs[0].getFunctionLogs(LEVEL.ERROR); - - for (const log of logMessages) { - expect(log).toContain('function_arn'); - expect(log).toContain('function_memory_size'); - expect(log).toContain('function_name'); - expect(log).toContain('function_request_id'); - expect(log).toContain('timestamp'); + it('should inject Lambda context into every log emitted', async () => { + + for (let i = 0; i < invocationCount; i++) { + // Get log messages of the invocation + const logMessages = invocationLogs[i].getFunctionLogs(LEVEL.ERROR); + + // Check that the context is logged on every log + for (const message of logMessages) { + const log = InvocationLogs.parseFunctionLog(message); + expect(log).toHaveProperty('function_arn'); + expect(log).toHaveProperty('function_memory_size'); + expect(log).toHaveProperty('function_name'); + expect(log).toHaveProperty('function_request_id'); + expect(log).toHaveProperty('timestamp'); + } } }, TEST_CASE_TIMEOUT); diff --git a/packages/logger/tests/helpers/populateEnvironmentVariables.ts b/packages/logger/tests/helpers/populateEnvironmentVariables.ts index e808ac84b9..604904e073 100644 --- a/packages/logger/tests/helpers/populateEnvironmentVariables.ts +++ b/packages/logger/tests/helpers/populateEnvironmentVariables.ts @@ -2,7 +2,9 @@ process.env._X_AMZN_TRACE_ID = 'Root=1-5759e988-bd862e3fe1be46a994272793;Parent=557abcec3ee5a047;Sampled=1'; process.env.AWS_LAMBDA_FUNCTION_NAME = 'my-lambda-function'; process.env.AWS_LAMBDA_FUNCTION_MEMORY_SIZE = '128'; -process.env.AWS_REGION = 'eu-west-1'; +if (process.env.AWS_REGION === undefined && process.env.CDK_DEFAULT_REGION === undefined) { + process.env.AWS_REGION = 'eu-west-1'; +} // Powertools variables process.env.LOG_LEVEL = 'DEBUG'; diff --git a/packages/logger/tests/helpers/types.ts b/packages/logger/tests/helpers/types.ts new file mode 100644 index 0000000000..8c7b5dcbdf --- /dev/null +++ b/packages/logger/tests/helpers/types.ts @@ -0,0 +1,5 @@ +export type TestEvent = { + invocation: number +}; + +export type TestOutput = Promise<{requestId: string}>; \ No newline at end of file diff --git a/packages/logger/tests/unit/Logger.test.ts b/packages/logger/tests/unit/Logger.test.ts index 717c964ad1..eedb348c81 100644 --- a/packages/logger/tests/unit/Logger.test.ts +++ b/packages/logger/tests/unit/Logger.test.ts @@ -3,12 +3,14 @@ * * @group unit/logger/all */ - -import { ContextExamples as dummyContext, Events as dummyEvent, LambdaInterface } from '@aws-lambda-powertools/commons'; +import { + ContextExamples as dummyContext, + Events as dummyEvent, LambdaInterface +} from '@aws-lambda-powertools/commons'; import { createLogger, Logger } from '../../src'; import { EnvironmentVariablesService } from '../../src/config'; import { PowertoolLogFormatter } from '../../src/formatter'; -import { ClassThatLogs, LogJsonIndent } from '../../src/types'; +import { ClassThatLogs, LogJsonIndent, ConstructorOptions } from '../../src/types'; import { Context } from 'aws-lambda'; import { Console } from 'console'; @@ -16,6 +18,7 @@ const mockDate = new Date(1466424490000); const dateSpy = jest.spyOn(global, 'Date').mockImplementation(() => mockDate); describe('Class: Logger', () => { + const ENVIRONMENT_VARIABLES = process.env; const context = dummyContext.helloworldContext; const event = dummyEvent.Custom.CustomEvent; @@ -45,6 +48,7 @@ describe('Class: Logger', () => { ) => { describe('Feature: log level', () => { + const methodOfLogger = method as keyof ClassThatLogs; test('when the Logger\'s log level is DEBUG, it ' + debugAction + ' print to stdout', () => { @@ -207,7 +211,7 @@ describe('Class: Logger', () => { }); - describe('Feature: capture Lambda context information and add it in the printed logs', () => { + describe('Feature: inject context', () => { const methodOfLogger = method as keyof ClassThatLogs; @@ -231,6 +235,7 @@ describe('Class: Logger', () => { timestamp: '2016-06-20T12:08:10.000Z', xray_trace_id: '1-5759e988-bd862e3fe1be46a994272793', })); + }); test('when the Lambda context is captured, it returns a valid ' + method.toUpperCase() + ' log', () => { @@ -398,7 +403,9 @@ describe('Class: Logger', () => { } } })); + }); + }); describe('Feature: persistent log attributes', () => { @@ -433,6 +440,7 @@ describe('Class: Logger', () => { aws_account_id: '123456789012', aws_region: 'eu-west-1', })); + }); }); @@ -463,6 +471,7 @@ describe('Class: Logger', () => { timestamp: '2016-06-20T12:08:10.000Z', xray_trace_id: '1-5759e988-bd862e3fe1be46a994272793', })); + }); test('when the `_X_AMZN_TRACE_ID` environment variable is NOT set it parses it correctly and adds the Trace ID to the log', () => { @@ -487,6 +496,7 @@ describe('Class: Logger', () => { service: 'hello-world', timestamp: '2016-06-20T12:08:10.000Z', })); + }); }); @@ -533,7 +543,7 @@ describe('Class: Logger', () => { }); - test('when a logged item has BigInt value, it doen\'t throw TypeError', () => { + test('when a logged item has BigInt value, it doesn\'t throw TypeError', () => { // Prepare const logger = new Logger(); @@ -600,28 +610,13 @@ describe('Class: Logger', () => { describe('Method: addContext', () => { - const baseContext = { - callbackWaitsForEmptyEventLoop: true, - functionVersion: '$LATEST', - functionName: 'foo-bar-function-with-cold-start', - memoryLimitInMB: '128', - logGroupName: '/aws/lambda/foo-bar-function-with-cold-start', - logStreamName: '2021/03/09/[$LATEST]1-5759e988-bd862e3fe1be46a994272793', - invokedFunctionArn: 'arn:aws:lambda:eu-west-1:123456789012:function:foo-bar-function-with-cold-start', - awsRequestId: 'c6af9ac6-7b61-11e6-9a41-93e812345678', - getRemainingTimeInMillis: () => 1234, - done: () => console.log('Done!'), - fail: () => console.log('Failed!'), - succeed: () => console.log('Succeeded!'), - }; - - test('when called during a COLD START invocation, it populates the logger\'s PowertoolLogData object with coldstart set to true', () => { + test('when called during a cold start invocation, it populates the logger\'s PowertoolLogData object with coldStart set to TRUE', () => { // Prepare const logger = new Logger(); // Act - logger.addContext(baseContext); + logger.addContext(context); // Assess expect(logger).toEqual({ @@ -648,23 +643,25 @@ describe('Class: Logger', () => { lambdaContext: { awsRequestId: 'c6af9ac6-7b61-11e6-9a41-93e812345678', coldStart: true, - functionName: 'foo-bar-function-with-cold-start', + functionName: 'foo-bar-function', functionVersion: '$LATEST', - invokedFunctionArn: 'arn:aws:lambda:eu-west-1:123456789012:function:foo-bar-function-with-cold-start', + invokedFunctionArn: 'arn:aws:lambda:eu-west-1:123456789012:function:foo-bar-function', memoryLimitInMB: 128, }, sampleRateValue: undefined, serviceName: 'hello-world', }, + }); + }); test('when called with a context object, the object is not mutated', () => { // Prepare const logger = new Logger(); - const context1 = { ...baseContext, awsRequestId: 'c6af9ac6-7b61-11e6-9a41-93e812345678' }; - const context2 = { ...baseContext, awsRequestId: 'd40c98a9-91c4-478c-a179-433c4b978289' }; + const context1 = { ...context, awsRequestId: 'c6af9ac6-7b61-11e6-9a41-93e812345678' }; + const context2 = { ...context, awsRequestId: 'd40c98a9-91c4-478c-a179-433c4b978289' }; // Act logger.addContext(context1); @@ -673,14 +670,15 @@ describe('Class: Logger', () => { // Assess expect(context1.awsRequestId).toEqual('c6af9ac6-7b61-11e6-9a41-93e812345678'); expect(context2.awsRequestId).toEqual('d40c98a9-91c4-478c-a179-433c4b978289'); + }); test('when called multiple times, the newer values override earlier values', () => { // Prepare const logger = new Logger(); - const context1 = { ...baseContext, awsRequestId: 'c6af9ac6-7b61-11e6-9a41-93e812345678' }; - const context2 = { ...baseContext, awsRequestId: 'd40c98a9-91c4-478c-a179-433c4b978289' }; + const context1 = { ...context, awsRequestId: 'c6af9ac6-7b61-11e6-9a41-93e812345678' }; + const context2 = { ...context, awsRequestId: 'd40c98a9-91c4-478c-a179-433c4b978289' }; // Act logger.addContext(context1); @@ -696,7 +694,9 @@ describe('Class: Logger', () => { }) }) ); + }); + }); describe('Method: appendKeys', () => { @@ -727,6 +727,7 @@ describe('Class: Logger', () => { }, }, })); + }); test('when called with user-provided attribute objects, the objects are not mutated', () => { @@ -743,6 +744,7 @@ describe('Class: Logger', () => { // Assess expect(attributes1).toEqual({ keyOne: 'abc' }); expect(attributes2).toEqual({ keyTwo: 'def' }); + }); test('when called multiple times, the newer values override earlier values', () => { @@ -764,7 +766,9 @@ describe('Class: Logger', () => { duplicateKey: 'two' } })); + }); + }); describe('Method: removeKeys', () => { @@ -794,6 +798,7 @@ describe('Class: Logger', () => { }, }, })); + }); test('when called with non-existing keys, the logger\'s property persistentLogAttributes is not mutated and it does not throw an error', () => { @@ -825,6 +830,7 @@ describe('Class: Logger', () => { }, }, })); + }); test('when called multiple times with the same keys, the outcome is the same', () => { @@ -853,6 +859,7 @@ describe('Class: Logger', () => { }, }, })); + }); }); @@ -860,11 +867,10 @@ describe('Class: Logger', () => { describe('Method: injectLambdaContext', () => { beforeEach(() => { - // eslint-disable-next-line @typescript-eslint/no-empty-function - jest.spyOn(console, 'log').mockImplementation(() => { }); + jest.spyOn(console, 'log').mockImplementation(() => ({})); }); - test('when used as decorator, it returns a function with the correct scope of the decorated class', async () => { + test('it returns a decorated method with the correct scope of the decorated class', async () => { // Prepare @@ -875,7 +881,7 @@ describe('Class: Logger', () => { @logger.injectLambdaContext() // eslint-disable-next-line @typescript-eslint/ban-ts-comment // @ts-ignore - public handler(_event: TEvent, _context: Context, _callback: Callback): void | Promise { + public async handler(_event: TEvent, _context: Context): Promise { this.myClassMethod(); } @@ -884,9 +890,11 @@ describe('Class: Logger', () => { } } + const handlerClass = new LambdaFunction(); + const handler = handlerClass.handler.bind(handlerClass); // Act - await new LambdaFunction().handler(event, context, () => console.log('Lambda invoked!')); + await handler(event, context); // Assess expect(consoleSpy).toBeCalledTimes(1); @@ -905,7 +913,7 @@ describe('Class: Logger', () => { }); - test('when used as decorator, it returns a function that captures Lambda\'s context information and adds it in the printed logs', async () => { + test('it captures Lambda\'s context information and adds it in the printed logs', async () => { // Prepare const logger = new Logger(); @@ -915,14 +923,16 @@ describe('Class: Logger', () => { @logger.injectLambdaContext() // eslint-disable-next-line @typescript-eslint/ban-ts-comment // @ts-ignore - public handler(_event: TEvent, _context: Context, _callback: Callback): void | Promise { + public async handler(_event: TEvent, _context: Context): Promise { logger.info('This is an INFO log with some context'); } } + const handlerClass = new LambdaFunction(); + const handler = handlerClass.handler.bind(handlerClass); // Act logger.info('An INFO log without context!'); - await new LambdaFunction().handler(event, context, () => console.log('Lambda invoked!')); + await handler(event, context); // Assess @@ -949,7 +959,7 @@ describe('Class: Logger', () => { }); - test('when used as decorator on an async handler without context, it returns a function that captures Lambda\'s context information and adds it in the printed logs', async () => { + test('it captures Lambda\'s context information and adds it in the printed logs for async methods', async () => { // Prepare const expectedReturnValue = 'Lambda invoked!'; @@ -966,10 +976,12 @@ describe('Class: Logger', () => { return expectedReturnValue; } } + const handlerClass = new LambdaFunction(); + const handler = handlerClass.handler.bind(handlerClass); // Act logger.info('An INFO log without context!'); - const actualResult = await new LambdaFunction().handler(event, context); + const actualResult = await handler(event, context); // Assess @@ -997,7 +1009,7 @@ describe('Class: Logger', () => { }); - test('when used as decorator with the clear state flag enabled, the persistent log attributes added in the handler are removed after the handler\'s code is executed', async () => { + test('when clearState is enabled, the persistent log attributes added in the handler are cleared when the method returns', async () => { // Prepare const logger = new Logger({ @@ -1007,40 +1019,38 @@ describe('Class: Logger', () => { biz: 'baz' } }); - - type CustomEvent = { user_id: string }; - class LambdaFunction implements LambdaInterface { @logger.injectLambdaContext({ clearState: true }) // eslint-disable-next-line @typescript-eslint/ban-ts-comment // @ts-ignore - public handler(event: CustomEvent, _context: Context, _callback: Callback): void | Promise { + public async handler(_event: TEvent, _context: Context): Promise { // Only add these persistent for the scope of this lambda handler logger.appendKeys({ - details: { user_id: event['user_id'] } + details: { user_id: '1234' } }); logger.debug('This is a DEBUG log with the user_id'); logger.debug('This is another DEBUG log with the user_id'); } } - - const persistentAttribs = { ...logger.getPersistentLogAttributes() }; + const handlerClass = new LambdaFunction(); + const handler = handlerClass.handler.bind(handlerClass); + const persistentAttribsBeforeInvocation = { ...logger.getPersistentLogAttributes() }; // Act - await new LambdaFunction().handler({ user_id: '123456' }, context, () => console.log('Lambda invoked!')); + await handler(event, context); const persistentAttribsAfterInvocation = { ...logger.getPersistentLogAttributes() }; // Assess - expect(persistentAttribs).toEqual({ + expect(persistentAttribsBeforeInvocation).toEqual({ foo: 'bar', biz: 'baz' }); - expect(persistentAttribsAfterInvocation).toEqual(persistentAttribs); + expect(persistentAttribsAfterInvocation).toEqual(persistentAttribsBeforeInvocation); }); - test('when used as decorator with the clear state flag enabled and the handler throws an error, the persistent log attributes added in the handler are removed after the handler\'s code is executed', async () => { + test('when clearState is enabled, the persistent log attributes added in the handler are cleared when the method throws', async () => { // Prepare const logger = new Logger({ @@ -1050,18 +1060,15 @@ describe('Class: Logger', () => { biz: 'baz' } }); - - type CustomEvent = { user_id: string }; - class LambdaFunction implements LambdaInterface { @logger.injectLambdaContext({ clearState: true }) // eslint-disable-next-line @typescript-eslint/ban-ts-comment // @ts-ignore - public handler(event: CustomEvent, _context: Context, _callback: Callback): void | Promise { + public async handler(_event: TEvent, _context: Context): Promise { // Only add these persistent for the scope of this lambda handler logger.appendKeys({ - details: { user_id: event['user_id'] } + details: { user_id: '1234' } }); logger.debug('This is a DEBUG log with the user_id'); logger.debug('This is another DEBUG log with the user_id'); @@ -1069,45 +1076,42 @@ describe('Class: Logger', () => { throw new Error('Unexpected error occurred!'); } } - - const persistentAttribs = { ...logger.getPersistentLogAttributes() }; + const handlerClass = new LambdaFunction(); + const handler = handlerClass.handler.bind(handlerClass); + const persistentAttribsBeforeInvocation = { ...logger.getPersistentLogAttributes() }; // Act & Assess - const executeLambdaHandler = async (): Promise => { - await new LambdaFunction().handler({ user_id: '123456' }, context, () => console.log('Lambda invoked!')); - }; - await expect(executeLambdaHandler()).rejects.toThrow('Unexpected error occurred!'); + await expect(handler(event, context)).rejects.toThrow(); const persistentAttribsAfterInvocation = { ...logger.getPersistentLogAttributes() }; - expect(persistentAttribs).toEqual({ + expect(persistentAttribsBeforeInvocation).toEqual({ foo: 'bar', biz: 'baz' }); - expect(persistentAttribsAfterInvocation).toEqual(persistentAttribs); + expect(persistentAttribsAfterInvocation).toEqual(persistentAttribsBeforeInvocation); }); - test('when used as decorator with the log event flag enabled, it logs the event', async () => { + test('when logEvent is enabled, it logs the event in the first log', async () => { // Prepare const logger = new Logger({ logLevel: 'DEBUG', }); const consoleSpy = jest.spyOn(logger['console'], 'info').mockImplementation(); - - type CustomEvent = { user_id: string }; - class LambdaFunction implements LambdaInterface { @logger.injectLambdaContext({ logEvent: true }) // eslint-disable-next-line @typescript-eslint/ban-ts-comment // @ts-ignore - public handler(_event: CustomEvent, _context: Context, _callback: Callback): void | Promise { + public async handler(_event: TEvent, _context: Context): Promise { return; } } + const handlerClass = new LambdaFunction(); + const handler = handlerClass.handler.bind(handlerClass); // Act - await new LambdaFunction().handler({ user_id: '123456' }, context, () => console.log('Lambda invoked!')); + await handler(event, context); // Assess expect(consoleSpy).toBeCalledTimes(1); @@ -1123,13 +1127,15 @@ describe('Class: Logger', () => { timestamp: '2016-06-20T12:08:10.000Z', xray_trace_id: '1-5759e988-bd862e3fe1be46a994272793', event: { - user_id: '123456' + key1: 'value1', + key2: 'value2', + key3: 'value3' } })); }); - test('when used as decorator without options, but POWERTOOLS_LOGGER_LOG_EVENT env var is set to true, it logs the event', async () => { + test('when logEvent is enabled via POWERTOOLS_LOGGER_LOG_EVENT env var, it logs the event', async () => { // Prepare process.env.POWERTOOLS_LOGGER_LOG_EVENT = 'true'; @@ -1138,20 +1144,20 @@ describe('Class: Logger', () => { }); const consoleSpy = jest.spyOn(logger['console'], 'info').mockImplementation(); - type CustomEvent = { user_id: string }; - class LambdaFunction implements LambdaInterface { @logger.injectLambdaContext() // eslint-disable-next-line @typescript-eslint/ban-ts-comment // @ts-ignore - public handler(_event: CustomEvent, _context: Context, _callback: Callback): void | Promise { + public async handler(_event: TEvent, _context: Context): Promise { return; } } + const handlerClass = new LambdaFunction(); + const handler = handlerClass.handler.bind(handlerClass); // Act - await new LambdaFunction().handler({ user_id: '123456' }, context, () => console.log('Lambda invoked!')); + await handler(event, context); // Assess expect(consoleSpy).toBeCalledTimes(1); @@ -1167,13 +1173,15 @@ describe('Class: Logger', () => { timestamp: '2016-06-20T12:08:10.000Z', xray_trace_id: '1-5759e988-bd862e3fe1be46a994272793', event: { - user_id: '123456' + key1: 'value1', + key2: 'value2', + key3: 'value3' } })); }); - test('when used as decorator the value of `this` is preserved on the decorated method/class', async () => { + test('it preserves the value of `this` of the decorated method/class', async () => { // Prepare const logger = new Logger({ @@ -1191,7 +1199,7 @@ describe('Class: Logger', () => { @logger.injectLambdaContext() // eslint-disable-next-line @typescript-eslint/ban-ts-comment // @ts-ignore - public handler(_event: unknown, _context: Context, _callback: Callback): void | Promise { + public async handler(_event: TEvent, _context: Context): Promise { this.dummyMethod(); return; @@ -1201,11 +1209,11 @@ describe('Class: Logger', () => { logger.info({ message: `memberVariable:${this.memberVariable}` }); } } - - // Act const lambda = new LambdaFunction('someValue'); const handler = lambda.handler.bind(lambda); - await handler({}, context, () => console.log('Lambda invoked!')); + + // Act + await handler({}, context); // Assess expect(consoleSpy).toBeCalledTimes(1); @@ -1224,14 +1232,13 @@ describe('Class: Logger', () => { }); - test('when used as decorator on an async method, the method is awaited correctly', async () => { + test('it awaits the decorated method correctly', async () => { // Prepare - const injectLambdaContextAfterOrOnErrorMock = jest.fn().mockReturnValue('worked'); - // Temporarily override the cleanup static method so that we can "spy" on it. - // This method is always called after the handler has returned in the decorator - // implementation. - Logger.injectLambdaContextAfterOrOnError = injectLambdaContextAfterOrOnErrorMock; + const injectLambdaContextAfterOrOnErrorSpy = jest.spyOn( + Logger, + 'injectLambdaContextAfterOrOnError' + ); const logger = new Logger({ logLevel: 'DEBUG', }); @@ -1240,7 +1247,7 @@ describe('Class: Logger', () => { @logger.injectLambdaContext() // eslint-disable-next-line @typescript-eslint/ban-ts-comment // @ts-ignore - public async handler(_event: unknown, _context: Context, _callback: Callback): void | Promise { + public async handler(_event: unknown, _context: unknown): Promise { await this.dummyMethod(); logger.info('This is a DEBUG log'); @@ -1251,18 +1258,78 @@ describe('Class: Logger', () => { return; } } - - // Act const lambda = new LambdaFunction(); const handler = lambda.handler.bind(lambda); - await handler({}, context, () => console.log('Lambda invoked!')); + + // Act + await handler({}, context); // Assess expect(consoleSpy).toBeCalledTimes(1); - // Here we assert that the logger.info method is called before the cleanup function that should awlays - // be called after the handler has returned. If logger.info is called after it means the decorator is - // NOT awaiting the handler which would cause the test to fail. - expect(consoleSpy.mock.invocationCallOrder[0]).toBeLessThan(injectLambdaContextAfterOrOnErrorMock.mock.invocationCallOrder[0]); + // Here we assert that the logger.info method is called before the cleanup function that should always + // be called ONLY after the handler has returned. If logger.info is called after the cleanup function + // it means the decorator is NOT awaiting the handler which would cause the test to fail. + expect(consoleSpy.mock.invocationCallOrder[0]) + .toBeLessThan(injectLambdaContextAfterOrOnErrorSpy.mock.invocationCallOrder[0]); + + }); + + test('when logEvent and clearState are both TRUE, and the logger has persistent attributes, any key added in the handler is cleared properly', async () => { + + // Prepare + const logger = new Logger({ + persistentLogAttributes: { + version: '1.0.0', + } + }); + const consoleSpy = jest.spyOn(logger['console'], 'info').mockImplementation(); + class LambdaFunction implements LambdaInterface { + @logger.injectLambdaContext({ clearState: true, logEvent: true }) + // eslint-disable-next-line @typescript-eslint/ban-ts-comment + // @ts-ignore + public async handler(event: { foo: string }, _context: unknown): Promise { + logger.appendKeys({ foo: event.foo }); + + return; + } + } + const lambda = new LambdaFunction(); + const handler = lambda.handler.bind(lambda); + + // Act + await handler({ foo: 'bar' }, {} as Context); + await handler({ foo: 'baz' }, {} as Context); + await handler({ foo: 'biz' }, {} as Context); + await handler({ foo: 'buz' }, {} as Context); + await handler({ foo: 'boz' }, {} as Context); + + expect(consoleSpy).toBeCalledTimes(5); + for (let i = 1; i === 5; i++) { + expect(consoleSpy).toHaveBeenNthCalledWith( + i, + expect.stringContaining('\"message\":\"Lambda invocation event\"'), + ); + expect(consoleSpy).toHaveBeenNthCalledWith( + i, + expect.stringContaining('\"version\":\"1.0.0\"'), + ); + } + expect(consoleSpy).toHaveBeenNthCalledWith( + 2, + expect.not.stringContaining('\"foo\":\"bar\"') + ); + expect(consoleSpy).toHaveBeenNthCalledWith( + 3, + expect.not.stringContaining('\"foo\":\"baz\"') + ); + expect(consoleSpy).toHaveBeenNthCalledWith( + 4, + expect.not.stringContaining('\"foo\":\"biz\"') + ); + expect(consoleSpy).toHaveBeenNthCalledWith( + 5, + expect.not.stringContaining('\"foo\":\"buz\"') + ); }); @@ -1270,7 +1337,7 @@ describe('Class: Logger', () => { describe('Method: refreshSampleRateCalculation', () => { - test('when called, it recalculates whether the current Lambda invocation\'s logs will be printed or not', () => { + test('it recalculates whether the current Lambda invocation\'s logs will be printed or not', () => { // Prepare const logger = new Logger({ @@ -1297,12 +1364,12 @@ describe('Class: Logger', () => { describe('Method: createChild', () => { - test('Child and grandchild loggers should have all ancestor\'s options', () => { + test('child and grandchild loggers should have all ancestor\'s options', () => { // Prepare const INDENTATION = LogJsonIndent.COMPACT; const loggerOptions = { serviceName: 'parent-service-name', - sampleRateValue: 0.01, + sampleRateValue: 0, }; const parentLogger = new Logger(loggerOptions); @@ -1339,7 +1406,7 @@ describe('Class: Logger', () => { powertoolLogData: { awsRegion: 'eu-west-1', environment: '', - sampleRateValue: 0.01, + sampleRateValue: undefined, serviceName: 'parent-service-name', }, }); @@ -1398,7 +1465,7 @@ describe('Class: Logger', () => { }); - test('when called, it returns a DISTINCT clone of the logger instance', () => { + test('child logger should be a DISTINCT clone of the logger instance', () => { // Prepare const INDENTATION = LogJsonIndent.COMPACT; @@ -1419,7 +1486,7 @@ describe('Class: Logger', () => { }; const childLoggerWithSampleRateEnabled = parentLogger.createChild(optionsWithSampleRateEnabled); - const optionsWithErrorLogLevel = { + const optionsWithErrorLogLevel: ConstructorOptions = { logLevel: 'ERROR', }; const childLoggerWithErrorLogLevel = parentLogger.createChild(optionsWithErrorLogLevel); @@ -1655,22 +1722,8 @@ describe('Class: Logger', () => { serviceName: 'hello-world', }, }); - }); - const context = { - callbackWaitsForEmptyEventLoop: true, - functionVersion: '$LATEST', - functionName: 'foo-bar-function-with-cold-start', - memoryLimitInMB: '128', - logGroupName: '/aws/lambda/foo-bar-function-with-cold-start', - logStreamName: '2021/03/09/[$LATEST]1-5759e988-bd862e3fe1be46a994272793', - invokedFunctionArn: 'arn:aws:lambda:eu-west-1:123456789012:function:foo-bar-function-with-cold-start', - awsRequestId: 'c6af9ac6-7b61-11e6-9a41-93e812345678', - getRemainingTimeInMillis: () => 1234, - done: () => console.log('Done!'), - fail: () => console.log('Failed!'), - succeed: () => console.log('Succeeded!'), - }; + }); test('child logger should have parent\'s context in PowertoolLogData', () => { @@ -1706,15 +1759,106 @@ describe('Class: Logger', () => { lambdaContext: { awsRequestId: 'c6af9ac6-7b61-11e6-9a41-93e812345678', coldStart: true, - functionName: 'foo-bar-function-with-cold-start', + functionName: 'foo-bar-function', functionVersion: '$LATEST', - invokedFunctionArn: 'arn:aws:lambda:eu-west-1:123456789012:function:foo-bar-function-with-cold-start', + invokedFunctionArn: 'arn:aws:lambda:eu-west-1:123456789012:function:foo-bar-function', memoryLimitInMB: 128, }, sampleRateValue: undefined, serviceName: 'hello-world', }, }); + + }); + + test('child logger should have parent\'s logFormatter', () => { + + // Prepare + class MyCustomLogFormatter extends PowertoolLogFormatter {} + const parentLogger = new Logger({ + logFormatter: new MyCustomLogFormatter() + }); + + // Act + const childLoggerWithParentLogFormatter = parentLogger.createChild(); + + // Assess + expect(childLoggerWithParentLogFormatter).toEqual( + expect.objectContaining({ + logFormatter: expect.any(MyCustomLogFormatter), + }) + ); + + }); + + test('child logger with custom logFormatter in options should have provided logFormatter', () => { + + // Prepare + class MyCustomLogFormatter extends PowertoolLogFormatter {} + const parentLogger = new Logger(); + + // Act + const childLoggerWithCustomLogFormatter = parentLogger.createChild({ + logFormatter: new MyCustomLogFormatter() + }); + + // Assess + expect(parentLogger).toEqual( + expect.objectContaining({ + logFormatter: expect.any(PowertoolLogFormatter), + }) + ); + + expect(childLoggerWithCustomLogFormatter).toEqual( + expect.objectContaining({ + logFormatter: expect.any(MyCustomLogFormatter), + }) + ); + + }); + + test('child logger should have exact same attributes as the parent logger created with all non-default options', () => { + + // Prepare + class MyCustomLogFormatter extends PowertoolLogFormatter {} + class MyCustomEnvironmentVariablesService extends EnvironmentVariablesService {} + + const options: ConstructorOptions = { + logLevel: 'ERROR', + serviceName: 'test-service-name', + sampleRateValue: 0.77, + logFormatter: new MyCustomLogFormatter(), + customConfigService: new MyCustomEnvironmentVariablesService(), + persistentLogAttributes: { + aws_account_id: '1234567890', + aws_region: 'eu-west-1', + }, + environment: 'local' + }; + const parentLogger = new Logger(options); + + // Act + const childLogger = parentLogger.createChild(); + + // Assess + expect(childLogger).toEqual({ + ...parentLogger, + console: expect.any(Console), + logsSampled: expect.any(Boolean), + }); + + expect(childLogger).toEqual( + expect.objectContaining({ + logFormatter: expect.any(MyCustomLogFormatter), + }) + ); + + expect(childLogger).toEqual( + expect.objectContaining({ + customConfigService: expect.any(MyCustomEnvironmentVariablesService), + }) + ); + }); }); @@ -1731,8 +1875,8 @@ describe('Class: Logger', () => { logger.logEventIfEnabled(event); // Assess - expect(consoleSpy).toBeCalledTimes(0); + }); test('When the feature is enabled via overwrite flag, it DOES log the event', () => { @@ -1760,6 +1904,7 @@ describe('Class: Logger', () => { } }, )); + }); }); @@ -1785,6 +1930,7 @@ describe('Class: Logger', () => { timestamp: '2016-06-20T12:08:10.000Z', xray_trace_id: '1-5759e988-bd862e3fe1be46a994272793', }, null, INDENTATION)); + }); test('when the `POWERTOOLS_DEV` env var is NOT SET it makes log output as one-liner', () => { @@ -1805,7 +1951,9 @@ describe('Class: Logger', () => { timestamp: '2016-06-20T12:08:10.000Z', xray_trace_id: '1-5759e988-bd862e3fe1be46a994272793', })); + }); + }); describe('Method: setConsole()', () => { @@ -1828,7 +1976,9 @@ describe('Class: Logger', () => { ...logger, console: console, }); + }); + }); }); diff --git a/packages/logger/tests/unit/config/EnvironmentVariablesService.test.ts b/packages/logger/tests/unit/config/EnvironmentVariablesService.test.ts index b9aa387614..637c9ca615 100644 --- a/packages/logger/tests/unit/config/EnvironmentVariablesService.test.ts +++ b/packages/logger/tests/unit/config/EnvironmentVariablesService.test.ts @@ -3,7 +3,6 @@ * * @group unit/logger/all */ - import { EnvironmentVariablesService } from '../../../src/config'; describe('Class: EnvironmentVariablesService', () => { @@ -21,7 +20,7 @@ describe('Class: EnvironmentVariablesService', () => { describe('Method: getAwsRegion', () => { - test('It returns the value of the environment variable AWS_REGION', () => { + test('it returns the value of the environment variable AWS_REGION', () => { // Prepare process.env.AWS_REGION = 'us-east-1'; @@ -32,13 +31,14 @@ describe('Class: EnvironmentVariablesService', () => { // Assess expect(value).toEqual('us-east-1'); + }); }); describe('Method: getCurrentEnvironment', () => { - test('It returns the value of the environment variable AWS_REGION', () => { + test('it returns the value of the environment variable AWS_REGION', () => { // Prepare process.env.ENVIRONMENT = 'stage'; @@ -55,7 +55,7 @@ describe('Class: EnvironmentVariablesService', () => { describe('Method: getFunctionMemory', () => { - test('It returns the value of the environment variable AWS_LAMBDA_FUNCTION_MEMORY_SIZE', () => { + test('it returns the value of the environment variable AWS_LAMBDA_FUNCTION_MEMORY_SIZE', () => { // Prepare process.env.AWS_LAMBDA_FUNCTION_MEMORY_SIZE = '123456'; @@ -66,13 +66,14 @@ describe('Class: EnvironmentVariablesService', () => { // Assess expect(value).toBe(123456); + }); }); describe('Method: getFunctionName', () => { - test('It returns the value of the environment variable AWS_LAMBDA_FUNCTION_NAME', () => { + test('it returns the value of the environment variable AWS_LAMBDA_FUNCTION_NAME', () => { // Prepare process.env.AWS_LAMBDA_FUNCTION_NAME = 'my-lambda-function'; @@ -83,13 +84,14 @@ describe('Class: EnvironmentVariablesService', () => { // Assess expect(value).toEqual('my-lambda-function'); + }); }); describe('Method: getFunctionVersion', () => { - test('It returns the value of the environment variable AWS_LAMBDA_FUNCTION_VERSION', () => { + test('it returns the value of the environment variable AWS_LAMBDA_FUNCTION_VERSION', () => { // Prepare process.env.AWS_LAMBDA_FUNCTION_VERSION = '1.4.0'; @@ -100,13 +102,14 @@ describe('Class: EnvironmentVariablesService', () => { // Assess expect(value).toEqual('1.4.0'); + }); }); describe('Method: getLogEvent', () => { - test('It returns true if the environment variable POWERTOOLS_LOGGER_LOG_EVENT is "true"', () => { + test('it returns true if the environment variable POWERTOOLS_LOGGER_LOG_EVENT is "true"', () => { // Prepare process.env.POWERTOOLS_LOGGER_LOG_EVENT = 'true'; @@ -117,9 +120,10 @@ describe('Class: EnvironmentVariablesService', () => { // Assess expect(value).toEqual(true); + }); - test('It returns false if the environment variable POWERTOOLS_LOGGER_LOG_EVENT is "false"', () => { + test('it returns false if the environment variable POWERTOOLS_LOGGER_LOG_EVENT is "false"', () => { // Prepare process.env.POWERTOOLS_LOGGER_LOG_EVENT = 'false'; @@ -130,9 +134,10 @@ describe('Class: EnvironmentVariablesService', () => { // Assess expect(value).toEqual(false); + }); - test('It returns false if the environment variable POWERTOOLS_LOGGER_LOG_EVENT is "somethingsilly"', () => { + test('it returns false if the environment variable POWERTOOLS_LOGGER_LOG_EVENT is "somethingsilly"', () => { // Prepare process.env.POWERTOOLS_LOGGER_LOG_EVENT = 'somethingsilly'; @@ -143,13 +148,14 @@ describe('Class: EnvironmentVariablesService', () => { // Assess expect(value).toEqual(false); + }); }); describe('Method: getLogLevel', () => { - test('It returns the value of the environment variable LOG_LEVEL', () => { + test('it returns the value of the environment variable LOG_LEVEL', () => { // Prepare process.env.LOG_LEVEL = 'ERROR'; @@ -160,13 +166,14 @@ describe('Class: EnvironmentVariablesService', () => { // Assess expect(value).toEqual('ERROR'); + }); }); describe('Method: getSampleRateValue', () => { - test('It returns the value of the environment variable POWERTOOLS_LOGGER_SAMPLE_RATE', () => { + test('it returns the value of the environment variable POWERTOOLS_LOGGER_SAMPLE_RATE', () => { // Prepare process.env.POWERTOOLS_LOGGER_SAMPLE_RATE = '0.01'; @@ -177,13 +184,14 @@ describe('Class: EnvironmentVariablesService', () => { // Assess expect(value).toEqual(0.01); + }); }); describe('Method: isDevMode', () => { - test('It returns true if the environment variable POWERTOOLS_DEV is "true"', () => { + test('it returns true if the environment variable POWERTOOLS_DEV is "true"', () => { // Prepare process.env.POWERTOOLS_DEV = 'true'; @@ -194,9 +202,10 @@ describe('Class: EnvironmentVariablesService', () => { // Assess expect(value).toEqual(true); + }); - test('It returns false if the environment variable POWERTOOLS_DEV is "false"', () => { + test('it returns false if the environment variable POWERTOOLS_DEV is "false"', () => { // Prepare process.env.POWERTOOLS_DEV = 'false'; @@ -207,9 +216,10 @@ describe('Class: EnvironmentVariablesService', () => { // Assess expect(value).toEqual(false); + }); - test('It returns false if the environment variable POWERTOOLS_DEV is NOT set', () => { + test('it returns false if the environment variable POWERTOOLS_DEV is NOT set', () => { // Prepare process.env.POWERTOOLS_DEV = 'somethingsilly'; @@ -220,9 +230,10 @@ describe('Class: EnvironmentVariablesService', () => { // Assess expect(value).toEqual(false); + }); - test('It returns false if the environment variable POWERTOOLS_DEV is "somethingsilly"', () => { + test('it returns false if the environment variable POWERTOOLS_DEV is "somethingsilly"', () => { // Prepare process.env.POWERTOOLS_DEV = 'somethingsilly'; @@ -233,6 +244,7 @@ describe('Class: EnvironmentVariablesService', () => { // Assess expect(value).toEqual(false); + }); }); @@ -253,7 +265,7 @@ describe('Class: EnvironmentVariablesService', () => { [ '0', false ] ]; - test.each(valuesToTest)('It takes string "%s" and returns %s', (input, output) => { + test.each(valuesToTest)('it takes string "%s" and returns %s', (input, output) => { // Prepare const service = new EnvironmentVariablesService(); // Act diff --git a/packages/logger/tests/unit/formatter/PowertoolLogFormatter.test.ts b/packages/logger/tests/unit/formatter/PowertoolLogFormatter.test.ts index 8b7f52a82e..1aff6d111a 100644 --- a/packages/logger/tests/unit/formatter/PowertoolLogFormatter.test.ts +++ b/packages/logger/tests/unit/formatter/PowertoolLogFormatter.test.ts @@ -3,7 +3,6 @@ * * @group unit/logger/all */ - import { AssertionError, strictEqual } from 'assert'; import { PowertoolLogFormatter } from '../../../src/formatter'; import { UnformattedAttributes } from '../../../src/types'; @@ -19,11 +18,11 @@ describe('Class: PowertoolLogFormatter', () => { describe('Method: formatAttributes', () => { - test('When optional parameters DO NOT have a value set, it returns an object with expected structure and values', () => { + test('when optional parameters DO NOT have a value set, it returns an object with expected structure and values', () => { // Prepare const formatter = new PowertoolLogFormatter(); - const unformattedAttributes = { + const unformattedAttributes: UnformattedAttributes = { sampleRateValue: undefined, awsRegion: 'eu-west-1', environment: '', @@ -51,9 +50,10 @@ describe('Class: PowertoolLogFormatter', () => { timestamp: '2016-06-20T12:08:10.000Z', xray_trace_id: '1-5759e988-bd862e3fe1be46a994272793', }); + }); - test('When optional parameters DO have a value set, it returns an object with expected structure and values', () => { + test('when optional parameters DO have a value set, it returns an object with expected structure and values', () => { // Prepare const formatter = new PowertoolLogFormatter(); @@ -94,19 +94,18 @@ describe('Class: PowertoolLogFormatter', () => { timestamp: '2016-06-20T12:08:10.000Z', xray_trace_id: '1-5759e988-bd862e3fe1be46a994272793', }); + }); }); describe('Method: formatError', () => { - test('When an error of type Error is passed, it returns an object with expected structure and values', () => { + test('when an error of type Error is passed, it returns an object with expected structure and values', () => { // Prepare const formatter = new PowertoolLogFormatter(); const shouldThrow = (): void => { - // eslint-disable-next-line @typescript-eslint/ban-ts-comment - // @ts-ignore throw new Error('Ouch!'); }; @@ -126,13 +125,15 @@ describe('Class: PowertoolLogFormatter', () => { } expect(shouldThrow).toThrowError(expect.any(Error)); + }); - test('When an error of type ReferenceError is passed, it returns an object with expected structure and values', () => { + test('when an error of type ReferenceError is passed, it returns an object with expected structure and values', () => { // Prepare const formatter = new PowertoolLogFormatter(); const shouldThrow = (): void => { + // This is a reference error purposely to test the formatter // eslint-disable-next-line @typescript-eslint/ban-ts-comment // @ts-ignore doesNotExist; @@ -157,13 +158,11 @@ describe('Class: PowertoolLogFormatter', () => { }); - test('When an error of type AssertionError is passed, it returns an object with expected structure and values', () => { + test('when an error of type AssertionError is passed, it returns an object with expected structure and values', () => { // Prepare const formatter = new PowertoolLogFormatter(); const shouldThrow = (): void => { - // eslint-disable-next-line @typescript-eslint/ban-ts-comment - // @ts-ignore strictEqual(1, 2); }; @@ -186,13 +185,11 @@ describe('Class: PowertoolLogFormatter', () => { }); - test('When an error of type RangeError is passed, it returns an object with expected structure and values', () => { + test('when an error of type RangeError is passed, it returns an object with expected structure and values', () => { // Prepare const formatter = new PowertoolLogFormatter(); const shouldThrow = (): void => { - // eslint-disable-next-line @typescript-eslint/ban-ts-comment - // @ts-ignore throw new RangeError('The argument must be between 10 and 20'); }; @@ -214,13 +211,11 @@ describe('Class: PowertoolLogFormatter', () => { expect(shouldThrow).toThrowError(expect.any(RangeError)); }); - test('When an error of type SyntaxError is passed, it returns an object with expected structure and values', () => { + test('when an error of type SyntaxError is passed, it returns an object with expected structure and values', () => { // Prepare const formatter = new PowertoolLogFormatter(); const shouldThrow = (): void => { - // eslint-disable-next-line @typescript-eslint/ban-ts-comment - // @ts-ignore eval('foo bar'); }; @@ -243,11 +238,12 @@ describe('Class: PowertoolLogFormatter', () => { }); - test('When an error of type TypeError is passed, it returns an object with expected structure and values', () => { + test('when an error of type TypeError is passed, it returns an object with expected structure and values', () => { // Prepare const formatter = new PowertoolLogFormatter(); const shouldThrow = (): void => { + // This is a reference error purposely to test the formatter // eslint-disable-next-line @typescript-eslint/ban-ts-comment // @ts-ignore null.foo(); @@ -270,15 +266,14 @@ describe('Class: PowertoolLogFormatter', () => { } expect(shouldThrow).toThrowError(expect.any(TypeError)); + }); - test('When an error of type URIError is passed, it returns an object with expected structure and values', () => { + test('when an error of type URIError is passed, it returns an object with expected structure and values', () => { // Prepare const formatter = new PowertoolLogFormatter(); const shouldThrow = (): void => { - // eslint-disable-next-line @typescript-eslint/ban-ts-comment - // @ts-ignore decodeURIComponent('%'); }; @@ -298,13 +293,14 @@ describe('Class: PowertoolLogFormatter', () => { } expect(shouldThrow).toThrowError(expect.any(URIError)); + }); }); describe('Method: formatTimestamp', () => { - test('It returns a datetime value ISO 8601 compliant', () => { + test('it returns a datetime value ISO 8601 compliant', () => { // Prepare const formatter = new PowertoolLogFormatter(); @@ -314,13 +310,14 @@ describe('Class: PowertoolLogFormatter', () => { // Assess expect(timestamp).toEqual('2016-06-20T12:08:10.000Z'); + }); }); describe('Method: getCodeLocation', () => { - test('When the stack IS present, it returns a datetime value ISO 8601 compliant', () => { + test('when the stack IS present, it returns a datetime value ISO 8601 compliant', () => { // Prepare const formatter = new PowertoolLogFormatter(); @@ -333,9 +330,10 @@ describe('Class: PowertoolLogFormatter', () => { // Assess expect(errorLocation).toEqual('/home/foo/bar/some-file.ts:154'); + }); - test('When the stack IS NOT present, it returns a datetime value ISO 8601 compliant', () => { + test('when the stack IS NOT present, it returns a datetime value ISO 8601 compliant', () => { // Prepare const formatter = new PowertoolLogFormatter(); @@ -346,9 +344,10 @@ describe('Class: PowertoolLogFormatter', () => { // Assess expect(errorLocation).toEqual(''); + }); - test('When the stack IS NOT present, it returns a datetime value ISO 8601 compliant', () => { + test('when the stack IS NOT present, it returns a datetime value ISO 8601 compliant', () => { // Prepare const formatter = new PowertoolLogFormatter(); @@ -359,6 +358,7 @@ describe('Class: PowertoolLogFormatter', () => { // Assess expect(errorLocation).toEqual(''); + }); }); diff --git a/packages/logger/tests/unit/helpers.test.ts b/packages/logger/tests/unit/helpers.test.ts index 4f953620fc..31842614fb 100644 --- a/packages/logger/tests/unit/helpers.test.ts +++ b/packages/logger/tests/unit/helpers.test.ts @@ -3,7 +3,6 @@ * * @group unit/logger/all */ - import { Console } from 'console'; import { ConfigServiceInterface, EnvironmentVariablesService } from '../../src/config'; import { LogFormatter, PowertoolLogFormatter } from '../../src/formatter'; @@ -56,7 +55,7 @@ describe('Helper: createLogger function', () => { test('when no parameters are set, returns a Logger instance with the correct properties', () => { // Prepare - const loggerOptions = { + const loggerOptions: ConstructorOptions = { logLevel: 'WARN', serviceName: 'my-lambda-service', sampleRateValue: 1, @@ -197,12 +196,13 @@ describe('Helper: createLogger function', () => { logLevel: 'DEBUG', logFormatter: {}, })); + }); - test('when a custom logLevel is passed, returns a Logger instance with the correct properties', () => { + test('when a custom uppercase logLevel is passed, returns a Logger instance with the correct properties', () => { // Prepare - const loggerOptions:ConstructorOptions = { + const loggerOptions: ConstructorOptions = { logLevel: 'ERROR', }; @@ -225,6 +225,36 @@ describe('Helper: createLogger function', () => { logLevel: 'ERROR', logFormatter: expect.any(PowertoolLogFormatter), })); + + }); + + test('when a custom lowercase logLevel is passed, returns a Logger instance with the correct properties', () => { + + // Prepare + const loggerOptions: ConstructorOptions = { + logLevel: 'warn', + }; + + // Act + const logger = createLogger(loggerOptions); + + // Assess + expect(logger).toBeInstanceOf(Logger); + expect(logger).toEqual(expect.objectContaining({ + logsSampled: false, + persistentLogAttributes: {}, + powertoolLogData: { + sampleRateValue: undefined, + awsRegion: 'eu-west-1', + environment: '', + serviceName: 'hello-world', + }, + envVarsService: expect.any(EnvironmentVariablesService), + customConfigService: undefined, + logLevel: 'WARN', + logFormatter: expect.any(PowertoolLogFormatter), + })); + }); test('when no log level is set, returns a Logger instance with INFO level', () => { @@ -263,6 +293,7 @@ describe('Helper: createLogger function', () => { serviceName: 'hello-world', }, }); + }); test('when a custom sampleRateValue is passed, returns a Logger instance with the correct properties', () => { @@ -291,6 +322,7 @@ describe('Helper: createLogger function', () => { logLevel: 'DEBUG', logFormatter: {}, })); + }); test('when a custom customConfigService is passed, returns a Logger instance with the correct properties', () => { @@ -346,6 +378,7 @@ describe('Helper: createLogger function', () => { logLevel: 'INFO', logFormatter: {}, })); + }); test('when custom persistentLogAttributes is passed, returns a Logger instance with the correct properties', () => { @@ -388,6 +421,7 @@ describe('Helper: createLogger function', () => { logLevel: 'DEBUG', logFormatter: {}, })); + }); test('when a custom environment is passed, returns a Logger instance with the correct properties', () => { @@ -416,7 +450,9 @@ describe('Helper: createLogger function', () => { logLevel: 'DEBUG', logFormatter: {}, })); + }); + }); }); \ No newline at end of file diff --git a/packages/logger/tests/unit/middleware/middy.test.ts b/packages/logger/tests/unit/middleware/middy.test.ts index fff1960b1b..c12680a1c5 100644 --- a/packages/logger/tests/unit/middleware/middy.test.ts +++ b/packages/logger/tests/unit/middleware/middy.test.ts @@ -4,12 +4,14 @@ * @group unit/logger/all */ +import { ContextExamples as dummyContext, Events as dummyEvent } from '@aws-lambda-powertools/commons'; import { ConfigServiceInterface, EnvironmentVariablesService } from '../../../src/config'; import { injectLambdaContext } from '../../../src/middleware/middy'; import { Logger } from './../../../src'; import middy from '@middy/core'; import { PowertoolLogFormatter } from '../../../src/formatter'; import { Console } from 'console'; +import { Context } from 'aws-lambda'; const mockDate = new Date(1466424490000); const dateSpy = jest.spyOn(global, 'Date').mockImplementation(() => mockDate); @@ -17,6 +19,8 @@ const dateSpy = jest.spyOn(global, 'Date').mockImplementation(() => mockDate); describe('Middy middleware', () => { const ENVIRONMENT_VARIABLES = process.env; + const context = dummyContext.helloworldContext; + const event = dummyEvent.Custom.CustomEvent; beforeEach(() => { jest.resetModules(); @@ -37,31 +41,12 @@ describe('Middy middleware', () => { // Prepare const logger = new Logger(); - const lambdaHandler = (): void => { + const handler = middy((): void => { logger.info('This is an INFO log with some context'); - }; - const handler = middy(lambdaHandler).use(injectLambdaContext(logger)); - const event = { foo: 'bar' }; - const getRandomInt = (): number => Math.floor(Math.random() * 1000000000); - - const awsRequestId = getRandomInt().toString(); - const context = { - callbackWaitsForEmptyEventLoop: true, - functionVersion: '$LATEST', - functionName: 'foo-bar-function', - memoryLimitInMB: '128', - logGroupName: '/aws/lambda/foo-bar-function', - logStreamName: '2021/03/09/[$LATEST]abcdef123456abcdef123456abcdef123456', - invokedFunctionArn: 'arn:aws:lambda:eu-west-1:123456789012:function:foo-bar-function', - awsRequestId: awsRequestId, - getRemainingTimeInMillis: () => 1234, - done: () => console.log('Done!'), - fail: () => console.log('Failed!'), - succeed: () => console.log('Succeeded!'), - }; + }).use(injectLambdaContext(logger)); // Act - await handler(event, context, () => console.log('Lambda invoked!')); + await handler(event, context); // Assess expect(logger).toEqual(expect.objectContaining({ @@ -72,7 +57,7 @@ describe('Middy middleware', () => { awsRegion: 'eu-west-1', environment: '', lambdaContext: { - awsRequestId: awsRequestId, + awsRequestId: 'c6af9ac6-7b61-11e6-9a41-93e812345678', coldStart: true, functionName: 'foo-bar-function', functionVersion: '$LATEST', @@ -94,34 +79,13 @@ describe('Middy middleware', () => { // Prepare const logger = new Logger(); const anotherLogger = new Logger(); - const lambdaHandler = (): void => { + const handler = middy((): void => { logger.info('This is an INFO log with some context'); anotherLogger.info('This is an INFO log with some context'); - }; - const handler = middy(lambdaHandler).use(injectLambdaContext([ logger, anotherLogger ])); - const event = { foo: 'bar' }; - - const getRandomInt = (): number => Math.floor(Math.random() * 1000000000); - - const awsRequestId = getRandomInt().toString(); - - const context = { - callbackWaitsForEmptyEventLoop: true, - functionVersion: '$LATEST', - functionName: 'foo-bar-function', - memoryLimitInMB: '128', - logGroupName: '/aws/lambda/foo-bar-function', - logStreamName: '2021/03/09/[$LATEST]abcdef123456abcdef123456abcdef123456', - invokedFunctionArn: 'arn:aws:lambda:eu-west-1:123456789012:function:foo-bar-function', - awsRequestId: awsRequestId, - getRemainingTimeInMillis: () => 1234, - done: () => console.log('Done!'), - fail: () => console.log('Failed!'), - succeed: () => console.log('Succeeded!'), - }; + }).use(injectLambdaContext([ logger, anotherLogger ])); // Act - await handler(event, context, () => console.log('Lambda invoked!')); + await handler(event, context); // Assess const expectation = expect.objectContaining({ @@ -132,7 +96,7 @@ describe('Middy middleware', () => { awsRegion: 'eu-west-1', environment: '', lambdaContext: { - awsRequestId: awsRequestId, + awsRequestId: 'c6af9ac6-7b61-11e6-9a41-93e812345678', coldStart: true, functionName: 'foo-bar-function', functionVersion: '$LATEST', @@ -168,46 +132,31 @@ describe('Middy middleware', () => { biz: 'baz' } }); - const context = { - callbackWaitsForEmptyEventLoop: true, - functionVersion: '$LATEST', - functionName: 'foo-bar-function', - memoryLimitInMB: '128', - logGroupName: '/aws/lambda/foo-bar-function', - logStreamName: '2021/03/09/[$LATEST]abcdef123456abcdef123456abcdef123456', - invokedFunctionArn: 'arn:aws:lambda:eu-west-1:123456789012:function:foo-bar-function', - awsRequestId: 'abcdef123456abcdef123456', - getRemainingTimeInMillis: () => 1234, - done: () => console.log('Done!'), - fail: () => console.log('Failed!'), - succeed: () => console.log('Succeeded!'), - }; - const lambdaHandler = (event: { user_id: string }): void => { + const handler = middy((): void => { // Only add these persistent for the scope of this lambda handler logger.appendKeys({ - details: { user_id: event['user_id'] } + details: { user_id: '1234' } }); logger.debug('This is a DEBUG log with the user_id'); logger.debug('This is another DEBUG log with the user_id'); - }; - const handler = middy(lambdaHandler).use(injectLambdaContext(logger, { clearState: true })); - const persistentAttribs = { ...logger.getPersistentLogAttributes() }; - + }).use(injectLambdaContext(logger, { clearState: true })); + const persistentAttribsBeforeInvocation = { ...logger.getPersistentLogAttributes() }; + // Act - await handler({ user_id: '123456' }, context, () => console.log('Lambda invoked!')); - const persistentAttribsAfterInvocation = { ...logger.getPersistentLogAttributes() }; - + await handler(event, context); + // Assess - expect(persistentAttribs).toEqual({ + const persistentAttribsAfterInvocation = { ...logger.getPersistentLogAttributes() }; + expect(persistentAttribsBeforeInvocation).toEqual({ foo: 'bar', biz: 'baz' }); - expect(persistentAttribsAfterInvocation).toEqual(persistentAttribs); + expect(persistentAttribsAfterInvocation).toEqual(persistentAttribsBeforeInvocation); }); - test('when enabled and the handler throws an error, the persistent log attributes added within the handler scope are removed after the invocation ends', async () => { + test('when enabled, the persistent log attributes added within the handler scope are removed after the invocation ends even if an error is thrown', async () => { // Prepare const logger = new Logger({ @@ -217,46 +166,27 @@ describe('Middy middleware', () => { biz: 'baz' } }); - const context = { - callbackWaitsForEmptyEventLoop: true, - functionVersion: '$LATEST', - functionName: 'foo-bar-function', - memoryLimitInMB: '128', - logGroupName: '/aws/lambda/foo-bar-function', - logStreamName: '2021/03/09/[$LATEST]abcdef123456abcdef123456abcdef123456', - invokedFunctionArn: 'arn:aws:lambda:eu-west-1:123456789012:function:foo-bar-function', - awsRequestId: 'abcdef123456abcdef123456', - getRemainingTimeInMillis: () => 1234, - done: () => console.log('Done!'), - fail: () => console.log('Failed!'), - succeed: () => console.log('Succeeded!'), - }; - - const lambdaHandler = (event: { user_id: string }): void => { + const handler = middy((): void => { // Only add these persistent for the scope of this lambda handler logger.appendKeys({ - details: { user_id: event['user_id'] } + details: { user_id: '1234' } }); logger.debug('This is a DEBUG log with the user_id'); logger.debug('This is another DEBUG log with the user_id'); throw new Error('Unexpected error occurred!'); - }; - - const persistentAttribs = { ...logger.getPersistentLogAttributes() }; - const handler = middy(lambdaHandler).use(injectLambdaContext(logger, { clearState: true })); - + }).use(injectLambdaContext(logger, { clearState: true })); + const persistentAttribsBeforeInvocation = { ...logger.getPersistentLogAttributes() }; + // Act & Assess - const executeLambdaHandler = async (): Promise => { - await handler({ user_id: '123456' }, context, () => console.log('Lambda invoked!')); - }; - await expect(executeLambdaHandler()).rejects.toThrow('Unexpected error occurred!'); + await expect(handler(event, context)) + .rejects.toThrow(); const persistentAttribsAfterInvocation = { ...logger.getPersistentLogAttributes() }; - expect(persistentAttribs).toEqual({ + expect(persistentAttribsBeforeInvocation).toEqual({ foo: 'bar', biz: 'baz' }); - expect(persistentAttribsAfterInvocation).toEqual(persistentAttribs); + expect(persistentAttribsAfterInvocation).toEqual(persistentAttribsBeforeInvocation); }); @@ -264,35 +194,17 @@ describe('Middy middleware', () => { describe('Feature: log event', () => { - test('when a logger is passed with option logEvent set to true, it logs the event', async () => { + test('when enabled, it logs the event', async () => { // Prepare const logger = new Logger(); const consoleSpy = jest.spyOn(logger['console'], 'info').mockImplementation(); - const lambdaHandler = (): void => { + const handler = middy((): void => { logger.info('This is an INFO log with some context'); - }; - const handler = middy(lambdaHandler).use(injectLambdaContext(logger , { logEvent: true })); - const event = { foo: 'bar' }; - const getRandomInt = (): number => Math.floor(Math.random() * 1000000000); - const awsRequestId = getRandomInt().toString(); - const context = { - callbackWaitsForEmptyEventLoop: true, - functionVersion: '$LATEST', - functionName: 'foo-bar-function', - memoryLimitInMB: '128', - logGroupName: '/aws/lambda/foo-bar-function', - logStreamName: '2021/03/09/[$LATEST]abcdef123456abcdef123456abcdef123456', - invokedFunctionArn: 'arn:aws:lambda:eu-west-1:123456789012:function:foo-bar-function', - awsRequestId: awsRequestId, - getRemainingTimeInMillis: () => 1234, - done: () => console.log('Done!'), - fail: () => console.log('Failed!'), - succeed: () => console.log('Succeeded!'), - }; + }).use(injectLambdaContext(logger , { logEvent: true })); // Act - await handler(event, context, () => console.log('Lambda invoked!')); + await handler(event, context); // Assess expect(consoleSpy).toBeCalledTimes(2); @@ -301,20 +213,22 @@ describe('Middy middleware', () => { function_arn: 'arn:aws:lambda:eu-west-1:123456789012:function:foo-bar-function', function_memory_size: 128, function_name: 'foo-bar-function', - function_request_id: awsRequestId, + function_request_id: 'c6af9ac6-7b61-11e6-9a41-93e812345678', level: 'INFO', message: 'Lambda invocation event', service: 'hello-world', timestamp: '2016-06-20T12:08:10.000Z', xray_trace_id: '1-5759e988-bd862e3fe1be46a994272793', event: { - foo: 'bar' + key1: 'value1', + key2: 'value2', + key3: 'value3', } })); }); - test('when a logger is passed with option logEvent set to true, while also having a custom configService, it logs the event', async () => { + test('when enabled, while also having a custom configService, it logs the event', async () => { // Prepare const configService: ConfigServiceInterface = { @@ -348,30 +262,12 @@ describe('Middy middleware', () => { customConfigService: configService, }); const consoleSpy = jest.spyOn(logger['console'], 'info').mockImplementation(); - const lambdaHandler = (): void => { + const handler = middy((): void => { logger.info('This is an INFO log with some context'); - }; - const handler = middy(lambdaHandler).use(injectLambdaContext(logger , { logEvent: true })); - const event = { foo: 'bar' }; - const getRandomInt = (): number => Math.floor(Math.random() * 1000000000); - const awsRequestId = getRandomInt().toString(); - const context = { - callbackWaitsForEmptyEventLoop: true, - functionVersion: '$LATEST', - functionName: 'foo-bar-function', - memoryLimitInMB: '128', - logGroupName: '/aws/lambda/foo-bar-function', - logStreamName: '2021/03/09/[$LATEST]abcdef123456abcdef123456abcdef123456', - invokedFunctionArn: 'arn:aws:lambda:eu-west-1:123456789012:function:foo-bar-function', - awsRequestId: awsRequestId, - getRemainingTimeInMillis: () => 1234, - done: () => console.log('Done!'), - fail: () => console.log('Failed!'), - succeed: () => console.log('Succeeded!'), - }; - + }).use(injectLambdaContext(logger , { logEvent: true })); + // Act - await handler(event, context, () => console.log('Lambda invoked!')); + await handler(event, context); // Assess expect(consoleSpy).toBeCalledTimes(2); @@ -380,49 +276,33 @@ describe('Middy middleware', () => { function_arn: 'arn:aws:lambda:eu-west-1:123456789012:function:foo-bar-function', function_memory_size: 128, function_name: 'foo-bar-function', - function_request_id: awsRequestId, + function_request_id: 'c6af9ac6-7b61-11e6-9a41-93e812345678', level: 'INFO', message: 'Lambda invocation event', service: 'my-backend-service', timestamp: '2016-06-20T12:08:10.000Z', xray_trace_id: '1-5759e988-bd862e3fe1be46a994272793', event: { - foo: 'bar' + key1: 'value1', + key2: 'value2', + key3: 'value3', } })); }); - test('when a logger is passed without options, but POWERTOOLS_LOGGER_LOG_EVENT env var is set to true, it logs the event', async () => { + test('when enabled via POWERTOOLS_LOGGER_LOG_EVENT env var, it logs the event', async () => { // Prepare process.env.POWERTOOLS_LOGGER_LOG_EVENT = 'true'; const logger = new Logger(); const consoleSpy = jest.spyOn(logger['console'], 'info').mockImplementation(); - const lambdaHandler = (): void => { + const handler = middy((): void => { logger.info('This is an INFO log with some context'); - }; - const handler = middy(lambdaHandler).use(injectLambdaContext(logger)); - const event = { foo: 'bar' }; - const getRandomInt = (): number => Math.floor(Math.random() * 1000000000); - const awsRequestId = getRandomInt().toString(); - const context = { - callbackWaitsForEmptyEventLoop: true, - functionVersion: '$LATEST', - functionName: 'foo-bar-function', - memoryLimitInMB: '128', - logGroupName: '/aws/lambda/foo-bar-function', - logStreamName: '2021/03/09/[$LATEST]abcdef123456abcdef123456abcdef123456', - invokedFunctionArn: 'arn:aws:lambda:eu-west-1:123456789012:function:foo-bar-function', - awsRequestId: awsRequestId, - getRemainingTimeInMillis: () => 1234, - done: () => console.log('Done!'), - fail: () => console.log('Failed!'), - succeed: () => console.log('Succeeded!'), - }; - + }).use(injectLambdaContext(logger)); + // Act - await handler(event, context, () => console.log('Lambda invoked!')); + await handler(event, context); // Assess expect(consoleSpy).toBeCalledTimes(2); @@ -431,49 +311,33 @@ describe('Middy middleware', () => { function_arn: 'arn:aws:lambda:eu-west-1:123456789012:function:foo-bar-function', function_memory_size: 128, function_name: 'foo-bar-function', - function_request_id: awsRequestId, + function_request_id: 'c6af9ac6-7b61-11e6-9a41-93e812345678', level: 'INFO', message: 'Lambda invocation event', service: 'hello-world', timestamp: '2016-06-20T12:08:10.000Z', xray_trace_id: '1-5759e988-bd862e3fe1be46a994272793', event: { - foo: 'bar' + key1: 'value1', + key2: 'value2', + key3: 'value3', } })); }); - test('when a logger is passed with option logEvent set to false, but POWERTOOLS_LOGGER_LOG_EVENT env var is set to true, it does not log the event', async () => { + test('when disabled in the middleware, but enabled via POWERTOOLS_LOGGER_LOG_EVENT env var, it still doesn\'t log the event', async () => { // Prepare process.env.POWERTOOLS_LOGGER_LOG_EVENT = 'true'; const logger = new Logger(); const consoleSpy = jest.spyOn(logger['console'], 'info').mockImplementation(); - const lambdaHandler = (): void => { + const handler = middy((): void => { logger.info('This is an INFO log'); - }; - const handler = middy(lambdaHandler).use(injectLambdaContext(logger, { logEvent: false })); - const event = { foo: 'bar' }; - const getRandomInt = (): number => Math.floor(Math.random() * 1000000000); - const awsRequestId = getRandomInt().toString(); - const context = { - callbackWaitsForEmptyEventLoop: true, - functionVersion: '$LATEST', - functionName: 'foo-bar-function', - memoryLimitInMB: '128', - logGroupName: '/aws/lambda/foo-bar-function', - logStreamName: '2021/03/09/[$LATEST]abcdef123456abcdef123456abcdef123456', - invokedFunctionArn: 'arn:aws:lambda:eu-west-1:123456789012:function:foo-bar-function', - awsRequestId: awsRequestId, - getRemainingTimeInMillis: () => 1234, - done: () => console.log('Done!'), - fail: () => console.log('Failed!'), - succeed: () => console.log('Succeeded!'), - }; - + }).use(injectLambdaContext(logger, { logEvent: false })); + // Act - await handler(event, context, () => console.log('Lambda invoked!')); + await handler(event, context); // Assess expect(consoleSpy).toBeCalledTimes(1); @@ -482,7 +346,7 @@ describe('Middy middleware', () => { function_arn: 'arn:aws:lambda:eu-west-1:123456789012:function:foo-bar-function', function_memory_size: 128, function_name: 'foo-bar-function', - function_request_id: awsRequestId, + function_request_id: 'c6af9ac6-7b61-11e6-9a41-93e812345678', level: 'INFO', message: 'This is an INFO log', service: 'hello-world', @@ -491,6 +355,54 @@ describe('Middy middleware', () => { })); }); + test('when logEvent and clearState are both TRUE, and the logger has persistent attributes, any key added in the handler is cleared properly', async () => { + + const logger = new Logger({ + persistentLogAttributes: { + version: '1.0.0', + } + }); + const consoleSpy = jest.spyOn(logger['console'], 'info').mockImplementation(); + const handler = middy(async (event: { foo: string }, _context: Context) => { + logger.appendKeys({ foo: event.foo }); + }).use(injectLambdaContext(logger, { logEvent: true, clearState: true })); + + await handler({ foo: 'bar' }, {} as Context); + await handler({ foo: 'baz' }, {} as Context); + await handler({ foo: 'biz' }, {} as Context); + await handler({ foo: 'buz' }, {} as Context); + await handler({ foo: 'boz' }, {} as Context); + + expect(consoleSpy).toBeCalledTimes(5); + for (let i = 1; i === 5; i++) { + expect(consoleSpy).toHaveBeenNthCalledWith( + i, + expect.stringContaining('\"message\":\"Lambda invocation event\"'), + ); + expect(consoleSpy).toHaveBeenNthCalledWith( + i, + expect.stringContaining('\"version\":\"1.0.0\"'), + ); + } + expect(consoleSpy).toHaveBeenNthCalledWith( + 2, + expect.not.stringContaining('\"foo\":\"bar\"') + ); + expect(consoleSpy).toHaveBeenNthCalledWith( + 3, + expect.not.stringContaining('\"foo\":\"baz\"') + ); + expect(consoleSpy).toHaveBeenNthCalledWith( + 4, + expect.not.stringContaining('\"foo\":\"biz\"') + ); + expect(consoleSpy).toHaveBeenNthCalledWith( + 5, + expect.not.stringContaining('\"foo\":\"buz\"') + ); + + }); + }); }); diff --git a/packages/metrics/CHANGELOG.md b/packages/metrics/CHANGELOG.md index 737e65944a..e0f9ef3e8a 100644 --- a/packages/metrics/CHANGELOG.md +++ b/packages/metrics/CHANGELOG.md @@ -3,6 +3,14 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. +# [1.6.0](https://github.com/awslabs/aws-lambda-powertools-typescript/compare/v1.5.1...v1.6.0) (2023-03-02) + +**Note:** Version bump only for package @aws-lambda-powertools/metrics + + + + + ## [1.5.1](https://github.com/awslabs/aws-lambda-powertools-typescript/compare/v1.5.0...v1.5.1) (2023-01-13) **Note:** Version bump only for package @aws-lambda-powertools/metrics diff --git a/packages/metrics/README.md b/packages/metrics/README.md index a148d17c99..8344b0262c 100644 --- a/packages/metrics/README.md +++ b/packages/metrics/README.md @@ -1,6 +1,6 @@ # AWS Lambda Powertools for TypeScript -A suite of utilities for AWS Lambda functions to ease the adoption of best practices such as tracing, structured logging, custom metrics, and more. +Powertools is a developer toolkit to implement Serverless [best practices and increase developer velocity](https://awslabs.github.io/aws-lambda-powertools-typescript/latest/#features). You can use the library in both TypeScript and JavaScript code bases. diff --git a/packages/metrics/jest.config.js b/packages/metrics/jest.config.js index 118de05065..11773c6994 100644 --- a/packages/metrics/jest.config.js +++ b/packages/metrics/jest.config.js @@ -1,4 +1,8 @@ module.exports = { + displayName: { + name: 'AWS Lambda Powertools utility: METRICS', + color: 'green', + }, 'runner': 'groups', 'preset': 'ts-jest', 'transform': { @@ -33,4 +37,7 @@ module.exports = { 'json-summary', 'text', 'lcov' ], + 'setupFiles': [ + '/tests/helpers/populateEnvironmentVariables.ts' + ] }; \ No newline at end of file diff --git a/packages/metrics/package.json b/packages/metrics/package.json index 901dfba5a5..058df1ee42 100644 --- a/packages/metrics/package.json +++ b/packages/metrics/package.json @@ -1,6 +1,6 @@ { "name": "@aws-lambda-powertools/metrics", - "version": "1.5.1", + "version": "1.6.0", "description": "The metrics package for the AWS Lambda Powertools for TypeScript library", "author": { "name": "Amazon Web Services", @@ -26,7 +26,7 @@ "prepare": "npm run build", "postversion": "git push --tags" }, - "homepage": "https://github.com/awslabs/aws-lambda-powertools-typescript/tree/master/packages/metrics#readme", + "homepage": "https://github.com/awslabs/aws-lambda-powertools-typescript/tree/main/packages/metrics#readme", "license": "MIT-0", "main": "./lib/index.js", "types": "./lib/index.d.ts", @@ -46,7 +46,7 @@ "url": "https://github.com/awslabs/aws-lambda-powertools-typescript/issues" }, "dependencies": { - "@aws-lambda-powertools/commons": "^1.5.1" + "@aws-lambda-powertools/commons": "^1.6.0" }, "keywords": [ "aws", diff --git a/packages/metrics/tests/helpers/populate-environment-variables.ts b/packages/metrics/tests/helpers/populate-environment-variables.ts deleted file mode 100644 index 82f69ebf44..0000000000 --- a/packages/metrics/tests/helpers/populate-environment-variables.ts +++ /dev/null @@ -1,9 +0,0 @@ -const populateEnvironmentVariables = (): void => { - - process.env.POWERTOOLS_METRICS_NAMESPACE = 'hello-world'; - -}; - -export { - populateEnvironmentVariables, -}; \ No newline at end of file diff --git a/packages/metrics/tests/helpers/populateEnvironmentVariables.ts b/packages/metrics/tests/helpers/populateEnvironmentVariables.ts new file mode 100644 index 0000000000..37e985813c --- /dev/null +++ b/packages/metrics/tests/helpers/populateEnvironmentVariables.ts @@ -0,0 +1,10 @@ +// Reserved variables +process.env._X_AMZN_TRACE_ID = 'Root=1-5759e988-bd862e3fe1be46a994272793;Parent=557abcec3ee5a047;Sampled=1'; +process.env.AWS_LAMBDA_FUNCTION_NAME = 'my-lambda-function'; +process.env.AWS_LAMBDA_FUNCTION_MEMORY_SIZE = '128'; +if (process.env.AWS_REGION === undefined && process.env.CDK_DEFAULT_REGION === undefined) { + process.env.AWS_REGION = 'eu-west-1'; +} + +// Powertools variables +process.env.POWERTOOLS_METRICS_NAMESPACE = 'hello-world'; \ No newline at end of file diff --git a/packages/metrics/tests/unit/Metrics.test.ts b/packages/metrics/tests/unit/Metrics.test.ts index ef34f6b6b9..5f2bd02bf8 100644 --- a/packages/metrics/tests/unit/Metrics.test.ts +++ b/packages/metrics/tests/unit/Metrics.test.ts @@ -7,7 +7,6 @@ import { ContextExamples as dummyContext, Events as dummyEvent, LambdaInterface } from '@aws-lambda-powertools/commons'; import { Context, Callback } from 'aws-lambda'; import { Metrics, MetricUnits } from '../../src/'; -import { populateEnvironmentVariables } from '../helpers'; const MAX_METRICS_SIZE = 100; const MAX_DIMENSION_COUNT = 29; @@ -20,7 +19,7 @@ interface LooseObject { } describe('Class: Metrics', () => { - const originalEnvironmentVariables = process.env; + const ENVIRONMENT_VARIABLES = process.env; const context = dummyContext.helloworldContext; const event = dummyEvent.Custom.CustomEvent; @@ -29,12 +28,7 @@ describe('Class: Metrics', () => { }); beforeAll(() => { - populateEnvironmentVariables(); - }); - - afterEach(() => { - process.env = originalEnvironmentVariables; - delete process.env.POWERTOOLS_SERVICE_NAME; + process.env = { ...ENVIRONMENT_VARIABLES }; }); describe('Feature: Dimensions logging', () => { diff --git a/packages/parameters/package.json b/packages/parameters/package.json index 55afcf9166..469e72f70b 100644 --- a/packages/parameters/package.json +++ b/packages/parameters/package.json @@ -13,10 +13,10 @@ "commit": "commit", "test": "npm run test:unit", "test:unit": "jest --group=unit --detectOpenHandles --coverage --verbose", - "test:e2e:nodejs14x": "echo \"Not implemented\"", - "test:e2e:nodejs16x": "echo \"Not implemented\"", - "test:e2e:nodejs18x": "echo \"Not implemented\"", - "test:e2e": "echo \"Not implemented\"", + "test:e2e:nodejs14x": "RUNTIME=nodejs14x jest --group=e2e", + "test:e2e:nodejs16x": "RUNTIME=nodejs16x jest --group=e2e", + "test:e2e:nodejs18x": "RUNTIME=nodejs18x jest --group=e2e", + "test:e2e": "jest --group=e2e", "watch": "jest --watch", "build": "tsc", "lint": "eslint --ext .ts --no-error-on-unmatched-pattern src tests", @@ -60,6 +60,6 @@ "aws-sdk-client-mock-jest": "^2.0.1" }, "dependencies": { - "@aws-sdk/util-base64": "^3.208.0" + "@aws-sdk/util-base64-node": "^3.209.0" } -} +} \ No newline at end of file diff --git a/packages/parameters/src/BaseProvider.ts b/packages/parameters/src/BaseProvider.ts index 2d993c71a2..b2fc4efc1c 100644 --- a/packages/parameters/src/BaseProvider.ts +++ b/packages/parameters/src/BaseProvider.ts @@ -1,4 +1,4 @@ -import { fromBase64 } from '@aws-sdk/util-base64'; +import { fromBase64 } from '@aws-sdk/util-base64-node'; import { GetOptions } from './GetOptions'; import { GetMultipleOptions } from './GetMultipleOptions'; import { ExpirableValue } from './ExpirableValue'; @@ -131,6 +131,11 @@ abstract class BaseProvider implements BaseProviderInterface { const transformValue = (value: string | Uint8Array | undefined, transform: TransformOptions, throwOnTransformError: boolean, key: string): string | Record | undefined => { try { const normalizedTransform = transform.toLowerCase(); + + if (value instanceof Uint8Array) { + value = new TextDecoder('utf-8').decode(value); + } + if ( (normalizedTransform === TRANSFORM_METHOD_JSON || (normalizedTransform === 'auto' && key.toLowerCase().endsWith(`.${TRANSFORM_METHOD_JSON}`))) && @@ -139,15 +144,12 @@ const transformValue = (value: string | Uint8Array | undefined, transform: Trans return JSON.parse(value) as Record; } else if ( (normalizedTransform === TRANSFORM_METHOD_BINARY || - (normalizedTransform === 'auto' && key.toLowerCase().endsWith(`.${TRANSFORM_METHOD_BINARY}`))) + (normalizedTransform === 'auto' && key.toLowerCase().endsWith(`.${TRANSFORM_METHOD_BINARY}`))) && + typeof value === 'string' ) { - if (typeof value === 'string') { - return new TextDecoder('utf-8').decode(fromBase64(value)); - } else { - return new TextDecoder('utf-8').decode(value); - } + return new TextDecoder('utf-8').decode(fromBase64(value)); } else { - return value as string; + return value; } } catch (error) { if (throwOnTransformError) diff --git a/packages/parameters/src/appconfig/AppConfigProvider.ts b/packages/parameters/src/appconfig/AppConfigProvider.ts index 0042722aec..9e9e2b0152 100644 --- a/packages/parameters/src/appconfig/AppConfigProvider.ts +++ b/packages/parameters/src/appconfig/AppConfigProvider.ts @@ -23,7 +23,16 @@ class AppConfigProvider extends BaseProvider { */ public constructor(options: AppConfigProviderOptions) { super(); - this.client = new AppConfigDataClient(options.clientConfig || {}); + if (options?.awsSdkV3Client) { + if (options?.awsSdkV3Client instanceof AppConfigDataClient) { + this.client = options.awsSdkV3Client; + } else { + throw Error('Not a valid AppConfigDataClient provided'); + } + } else { + this.client = new AppConfigDataClient(options.clientConfig || {}); + } + if (!options?.application && !process.env['POWERTOOLS_SERVICE_NAME']) { throw new Error( 'Application name is not defined or POWERTOOLS_SERVICE_NAME is not set' diff --git a/packages/parameters/src/dynamodb/DynamoDBProvider.ts b/packages/parameters/src/dynamodb/DynamoDBProvider.ts index f99ab90651..58f0f2456b 100644 --- a/packages/parameters/src/dynamodb/DynamoDBProvider.ts +++ b/packages/parameters/src/dynamodb/DynamoDBProvider.ts @@ -19,8 +19,17 @@ class DynamoDBProvider extends BaseProvider { public constructor(config: DynamoDBProviderOptions) { super(); - const clientConfig = config.clientConfig || {}; - this.client = new DynamoDBClient(clientConfig); + if (config?.awsSdkV3Client) { + if (config?.awsSdkV3Client instanceof DynamoDBClient) { + this.client = config.awsSdkV3Client; + } else { + throw Error('Not a valid DynamoDBClient provided'); + } + } else { + const clientConfig = config?.clientConfig || {}; + this.client = new DynamoDBClient(clientConfig); + } + this.tableName = config.tableName; if (config.keyAttr) this.keyAttr = config.keyAttr; if (config.sortAttr) this.sortAttr = config.sortAttr; @@ -49,7 +58,10 @@ class DynamoDBProvider extends BaseProvider { ...(options?.sdkOptions || {}), TableName: this.tableName, Key: marshall({ [this.keyAttr]: name }), - ProjectionExpression: this.valueAttr, + ProjectionExpression: '#value', + ExpressionAttributeNames: { + '#value': this.valueAttr, + } }; const result = await this.client.send(new GetItemCommand(sdkOptions)); @@ -63,9 +75,14 @@ class DynamoDBProvider extends BaseProvider { const sdkOptions: QueryCommandInput = { ...(options?.sdkOptions || {}), TableName: this.tableName, - KeyConditionExpression: `${this.keyAttr} = :key`, + KeyConditionExpression: '#key = :key', ExpressionAttributeValues: marshall({ ':key': path }), - ProjectionExpression: `${this.sortAttr}, ${this.valueAttr}`, + ExpressionAttributeNames: { + '#key': this.keyAttr, + '#sk': this.sortAttr, + '#value': this.valueAttr, + }, + ProjectionExpression: '#sk, #value', }; const paginationOptions: PaginationConfiguration = { client: this.client, diff --git a/packages/parameters/src/secrets/SecretsProvider.ts b/packages/parameters/src/secrets/SecretsProvider.ts index 4d91009610..12a6703783 100644 --- a/packages/parameters/src/secrets/SecretsProvider.ts +++ b/packages/parameters/src/secrets/SecretsProvider.ts @@ -15,8 +15,17 @@ class SecretsProvider extends BaseProvider { public constructor (config?: SecretsProviderOptions) { super(); - const clientConfig = config?.clientConfig || {}; - this.client = new SecretsManagerClient(clientConfig); + if (config?.awsSdkV3Client) { + if (config?.awsSdkV3Client instanceof SecretsManagerClient) { + this.client = config.awsSdkV3Client; + } else { + throw Error('Not a valid SecretsManagerClient provided'); + } + } else { + const clientConfig = config?.clientConfig || {}; + this.client = new SecretsManagerClient(clientConfig); + } + } public async get( diff --git a/packages/parameters/src/ssm/SSMProvider.ts b/packages/parameters/src/ssm/SSMProvider.ts index 66d7e12367..dd45070162 100644 --- a/packages/parameters/src/ssm/SSMProvider.ts +++ b/packages/parameters/src/ssm/SSMProvider.ts @@ -14,7 +14,7 @@ import type { GetParametersCommandOutput, } from '@aws-sdk/client-ssm'; import type { - SSMProviderOptionsInterface, + SSMProviderOptions, SSMGetMultipleOptionsInterface, SSMGetOptionsInterface, SSMGetParametersByNameOutputInterface, @@ -29,9 +29,19 @@ class SSMProvider extends BaseProvider { protected errorsKey = '_errors'; protected maxGetParametersItems = 10; - public constructor(config?: SSMProviderOptionsInterface) { + public constructor(config?: SSMProviderOptions) { super(); - this.client = new SSMClient(config?.clientConfig || {}); + + if (config?.awsSdkV3Client) { + if (config?.awsSdkV3Client instanceof SSMClient) { + this.client = config.awsSdkV3Client; + } else { + throw Error('Not a valid SSMClient provided'); + } + } else { + const clientConfig = config?.clientConfig || {}; + this.client = new SSMClient(clientConfig); + } } public async get( @@ -134,14 +144,11 @@ class SSMProvider extends BaseProvider { options?: SSMGetOptionsInterface ): Promise { const sdkOptions: GetParameterCommandInput = { + ...(options?.sdkOptions || {}), Name: name, }; - if (options) { - if (options.hasOwnProperty('decrypt')) sdkOptions.WithDecryption = options.decrypt; - if (options.hasOwnProperty('sdkOptions')) { - Object.assign(sdkOptions, options.sdkOptions); - } - } + sdkOptions.WithDecryption = options?.decrypt !== undefined ? + options.decrypt : sdkOptions.WithDecryption; const result = await this.client.send(new GetParameterCommand(sdkOptions)); return result.Parameter?.Value; @@ -152,21 +159,18 @@ class SSMProvider extends BaseProvider { options?: SSMGetMultipleOptionsInterface ): Promise> { const sdkOptions: GetParametersByPathCommandInput = { + ...(options?.sdkOptions || {}), Path: path, }; const paginationOptions: PaginationConfiguration = { client: this.client }; - if (options) { - if (options.hasOwnProperty('decrypt')) sdkOptions.WithDecryption = options.decrypt; - if (options.hasOwnProperty('recursive')) sdkOptions.Recursive = options.recursive; - if (options.hasOwnProperty('sdkOptions')) { - Object.assign(sdkOptions, options.sdkOptions); - if (sdkOptions.MaxResults) { - paginationOptions.pageSize = sdkOptions.MaxResults; - } - } - } + sdkOptions.WithDecryption = options?.decrypt !== undefined ? + options.decrypt : sdkOptions.WithDecryption; + sdkOptions.Recursive = options?.recursive !== undefined ? + options.recursive : sdkOptions.Recursive; + paginationOptions.pageSize = sdkOptions.MaxResults !== undefined ? + sdkOptions.MaxResults : undefined; const parameters: Record = {}; for await (const page of paginateGetParametersByPath(paginationOptions, sdkOptions)) { @@ -379,13 +383,11 @@ class SSMProvider extends BaseProvider { const overrides = parameterOptions; overrides.transform = overrides.transform || configs.transform; - if (!overrides.hasOwnProperty('decrypt')) { - overrides.decrypt = configs.decrypt; - } - if (!overrides.hasOwnProperty('maxAge')) { - overrides.maxAge = configs.maxAge; - } - + overrides.decrypt = overrides.decrypt !== undefined ? + overrides.decrypt : configs.decrypt; + overrides.maxAge = overrides.maxAge !== undefined ? + overrides.maxAge : configs.maxAge; + if (overrides.decrypt) { parametersToDecrypt[parameterName] = overrides; } else { diff --git a/packages/parameters/src/ssm/index.ts b/packages/parameters/src/ssm/index.ts index 329d3d3f3b..e275be6d78 100644 --- a/packages/parameters/src/ssm/index.ts +++ b/packages/parameters/src/ssm/index.ts @@ -1,5 +1,4 @@ export * from './SSMProvider'; export * from './getParameter'; export * from './getParameters'; -export * from './getParametersByName'; -export * from '../types/SSMProvider'; \ No newline at end of file +export * from './getParametersByName'; \ No newline at end of file diff --git a/packages/parameters/src/types/AppConfigProvider.ts b/packages/parameters/src/types/AppConfigProvider.ts index c699714639..007bca8a50 100644 --- a/packages/parameters/src/types/AppConfigProvider.ts +++ b/packages/parameters/src/types/AppConfigProvider.ts @@ -1,23 +1,59 @@ import type { + AppConfigDataClient, AppConfigDataClientConfig, StartConfigurationSessionCommandInput, } from '@aws-sdk/client-appconfigdata'; import type { GetOptionsInterface } from 'types/BaseProvider'; /** - * Options for the AppConfigProvider class constructor. + * Base interface for AppConfigProviderOptions. * - * @interface AppConfigProviderOptions + * @interface * @property {string} environment - The environment ID or the environment name. * @property {string} [application] - The application ID or the application name. - * @property {AppConfigDataClientConfig} [clientConfig] - Optional configuration to pass during client initialization, e.g. AWS region. */ -interface AppConfigProviderOptions { +interface AppConfigProviderOptionsBaseInterface { environment: string application?: string +} + +/** + * Interface for AppConfigProviderOptions with clientConfig property. + * + * @interface + * @extends AppConfigProviderOptionsBaseInterface + * @property {AppConfigDataClientConfig} [clientConfig] - Optional configuration to pass during client initialization, e.g. AWS region. + * @property {never} [awsSdkV3Client] - This property should never be passed. + */ +interface AppConfigProviderOptionsWithClientConfig extends AppConfigProviderOptionsBaseInterface { clientConfig?: AppConfigDataClientConfig + awsSdkV3Client?: never +} + +/** + * Interface for AppConfigProviderOptions with awsSdkV3Client property. + * + * @interface + * @extends AppConfigProviderOptionsBaseInterface + * @property {AppConfigDataClient} [awsSdkV3Client] - Optional AWS SDK v3 client to pass during AppConfigProvider class instantiation + * @property {never} [clientConfig] - This property should never be passed. + */ +interface AppConfigProviderOptionsWithClientInstance extends AppConfigProviderOptionsBaseInterface { + awsSdkV3Client?: AppConfigDataClient + clientConfig?: never } +/** + * Options for the AppConfigProvider class constructor. + * + * @type AppConfigProviderOptions + * @property {string} environment - The environment ID or the environment name. + * @property {string} [application] - The application ID or the application name. + * @property {AppConfigDataClientConfig} [clientConfig] - Optional configuration to pass during client initialization, e.g. AWS region. Mutually exclusive with awsSdkV3Client. + * @property {AppConfigDataClient} [awsSdkV3Client] - Optional AWS SDK v3 client to pass during AppConfigProvider class instantiation. Mutually exclusive with clientConfig. + */ +type AppConfigProviderOptions = AppConfigProviderOptionsWithClientConfig | AppConfigProviderOptionsWithClientInstance; + /** * Options for the AppConfigProvider get method. * @@ -40,7 +76,7 @@ interface AppConfigGetOptionsInterface extends Omit, + extends Omit, AppConfigGetOptionsInterface {} export type { diff --git a/packages/parameters/src/types/DynamoDBProvider.ts b/packages/parameters/src/types/DynamoDBProvider.ts index a0327a9557..140bf50fd2 100644 --- a/packages/parameters/src/types/DynamoDBProvider.ts +++ b/packages/parameters/src/types/DynamoDBProvider.ts @@ -1,14 +1,25 @@ import type { GetOptionsInterface, GetMultipleOptionsInterface } from './BaseProvider'; -import type { GetItemCommandInput, QueryCommandInput, DynamoDBClientConfig } from '@aws-sdk/client-dynamodb'; +import type { DynamoDBClient, GetItemCommandInput, QueryCommandInput, DynamoDBClientConfig } from '@aws-sdk/client-dynamodb'; -interface DynamoDBProviderOptions { +interface DynamoDBProviderOptionsBaseInterface { tableName: string keyAttr?: string sortAttr?: string valueAttr?: string +} + +interface DynamoDBProviderOptionsWithClientConfig extends DynamoDBProviderOptionsBaseInterface { clientConfig?: DynamoDBClientConfig + awsSdkV3Client?: never } +interface DynamoDBProviderOptionsWithClientInstance extends DynamoDBProviderOptionsBaseInterface { + awsSdkV3Client?: DynamoDBClient + clientConfig?: never +} + +type DynamoDBProviderOptions = DynamoDBProviderOptionsWithClientConfig | DynamoDBProviderOptionsWithClientInstance; + /** * Options for the DynamoDBProvider get method. * diff --git a/packages/parameters/src/types/SSMProvider.ts b/packages/parameters/src/types/SSMProvider.ts index f1127b289e..9ce1f66e97 100644 --- a/packages/parameters/src/types/SSMProvider.ts +++ b/packages/parameters/src/types/SSMProvider.ts @@ -1,4 +1,5 @@ import type { + SSMClient, SSMClientConfig, GetParameterCommandInput, GetParametersByPathCommandInput @@ -9,10 +10,18 @@ import type { TransformOptions } from './BaseProvider'; -interface SSMProviderOptionsInterface { - clientConfig: SSMClientConfig +interface SSMProviderOptionsWithClientConfig { + clientConfig?: SSMClientConfig + awsSdkV3Client?: never } +interface SSMProviderOptionsWithClientInstance { + awsSdkV3Client?: SSMClient + clientConfig?: never +} + +type SSMProviderOptions = SSMProviderOptionsWithClientConfig | SSMProviderOptionsWithClientInstance; + /** * Options for the SSMProvider get method. * @@ -56,7 +65,7 @@ type SSMGetParametersByNameFromCacheOutputType = { }; export type { - SSMProviderOptionsInterface, + SSMProviderOptions, SSMGetOptionsInterface, SSMGetMultipleOptionsInterface, SSMGetParametersByNameOptionsInterface, diff --git a/packages/parameters/src/types/SecretsProvider.ts b/packages/parameters/src/types/SecretsProvider.ts index b936309765..757f38b18b 100644 --- a/packages/parameters/src/types/SecretsProvider.ts +++ b/packages/parameters/src/types/SecretsProvider.ts @@ -1,10 +1,18 @@ import type { GetOptionsInterface } from './BaseProvider'; -import type { SecretsManagerClientConfig, GetSecretValueCommandInput } from '@aws-sdk/client-secrets-manager'; +import type { SecretsManagerClient, SecretsManagerClientConfig, GetSecretValueCommandInput } from '@aws-sdk/client-secrets-manager'; -interface SecretsProviderOptions { +interface SecretsProviderOptionsWithClientConfig { clientConfig?: SecretsManagerClientConfig + awsSdkV3Client?: never } +interface SecretsProviderOptionsWithClientInstance { + awsSdkV3Client?: SecretsManagerClient + clientConfig?: never +} + +type SecretsProviderOptions = SecretsProviderOptionsWithClientConfig | SecretsProviderOptionsWithClientInstance; + interface SecretsGetOptionsInterface extends GetOptionsInterface { sdkOptions?: Omit, 'SecretId'> } diff --git a/packages/parameters/tests/e2e/appConfigProvider.class.test.functionCode.ts b/packages/parameters/tests/e2e/appConfigProvider.class.test.functionCode.ts new file mode 100644 index 0000000000..11d8feb01f --- /dev/null +++ b/packages/parameters/tests/e2e/appConfigProvider.class.test.functionCode.ts @@ -0,0 +1,114 @@ +import { Context } from 'aws-lambda'; +import { + AppConfigProvider, +} from '../../src/appconfig'; +import { + AppConfigGetOptionsInterface, +} from '../../src/types'; +import { TinyLogger } from '../helpers/tinyLogger'; +import { middleware } from '../helpers/sdkMiddlewareRequestCounter'; +import { AppConfigDataClient } from '@aws-sdk/client-appconfigdata'; + +// We use a custom logger to log pure JSON objects to stdout +const logger = new TinyLogger(); + +const application = process.env.APPLICATION_NAME || 'my-app'; +const environment = process.env.ENVIRONMENT_NAME || 'my-env'; +const freeFormJsonName = process.env.FREEFORM_JSON_NAME || 'freeform-json'; +const freeFormYamlName = process.env.FREEFORM_YAML_NAME || 'freeform-yaml'; +const freeFormBase64encodedPlainText = process.env.FREEFORM_BASE64_ENCODED_PLAIN_TEXT_NAME || 'freeform-plain-text'; +const featureFlagName = process.env.FEATURE_FLAG_NAME || 'feature-flag'; + +const defaultProvider = new AppConfigProvider({ + application, + environment, +}); +// Provider test +const customClient = new AppConfigDataClient({}); +customClient.middlewareStack.use(middleware); +const providerWithMiddleware = new AppConfigProvider({ + awsSdkV3Client: customClient, + application, + environment, +}); + +// Use provider specified, or default to main one & return it with cache cleared +const resolveProvider = (provider?: AppConfigProvider): AppConfigProvider => { + const resolvedProvider = provider ? provider : defaultProvider; + resolvedProvider.clearCache(); + + return resolvedProvider; +}; + +// Helper function to call get() and log the result +const _call_get = async ( + paramName: string, + testName: string, + options?: AppConfigGetOptionsInterface, + provider?: AppConfigProvider, +): Promise => { + try { + const currentProvider = resolveProvider(provider); + + const parameterValue = await currentProvider.get(paramName, options); + logger.log({ + test: testName, + value: parameterValue + }); + } catch (err) { + logger.log({ + test: testName, + error: err.message + }); + } +}; + +export const handler = async (_event: unknown, _context: Context): Promise => { + // Test 1 - get a single parameter as-is (no transformation - should return an Uint8Array) + await _call_get(freeFormYamlName, 'get'); + + // Test 2 - get a free-form JSON and apply json transformation (should return an object) + await _call_get(freeFormJsonName, 'get-freeform-json-binary', { transform: 'json' }); + + // Test 3 - get a free-form base64-encoded plain text and apply binary transformation (should return a decoded string) + await _call_get(freeFormBase64encodedPlainText, 'get-freeform-base64-plaintext-binary', { transform: 'binary' }); + + // Test 5 - get a feature flag and apply json transformation (should return an object) + await _call_get(featureFlagName, 'get-feature-flag-binary', { transform: 'json' }); + + // Test 6 + // get parameter twice with middleware, which counts the number of requests, we check later if we only called AppConfig API once + try { + providerWithMiddleware.clearCache(); + middleware.counter = 0; + await providerWithMiddleware.get(freeFormBase64encodedPlainText); + await providerWithMiddleware.get(freeFormBase64encodedPlainText); + logger.log({ + test: 'get-cached', + value: middleware.counter // should be 1 + }); + } catch (err) { + logger.log({ + test: 'get-cached', + error: err.message + }); + } + + // Test 7 + // get parameter twice, but force fetch 2nd time, we count number of SDK requests and check that we made two API calls + try { + providerWithMiddleware.clearCache(); + middleware.counter = 0; + await providerWithMiddleware.get(freeFormBase64encodedPlainText); + await providerWithMiddleware.get(freeFormBase64encodedPlainText, { forceFetch: true }); + logger.log({ + test: 'get-forced', + value: middleware.counter // should be 2 + }); + } catch (err) { + logger.log({ + test: 'get-forced', + error: err.message + }); + } +}; \ No newline at end of file diff --git a/packages/parameters/tests/e2e/appConfigProvider.class.test.ts b/packages/parameters/tests/e2e/appConfigProvider.class.test.ts new file mode 100644 index 0000000000..02b2de3291 --- /dev/null +++ b/packages/parameters/tests/e2e/appConfigProvider.class.test.ts @@ -0,0 +1,325 @@ +/** + * Test AppConfigProvider class + * + * @group e2e/parameters/appconfig/class + */ +import path from 'path'; +import { App, Stack, Aspects } from 'aws-cdk-lib'; +import { toBase64 } from '@aws-sdk/util-base64-node'; +import { v4 } from 'uuid'; +import { + generateUniqueName, + isValidRuntimeKey, + createStackWithLambdaFunction, + invokeFunction, +} from '../../../commons/tests/utils/e2eUtils'; +import { InvocationLogs } from '../../../commons/tests/utils/InvocationLogs'; +import { deployStack, destroyStack } from '../../../commons/tests/utils/cdk-cli'; +import { ResourceAccessGranter } from '../helpers/cdkAspectGrantAccess'; +import { + RESOURCE_NAME_PREFIX, + SETUP_TIMEOUT, + TEARDOWN_TIMEOUT, + TEST_CASE_TIMEOUT +} from './constants'; +import { + createBaseAppConfigResources, + createAppConfigConfigurationProfile, +} from '../helpers/parametersUtils'; + +const runtime: string = process.env.RUNTIME || 'nodejs18x'; + +if (!isValidRuntimeKey(runtime)) { + throw new Error(`Invalid runtime key value: ${runtime}`); +} + +const uuid = v4(); +const stackName = generateUniqueName(RESOURCE_NAME_PREFIX, uuid, runtime, 'appConfigProvider'); +const functionName = generateUniqueName(RESOURCE_NAME_PREFIX, uuid, runtime, 'appConfigProvider'); +const lambdaFunctionCodeFile = 'appConfigProvider.class.test.functionCode.ts'; + +const invocationCount = 1; + +const applicationName = generateUniqueName(RESOURCE_NAME_PREFIX, uuid, runtime, 'app'); +const environmentName = generateUniqueName(RESOURCE_NAME_PREFIX, uuid, runtime, 'env'); +const deploymentStrategyName = generateUniqueName(RESOURCE_NAME_PREFIX, uuid, runtime, 'immediate'); +const freeFormJsonName = generateUniqueName(RESOURCE_NAME_PREFIX, uuid, runtime, 'freeFormJson'); +const freeFormYamlName = generateUniqueName(RESOURCE_NAME_PREFIX, uuid, runtime, 'freeFormYaml'); +const freeFormBase64PlainTextName = generateUniqueName(RESOURCE_NAME_PREFIX, uuid, runtime, 'freeFormBase64PlainText'); +const featureFlagName = generateUniqueName(RESOURCE_NAME_PREFIX, uuid, runtime, 'featureFlag'); + +const freeFormJsonValue = { + foo: 'bar', +}; +const freeFormYamlValue = `foo: bar +`; +const freeFormPlainTextValue = 'foo'; +const featureFlagValue = { + version: '1', + flags: { + myFeatureFlag: { + 'name': 'myFeatureFlag', + } + }, + values: { + myFeatureFlag: { + enabled: true, + } + } +}; + +const integTestApp = new App(); +let stack: Stack; + +/** + * This test suite deploys a CDK stack with a Lambda function and a number of AppConfig parameters. + * The function code uses the Parameters utility to retrieve the parameters. + * It then logs the values to CloudWatch Logs as JSON objects. + * + * Once the stack is deployed, the Lambda function is invoked and the CloudWatch Logs are retrieved. + * The logs are then parsed and the values are checked against the expected values for each test case. + * + * The stack creates an AppConfig application and environment, and then creates a number configuration + * profiles, each with a different type of parameter. + * + * The parameters created are: + * - Free-form JSON + * - Free-form YAML + * - Free-form plain text base64-encoded string + * - Feature flag + * + * These parameters allow to retrieve the values and test some transformations. + * + * The tests are: + * + * Test 1 + * get a single parameter as-is (no transformation - should return an Uint8Array) + * + * Test 2 + * get a free-form JSON and apply json transformation (should return an object) + * + * Test 3 + * get a free-form base64-encoded plain text and apply binary transformation (should return a decoded string) + * + * Test 4 + * get a feature flag and apply json transformation (should return an object) + * + * Test 5 + * get parameter twice with middleware, which counts the number of requests, + * we check later if we only called AppConfig API once + * + * Test 6 + * get parameter twice, but force fetch 2nd time, we count number of SDK requests and + * check that we made two API calls + * + * Note: To avoid race conditions, we add a dependency between each pair of configuration profiles. + * This allows us to influence the order of creation and ensure that each configuration profile + * is created after the previous one. This is necessary because we share the same AppConfig + * application and environment for all tests. + */ +describe(`parameters E2E tests (appConfigProvider) for runtime ${runtime}`, () => { + + let invocationLogs: InvocationLogs[]; + const encoder = new TextEncoder(); + + beforeAll(async () => { + // Create a stack with a Lambda function + stack = createStackWithLambdaFunction({ + app: integTestApp, + stackName, + functionName, + functionEntry: path.join(__dirname, lambdaFunctionCodeFile), + environment: { + UUID: uuid, + + // Values(s) to be used by Parameters in the Lambda function + APPLICATION_NAME: applicationName, + ENVIRONMENT_NAME: environmentName, + FREEFORM_JSON_NAME: freeFormJsonName, + FREEFORM_YAML_NAME: freeFormYamlName, + FREEFORM_BASE64_ENCODED_PLAIN_TEXT_NAME: freeFormBase64PlainTextName, + FEATURE_FLAG_NAME: featureFlagName, + }, + runtime, + }); + + // Create the base resources for an AppConfig application. + const { + application, + environment, + deploymentStrategy + } = createBaseAppConfigResources({ + stack, + applicationName, + environmentName, + deploymentStrategyName, + }); + + // Create configuration profiles for tests. + const freeFormJson = createAppConfigConfigurationProfile({ + stack, + application, + environment, + deploymentStrategy, + name: freeFormJsonName, + type: 'AWS.Freeform', + content: { + content: JSON.stringify(freeFormJsonValue), + contentType: 'application/json', + } + }); + + const freeFormYaml = createAppConfigConfigurationProfile({ + stack, + application, + environment, + deploymentStrategy, + name: freeFormYamlName, + type: 'AWS.Freeform', + content: { + content: freeFormYamlValue, + contentType: 'application/x-yaml', + } + }); + freeFormYaml.node.addDependency(freeFormJson); + + const freeFormBase64PlainText = createAppConfigConfigurationProfile({ + stack, + application, + environment, + deploymentStrategy, + name: freeFormBase64PlainTextName, + type: 'AWS.Freeform', + content: { + content: toBase64(new TextEncoder().encode(freeFormPlainTextValue)), + contentType: 'text/plain', + } + }); + freeFormBase64PlainText.node.addDependency(freeFormYaml); + + const featureFlag = createAppConfigConfigurationProfile({ + stack, + application, + environment, + deploymentStrategy, + name: featureFlagName, + type: 'AWS.AppConfig.FeatureFlags', + content: { + content: JSON.stringify(featureFlagValue), + contentType: 'application/json', + } + }); + featureFlag.node.addDependency(freeFormBase64PlainText); + + // Grant access to the Lambda function to the AppConfig resources. + Aspects.of(stack).add(new ResourceAccessGranter([ + freeFormJson, + freeFormYaml, + freeFormBase64PlainText, + featureFlag, + ])); + + // Deploy the stack + await deployStack(integTestApp, stack); + + // and invoke the Lambda function + invocationLogs = await invokeFunction(functionName, invocationCount, 'SEQUENTIAL'); + + }, SETUP_TIMEOUT); + + describe('AppConfigProvider usage', () => { + + // Test 1 - get a single parameter as-is (no transformation - should return an Uint8Array) + it('should retrieve single parameter as-is', () => { + + const logs = invocationLogs[0].getFunctionLogs(); + const testLog = InvocationLogs.parseFunctionLog(logs[0]); + + expect(testLog).toStrictEqual({ + test: 'get', + value: JSON.parse( + JSON.stringify( + encoder.encode(freeFormYamlValue) + ) + ), + }); + + }); + + // Test 2 - get a free-form JSON and apply json transformation (should return an object) + it('should retrieve a free-form JSON parameter with JSON transformation', () => { + + const logs = invocationLogs[0].getFunctionLogs(); + const testLog = InvocationLogs.parseFunctionLog(logs[1]); + + expect(testLog).toStrictEqual({ + test: 'get-freeform-json-binary', + value: freeFormJsonValue, + }); + + }); + + // Test 3 - get a free-form base64-encoded plain text and apply binary transformation + // (should return a decoded string) + it('should retrieve a base64-encoded plain text parameter with binary transformation', () => { + + const logs = invocationLogs[0].getFunctionLogs(); + const testLog = InvocationLogs.parseFunctionLog(logs[2]); + + expect(testLog).toStrictEqual({ + test: 'get-freeform-base64-plaintext-binary', + value: freeFormPlainTextValue, + }); + + }); + + // Test 4 - get a feature flag and apply json transformation (should return an object) + it('should retrieve a feature flag parameter with JSON transformation', () => { + + const logs = invocationLogs[0].getFunctionLogs(); + const testLog = InvocationLogs.parseFunctionLog(logs[3]); + + expect(testLog).toStrictEqual({ + test: 'get-feature-flag-binary', + value: featureFlagValue.values, + }); + + }); + + // Test 5 - get parameter twice with middleware, which counts the number + // of requests, we check later if we only called AppConfig API once + it('should retrieve single parameter cached', () => { + + const logs = invocationLogs[0].getFunctionLogs(); + const testLog = InvocationLogs.parseFunctionLog(logs[4]); + + expect(testLog).toStrictEqual({ + test: 'get-cached', + value: 1 + }); + + }, TEST_CASE_TIMEOUT); + + // Test 6 - get parameter twice, but force fetch 2nd time, + // we count number of SDK requests and check that we made two API calls + it('should retrieve single parameter twice without caching', async () => { + + const logs = invocationLogs[0].getFunctionLogs(); + const testLog = InvocationLogs.parseFunctionLog(logs[5]); + + expect(testLog).toStrictEqual({ + test: 'get-forced', + value: 2 + }); + + }, TEST_CASE_TIMEOUT); + + }); + + afterAll(async () => { + if (!process.env.DISABLE_TEARDOWN) { + await destroyStack(integTestApp, stack); + } + }, TEARDOWN_TIMEOUT); + +}); \ No newline at end of file diff --git a/packages/parameters/tests/e2e/constants.ts b/packages/parameters/tests/e2e/constants.ts new file mode 100644 index 0000000000..03fb4eed52 --- /dev/null +++ b/packages/parameters/tests/e2e/constants.ts @@ -0,0 +1,5 @@ +export const RESOURCE_NAME_PREFIX = 'Parameters-E2E'; +export const ONE_MINUTE = 60 * 1000; +export const TEST_CASE_TIMEOUT = 3 * ONE_MINUTE; +export const SETUP_TIMEOUT = 5 * ONE_MINUTE; +export const TEARDOWN_TIMEOUT = 5 * ONE_MINUTE; \ No newline at end of file diff --git a/packages/parameters/tests/e2e/dynamoDBProvider.class.test.functionCode.ts b/packages/parameters/tests/e2e/dynamoDBProvider.class.test.functionCode.ts new file mode 100644 index 0000000000..30ac2bbbdc --- /dev/null +++ b/packages/parameters/tests/e2e/dynamoDBProvider.class.test.functionCode.ts @@ -0,0 +1,161 @@ +import { Context } from 'aws-lambda'; +import { DynamoDBProvider } from '../../src/dynamodb'; +import { + DynamoDBGetOptionsInterface, + DynamoDBGetMultipleOptionsInterface, +} from '../../src/types'; +import { TinyLogger } from '../helpers/tinyLogger'; +import { middleware } from '../helpers/sdkMiddlewareRequestCounter'; +import { DynamoDBClient } from '@aws-sdk/client-dynamodb'; + +// We use a custom logger to log pure JSON objects to stdout +const logger = new TinyLogger(); + +const tableGet = process.env.TABLE_GET ?? 'my-table'; +const tableGetMultiple = process.env.TABLE_GET_MULTIPLE ?? 'my-table'; +const tableGetCustomkeys = process.env.TABLE_GET_CUSTOM_KEYS ?? 'my-table'; +const tableGetMultipleCustomkeys = process.env.TABLE_GET_MULTIPLE_CUSTOM_KEYS ?? 'my-table'; +const keyAttr = process.env.KEY_ATTR ?? 'id'; +const sortAttr = process.env.SORT_ATTR ?? 'sk'; +const valueAttr = process.env.VALUE_ATTR ?? 'value'; + +// Provider test 1, 5, 6 +const providerGet = new DynamoDBProvider({ + tableName: tableGet, +}); +// Provider test 2, 7 +const providerGetMultiple = new DynamoDBProvider({ + tableName: tableGetMultiple, +}); +// Provider test 3 +const providerGetCustomKeys = new DynamoDBProvider({ + tableName: tableGetCustomkeys, + keyAttr, + valueAttr, +}); +// Provider 4 +const providerGetMultipleCustomKeys = new DynamoDBProvider({ + tableName: tableGetMultipleCustomkeys, + keyAttr, + sortAttr, + valueAttr, +}); + +// Provider test 8, 9 +const customClient = new DynamoDBClient({}); +customClient.middlewareStack.use(middleware); +const providerWithMiddleware = new DynamoDBProvider({ + awsSdkV3Client: customClient, + tableName: tableGet, +}); + +// Helper function to call get() and log the result +const _call_get = async ( + paramName: string, + testName: string, + provider: DynamoDBProvider, + options?: DynamoDBGetOptionsInterface, +): Promise => { + try { + const parameterValue = await provider.get(paramName, options); + logger.log({ + test: testName, + value: parameterValue + }); + } catch (err) { + logger.log({ + test: testName, + error: err.message + }); + } +}; + +// Helper function to call getMultiple() and log the result +const _call_get_multiple = async ( + paramPath: string, + testName: string, + provider: DynamoDBProvider, + options?: DynamoDBGetMultipleOptionsInterface, +): Promise => { + try { + const parameterValues = await provider.getMultiple( + paramPath, + options + ); + logger.log({ + test: testName, + value: parameterValues + }); + } catch (err) { + logger.log({ + test: testName, + error: err.message + }); + } +}; + +export const handler = async (_event: unknown, _context: Context): Promise => { + // Test 1 - get a single parameter with default options (keyAttr: 'id', valueAttr: 'value') + await _call_get('my-param', 'get', providerGet); + + // Test 2 - get multiple parameters with default options (keyAttr: 'id', sortAttr: 'sk', valueAttr: 'value') + await _call_get_multiple('my-params', 'get-multiple', providerGetMultiple); + + // Test 3 - get a single parameter with custom options (keyAttr: 'key', valueAttr: 'val') + await _call_get('my-param', 'get-custom', providerGetCustomKeys); + + // Test 4 - get multiple parameters with custom options (keyAttr: 'key', sortAttr: 'sort', valueAttr: 'val') + await _call_get_multiple('my-params', 'get-multiple-custom', providerGetMultipleCustomKeys); + + // Test 5 - get a single parameter with json transform + await _call_get('my-param-json', 'get-json-transform', providerGet, { + transform: 'json' + }); + + // Test 6 - get a single parameter with binary transform + await _call_get('my-param-binary', 'get-binary-transform', providerGet, { + transform: 'binary' + }); + + // Test 7 - get multiple parameters with auto transform + await _call_get_multiple('my-encoded-params', 'get-multiple-auto-transform', providerGetMultiple, { + transform: 'auto' + }); + + // Test 8 + // get parameter twice with middleware, which counts the number of requests, we check later if we only called DynamoDB once + try { + providerWithMiddleware.clearCache(); + middleware.counter = 0; + await providerWithMiddleware.get('my-param'); + await providerWithMiddleware.get('my-param'); + logger.log({ + test: 'get-cached', + value: middleware.counter // should be 1 + }); + } catch (err) { + logger.log({ + test: 'get-cached', + error: err.message + }); + } + + // Test 9 + // get parameter twice, but force fetch 2nd time, we count number of SDK requests and check that we made two API calls + try { + providerWithMiddleware.clearCache(); + middleware.counter = 0; + await providerWithMiddleware.get('my-param'); + await providerWithMiddleware.get('my-param', { forceFetch: true }); + logger.log({ + test: 'get-forced', + value: middleware.counter // should be 2 + }); + } catch (err) { + logger.log({ + test: 'get-forced', + error: err.message + }); + } + +}; \ No newline at end of file diff --git a/packages/parameters/tests/e2e/dynamoDBProvider.class.test.ts b/packages/parameters/tests/e2e/dynamoDBProvider.class.test.ts new file mode 100644 index 0000000000..62e8bd6c39 --- /dev/null +++ b/packages/parameters/tests/e2e/dynamoDBProvider.class.test.ts @@ -0,0 +1,458 @@ +/** + * Test DynamoDBProvider class + * + * @group e2e/parameters/dynamodb/class + */ +import path from 'path'; +import { AttributeType } from 'aws-cdk-lib/aws-dynamodb'; +import { App, Stack, Aspects } from 'aws-cdk-lib'; +import { v4 } from 'uuid'; +import { + generateUniqueName, + isValidRuntimeKey, + createStackWithLambdaFunction, + invokeFunction, +} from '../../../commons/tests/utils/e2eUtils'; +import { InvocationLogs } from '../../../commons/tests/utils/InvocationLogs'; +import { deployStack, destroyStack } from '../../../commons/tests/utils/cdk-cli'; +import { ResourceAccessGranter } from '../helpers/cdkAspectGrantAccess'; +import { + RESOURCE_NAME_PREFIX, + SETUP_TIMEOUT, + TEARDOWN_TIMEOUT, + TEST_CASE_TIMEOUT +} from './constants'; +import { createDynamoDBTable, putDynamoDBItem } from '../helpers/parametersUtils'; + +const runtime: string = process.env.RUNTIME || 'nodejs18x'; + +if (!isValidRuntimeKey(runtime)) { + throw new Error(`Invalid runtime key value: ${runtime}`); +} + +const uuid = v4(); +const stackName = generateUniqueName(RESOURCE_NAME_PREFIX, uuid, runtime, 'dynamoDBProvider'); +const functionName = generateUniqueName(RESOURCE_NAME_PREFIX, uuid, runtime, 'dynamoDBProvider'); +const lambdaFunctionCodeFile = 'dynamoDBProvider.class.test.functionCode.ts'; + +const invocationCount = 1; + +// Parameters to be used by Parameters in the Lambda function +const tableGet = generateUniqueName(RESOURCE_NAME_PREFIX, uuid, runtime, 'Table-Get'); +const tableGetMultiple = generateUniqueName(RESOURCE_NAME_PREFIX, uuid, runtime, 'Table-GetMultiple'); +const tableGetCustomkeys = generateUniqueName(RESOURCE_NAME_PREFIX, uuid, runtime, 'Table-GetCustomKeys'); +const tableGetMultipleCustomkeys = generateUniqueName(RESOURCE_NAME_PREFIX, uuid, runtime, 'Table-GetMultipleCustomKeys'); +const keyAttr = 'key'; +const sortAttr = 'sort'; +const valueAttr = 'val'; + +const integTestApp = new App(); +let stack: Stack; + +/** + * This test suite deploys a CDK stack with a Lambda function and a number of DynamoDB tables. + * The function code uses the Parameters utility to retrieve values from the DynamoDB tables. + * It then logs the values to CloudWatch Logs as JSON. + * + * Once the stack is deployed, the Lambda function is invoked and the CloudWatch Logs are retrieved. + * The logs are then parsed and the values are compared to the expected values in each test case. + * + * The tables are populated with data before the Lambda function is invoked. These tables and values + * allow to test the different use cases of the DynamoDBProvider class. + * + * The tables are: + * + * - Table-Get: a table with a single partition key (id) and attribute (value) + * +-----------------+----------------------+ + * | id | value | + * +-----------------+----------------------+ + * | my-param | foo | + * | my-param-json | "{\"foo\": \"bar\"}" | + * | my-param-binary | "YmF6" | + * +-----------------+----------------------+ + * + * - Table-GetMultiple: a table with a partition key (id) and a sort key (sk) and attribute (value) + * +-------------------+---------------+----------------------+ + * | id | sk | value | + * +-------------------+---------------+----------------------+ + * | my-params | config | bar | + * | my-params | key | baz | + * | my-encoded-params | config.json | "{\"foo\": \"bar\"}" | + * | my-encoded-params | config.binary | "YmF6" | + * +-------------------+---------------+----------------------+ + * + * - Table-GetCustomKeys: a table with a single partition key (key) and attribute (val) + * +-----------------+----------------------+ + * | key | val | + * +-----------------+----------------------+ + * | my-param | foo | + * +-----------------+----------------------+ + * + * - Table-GetMultipleCustomKeys: a table with a partition key (key) and a sort key (sort) and attribute (val) + * +-------------------+---------------+----------------------+ + * | key | sort | val | + * +-------------------+---------------+----------------------+ + * | my-params | config | bar | + * | my-params | key | baz | + * +-------------------+---------------+----------------------+ + * + * The tests are: + * + * Test 1 + * Get a single parameter with default options (keyAttr: 'id', valueAttr: 'value') from table Table-Get + * + * Test 2 + * Get multiple parameters with default options (keyAttr: 'id', sortAttr: 'sk', valueAttr: 'value') from table Table-GetMultiple + * + * Test 3 + * Get a single parameter with custom options (keyAttr: 'key', valueAttr: 'val') from table Table-GetCustomKeys + * + * Test 4 + * Get multiple parameters with custom options (keyAttr: 'key', sortAttr: 'sort', valueAttr: 'val') from table Table-GetMultipleCustomKeys + * + * Test 5 + * Get a single JSON parameter with default options (keyAttr: 'id', valueAttr: 'value') and transform from table Table-Get + * + * Test 6 + * Get a single binrary parameter with default options (keyAttr: 'id', valueAttr: 'value') and transform it from table Table-Get + * + * Test 7 + * Get multiple JSON and binary parameters with default options (keyAttr: 'id', sortAttr: 'sk', valueAttr: 'value') and transform them automatically from table Table-GetMultiple + * + * Test 8 + * Get a parameter twice and check that the value is cached. This uses a custom SDK client that counts the number of calls to DynamoDB. + * + * Test 9 + * Get a cached parameter and force retrieval. This also uses the same custom SDK client that counts the number of calls to DynamoDB. + */ +describe(`parameters E2E tests (dynamoDBProvider) for runtime: ${runtime}`, () => { + + let invocationLogs: InvocationLogs[]; + + beforeAll(async () => { + // Create a stack with a Lambda function + stack = createStackWithLambdaFunction({ + app: integTestApp, + stackName, + functionName, + functionEntry: path.join(__dirname, lambdaFunctionCodeFile), + environment: { + UUID: uuid, + + // Values(s) to be used by Parameters in the Lambda function + TABLE_GET: tableGet, + TABLE_GET_MULTIPLE: tableGetMultiple, + TABLE_GET_CUSTOM_KEYS: tableGetCustomkeys, + TABLE_GET_MULTIPLE_CUSTOM_KEYS: tableGetMultipleCustomkeys, + KEY_ATTR: keyAttr, + SORT_ATTR: sortAttr, + VALUE_ATTR: valueAttr, + }, + runtime, + }); + + // Create the DynamoDB tables + const ddbTableGet = createDynamoDBTable({ + stack, + id: 'Table-get', + tableName: tableGet, + partitionKey: { + name: 'id', + type: AttributeType.STRING + }, + }); + const ddbTableGetMultiple = createDynamoDBTable({ + stack, + id: 'Table-getMultiple', + tableName: tableGetMultiple, + partitionKey: { + name: 'id', + type: AttributeType.STRING + }, + sortKey: { + name: 'sk', + type: AttributeType.STRING + } + }); + const ddbTableGetCustomKeys = createDynamoDBTable({ + stack, + id: 'Table-getCustomKeys', + tableName: tableGetCustomkeys, + partitionKey: { + name: keyAttr, + type: AttributeType.STRING + }, + }); + const ddbTabelGetMultipleCustomKeys = createDynamoDBTable({ + stack, + id: 'Table-getMultipleCustomKeys', + tableName: tableGetMultipleCustomkeys, + partitionKey: { + name: keyAttr, + type: AttributeType.STRING + }, + sortKey: { + name: sortAttr, + type: AttributeType.STRING + }, + }); + + // Give the Lambda access to the DynamoDB tables + Aspects.of(stack).add(new ResourceAccessGranter([ + ddbTableGet, + ddbTableGetMultiple, + ddbTableGetCustomKeys, + ddbTabelGetMultipleCustomKeys, + ])); + + // Seed tables with test data + // Test 1 + putDynamoDBItem({ + stack, + id: 'my-param-test1', + table: ddbTableGet, + item: { + id: 'my-param', + value: 'foo', + }, + }); + + // Test 2 + putDynamoDBItem({ + stack, + id: 'my-param-test2-a', + table: ddbTableGetMultiple, + item: { + id: 'my-params', + sk: 'config', + value: 'bar', + }, + }); + putDynamoDBItem({ + stack, + id: 'my-param-test2-b', + table: ddbTableGetMultiple, + item: { + id: 'my-params', + sk: 'key', + value: 'baz', + }, + }); + + // Test 3 + putDynamoDBItem({ + stack, + id: 'my-param-test3', + table: ddbTableGetCustomKeys, + item: { + [keyAttr]: 'my-param', + [valueAttr]: 'foo', + }, + }); + + // Test 4 + putDynamoDBItem({ + stack, + id: 'my-param-test4-a', + table: ddbTabelGetMultipleCustomKeys, + item: { + [keyAttr]: 'my-params', + [sortAttr]: 'config', + [valueAttr]: 'bar', + }, + }); + putDynamoDBItem({ + stack, + id: 'my-param-test4-b', + table: ddbTabelGetMultipleCustomKeys, + item: { + [keyAttr]: 'my-params', + [sortAttr]: 'key', + [valueAttr]: 'baz', + }, + }); + + // Test 5 + putDynamoDBItem({ + stack, + id: 'my-param-test5', + table: ddbTableGet, + item: { + id: 'my-param-json', + value: JSON.stringify({ foo: 'bar' }), + }, + }); + + // Test 6 + putDynamoDBItem({ + stack, + id: 'my-param-test6', + table: ddbTableGet, + item: { + id: 'my-param-binary', + value: 'YmF6', // base64 encoded 'baz' + }, + }); + + // Test 7 + putDynamoDBItem({ + stack, + id: 'my-param-test7-a', + table: ddbTableGetMultiple, + item: { + id: 'my-encoded-params', + sk: 'config.json', + value: JSON.stringify({ foo: 'bar' }), + }, + }); + putDynamoDBItem({ + stack, + id: 'my-param-test7-b', + table: ddbTableGetMultiple, + item: { + id: 'my-encoded-params', + sk: 'key.binary', + value: 'YmF6', // base64 encoded 'baz' + }, + }); + + // Test 8 & 9 use the same items as Test 1 + + // Deploy the stack + await deployStack(integTestApp, stack); + + // and invoke the Lambda function + invocationLogs = await invokeFunction(functionName, invocationCount, 'SEQUENTIAL'); + + }, SETUP_TIMEOUT); + + describe('DynamoDBProvider usage', () => { + + // Test 1 - get a single parameter with default options (keyAttr: 'id', valueAttr: 'value') + it('should retrieve a single parameter', async () => { + + const logs = invocationLogs[0].getFunctionLogs(); + const testLog = InvocationLogs.parseFunctionLog(logs[0]); + + expect(testLog).toStrictEqual({ + test: 'get', + value: 'foo', + }); + + }, TEST_CASE_TIMEOUT); + + // Test 2 - get multiple parameters with default options (keyAttr: 'id', sortAttr: 'sk', valueAttr: 'value') + it('should retrieve multiple parameters', async () => { + + const logs = invocationLogs[0].getFunctionLogs(); + const testLog = InvocationLogs.parseFunctionLog(logs[1]); + + expect(testLog).toStrictEqual({ + test: 'get-multiple', + value: { config: 'bar', key: 'baz' }, + }); + + }, TEST_CASE_TIMEOUT); + + // Test 3 - get a single parameter with custom options (keyAttr: 'key', valueAttr: 'val') + it('should retrieve a single parameter', async () => { + + const logs = invocationLogs[0].getFunctionLogs(); + const testLog = InvocationLogs.parseFunctionLog(logs[2]); + + expect(testLog).toStrictEqual({ + test: 'get-custom', + value: 'foo', + }); + + }, TEST_CASE_TIMEOUT); + + // Test 4 - get multiple parameters with custom options (keyAttr: 'key', sortAttr: 'sort', valueAttr: 'val') + it('should retrieve multiple parameters', async () => { + + const logs = invocationLogs[0].getFunctionLogs(); + const testLog = InvocationLogs.parseFunctionLog(logs[3]); + + expect(testLog).toStrictEqual({ + test: 'get-multiple-custom', + value: { config: 'bar', key: 'baz' }, + }); + + }, TEST_CASE_TIMEOUT); + + // Test 5 - get a single parameter with json transform + it('should retrieve a single parameter with json transform', async () => { + + const logs = invocationLogs[0].getFunctionLogs(); + const testLog = InvocationLogs.parseFunctionLog(logs[4]); + + expect(testLog).toStrictEqual({ + test: 'get-json-transform', + value: { foo: 'bar' }, + }); + + }); + + // Test 6 - get a single parameter with binary transform + it('should retrieve a single parameter with binary transform', async () => { + + const logs = invocationLogs[0].getFunctionLogs(); + const testLog = InvocationLogs.parseFunctionLog(logs[5]); + + expect(testLog).toStrictEqual({ + test: 'get-binary-transform', + value: 'baz', + }); + + }); + + // Test 7 - get multiple parameters with auto transforms (json and binary) + it('should retrieve multiple parameters with auto transforms', async () => { + + const logs = invocationLogs[0].getFunctionLogs(); + const testLog = InvocationLogs.parseFunctionLog(logs[6]); + + expect(testLog).toStrictEqual({ + test: 'get-multiple-auto-transform', + value: { + 'config.json': { foo: 'bar' }, + 'key.binary': 'baz', + }, + }); + + }); + + // Test 8 - Get a parameter twice and check that the value is cached. + it('should retrieve multiple parameters with auto transforms', async () => { + + const logs = invocationLogs[0].getFunctionLogs(); + const testLog = InvocationLogs.parseFunctionLog(logs[7]); + + expect(testLog).toStrictEqual({ + test: 'get-cached', + value: 1, + }); + + }); + + // Test 9 - Get a cached parameter and force retrieval. + it('should retrieve multiple parameters with auto transforms', async () => { + + const logs = invocationLogs[0].getFunctionLogs(); + const testLog = InvocationLogs.parseFunctionLog(logs[8]); + + expect(testLog).toStrictEqual({ + test: 'get-forced', + value: 2, + }); + + }); + + }); + + afterAll(async () => { + if (!process.env.DISABLE_TEARDOWN) { + await destroyStack(integTestApp, stack); + } + }, TEARDOWN_TIMEOUT); +}); diff --git a/packages/parameters/tests/e2e/secretsProvider.class.test.functionCode.ts b/packages/parameters/tests/e2e/secretsProvider.class.test.functionCode.ts new file mode 100644 index 0000000000..a1bd955919 --- /dev/null +++ b/packages/parameters/tests/e2e/secretsProvider.class.test.functionCode.ts @@ -0,0 +1,95 @@ +import { Context } from 'aws-lambda'; +import { TinyLogger } from '../helpers/tinyLogger'; +import { SecretsManagerClient } from '@aws-sdk/client-secrets-manager'; +import { middleware } from '../helpers/sdkMiddlewareRequestCounter'; +import { SecretsProvider } from '../../src/secrets'; +import { SecretsGetOptionsInterface } from '../../src/types'; + +const logger = new TinyLogger(); +const defaultProvider = new SecretsProvider(); + +const secretNamePlain = process.env.SECRET_NAME_PLAIN || ''; +const secretNameObject = process.env.SECRET_NAME_OBJECT || ''; +const secretNameBinary = process.env.SECRET_NAME_BINARY || ''; +const secretNameObjectWithSuffix = process.env.SECRET_NAME_OBJECT_WITH_SUFFIX || ''; +const secretNameBinaryWithSuffix = process.env.SECRET_NAME_BINARY_WITH_SUFFIX || ''; +const secretNamePlainChached = process.env.SECRET_NAME_PLAIN_CACHED || ''; +const secretNamePlainForceFetch = process.env.SECRET_NAME_PLAIN_FORCE_FETCH || ''; + +// Provider test 8, 9 +const customClient = new SecretsManagerClient({}); +customClient.middlewareStack.use(middleware); +const providerWithMiddleware = new SecretsProvider({ + awsSdkV3Client: customClient +}); + +const _call_get = async (paramName: string, testName: string, options?: SecretsGetOptionsInterface, provider?: SecretsProvider,): Promise => { + try { + // we might get a provider with specific sdk options, otherwise fallback to default + const currentProvider = provider ? provider : defaultProvider; + + const parameterValue = await currentProvider.get(paramName, options); + logger.log({ + test: testName, + value: parameterValue + }); + } catch (err) { + logger.log({ + test: testName, + error: err.message + }); + } +}; + +export const handler = async (_event: unknown, _context: Context): Promise => { + + // Test 1 get single secret as plaintext + await _call_get(secretNamePlain, 'get-plain'); + + // Test 2 get single secret with transform json + await _call_get(secretNameObject, 'get-transform-json', { transform: 'json' }); + + // Test 3 get single secret with transform binary + await _call_get(secretNameBinary, 'get-transform-binary', { transform: 'binary' }); + + // Test 4 get single secret with transform auto json + await _call_get(secretNameObjectWithSuffix, 'get-transform-auto-json', { transform: 'auto' }); + + // Test 5 get single secret with transform auto binary + await _call_get(secretNameBinaryWithSuffix, 'get-transform-auto-binary', { transform: 'auto' }); + + // Test 6 + // get secret twice with middleware, which counts number of SDK requests, we check later if we only called SecretManager API once + try { + middleware.counter = 0; + await providerWithMiddleware.get(secretNamePlainChached); + await providerWithMiddleware.get(secretNamePlainChached); + logger.log({ + test: 'get-plain-cached', + value: middleware.counter // should be 1 + }); + } catch (err) { + logger.log({ + test: secretNamePlainChached, + error: err.message + }); + } + // Test 7 + // get secret twice, but force fetch 2nd time, we count number of SDK requests and check that we made two API calls + try { + middleware.counter = 0; + providerWithMiddleware.clearCache(); + await providerWithMiddleware.get(secretNamePlainForceFetch); + await providerWithMiddleware.get(secretNamePlainForceFetch, { forceFetch: true }); + logger.log({ + test: 'get-plain-force', + value: middleware.counter // should be 2 + }); + } catch (err) { + logger.log({ + test: secretNamePlainChached, + error: err.message + }); + } + +}; diff --git a/packages/parameters/tests/e2e/secretsProvider.class.test.ts b/packages/parameters/tests/e2e/secretsProvider.class.test.ts new file mode 100644 index 0000000000..48e2734974 --- /dev/null +++ b/packages/parameters/tests/e2e/secretsProvider.class.test.ts @@ -0,0 +1,222 @@ +/** + * Test SecretsPorovider class + * + * @group e2e/parameters/secrets/class + */ +import { + createStackWithLambdaFunction, + generateUniqueName, + invokeFunction, + isValidRuntimeKey +} from '../../../commons/tests/utils/e2eUtils'; +import { RESOURCE_NAME_PREFIX, SETUP_TIMEOUT, TEARDOWN_TIMEOUT, TEST_CASE_TIMEOUT } from './constants'; +import { v4 } from 'uuid'; +import { Tracing } from 'aws-cdk-lib/aws-lambda'; +import { deployStack, destroyStack } from '../../../commons/tests/utils/cdk-cli'; +import { App, Aspects, SecretValue, Stack } from 'aws-cdk-lib'; +import path from 'path'; +import { Secret } from 'aws-cdk-lib/aws-secretsmanager'; +import { InvocationLogs } from '../../../commons/tests/utils/InvocationLogs'; +import { ResourceAccessGranter } from '../helpers/cdkAspectGrantAccess'; + +const runtime: string = process.env.RUNTIME || 'nodejs18x'; + +if (!isValidRuntimeKey(runtime)) { + throw new Error(`Invalid runtime key: ${runtime}`); +} +/** + * Collection of e2e tests for SecretsProvider utility. + * + * Test 1: create a secret with plain text value, fetch it with no additional options + * Test 2: create a secret with json value, fetch it using `transform: 'json'` option + * Test 3: create a secret with base64 encoded value (technicaly string), fetch it using `transform: 'binary'` option + * Test 4: create a secret with json value and secret name ends with .json, fetch it using `transform: 'auto'` option + * Test 5: create a secret with base64 encoded value (technicaly string) and secert name ends with .binary, fetch it using `transform: 'auto'` option + * Test 6: create a secret with plain text value, fetch it twice, check that value was cached, the number of SDK calls should be 1 + * Test 7: create a secret with plain text value, fetch it twice, second time with `forceFetch: true` option, check that value was not cached, the number of SDK calls should be 2 + * + * For tests 6 and 7 we use our own AWS SDK custom middleware plugin `sdkMiddlewareRequestCounter.ts` + * + * Adding new test: + * Please keep the state clean, and create dedicated resource for your test, don't reuse resources from other tests. + * Pass the necessary information to lambda function by using enviroment variables + * Make sure to add the right permissions to the lambda function to access the resources. We use our `ResourceAccessGranter` to add permissions. + * + */ +describe(`parameters E2E tests (SecretsProvider) for runtime: ${runtime}`, () => { + + const uuid = v4(); + let invocationLogs: InvocationLogs[]; + const stackName = generateUniqueName(RESOURCE_NAME_PREFIX, uuid, runtime, 'secretsProvider'); + const functionName = generateUniqueName(RESOURCE_NAME_PREFIX, uuid, runtime, 'secretsProvider'); + const lambdaFunctionCodeFile = 'secretsProvider.class.test.functionCode.ts'; + + const invocationCount = 1; + + const integTestApp = new App(); + let stack: Stack; + + beforeAll(async () => { + + // use unique names for each test to keep a clean state + const secretNamePlain = generateUniqueName(RESOURCE_NAME_PREFIX, uuid, runtime, 'testSecretPlain'); + const secretNameObject = generateUniqueName(RESOURCE_NAME_PREFIX, uuid, runtime, 'testSecretObject'); + const secretNameBinary = generateUniqueName(RESOURCE_NAME_PREFIX, uuid, runtime, 'testSecretBinary'); + const secretNameObjectWithSuffix = generateUniqueName(RESOURCE_NAME_PREFIX, uuid, runtime, 'testSecretObject.json'); + const secretNameBinaryWithSuffix = generateUniqueName(RESOURCE_NAME_PREFIX, uuid, runtime, 'testSecretObject.binary'); + const secretNamePlainCached = generateUniqueName(RESOURCE_NAME_PREFIX, uuid, runtime, 'testSecretPlainCached'); + const secretNamePlainForceFetch = generateUniqueName(RESOURCE_NAME_PREFIX, uuid, runtime, 'testSecretPlainForceFetch'); + + // creates the test fuction that uses powertools secret provider we want to test + // pass env vars with secret names we want to fetch + stack = createStackWithLambdaFunction({ + app: integTestApp, + stackName: stackName, + functionName: functionName, + functionEntry: path.join(__dirname, lambdaFunctionCodeFile), + tracing: Tracing.ACTIVE, + environment: { + UUID: uuid, + SECRET_NAME_PLAIN: secretNamePlain, + SECRET_NAME_OBJECT: secretNameObject, + SECRET_NAME_BINARY: secretNameBinary, + SECRET_NAME_OBJECT_WITH_SUFFIX: secretNameObjectWithSuffix, + SECRET_NAME_BINARY_WITH_SUFFIX: secretNameBinaryWithSuffix, + SECRET_NAME_PLAIN_CACHED: secretNamePlainCached, + SECRET_NAME_PLAIN_FORCE_FETCH: secretNamePlainForceFetch, + }, + runtime: runtime + }); + + const secretString = new Secret(stack, 'testSecretPlain', { + secretName: secretNamePlain, + secretStringValue: SecretValue.unsafePlainText('foo') + }); + + const secretObject = new Secret(stack, 'testSecretObject', { + secretName: secretNameObject, + secretObjectValue: { + foo: SecretValue.unsafePlainText('bar'), + } + }); + + const secretBinary = new Secret(stack, 'testSecretBinary', { + secretName: secretNameBinary, + secretStringValue: SecretValue.unsafePlainText('Zm9v') // 'foo' encoded in base64 + }); + + const secretObjectWithSuffix = new Secret(stack, 'testSecretObjectWithSuffix', { + secretName: secretNameObjectWithSuffix, + secretObjectValue: { + foo: SecretValue.unsafePlainText('bar') + } + }); + + const secretBinaryWithSuffix = new Secret(stack, 'testSecretBinaryWithSuffix', { + secretName: secretNameBinaryWithSuffix, + secretStringValue: SecretValue.unsafePlainText('Zm9v') // 'foo' encoded in base64 + }); + + const secretStringCached = new Secret(stack, 'testSecretStringCached', { + secretName: secretNamePlainCached, + secretStringValue: SecretValue.unsafePlainText('foo') + }); + + const secretStringForceFetch = new Secret(stack, 'testSecretStringForceFetch', { + secretName: secretNamePlainForceFetch, + secretStringValue: SecretValue.unsafePlainText('foo') + }); + + // add secrets here to grant lambda permisisons to access secrets + Aspects.of(stack).add(new ResourceAccessGranter([ + secretString, secretObject, secretBinary, secretObjectWithSuffix, secretBinaryWithSuffix, secretStringCached, secretStringForceFetch ])); + + await deployStack(integTestApp, stack); + + invocationLogs = await invokeFunction(functionName, invocationCount, 'SEQUENTIAL'); + + }, SETUP_TIMEOUT); + + describe('SecretsProvider usage', () => { + + it('should retrieve a secret as plain string', async () => { + + const logs = invocationLogs[0].getFunctionLogs(); + const testLog = InvocationLogs.parseFunctionLog(logs[0]); + + expect(testLog).toStrictEqual({ + test: 'get-plain', + value: 'foo' + }); + }, TEST_CASE_TIMEOUT); + + it('should retrieve a secret using transform json option', async () => { + const logs = invocationLogs[0].getFunctionLogs(); + const testLog = InvocationLogs.parseFunctionLog(logs[1]); + + expect(testLog).toStrictEqual({ + test: 'get-transform-json', + value: { foo: 'bar' } + }); + }, TEST_CASE_TIMEOUT); + + it('should retrieve a secret using transform binary option', async () => { + const logs = invocationLogs[0].getFunctionLogs(); + const testLog = InvocationLogs.parseFunctionLog(logs[2]); + + expect(testLog).toStrictEqual({ + test: 'get-transform-binary', + value: 'foo' + }); + }, TEST_CASE_TIMEOUT); + }); + + it('should retrieve a secret using transform auto option with implicit json', async () => { + const logs = invocationLogs[0].getFunctionLogs(); + const testLog = InvocationLogs.parseFunctionLog(logs[3]); + + // result should be a json object + expect(testLog).toStrictEqual({ + test: 'get-transform-auto-json', + value: { foo: 'bar' } + }); + }, TEST_CASE_TIMEOUT); + + it('should retrieve a secret using transform auto option with implicit binary', async () => { + const logs = invocationLogs[0].getFunctionLogs(); + const testLog = InvocationLogs.parseFunctionLog(logs[4]); + + expect(testLog).toStrictEqual({ + test: 'get-transform-auto-binary', + value: 'foo' + }); + }); + + it('should retrieve a secret twice with cached value', async () => { + const logs = invocationLogs[0].getFunctionLogs(); + const testLogFirst = InvocationLogs.parseFunctionLog(logs[5]); + + // we fetch twice, but we expect to make an API call only once + expect(testLogFirst).toStrictEqual({ + test: 'get-plain-cached', + value: 1 + }); + }); + + it('should retrieve a secret twice with forceFetch second time', async () => { + const logs = invocationLogs[0].getFunctionLogs(); + const testLogFirst = InvocationLogs.parseFunctionLog(logs[6]); + + // we fetch twice, 2nd time with forceFetch: true flag, we expect two api calls + expect(testLogFirst).toStrictEqual({ + test: 'get-plain-force', + value: 2 + }); + }); + + afterAll(async () => { + if (!process.env.DISABLE_TEARDOWN) { + await destroyStack(integTestApp, stack); + } + }, TEARDOWN_TIMEOUT); +}); \ No newline at end of file diff --git a/packages/parameters/tests/e2e/ssmProvider.class.test.functionCode.ts b/packages/parameters/tests/e2e/ssmProvider.class.test.functionCode.ts new file mode 100644 index 0000000000..4f0280f0a8 --- /dev/null +++ b/packages/parameters/tests/e2e/ssmProvider.class.test.functionCode.ts @@ -0,0 +1,183 @@ +import { Context } from 'aws-lambda'; +import { + SSMProvider, +} from '../../src/ssm'; +import { + SSMGetOptionsInterface, + SSMGetMultipleOptionsInterface, + SSMGetParametersByNameOptionsInterface +} from '../../src/types'; +import { TinyLogger } from '../helpers/tinyLogger'; +import { middleware } from '../helpers/sdkMiddlewareRequestCounter'; +import { SSMClient } from '@aws-sdk/client-ssm'; + +// We use a custom logger to log pure JSON objects to stdout +const logger = new TinyLogger(); + +const defaultProvider = new SSMProvider(); +// Provider test 8, 9 +const customClient = new SSMClient({}); +customClient.middlewareStack.use(middleware); +const providerWithMiddleware = new SSMProvider({ + awsSdkV3Client: customClient +}); + +const paramA = process.env.PARAM_A ?? 'my-param'; +const paramB = process.env.PARAM_B ?? 'my-param'; +const paramEncryptedA = process.env.PARAM_ENCRYPTED_A ?? 'my-encrypted-param'; +const paramEncryptedB = process.env.PARAM_ENCRYPTED_B ?? 'my-encrypted-param'; + +// Use provider specified, or default to main one & return it with cache cleared +const resolveProvider = (provider?: SSMProvider): SSMProvider => { + const resolvedProvider = provider ? provider : defaultProvider; + resolvedProvider.clearCache(); + + return resolvedProvider; +}; + +// Helper function to call get() and log the result +const _call_get = async ( + paramName: string, + testName: string, + options?: SSMGetOptionsInterface, + provider?: SSMProvider +): Promise => { + try { + const currentProvider = resolveProvider(provider); + + const parameterValue = await currentProvider.get(paramName, options); + logger.log({ + test: testName, + value: parameterValue + }); + } catch (err) { + logger.log({ + test: testName, + error: err.message + }); + } +}; + +// Helper function to call getMultiple() and log the result +const _call_get_multiple = async ( + paramPath: string, + testName: string, + options?: SSMGetMultipleOptionsInterface, + provider?: SSMProvider +): Promise => { + try { + const currentProvider = resolveProvider(provider); + + const parameterValues = await currentProvider.getMultiple( + paramPath, + options + ); + logger.log({ + test: testName, + value: parameterValues + }); + } catch (err) { + logger.log({ + test: testName, + error: err.message + }); + } +}; + +// Helper function to call getParametersByName() and log the result +const _call_get_parameters_by_name = async ( + params: Record, + testName: string, + options?: SSMGetParametersByNameOptionsInterface, + provider?: SSMProvider +): Promise => { + try { + const currentProvider = resolveProvider(provider); + + const parameterValues = await currentProvider.getParametersByName(params, options); + logger.log({ + test: testName, + value: parameterValues + }); + } catch (err) { + logger.log({ + test: testName, + error: err.message + }); + } +}; + +export const handler = async (_event: unknown, _context: Context): Promise => { + // Test 1 - get a single parameter by name with default options + await _call_get(paramA, 'get'); + + // Test 2 - get a single parameter by name with decrypt + await _call_get(paramEncryptedA, 'get-decrypt', { decrypt: true }); + + // Test 3 - get multiple parameters by path with default options + // Get path (/param/get) + const parameterPath = paramA.substring(0, paramA.lastIndexOf('/')); + await _call_get_multiple(parameterPath, 'get-multiple'); + + // Test 4 - get multiple parameters by path recursively (aka. get all parameters under a path recursively) + // Get parameters root (i.e. from /param/get/a & /param/get/b to /param) + const parameterRoot = paramA.substring( + 0, + paramA.substring(1, paramA.length).indexOf('/') + 1 + ); + await _call_get_multiple(parameterRoot, 'get-multiple-recursive', { recursive: true }); + + // Test 5 - get multiple parameters by path with decrypt + // Get parameters path (i.e. from /param/get/a & /param/get/b to /param/get) + const parameterPathDecrypt = paramEncryptedA.substring(0, paramEncryptedA.lastIndexOf('/')); + await _call_get_multiple(parameterPathDecrypt, 'get-multiple-decrypt', { decrypt: true }); + + // Test 6 - get multiple parameters by name with default options + await _call_get_parameters_by_name({ + [paramA]: {}, + [paramB]: {}, + }, 'get-multiple-by-name'); + + // Test 7 - get multiple parameters by name, some of them encrypted and some not + await _call_get_parameters_by_name({ + [paramA]: {}, + [paramEncryptedA]: { decrypt: true }, + [paramEncryptedB]: { decrypt: true }, + }, 'get-multiple-by-name-mixed-decrypt'); + + // Test 8 + // get parameter twice with middleware, which counts the number of requests, we check later if we only called SSM API once + try { + providerWithMiddleware.clearCache(); + middleware.counter = 0; + await providerWithMiddleware.get(paramA); + await providerWithMiddleware.get(paramA); + logger.log({ + test: 'get-cached', + value: middleware.counter // should be 1 + }); + } catch (err) { + logger.log({ + test: 'get-cached', + error: err.message + }); + } + + // Test 9 + // get parameter twice, but force fetch 2nd time, we count number of SDK requests and check that we made two API calls + try { + providerWithMiddleware.clearCache(); + middleware.counter = 0; + await providerWithMiddleware.get(paramA); + await providerWithMiddleware.get(paramA, { forceFetch: true }); + logger.log({ + test: 'get-forced', + value: middleware.counter // should be 2 + }); + } catch (err) { + logger.log({ + test: 'get-forced', + error: err.message + }); + } +}; \ No newline at end of file diff --git a/packages/parameters/tests/e2e/ssmProvider.class.test.ts b/packages/parameters/tests/e2e/ssmProvider.class.test.ts new file mode 100644 index 0000000000..fb7f3e56f4 --- /dev/null +++ b/packages/parameters/tests/e2e/ssmProvider.class.test.ts @@ -0,0 +1,323 @@ +/** + * Test SSMProvider class + * + * @group e2e/parameters/ssm/class + */ +import path from 'path'; +import { App, Stack, Aspects } from 'aws-cdk-lib'; +import { StringParameter } from 'aws-cdk-lib/aws-ssm'; +import { v4 } from 'uuid'; +import { + generateUniqueName, + isValidRuntimeKey, + createStackWithLambdaFunction, + invokeFunction, +} from '../../../commons/tests/utils/e2eUtils'; +import { InvocationLogs } from '../../../commons/tests/utils/InvocationLogs'; +import { deployStack, destroyStack } from '../../../commons/tests/utils/cdk-cli'; +import { ResourceAccessGranter } from '../helpers/cdkAspectGrantAccess'; +import { + RESOURCE_NAME_PREFIX, + SETUP_TIMEOUT, + TEARDOWN_TIMEOUT, + TEST_CASE_TIMEOUT +} from './constants'; +import { createSSMSecureString } from '../helpers/parametersUtils'; + +const runtime: string = process.env.RUNTIME || 'nodejs18x'; + +if (!isValidRuntimeKey(runtime)) { + throw new Error(`Invalid runtime key value: ${runtime}`); +} + +const uuid = v4(); +const stackName = generateUniqueName(RESOURCE_NAME_PREFIX, uuid, runtime, 'ssmProvider'); +const functionName = generateUniqueName(RESOURCE_NAME_PREFIX, uuid, runtime, 'ssmProvider'); +const lambdaFunctionCodeFile = 'ssmProvider.class.test.functionCode.ts'; + +const invocationCount = 1; + +// Parameter names to be used by Parameters in the Lambda function +const paramA = generateUniqueName(`/${RESOURCE_NAME_PREFIX}`, uuid, runtime, 'param/a'); +const paramB = generateUniqueName(`/${RESOURCE_NAME_PREFIX}`, uuid, runtime, 'param/b'); +const paramEncryptedA = generateUniqueName(`/${RESOURCE_NAME_PREFIX}`, uuid, runtime, 'param-encrypted/a'); +const paramEncryptedB = generateUniqueName(`/${RESOURCE_NAME_PREFIX}`, uuid, runtime, 'param-encrypted/b'); + +// Parameters values +const paramAValue = 'foo'; +const paramBValue = 'bar'; +const paramEncryptedAValue = 'foo-encrypted'; +const paramEncryptedBValue = 'bar-encrypted'; + +const integTestApp = new App(); +let stack: Stack; + +/** + * This test suite deploys a CDK stack with a Lambda function and a number of SSM parameters. + * The function code uses the Parameters utility to retrieve the SSM parameters. + * It then logs the values to CloudWatch Logs as JSON objects. + * + * Once the stack is deployed, the Lambda function is invoked and the CloudWatch Logs are retrieved. + * The logs are then parsed and the values are checked against the expected values for each test case. + * + * The parameters created are: + * - Name: param/a - Value: foo + * - Name: param/b - Value: bar + * - Name: param-encrypted/a - Value: foo-encrypted + * - Name: param-encrypted/b - Value: bar-encrypted + * + * These parameters allow to retrieve one or more parameters both by name and by path, as well as + * mixing encrypted and unencrypted parameters. + * + * The tests are: + * + * Test 1 + * get a single parameter by name with default options + * + * Test 2 + * get a single parameter by name with decrypt + * + * Test 3 + * get multiple parameters by path with default options + * + * Test 4 + * get multiple parameters by path recursively (aka. get all parameters under a path recursively) + * i.e. given /param, retrieve /param/get/a and /param/get/b (note path depth) + * + * Test 5 + * get multiple parameters by path with decrypt + * + * Test 6 + * get multiple parameters by name with default options + * + * Test 7 + * get multiple parameters by name, some of them encrypted and some not + * + * Test 8 + * get parameter twice with middleware, which counts the number of requests, + * we check later if we only called SSM API once + * + * Test 9 + * get parameter twice, but force fetch 2nd time, we count number of SDK requests and + * check that we made two API calls + */ +describe(`parameters E2E tests (ssmProvider) for runtime: ${runtime}`, () => { + + let invocationLogs: InvocationLogs[]; + + beforeAll(async () => { + // Create a stack with a Lambda function + stack = createStackWithLambdaFunction({ + app: integTestApp, + stackName, + functionName, + functionEntry: path.join(__dirname, lambdaFunctionCodeFile), + environment: { + UUID: uuid, + + // Values(s) to be used by Parameters in the Lambda function + PARAM_A: paramA, + PARAM_B: paramB, + PARAM_ENCRYPTED_A: paramEncryptedA, + PARAM_ENCRYPTED_B: paramEncryptedB, + }, + runtime, + }); + + // Create SSM parameters + const parameterGetA = new StringParameter(stack, 'Param-a', { + parameterName: paramA, + stringValue: paramAValue, + }); + const parameterGetB = new StringParameter(stack, 'Param-b', { + parameterName: paramB, + stringValue: paramBValue, + }); + + const parameterEncryptedA = createSSMSecureString({ + stack, + id: 'Param-encrypted-a', + name: paramEncryptedA, + value: paramEncryptedAValue, + }); + + const parameterEncryptedB = createSSMSecureString({ + stack, + id: 'Param-encrypted-b', + name: paramEncryptedB, + value: paramEncryptedBValue, + }); + + // Give the Lambda function access to the SSM parameters + Aspects.of(stack).add(new ResourceAccessGranter([ + parameterGetA, + parameterGetB, + parameterEncryptedA, + parameterEncryptedB, + ])); + + // Deploy the stack + await deployStack(integTestApp, stack); + + // and invoke the Lambda function + invocationLogs = await invokeFunction(functionName, invocationCount, 'SEQUENTIAL'); + + }, SETUP_TIMEOUT); + + describe('SSMProvider usage', () => { + + // Test 1 - get a single parameter by name with default options + it('should retrieve a single parameter', async () => { + + const logs = invocationLogs[0].getFunctionLogs(); + const testLog = InvocationLogs.parseFunctionLog(logs[0]); + + expect(testLog).toStrictEqual({ + test: 'get', + value: paramAValue + }); + + }, TEST_CASE_TIMEOUT); + + // Test 2 - get a single parameter by name with decrypt + it('should retrieve a single parameter with decryption', async () => { + + const logs = invocationLogs[0].getFunctionLogs(); + const testLog = InvocationLogs.parseFunctionLog(logs[1]); + + expect(testLog).toStrictEqual({ + test: 'get-decrypt', + value: paramEncryptedAValue + }); + + }, TEST_CASE_TIMEOUT); + + // Test 3 - get multiple parameters by path with default options + it('should retrieve multiple parameters', async () => { + + const logs = invocationLogs[0].getFunctionLogs(); + const testLog = InvocationLogs.parseFunctionLog(logs[2]); + const expectedParameterNameA = paramA.substring(paramA.lastIndexOf('/') + 1); + const expectedParameterNameB = paramB.substring(paramB.lastIndexOf('/') + 1); + + expect(testLog).toStrictEqual({ + test: 'get-multiple', + value: { + [expectedParameterNameA]: paramAValue, + [expectedParameterNameB]: paramBValue, + } + }); + + }, TEST_CASE_TIMEOUT); + + // Test 4 - get multiple parameters by path recursively + // (aka. get all parameters under a path recursively) i.e. + // given /param, retrieve /param/get/a and /param/get/b (note path depth) + it('should retrieve multiple parameters recursively', async () => { + + const logs = invocationLogs[0].getFunctionLogs(); + const testLog = InvocationLogs.parseFunctionLog(logs[3]); + const expectedParameterNameA = paramA.substring(paramA.lastIndexOf('/') + 1); + const expectedParameterNameB = paramB.substring(paramB.lastIndexOf('/') + 1); + + expect(testLog).toStrictEqual({ + test: 'get-multiple-recursive', + value: { + [expectedParameterNameA]: paramAValue, + [expectedParameterNameB]: paramBValue, + } + }); + + }, TEST_CASE_TIMEOUT); + + it('should retrieve multiple parameters with decryption', async () => { + + const logs = invocationLogs[0].getFunctionLogs(); + const testLog = InvocationLogs.parseFunctionLog(logs[4]); + const expectedParameterNameA = paramEncryptedA.substring( + paramEncryptedA.lastIndexOf('/') + 1 + ); + const expectedParameterNameB = paramEncryptedB.substring( + paramEncryptedB.lastIndexOf('/') + 1 + ); + + expect(testLog).toStrictEqual({ + test: 'get-multiple-decrypt', + value: { + [expectedParameterNameA]: paramEncryptedAValue, + [expectedParameterNameB]: paramEncryptedBValue, + } + }); + + }, TEST_CASE_TIMEOUT); + + // Test 6 - get multiple parameters by name with default options + it('should retrieve multiple parameters by name', async () => { + + const logs = invocationLogs[0].getFunctionLogs(); + const testLog = InvocationLogs.parseFunctionLog(logs[5]); + + expect(testLog).toStrictEqual({ + test: 'get-multiple-by-name', + value: { + [paramA]: paramAValue, + [paramB]: paramBValue, + } + }); + + }, TEST_CASE_TIMEOUT); + + // Test 7 - get multiple parameters by name, some of them encrypted and some not + it('should retrieve multiple parameters by name with mixed decryption', async () => { + + const logs = invocationLogs[0].getFunctionLogs(); + const testLog = InvocationLogs.parseFunctionLog(logs[6]); + + expect(testLog).toStrictEqual({ + test: 'get-multiple-by-name-mixed-decrypt', + value: { + [paramEncryptedA]: paramEncryptedAValue, + [paramEncryptedB]: paramEncryptedBValue, + [paramA]: paramAValue, + } + }); + + }, TEST_CASE_TIMEOUT); + + // Test 8 - get parameter twice with middleware, which counts the number + // of requests, we check later if we only called SSM API once + it('should retrieve single parameter cached', async () => { + + const logs = invocationLogs[0].getFunctionLogs(); + const testLog = InvocationLogs.parseFunctionLog(logs[7]); + + expect(testLog).toStrictEqual({ + test: 'get-cached', + value: 1 + }); + + }, TEST_CASE_TIMEOUT); + + // Test 9 - get parameter twice, but force fetch 2nd time, + // we count number of SDK requests and check that we made two API calls + it('should retrieve single parameter twice without caching', async () => { + + const logs = invocationLogs[0].getFunctionLogs(); + const testLog = InvocationLogs.parseFunctionLog(logs[8]); + + expect(testLog).toStrictEqual({ + test: 'get-forced', + value: 2 + }); + + }, TEST_CASE_TIMEOUT); + + }); + + afterAll(async () => { + if (!process.env.DISABLE_TEARDOWN) { + await destroyStack(integTestApp, stack); + } + }, TEARDOWN_TIMEOUT); + +}); \ No newline at end of file diff --git a/packages/parameters/tests/helpers/cdkAspectGrantAccess.ts b/packages/parameters/tests/helpers/cdkAspectGrantAccess.ts new file mode 100644 index 0000000000..68f755a3fc --- /dev/null +++ b/packages/parameters/tests/helpers/cdkAspectGrantAccess.ts @@ -0,0 +1,85 @@ +import { IAspect, Stack } from 'aws-cdk-lib'; +import { IConstruct } from 'constructs'; +import { NodejsFunction } from 'aws-cdk-lib/aws-lambda-nodejs'; +import { Table } from 'aws-cdk-lib/aws-dynamodb'; +import { PolicyStatement, Effect } from 'aws-cdk-lib/aws-iam'; +import { Secret } from 'aws-cdk-lib/aws-secretsmanager'; +import { CfnDeployment } from 'aws-cdk-lib/aws-appconfig'; +import { StringParameter, IStringParameter } from 'aws-cdk-lib/aws-ssm'; + +const isStringParameterGeneric = (parameter: IConstruct): parameter is StringParameter | IStringParameter => + parameter.hasOwnProperty('parameterArn'); + +/** + * An aspect that grants access to resources to a Lambda function. + * + * In our integration tests, we dynamically generate AWS CDK stacks that contain a Lambda function. + * We want to grant access to resources to the Lambda function, but we don't know the name of the + * Lambda function at the time we create the resources. Additionally, we want to keep the code + * that creates the stacks and functions as generic as possible. + * + * This aspect allows us to grant access to specific resources to all Lambda functions in a stack + * after the stack tree has been generated and before the stack is deployed. This aspect is + * used to grant access to different resource types (DynamoDB tables, SSM parameters, etc.). + * + * @see {@link https://docs.aws.amazon.com/cdk/v2/guide/aspects.html CDK Docs - Aspects} + */ +export class ResourceAccessGranter implements IAspect { + private readonly resources: Table[] | Secret[] | StringParameter[] | IStringParameter[] | CfnDeployment[]; + + public constructor(resources: Table[] | Secret[] | StringParameter[] | IStringParameter[] | CfnDeployment[]) { + this.resources = resources; + } + + public visit(node: IConstruct): void { + // See that we're dealing with a Function + if (node instanceof NodejsFunction) { + + // Grant access to the resources + this.resources.forEach((resource: Table | Secret | StringParameter | IStringParameter | CfnDeployment) => { + + if (resource instanceof Table) { + resource.grantReadData(node); + } else if ( + resource instanceof Secret + ) { + resource.grantRead(node); + } else if (isStringParameterGeneric(resource)) { + resource.grantRead(node); + + // Grant access also to the path of the parameter + node.addToRolePolicy( + new PolicyStatement({ + effect: Effect.ALLOW, + actions: [ + 'ssm:GetParametersByPath', + ], + resources: [ + resource.parameterArn.split(':').slice(0, -1).join(':'), + ], + }), + ); + } else if (resource instanceof CfnDeployment) { + const appConfigConfigurationArn = Stack.of(node).formatArn({ + service: 'appconfig', + resource: `application/${resource.applicationId}/environment/${resource.environmentId}/configuration/${resource.configurationProfileId}`, + }); + + node.addToRolePolicy( + new PolicyStatement({ + effect: Effect.ALLOW, + actions: [ + 'appconfig:StartConfigurationSession', + 'appconfig:GetLatestConfiguration', + ], + resources: [ + appConfigConfigurationArn, + ], + }), + ); + } + + }); + } + } +} diff --git a/packages/parameters/tests/helpers/parametersUtils.ts b/packages/parameters/tests/helpers/parametersUtils.ts new file mode 100644 index 0000000000..89a8c52efc --- /dev/null +++ b/packages/parameters/tests/helpers/parametersUtils.ts @@ -0,0 +1,210 @@ +import { Stack, RemovalPolicy } from 'aws-cdk-lib'; +import { PhysicalResourceId } from 'aws-cdk-lib/custom-resources'; +import { StringParameter, IStringParameter } from 'aws-cdk-lib/aws-ssm'; +import { Table, TableProps, BillingMode } from 'aws-cdk-lib/aws-dynamodb'; +import { + CfnApplication, + CfnConfigurationProfile, + CfnDeployment, + CfnDeploymentStrategy, + CfnEnvironment, + CfnHostedConfigurationVersion, +} from 'aws-cdk-lib/aws-appconfig'; +import { + AwsCustomResource, + AwsCustomResourcePolicy +} from 'aws-cdk-lib/custom-resources'; +import { marshall } from '@aws-sdk/util-dynamodb'; + +export type CreateDynamoDBTableOptions = { + stack: Stack + id: string +} & TableProps; + +const createDynamoDBTable = (options: CreateDynamoDBTableOptions): Table => { + const { stack, id, ...tableProps } = options; + const props = { + billingMode: BillingMode.PAY_PER_REQUEST, + removalPolicy: RemovalPolicy.DESTROY, + ...tableProps, + }; + + return new Table(stack, id, props); +}; + +export type AppConfigResourcesOptions = { + stack: Stack + applicationName: string + environmentName: string + deploymentStrategyName: string +}; + +type AppConfigResourcesOutput = { + application: CfnApplication + environment: CfnEnvironment + deploymentStrategy: CfnDeploymentStrategy +}; + +/** + * Utility function to create the base resources for an AppConfig application. + */ +const createBaseAppConfigResources = (options: AppConfigResourcesOptions): AppConfigResourcesOutput => { + const { + stack, + applicationName, + environmentName, + deploymentStrategyName, + } = options; + + // create a new app config application. + const application = new CfnApplication( + stack, + 'application', + { + name: applicationName, + } + ); + + const environment = new CfnEnvironment(stack, 'environment', { + name: environmentName, + applicationId: application.ref, + }); + + const deploymentStrategy = new CfnDeploymentStrategy(stack, 'deploymentStrategy', { + name: deploymentStrategyName, + deploymentDurationInMinutes: 0, + growthFactor: 100, + replicateTo: 'NONE', + finalBakeTimeInMinutes: 0, + }); + + return { + application, + environment, + deploymentStrategy, + }; +}; + +export type CreateAppConfigConfigurationProfileOptions = { + stack: Stack + name: string + application: CfnApplication + environment: CfnEnvironment + deploymentStrategy: CfnDeploymentStrategy + type: 'AWS.Freeform' | 'AWS.AppConfig.FeatureFlags' + content: { + contentType: 'application/json' | 'application/x-yaml' | 'text/plain' + content: string + } +}; + +/** + * Utility function to create an AppConfig configuration profile and deployment. + */ +const createAppConfigConfigurationProfile = (options: CreateAppConfigConfigurationProfileOptions): CfnDeployment => { + const { + stack, + name, + application, + environment, + deploymentStrategy, + type, + content, + } = options; + + const configProfile = new CfnConfigurationProfile(stack, `${name}-configProfile`, { + name, + applicationId: application.ref, + locationUri: 'hosted', + type, + }); + + const configVersion = new CfnHostedConfigurationVersion(stack, `${name}-configVersion`, { + applicationId: application.ref, + configurationProfileId: configProfile.ref, + ...content + }); + + return new CfnDeployment(stack, `${name}-deployment`, { + applicationId: application.ref, + configurationProfileId: configProfile.ref, + configurationVersion: configVersion.ref, + deploymentStrategyId: deploymentStrategy.ref, + environmentId: environment.ref, + }); +}; + +export type CreateSSMSecureStringOptions = { + stack: Stack + id: string + name: string + value: string +}; + +const createSSMSecureString = (options: CreateSSMSecureStringOptions): IStringParameter => { + const { stack, id, name, value } = options; + + const paramCreator = new AwsCustomResource(stack, `create-${id}`, { + onCreate: { + service: 'SSM', + action: 'putParameter', + parameters: { + Name: name, + Value: value, + Type: 'SecureString', + }, + physicalResourceId: PhysicalResourceId.of(id), + }, + onDelete: { + service: 'SSM', + action: 'deleteParameter', + parameters: { + Name: name, + }, + }, + policy: AwsCustomResourcePolicy.fromSdkCalls({ + resources: AwsCustomResourcePolicy.ANY_RESOURCE, + }), + }); + + const param = StringParameter.fromSecureStringParameterAttributes(stack, id, { + parameterName: name, + }); + param.node.addDependency(paramCreator); + + return param; +}; + +export type PutDynamoDBItemOptions = { + stack: Stack + id: string + table: Table + item: Record +}; + +const putDynamoDBItem = async (options: PutDynamoDBItemOptions): Promise => { + const { stack, id, table, item } = options; + + new AwsCustomResource(stack, id, { + onCreate: { + service: 'DynamoDB', + action: 'putItem', + parameters: { + TableName: table.tableName, + Item: marshall(item), + }, + physicalResourceId: PhysicalResourceId.of(id), + }, + policy: AwsCustomResourcePolicy.fromSdkCalls({ + resources: [table.tableArn], + }), + }); +}; + +export { + createDynamoDBTable, + createBaseAppConfigResources, + createAppConfigConfigurationProfile, + createSSMSecureString, + putDynamoDBItem, +}; diff --git a/packages/parameters/tests/helpers/populateEnvironmentVariables.ts b/packages/parameters/tests/helpers/populateEnvironmentVariables.ts index e808ac84b9..7ff0774273 100644 --- a/packages/parameters/tests/helpers/populateEnvironmentVariables.ts +++ b/packages/parameters/tests/helpers/populateEnvironmentVariables.ts @@ -2,8 +2,6 @@ process.env._X_AMZN_TRACE_ID = 'Root=1-5759e988-bd862e3fe1be46a994272793;Parent=557abcec3ee5a047;Sampled=1'; process.env.AWS_LAMBDA_FUNCTION_NAME = 'my-lambda-function'; process.env.AWS_LAMBDA_FUNCTION_MEMORY_SIZE = '128'; -process.env.AWS_REGION = 'eu-west-1'; - -// Powertools variables -process.env.LOG_LEVEL = 'DEBUG'; -process.env.POWERTOOLS_SERVICE_NAME = 'hello-world'; +if (process.env.AWS_REGION === undefined && process.env.CDK_DEFAULT_REGION === undefined) { + process.env.AWS_REGION = 'eu-west-1'; +} diff --git a/packages/parameters/tests/helpers/sdkMiddlewareRequestCounter.ts b/packages/parameters/tests/helpers/sdkMiddlewareRequestCounter.ts new file mode 100644 index 0000000000..0fbff71084 --- /dev/null +++ b/packages/parameters/tests/helpers/sdkMiddlewareRequestCounter.ts @@ -0,0 +1,37 @@ +/** + * Middleware to count the number of API calls made by the SDK. + * + * The AWS SDK for JavaScript v3 uses a middleware stack to manage the execution of + * operations. Middleware can be added to the stack to perform custom tasks before + * or after an operation is executed. + * + * This middleware is added to the stack to count the number of API calls (`ROUND_TRIP`) made by the SDK. + * This allows us to verify that the SDK is making the expected number of API calls and thus test that + * caching or forcing a retrieval are working as expected. + * + * @see {@link https://aws.amazon.com/blogs/developer/middleware-stack-modular-aws-sdk-js/|AWS Blog - Middleware Stack} + */ +export const middleware = { + // + counter : 0, + applyToStack: (stack) => { + // Middleware added to mark start and end of an complete API call. + stack.add( + (next, context) => async (args) => { + // We only want to count API calls to retrieve data, + // not the StartConfigurationSessionCommand + if ( + context.clientName !== 'AppConfigDataClient' || + context.commandName !== 'StartConfigurationSessionCommand' + ) { + // Increment counter + middleware.counter++; + } + + // Call next middleware + return await next(args); + }, + { tags: ['ROUND_TRIP'] } + ); + }, +}; \ No newline at end of file diff --git a/packages/parameters/tests/helpers/tinyLogger.ts b/packages/parameters/tests/helpers/tinyLogger.ts new file mode 100644 index 0000000000..0effa723ae --- /dev/null +++ b/packages/parameters/tests/helpers/tinyLogger.ts @@ -0,0 +1,21 @@ +import { Console } from 'console'; + +/** + * A tiny logger that logs to stdout and stderr. + * + * This is used to log the results of the function code during the integration tests. + * We use this instead of the global console object because we want to log pure JSON objects. + * In Node.js runtimes, AWS Lambda usually patches the global console object to inject some + * metadata like the request ID. This is not desirable in our case because we want to log pure + * JSON objects to stdout and stderr. + * + * This allows us to get the logs when invoking the function and parse them to verify that + * the function code is working as expected. + */ +export class TinyLogger { + private console = new Console({ stdout: process.stdout, stderr: process.stderr }); + + public log(message: unknown): void { + this.console.log(JSON.stringify(message)); + } +} \ No newline at end of file diff --git a/packages/parameters/tests/unit/AppConfigProvider.test.ts b/packages/parameters/tests/unit/AppConfigProvider.test.ts index f0b23560df..56365d882c 100644 --- a/packages/parameters/tests/unit/AppConfigProvider.test.ts +++ b/packages/parameters/tests/unit/AppConfigProvider.test.ts @@ -21,6 +21,85 @@ describe('Class: AppConfigProvider', () => { jest.clearAllMocks(); }); + describe('Method: constructor', () => { + test('when the class instantiates without SDK client and client config it has default options', async () => { + // Prepare + const options: AppConfigProviderOptions = { + application: 'MyApp', + environment: 'MyAppProdEnv', + }; + + // Act + const provider = new AppConfigProvider(options); + + // Assess + expect(provider.client.config).toEqual( + expect.objectContaining({ + serviceId: 'AppConfigData', + }) + ); + }); + + test('when the user provides a client config in the options, the class instantiates a new client with client config options', async () => { + // Prepare + const options: AppConfigProviderOptions = { + application: 'MyApp', + environment: 'MyAppProdEnv', + clientConfig: { + serviceId: 'with-client-config', + }, + }; + + // Act + const provider = new AppConfigProvider(options); + + // Assess + expect(provider.client.config).toEqual( + expect.objectContaining({ + serviceId: 'with-client-config', + }) + ); + }); + + test('when the user provides an SDK client in the options, the class instantiates with it', async () => { + // Prepare + const awsSdkV3Client = new AppConfigDataClient({ + serviceId: 'with-custom-sdk-client', + }); + + const options: AppConfigProviderOptions = { + application: 'MyApp', + environment: 'MyAppProdEnv', + awsSdkV3Client: awsSdkV3Client, + }; + + // Act + const provider = new AppConfigProvider(options); + + // Assess + expect(provider.client.config).toEqual( + expect.objectContaining({ + serviceId: 'with-custom-sdk-client', + }) + ); + }); + + test('when the user provides NOT an SDK client in the options, it throws an error', async () => { + // Prepare + const awsSdkV3Client = {}; + const options: AppConfigProviderOptions = { + application: 'MyApp', + environment: 'MyAppProdEnv', + awsSdkV3Client: awsSdkV3Client as AppConfigDataClient, + }; + + // Act & Assess + expect(() => { + new AppConfigProvider(options); + }).toThrow(); + }); + }); + describe('Method: _get', () => { test('when called with name and options, it returns binary configuration', async () => { // Prepare diff --git a/packages/parameters/tests/unit/BaseProvider.test.ts b/packages/parameters/tests/unit/BaseProvider.test.ts index bc64b55150..186e0c1cdc 100644 --- a/packages/parameters/tests/unit/BaseProvider.test.ts +++ b/packages/parameters/tests/unit/BaseProvider.test.ts @@ -9,7 +9,7 @@ import { GetParameterError, TransformParameterError } from '../../src'; -import { toBase64 } from '@aws-sdk/util-base64'; +import { toBase64 } from '@aws-sdk/util-base64-node'; const encoder = new TextEncoder(); @@ -206,19 +206,15 @@ describe('Class: BaseProvider', () => { }); - test('when called with a binary transform, and the value is a valid binary, it returns the decoded value', async () => { + test('when called with a binary transform, and the value is a valid binary but NOT base64 encoded, it throws', async () => { // Prepare const mockData = encoder.encode('my-value'); const provider = new TestProvider(); jest.spyOn(provider, '_get').mockImplementation(() => new Promise((resolve, _reject) => resolve(mockData as unknown as string))); - // Act - const value = await provider.get('my-parameter', { transform: 'binary' }); - - // Assess - expect(typeof value).toBe('string'); - expect(value).toEqual('my-value'); + // Act & Assess + await expect(provider.get('my-parameter', { transform: 'binary' })).rejects.toThrowError(TransformParameterError); }); diff --git a/packages/parameters/tests/unit/DynamoDBProvider.test.ts b/packages/parameters/tests/unit/DynamoDBProvider.test.ts index 2ecbd4dd44..86ebc01890 100644 --- a/packages/parameters/tests/unit/DynamoDBProvider.test.ts +++ b/packages/parameters/tests/unit/DynamoDBProvider.test.ts @@ -6,6 +6,7 @@ import { DynamoDBProvider } from '../../src/dynamodb'; import { DynamoDBClient, GetItemCommand, QueryCommand } from '@aws-sdk/client-dynamodb'; import type { GetItemCommandInput, QueryCommandInput } from '@aws-sdk/client-dynamodb'; +import type { DynamoDBProviderOptions } from '../../src/types/DynamoDBProvider'; import { marshall } from '@aws-sdk/util-dynamodb'; import { mockClient } from 'aws-sdk-client-mock'; import 'aws-sdk-client-mock-jest'; @@ -16,6 +17,84 @@ describe('Class: DynamoDBProvider', () => { jest.clearAllMocks(); }); + describe('Method: constructor', () => { + test('when the class instantiates without SDK client and client config it has default options', async () => { + + // Prepare + const options: DynamoDBProviderOptions = { + tableName: 'test-table', + }; + + // Act + const provider = new DynamoDBProvider(options); + + // Assess + expect(provider.client.config).toEqual( + expect.objectContaining({ + serviceId: 'DynamoDB', + }) + ); + }); + + test('when the user provides a client config in the options, the class instantiates a new client with client config options', async () => { + + // Prepare + const options: DynamoDBProviderOptions = { + tableName: 'test-table', + clientConfig: { + serviceId: 'with-client-config', + }, + }; + + // Act + const provider = new DynamoDBProvider(options); + + // Assess + expect(provider.client.config).toEqual( + expect.objectContaining({ + serviceId: 'with-client-config', + }) + ); + }); + + test('when the user provides an SDK client in the options, the class instantiates with it', async () => { + + // Prepare + const awsSdkV3Client = new DynamoDBClient({ + serviceId: 'with-custom-sdk-client', + }); + + const options: DynamoDBProviderOptions = { + tableName: 'test-table', + awsSdkV3Client: awsSdkV3Client, + }; + + // Act + const provider = new DynamoDBProvider(options); + + // Assess + expect(provider.client.config).toEqual( + expect.objectContaining({ + serviceId: 'with-custom-sdk-client', + }) + ); + }); + + test('when the user provides NOT an SDK client in the options, it throws an error', async () => { + // Prepare + const awsSdkV3Client = {}; + const options: DynamoDBProviderOptions = { + tableName: 'test-table', + awsSdkV3Client: awsSdkV3Client as DynamoDBClient, + }; + + // Act & Assess + expect(() => { + new DynamoDBProvider(options); + }).toThrow(); + }); + }); + describe('Method: _get', () => { test('when called and the sdk client returns no items, it returns undefined', async () => { @@ -59,7 +138,10 @@ describe('Class: DynamoDBProvider', () => { Key: marshall({ id: parameterName, }), - ProjectionExpression: 'value', + ExpressionAttributeNames: { + '#value': 'value', + }, + ProjectionExpression: '#value', }); expect(parameter).toEqual(parameterValue); @@ -91,7 +173,10 @@ describe('Class: DynamoDBProvider', () => { Key: marshall({ key: parameterName, }), - ProjectionExpression: 'val', + ExpressionAttributeNames: { + '#value': 'val', + }, + ProjectionExpression: '#value', }); expect(parameter).toEqual(parameterValue); @@ -125,7 +210,10 @@ describe('Class: DynamoDBProvider', () => { Key: marshall({ id: parameterName, }), - ProjectionExpression: 'value', + ExpressionAttributeNames: { + '#value': 'value', + }, + ProjectionExpression: '#value', ConsistentRead: true, }); expect(parameter).toEqual(parameterValue); @@ -164,7 +252,10 @@ describe('Class: DynamoDBProvider', () => { Key: marshall({ id: parameterName, }), - ProjectionExpression: 'value', + ExpressionAttributeNames: { + '#value': 'value', + }, + ProjectionExpression: '#value', }); }); @@ -206,11 +297,16 @@ describe('Class: DynamoDBProvider', () => { // Assess expect(client).toReceiveCommandWith(QueryCommand, { TableName: 'test-table', - KeyConditionExpression: `id = :key`, + KeyConditionExpression: `#key = :key`, ExpressionAttributeValues: marshall({ ':key': parameterPath, }), - ProjectionExpression: 'sk, value', + ExpressionAttributeNames: { + '#key': 'id', + '#sk': 'sk', + '#value': 'value' + }, + ProjectionExpression: '#sk, #value', }); expect(parameters).toEqual({ a: 'parameter-a', @@ -256,11 +352,16 @@ describe('Class: DynamoDBProvider', () => { // Assess expect(client).toReceiveCommandWith(QueryCommand, { TableName: 'test-table', - KeyConditionExpression: `key = :key`, + KeyConditionExpression: `#key = :key`, ExpressionAttributeValues: marshall({ ':key': parameterPath, }), - ProjectionExpression: 'sort, val', + ExpressionAttributeNames: { + '#key': 'key', + '#sk': 'sort', + '#value': 'val' + }, + ProjectionExpression: '#sk, #value', }); expect(parameters).toEqual({ a: 'parameter-a', @@ -308,11 +409,16 @@ describe('Class: DynamoDBProvider', () => { // Assess expect(client).toReceiveCommandWith(QueryCommand, { TableName: 'test-table', - KeyConditionExpression: `id = :key`, + KeyConditionExpression: `#key = :key`, ExpressionAttributeValues: marshall({ ':key': parameterPath, }), - ProjectionExpression: 'sk, value', + ExpressionAttributeNames: { + '#key': 'id', + '#sk': 'sk', + '#value': 'value' + }, + ProjectionExpression: '#sk, #value', ConsistentRead: true, }); expect(parameters).toEqual({ @@ -419,11 +525,16 @@ describe('Class: DynamoDBProvider', () => { // Assess expect(client).toReceiveCommandWith(QueryCommand, { TableName: 'test-table', - KeyConditionExpression: `id = :key`, + KeyConditionExpression: `#key = :key`, ExpressionAttributeValues: marshall({ ':key': parameterPath, }), - ProjectionExpression: 'sk, value', + ExpressionAttributeNames: { + '#key': 'id', + '#sk': 'sk', + '#value': 'value' + }, + ProjectionExpression: '#sk, #value', ConsistentRead: true, Limit: 10, }); diff --git a/packages/parameters/tests/unit/SSMProvider.test.ts b/packages/parameters/tests/unit/SSMProvider.test.ts index a48e6a4004..856f2debec 100644 --- a/packages/parameters/tests/unit/SSMProvider.test.ts +++ b/packages/parameters/tests/unit/SSMProvider.test.ts @@ -14,6 +14,7 @@ import type { GetParametersCommandOutput } from '@aws-sdk/client-ssm'; import { mockClient } from 'aws-sdk-client-mock'; import 'aws-sdk-client-mock-jest'; import type { + SSMProviderOptions, SSMGetParametersByNameFromCacheOutputType, SSMGetParametersByNameOptionsInterface, SSMSplitBatchAndDecryptParametersOutputType, @@ -30,6 +31,79 @@ describe('Class: SSMProvider', () => { jest.clearAllMocks(); }); + describe('Method: constructor', () => { + test('when the class instantiates without SDK client and client config it has default options', async () => { + + // Prepare + const options: SSMProviderOptions = {}; + + // Act + const provider = new SSMProvider(options); + + // Assess + expect(provider.client.config).toEqual( + expect.objectContaining({ + serviceId: 'SSM', + }) + ); + }); + + test('when the user provides a client config in the options, the class instantiates a new client with client config options', async () => { + + // Prepare + const options: SSMProviderOptions = { + clientConfig: { + serviceId: 'with-client-config', + }, + }; + + // Act + const provider = new SSMProvider(options); + + // Assess + expect(provider.client.config).toEqual( + expect.objectContaining({ + serviceId: 'with-client-config', + }) + ); + }); + + test('when the user provides an SDK client in the options, the class instantiates with it', async () => { + + // Prepare + const awsSdkV3Client = new SSMClient({ + serviceId: 'with-custom-sdk-client', + }); + + const options: SSMProviderOptions = { + awsSdkV3Client: awsSdkV3Client, + }; + + // Act + const provider = new SSMProvider(options); + + // Assess + expect(provider.client.config).toEqual( + expect.objectContaining({ + serviceId: 'with-custom-sdk-client', + }) + ); + }); + + test('when the user provides NOT an SDK client in the options, it throws an error', async () => { + // Prepare + const awsSdkV3Client = {}; + const options: SSMProviderOptions = { + awsSdkV3Client: awsSdkV3Client as SSMClient, + }; + + // Act & Assess + expect(() => { + new SSMProvider(options); + }).toThrow(); + }); + }); + describe('Method: getParametersByName', () => { class SSMProviderMock extends SSMProvider { diff --git a/packages/parameters/tests/unit/SecretsProvider.test.ts b/packages/parameters/tests/unit/SecretsProvider.test.ts index 8b4fc3067a..e35923cb32 100644 --- a/packages/parameters/tests/unit/SecretsProvider.test.ts +++ b/packages/parameters/tests/unit/SecretsProvider.test.ts @@ -6,6 +6,7 @@ import { SecretsProvider } from '../../src/secrets'; import { SecretsManagerClient, GetSecretValueCommand } from '@aws-sdk/client-secrets-manager'; import type { GetSecretValueCommandInput } from '@aws-sdk/client-secrets-manager'; +import type { SecretsProviderOptions } from '../../src/types/SecretsProvider'; import { mockClient } from 'aws-sdk-client-mock'; import 'aws-sdk-client-mock-jest'; @@ -19,6 +20,79 @@ describe('Class: SecretsProvider', () => { jest.clearAllMocks(); }); + describe('Method: constructor', () => { + test('when the class instantiates without SDK client and client config it has default options', async () => { + + // Prepare + const options: SecretsProviderOptions = {}; + + // Act + const provider = new SecretsProvider(options); + + // Assess + expect(provider.client.config).toEqual( + expect.objectContaining({ + serviceId: 'Secrets Manager', + }) + ); + }); + + test('when the user provides a client config in the options, the class instantiates a new client with client config options', async () => { + + // Prepare + const options: SecretsProviderOptions = { + clientConfig: { + serviceId: 'with-client-config', + }, + }; + + // Act + const provider = new SecretsProvider(options); + + // Assess + expect(provider.client.config).toEqual( + expect.objectContaining({ + serviceId: 'with-client-config', + }) + ); + }); + + test('when the user provides an SDK client in the options, the class instantiates with it', async () => { + + // Prepare + const awsSdkV3Client = new SecretsManagerClient({ + serviceId: 'with-custom-sdk-client', + }); + + const options: SecretsProviderOptions = { + awsSdkV3Client: awsSdkV3Client, + }; + + // Act + const provider = new SecretsProvider(options); + + // Assess + expect(provider.client.config).toEqual( + expect.objectContaining({ + serviceId: 'with-custom-sdk-client', + }) + ); + }); + + test('when the user provides NOT an SDK client in the options, it throws an error', async () => { + // Prepare + const awsSdkV3Client = {}; + const options: SecretsProviderOptions = { + awsSdkV3Client: awsSdkV3Client as SecretsManagerClient, + }; + + // Act & Assess + expect(() => { + new SecretsProvider(options); + }).toThrow(); + }); + }); + describe('Method: _get', () => { test('when called with only a name, it gets the secret string', async () => { diff --git a/packages/parameters/tests/unit/getAppConfig.test.ts b/packages/parameters/tests/unit/getAppConfig.test.ts index af03a8ec32..e729d23dfd 100644 --- a/packages/parameters/tests/unit/getAppConfig.test.ts +++ b/packages/parameters/tests/unit/getAppConfig.test.ts @@ -16,11 +16,11 @@ import { import { mockClient } from 'aws-sdk-client-mock'; import 'aws-sdk-client-mock-jest'; import type { GetAppConfigCombinedInterface } from '../../src/types/AppConfigProvider'; +import { toBase64 } from '@aws-sdk/util-base64-node'; describe('Function: getAppConfig', () => { const client = mockClient(AppConfigDataClient); const encoder = new TextEncoder(); - const decoder = new TextDecoder(); beforeEach(() => { jest.clearAllMocks(); @@ -103,8 +103,8 @@ describe('Function: getAppConfig', () => { 'AYADeNgfsRxdKiJ37A12OZ9vN2cAXwABABVhd3MtY3J5cHRvLXB1YmxpYy1rZXkAREF1RzlLMTg1Tkx2Wjk4OGV2UXkyQ1'; const mockNextToken = 'ImRmyljpZnxt7FfxeEOE5H8xQF1SfOlWZFnHujbzJmIvNeSAAA8/qA9ivK0ElRMwpvx96damGxt125XtMkmYf6a0OWSqnBw=='; - const mockData = encoder.encode('myAppConfiguration'); - const decodedData = decoder.decode(mockData); + const expectedValue = 'my-value'; + const mockData = encoder.encode(toBase64(encoder.encode(expectedValue))); client .on(StartConfigurationSessionCommand) @@ -121,6 +121,6 @@ describe('Function: getAppConfig', () => { const result = await getAppConfig(name, options); // Assess - expect(result).toBe(decodedData); + expect(result).toBe(expectedValue); }); }); diff --git a/packages/tracer/CHANGELOG.md b/packages/tracer/CHANGELOG.md index a25bef0254..e4b7505622 100644 --- a/packages/tracer/CHANGELOG.md +++ b/packages/tracer/CHANGELOG.md @@ -3,6 +3,14 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. +# [1.6.0](https://github.com/awslabs/aws-lambda-powertools-typescript/compare/v1.5.1...v1.6.0) (2023-03-02) + +**Note:** Version bump only for package @aws-lambda-powertools/tracer + + + + + ## [1.5.1](https://github.com/awslabs/aws-lambda-powertools-typescript/compare/v1.5.0...v1.5.1) (2023-01-13) **Note:** Version bump only for package @aws-lambda-powertools/tracer diff --git a/packages/tracer/README.md b/packages/tracer/README.md index a148d17c99..8344b0262c 100644 --- a/packages/tracer/README.md +++ b/packages/tracer/README.md @@ -1,6 +1,6 @@ # AWS Lambda Powertools for TypeScript -A suite of utilities for AWS Lambda functions to ease the adoption of best practices such as tracing, structured logging, custom metrics, and more. +Powertools is a developer toolkit to implement Serverless [best practices and increase developer velocity](https://awslabs.github.io/aws-lambda-powertools-typescript/latest/#features). You can use the library in both TypeScript and JavaScript code bases. diff --git a/packages/tracer/jest.config.js b/packages/tracer/jest.config.js index 21510dceb2..d23175955a 100644 --- a/packages/tracer/jest.config.js +++ b/packages/tracer/jest.config.js @@ -1,7 +1,7 @@ module.exports = { displayName: { name: 'AWS Lambda Powertools utility: TRACER', - color: 'cyan', + color: 'white', }, 'runner': 'groups', 'preset': 'ts-jest', diff --git a/packages/tracer/package.json b/packages/tracer/package.json index 80469ccf06..21d891bff8 100644 --- a/packages/tracer/package.json +++ b/packages/tracer/package.json @@ -1,6 +1,6 @@ { "name": "@aws-lambda-powertools/tracer", - "version": "1.5.1", + "version": "1.6.0", "description": "The tracer package for the AWS Lambda Powertools for TypeScript library", "author": { "name": "Amazon Web Services", @@ -26,7 +26,7 @@ "prepare": "npm run build", "postversion": "git push --tags" }, - "homepage": "https://github.com/awslabs/aws-lambda-powertools-typescript/tree/master/packages/tracer#readme", + "homepage": "https://github.com/awslabs/aws-lambda-powertools-typescript/tree/main/packages/tracer#readme", "license": "MIT-0", "main": "./lib/index.js", "types": "./lib/index.d.ts", @@ -48,7 +48,7 @@ "url": "https://github.com/awslabs/aws-lambda-powertools-typescript/issues" }, "dependencies": { - "@aws-lambda-powertools/commons": "^1.5.1", + "@aws-lambda-powertools/commons": "^1.6.0", "aws-xray-sdk-core": "^3.4.0" }, "keywords": [ diff --git a/packages/tracer/tests/helpers/populateEnvironmentVariables.ts b/packages/tracer/tests/helpers/populateEnvironmentVariables.ts index 4eb2b25522..3dd17a6aa7 100644 --- a/packages/tracer/tests/helpers/populateEnvironmentVariables.ts +++ b/packages/tracer/tests/helpers/populateEnvironmentVariables.ts @@ -3,7 +3,9 @@ process.env._X_AMZN_TRACE_ID = '1-abcdef12-3456abcdef123456abcdef12'; process.env.AWS_LAMBDA_FUNCTION_NAME = 'my-lambda-function'; process.env.AWS_EXECUTION_ENV = 'nodejs16.x'; process.env.AWS_LAMBDA_FUNCTION_MEMORY_SIZE = '128'; -process.env.AWS_REGION = 'eu-west-1'; +if (process.env.AWS_REGION === undefined && process.env.CDK_DEFAULT_REGION === undefined) { + process.env.AWS_REGION = 'eu-west-1'; +} process.env._HANDLER = 'index.handler'; // Powertools variables