diff --git a/.github/renovate.json5 b/.github/renovate.json5 index acd181310d6..c4c24799da1 100644 --- a/.github/renovate.json5 +++ b/.github/renovate.json5 @@ -157,6 +157,7 @@ "html-webpack-injector", "html-webpack-plugin", "interprocess", + "itertools", "json5", "keytar", "libc", diff --git a/.github/workflows/alert-ddg-files-modified.yml b/.github/workflows/alert-ddg-files-modified.yml index 90c055a97b8..35eb0515c10 100644 --- a/.github/workflows/alert-ddg-files-modified.yml +++ b/.github/workflows/alert-ddg-files-modified.yml @@ -14,7 +14,7 @@ jobs: pull-requests: write steps: - name: Checkout code - uses: actions/checkout@93cb6efe18208431cddfb8368fd83d5badbf9bfd # v5.0.1 + uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1 with: fetch-depth: 0 persist-credentials: false diff --git a/.github/workflows/auto-branch-updater.yml b/.github/workflows/auto-branch-updater.yml index 02176b3169e..be9cd338e82 100644 --- a/.github/workflows/auto-branch-updater.yml +++ b/.github/workflows/auto-branch-updater.yml @@ -30,7 +30,7 @@ jobs: run: echo "branch=${GITHUB_REF#refs/heads/}" >> "$GITHUB_OUTPUT" - name: Checkout repo - uses: actions/checkout@93cb6efe18208431cddfb8368fd83d5badbf9bfd # v5.0.1 + uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1 with: ref: 'eu-web-${{ steps.setup.outputs.branch }}' fetch-depth: 0 diff --git a/.github/workflows/build-browser.yml b/.github/workflows/build-browser.yml index ab932c561ba..b5859516eaa 100644 --- a/.github/workflows/build-browser.yml +++ b/.github/workflows/build-browser.yml @@ -55,7 +55,7 @@ jobs: has_secrets: ${{ steps.check-secrets.outputs.has_secrets }} steps: - name: Check out repo - uses: actions/checkout@93cb6efe18208431cddfb8368fd83d5badbf9bfd # v5.0.1 + uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1 with: ref: ${{ github.event.pull_request.head.sha }} persist-credentials: false @@ -94,7 +94,7 @@ jobs: working-directory: apps/browser steps: - name: Check out repo - uses: actions/checkout@93cb6efe18208431cddfb8368fd83d5badbf9bfd # v5.0.1 + uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1 with: ref: ${{ github.event.pull_request.head.sha }} persist-credentials: false @@ -146,7 +146,7 @@ jobs: _NODE_VERSION: ${{ needs.setup.outputs.node_version }} steps: - name: Check out repo - uses: actions/checkout@93cb6efe18208431cddfb8368fd83d5badbf9bfd # v5.0.1 + uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1 with: ref: ${{ github.event.pull_request.head.sha }} persist-credentials: false @@ -254,7 +254,7 @@ jobs: artifact_name: "dist-opera-MV3" steps: - name: Check out repo - uses: actions/checkout@93cb6efe18208431cddfb8368fd83d5badbf9bfd # v5.0.1 + uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1 with: ref: ${{ github.event.pull_request.head.sha }} persist-credentials: false @@ -386,7 +386,7 @@ jobs: _NODE_VERSION: ${{ needs.setup.outputs.node_version }} steps: - name: Check out repo - uses: actions/checkout@93cb6efe18208431cddfb8368fd83d5badbf9bfd # v5.0.1 + uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1 with: ref: ${{ github.event.pull_request.head.sha }} persist-credentials: false @@ -542,7 +542,7 @@ jobs: - build-safari steps: - name: Check out repo - uses: actions/checkout@93cb6efe18208431cddfb8368fd83d5badbf9bfd # v5.0.1 + uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1 with: ref: ${{ github.event.pull_request.head.sha }} persist-credentials: false diff --git a/.github/workflows/build-cli.yml b/.github/workflows/build-cli.yml index 964cbc834c5..704a9810b27 100644 --- a/.github/workflows/build-cli.yml +++ b/.github/workflows/build-cli.yml @@ -59,7 +59,7 @@ jobs: has_secrets: ${{ steps.check-secrets.outputs.has_secrets }} steps: - name: Check out repo - uses: actions/checkout@93cb6efe18208431cddfb8368fd83d5badbf9bfd # v5.0.1 + uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1 with: ref: ${{ github.event.pull_request.head.sha }} persist-credentials: false @@ -114,7 +114,7 @@ jobs: steps: - name: Check out repo - uses: actions/checkout@93cb6efe18208431cddfb8368fd83d5badbf9bfd # v5.0.1 + uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1 with: ref: ${{ github.event.pull_request.head.sha }} persist-credentials: false @@ -311,7 +311,7 @@ jobs: _WIN_PKG_VERSION: 3.5 steps: - name: Check out repo - uses: actions/checkout@93cb6efe18208431cddfb8368fd83d5badbf9bfd # v5.0.1 + uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1 with: ref: ${{ github.event.pull_request.head.sha }} persist-credentials: false @@ -520,7 +520,7 @@ jobs: _PACKAGE_VERSION: ${{ needs.setup.outputs.package_version }} steps: - name: Check out repo - uses: actions/checkout@93cb6efe18208431cddfb8368fd83d5badbf9bfd # v5.0.1 + uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1 with: ref: ${{ github.event.pull_request.head.sha }} persist-credentials: false diff --git a/.github/workflows/build-desktop.yml b/.github/workflows/build-desktop.yml index 5a7703adb78..45297a110a0 100644 --- a/.github/workflows/build-desktop.yml +++ b/.github/workflows/build-desktop.yml @@ -55,7 +55,7 @@ jobs: runs-on: ubuntu-22.04 steps: - name: Check out repo - uses: actions/checkout@93cb6efe18208431cddfb8368fd83d5badbf9bfd # v5.0.1 + uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1 with: ref: ${{ github.event.pull_request.head.sha }} persist-credentials: false @@ -88,7 +88,7 @@ jobs: working-directory: apps/desktop steps: - name: Check out repo - uses: actions/checkout@93cb6efe18208431cddfb8368fd83d5badbf9bfd # v5.0.1 + uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1 with: ref: ${{ github.event.pull_request.head.sha }} persist-credentials: true @@ -173,24 +173,14 @@ jobs: working-directory: apps/desktop steps: - name: Check out repo - uses: actions/checkout@93cb6efe18208431cddfb8368fd83d5badbf9bfd # v5.0.1 + uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1 with: fetch-depth: 1 ref: ${{ github.event.pull_request.head.sha }} persist-credentials: false - - name: Free disk space for build - run: | - sudo rm -rf /usr/share/dotnet - sudo rm -rf /usr/share/swift - sudo rm -rf /usr/local/.ghcup - sudo rm -rf /usr/share/miniconda - sudo rm -rf /usr/share/az_* - sudo rm -rf /usr/local/julia* - sudo rm -rf /usr/lib/mono - sudo rm -rf /usr/lib/heroku - sudo rm -rf /usr/local/aws-cli - sudo rm -rf /usr/local/aws-sam-cli + - name: Free disk space + uses: bitwarden/gh-actions/free-disk-space@main - name: Set up Node uses: actions/setup-node@a0853c24544627f65ddf259abe73b1d18a591444 # v5.0.0 @@ -343,7 +333,7 @@ jobs: working-directory: apps/desktop steps: - name: Check out repo - uses: actions/checkout@93cb6efe18208431cddfb8368fd83d5badbf9bfd # v5.0.1 + uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1 with: ref: ${{ github.event.pull_request.head.sha }} persist-credentials: false @@ -491,7 +481,7 @@ jobs: NODE_OPTIONS: --max_old_space_size=4096 steps: - name: Check out repo - uses: actions/checkout@93cb6efe18208431cddfb8368fd83d5badbf9bfd # v5.0.1 + uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1 with: ref: ${{ github.event.pull_request.head.sha }} persist-credentials: false @@ -759,7 +749,7 @@ jobs: NODE_OPTIONS: --max_old_space_size=4096 steps: - name: Check out repo - uses: actions/checkout@93cb6efe18208431cddfb8368fd83d5badbf9bfd # v5.0.1 + uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1 with: ref: ${{ github.event.pull_request.head.sha }} persist-credentials: false @@ -1004,7 +994,7 @@ jobs: working-directory: apps/desktop steps: - name: Check out repo - uses: actions/checkout@93cb6efe18208431cddfb8368fd83d5badbf9bfd # v5.0.1 + uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1 with: ref: ${{ github.event.pull_request.head.sha }} persist-credentials: false @@ -1244,7 +1234,7 @@ jobs: working-directory: apps/desktop steps: - name: Check out repo - uses: actions/checkout@93cb6efe18208431cddfb8368fd83d5badbf9bfd # v5.0.1 + uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1 with: ref: ${{ github.event.pull_request.head.sha }} persist-credentials: false @@ -1519,7 +1509,7 @@ jobs: working-directory: apps/desktop steps: - name: Check out repo - uses: actions/checkout@93cb6efe18208431cddfb8368fd83d5badbf9bfd # v5.0.1 + uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1 with: ref: ${{ github.event.pull_request.head.sha }} persist-credentials: false @@ -1860,7 +1850,7 @@ jobs: runs-on: ubuntu-22.04 steps: - name: Check out repo - uses: actions/checkout@93cb6efe18208431cddfb8368fd83d5badbf9bfd # v5.0.1 + uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1 with: ref: ${{ github.event.pull_request.head.sha }} persist-credentials: false diff --git a/.github/workflows/build-web.yml b/.github/workflows/build-web.yml index 02ab7727c24..7d302fb453b 100644 --- a/.github/workflows/build-web.yml +++ b/.github/workflows/build-web.yml @@ -64,7 +64,7 @@ jobs: has_secrets: ${{ steps.check-secrets.outputs.has_secrets }} steps: - name: Check out repo - uses: actions/checkout@93cb6efe18208431cddfb8368fd83d5badbf9bfd # v5.0.1 + uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1 with: ref: ${{ github.event.pull_request.head.sha }} persist-credentials: false @@ -144,7 +144,7 @@ jobs: _VERSION: ${{ needs.setup.outputs.version }} steps: - name: Check out repo - uses: actions/checkout@93cb6efe18208431cddfb8368fd83d5badbf9bfd # v5.0.1 + uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1 with: ref: ${{ github.event.pull_request.head.sha }} persist-credentials: false @@ -174,7 +174,7 @@ jobs: echo "server_ref=$SERVER_REF" >> "$GITHUB_OUTPUT" - name: Check out Server repo - uses: actions/checkout@93cb6efe18208431cddfb8368fd83d5badbf9bfd # v5.0.1 + uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1 with: path: server repository: bitwarden/server @@ -367,7 +367,7 @@ jobs: runs-on: ubuntu-24.04 steps: - name: Check out repo - uses: actions/checkout@93cb6efe18208431cddfb8368fd83d5badbf9bfd # v5.0.1 + uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1 with: ref: ${{ github.event.pull_request.head.sha }} persist-credentials: false diff --git a/.github/workflows/chromatic.yml b/.github/workflows/chromatic.yml index 44ea21276e2..c7d80b82baa 100644 --- a/.github/workflows/chromatic.yml +++ b/.github/workflows/chromatic.yml @@ -31,7 +31,7 @@ jobs: steps: - name: Check out repo - uses: actions/checkout@93cb6efe18208431cddfb8368fd83d5badbf9bfd # v5.0.1 + uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1 with: ref: ${{ github.event.pull_request.head.sha }} fetch-depth: 0 diff --git a/.github/workflows/crowdin-pull.yml b/.github/workflows/crowdin-pull.yml index 5475c4dd692..e99034c499a 100644 --- a/.github/workflows/crowdin-pull.yml +++ b/.github/workflows/crowdin-pull.yml @@ -58,7 +58,7 @@ jobs: permission-pull-requests: write # for generating pull requests - name: Checkout repo - uses: actions/checkout@93cb6efe18208431cddfb8368fd83d5badbf9bfd # v5.0.1 + uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1 with: token: ${{ steps.app-token.outputs.token }} persist-credentials: false diff --git a/.github/workflows/lint-crowdin-config.yml b/.github/workflows/lint-crowdin-config.yml index b0efeb50823..dff253a8da2 100644 --- a/.github/workflows/lint-crowdin-config.yml +++ b/.github/workflows/lint-crowdin-config.yml @@ -22,7 +22,7 @@ jobs: ] steps: - name: Check out repo - uses: actions/checkout@93cb6efe18208431cddfb8368fd83d5badbf9bfd # v5.0.1 + uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1 with: fetch-depth: 1 persist-credentials: false diff --git a/.github/workflows/lint.yml b/.github/workflows/lint.yml index 47c5e9faef0..3aeb75dcbf6 100644 --- a/.github/workflows/lint.yml +++ b/.github/workflows/lint.yml @@ -31,7 +31,7 @@ jobs: runs-on: ubuntu-22.04 steps: - name: Checkout repo - uses: actions/checkout@93cb6efe18208431cddfb8368fd83d5badbf9bfd # v5.0.1 + uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1 with: persist-credentials: false @@ -95,7 +95,7 @@ jobs: steps: - name: Checkout repo - uses: actions/checkout@93cb6efe18208431cddfb8368fd83d5badbf9bfd # v5.0.1 + uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1 with: persist-credentials: false @@ -144,7 +144,7 @@ jobs: - name: Install cargo-deny uses: taiki-e/install-action@073d46cba2cde38f6698c798566c1b3e24feeb44 # v2.62.67 with: - tool: cargo-deny@0.18.5 + tool: cargo-deny@0.18.6 - name: Run cargo deny working-directory: ./apps/desktop/desktop_native diff --git a/.github/workflows/locales-lint.yml b/.github/workflows/locales-lint.yml index 8335d6aacad..e431854aea2 100644 --- a/.github/workflows/locales-lint.yml +++ b/.github/workflows/locales-lint.yml @@ -17,11 +17,11 @@ jobs: runs-on: ubuntu-22.04 steps: - name: Checkout repo - uses: actions/checkout@93cb6efe18208431cddfb8368fd83d5badbf9bfd # v5.0.1 + uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1 with: persist-credentials: false - name: Checkout base branch repo - uses: actions/checkout@93cb6efe18208431cddfb8368fd83d5badbf9bfd # v5.0.1 + uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1 with: ref: ${{ github.event.pull_request.base.sha }} path: base diff --git a/.github/workflows/nx.yml b/.github/workflows/nx.yml index 0f01aa27899..1e23c31b033 100644 --- a/.github/workflows/nx.yml +++ b/.github/workflows/nx.yml @@ -12,7 +12,7 @@ jobs: runs-on: ubuntu-22.04 steps: - name: Checkout repository - uses: actions/checkout@93cb6efe18208431cddfb8368fd83d5badbf9bfd # v5.0.1 + uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1 with: fetch-depth: 0 persist-credentials: false diff --git a/.github/workflows/publish-cli.yml b/.github/workflows/publish-cli.yml index 8fcd1fe7c98..ef287b0de08 100644 --- a/.github/workflows/publish-cli.yml +++ b/.github/workflows/publish-cli.yml @@ -103,7 +103,7 @@ jobs: _PKG_VERSION: ${{ needs.setup.outputs.release_version }} steps: - name: Checkout repo - uses: actions/checkout@93cb6efe18208431cddfb8368fd83d5badbf9bfd # v5.0.1 + uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1 with: persist-credentials: false @@ -151,7 +151,7 @@ jobs: _PKG_VERSION: ${{ needs.setup.outputs.release_version }} steps: - name: Checkout repo - uses: actions/checkout@93cb6efe18208431cddfb8368fd83d5badbf9bfd # v5.0.1 + uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1 with: persist-credentials: false @@ -203,7 +203,7 @@ jobs: _PKG_VERSION: ${{ needs.setup.outputs.release_version }} steps: - name: Checkout repo - uses: actions/checkout@93cb6efe18208431cddfb8368fd83d5badbf9bfd # v5.0.1 + uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1 with: persist-credentials: false diff --git a/.github/workflows/publish-desktop.yml b/.github/workflows/publish-desktop.yml index 3d512d49559..f013abbbb3b 100644 --- a/.github/workflows/publish-desktop.yml +++ b/.github/workflows/publish-desktop.yml @@ -204,7 +204,7 @@ jobs: _RELEASE_TAG: ${{ needs.setup.outputs.tag_name }} steps: - name: Checkout Repo - uses: actions/checkout@93cb6efe18208431cddfb8368fd83d5badbf9bfd # v5.0.1 + uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1 with: persist-credentials: false @@ -258,7 +258,7 @@ jobs: _RELEASE_TAG: ${{ needs.setup.outputs.tag_name }} steps: - name: Checkout Repo - uses: actions/checkout@93cb6efe18208431cddfb8368fd83d5badbf9bfd # v5.0.1 + uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1 with: persist-credentials: false @@ -315,7 +315,7 @@ jobs: _RELEASE_TAG: ${{ needs.setup.outputs.tag_name }} steps: - name: Checkout repo - uses: actions/checkout@93cb6efe18208431cddfb8368fd83d5badbf9bfd # v5.0.1 + uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1 with: persist-credentials: false diff --git a/.github/workflows/publish-web.yml b/.github/workflows/publish-web.yml index fb1de5a1bc5..be0087800f7 100644 --- a/.github/workflows/publish-web.yml +++ b/.github/workflows/publish-web.yml @@ -28,7 +28,7 @@ jobs: contents: read steps: - name: Checkout repo - uses: actions/checkout@93cb6efe18208431cddfb8368fd83d5badbf9bfd # v5.0.1 + uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1 with: persist-credentials: false @@ -74,7 +74,7 @@ jobs: echo "Github Release Option: $_RELEASE_OPTION" - name: Checkout repo - uses: actions/checkout@93cb6efe18208431cddfb8368fd83d5badbf9bfd # v5.0.1 + uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1 with: persist-credentials: false diff --git a/.github/workflows/release-browser.yml b/.github/workflows/release-browser.yml index ff5fb669faf..f7e45919308 100644 --- a/.github/workflows/release-browser.yml +++ b/.github/workflows/release-browser.yml @@ -28,7 +28,7 @@ jobs: release_version: ${{ steps.version.outputs.version }} steps: - name: Checkout repo - uses: actions/checkout@93cb6efe18208431cddfb8368fd83d5badbf9bfd # v5.0.1 + uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1 with: persist-credentials: false @@ -61,7 +61,7 @@ jobs: contents: read steps: - name: Checkout repo - uses: actions/checkout@93cb6efe18208431cddfb8368fd83d5badbf9bfd # v5.0.1 + uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1 with: persist-credentials: false diff --git a/.github/workflows/release-cli.yml b/.github/workflows/release-cli.yml index 08045b8d3c7..3f7b7e326d9 100644 --- a/.github/workflows/release-cli.yml +++ b/.github/workflows/release-cli.yml @@ -29,7 +29,7 @@ jobs: release_version: ${{ steps.version.outputs.version }} steps: - name: Checkout repo - uses: actions/checkout@93cb6efe18208431cddfb8368fd83d5badbf9bfd # v5.0.1 + uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1 with: persist-credentials: false diff --git a/.github/workflows/release-desktop.yml b/.github/workflows/release-desktop.yml index 2239cb1268f..ec529d7b4d8 100644 --- a/.github/workflows/release-desktop.yml +++ b/.github/workflows/release-desktop.yml @@ -31,7 +31,7 @@ jobs: release_channel: ${{ steps.release_channel.outputs.channel }} steps: - name: Checkout repo - uses: actions/checkout@93cb6efe18208431cddfb8368fd83d5badbf9bfd # v5.0.1 + uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1 with: persist-credentials: false diff --git a/.github/workflows/release-web.yml b/.github/workflows/release-web.yml index fc0ac340234..f6feb3386a7 100644 --- a/.github/workflows/release-web.yml +++ b/.github/workflows/release-web.yml @@ -25,7 +25,7 @@ jobs: tag_version: ${{ steps.version.outputs.tag }} steps: - name: Checkout repo - uses: actions/checkout@93cb6efe18208431cddfb8368fd83d5badbf9bfd # v5.0.1 + uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1 with: persist-credentials: false diff --git a/.github/workflows/repository-management.yml b/.github/workflows/repository-management.yml index 0a343be878c..b2edf0171db 100644 --- a/.github/workflows/repository-management.yml +++ b/.github/workflows/repository-management.yml @@ -105,7 +105,7 @@ jobs: permission-contents: write # for committing and pushing to current branch - name: Check out branch - uses: actions/checkout@93cb6efe18208431cddfb8368fd83d5badbf9bfd # v5.0.1 + uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1 with: ref: ${{ github.ref }} token: ${{ steps.app-token.outputs.token }} @@ -471,7 +471,7 @@ jobs: permission-contents: write # for creating and pushing new branch - name: Check out target ref - uses: actions/checkout@93cb6efe18208431cddfb8368fd83d5badbf9bfd # v5.0.1 + uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1 with: ref: ${{ inputs.target_ref }} token: ${{ steps.app-token.outputs.token }} diff --git a/.github/workflows/review-code.yml b/.github/workflows/review-code.yml index 0e0597fccf0..908664209d8 100644 --- a/.github/workflows/review-code.yml +++ b/.github/workflows/review-code.yml @@ -2,7 +2,7 @@ name: Code Review on: pull_request: - types: [opened, synchronize, reopened, ready_for_review] + types: [opened, labeled] permissions: {} diff --git a/.github/workflows/sdk-breaking-change-check.yml b/.github/workflows/sdk-breaking-change-check.yml index 14547b3942f..ecc803ebd5c 100644 --- a/.github/workflows/sdk-breaking-change-check.yml +++ b/.github/workflows/sdk-breaking-change-check.yml @@ -64,7 +64,7 @@ jobs: uses: bitwarden/gh-actions/azure-logout@main - name: Check out clients repository - uses: actions/checkout@93cb6efe18208431cddfb8368fd83d5badbf9bfd # v5.0.1 + uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1 with: persist-credentials: false diff --git a/.github/workflows/test-browser-interactions.yml b/.github/workflows/test-browser-interactions.yml index c8f4c959c52..6e236f2352c 100644 --- a/.github/workflows/test-browser-interactions.yml +++ b/.github/workflows/test-browser-interactions.yml @@ -18,7 +18,7 @@ jobs: id-token: write steps: - name: Checkout code - uses: actions/checkout@93cb6efe18208431cddfb8368fd83d5badbf9bfd # v5.0.1 + uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1 with: fetch-depth: 0 persist-credentials: false diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index e3ba6112b7d..e8f062ea345 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -24,7 +24,7 @@ jobs: steps: - name: Check out repo - uses: actions/checkout@93cb6efe18208431cddfb8368fd83d5badbf9bfd # v5.0.1 + uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1 with: persist-credentials: false @@ -103,7 +103,7 @@ jobs: sudo apt-get install -y gnome-keyring dbus-x11 - name: Check out repo - uses: actions/checkout@93cb6efe18208431cddfb8368fd83d5badbf9bfd # v5.0.1 + uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1 with: persist-credentials: false @@ -137,7 +137,7 @@ jobs: runs-on: macos-14 steps: - name: Checkout - uses: actions/checkout@93cb6efe18208431cddfb8368fd83d5badbf9bfd # v5.0.1 + uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1 with: persist-credentials: false @@ -173,7 +173,7 @@ jobs: - rust-coverage steps: - name: Check out repo - uses: actions/checkout@93cb6efe18208431cddfb8368fd83d5badbf9bfd # v5.0.1 + uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1 with: persist-credentials: false diff --git a/.github/workflows/version-auto-bump.yml b/.github/workflows/version-auto-bump.yml index 65f004149de..d66c48fcf58 100644 --- a/.github/workflows/version-auto-bump.yml +++ b/.github/workflows/version-auto-bump.yml @@ -39,7 +39,7 @@ jobs: permission-contents: write # for committing and pushing to the current branch - name: Check out target ref - uses: actions/checkout@93cb6efe18208431cddfb8368fd83d5badbf9bfd # v5.0.1 + uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1 with: ref: main token: ${{ steps.app-token.outputs.token }} diff --git a/apps/browser/package.json b/apps/browser/package.json index cf2be624a22..7055aabf4fd 100644 --- a/apps/browser/package.json +++ b/apps/browser/package.json @@ -1,6 +1,6 @@ { "name": "@bitwarden/browser", - "version": "2025.12.0", + "version": "2025.12.1", "scripts": { "build": "npm run build:chrome", "build:bit": "npm run build:bit:chrome", diff --git a/apps/browser/src/_locales/az/messages.json b/apps/browser/src/_locales/az/messages.json index 3f98313c2b8..d7257bab478 100644 --- a/apps/browser/src/_locales/az/messages.json +++ b/apps/browser/src/_locales/az/messages.json @@ -2498,7 +2498,7 @@ } }, "topLayerHijackWarning": { - "message": "This page is interfering with the Bitwarden experience. The Bitwarden inline menu has been temporarily disabled as a safety measure." + "message": "Bu səhifə Bitwarden təcrübəsinə müdaxilə edir. Bitwarden daxili menyusu, təhlükəsizlik tədbiri olaraq müvəqqəti sıradan çıxarılıb." }, "setMasterPassword": { "message": "Ana parolu ayarla" @@ -4124,7 +4124,7 @@ "message": "Avto-doldurula bilmir" }, "cannotAutofillExactMatch": { - "message": "Default matching is set to 'Exact Match'. The current website does not exactly match the saved login details for this item." + "message": "İlkin uyuşma 'Tam Uyuşur' olaraq ayarlanıb. Hazırkı veb sayt, bu element üçün saxlanılmış giriş məlumatları ilə tam uyuşmur." }, "okay": { "message": "Oldu" diff --git a/apps/browser/src/_locales/en/messages.json b/apps/browser/src/_locales/en/messages.json index 2b103555604..95d3f662994 100644 --- a/apps/browser/src/_locales/en/messages.json +++ b/apps/browser/src/_locales/en/messages.json @@ -6039,5 +6039,8 @@ }, "whyAmISeeingThis": { "message": "Why am I seeing this?" + }, + "resizeSideNavigation": { + "message": "Resize side navigation" } } diff --git a/apps/browser/src/_locales/zh_CN/messages.json b/apps/browser/src/_locales/zh_CN/messages.json index a699be016eb..c7f7fbcd618 100644 --- a/apps/browser/src/_locales/zh_CN/messages.json +++ b/apps/browser/src/_locales/zh_CN/messages.json @@ -1486,7 +1486,7 @@ "message": "选择一个文件" }, "itemsTransferred": { - "message": "项目已传输" + "message": "项目已转移" }, "maxFileSize": { "message": "文件最大为 500 MB。" @@ -3804,7 +3804,7 @@ "description": "Browser extension/addon" }, "desktop": { - "message": "桌面", + "message": "桌面端", "description": "Desktop app" }, "webVault": { @@ -5707,7 +5707,7 @@ "message": "导入现有密码" }, "emptyVaultNudgeBody": { - "message": "使用导入器快速将登录传输到 Bitwarden 而无需手动添加。" + "message": "使用导入器快速将登录转移到 Bitwarden 而无需手动添加。" }, "emptyVaultNudgeButton": { "message": "立即导入" @@ -6014,7 +6014,7 @@ "message": "我该如何管理我的密码库?" }, "transferItemsToOrganizationTitle": { - "message": "传输项目到 $ORGANIZATION$", + "message": "转移项目到 $ORGANIZATION$", "placeholders": { "organization": { "content": "$1", @@ -6023,7 +6023,7 @@ } }, "transferItemsToOrganizationContent": { - "message": "出于安全和合规考虑,$ORGANIZATION$ 要求所有项目归组织所有。点击「接受」以传输您的项目的所有权。", + "message": "出于安全和合规考虑,$ORGANIZATION$ 要求所有项目归组织所有。点击「接受」以转移您的项目的所有权。", "placeholders": { "organization": { "content": "$1", @@ -6032,7 +6032,7 @@ } }, "acceptTransfer": { - "message": "接受传输" + "message": "接受转移" }, "declineAndLeave": { "message": "拒绝并退出" diff --git a/apps/browser/src/autofill/fido2/content/messaging/messenger.ts b/apps/browser/src/autofill/fido2/content/messaging/messenger.ts index 257f7e9efd5..61ed7a8ed08 100644 --- a/apps/browser/src/autofill/fido2/content/messaging/messenger.ts +++ b/apps/browser/src/autofill/fido2/content/messaging/messenger.ts @@ -1,5 +1,3 @@ -// FIXME: Update this file to be type safe and remove this and next line -// @ts-strict-ignore import { Message, MessageTypes } from "./message"; const SENDER = "bitwarden-webauthn"; @@ -25,7 +23,7 @@ type Handler = ( * handling aborts and exceptions across separate execution contexts. */ export class Messenger { - private messageEventListener: (event: MessageEvent) => void | null = null; + private messageEventListener: ((event: MessageEvent) => void) | null = null; private onDestroy = new EventTarget(); /** @@ -60,6 +58,12 @@ export class Messenger { this.broadcastChannel.addEventListener(this.messageEventListener); } + private stripMetadata({ SENDER, senderId, ...message }: MessageWithMetadata): Message { + void SENDER; + void senderId; + return message; + } + /** * Sends a request to the content script and returns the response. * AbortController signals will be forwarded to the content script. @@ -74,7 +78,9 @@ export class Messenger { try { const promise = new Promise((resolve) => { - localPort.onmessage = (event: MessageEvent) => resolve(event.data); + localPort.onmessage = (event: MessageEvent) => { + resolve(this.stripMetadata(event.data)); + }; }); const abortListener = () => @@ -129,7 +135,9 @@ export class Messenger { try { const handlerResponse = await this.handler(message, abortController); - port.postMessage({ ...handlerResponse, SENDER }); + if (handlerResponse !== undefined) { + port.postMessage({ ...handlerResponse, SENDER }); + } } catch (error) { port.postMessage({ SENDER, diff --git a/apps/browser/src/autofill/overlay/inline-menu/iframe-content/autofill-inline-menu-iframe.service.ts b/apps/browser/src/autofill/overlay/inline-menu/iframe-content/autofill-inline-menu-iframe.service.ts index 64ef7d180ed..ad1241e98d2 100644 --- a/apps/browser/src/autofill/overlay/inline-menu/iframe-content/autofill-inline-menu-iframe.service.ts +++ b/apps/browser/src/autofill/overlay/inline-menu/iframe-content/autofill-inline-menu-iframe.service.ts @@ -1,5 +1,3 @@ -// FIXME: Update this file to be type safe and remove this and next line -// @ts-strict-ignore import { EVENTS } from "@bitwarden/common/autofill/constants"; import { ThemeTypes } from "@bitwarden/common/platform/enums"; @@ -15,14 +13,17 @@ export class AutofillInlineMenuIframeService implements AutofillInlineMenuIframe private readonly setElementStyles = setElementStyles; private readonly sendExtensionMessage = sendExtensionMessage; private port: chrome.runtime.Port | null = null; - private portKey: string; + private portKey?: string; private readonly extensionOrigin: string; private iframeMutationObserver: MutationObserver; - private iframe: HTMLIFrameElement; - private ariaAlertElement: HTMLDivElement; - private ariaAlertTimeout: number | NodeJS.Timeout; - private delayedCloseTimeout: number | NodeJS.Timeout; - private fadeInTimeout: number | NodeJS.Timeout; + /** + * Initialized in initMenuIframe which makes it safe to assert non null by lifecycle. + */ + private iframe!: HTMLIFrameElement; + private ariaAlertElement?: HTMLDivElement; + private ariaAlertTimeout: number | NodeJS.Timeout | null = null; + private delayedCloseTimeout: number | NodeJS.Timeout | null = null; + private fadeInTimeout: number | NodeJS.Timeout | null = null; private readonly fadeInOpacityTransition = "opacity 125ms ease-out 0s"; private readonly fadeOutOpacityTransition = "opacity 65ms ease-out 0s"; private iframeStyles: Partial = { @@ -50,7 +51,7 @@ export class AutofillInlineMenuIframeService implements AutofillInlineMenuIframe }; private foreignMutationsCount = 0; private mutationObserverIterations = 0; - private mutationObserverIterationsResetTimeout: number | NodeJS.Timeout; + private mutationObserverIterationsResetTimeout: number | NodeJS.Timeout | null = null; private readonly backgroundPortMessageHandlers: BackgroundPortMessageHandlers = { initAutofillInlineMenuButton: ({ message }) => this.initAutofillInlineMenu(message), initAutofillInlineMenuList: ({ message }) => this.initAutofillInlineMenu(message), @@ -134,7 +135,9 @@ export class AutofillInlineMenuIframeService implements AutofillInlineMenuIframe this.port.onDisconnect.addListener(this.handlePortDisconnect); this.port.onMessage.addListener(this.handlePortMessage); - this.announceAriaAlert(this.ariaAlert, 2000); + if (this.ariaAlert) { + this.announceAriaAlert(this.ariaAlert, 2000); + } }; /** @@ -155,7 +158,7 @@ export class AutofillInlineMenuIframeService implements AutofillInlineMenuIframe this.ariaAlertTimeout = globalThis.setTimeout(async () => { const isFieldFocused = await this.sendExtensionMessage("checkIsFieldCurrentlyFocused"); - if (isFieldFocused || triggeredByUser) { + if ((isFieldFocused || triggeredByUser) && this.ariaAlertElement) { this.shadow.appendChild(this.ariaAlertElement); } this.ariaAlertTimeout = null; @@ -242,7 +245,7 @@ export class AutofillInlineMenuIframeService implements AutofillInlineMenuIframe */ private initAutofillInlineMenuList(message: AutofillInlineMenuIframeExtensionMessage) { const { theme } = message; - let borderColor: string; + let borderColor: string | undefined; let verifiedTheme = theme; if (verifiedTheme === ThemeTypes.System) { verifiedTheme = globalThis.matchMedia("(prefers-color-scheme: dark)").matches @@ -274,8 +277,8 @@ export class AutofillInlineMenuIframeService implements AutofillInlineMenuIframe * * @param position - The position styles to apply to the iframe */ - private updateIframePosition(position: Partial) { - if (!globalThis.document.hasFocus()) { + private updateIframePosition(position?: Partial) { + if (!position || !globalThis.document.hasFocus()) { return; } @@ -295,7 +298,9 @@ export class AutofillInlineMenuIframeService implements AutofillInlineMenuIframe this.handleFadeInInlineMenuIframe(); } - this.announceAriaAlert(this.ariaAlert, 2000); + if (this.ariaAlert) { + this.announceAriaAlert(this.ariaAlert, 2000); + } } /** @@ -359,8 +364,8 @@ export class AutofillInlineMenuIframeService implements AutofillInlineMenuIframe * @param customElement - The element to update the styles for * @param styles - The styles to apply to the element */ - private updateElementStyles(customElement: HTMLElement, styles: Partial) { - if (!customElement) { + private updateElementStyles(customElement: HTMLElement, styles?: Partial) { + if (!customElement || !styles) { return; } diff --git a/apps/browser/src/autofill/overlay/notifications/content/overlay-notifications-content.service.ts b/apps/browser/src/autofill/overlay/notifications/content/overlay-notifications-content.service.ts index ab3b8144426..5784fd7a73a 100644 --- a/apps/browser/src/autofill/overlay/notifications/content/overlay-notifications-content.service.ts +++ b/apps/browser/src/autofill/overlay/notifications/content/overlay-notifications-content.service.ts @@ -1,5 +1,3 @@ -// FIXME: Update this file to be type safe and remove this and next line -// @ts-strict-ignore import { EVENTS } from "@bitwarden/common/autofill/constants"; import { BrowserApi } from "../../../../platform/browser/browser-api"; @@ -84,11 +82,15 @@ export class OverlayNotificationsContentService implements OverlayNotificationsC } const { type, typeData, params } = message.data; + if (!typeData) { + return; + } + if (this.currentNotificationBarType && type !== this.currentNotificationBarType) { this.closeNotificationBar(); } - const initData = { + const initData: NotificationBarIframeInitData = { type: type as NotificationType, isVaultLocked: typeData.isVaultLocked, theme: typeData.theme, @@ -116,7 +118,9 @@ export class OverlayNotificationsContentService implements OverlayNotificationsC const closedByUser = typeof message.data?.closedByUser === "boolean" ? message.data.closedByUser : true; if (message.data?.fadeOutNotification) { - setElementStyles(this.notificationBarIframeElement, { opacity: "0" }, true); + if (this.notificationBarIframeElement) { + setElementStyles(this.notificationBarIframeElement, { opacity: "0" }, true); + } globalThis.setTimeout(() => this.closeNotificationBar(closedByUser), 150); return; } @@ -166,7 +170,9 @@ export class OverlayNotificationsContentService implements OverlayNotificationsC this.createNotificationBarElement(); this.setupInitNotificationBarMessageListener(initData); - globalThis.document.body.appendChild(this.notificationBarRootElement); + if (this.notificationBarRootElement) { + globalThis.document.body.appendChild(this.notificationBarRootElement); + } } } @@ -179,7 +185,7 @@ export class OverlayNotificationsContentService implements OverlayNotificationsC const isNotificationFresh = initData.launchTimestamp && Date.now() - initData.launchTimestamp < 250; - this.currentNotificationBarType = initData.type; + this.currentNotificationBarType = initData.type ?? null; this.notificationBarIframeElement = globalThis.document.createElement("iframe"); this.notificationBarIframeElement.id = "bit-notification-bar-iframe"; const parentOrigin = globalThis.location.origin; @@ -206,11 +212,13 @@ export class OverlayNotificationsContentService implements OverlayNotificationsC * This will animate the notification bar into view. */ private handleNotificationBarIframeOnLoad = () => { - setElementStyles( - this.notificationBarIframeElement, - { transform: "translateX(0)", opacity: "1" }, - true, - ); + if (this.notificationBarIframeElement) { + setElementStyles( + this.notificationBarIframeElement, + { transform: "translateX(0)", opacity: "1" }, + true, + ); + } this.notificationBarIframeElement?.removeEventListener( EVENTS.LOAD, @@ -252,6 +260,7 @@ export class OverlayNotificationsContentService implements OverlayNotificationsC const handleInitNotificationBarMessage = (event: MessageEvent) => { const { source, data } = event; if ( + !this.notificationBarIframeElement?.contentWindow || source !== this.notificationBarIframeElement.contentWindow || data?.command !== "initNotificationBar" ) { @@ -282,13 +291,14 @@ export class OverlayNotificationsContentService implements OverlayNotificationsC return; } - this.notificationBarIframeElement.remove(); + this.notificationBarIframeElement?.remove(); this.notificationBarIframeElement = null; - this.notificationBarElement.remove(); + this.notificationBarElement?.remove(); this.notificationBarElement = null; this.notificationBarShadowRoot = null; - this.notificationBarRootElement.remove(); + + this.notificationBarRootElement?.remove(); this.notificationBarRootElement = null; const removableNotificationTypes = new Set([ @@ -297,7 +307,11 @@ export class OverlayNotificationsContentService implements OverlayNotificationsC NotificationTypes.AtRiskPassword, ] as NotificationType[]); - if (closedByUserAction && removableNotificationTypes.has(this.currentNotificationBarType)) { + if ( + closedByUserAction && + this.currentNotificationBarType && + removableNotificationTypes.has(this.currentNotificationBarType) + ) { void sendExtensionMessage("bgRemoveTabFromNotificationQueue"); } @@ -310,7 +324,7 @@ export class OverlayNotificationsContentService implements OverlayNotificationsC * @param message - The message to send to the notification bar iframe. */ private sendMessageToNotificationBarIframe(message: Record) { - if (this.notificationBarIframeElement) { + if (this.notificationBarIframeElement?.contentWindow) { this.notificationBarIframeElement.contentWindow.postMessage(message, this.extensionOrigin); } } diff --git a/apps/browser/src/autofill/popup/settings/autofill.component.html b/apps/browser/src/autofill/popup/settings/autofill.component.html index 1153ad58719..085145adb19 100644 --- a/apps/browser/src/autofill/popup/settings/autofill.component.html +++ b/apps/browser/src/autofill/popup/settings/autofill.component.html @@ -6,16 +6,18 @@
-
- -
+ @if (showSpotlightNudge$ | async) { +
+ +
+ }

{{ "autofillSuggestionsSectionTitle" | i18n }}

diff --git a/apps/browser/src/autofill/popup/settings/autofill.component.ts b/apps/browser/src/autofill/popup/settings/autofill.component.ts index 49be3104dc1..acb2aa7a970 100644 --- a/apps/browser/src/autofill/popup/settings/autofill.component.ts +++ b/apps/browser/src/autofill/popup/settings/autofill.component.ts @@ -611,6 +611,10 @@ export class AutofillComponent implements OnInit { if (this.canOverrideBrowserAutofillSetting) { this.defaultBrowserAutofillDisabled = true; await this.updateDefaultBrowserAutofillDisabled(); + await this.nudgesService.dismissNudge( + NudgeType.AutofillNudge, + await firstValueFrom(this.accountService.activeAccount$.pipe(getUserId)), + ); } else { await this.openURI(event, this.disablePasswordManagerURI); } diff --git a/apps/browser/src/autofill/services/collect-autofill-content.service.ts b/apps/browser/src/autofill/services/collect-autofill-content.service.ts index 367599f7ad0..18eb8e2baf8 100644 --- a/apps/browser/src/autofill/services/collect-autofill-content.service.ts +++ b/apps/browser/src/autofill/services/collect-autofill-content.service.ts @@ -60,6 +60,15 @@ export class CollectAutofillContentService implements CollectAutofillContentServ "button", "image", "file", + "search", + "url", + "date", + "time", + "datetime", // Note: datetime is deprecated in HTML5; keeping here for backwards compatibility + "datetime-local", + "week", + "color", + "range", ]); constructor( diff --git a/apps/browser/src/background/main.background.ts b/apps/browser/src/background/main.background.ts index 2d1da8510c1..3cd8b59aabc 100644 --- a/apps/browser/src/background/main.background.ts +++ b/apps/browser/src/background/main.background.ts @@ -126,6 +126,7 @@ import { FileUploadService as FileUploadServiceAbstraction } from "@bitwarden/co import { I18nService as I18nServiceAbstraction } from "@bitwarden/common/platform/abstractions/i18n.service"; import { LogService as LogServiceAbstraction } from "@bitwarden/common/platform/abstractions/log.service"; import { PlatformUtilsService as PlatformUtilsServiceAbstraction } from "@bitwarden/common/platform/abstractions/platform-utils.service"; +import { RegisterSdkService } from "@bitwarden/common/platform/abstractions/sdk/register-sdk.service"; import { SdkLoadService } from "@bitwarden/common/platform/abstractions/sdk/sdk-load.service"; import { SdkService } from "@bitwarden/common/platform/abstractions/sdk/sdk.service"; import { StateService as StateServiceAbstraction } from "@bitwarden/common/platform/abstractions/state.service"; @@ -164,6 +165,7 @@ import { MigrationRunner } from "@bitwarden/common/platform/services/migration-r import { DefaultSdkClientFactory } from "@bitwarden/common/platform/services/sdk/default-sdk-client-factory"; import { DefaultSdkService } from "@bitwarden/common/platform/services/sdk/default-sdk.service"; import { NoopSdkClientFactory } from "@bitwarden/common/platform/services/sdk/noop-sdk-client-factory"; +import { DefaultRegisterSdkService } from "@bitwarden/common/platform/services/sdk/register-sdk.service"; import { SystemService } from "@bitwarden/common/platform/services/system.service"; import { UserAutoUnlockKeyService } from "@bitwarden/common/platform/services/user-auto-unlock-key.service"; import { PrimarySecondaryStorageService } from "@bitwarden/common/platform/storage/primary-secondary-storage.service"; @@ -463,6 +465,7 @@ export default class MainBackground { themeStateService: DefaultThemeStateService; autoSubmitLoginBackground: AutoSubmitLoginBackground; sdkService: SdkService; + registerSdkService: RegisterSdkService; sdkLoadService: SdkLoadService; cipherAuthorizationService: CipherAuthorizationService; endUserNotificationService: EndUserNotificationService; @@ -578,7 +581,7 @@ export default class MainBackground { "ephemeral", "bitwarden-ephemeral", ); - await sessionStorage.save("session-key", derivedKey); + await sessionStorage.save("session-key", derivedKey.toJSON()); return derivedKey; }); @@ -797,18 +800,6 @@ export default class MainBackground { this.apiService, this.accountService, ); - this.keyConnectorService = new KeyConnectorService( - this.accountService, - this.masterPasswordService, - this.keyService, - this.apiService, - this.tokenService, - this.logService, - this.organizationService, - this.keyGenerationService, - logoutCallback, - this.stateProvider, - ); this.authService = new AuthService( this.accountService, @@ -846,6 +837,37 @@ export default class MainBackground { this.configService, ); + this.registerSdkService = new DefaultRegisterSdkService( + sdkClientFactory, + this.environmentService, + this.platformUtilsService, + this.accountService, + this.apiService, + this.stateProvider, + this.configService, + ); + + this.accountCryptographicStateService = new DefaultAccountCryptographicStateService( + this.stateProvider, + ); + + this.keyConnectorService = new KeyConnectorService( + this.accountService, + this.masterPasswordService, + this.keyService, + this.apiService, + this.tokenService, + this.logService, + this.organizationService, + this.keyGenerationService, + logoutCallback, + this.stateProvider, + this.configService, + this.registerSdkService, + this.securityStateService, + this.accountCryptographicStateService, + ); + this.pinService = new PinService( this.encryptService, this.logService, @@ -1013,9 +1035,7 @@ export default class MainBackground { this.avatarService = new AvatarService(this.apiService, this.stateProvider); this.providerService = new ProviderService(this.stateProvider); - this.accountCryptographicStateService = new DefaultAccountCryptographicStateService( - this.stateProvider, - ); + this.syncService = new DefaultSyncService( this.masterPasswordService, this.accountService, diff --git a/apps/browser/src/dirt/phishing-detection/phishing-resources.ts b/apps/browser/src/dirt/phishing-detection/phishing-resources.ts new file mode 100644 index 00000000000..262d6cf833b --- /dev/null +++ b/apps/browser/src/dirt/phishing-detection/phishing-resources.ts @@ -0,0 +1,98 @@ +export type PhishingResource = { + name?: string; + remoteUrl: string; + checksumUrl: string; + todayUrl: string; + /** Matcher used to decide whether a given URL matches an entry from this resource */ + match: (url: URL, entry: string) => boolean; +}; + +export const PhishingResourceType = Object.freeze({ + Domains: "domains", + Links: "links", +} as const); + +export type PhishingResourceType = (typeof PhishingResourceType)[keyof typeof PhishingResourceType]; + +export const PHISHING_RESOURCES: Record = { + [PhishingResourceType.Domains]: [ + { + name: "Phishing.Database Domains", + remoteUrl: + "https://raw.githubusercontent.com/Phishing-Database/Phishing.Database/master/phishing-domains-ACTIVE.txt", + checksumUrl: + "https://raw.githubusercontent.com/Phishing-Database/checksums/refs/heads/master/phishing-domains-ACTIVE.txt.md5", + todayUrl: + "https://raw.githubusercontent.com/Phishing-Database/Phishing.Database/refs/heads/master/phishing-domains-NEW-today.txt", + match: (url: URL, entry: string) => { + if (!entry) { + return false; + } + const candidate = entry.trim().toLowerCase().replace(/\/$/, ""); + // If entry contains a scheme, strip it for comparison + const e = candidate.replace(/^https?:\/\//, ""); + // Compare against hostname or host+path + if (e === url.hostname.toLowerCase()) { + return true; + } + const urlNoProto = url.href + .toLowerCase() + .replace(/https?:\/\//, "") + .replace(/\/$/, ""); + return urlNoProto === e || urlNoProto.startsWith(e + "/"); + }, + }, + ], + [PhishingResourceType.Links]: [ + { + name: "Phishing.Database Links", + remoteUrl: + "https://raw.githubusercontent.com/Phishing-Database/Phishing.Database/master/phishing-links-ACTIVE.txt", + checksumUrl: + "https://raw.githubusercontent.com/Phishing-Database/checksums/refs/heads/master/phishing-links-ACTIVE.txt.md5", + todayUrl: + "https://raw.githubusercontent.com/Phishing-Database/Phishing.Database/refs/heads/master/phishing-links-NEW-today.txt", + match: (url: URL, entry: string) => { + if (!entry) { + return false; + } + // Basic HTML entity decode for common cases (the lists sometimes contain &) + const decodeHtml = (s: string) => s.replace(/&/g, "&"); + + const normalizedEntry = decodeHtml(entry.trim()).toLowerCase().replace(/\/$/, ""); + + // Normalize URL for comparison - always strip protocol for consistent matching + const normalizedUrl = decodeHtml(url.href).toLowerCase().replace(/\/$/, ""); + const urlNoProto = normalizedUrl.replace(/^https?:\/\//, ""); + + // Strip protocol from entry if present (http:// and https:// should be treated as equivalent) + const entryNoProto = normalizedEntry.replace(/^https?:\/\//, ""); + + // Compare full path (without protocol) - exact match + if (urlNoProto === entryNoProto) { + return true; + } + + // Check if URL starts with entry (prefix match for subpaths/query/hash) + // e.g., entry "site.com/phish" matches "site.com/phish/subpage" or "site.com/phish?id=1" + if ( + urlNoProto.startsWith(entryNoProto + "/") || + urlNoProto.startsWith(entryNoProto + "?") || + urlNoProto.startsWith(entryNoProto + "#") + ) { + return true; + } + + return false; + }, + }, + ], +}; + +export function getPhishingResources( + type: PhishingResourceType, + index = 0, +): PhishingResource | undefined { + const list = PHISHING_RESOURCES[type] ?? []; + return list[index]; +} diff --git a/apps/browser/src/dirt/phishing-detection/services/phishing-data.service.spec.ts b/apps/browser/src/dirt/phishing-detection/services/phishing-data.service.spec.ts index 94f3e99f8be..30aa947092d 100644 --- a/apps/browser/src/dirt/phishing-detection/services/phishing-data.service.spec.ts +++ b/apps/browser/src/dirt/phishing-detection/services/phishing-data.service.spec.ts @@ -25,7 +25,7 @@ describe("PhishingDataService", () => { }; let fetchChecksumSpy: jest.SpyInstance; - let fetchDomainsSpy: jest.SpyInstance; + let fetchWebAddressesSpy: jest.SpyInstance; beforeEach(() => { jest.useFakeTimers(); @@ -45,113 +45,113 @@ describe("PhishingDataService", () => { platformUtilsService, ); - fetchChecksumSpy = jest.spyOn(service as any, "fetchPhishingDomainsChecksum"); - fetchDomainsSpy = jest.spyOn(service as any, "fetchPhishingDomains"); + fetchChecksumSpy = jest.spyOn(service as any, "fetchPhishingChecksum"); + fetchWebAddressesSpy = jest.spyOn(service as any, "fetchPhishingWebAddresses"); }); - describe("isPhishingDomains", () => { - it("should detect a phishing domain", async () => { + describe("isPhishingWebAddress", () => { + it("should detect a phishing web address", async () => { setMockState({ - domains: ["phish.com", "badguy.net"], + webAddresses: ["phish.com", "badguy.net"], timestamp: Date.now(), checksum: "abc123", applicationVersion: "1.0.0", }); const url = new URL("http://phish.com"); - const result = await service.isPhishingDomain(url); + const result = await service.isPhishingWebAddress(url); expect(result).toBe(true); }); - it("should not detect a safe domain", async () => { + it("should not detect a safe web address", async () => { setMockState({ - domains: ["phish.com", "badguy.net"], + webAddresses: ["phish.com", "badguy.net"], timestamp: Date.now(), checksum: "abc123", applicationVersion: "1.0.0", }); const url = new URL("http://safe.com"); - const result = await service.isPhishingDomain(url); + const result = await service.isPhishingWebAddress(url); expect(result).toBe(false); }); - it("should match against root domain", async () => { + it("should match against root web address", async () => { setMockState({ - domains: ["phish.com", "badguy.net"], + webAddresses: ["phish.com", "badguy.net"], timestamp: Date.now(), checksum: "abc123", applicationVersion: "1.0.0", }); const url = new URL("http://phish.com/about"); - const result = await service.isPhishingDomain(url); + const result = await service.isPhishingWebAddress(url); expect(result).toBe(true); }); it("should not error on empty state", async () => { setMockState(undefined as any); const url = new URL("http://phish.com/about"); - const result = await service.isPhishingDomain(url); + const result = await service.isPhishingWebAddress(url); expect(result).toBe(false); }); }); - describe("getNextDomains", () => { - it("refetches all domains if applicationVersion has changed", async () => { + describe("getNextWebAddresses", () => { + it("refetches all web addresses if applicationVersion has changed", async () => { const prev: PhishingData = { - domains: ["a.com"], + webAddresses: ["a.com"], timestamp: Date.now() - 60000, checksum: "old", applicationVersion: "1.0.0", }; fetchChecksumSpy.mockResolvedValue("new"); - fetchDomainsSpy.mockResolvedValue(["d.com", "e.com"]); + fetchWebAddressesSpy.mockResolvedValue(["d.com", "e.com"]); platformUtilsService.getApplicationVersion.mockResolvedValue("2.0.0"); - const result = await service.getNextDomains(prev); + const result = await service.getNextWebAddresses(prev); - expect(result!.domains).toEqual(["d.com", "e.com"]); + expect(result!.webAddresses).toEqual(["d.com", "e.com"]); expect(result!.checksum).toBe("new"); expect(result!.applicationVersion).toBe("2.0.0"); }); it("only updates timestamp if checksum matches", async () => { const prev: PhishingData = { - domains: ["a.com"], + webAddresses: ["a.com"], timestamp: Date.now() - 60000, checksum: "abc", applicationVersion: "1.0.0", }; fetchChecksumSpy.mockResolvedValue("abc"); - const result = await service.getNextDomains(prev); - expect(result!.domains).toEqual(prev.domains); + const result = await service.getNextWebAddresses(prev); + expect(result!.webAddresses).toEqual(prev.webAddresses); expect(result!.checksum).toBe("abc"); expect(result!.timestamp).not.toBe(prev.timestamp); }); it("patches daily domains if cache is fresh", async () => { const prev: PhishingData = { - domains: ["a.com"], + webAddresses: ["a.com"], timestamp: Date.now() - 60000, checksum: "old", applicationVersion: "1.0.0", }; fetchChecksumSpy.mockResolvedValue("new"); - fetchDomainsSpy.mockResolvedValue(["b.com", "c.com"]); - const result = await service.getNextDomains(prev); - expect(result!.domains).toEqual(["a.com", "b.com", "c.com"]); + fetchWebAddressesSpy.mockResolvedValue(["b.com", "c.com"]); + const result = await service.getNextWebAddresses(prev); + expect(result!.webAddresses).toEqual(["a.com", "b.com", "c.com"]); expect(result!.checksum).toBe("new"); }); it("fetches all domains if cache is old", async () => { const prev: PhishingData = { - domains: ["a.com"], + webAddresses: ["a.com"], timestamp: Date.now() - 2 * 24 * 60 * 60 * 1000, checksum: "old", applicationVersion: "1.0.0", }; fetchChecksumSpy.mockResolvedValue("new"); - fetchDomainsSpy.mockResolvedValue(["d.com", "e.com"]); - const result = await service.getNextDomains(prev); - expect(result!.domains).toEqual(["d.com", "e.com"]); + fetchWebAddressesSpy.mockResolvedValue(["d.com", "e.com"]); + const result = await service.getNextWebAddresses(prev); + expect(result!.webAddresses).toEqual(["d.com", "e.com"]); expect(result!.checksum).toBe("new"); }); }); diff --git a/apps/browser/src/dirt/phishing-detection/services/phishing-data.service.ts b/apps/browser/src/dirt/phishing-detection/services/phishing-data.service.ts index 6e1bf07c647..21fe74f1873 100644 --- a/apps/browser/src/dirt/phishing-detection/services/phishing-data.service.ts +++ b/apps/browser/src/dirt/phishing-detection/services/phishing-data.service.ts @@ -20,14 +20,16 @@ import { ScheduledTaskNames, TaskSchedulerService } from "@bitwarden/common/plat import { LogService } from "@bitwarden/logging"; import { GlobalStateProvider, KeyDefinition, PHISHING_DETECTION_DISK } from "@bitwarden/state"; +import { getPhishingResources, PhishingResourceType } from "../phishing-resources"; + export type PhishingData = { - domains: string[]; + webAddresses: string[]; timestamp: number; checksum: string; /** * We store the application version to refetch the entire dataset on a new client release. - * This counteracts daily appends updates not removing inactive or false positive domains. + * This counteracts daily appends updates not removing inactive or false positive web addresses. */ applicationVersion: string; }; @@ -37,34 +39,27 @@ export const PHISHING_DOMAINS_KEY = new KeyDefinition( "phishingDomains", { deserializer: (value: PhishingData) => - value ?? { domains: [], timestamp: 0, checksum: "", applicationVersion: "" }, + value ?? { webAddresses: [], timestamp: 0, checksum: "", applicationVersion: "" }, }, ); -/** Coordinates fetching, caching, and patching of known phishing domains */ +/** Coordinates fetching, caching, and patching of known phishing web addresses */ export class PhishingDataService { - private static readonly RemotePhishingDatabaseUrl = - "https://raw.githubusercontent.com/Phishing-Database/Phishing.Database/master/phishing-domains-ACTIVE.txt"; - private static readonly RemotePhishingDatabaseChecksumUrl = - "https://raw.githubusercontent.com/Phishing-Database/checksums/refs/heads/master/phishing-domains-ACTIVE.txt.md5"; - private static readonly RemotePhishingDatabaseTodayUrl = - "https://raw.githubusercontent.com/Phishing-Database/Phishing.Database/refs/heads/master/phishing-domains-NEW-today.txt"; - - private _testDomains = this.getTestDomains(); + private _testWebAddresses = this.getTestWebAddresses(); private _cachedState = this.globalStateProvider.get(PHISHING_DOMAINS_KEY); - private _domains$ = this._cachedState.state$.pipe( + private _webAddresses$ = this._cachedState.state$.pipe( map( (state) => new Set( - (state?.domains?.filter((line) => line.trim().length > 0) ?? []).concat( - this._testDomains, + (state?.webAddresses?.filter((line) => line.trim().length > 0) ?? []).concat( + this._testWebAddresses, "phishing.testcategory.com", // Included for QA to test in prod ), ), ), ); - // How often are new domains added to the remote? + // How often are new web addresses added to the remote? readonly UPDATE_INTERVAL_DURATION = 24 * 60 * 60 * 1000; // 24 hours private _triggerUpdate$ = new Subject(); @@ -75,7 +70,7 @@ export class PhishingDataService { this._cachedState.state$.pipe( first(), // Only take the first value to avoid an infinite loop when updating the cache below switchMap(async (cachedState) => { - const next = await this.getNextDomains(cachedState); + const next = await this.getNextWebAddresses(cachedState); if (next) { await this._cachedState.update(() => next); this.logService.info(`[PhishingDataService] cache updated`); @@ -85,7 +80,7 @@ export class PhishingDataService { count: 3, delay: (err, count) => { this.logService.error( - `[PhishingDataService] Unable to update domains. Attempt ${count}.`, + `[PhishingDataService] Unable to update web addresses. Attempt ${count}.`, err, ); return timer(5 * 60 * 1000); // 5 minutes @@ -97,7 +92,7 @@ export class PhishingDataService { err: unknown /** Eslint actually crashed if you remove this type: https://github.com/cartant/eslint-plugin-rxjs/issues/122 */, ) => { this.logService.error( - "[PhishingDataService] Retries unsuccessful. Unable to update domains.", + "[PhishingDataService] Retries unsuccessful. Unable to update web addresses.", err, ); return EMPTY; @@ -114,6 +109,7 @@ export class PhishingDataService { private globalStateProvider: GlobalStateProvider, private logService: LogService, private platformUtilsService: PlatformUtilsService, + private resourceType: PhishingResourceType = PhishingResourceType.Links, ) { this.taskSchedulerService.registerTaskHandler(ScheduledTaskNames.phishingDomainUpdate, () => { this._triggerUpdate$.next(); @@ -125,22 +121,31 @@ export class PhishingDataService { } /** - * Checks if the given URL is a known phishing domain + * Checks if the given URL is a known phishing web address * * @param url The URL to check - * @returns True if the URL is a known phishing domain, false otherwise + * @returns True if the URL is a known phishing web address, false otherwise */ - async isPhishingDomain(url: URL): Promise { - const domains = await firstValueFrom(this._domains$); - const result = domains.has(url.hostname); - if (result) { - return true; + async isPhishingWebAddress(url: URL): Promise { + // Use domain (hostname) matching for domain resources, and link matching for links resources + const entries = await firstValueFrom(this._webAddresses$); + + const resource = getPhishingResources(this.resourceType); + if (resource && resource.match) { + for (const entry of entries) { + if (resource.match(url, entry)) { + return true; + } + } + return false; } - return false; + + // Default/domain behavior: exact hostname match as a fallback + return entries.has(url.hostname); } - async getNextDomains(prev: PhishingData | null): Promise { - prev = prev ?? { domains: [], timestamp: 0, checksum: "", applicationVersion: "" }; + async getNextWebAddresses(prev: PhishingData | null): Promise { + prev = prev ?? { webAddresses: [], timestamp: 0, checksum: "", applicationVersion: "" }; const timestamp = Date.now(); const prevAge = timestamp - prev.timestamp; this.logService.info(`[PhishingDataService] Cache age: ${prevAge}`); @@ -148,7 +153,7 @@ export class PhishingDataService { const applicationVersion = await this.platformUtilsService.getApplicationVersion(); // If checksum matches, return existing data with new timestamp & version - const remoteChecksum = await this.fetchPhishingDomainsChecksum(); + const remoteChecksum = await this.fetchPhishingChecksum(this.resourceType); if (remoteChecksum && prev.checksum === remoteChecksum) { this.logService.info( `[PhishingDataService] Remote checksum matches local checksum, updating timestamp only.`, @@ -157,66 +162,66 @@ export class PhishingDataService { } // Checksum is different, data needs to be updated. - // Approach 1: Fetch only new domains and append + // Approach 1: Fetch only new web addresses and append const isOneDayOldMax = prevAge <= this.UPDATE_INTERVAL_DURATION; if (isOneDayOldMax && applicationVersion === prev.applicationVersion) { - const dailyDomains: string[] = await this.fetchPhishingDomains( - PhishingDataService.RemotePhishingDatabaseTodayUrl, - ); + const webAddressesTodayUrl = getPhishingResources(this.resourceType)!.todayUrl; + const dailyWebAddresses: string[] = + await this.fetchPhishingWebAddresses(webAddressesTodayUrl); this.logService.info( - `[PhishingDataService] ${dailyDomains.length} new phishing domains added`, + `[PhishingDataService] ${dailyWebAddresses.length} new phishing web addresses added`, ); return { - domains: prev.domains.concat(dailyDomains), + webAddresses: prev.webAddresses.concat(dailyWebAddresses), checksum: remoteChecksum, timestamp, applicationVersion, }; } - // Approach 2: Fetch all domains - const domains = await this.fetchPhishingDomains(PhishingDataService.RemotePhishingDatabaseUrl); + // Approach 2: Fetch all web addresses + const remoteUrl = getPhishingResources(this.resourceType)!.remoteUrl; + const remoteWebAddresses = await this.fetchPhishingWebAddresses(remoteUrl); return { - domains, + webAddresses: remoteWebAddresses, timestamp, checksum: remoteChecksum, applicationVersion, }; } - private async fetchPhishingDomainsChecksum() { - const response = await this.apiService.nativeFetch( - new Request(PhishingDataService.RemotePhishingDatabaseChecksumUrl), - ); + private async fetchPhishingChecksum(type: PhishingResourceType = PhishingResourceType.Domains) { + const checksumUrl = getPhishingResources(type)!.checksumUrl; + const response = await this.apiService.nativeFetch(new Request(checksumUrl)); if (!response.ok) { throw new Error(`[PhishingDataService] Failed to fetch checksum: ${response.status}`); } return response.text(); } - private async fetchPhishingDomains(url: string) { + private async fetchPhishingWebAddresses(url: string) { const response = await this.apiService.nativeFetch(new Request(url)); if (!response.ok) { - throw new Error(`[PhishingDataService] Failed to fetch domains: ${response.status}`); + throw new Error(`[PhishingDataService] Failed to fetch web addresses: ${response.status}`); } return response.text().then((text) => text.split("\n")); } - private getTestDomains() { + private getTestWebAddresses() { const flag = devFlagEnabled("testPhishingUrls"); if (!flag) { return []; } - const domains = devFlagValue("testPhishingUrls") as unknown[]; - if (domains && domains instanceof Array) { + const webAddresses = devFlagValue("testPhishingUrls") as unknown[]; + if (webAddresses && webAddresses instanceof Array) { this.logService.debug( - "[PhishingDetectionService] Dev flag enabled for testing phishing detection. Adding test phishing domains:", - domains, + "[PhishingDetectionService] Dev flag enabled for testing phishing detection. Adding test phishing web addresses:", + webAddresses, ); - return domains as string[]; + return webAddresses as string[]; } return []; } diff --git a/apps/browser/src/dirt/phishing-detection/services/phishing-detection.service.ts b/apps/browser/src/dirt/phishing-detection/services/phishing-detection.service.ts index e04d08559ab..d90e872eef8 100644 --- a/apps/browser/src/dirt/phishing-detection/services/phishing-detection.service.ts +++ b/apps/browser/src/dirt/phishing-detection/services/phishing-detection.service.ts @@ -94,7 +94,7 @@ export class PhishingDetectionService { this._ignoredHostnames.delete(url.hostname); return; } - const isPhishing = await phishingDataService.isPhishingDomain(url); + const isPhishing = await phishingDataService.isPhishingWebAddress(url); if (!isPhishing) { return; } diff --git a/apps/browser/src/manifest.json b/apps/browser/src/manifest.json index 1651f616e03..26add57d1ae 100644 --- a/apps/browser/src/manifest.json +++ b/apps/browser/src/manifest.json @@ -2,7 +2,7 @@ "manifest_version": 2, "name": "__MSG_extName__", "short_name": "Bitwarden", - "version": "2025.12.0", + "version": "2025.12.1", "description": "__MSG_extDesc__", "default_locale": "en", "author": "Bitwarden Inc.", diff --git a/apps/browser/src/manifest.v3.json b/apps/browser/src/manifest.v3.json index 67399192b64..64d182ebd3d 100644 --- a/apps/browser/src/manifest.v3.json +++ b/apps/browser/src/manifest.v3.json @@ -3,7 +3,7 @@ "minimum_chrome_version": "102.0", "name": "__MSG_extName__", "short_name": "Bitwarden", - "version": "2025.12.0", + "version": "2025.12.1", "description": "__MSG_extDesc__", "default_locale": "en", "author": "Bitwarden Inc.", diff --git a/apps/browser/src/popup/services/services.module.ts b/apps/browser/src/popup/services/services.module.ts index 739166ff6f8..7a2ded5bb83 100644 --- a/apps/browser/src/popup/services/services.module.ts +++ b/apps/browser/src/popup/services/services.module.ts @@ -23,6 +23,8 @@ import { WINDOW, } from "@bitwarden/angular/services/injection-tokens"; import { JslibServicesModule } from "@bitwarden/angular/services/jslib-services.module"; +import { AUTOFILL_NUDGE_SERVICE } from "@bitwarden/angular/vault"; +import { SingleNudgeService } from "@bitwarden/angular/vault/services/default-single-nudge.service"; import { LoginComponentService, TwoFactorAuthComponentService, @@ -208,6 +210,7 @@ import { } from "../../platform/system-notifications/browser-system-notification.service"; import { fromChromeRuntimeMessaging } from "../../platform/utils/from-chrome-runtime-messaging"; import { FilePopoutUtilsService } from "../../tools/popup/services/file-popout-utils.service"; +import { BrowserAutofillNudgeService } from "../../vault/popup/services/browser-autofill-nudge.service"; import { Fido2UserVerificationService } from "../../vault/services/fido2-user-verification.service"; import { ExtensionAnonLayoutWrapperDataService } from "../components/extension-anon-layout-wrapper/extension-anon-layout-wrapper-data.service"; @@ -756,6 +759,11 @@ const safeProviders: SafeProvider[] = [ MessagingServiceAbstraction, ], }), + safeProvider({ + provide: AUTOFILL_NUDGE_SERVICE as SafeInjectionToken, + useClass: BrowserAutofillNudgeService, + deps: [], + }), ]; @NgModule({ diff --git a/apps/browser/src/safari/desktop/Info.plist b/apps/browser/src/safari/desktop/Info.plist index b687d9d2f3a..94542609351 100644 --- a/apps/browser/src/safari/desktop/Info.plist +++ b/apps/browser/src/safari/desktop/Info.plist @@ -25,7 +25,7 @@ LSMinimumSystemVersion $(MACOSX_DEPLOYMENT_TARGET) NSHumanReadableCopyright - Copyright © 2015-2025 Bitwarden Inc. All rights reserved. + Copyright © 2015-2026 Bitwarden Inc. All rights reserved. NSMainStoryboardFile Main NSPrincipalClass diff --git a/apps/browser/src/safari/safari/Info.plist b/apps/browser/src/safari/safari/Info.plist index 95172846758..68b872610e9 100644 --- a/apps/browser/src/safari/safari/Info.plist +++ b/apps/browser/src/safari/safari/Info.plist @@ -30,7 +30,7 @@ $(PRODUCT_MODULE_NAME).SafariWebExtensionHandler NSHumanReadableCopyright - Copyright © 2015-2025 Bitwarden Inc. All rights reserved. + Copyright © 2015-2026 Bitwarden Inc. All rights reserved. NSHumanReadableDescription A secure and free password manager for all of your devices. SFSafariAppExtensionBundleIdentifiersToReplace diff --git a/apps/browser/src/tools/popup/send-v2/send-created/send-created.component.html b/apps/browser/src/tools/popup/send-v2/send-created/send-created.component.html index 16711fabbf4..828c1667c57 100644 --- a/apps/browser/src/tools/popup/send-v2/send-created/send-created.component.html +++ b/apps/browser/src/tools/popup/send-v2/send-created/send-created.component.html @@ -1,39 +1,37 @@ -
- - - - - - + + + + + + -
-
- -
-

- {{ "createdSendSuccessfully" | i18n }} -

-

- {{ formatExpirationDate() }} -

- +
+
+
- - - - - -
+

+ {{ "createdSendSuccessfully" | i18n }} +

+

+ {{ formatExpirationDate() }} +

+ +
+ + + + + diff --git a/apps/browser/src/tools/popup/settings/settings-v2.component.html b/apps/browser/src/tools/popup/settings/settings-v2.component.html index 683b7d70ed6..06c89e15f59 100644 --- a/apps/browser/src/tools/popup/settings/settings-v2.component.html +++ b/apps/browser/src/tools/popup/settings/settings-v2.component.html @@ -34,13 +34,11 @@

{{ "autofill" | i18n }}

- 1 + @if (showAutofillBadge$ | async) { + 1 + }
diff --git a/apps/browser/src/tools/popup/settings/settings-v2.component.spec.ts b/apps/browser/src/tools/popup/settings/settings-v2.component.spec.ts index f51d514289e..4cc3ed0149c 100644 --- a/apps/browser/src/tools/popup/settings/settings-v2.component.spec.ts +++ b/apps/browser/src/tools/popup/settings/settings-v2.component.spec.ts @@ -148,31 +148,7 @@ describe("SettingsV2Component", () => { expect(openSpy).toHaveBeenCalledWith(dialogService); }); - it("isBrowserAutofillSettingOverridden$ emits the value from the AutofillBrowserSettingsService", async () => { - pushActiveAccount(); - - mockAutofillSettings.isBrowserAutofillSettingOverridden.mockResolvedValue(true); - - const fixture = TestBed.createComponent(SettingsV2Component); - const component = fixture.componentInstance; - fixture.detectChanges(); - await fixture.whenStable(); - - const value = await firstValueFrom(component["isBrowserAutofillSettingOverridden$"]); - expect(value).toBe(true); - - mockAutofillSettings.isBrowserAutofillSettingOverridden.mockResolvedValue(false); - - const fixture2 = TestBed.createComponent(SettingsV2Component); - const component2 = fixture2.componentInstance; - fixture2.detectChanges(); - await fixture2.whenStable(); - - const value2 = await firstValueFrom(component2["isBrowserAutofillSettingOverridden$"]); - expect(value2).toBe(false); - }); - - it("showAutofillBadge$ emits true when default autofill is NOT disabled and nudge is true", async () => { + it("showAutofillBadge$ emits true when showNudgeBadge is true", async () => { pushActiveAccount(); mockNudges.showNudgeBadge$.mockImplementation((type: NudgeType) => @@ -184,30 +160,10 @@ describe("SettingsV2Component", () => { fixture.detectChanges(); await fixture.whenStable(); - mockAutofillSettings.defaultBrowserAutofillDisabled$.next(false); - const value = await firstValueFrom(component.showAutofillBadge$); expect(value).toBe(true); }); - it("showAutofillBadge$ emits false when default autofill IS disabled even if nudge is true", async () => { - pushActiveAccount(); - - mockNudges.showNudgeBadge$.mockImplementation((type: NudgeType) => - of(type === NudgeType.AutofillNudge), - ); - - const fixture = TestBed.createComponent(SettingsV2Component); - const component = fixture.componentInstance; - fixture.detectChanges(); - await fixture.whenStable(); - - mockAutofillSettings.defaultBrowserAutofillDisabled$.next(true); - - const value = await firstValueFrom(component.showAutofillBadge$); - expect(value).toBe(false); - }); - it("dismissBadge dismisses when showVaultBadge$ emits true", async () => { const acct = pushActiveAccount(); diff --git a/apps/browser/src/tools/popup/settings/settings-v2.component.ts b/apps/browser/src/tools/popup/settings/settings-v2.component.ts index 95aeeb2f480..e10d41b9445 100644 --- a/apps/browser/src/tools/popup/settings/settings-v2.component.ts +++ b/apps/browser/src/tools/popup/settings/settings-v2.component.ts @@ -1,16 +1,7 @@ import { CommonModule } from "@angular/common"; import { ChangeDetectionStrategy, Component } from "@angular/core"; import { RouterModule } from "@angular/router"; -import { - combineLatest, - filter, - firstValueFrom, - from, - map, - Observable, - shareReplay, - switchMap, -} from "rxjs"; +import { filter, firstValueFrom, Observable, shareReplay, switchMap } from "rxjs"; import { PremiumUpgradeDialogComponent } from "@bitwarden/angular/billing/components"; import { JslibModule } from "@bitwarden/angular/jslib.module"; @@ -28,8 +19,6 @@ import { } from "@bitwarden/components"; import { CurrentAccountComponent } from "../../../auth/popup/account-switching/current-account.component"; -import { AutofillBrowserSettingsService } from "../../../autofill/services/autofill-browser-settings.service"; -import { BrowserApi } from "../../../platform/browser/browser-api"; import { PopOutComponent } from "../../../platform/popup/components/pop-out.component"; import { PopupHeaderComponent } from "../../../platform/popup/layout/popup-header.component"; import { PopupPageComponent } from "../../../platform/popup/layout/popup-page.component"; @@ -55,12 +44,6 @@ import { PopupPageComponent } from "../../../platform/popup/layout/popup-page.co export class SettingsV2Component { NudgeType = NudgeType; - protected isBrowserAutofillSettingOverridden$ = from( - this.autofillBrowserSettingsService.isBrowserAutofillSettingOverridden( - BrowserApi.getBrowserClientVendor(window), - ), - ); - private authenticatedAccount$: Observable = this.accountService.activeAccount$.pipe( filter((account): account is Account => account !== null), shareReplay({ bufferSize: 1, refCount: true }), @@ -82,23 +65,13 @@ export class SettingsV2Component { ), ); - showAutofillBadge$: Observable = combineLatest([ - this.autofillBrowserSettingsService.defaultBrowserAutofillDisabled$, - this.authenticatedAccount$, - ]).pipe( - switchMap(([defaultBrowserAutofillDisabled, account]) => - this.nudgesService.showNudgeBadge$(NudgeType.AutofillNudge, account.id).pipe( - map((badgeStatus) => { - return !defaultBrowserAutofillDisabled && badgeStatus; - }), - ), - ), + showAutofillBadge$: Observable = this.authenticatedAccount$.pipe( + switchMap((account) => this.nudgesService.showNudgeBadge$(NudgeType.AutofillNudge, account.id)), ); constructor( private readonly nudgesService: NudgesService, private readonly accountService: AccountService, - private readonly autofillBrowserSettingsService: AutofillBrowserSettingsService, private readonly accountProfileStateService: BillingAccountProfileStateService, private readonly dialogService: DialogService, ) {} diff --git a/apps/browser/src/vault/popup/components/vault-v2/autofill-confirmation-dialog/autofill-confirmation-dialog.component.html b/apps/browser/src/vault/popup/components/vault-v2/autofill-confirmation-dialog/autofill-confirmation-dialog.component.html index 88bff47191a..d8c12122120 100644 --- a/apps/browser/src/vault/popup/components/vault-v2/autofill-confirmation-dialog/autofill-confirmation-dialog.component.html +++ b/apps/browser/src/vault/popup/components/vault-v2/autofill-confirmation-dialog/autofill-confirmation-dialog.component.html @@ -15,8 +15,8 @@ } @if (savedUrls().length > 1) {
-

- {{ "savedWebsites" | i18n: savedUrls().length }} +

+ {{ "savedWebsites" | i18n: savedUrls().length.toString() }}

- - @if (!(autofillConfirmationFlagEnabled$ | async)) { - - } diff --git a/apps/browser/src/vault/popup/components/vault-v2/item-more-options/item-more-options.component.spec.ts b/apps/browser/src/vault/popup/components/vault-v2/item-more-options/item-more-options.component.spec.ts index b9f48b7407b..bd9ce108522 100644 --- a/apps/browser/src/vault/popup/components/vault-v2/item-more-options/item-more-options.component.spec.ts +++ b/apps/browser/src/vault/popup/components/vault-v2/item-more-options/item-more-options.component.spec.ts @@ -13,7 +13,6 @@ import { UriMatchStrategy, UriMatchStrategySetting, } from "@bitwarden/common/models/domain/domain-service"; -import { ConfigService } from "@bitwarden/common/platform/abstractions/config/config.service"; import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.service"; import { CipherArchiveService } from "@bitwarden/common/vault/abstractions/cipher-archive.service"; import { CipherService } from "@bitwarden/common/vault/abstractions/cipher.service"; @@ -40,10 +39,6 @@ describe("ItemMoreOptionsComponent", () => { openSimpleDialog: jest.fn().mockResolvedValue(true), open: jest.fn(), }; - const featureFlag$ = new BehaviorSubject(false); - const configService = { - getFeatureFlag$: jest.fn().mockImplementation(() => featureFlag$.asObservable()), - }; const cipherService = { getFullCipherView: jest.fn(), encrypt: jest.fn(), @@ -93,7 +88,6 @@ describe("ItemMoreOptionsComponent", () => { TestBed.configureTestingModule({ imports: [ItemMoreOptionsComponent, NoopAnimationsModule], providers: [ - { provide: ConfigService, useValue: configService }, { provide: CipherService, useValue: cipherService }, { provide: VaultPopupAutofillService, useValue: autofillSvc }, @@ -152,22 +146,6 @@ describe("ItemMoreOptionsComponent", () => { expect(passwordRepromptService.passwordRepromptCheck).toHaveBeenCalledWith(baseCipher); }); - it("calls the autofill service to autofill without showing the confirmation dialog when the feature flag is disabled", async () => { - autofillSvc.currentAutofillTab$.next({ url: "https://page.example.com" }); - - await component.doAutofill(); - - expect(cipherService.getFullCipherView).toHaveBeenCalled(); - expect(autofillSvc.doAutofill).toHaveBeenCalledTimes(1); - expect(autofillSvc.doAutofill).toHaveBeenCalledWith( - expect.objectContaining({ id: "cipher-1" }), - true, - true, - ); - expect(autofillSvc.doAutofillAndSave).not.toHaveBeenCalled(); - expect(dialogService.openSimpleDialog).not.toHaveBeenCalled(); - }); - it("does nothing if the user fails master password reprompt", async () => { baseCipher.reprompt = 2; // Master Password reprompt enabled autofillSvc.currentAutofillTab$.next({ url: "https://page.example.com" }); @@ -181,7 +159,6 @@ describe("ItemMoreOptionsComponent", () => { }); it("does not show the exact match dialog when the default match strategy is Exact and autofill confirmation is not to be shown", async () => { - // autofill confirmation dialog is not shown when either the feature flag is disabled uriMatchStrategy$.next(UriMatchStrategy.Exact); autofillSvc.currentAutofillTab$.next({ url: "https://page.example.com/path" }); await component.doAutofill(); @@ -191,8 +168,6 @@ describe("ItemMoreOptionsComponent", () => { describe("autofill confirmation dialog", () => { beforeEach(() => { - // autofill confirmation dialog is shown when feature flag is enabled - featureFlag$.next(true); uriMatchStrategy$.next(UriMatchStrategy.Domain); passwordRepromptService.passwordRepromptCheck.mockResolvedValue(true); }); @@ -206,7 +181,7 @@ describe("ItemMoreOptionsComponent", () => { expect(passwordRepromptService.passwordRepromptCheck).toHaveBeenCalledWith(baseCipher); }); - it("opens the autofill confirmation dialog with filtered saved URLs when the feature flag is enabled", async () => { + it("opens the autofill confirmation dialog with filtered saved URLs", async () => { autofillSvc.currentAutofillTab$.next({ url: "https://page.example.com/path" }); const openSpy = mockConfirmDialogResult(AutofillConfirmationDialogResult.Canceled); diff --git a/apps/browser/src/vault/popup/components/vault-v2/item-more-options/item-more-options.component.ts b/apps/browser/src/vault/popup/components/vault-v2/item-more-options/item-more-options.component.ts index b65acc6ca8e..c4353e17bef 100644 --- a/apps/browser/src/vault/popup/components/vault-v2/item-more-options/item-more-options.component.ts +++ b/apps/browser/src/vault/popup/components/vault-v2/item-more-options/item-more-options.component.ts @@ -11,9 +11,7 @@ import { OrganizationService } from "@bitwarden/common/admin-console/abstraction import { AccountService } from "@bitwarden/common/auth/abstractions/account.service"; import { getUserId } from "@bitwarden/common/auth/services/account.service"; import { DomainSettingsService } from "@bitwarden/common/autofill/services/domain-settings.service"; -import { FeatureFlag } from "@bitwarden/common/enums/feature-flag.enum"; import { UriMatchStrategy } from "@bitwarden/common/models/domain/domain-service"; -import { ConfigService } from "@bitwarden/common/platform/abstractions/config/config.service"; import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.service"; import { CipherId, UserId } from "@bitwarden/common/types/guid"; import { CipherArchiveService } from "@bitwarden/common/vault/abstractions/cipher-archive.service"; @@ -37,7 +35,6 @@ import { PasswordRepromptService } from "@bitwarden/vault"; import { BrowserPremiumUpgradePromptService } from "../../../services/browser-premium-upgrade-prompt.service"; import { VaultPopupAutofillService } from "../../../services/vault-popup-autofill.service"; -import { VaultPopupItemsService } from "../../../services/vault-popup-items.service"; import { AddEditQueryParams } from "../add-edit/add-edit-v2.component"; import { AutofillConfirmationDialogComponent, @@ -98,10 +95,6 @@ export class ItemMoreOptionsComponent { protected autofillAllowed$ = this.vaultPopupAutofillService.autofillAllowed$; - protected autofillConfirmationFlagEnabled$ = this.configService - .getFeatureFlag$(FeatureFlag.AutofillConfirmation) - .pipe(map((isFeatureFlagEnabled) => isFeatureFlagEnabled)); - protected uriMatchStrategy$ = this.domainSettingsService.resolvedDefaultUriMatchStrategy$; /** @@ -166,8 +159,6 @@ export class ItemMoreOptionsComponent { private collectionService: CollectionService, private restrictedItemTypesService: RestrictedItemTypesService, private cipherArchiveService: CipherArchiveService, - private configService: ConfigService, - private vaultPopupItemsService: VaultPopupItemsService, private domainSettingsService: DomainSettingsService, ) {} @@ -216,13 +207,9 @@ export class ItemMoreOptionsComponent { const cipherHasAllExactMatchLoginUris = uris.length > 0 && uris.every((u) => u.uri && u.match === UriMatchStrategy.Exact); - const showAutofillConfirmation = await firstValueFrom(this.autofillConfirmationFlagEnabled$); const uriMatchStrategy = await firstValueFrom(this.uriMatchStrategy$); - if ( - showAutofillConfirmation && - (cipherHasAllExactMatchLoginUris || uriMatchStrategy === UriMatchStrategy.Exact) - ) { + if (cipherHasAllExactMatchLoginUris || uriMatchStrategy === UriMatchStrategy.Exact) { await this.dialogService.openSimpleDialog({ title: { key: "cannotAutofill" }, content: { key: "cannotAutofillExactMatch" }, @@ -233,11 +220,6 @@ export class ItemMoreOptionsComponent { return; } - if (!showAutofillConfirmation) { - await this.vaultPopupAutofillService.doAutofill(cipher, true, true); - return; - } - const currentTab = await firstValueFrom(this.vaultPopupAutofillService.currentAutofillTab$); if (!currentTab?.url) { diff --git a/apps/browser/src/vault/popup/services/browser-autofill-nudge.service.spec.ts b/apps/browser/src/vault/popup/services/browser-autofill-nudge.service.spec.ts new file mode 100644 index 00000000000..40782760283 --- /dev/null +++ b/apps/browser/src/vault/popup/services/browser-autofill-nudge.service.spec.ts @@ -0,0 +1,157 @@ +import { TestBed } from "@angular/core/testing"; +import { mock, MockProxy } from "jest-mock-extended"; +import { firstValueFrom } from "rxjs"; + +import { NudgeStatus, NudgeType } from "@bitwarden/angular/vault"; +import { VaultProfileService } from "@bitwarden/angular/vault/services/vault-profile.service"; +import { BrowserClientVendors } from "@bitwarden/common/autofill/constants"; +import { LogService } from "@bitwarden/common/platform/abstractions/log.service"; +import { StateProvider } from "@bitwarden/common/platform/state"; +import { UserId } from "@bitwarden/common/types/guid"; + +import { FakeStateProvider, mockAccountServiceWith } from "../../../../../../libs/common/spec"; +import { BrowserApi } from "../../../platform/browser/browser-api"; + +import { BrowserAutofillNudgeService } from "./browser-autofill-nudge.service"; + +describe("BrowserAutofillNudgeService", () => { + let service: BrowserAutofillNudgeService; + let vaultProfileService: MockProxy; + let fakeStateProvider: FakeStateProvider; + + const userId = "test-user-id" as UserId; + const nudgeType = NudgeType.AutofillNudge; + + const notDismissedStatus: NudgeStatus = { + hasBadgeDismissed: false, + hasSpotlightDismissed: false, + }; + + const dismissedStatus: NudgeStatus = { + hasBadgeDismissed: true, + hasSpotlightDismissed: true, + }; + + // Set profile creation date to now (new account, within 30 days) + const recentProfileDate = new Date(); + + beforeEach(() => { + vaultProfileService = mock(); + vaultProfileService.getProfileCreationDate.mockResolvedValue(recentProfileDate); + + fakeStateProvider = new FakeStateProvider(mockAccountServiceWith(userId)); + + TestBed.configureTestingModule({ + providers: [ + BrowserAutofillNudgeService, + { + provide: VaultProfileService, + useValue: vaultProfileService, + }, + { + provide: StateProvider, + useValue: fakeStateProvider, + }, + { + provide: LogService, + useValue: mock(), + }, + ], + }); + + service = TestBed.inject(BrowserAutofillNudgeService); + }); + + afterEach(() => { + jest.restoreAllMocks(); + }); + + describe("nudgeStatus$", () => { + it("returns parent status when browser client is Unknown", async () => { + jest + .spyOn(BrowserApi, "getBrowserClientVendor") + .mockReturnValue(BrowserClientVendors.Unknown); + jest.spyOn(BrowserApi, "browserAutofillSettingsOverridden").mockResolvedValue(true); + + const result = await firstValueFrom(service.nudgeStatus$(nudgeType, userId)); + + expect(result).toEqual(notDismissedStatus); + }); + + it("returns parent status when browser autofill is not overridden", async () => { + jest.spyOn(BrowserApi, "getBrowserClientVendor").mockReturnValue(BrowserClientVendors.Chrome); + jest.spyOn(BrowserApi, "browserAutofillSettingsOverridden").mockResolvedValue(false); + + const result = await firstValueFrom(service.nudgeStatus$(nudgeType, userId)); + + expect(result).toEqual(notDismissedStatus); + }); + + it("returns dismissed status when browser autofill is overridden", async () => { + jest.spyOn(BrowserApi, "getBrowserClientVendor").mockReturnValue(BrowserClientVendors.Chrome); + jest.spyOn(BrowserApi, "browserAutofillSettingsOverridden").mockResolvedValue(true); + + const result = await firstValueFrom(service.nudgeStatus$(nudgeType, userId)); + + expect(result).toEqual(dismissedStatus); + }); + + it("preserves parent dismissed status when account is older than 30 days", async () => { + // Set profile creation date to more than 30 days ago + const oldProfileDate = new Date(Date.now() - 31 * 24 * 60 * 60 * 1000); + vaultProfileService.getProfileCreationDate.mockResolvedValue(oldProfileDate); + + jest.spyOn(BrowserApi, "getBrowserClientVendor").mockReturnValue(BrowserClientVendors.Chrome); + jest.spyOn(BrowserApi, "browserAutofillSettingsOverridden").mockResolvedValue(false); + + const result = await firstValueFrom(service.nudgeStatus$(nudgeType, userId)); + + expect(result).toEqual(dismissedStatus); + }); + + it("combines parent dismissed and browser autofill overridden status", async () => { + // Set profile creation date to more than 30 days ago (parent dismisses) + const oldProfileDate = new Date(Date.now() - 31 * 24 * 60 * 60 * 1000); + vaultProfileService.getProfileCreationDate.mockResolvedValue(oldProfileDate); + + jest.spyOn(BrowserApi, "getBrowserClientVendor").mockReturnValue(BrowserClientVendors.Chrome); + jest.spyOn(BrowserApi, "browserAutofillSettingsOverridden").mockResolvedValue(true); + + const result = await firstValueFrom(service.nudgeStatus$(nudgeType, userId)); + + expect(result).toEqual(dismissedStatus); + }); + + it.each([ + BrowserClientVendors.Chrome, + BrowserClientVendors.Edge, + BrowserClientVendors.Opera, + BrowserClientVendors.Vivaldi, + ])("checks browser autofill settings for %s browser", async (browserVendor) => { + const getBrowserClientVendorSpy = jest + .spyOn(BrowserApi, "getBrowserClientVendor") + .mockReturnValue(browserVendor); + const browserAutofillSettingsOverriddenSpy = jest + .spyOn(BrowserApi, "browserAutofillSettingsOverridden") + .mockResolvedValue(true); + + await firstValueFrom(service.nudgeStatus$(nudgeType, userId)); + + expect(getBrowserClientVendorSpy).toHaveBeenCalledWith(window); + expect(browserAutofillSettingsOverriddenSpy).toHaveBeenCalled(); + }); + + it("does not check browser autofill settings for Unknown browser", async () => { + jest + .spyOn(BrowserApi, "getBrowserClientVendor") + .mockReturnValue(BrowserClientVendors.Unknown); + const browserAutofillSettingsOverriddenSpy = jest + .spyOn(BrowserApi, "browserAutofillSettingsOverridden") + .mockResolvedValue(true); + + await firstValueFrom(service.nudgeStatus$(nudgeType, userId)); + + expect(browserAutofillSettingsOverriddenSpy).not.toHaveBeenCalled(); + }); + }); +}); diff --git a/apps/browser/src/vault/popup/services/browser-autofill-nudge.service.ts b/apps/browser/src/vault/popup/services/browser-autofill-nudge.service.ts new file mode 100644 index 00000000000..7fe5f527bcb --- /dev/null +++ b/apps/browser/src/vault/popup/services/browser-autofill-nudge.service.ts @@ -0,0 +1,37 @@ +import { Injectable } from "@angular/core"; +import { Observable, switchMap } from "rxjs"; + +import { NudgeStatus, NudgeType } from "@bitwarden/angular/vault"; +import { NewAccountNudgeService } from "@bitwarden/angular/vault/services/custom-nudges-services/new-account-nudge.service"; +import { BrowserClientVendors } from "@bitwarden/common/autofill/constants"; +import { UserId } from "@bitwarden/common/types/guid"; + +import { BrowserApi } from "../../../platform/browser/browser-api"; + +/** + * Browser-specific autofill nudge service. + * Extends NewAccountNudgeService (30-day account age check) and adds + * browser autofill setting detection. + * + * Nudge is dismissed if: + * - Account is older than 30 days (inherited from NewAccountNudgeService) + * - Browser's built-in password manager is already disabled via privacy settings + */ +@Injectable() +export class BrowserAutofillNudgeService extends NewAccountNudgeService { + override nudgeStatus$(nudgeType: NudgeType, userId: UserId): Observable { + return super.nudgeStatus$(nudgeType, userId).pipe( + switchMap(async (status) => { + const browserClient = BrowserApi.getBrowserClientVendor(window); + const browserAutofillOverridden = + browserClient !== BrowserClientVendors.Unknown && + (await BrowserApi.browserAutofillSettingsOverridden()); + + return { + hasBadgeDismissed: status.hasBadgeDismissed || browserAutofillOverridden, + hasSpotlightDismissed: status.hasSpotlightDismissed || browserAutofillOverridden, + }; + }), + ); + } +} diff --git a/apps/cli/package.json b/apps/cli/package.json index ff74664ac76..5174e324586 100644 --- a/apps/cli/package.json +++ b/apps/cli/package.json @@ -1,7 +1,7 @@ { "name": "@bitwarden/cli", "description": "A secure and free password manager for all of your devices.", - "version": "2025.12.0", + "version": "2025.12.1", "keywords": [ "bitwarden", "password", diff --git a/apps/cli/src/service-container/service-container.ts b/apps/cli/src/service-container/service-container.ts index 2f1e92d14fc..d98b5f0a861 100644 --- a/apps/cli/src/service-container/service-container.ts +++ b/apps/cli/src/service-container/service-container.ts @@ -104,6 +104,7 @@ import { EnvironmentService, RegionConfig, } from "@bitwarden/common/platform/abstractions/environment.service"; +import { RegisterSdkService } from "@bitwarden/common/platform/abstractions/sdk/register-sdk.service"; import { SdkLoadService } from "@bitwarden/common/platform/abstractions/sdk/sdk-load.service"; import { SdkService } from "@bitwarden/common/platform/abstractions/sdk/sdk.service"; import { LogLevelType } from "@bitwarden/common/platform/enums"; @@ -124,6 +125,7 @@ import { MigrationRunner } from "@bitwarden/common/platform/services/migration-r import { DefaultSdkClientFactory } from "@bitwarden/common/platform/services/sdk/default-sdk-client-factory"; import { DefaultSdkService } from "@bitwarden/common/platform/services/sdk/default-sdk.service"; import { NoopSdkClientFactory } from "@bitwarden/common/platform/services/sdk/noop-sdk-client-factory"; +import { DefaultRegisterSdkService } from "@bitwarden/common/platform/services/sdk/register-sdk.service"; import { StorageServiceProvider } from "@bitwarden/common/platform/services/storage-service.provider"; import { UserAutoUnlockKeyService } from "@bitwarden/common/platform/services/user-auto-unlock-key.service"; import { SyncService } from "@bitwarden/common/platform/sync"; @@ -323,6 +325,7 @@ export class ServiceContainer { kdfConfigService: KdfConfigService; taskSchedulerService: TaskSchedulerService; sdkService: SdkService; + registerSdkService: RegisterSdkService; sdkLoadService: SdkLoadService; cipherAuthorizationService: CipherAuthorizationService; ssoUrlService: SsoUrlService; @@ -632,26 +635,10 @@ export class ServiceContainer { this.accountService, ); - this.keyConnectorService = new KeyConnectorService( - this.accountService, - this.masterPasswordService, - this.keyService, - this.apiService, - this.tokenService, - this.logService, - this.organizationService, - this.keyGenerationService, - logoutCallback, + this.accountCryptographicStateService = new DefaultAccountCryptographicStateService( this.stateProvider, ); - this.twoFactorService = new DefaultTwoFactorService( - this.i18nService, - this.platformUtilsService, - this.globalStateProvider, - this.twoFactorApiService, - ); - const sdkClientFactory = flagEnabled("sdk") ? new DefaultSdkClientFactory() : new NoopSdkClientFactory(); @@ -670,6 +657,41 @@ export class ServiceContainer { customUserAgent, ); + this.registerSdkService = new DefaultRegisterSdkService( + sdkClientFactory, + this.environmentService, + this.platformUtilsService, + this.accountService, + this.apiService, + this.stateProvider, + this.configService, + customUserAgent, + ); + + this.keyConnectorService = new KeyConnectorService( + this.accountService, + this.masterPasswordService, + this.keyService, + this.apiService, + this.tokenService, + this.logService, + this.organizationService, + this.keyGenerationService, + logoutCallback, + this.stateProvider, + this.configService, + this.registerSdkService, + this.securityStateService, + this.accountCryptographicStateService, + ); + + this.twoFactorService = new DefaultTwoFactorService( + this.i18nService, + this.platformUtilsService, + this.globalStateProvider, + this.twoFactorApiService, + ); + this.passwordStrengthService = new PasswordStrengthService(); this.passwordGenerationService = legacyPasswordGenerationServiceFactory( @@ -719,10 +741,6 @@ export class ServiceContainer { this.accountService, ); - this.accountCryptographicStateService = new DefaultAccountCryptographicStateService( - this.stateProvider, - ); - this.loginStrategyService = new LoginStrategyService( this.accountService, this.masterPasswordService, diff --git a/apps/cli/stores/chocolatey/bitwarden-cli.nuspec b/apps/cli/stores/chocolatey/bitwarden-cli.nuspec index f7f86bc843f..9552ccc282c 100644 --- a/apps/cli/stores/chocolatey/bitwarden-cli.nuspec +++ b/apps/cli/stores/chocolatey/bitwarden-cli.nuspec @@ -10,7 +10,7 @@ Bitwarden Inc. https://bitwarden.com/ https://raw.githubusercontent.com/bitwarden/brand/master/icons/256x256.png - Copyright © 2015-2025 Bitwarden Inc. + Copyright © 2015-2026 Bitwarden Inc. https://github.com/bitwarden/clients/ https://help.bitwarden.com/article/cli/ https://github.com/bitwarden/clients/issues diff --git a/apps/desktop/desktop_native/Cargo.lock b/apps/desktop/desktop_native/Cargo.lock index 5978659f21e..f5e5cf7ee18 100644 --- a/apps/desktop/desktop_native/Cargo.lock +++ b/apps/desktop/desktop_native/Cargo.lock @@ -329,6 +329,7 @@ name = "autotype" version = "0.0.0" dependencies = [ "anyhow", + "itertools", "mockall", "serial_test", "tracing", @@ -1026,6 +1027,12 @@ dependencies = [ "zeroize", ] +[[package]] +name = "either" +version = "1.15.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "48c757948c5ede0e46177b7add2e67155f70e33c07fea8284df6576da70b3719" + [[package]] name = "elliptic-curve" version = "0.13.8" @@ -1617,6 +1624,15 @@ version = "1.70.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7943c866cc5cd64cbc25b2e01621d07fa8eb2a1a23160ee81ce38704e97b8ecf" +[[package]] +name = "itertools" +version = "0.14.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2b192c782037fadd9cfa75548310488aabdbf3d2da73885b31bd0abd03351285" +dependencies = [ + "either", +] + [[package]] name = "itoa" version = "1.0.15" diff --git a/apps/desktop/desktop_native/Cargo.toml b/apps/desktop/desktop_native/Cargo.toml index 26f791fd660..86eb507a6c1 100644 --- a/apps/desktop/desktop_native/Cargo.toml +++ b/apps/desktop/desktop_native/Cargo.toml @@ -39,6 +39,7 @@ futures = "=0.3.31" hex = "=0.4.3" homedir = "=0.3.6" interprocess = "=2.2.1" +itertools = "=0.14.0" libc = "=0.2.178" linux-keyutils = "=0.2.4" memsec = "=0.7.0" diff --git a/apps/desktop/desktop_native/autotype/Cargo.toml b/apps/desktop/desktop_native/autotype/Cargo.toml index 580df30e72d..6bf3218d98a 100644 --- a/apps/desktop/desktop_native/autotype/Cargo.toml +++ b/apps/desktop/desktop_native/autotype/Cargo.toml @@ -9,6 +9,7 @@ publish.workspace = true anyhow = { workspace = true } [target.'cfg(windows)'.dependencies] +itertools.workspace = true mockall = "=0.14.0" serial_test = "=3.2.0" tracing.workspace = true diff --git a/apps/desktop/desktop_native/autotype/src/lib.rs b/apps/desktop/desktop_native/autotype/src/lib.rs index c87fea23b60..4b9e65180e6 100644 --- a/apps/desktop/desktop_native/autotype/src/lib.rs +++ b/apps/desktop/desktop_native/autotype/src/lib.rs @@ -28,6 +28,6 @@ pub fn get_foreground_window_title() -> Result { /// This function returns an `anyhow::Error` if there is any /// issue in typing the input. Detailed reasons will /// vary based on platform implementation. -pub fn type_input(input: Vec, keyboard_shortcut: Vec) -> Result<()> { +pub fn type_input(input: &[u16], keyboard_shortcut: &[String]) -> Result<()> { windowing::type_input(input, keyboard_shortcut) } diff --git a/apps/desktop/desktop_native/autotype/src/linux.rs b/apps/desktop/desktop_native/autotype/src/linux.rs index 9fda0ed9e33..e7b0ee8117e 100644 --- a/apps/desktop/desktop_native/autotype/src/linux.rs +++ b/apps/desktop/desktop_native/autotype/src/linux.rs @@ -2,6 +2,6 @@ pub fn get_foreground_window_title() -> anyhow::Result { todo!("Bitwarden does not yet support Linux autotype"); } -pub fn type_input(_input: Vec, _keyboard_shortcut: Vec) -> anyhow::Result<()> { +pub fn type_input(_input: &[u16], _keyboard_shortcut: &[String]) -> anyhow::Result<()> { todo!("Bitwarden does not yet support Linux autotype"); } diff --git a/apps/desktop/desktop_native/autotype/src/macos.rs b/apps/desktop/desktop_native/autotype/src/macos.rs index c6681a3291e..56995a7f810 100644 --- a/apps/desktop/desktop_native/autotype/src/macos.rs +++ b/apps/desktop/desktop_native/autotype/src/macos.rs @@ -2,6 +2,6 @@ pub fn get_foreground_window_title() -> anyhow::Result { todo!("Bitwarden does not yet support macOS autotype"); } -pub fn type_input(_input: Vec, _keyboard_shortcut: Vec) -> anyhow::Result<()> { +pub fn type_input(_input: &[u16], _keyboard_shortcut: &[String]) -> anyhow::Result<()> { todo!("Bitwarden does not yet support macOS autotype"); } diff --git a/apps/desktop/desktop_native/autotype/src/windows/mod.rs b/apps/desktop/desktop_native/autotype/src/windows/mod.rs index 3ea63b2b8f4..9cd9bc0cbe5 100644 --- a/apps/desktop/desktop_native/autotype/src/windows/mod.rs +++ b/apps/desktop/desktop_native/autotype/src/windows/mod.rs @@ -1,6 +1,10 @@ use anyhow::Result; +use itertools::Itertools; use tracing::debug; -use windows::Win32::Foundation::{GetLastError, SetLastError, WIN32_ERROR}; +use windows::Win32::{ + Foundation::{GetLastError, SetLastError, WIN32_ERROR}, + UI::Input::KeyboardAndMouse::INPUT, +}; mod type_input; mod window_title; @@ -12,7 +16,7 @@ const WIN32_SUCCESS: WIN32_ERROR = WIN32_ERROR(0); /// win32 errors. #[cfg_attr(test, mockall::automock)] trait ErrorOperations { - /// https://learn.microsoft.com/en-us/windows/win32/api/errhandlingapi/nf-errhandlingapi-setlasterror + /// fn set_last_error(err: u32) { debug!(err, "Calling SetLastError"); unsafe { @@ -20,7 +24,7 @@ trait ErrorOperations { } } - /// https://learn.microsoft.com/en-us/windows/win32/api/errhandlingapi/nf-errhandlingapi-getlasterror + /// fn get_last_error() -> WIN32_ERROR { let last_err = unsafe { GetLastError() }; debug!("GetLastError(): {}", last_err.to_hresult().message()); @@ -36,6 +40,23 @@ pub fn get_foreground_window_title() -> Result { window_title::get_foreground_window_title() } -pub fn type_input(input: Vec, keyboard_shortcut: Vec) -> Result<()> { - type_input::type_input(input, keyboard_shortcut) +/// `KeyboardShortcutInput` is an `INPUT` of one of the valid shortcut keys: +/// - Control +/// - Alt +/// - Super +/// - Shift +/// - \[a-z\]\[A-Z\] +struct KeyboardShortcutInput(INPUT); + +pub fn type_input(input: &[u16], keyboard_shortcut: &[String]) -> Result<()> { + debug!(?keyboard_shortcut, "type_input() called."); + + // convert the raw string input to Windows input and error + // if any key is not a valid keyboard shortcut input + let keyboard_shortcut: Vec = keyboard_shortcut + .iter() + .map(|s| KeyboardShortcutInput::try_from(s.as_str())) + .try_collect()?; + + type_input::type_input(input, &keyboard_shortcut) } diff --git a/apps/desktop/desktop_native/autotype/src/windows/type_input.rs b/apps/desktop/desktop_native/autotype/src/windows/type_input.rs index b2f4c6b82df..b62dd7290d1 100644 --- a/apps/desktop/desktop_native/autotype/src/windows/type_input.rs +++ b/apps/desktop/desktop_native/autotype/src/windows/type_input.rs @@ -5,7 +5,15 @@ use windows::Win32::UI::Input::KeyboardAndMouse::{ VIRTUAL_KEY, }; -use super::{ErrorOperations, Win32ErrorOperations}; +use super::{ErrorOperations, KeyboardShortcutInput, Win32ErrorOperations}; + +const SHIFT_KEY_STR: &str = "Shift"; +const CONTROL_KEY_STR: &str = "Control"; +const ALT_KEY_STR: &str = "Alt"; +const LEFT_WINDOWS_KEY_STR: &str = "Super"; + +const IS_VIRTUAL_KEY: bool = true; +const IS_REAL_KEY: bool = false; /// `InputOperations` provides an interface to Window32 API for /// working with inputs. @@ -13,7 +21,7 @@ use super::{ErrorOperations, Win32ErrorOperations}; trait InputOperations { /// Attempts to type the provided input wherever the user's cursor is. /// - /// https://learn.microsoft.com/en-in/windows/win32/api/winuser/nf-winuser-sendinput + /// fn send_input(inputs: &[INPUT]) -> u32; } @@ -21,8 +29,11 @@ struct Win32InputOperations; impl InputOperations for Win32InputOperations { fn send_input(inputs: &[INPUT]) -> u32 { - const INPUT_STRUCT_SIZE: i32 = std::mem::size_of::() as i32; - let insert_count = unsafe { SendInput(inputs, INPUT_STRUCT_SIZE) }; + const INPUT_STRUCT_SIZE: usize = std::mem::size_of::(); + + let size = i32::try_from(INPUT_STRUCT_SIZE).expect("INPUT size to fit in i32"); + + let insert_count = unsafe { SendInput(inputs, size) }; debug!(insert_count, "SendInput() called."); @@ -33,40 +44,37 @@ impl InputOperations for Win32InputOperations { /// Attempts to type the input text wherever the user's cursor is. /// /// `input` must be a vector of utf-16 encoded characters to insert. -/// `keyboard_shortcut` must be a vector of Strings, where valid shortcut keys: Control, Alt, Super, -/// Shift, letters a - Z +/// `keyboard_shortcut` is a vector of valid shortcut keys. /// -/// https://learn.microsoft.com/en-in/windows/win32/api/winuser/nf-winuser-sendinput -pub(super) fn type_input(input: Vec, keyboard_shortcut: Vec) -> Result<()> { +/// +pub(super) fn type_input(input: &[u16], keyboard_shortcut: &[KeyboardShortcutInput]) -> Result<()> { // the length of this vec is always shortcut keys to release + (2x length of input chars) let mut keyboard_inputs: Vec = Vec::with_capacity(keyboard_shortcut.len() + (input.len() * 2)); - debug!(?keyboard_shortcut, "Converting keyboard shortcut to input."); - - // Add key "up" inputs for the shortcut - for key in keyboard_shortcut { - keyboard_inputs.push(convert_shortcut_key_to_up_input(key)?); + // insert the keyboard shortcut + for shortcut in keyboard_shortcut { + keyboard_inputs.push(shortcut.0); } - add_input(&input, &mut keyboard_inputs); + add_input(input, &mut keyboard_inputs); - send_input::(keyboard_inputs) + send_input::(&keyboard_inputs) } // Add key "down" and "up" inputs for the input // (currently in this form: {username}/t{password}) fn add_input(input: &[u16], keyboard_inputs: &mut Vec) { - const TAB_KEY: u8 = 9; + const TAB_KEY: u16 = 9; for i in input { - let next_down_input = if *i == TAB_KEY.into() { - build_virtual_key_input(InputKeyPress::Down, *i as u8) + let next_down_input = if *i == TAB_KEY { + build_virtual_key_input(InputKeyPress::Down, *i) } else { build_unicode_input(InputKeyPress::Down, *i) }; - let next_up_input = if *i == TAB_KEY.into() { - build_virtual_key_input(InputKeyPress::Up, *i as u8) + let next_up_input = if *i == TAB_KEY { + build_virtual_key_input(InputKeyPress::Up, *i) } else { build_unicode_input(InputKeyPress::Up, *i) }; @@ -76,26 +84,27 @@ fn add_input(input: &[u16], keyboard_inputs: &mut Vec) { } } -/// Converts a valid shortcut key to an "up" keyboard input. -/// -/// `input` must be a valid shortcut key: Control, Alt, Super, Shift, letters [a-z][A-Z] -fn convert_shortcut_key_to_up_input(key: String) -> Result { - const SHIFT_KEY: u8 = 0x10; - const SHIFT_KEY_STR: &str = "Shift"; - const CONTROL_KEY: u8 = 0x11; - const CONTROL_KEY_STR: &str = "Control"; - const ALT_KEY: u8 = 0x12; - const ALT_KEY_STR: &str = "Alt"; - const LEFT_WINDOWS_KEY: u8 = 0x5B; - const LEFT_WINDOWS_KEY_STR: &str = "Super"; +impl TryFrom<&str> for KeyboardShortcutInput { + type Error = anyhow::Error; - Ok(match key.as_str() { - SHIFT_KEY_STR => build_virtual_key_input(InputKeyPress::Up, SHIFT_KEY), - CONTROL_KEY_STR => build_virtual_key_input(InputKeyPress::Up, CONTROL_KEY), - ALT_KEY_STR => build_virtual_key_input(InputKeyPress::Up, ALT_KEY), - LEFT_WINDOWS_KEY_STR => build_virtual_key_input(InputKeyPress::Up, LEFT_WINDOWS_KEY), - _ => build_unicode_input(InputKeyPress::Up, get_alphabetic_hotkey(key)?), - }) + fn try_from(key: &str) -> std::result::Result { + const SHIFT_KEY: u16 = 0x10; + const CONTROL_KEY: u16 = 0x11; + const ALT_KEY: u16 = 0x12; + const LEFT_WINDOWS_KEY: u16 = 0x5B; + + // the modifier keys are using the Up keypress variant because the user has already + // pressed those keys in order to trigger the feature. + let input = match key { + SHIFT_KEY_STR => build_virtual_key_input(InputKeyPress::Up, SHIFT_KEY), + CONTROL_KEY_STR => build_virtual_key_input(InputKeyPress::Up, CONTROL_KEY), + ALT_KEY_STR => build_virtual_key_input(InputKeyPress::Up, ALT_KEY), + LEFT_WINDOWS_KEY_STR => build_virtual_key_input(InputKeyPress::Up, LEFT_WINDOWS_KEY), + _ => build_unicode_input(InputKeyPress::Up, get_alphabetic_hotkey(key)?), + }; + + Ok(KeyboardShortcutInput(input)) + } } /// Given a letter that is a String, get the utf16 encoded @@ -105,7 +114,7 @@ fn convert_shortcut_key_to_up_input(key: String) -> Result { /// Because we only accept [a-z][A-Z], the decimal u16 /// cast of the letter is safe because the unicode code point /// of these characters fits in a u16. -fn get_alphabetic_hotkey(letter: String) -> Result { +fn get_alphabetic_hotkey(letter: &str) -> Result { if letter.len() != 1 { error!( len = letter.len(), @@ -135,23 +144,28 @@ fn get_alphabetic_hotkey(letter: String) -> Result { } /// An input key can be either pressed (down), or released (up). +#[derive(Copy, Clone)] enum InputKeyPress { Down, Up, } -/// A function for easily building keyboard unicode INPUT structs used in SendInput(). -/// -/// Before modifying this function, make sure you read the SendInput() documentation: -/// https://learn.microsoft.com/en-in/windows/win32/api/winuser/nf-winuser-sendinput -fn build_unicode_input(key_press: InputKeyPress, character: u16) -> INPUT { +/// Before modifying this function, make sure you read the `SendInput()` documentation: +/// +/// +fn build_input(key_press: InputKeyPress, character: u16, is_virtual: bool) -> INPUT { + let (w_vk, w_scan) = if is_virtual { + (VIRTUAL_KEY(character), 0) + } else { + (VIRTUAL_KEY::default(), character) + }; match key_press { InputKeyPress::Down => INPUT { r#type: INPUT_KEYBOARD, Anonymous: INPUT_0 { ki: KEYBDINPUT { - wVk: Default::default(), - wScan: character, + wVk: w_vk, + wScan: w_scan, dwFlags: KEYEVENTF_UNICODE, time: 0, dwExtraInfo: 0, @@ -162,8 +176,8 @@ fn build_unicode_input(key_press: InputKeyPress, character: u16) -> INPUT { r#type: INPUT_KEYBOARD, Anonymous: INPUT_0 { ki: KEYBDINPUT { - wVk: Default::default(), - wScan: character, + wVk: w_vk, + wScan: w_scan, dwFlags: KEYEVENTF_KEYUP | KEYEVENTF_UNICODE, time: 0, dwExtraInfo: 0, @@ -173,53 +187,29 @@ fn build_unicode_input(key_press: InputKeyPress, character: u16) -> INPUT { } } -/// A function for easily building keyboard virtual-key INPUT structs used in SendInput(). -/// -/// Before modifying this function, make sure you read the SendInput() documentation: -/// https://learn.microsoft.com/en-in/windows/win32/api/winuser/nf-winuser-sendinput -/// https://learn.microsoft.com/en-us/windows/win32/inputdev/virtual-key-codes -fn build_virtual_key_input(key_press: InputKeyPress, virtual_key: u8) -> INPUT { - match key_press { - InputKeyPress::Down => INPUT { - r#type: INPUT_KEYBOARD, - Anonymous: INPUT_0 { - ki: KEYBDINPUT { - wVk: VIRTUAL_KEY(virtual_key as u16), - wScan: Default::default(), - dwFlags: Default::default(), - time: 0, - dwExtraInfo: 0, - }, - }, - }, - InputKeyPress::Up => INPUT { - r#type: INPUT_KEYBOARD, - Anonymous: INPUT_0 { - ki: KEYBDINPUT { - wVk: VIRTUAL_KEY(virtual_key as u16), - wScan: Default::default(), - dwFlags: KEYEVENTF_KEYUP, - time: 0, - dwExtraInfo: 0, - }, - }, - }, - } +/// A function for easily building keyboard unicode `INPUT` structs used in `SendInput()`. +fn build_unicode_input(key_press: InputKeyPress, character: u16) -> INPUT { + build_input(key_press, character, IS_REAL_KEY) } -fn send_input(inputs: Vec) -> Result<()> +/// A function for easily building keyboard virtual-key `INPUT` structs used in `SendInput()`. +fn build_virtual_key_input(key_press: InputKeyPress, character: u16) -> INPUT { + build_input(key_press, character, IS_VIRTUAL_KEY) +} + +fn send_input(inputs: &[INPUT]) -> Result<()> where I: InputOperations, E: ErrorOperations, { - let insert_count = I::send_input(&inputs); + let insert_count = I::send_input(inputs); if insert_count == 0 { let last_err = E::get_last_error().to_hresult().message(); error!(GetLastError = %last_err, "SendInput sent 0 inputs. Input was blocked by another thread."); return Err(anyhow!("SendInput sent 0 inputs. Input was blocked by another thread. GetLastError: {last_err}")); - } else if insert_count != inputs.len() as u32 { + } else if insert_count != u32::try_from(inputs.len()).expect("to convert inputs len to u32") { let last_err = E::get_last_error().to_hresult().message(); error!(sent = %insert_count, expected = inputs.len(), GetLastError = %last_err, "SendInput sent does not match expected." @@ -237,8 +227,9 @@ where mod tests { //! For the mocking of the traits that are static methods, we need to use the `serial_test` //! crate in order to mock those, since the mock expectations set have to be global in - //! absence of a `self`. More info: https://docs.rs/mockall/latest/mockall/#static-methods + //! absence of a `self`. More info: + use itertools::Itertools; use serial_test::serial; use windows::Win32::Foundation::WIN32_ERROR; @@ -249,7 +240,7 @@ mod tests { fn get_alphabetic_hot_key_succeeds() { for c in ('a'..='z').chain('A'..='Z') { let letter = c.to_string(); - let converted = get_alphabetic_hotkey(letter).unwrap(); + let converted = get_alphabetic_hotkey(&letter).unwrap(); assert_eq!(converted, c as u16); } } @@ -258,14 +249,14 @@ mod tests { #[should_panic = "Final keyboard shortcut key should be a single character: foo"] fn get_alphabetic_hot_key_fail_not_single_char() { let letter = String::from("foo"); - get_alphabetic_hotkey(letter).unwrap(); + get_alphabetic_hotkey(&letter).unwrap(); } #[test] #[should_panic = "Letter is not ASCII Alphabetic ([a-z][A-Z]): '}'"] fn get_alphabetic_hot_key_fail_not_alphabetic() { let letter = String::from("}"); - get_alphabetic_hotkey(letter).unwrap(); + get_alphabetic_hotkey(&letter).unwrap(); } #[test] @@ -275,7 +266,7 @@ mod tests { ctxi.checkpoint(); ctxi.expect().returning(|_| 1); - send_input::(vec![build_unicode_input( + send_input::(&[build_unicode_input( InputKeyPress::Up, 0, )]) @@ -284,6 +275,29 @@ mod tests { drop(ctxi); } + #[test] + #[serial] + fn keyboard_shortcut_conversion_succeeds() { + let keyboard_shortcut = [CONTROL_KEY_STR, SHIFT_KEY_STR, "B"]; + let _: Vec = keyboard_shortcut + .iter() + .map(|s| KeyboardShortcutInput::try_from(*s)) + .try_collect() + .unwrap(); + } + + #[test] + #[serial] + #[should_panic = "Letter is not ASCII Alphabetic ([a-z][A-Z]): '1'"] + fn keyboard_shortcut_conversion_fails_invalid_key() { + let keyboard_shortcut = [CONTROL_KEY_STR, SHIFT_KEY_STR, "1"]; + let _: Vec = keyboard_shortcut + .iter() + .map(|s| KeyboardShortcutInput::try_from(*s)) + .try_collect() + .unwrap(); + } + #[test] #[serial] #[should_panic( @@ -298,7 +312,7 @@ mod tests { ctxge.checkpoint(); ctxge.expect().returning(|| WIN32_ERROR(1)); - send_input::(vec![build_unicode_input( + send_input::(&[build_unicode_input( InputKeyPress::Up, 0, )]) @@ -320,7 +334,7 @@ mod tests { ctxge.checkpoint(); ctxge.expect().returning(|| WIN32_ERROR(1)); - send_input::(vec![build_unicode_input( + send_input::(&[build_unicode_input( InputKeyPress::Up, 0, )]) diff --git a/apps/desktop/desktop_native/autotype/src/windows/window_title.rs b/apps/desktop/desktop_native/autotype/src/windows/window_title.rs index 4fc0b3bb3ad..12e6501a7c5 100644 --- a/apps/desktop/desktop_native/autotype/src/windows/window_title.rs +++ b/apps/desktop/desktop_native/autotype/src/windows/window_title.rs @@ -11,10 +11,10 @@ use super::{ErrorOperations, Win32ErrorOperations, WIN32_SUCCESS}; #[cfg_attr(test, mockall::automock)] trait WindowHandleOperations { - // https://learn.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-getwindowtextlengthw + // fn get_window_text_length_w(&self) -> Result; - // https://learn.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-getwindowtextw + // fn get_window_text_w(&self, buffer: &mut Vec) -> Result; } @@ -70,7 +70,7 @@ pub(super) fn get_foreground_window_title() -> Result { /// Retrieves the foreground window handle and validates it. fn get_foreground_window_handle() -> Result { - // https://learn.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-getforegroundwindow + // let handle = unsafe { GetForegroundWindow() }; debug!("GetForegroundWindow() called."); @@ -87,7 +87,7 @@ fn get_foreground_window_handle() -> Result { /// /// # Errors /// -/// - If the length zero and GetLastError() != 0, return the GetLastError() message. +/// - If the length zero and `GetLastError()` != 0, return the `GetLastError()` message. fn get_window_title_length(window_handle: &H) -> Result where H: WindowHandleOperations, @@ -128,7 +128,7 @@ where /// # Errors /// /// - If the actual window title length (what the win32 API declares was written into the buffer), -/// is length zero and GetLastError() != 0 , return the GetLastError() message. +/// is length zero and `GetLastError()` != 0 , return the `GetLastError()` message. fn get_window_title(window_handle: &H, expected_title_length: usize) -> Result where H: WindowHandleOperations, @@ -140,7 +140,7 @@ where // The upstream will make a contains comparison on what we return, so an empty string // will not result on a match. warn!("Window title length is zero."); - return Ok(String::from("")); + return Ok(String::new()); } let mut buffer: Vec = vec![0; expected_title_length + 1]; // add extra space for the null character @@ -171,7 +171,7 @@ where mod tests { //! For the mocking of the traits that are static methods, we need to use the `serial_test` //! crate in order to mock those, since the mock expectations set have to be global in - //! absence of a `self`. More info: https://docs.rs/mockall/latest/mockall/#static-methods + //! absence of a `self`. More info: use mockall::predicate; use serial_test::serial; diff --git a/apps/desktop/desktop_native/napi/src/lib.rs b/apps/desktop/desktop_native/napi/src/lib.rs index fe084349501..588f757631c 100644 --- a/apps/desktop/desktop_native/napi/src/lib.rs +++ b/apps/desktop/desktop_native/napi/src/lib.rs @@ -1241,8 +1241,7 @@ pub mod autotype { input: Vec, keyboard_shortcut: Vec, ) -> napi::Result<(), napi::Status> { - autotype::type_input(input, keyboard_shortcut).map_err(|_| { - napi::Error::from_reason("Autotype Error: failed to type input".to_string()) - }) + autotype::type_input(&input, &keyboard_shortcut) + .map_err(|e| napi::Error::from_reason(format!("Autotype Error: {e}"))) } } diff --git a/apps/desktop/electron-builder.beta.json b/apps/desktop/electron-builder.beta.json index 630a956560d..0c95c7f01a6 100644 --- a/apps/desktop/electron-builder.beta.json +++ b/apps/desktop/electron-builder.beta.json @@ -5,7 +5,7 @@ "productName": "Bitwarden Beta", "appId": "com.bitwarden.desktop.beta", "buildDependenciesFromSource": true, - "copyright": "Copyright © 2015-2025 Bitwarden Inc.", + "copyright": "Copyright © 2015-2026 Bitwarden Inc.", "directories": { "buildResources": "resources", "output": "dist", diff --git a/apps/desktop/electron-builder.json b/apps/desktop/electron-builder.json index f979df81fd0..a4e1c44dc5b 100644 --- a/apps/desktop/electron-builder.json +++ b/apps/desktop/electron-builder.json @@ -5,7 +5,7 @@ "productName": "Bitwarden", "appId": "com.bitwarden.desktop", "buildDependenciesFromSource": true, - "copyright": "Copyright © 2015-2025 Bitwarden Inc.", + "copyright": "Copyright © 2015-2026 Bitwarden Inc.", "directories": { "buildResources": "resources", "output": "dist", diff --git a/apps/desktop/src/app/app.component.ts b/apps/desktop/src/app/app.component.ts index 836328142b5..d75702ee8b8 100644 --- a/apps/desktop/src/app/app.component.ts +++ b/apps/desktop/src/app/app.component.ts @@ -70,6 +70,7 @@ import { SyncService } from "@bitwarden/common/platform/sync"; import { UserId } from "@bitwarden/common/types/guid"; import { CipherService } from "@bitwarden/common/vault/abstractions/cipher.service"; import { InternalFolderService } from "@bitwarden/common/vault/abstractions/folder/folder.service.abstraction"; +import { PremiumUpgradePromptService } from "@bitwarden/common/vault/abstractions/premium-upgrade-prompt.service"; import { SearchService } from "@bitwarden/common/vault/abstractions/search.service"; import { CipherType } from "@bitwarden/common/vault/enums"; import { RestrictedItemTypesService } from "@bitwarden/common/vault/services/restricted-item-types.service"; @@ -198,6 +199,7 @@ export class AppComponent implements OnInit, OnDestroy { private readonly tokenService: TokenService, private desktopAutotypeDefaultSettingPolicy: DesktopAutotypeDefaultSettingPolicy, private readonly lockService: LockService, + private premiumUpgradePromptService: PremiumUpgradePromptService, ) { this.deviceTrustToastService.setupListeners$.pipe(takeUntilDestroyed()).subscribe(); @@ -305,7 +307,7 @@ export class AppComponent implements OnInit, OnDestroy { await this.openModal(SettingsComponent, this.settingsRef); break; case "openPremium": - this.dialogService.open(PremiumComponent); + await this.premiumUpgradePromptService.promptForPremium(); break; case "showFingerprintPhrase": { const activeUserId = await firstValueFrom( diff --git a/apps/desktop/src/app/app.module.ts b/apps/desktop/src/app/app.module.ts index 31131c6202a..52a52ffd225 100644 --- a/apps/desktop/src/app/app.module.ts +++ b/apps/desktop/src/app/app.module.ts @@ -8,6 +8,7 @@ import { BrowserAnimationsModule } from "@angular/platform-browser/animations"; import { ColorPasswordCountPipe } from "@bitwarden/angular/pipes/color-password-count.pipe"; import { ColorPasswordPipe } from "@bitwarden/angular/pipes/color-password.pipe"; +import { PremiumUpgradePromptService } from "@bitwarden/common/vault/abstractions/premium-upgrade-prompt.service"; import { CalloutModule, DialogModule } from "@bitwarden/components"; import { AssignCollectionsComponent } from "@bitwarden/vault"; @@ -15,6 +16,7 @@ import { DeleteAccountComponent } from "../auth/delete-account.component"; import { LoginModule } from "../auth/login/login.module"; import { SshAgentService } from "../autofill/services/ssh-agent.service"; import { PremiumComponent } from "../billing/app/accounts/premium.component"; +import { DesktopPremiumUpgradePromptService } from "../services/desktop-premium-upgrade-prompt.service"; import { VaultFilterModule } from "../vault/app/vault/vault-filter/vault-filter.module"; import { VaultV2Component } from "../vault/app/vault/vault-v2.component"; @@ -51,7 +53,13 @@ import { SharedModule } from "./shared/shared.module"; PremiumComponent, SearchComponent, ], - providers: [SshAgentService], + providers: [ + SshAgentService, + { + provide: PremiumUpgradePromptService, + useClass: DesktopPremiumUpgradePromptService, + }, + ], bootstrap: [AppComponent], }) export class AppModule {} diff --git a/apps/desktop/src/app/layout/desktop-layout.component.spec.ts b/apps/desktop/src/app/layout/desktop-layout.component.spec.ts index 74cddd02495..253444232e5 100644 --- a/apps/desktop/src/app/layout/desktop-layout.component.spec.ts +++ b/apps/desktop/src/app/layout/desktop-layout.component.spec.ts @@ -4,7 +4,9 @@ import { RouterModule } from "@angular/router"; import { mock } from "jest-mock-extended"; import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.service"; +import { FakeGlobalStateProvider } from "@bitwarden/common/spec"; import { NavigationModule } from "@bitwarden/components"; +import { GlobalStateProvider } from "@bitwarden/state"; import { SendFiltersNavComponent } from "../tools/send-v2/send-filters-nav.component"; @@ -36,6 +38,8 @@ describe("DesktopLayoutComponent", () => { let component: DesktopLayoutComponent; let fixture: ComponentFixture; + const fakeGlobalStateProvider = new FakeGlobalStateProvider(); + beforeEach(async () => { await TestBed.configureTestingModule({ imports: [DesktopLayoutComponent, RouterModule.forRoot([]), NavigationModule], @@ -44,6 +48,10 @@ describe("DesktopLayoutComponent", () => { provide: I18nService, useValue: mock(), }, + { + provide: GlobalStateProvider, + useValue: fakeGlobalStateProvider, + }, ], }) .overrideComponent(DesktopLayoutComponent, { diff --git a/apps/desktop/src/app/layout/desktop-side-nav.component.spec.ts b/apps/desktop/src/app/layout/desktop-side-nav.component.spec.ts index 4d5c3a90253..9b99dbf09c2 100644 --- a/apps/desktop/src/app/layout/desktop-side-nav.component.spec.ts +++ b/apps/desktop/src/app/layout/desktop-side-nav.component.spec.ts @@ -2,7 +2,9 @@ import { ComponentFixture, TestBed } from "@angular/core/testing"; import { mock } from "jest-mock-extended"; import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.service"; +import { FakeGlobalStateProvider } from "@bitwarden/common/spec"; import { NavigationModule } from "@bitwarden/components"; +import { GlobalStateProvider } from "@bitwarden/state"; import { DesktopSideNavComponent } from "./desktop-side-nav.component"; @@ -24,6 +26,8 @@ describe("DesktopSideNavComponent", () => { let component: DesktopSideNavComponent; let fixture: ComponentFixture; + const fakeGlobalStateProvider = new FakeGlobalStateProvider(); + beforeEach(async () => { await TestBed.configureTestingModule({ imports: [DesktopSideNavComponent, NavigationModule], @@ -32,6 +36,10 @@ describe("DesktopSideNavComponent", () => { provide: I18nService, useValue: mock(), }, + { + provide: GlobalStateProvider, + useValue: fakeGlobalStateProvider, + }, ], }).compileComponents(); diff --git a/apps/desktop/src/app/tools/send-v2/send-filters-nav.component.spec.ts b/apps/desktop/src/app/tools/send-v2/send-filters-nav.component.spec.ts index 95ba5c53e36..ab881e5b57b 100644 --- a/apps/desktop/src/app/tools/send-v2/send-filters-nav.component.spec.ts +++ b/apps/desktop/src/app/tools/send-v2/send-filters-nav.component.spec.ts @@ -5,9 +5,11 @@ import { RouterTestingHarness } from "@angular/router/testing"; import { BehaviorSubject } from "rxjs"; import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.service"; +import { FakeGlobalStateProvider } from "@bitwarden/common/spec"; import { SendType } from "@bitwarden/common/tools/send/enums/send-type"; import { NavigationModule } from "@bitwarden/components"; import { SendListFiltersService } from "@bitwarden/send-ui"; +import { GlobalStateProvider } from "@bitwarden/state"; import { SendFiltersNavComponent } from "./send-filters-nav.component"; @@ -35,6 +37,8 @@ describe("SendFiltersNavComponent", () => { let filterFormValueSubject: BehaviorSubject<{ sendType: SendType | null }>; let mockSendListFiltersService: Partial; + const fakeGlobalStateProvider = new FakeGlobalStateProvider(); + beforeEach(async () => { filterFormValueSubject = new BehaviorSubject<{ sendType: SendType | null }>({ sendType: null, @@ -72,6 +76,10 @@ describe("SendFiltersNavComponent", () => { t: jest.fn((key) => key), }, }, + { + provide: GlobalStateProvider, + useValue: fakeGlobalStateProvider, + }, ], }).compileComponents(); diff --git a/apps/desktop/src/locales/en/messages.json b/apps/desktop/src/locales/en/messages.json index d26a46a9efe..9be96a62589 100644 --- a/apps/desktop/src/locales/en/messages.json +++ b/apps/desktop/src/locales/en/messages.json @@ -4388,6 +4388,9 @@ "sessionTimeoutHeader": { "message": "Session timeout" }, + "resizeSideNavigation": { + "message": "Resize side navigation" + }, "sessionTimeoutSettingsManagedByOrganization": { "message": "This setting is managed by your organization." }, diff --git a/apps/desktop/src/locales/zh_CN/messages.json b/apps/desktop/src/locales/zh_CN/messages.json index 7d1c1648bb6..b80e1cea689 100644 --- a/apps/desktop/src/locales/zh_CN/messages.json +++ b/apps/desktop/src/locales/zh_CN/messages.json @@ -709,7 +709,7 @@ "message": "添加附件" }, "itemsTransferred": { - "message": "项目已传输" + "message": "项目已转移" }, "fixEncryption": { "message": "修复加密" @@ -4454,7 +4454,7 @@ "message": "我该如何管理我的密码库?" }, "transferItemsToOrganizationTitle": { - "message": "传输项目到 $ORGANIZATION$", + "message": "转移项目到 $ORGANIZATION$", "placeholders": { "organization": { "content": "$1", @@ -4463,7 +4463,7 @@ } }, "transferItemsToOrganizationContent": { - "message": "出于安全和合规考虑,$ORGANIZATION$ 要求所有项目归组织所有。点击「接受」以传输您的项目的所有权。", + "message": "出于安全和合规考虑,$ORGANIZATION$ 要求所有项目归组织所有。点击「接受」以转移您的项目的所有权。", "placeholders": { "organization": { "content": "$1", @@ -4472,7 +4472,7 @@ } }, "acceptTransfer": { - "message": "接受传输" + "message": "接受转移" }, "declineAndLeave": { "message": "拒绝并退出" diff --git a/apps/desktop/src/services/desktop-premium-upgrade-prompt.service.spec.ts b/apps/desktop/src/services/desktop-premium-upgrade-prompt.service.spec.ts index 1eee4cd54f6..3c36d648167 100644 --- a/apps/desktop/src/services/desktop-premium-upgrade-prompt.service.spec.ts +++ b/apps/desktop/src/services/desktop-premium-upgrade-prompt.service.spec.ts @@ -4,26 +4,24 @@ import { mock, MockProxy } from "jest-mock-extended"; import { PremiumUpgradeDialogComponent } from "@bitwarden/angular/billing/components"; import { FeatureFlag } from "@bitwarden/common/enums/feature-flag.enum"; import { ConfigService } from "@bitwarden/common/platform/abstractions/config/config.service"; -import { MessagingService } from "@bitwarden/common/platform/abstractions/messaging.service"; import { DialogService } from "@bitwarden/components"; +import { PremiumComponent } from "../billing/app/accounts/premium.component"; + import { DesktopPremiumUpgradePromptService } from "./desktop-premium-upgrade-prompt.service"; describe("DesktopPremiumUpgradePromptService", () => { let service: DesktopPremiumUpgradePromptService; - let messager: MockProxy; let configService: MockProxy; let dialogService: MockProxy; beforeEach(async () => { - messager = mock(); configService = mock(); dialogService = mock(); await TestBed.configureTestingModule({ providers: [ DesktopPremiumUpgradePromptService, - { provide: MessagingService, useValue: messager }, { provide: ConfigService, useValue: configService }, { provide: DialogService, useValue: dialogService }, ], @@ -52,10 +50,10 @@ describe("DesktopPremiumUpgradePromptService", () => { FeatureFlag.PM23713_PremiumBadgeOpensNewPremiumUpgradeDialog, ); expect(openSpy).toHaveBeenCalledWith(dialogService); - expect(messager.send).not.toHaveBeenCalled(); + expect(dialogService.open).not.toHaveBeenCalled(); }); - it("sends openPremium message when feature flag is disabled", async () => { + it("opens the PremiumComponent when feature flag is disabled", async () => { configService.getFeatureFlag.mockResolvedValue(false); await service.promptForPremium(); @@ -63,7 +61,7 @@ describe("DesktopPremiumUpgradePromptService", () => { expect(configService.getFeatureFlag).toHaveBeenCalledWith( FeatureFlag.PM23713_PremiumBadgeOpensNewPremiumUpgradeDialog, ); - expect(messager.send).toHaveBeenCalledWith("openPremium"); + expect(dialogService.open).toHaveBeenCalledWith(PremiumComponent); expect(openSpy).not.toHaveBeenCalled(); }); }); diff --git a/apps/desktop/src/services/desktop-premium-upgrade-prompt.service.ts b/apps/desktop/src/services/desktop-premium-upgrade-prompt.service.ts index 5004e5ed547..0161baba801 100644 --- a/apps/desktop/src/services/desktop-premium-upgrade-prompt.service.ts +++ b/apps/desktop/src/services/desktop-premium-upgrade-prompt.service.ts @@ -3,15 +3,15 @@ import { inject } from "@angular/core"; import { PremiumUpgradeDialogComponent } from "@bitwarden/angular/billing/components"; import { FeatureFlag } from "@bitwarden/common/enums/feature-flag.enum"; import { ConfigService } from "@bitwarden/common/platform/abstractions/config/config.service"; -import { MessagingService } from "@bitwarden/common/platform/abstractions/messaging.service"; import { PremiumUpgradePromptService } from "@bitwarden/common/vault/abstractions/premium-upgrade-prompt.service"; import { DialogService } from "@bitwarden/components"; +import { PremiumComponent } from "../billing/app/accounts/premium.component"; + /** * This class handles the premium upgrade process for the desktop. */ export class DesktopPremiumUpgradePromptService implements PremiumUpgradePromptService { - private messagingService = inject(MessagingService); private configService = inject(ConfigService); private dialogService = inject(DialogService); @@ -23,7 +23,7 @@ export class DesktopPremiumUpgradePromptService implements PremiumUpgradePromptS if (showNewDialog) { PremiumUpgradeDialogComponent.open(this.dialogService); } else { - this.messagingService.send("openPremium"); + this.dialogService.open(PremiumComponent); } } } diff --git a/apps/desktop/src/vault/app/vault/vault-v2.component.ts b/apps/desktop/src/vault/app/vault/vault-v2.component.ts index 6c4ebe13f14..730891f6dea 100644 --- a/apps/desktop/src/vault/app/vault/vault-v2.component.ts +++ b/apps/desktop/src/vault/app/vault/vault-v2.component.ts @@ -565,7 +565,7 @@ export class VaultV2Component } } - if (!cipher.organizationId && !cipher.isDeleted && !cipher.isArchived) { + if (userCanArchive && !cipher.isDeleted && !cipher.isArchived) { menu.push({ label: this.i18nService.t("archiveVerb"), click: async () => { diff --git a/apps/desktop/stores/chocolatey/bitwarden.nuspec b/apps/desktop/stores/chocolatey/bitwarden.nuspec index 450fa734736..567002d0d8c 100644 --- a/apps/desktop/stores/chocolatey/bitwarden.nuspec +++ b/apps/desktop/stores/chocolatey/bitwarden.nuspec @@ -10,7 +10,7 @@ Bitwarden Inc. https://bitwarden.com/ https://raw.githubusercontent.com/bitwarden/brand/master/icons/256x256.png - Copyright © 2015-2025 Bitwarden Inc. + Copyright © 2015-2026 Bitwarden Inc. https://github.com/bitwarden/clients/ https://bitwarden.com/help/ https://github.com/bitwarden/clients/issues diff --git a/apps/web/package.json b/apps/web/package.json index a5399de920e..b92fc5f736a 100644 --- a/apps/web/package.json +++ b/apps/web/package.json @@ -1,6 +1,6 @@ { "name": "@bitwarden/web-vault", - "version": "2025.12.1", + "version": "2025.12.2", "scripts": { "build:oss": "webpack", "build:bit": "webpack -c ../../bitwarden_license/bit-web/webpack.config.js", diff --git a/apps/web/src/app/admin-console/organizations/collections/vault.component.ts b/apps/web/src/app/admin-console/organizations/collections/vault.component.ts index f827dda9a9b..4adf3739845 100644 --- a/apps/web/src/app/admin-console/organizations/collections/vault.component.ts +++ b/apps/web/src/app/admin-console/organizations/collections/vault.component.ts @@ -587,6 +587,9 @@ export class VaultComponent implements OnInit, OnDestroy { queryParams: { search: Utils.isNullOrEmpty(searchText) ? null : searchText }, queryParamsHandling: "merge", replaceUrl: true, + state: { + focusMainAfterNav: false, + }, }), ); diff --git a/apps/web/src/app/auth/settings/two-factor/two-factor-setup-webauthn.component.html b/apps/web/src/app/auth/settings/two-factor/two-factor-setup-webauthn.component.html index c272a8e5b70..8a538cb961c 100644 --- a/apps/web/src/app/auth/settings/two-factor/two-factor-setup-webauthn.component.html +++ b/apps/web/src/app/auth/settings/two-factor/two-factor-setup-webauthn.component.html @@ -16,27 +16,26 @@ FIDO2 WebAuthn logo
  • - - - {{ "webAuthnkeyX" | i18n: (i + 1).toString() }} - - - {{ k.name }} - - - - {{ "webAuthnMigrated" | i18n }} + + + + {{ k.name || ("unnamedKey" | i18n) }} + + + + {{ "webAuthnMigrated" | i18n }} + + + + + - + {{ "remove" | i18n }} - - - - - - {{ "remove" | i18n }}
@@ -60,7 +59,9 @@ type="button" [bitAction]="readKey" buttonType="secondary" - [disabled]="$any(readKeyBtn).loading() || webAuthnListening || !keyIdAvailable" + [disabled]=" + $any(readKeyBtn).loading() || webAuthnListening || !keyIdAvailable || formGroup.invalid + " class="tw-mr-2" #readKeyBtn > diff --git a/apps/web/src/app/auth/settings/two-factor/two-factor-setup-webauthn.component.ts b/apps/web/src/app/auth/settings/two-factor/two-factor-setup-webauthn.component.ts index 11ba5955902..57001acc4d2 100644 --- a/apps/web/src/app/auth/settings/two-factor/two-factor-setup-webauthn.component.ts +++ b/apps/web/src/app/auth/settings/two-factor/two-factor-setup-webauthn.component.ts @@ -1,6 +1,6 @@ import { CommonModule } from "@angular/common"; import { Component, Inject, NgZone } from "@angular/core"; -import { FormControl, FormGroup, ReactiveFormsModule } from "@angular/forms"; +import { FormControl, FormGroup, ReactiveFormsModule, Validators } from "@angular/forms"; import { JslibModule } from "@bitwarden/angular/jslib.module"; import { UserVerificationService } from "@bitwarden/common/auth/abstractions/user-verification/user-verification.service.abstraction"; @@ -99,7 +99,7 @@ export class TwoFactorSetupWebAuthnComponent extends TwoFactorSetupMethodBaseCom toastService, ); this.formGroup = new FormGroup({ - name: new FormControl({ value: "", disabled: false }), + name: new FormControl({ value: "", disabled: false }, Validators.required), }); this.auth(data); } @@ -213,7 +213,22 @@ export class TwoFactorSetupWebAuthnComponent extends TwoFactorSetupMethodBaseCom this.webAuthnListening = listening; } + private findNextAvailableKeyId(existingIds: Set): number { + // Search for first gap, bounded by current key count + 1 + for (let i = 1; i <= existingIds.size + 1; i++) { + if (!existingIds.has(i)) { + return i; + } + } + + // This should never be reached due to loop bounds, but TypeScript requires a return + throw new Error("Unable to find next available key ID"); + } + private processResponse(response: TwoFactorWebAuthnResponse) { + if (!response.keys || response.keys.length === 0) { + response.keys = []; + } this.resetWebAuthn(); this.keys = []; this.keyIdAvailable = null; @@ -223,26 +238,37 @@ export class TwoFactorSetupWebAuthnComponent extends TwoFactorSetupMethodBaseCom nameControl.setValue(""); } this.keysConfiguredCount = 0; - for (let i = 1; i <= 5; i++) { - if (response.keys != null) { - const key = response.keys.filter((k) => k.id === i); - if (key.length > 0) { - this.keysConfiguredCount++; - this.keys.push({ - id: i, - name: key[0].name, - configured: true, - migrated: key[0].migrated, - removePromise: null, - }); - continue; - } - } - this.keys.push({ id: i, name: "", configured: false, removePromise: null }); - if (this.keyIdAvailable == null) { - this.keyIdAvailable = i; - } + + // Build configured keys + for (const key of response.keys) { + this.keysConfiguredCount++; + this.keys.push({ + id: key.id, + name: key.name, + configured: true, + migrated: key.migrated, + removePromise: null, + }); } + + // [PM-20109]: To accommodate the existing form logic with minimal changes, + // we need to have at least one unconfigured key slot available to the collection. + // Prior to PM-20109, both client and server had hard checks for IDs <= 5. + // While we don't have any technical constraints _at this time_, we should avoid + // unbounded growth of key IDs over time as users add/remove keys; + // this strategy gap-fills key IDs. + const existingIds = new Set(response.keys.map((k) => k.id)); + const nextId = this.findNextAvailableKeyId(existingIds); + + // Add unconfigured slot, which can be used to add a new key + this.keys.push({ + id: nextId, + name: "", + configured: false, + removePromise: null, + }); + this.keyIdAvailable = nextId; + this.enabled = response.enabled; this.onUpdated.emit(this.enabled); } diff --git a/apps/web/src/app/billing/organizations/payment-details/organization-payment-details.component.html b/apps/web/src/app/billing/organizations/payment-details/organization-payment-details.component.html index cd31f1f33be..504cfcdeccd 100644 --- a/apps/web/src/app/billing/organizations/payment-details/organization-payment-details.component.html +++ b/apps/web/src/app/billing/organizations/payment-details/organization-payment-details.component.html @@ -29,7 +29,7 @@ diff --git a/apps/web/src/app/billing/organizations/payment-details/organization-payment-details.component.ts b/apps/web/src/app/billing/organizations/payment-details/organization-payment-details.component.ts index 9609160089b..e989185e582 100644 --- a/apps/web/src/app/billing/organizations/payment-details/organization-payment-details.component.ts +++ b/apps/web/src/app/billing/organizations/payment-details/organization-payment-details.component.ts @@ -22,8 +22,6 @@ import { OrganizationService } from "@bitwarden/common/admin-console/abstraction import { Organization } from "@bitwarden/common/admin-console/models/domain/organization"; import { AccountService } from "@bitwarden/common/auth/abstractions/account.service"; import { getUserId } from "@bitwarden/common/auth/services/account.service"; -import { FeatureFlag } from "@bitwarden/common/enums/feature-flag.enum"; -import { ConfigService } from "@bitwarden/common/platform/abstractions/config/config.service"; import { getById } from "@bitwarden/common/platform/misc"; import { DialogService } from "@bitwarden/components"; import { CommandDefinition, MessageListener } from "@bitwarden/messaging"; @@ -118,12 +116,9 @@ export class OrganizationPaymentDetailsComponent implements OnInit, OnDestroy { private destroy$ = new Subject(); - protected enableTaxIdWarning!: boolean; - constructor( private accountService: AccountService, private activatedRoute: ActivatedRoute, - private configService: ConfigService, private dialogService: DialogService, private messageListener: MessageListener, private organizationService: OrganizationService, @@ -140,36 +135,30 @@ export class OrganizationPaymentDetailsComponent implements OnInit, OnDestroy { await this.changePaymentMethod(); } - this.enableTaxIdWarning = await this.configService.getFeatureFlag( - FeatureFlag.PM22415_TaxIDWarnings, - ); - - if (this.enableTaxIdWarning) { - this.organizationWarningsService.taxIdWarningRefreshed$ - .pipe( - switchMap((warning) => - combineLatest([ - of(warning), - this.organization$.pipe(take(1)).pipe( - mapOrganizationToSubscriber, - switchMap((organization) => - this.subscriberBillingClient.getBillingAddress(organization), - ), + this.organizationWarningsService.taxIdWarningRefreshed$ + .pipe( + switchMap((warning) => + combineLatest([ + of(warning), + this.organization$.pipe(take(1)).pipe( + mapOrganizationToSubscriber, + switchMap((organization) => + this.subscriberBillingClient.getBillingAddress(organization), ), - ]), - ), - takeUntil(this.destroy$), - ) - .subscribe(([taxIdWarning, billingAddress]) => { - if (this.viewState$.value) { - this.viewState$.next({ - ...this.viewState$.value, - taxIdWarning, - billingAddress, - }); - } - }); - } + ), + ]), + ), + takeUntil(this.destroy$), + ) + .subscribe(([taxIdWarning, billingAddress]) => { + if (this.viewState$.value) { + this.viewState$.next({ + ...this.viewState$.value, + taxIdWarning, + billingAddress, + }); + } + }); this.messageListener .messages$(BANK_ACCOUNT_VERIFIED_COMMAND) @@ -216,10 +205,7 @@ export class OrganizationPaymentDetailsComponent implements OnInit, OnDestroy { setBillingAddress = (billingAddress: BillingAddress) => { if (this.viewState$.value) { - if ( - this.enableTaxIdWarning && - this.viewState$.value.billingAddress?.taxId !== billingAddress.taxId - ) { + if (this.viewState$.value.billingAddress?.taxId !== billingAddress.taxId) { this.organizationWarningsService.refreshTaxIdWarning(); } this.viewState$.next({ diff --git a/apps/web/src/app/billing/warnings/components/tax-id-warning.component.ts b/apps/web/src/app/billing/warnings/components/tax-id-warning.component.ts index c0fe5626fcb..f2adcaccf30 100644 --- a/apps/web/src/app/billing/warnings/components/tax-id-warning.component.ts +++ b/apps/web/src/app/billing/warnings/components/tax-id-warning.component.ts @@ -12,8 +12,6 @@ import { import { Account, AccountService } from "@bitwarden/common/auth/abstractions/account.service"; import { getUserId } from "@bitwarden/common/auth/services/account.service"; -import { FeatureFlag } from "@bitwarden/common/enums/feature-flag.enum"; -import { ConfigService } from "@bitwarden/common/platform/abstractions/config/config.service"; import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.service"; import { BannerModule, DialogService } from "@bitwarden/components"; import { BILLING_DISK, StateProvider, UserKeyDefinition } from "@bitwarden/state"; @@ -88,23 +86,21 @@ type GetWarning$ = () => Observable; @Component({ selector: "app-tax-id-warning", template: ` - @if (enableTaxIdWarning$ | async) { - @let view = view$ | async; + @let view = view$ | async; - @if (view) { - - {{ view.message }} - - {{ view.callToAction }} - - - } + @if (view) { + + {{ view.message }} + + {{ view.callToAction }} + + } `, imports: [BannerModule, SharedModule], @@ -120,10 +116,6 @@ export class TaxIdWarningComponent implements OnInit { // eslint-disable-next-line @angular-eslint/prefer-output-emitter-ref @Output() billingAddressUpdated = new EventEmitter(); - protected enableTaxIdWarning$ = this.configService.getFeatureFlag$( - FeatureFlag.PM22415_TaxIDWarnings, - ); - protected userId$ = this.accountService.activeAccount$.pipe( filter((account): account is Account => account !== null), getUserId, @@ -209,7 +201,6 @@ export class TaxIdWarningComponent implements OnInit { constructor( private accountService: AccountService, - private configService: ConfigService, private dialogService: DialogService, private i18nService: I18nService, private subscriberBillingClient: SubscriberBillingClient, diff --git a/apps/web/src/app/dirt/reports/pages/exposed-passwords-report.component.html b/apps/web/src/app/dirt/reports/pages/exposed-passwords-report.component.html index eb476090963..fcdb3f6ca64 100644 --- a/apps/web/src/app/dirt/reports/pages/exposed-passwords-report.component.html +++ b/apps/web/src/app/dirt/reports/pages/exposed-passwords-report.component.html @@ -26,7 +26,7 @@
- + {{ "name" | i18n }} diff --git a/apps/web/src/app/dirt/reports/pages/weak-passwords-report.component.html b/apps/web/src/app/dirt/reports/pages/weak-passwords-report.component.html index 5fa2806d133..92d56c1c7a3 100644 --- a/apps/web/src/app/dirt/reports/pages/weak-passwords-report.component.html +++ b/apps/web/src/app/dirt/reports/pages/weak-passwords-report.component.html @@ -31,7 +31,7 @@ - + {{ "name" | i18n }} diff --git a/apps/web/src/app/key-management/data-recovery/steps/cipher-step.spec.ts b/apps/web/src/app/key-management/data-recovery/steps/cipher-step.spec.ts index a894fce0c41..9ae0600fb2a 100644 --- a/apps/web/src/app/key-management/data-recovery/steps/cipher-step.spec.ts +++ b/apps/web/src/app/key-management/data-recovery/steps/cipher-step.spec.ts @@ -132,7 +132,10 @@ describe("CipherStep", () => { userKey: null, encryptedPrivateKey: null, isPrivateKeyCorrupt: false, - ciphers: [{ id: "cipher-1", organizationId: null } as Cipher], + ciphers: [ + { id: "cipher-1", organizationId: null } as Cipher, + { id: "cipher-2", organizationId: null } as Cipher, + ], folders: [], }; @@ -144,14 +147,39 @@ describe("CipherStep", () => { expect(result).toBe(false); }); - it("returns true when there are undecryptable ciphers", async () => { + it("returns true when there are undecryptable ciphers but at least one decryptable cipher", async () => { const userId = "user-id" as UserId; const workingData: RecoveryWorkingData = { userId, userKey: null, encryptedPrivateKey: null, isPrivateKeyCorrupt: false, - ciphers: [{ id: "cipher-1", organizationId: null } as Cipher], + ciphers: [ + { id: "cipher-1", organizationId: null } as Cipher, + { id: "cipher-2", organizationId: null } as Cipher, + ], + folders: [], + }; + + cipherEncryptionService.decrypt.mockRejectedValueOnce(new Error("Decryption failed")); + + await cipherStep.runDiagnostics(workingData, logger); + const result = cipherStep.canRecover(workingData); + + expect(result).toBe(true); + }); + + it("returns false when all ciphers are undecryptable", async () => { + const userId = "user-id" as UserId; + const workingData: RecoveryWorkingData = { + userId, + userKey: null, + encryptedPrivateKey: null, + isPrivateKeyCorrupt: false, + ciphers: [ + { id: "cipher-1", organizationId: null } as Cipher, + { id: "cipher-2", organizationId: null } as Cipher, + ], folders: [], }; @@ -160,7 +188,7 @@ describe("CipherStep", () => { await cipherStep.runDiagnostics(workingData, logger); const result = cipherStep.canRecover(workingData); - expect(result).toBe(true); + expect(result).toBe(false); }); }); diff --git a/apps/web/src/app/key-management/data-recovery/steps/cipher-step.ts b/apps/web/src/app/key-management/data-recovery/steps/cipher-step.ts index b44e8afc54d..01c2d9bc2a1 100644 --- a/apps/web/src/app/key-management/data-recovery/steps/cipher-step.ts +++ b/apps/web/src/app/key-management/data-recovery/steps/cipher-step.ts @@ -10,6 +10,7 @@ export class CipherStep implements RecoveryStep { title = "recoveryStepCipherTitle"; private undecryptableCipherIds: string[] = []; + private decryptableCipherIds: string[] = []; constructor( private apiService: ApiService, @@ -31,18 +32,21 @@ export class CipherStep implements RecoveryStep { for (const cipher of userCiphers) { try { await this.cipherService.decrypt(cipher, workingData.userId); + this.decryptableCipherIds.push(cipher.id); } catch { logger.record(`Cipher ID ${cipher.id} was undecryptable`); this.undecryptableCipherIds.push(cipher.id); } } logger.record(`Found ${this.undecryptableCipherIds.length} undecryptable ciphers`); + logger.record(`Found ${this.decryptableCipherIds.length} decryptable ciphers`); return this.undecryptableCipherIds.length == 0; } canRecover(workingData: RecoveryWorkingData): boolean { - return this.undecryptableCipherIds.length > 0; + // If everything fails to decrypt, it's a deeper issue and we shouldn't offer recovery here. + return this.undecryptableCipherIds.length > 0 && this.decryptableCipherIds.length > 0; } async runRecovery(workingData: RecoveryWorkingData, logger: LogRecorder): Promise { diff --git a/apps/web/src/app/key-management/data-recovery/steps/folder-step.ts b/apps/web/src/app/key-management/data-recovery/steps/folder-step.ts index bc0ae31efba..90e252ce6c3 100644 --- a/apps/web/src/app/key-management/data-recovery/steps/folder-step.ts +++ b/apps/web/src/app/key-management/data-recovery/steps/folder-step.ts @@ -11,6 +11,7 @@ export class FolderStep implements RecoveryStep { title = "recoveryStepFoldersTitle"; private undecryptableFolderIds: string[] = []; + private decryptableFolderIds: string[] = []; constructor( private folderService: FolderApiServiceAbstraction, @@ -36,18 +37,21 @@ export class FolderStep implements RecoveryStep { folder.name.encryptedString, workingData.userKey.toEncoded(), ); + this.decryptableFolderIds.push(folder.id); } catch { logger.record(`Folder name for folder ID ${folder.id} was undecryptable`); this.undecryptableFolderIds.push(folder.id); } } logger.record(`Found ${this.undecryptableFolderIds.length} undecryptable folders`); + logger.record(`Found ${this.decryptableFolderIds.length} decryptable folders`); return this.undecryptableFolderIds.length == 0; } canRecover(workingData: RecoveryWorkingData): boolean { - return this.undecryptableFolderIds.length > 0; + // If everything fails to decrypt, it's a deeper issue and we shouldn't offer recovery here. + return this.undecryptableFolderIds.length > 0 && this.decryptableFolderIds.length > 0; } async runRecovery(workingData: RecoveryWorkingData, logger: LogRecorder): Promise { diff --git a/apps/web/src/app/layouts/product-switcher/navigation-switcher/navigation-switcher.component.spec.ts b/apps/web/src/app/layouts/product-switcher/navigation-switcher/navigation-switcher.component.spec.ts index 9f6c8f6b194..9a6de3ad9af 100644 --- a/apps/web/src/app/layouts/product-switcher/navigation-switcher/navigation-switcher.component.spec.ts +++ b/apps/web/src/app/layouts/product-switcher/navigation-switcher/navigation-switcher.component.spec.ts @@ -7,10 +7,12 @@ import { BehaviorSubject } from "rxjs"; import { I18nPipe } from "@bitwarden/angular/platform/pipes/i18n.pipe"; import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.service"; +import { FakeGlobalStateProvider } from "@bitwarden/common/spec"; import { IconButtonModule, NavigationModule } from "@bitwarden/components"; // FIXME: remove `src` and fix import // eslint-disable-next-line no-restricted-imports import { NavItemComponent } from "@bitwarden/components/src/navigation/nav-item.component"; +import { GlobalStateProvider } from "@bitwarden/state"; import { ProductSwitcherItem, ProductSwitcherService } from "../shared/product-switcher.service"; @@ -59,6 +61,8 @@ describe("NavigationProductSwitcherComponent", () => { productSwitcherService.shouldShowPremiumUpgradeButton$ = mockShouldShowPremiumUpgradeButton$; mockProducts$.next({ bento: [], other: [] }); + const fakeGlobalStateProvider = new FakeGlobalStateProvider(); + await TestBed.configureTestingModule({ imports: [RouterModule, NavigationModule, IconButtonModule, MockUpgradeNavButtonComponent], declarations: [NavigationProductSwitcherComponent, I18nPipe], @@ -72,6 +76,10 @@ describe("NavigationProductSwitcherComponent", () => { provide: ActivatedRoute, useValue: mock(), }, + { + provide: GlobalStateProvider, + useValue: fakeGlobalStateProvider, + }, ], }).compileComponents(); }); diff --git a/apps/web/src/app/layouts/product-switcher/navigation-switcher/navigation-switcher.stories.ts b/apps/web/src/app/layouts/product-switcher/navigation-switcher/navigation-switcher.stories.ts index ea6e972e431..ba36063fb7b 100644 --- a/apps/web/src/app/layouts/product-switcher/navigation-switcher/navigation-switcher.stories.ts +++ b/apps/web/src/app/layouts/product-switcher/navigation-switcher/navigation-switcher.stories.ts @@ -16,10 +16,15 @@ import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.servic import { PlatformUtilsService } from "@bitwarden/common/platform/abstractions/platform-utils.service"; import { SyncService } from "@bitwarden/common/platform/sync"; import { UserId } from "@bitwarden/common/types/guid"; -import { LayoutComponent, NavigationModule } from "@bitwarden/components"; +import { + LayoutComponent, + NavigationModule, + StorybookGlobalStateProvider, +} from "@bitwarden/components"; // FIXME: remove `src` and fix import // eslint-disable-next-line no-restricted-imports import { I18nMockService } from "@bitwarden/components/src/utils/i18n-mock.service"; +import { GlobalStateProvider } from "@bitwarden/state"; import { I18nPipe } from "@bitwarden/ui-common"; import { ProductSwitcherService } from "../shared/product-switcher.service"; @@ -82,7 +87,7 @@ class MockAccountService implements Partial { name: "Test User 1", email: "test@email.com", emailVerified: true, - creationDate: "2024-01-01T00:00:00.000Z", + creationDate: new Date("2024-01-01T00:00:00.000Z"), }); } @@ -183,6 +188,10 @@ export default { }, ]), ), + { + provide: GlobalStateProvider, + useClass: StorybookGlobalStateProvider, + }, ], }), ], diff --git a/apps/web/src/app/layouts/product-switcher/product-switcher.stories.ts b/apps/web/src/app/layouts/product-switcher/product-switcher.stories.ts index d412530a635..ad18b2b3490 100644 --- a/apps/web/src/app/layouts/product-switcher/product-switcher.stories.ts +++ b/apps/web/src/app/layouts/product-switcher/product-switcher.stories.ts @@ -82,7 +82,7 @@ class MockAccountService implements Partial { name: "Test User 1", email: "test@email.com", emailVerified: true, - creationDate: "2024-01-01T00:00:00.000Z", + creationDate: new Date("2024-01-01T00:00:00.000Z"), }); } diff --git a/apps/web/src/app/vault/components/vault-items/vault-items.stories.ts b/apps/web/src/app/vault/components/vault-items/vault-items.stories.ts index a71427cf475..9c56df0db59 100644 --- a/apps/web/src/app/vault/components/vault-items/vault-items.stories.ts +++ b/apps/web/src/app/vault/components/vault-items/vault-items.stories.ts @@ -39,7 +39,8 @@ import { LoginView } from "@bitwarden/common/vault/models/view/login.view"; import { CipherAuthorizationService } from "@bitwarden/common/vault/services/cipher-authorization.service"; import { RestrictedItemTypesService } from "@bitwarden/common/vault/services/restricted-item-types.service"; import { CipherViewLike } from "@bitwarden/common/vault/utils/cipher-view-like-utils"; -import { LayoutComponent } from "@bitwarden/components"; +import { LayoutComponent, StorybookGlobalStateProvider } from "@bitwarden/components"; +import { GlobalStateProvider } from "@bitwarden/state"; import { RoutedVaultFilterService } from "@bitwarden/web-vault/app/vault/individual-vault/vault-filter/services/routed-vault-filter.service"; import { GroupView } from "../../../admin-console/organizations/core"; @@ -168,6 +169,10 @@ export default { providers: [ importProvidersFrom(RouterModule.forRoot([], { useHash: true })), importProvidersFrom(PreloadedEnglishI18nModule), + { + provide: GlobalStateProvider, + useClass: StorybookGlobalStateProvider, + }, ], }), ], diff --git a/apps/web/src/app/vault/individual-vault/vault-filter/services/routed-vault-filter.service.ts b/apps/web/src/app/vault/individual-vault/vault-filter/services/routed-vault-filter.service.ts index a5a99428b2d..bc9da5e1692 100644 --- a/apps/web/src/app/vault/individual-vault/vault-filter/services/routed-vault-filter.service.ts +++ b/apps/web/src/app/vault/individual-vault/vault-filter/services/routed-vault-filter.service.ts @@ -74,6 +74,9 @@ export class RoutedVaultFilterService implements OnDestroy { type: filter.type ?? null, }, queryParamsHandling: "merge", + state: { + focusMainAfterNav: false, + }, }; return [commands, extras]; } diff --git a/apps/web/src/app/vault/individual-vault/vault.component.ts b/apps/web/src/app/vault/individual-vault/vault.component.ts index e791ca7a90b..a5121831304 100644 --- a/apps/web/src/app/vault/individual-vault/vault.component.ts +++ b/apps/web/src/app/vault/individual-vault/vault.component.ts @@ -424,6 +424,9 @@ export class VaultComponent implements OnInit, OnDestr queryParams: { search: Utils.isNullOrEmpty(searchText) ? null : searchText }, queryParamsHandling: "merge", replaceUrl: true, + state: { + focusMainAfterNav: false, + }, }), ); diff --git a/apps/web/src/index.html b/apps/web/src/index.html index 06f7587a123..5e56df553fc 100644 --- a/apps/web/src/index.html +++ b/apps/web/src/index.html @@ -122,7 +122,6 @@ - `;
diff --git a/bitwarden_license/bit-web/src/app/billing/providers/payment-details/provider-payment-details.component.ts b/bitwarden_license/bit-web/src/app/billing/providers/payment-details/provider-payment-details.component.ts index 183e6098471..1de271bcf28 100644 --- a/bitwarden_license/bit-web/src/app/billing/providers/payment-details/provider-payment-details.component.ts +++ b/bitwarden_license/bit-web/src/app/billing/providers/payment-details/provider-payment-details.component.ts @@ -21,8 +21,6 @@ import { ProviderService } from "@bitwarden/common/admin-console/abstractions/pr import { Provider } from "@bitwarden/common/admin-console/models/domain/provider"; import { AccountService } from "@bitwarden/common/auth/abstractions/account.service"; import { getUserId } from "@bitwarden/common/auth/services/account.service"; -import { FeatureFlag } from "@bitwarden/common/enums/feature-flag.enum"; -import { ConfigService } from "@bitwarden/common/platform/abstractions/config/config.service"; import { CommandDefinition, MessageListener } from "@bitwarden/messaging"; import { UserId } from "@bitwarden/user-core"; import { SubscriberBillingClient } from "@bitwarden/web-vault/app/billing/clients"; @@ -119,13 +117,10 @@ export class ProviderPaymentDetailsComponent implements OnInit, OnDestroy { private destroy$ = new Subject(); - protected enableTaxIdWarning!: boolean; - constructor( private accountService: AccountService, private activatedRoute: ActivatedRoute, private billingClient: SubscriberBillingClient, - private configService: ConfigService, private messageListener: MessageListener, private providerService: ProviderService, private providerWarningsService: ProviderWarningsService, @@ -133,34 +128,28 @@ export class ProviderPaymentDetailsComponent implements OnInit, OnDestroy { ) {} async ngOnInit() { - this.enableTaxIdWarning = await this.configService.getFeatureFlag( - FeatureFlag.PM22415_TaxIDWarnings, - ); - - if (this.enableTaxIdWarning) { - this.providerWarningsService.taxIdWarningRefreshed$ - .pipe( - switchMap((warning) => - combineLatest([ - of(warning), - this.provider$.pipe(take(1)).pipe( - mapProviderToSubscriber, - switchMap((provider) => this.subscriberBillingClient.getBillingAddress(provider)), - ), - ]), - ), - takeUntil(this.destroy$), - ) - .subscribe(([taxIdWarning, billingAddress]) => { - if (this.viewState$.value) { - this.viewState$.next({ - ...this.viewState$.value, - taxIdWarning, - billingAddress, - }); - } - }); - } + this.providerWarningsService.taxIdWarningRefreshed$ + .pipe( + switchMap((warning) => + combineLatest([ + of(warning), + this.provider$.pipe(take(1)).pipe( + mapProviderToSubscriber, + switchMap((provider) => this.subscriberBillingClient.getBillingAddress(provider)), + ), + ]), + ), + takeUntil(this.destroy$), + ) + .subscribe(([taxIdWarning, billingAddress]) => { + if (this.viewState$.value) { + this.viewState$.next({ + ...this.viewState$.value, + taxIdWarning, + billingAddress, + }); + } + }); this.messageListener .messages$(BANK_ACCOUNT_VERIFIED_COMMAND) @@ -197,10 +186,7 @@ export class ProviderPaymentDetailsComponent implements OnInit, OnDestroy { setBillingAddress = (billingAddress: BillingAddress) => { if (this.viewState$.value) { - if ( - this.enableTaxIdWarning && - this.viewState$.value.billingAddress?.taxId !== billingAddress.taxId - ) { + if (this.viewState$.value.billingAddress?.taxId !== billingAddress.taxId) { this.providerWarningsService.refreshTaxIdWarning(); } this.viewState$.next({ diff --git a/libs/angular/src/services/jslib-services.module.ts b/libs/angular/src/services/jslib-services.module.ts index ab6ca7295e3..7899ff5281a 100644 --- a/libs/angular/src/services/jslib-services.module.ts +++ b/libs/angular/src/services/jslib-services.module.ts @@ -1146,6 +1146,10 @@ const safeProviders: SafeProvider[] = [ KeyGenerationService, LOGOUT_CALLBACK, StateProvider, + ConfigService, + RegisterSdkService, + SecurityStateService, + AccountCryptographicStateService, ], }), safeProvider({ diff --git a/libs/angular/src/vault/index.ts b/libs/angular/src/vault/index.ts index cb43fadb3bc..b9131338a45 100644 --- a/libs/angular/src/vault/index.ts +++ b/libs/angular/src/vault/index.ts @@ -1,3 +1,4 @@ // Note: Nudge related code is exported from `libs/angular` because it is consumed by multiple // `libs/*` packages. Exporting from the `libs/vault` package creates circular dependencies. export { NudgesService, NudgeStatus, NudgeType } from "./services/nudges.service"; +export { AUTOFILL_NUDGE_SERVICE } from "./services/nudge-injection-tokens"; diff --git a/libs/angular/src/vault/services/custom-nudges-services/index.ts b/libs/angular/src/vault/services/custom-nudges-services/index.ts index f60592b9c71..d4bfe80a525 100644 --- a/libs/angular/src/vault/services/custom-nudges-services/index.ts +++ b/libs/angular/src/vault/services/custom-nudges-services/index.ts @@ -4,3 +4,4 @@ export * from "./empty-vault-nudge.service"; export * from "./vault-settings-import-nudge.service"; export * from "./new-item-nudge.service"; export * from "./new-account-nudge.service"; +export * from "./noop-nudge.service"; diff --git a/libs/angular/src/vault/services/custom-nudges-services/noop-nudge.service.ts b/libs/angular/src/vault/services/custom-nudges-services/noop-nudge.service.ts new file mode 100644 index 00000000000..eabf1d6fc4a --- /dev/null +++ b/libs/angular/src/vault/services/custom-nudges-services/noop-nudge.service.ts @@ -0,0 +1,27 @@ +import { Injectable } from "@angular/core"; +import { Observable, of } from "rxjs"; + +import { UserId } from "@bitwarden/common/types/guid"; + +import { SingleNudgeService } from "../default-single-nudge.service"; +import { NudgeStatus, NudgeType } from "../nudges.service"; + +/** + * A no-op nudge service that always returns dismissed status. + * Use this for nudges that should be completely ignored/hidden in certain clients. + * For example, browser-specific nudges can use this as the default in non-browser clients. + */ +@Injectable({ providedIn: "root" }) +export class NoOpNudgeService implements SingleNudgeService { + nudgeStatus$(_nudgeType: NudgeType, _userId: UserId): Observable { + return of({ hasBadgeDismissed: true, hasSpotlightDismissed: true }); + } + + async setNudgeStatus( + _nudgeType: NudgeType, + _newStatus: NudgeStatus, + _userId: UserId, + ): Promise { + // No-op: state changes are ignored + } +} diff --git a/libs/angular/src/vault/services/nudge-injection-tokens.ts b/libs/angular/src/vault/services/nudge-injection-tokens.ts new file mode 100644 index 00000000000..52a0838d356 --- /dev/null +++ b/libs/angular/src/vault/services/nudge-injection-tokens.ts @@ -0,0 +1,7 @@ +import { InjectionToken } from "@angular/core"; + +import { SingleNudgeService } from "./default-single-nudge.service"; + +export const AUTOFILL_NUDGE_SERVICE = new InjectionToken( + "AutofillNudgeService", +); diff --git a/libs/angular/src/vault/services/nudges.service.ts b/libs/angular/src/vault/services/nudges.service.ts index 05d565eb499..19acf690d32 100644 --- a/libs/angular/src/vault/services/nudges.service.ts +++ b/libs/angular/src/vault/services/nudges.service.ts @@ -12,8 +12,10 @@ import { NewItemNudgeService, AccountSecurityNudgeService, VaultSettingsImportNudgeService, + NoOpNudgeService, } from "./custom-nudges-services"; import { DefaultSingleNudgeService, SingleNudgeService } from "./default-single-nudge.service"; +import { AUTOFILL_NUDGE_SERVICE } from "./nudge-injection-tokens"; export type NudgeStatus = { hasBadgeDismissed: boolean; @@ -56,6 +58,12 @@ export class NudgesService { private newItemNudgeService = inject(NewItemNudgeService); private newAcctNudgeService = inject(NewAccountNudgeService); + // NoOp service that always returns dismissed + private noOpNudgeService = inject(NoOpNudgeService); + + // Optional Browser-specific service provided via injection token (not all clients have autofill) + private autofillNudgeService = inject(AUTOFILL_NUDGE_SERVICE, { optional: true }); + /** * Custom nudge services to use for specific nudge types * Each nudge type can have its own service to determine when to show the nudge @@ -66,7 +74,7 @@ export class NudgesService { [NudgeType.EmptyVaultNudge]: inject(EmptyVaultNudgeService), [NudgeType.VaultSettingsImportNudge]: inject(VaultSettingsImportNudgeService), [NudgeType.AccountSecurity]: inject(AccountSecurityNudgeService), - [NudgeType.AutofillNudge]: this.newAcctNudgeService, + [NudgeType.AutofillNudge]: this.autofillNudgeService ?? this.noOpNudgeService, [NudgeType.DownloadBitwarden]: this.newAcctNudgeService, [NudgeType.GeneratorNudgeStatus]: this.newAcctNudgeService, [NudgeType.NewLoginItemStatus]: this.newItemNudgeService, diff --git a/libs/auth/src/angular/login-decryption-options/login-decryption-options.component.spec.ts b/libs/auth/src/angular/login-decryption-options/login-decryption-options.component.spec.ts new file mode 100644 index 00000000000..248eaa608af --- /dev/null +++ b/libs/auth/src/angular/login-decryption-options/login-decryption-options.component.spec.ts @@ -0,0 +1,377 @@ +// Mock asUuid to return the input value for test consistency +jest.mock("@bitwarden/common/platform/abstractions/sdk/sdk.service", () => ({ + asUuid: (x: any) => x, +})); + +import { DestroyRef } from "@angular/core"; +import { FormBuilder } from "@angular/forms"; +import { Router } from "@angular/router"; +import { mock, MockProxy } from "jest-mock-extended"; +import { BehaviorSubject, of } from "rxjs"; + +import { + LoginEmailServiceAbstraction, + LogoutService, + UserDecryptionOptionsServiceAbstraction, +} from "@bitwarden/auth/common"; +import { ApiService } from "@bitwarden/common/abstractions/api.service"; +import { OrganizationApiServiceAbstraction } from "@bitwarden/common/admin-console/abstractions/organization/organization-api.service.abstraction"; +import { AccountService } from "@bitwarden/common/auth/abstractions/account.service"; +import { PasswordResetEnrollmentServiceAbstraction } from "@bitwarden/common/auth/abstractions/password-reset-enrollment.service.abstraction"; +import { SsoLoginServiceAbstraction } from "@bitwarden/common/auth/abstractions/sso-login.service.abstraction"; +import { ClientType } from "@bitwarden/common/enums"; +import { FeatureFlag } from "@bitwarden/common/enums/feature-flag.enum"; +import { DeviceTrustServiceAbstraction } from "@bitwarden/common/key-management/device-trust/abstractions/device-trust.service.abstraction"; +import { SecurityStateService } from "@bitwarden/common/key-management/security-state/abstractions/security-state.service"; +import { SignedSecurityState } from "@bitwarden/common/key-management/types"; +import { AppIdService } from "@bitwarden/common/platform/abstractions/app-id.service"; +import { ConfigService } from "@bitwarden/common/platform/abstractions/config/config.service"; +import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.service"; +import { MessagingService } from "@bitwarden/common/platform/abstractions/messaging.service"; +import { PlatformUtilsService } from "@bitwarden/common/platform/abstractions/platform-utils.service"; +import { RegisterSdkService } from "@bitwarden/common/platform/abstractions/sdk/register-sdk.service"; +import { ValidationService } from "@bitwarden/common/platform/abstractions/validation.service"; +import { SymmetricCryptoKey } from "@bitwarden/common/platform/models/domain/symmetric-crypto-key"; +import { UserId } from "@bitwarden/common/types/guid"; +// eslint-disable-next-line no-restricted-imports +import { AnonLayoutWrapperDataService, DialogService, ToastService } from "@bitwarden/components"; +import { KeyService } from "@bitwarden/key-management"; + +import { LoginDecryptionOptionsComponent } from "./login-decryption-options.component"; +import { LoginDecryptionOptionsService } from "./login-decryption-options.service"; + +describe("LoginDecryptionOptionsComponent", () => { + let component: LoginDecryptionOptionsComponent; + let accountService: MockProxy; + let anonLayoutWrapperDataService: MockProxy; + let apiService: MockProxy; + let destroyRef: MockProxy; + let deviceTrustService: MockProxy; + let dialogService: MockProxy; + let formBuilder: FormBuilder; + let i18nService: MockProxy; + let keyService: MockProxy; + let loginDecryptionOptionsService: MockProxy; + let loginEmailService: MockProxy; + let messagingService: MockProxy; + let organizationApiService: MockProxy; + let passwordResetEnrollmentService: MockProxy; + let platformUtilsService: MockProxy; + let router: MockProxy; + let ssoLoginService: MockProxy; + let toastService: MockProxy; + let userDecryptionOptionsService: MockProxy; + let validationService: MockProxy; + let logoutService: MockProxy; + let registerSdkService: MockProxy; + let securityStateService: MockProxy; + let appIdService: MockProxy; + let configService: MockProxy; + let accountCryptographicStateService: MockProxy; + + const mockUserId = "user-id-123" as UserId; + const mockEmail = "test@example.com"; + const mockOrgId = "org-id-456"; + + beforeEach(() => { + accountService = mock(); + anonLayoutWrapperDataService = mock(); + apiService = mock(); + destroyRef = mock(); + deviceTrustService = mock(); + dialogService = mock(); + formBuilder = new FormBuilder(); + i18nService = mock(); + keyService = mock(); + loginDecryptionOptionsService = mock(); + loginEmailService = mock(); + messagingService = mock(); + organizationApiService = mock(); + passwordResetEnrollmentService = mock(); + platformUtilsService = mock(); + router = mock(); + ssoLoginService = mock(); + toastService = mock(); + userDecryptionOptionsService = mock(); + validationService = mock(); + logoutService = mock(); + registerSdkService = mock(); + securityStateService = mock(); + appIdService = mock(); + configService = mock(); + accountCryptographicStateService = mock(); + + // Setup default mocks + accountService.activeAccount$ = new BehaviorSubject({ + id: mockUserId, + email: mockEmail, + name: "Test User", + emailVerified: true, + creationDate: new Date(), + }); + platformUtilsService.getClientType.mockReturnValue(ClientType.Browser); + deviceTrustService.getShouldTrustDevice.mockResolvedValue(true); + i18nService.t.mockImplementation((key: string) => key); + + component = new LoginDecryptionOptionsComponent( + accountService, + anonLayoutWrapperDataService, + apiService, + destroyRef, + deviceTrustService, + dialogService, + formBuilder, + i18nService, + keyService, + loginDecryptionOptionsService, + loginEmailService, + messagingService, + organizationApiService, + passwordResetEnrollmentService, + platformUtilsService, + router, + ssoLoginService, + toastService, + userDecryptionOptionsService, + validationService, + logoutService, + registerSdkService, + securityStateService, + appIdService, + configService, + accountCryptographicStateService, + ); + }); + + describe("createUser with feature flag enabled", () => { + let mockPostKeysForTdeRegistration: jest.Mock; + let mockRegistration: any; + let mockAuth: any; + let mockSdkValue: any; + let mockSdkRef: any; + let mockSdk: any; + let mockDeviceKey: string; + let mockDeviceKeyObj: SymmetricCryptoKey; + let mockUserKeyBytes: Uint8Array; + let mockPrivateKey: string; + let mockSignedPublicKey: string; + let mockSigningKey: string; + let mockSecurityState: SignedSecurityState; + + beforeEach(async () => { + // Mock asUuid to return the input value for test consistency + jest.mock("@bitwarden/common/platform/abstractions/sdk/sdk.service", () => ({ + asUuid: (x: any) => x, + })); + (Symbol as any).dispose = Symbol("dispose"); + + mockPrivateKey = "mock-private-key"; + mockSignedPublicKey = "mock-signed-public-key"; + mockSigningKey = "mock-signing-key"; + mockSecurityState = { + signature: "mock-signature", + payload: { + version: 2, + timestamp: Date.now(), + privateKeyHash: "mock-hash", + }, + } as any; + const deviceKeyBytes = new Uint8Array(32).fill(5); + mockDeviceKey = Buffer.from(deviceKeyBytes).toString("base64"); + mockDeviceKeyObj = SymmetricCryptoKey.fromString(mockDeviceKey); + mockUserKeyBytes = new Uint8Array(64); + + mockPostKeysForTdeRegistration = jest.fn().mockResolvedValue({ + account_cryptographic_state: { + V2: { + private_key: mockPrivateKey, + signed_public_key: mockSignedPublicKey, + signing_key: mockSigningKey, + security_state: mockSecurityState, + }, + }, + device_key: mockDeviceKey, + user_key: mockUserKeyBytes, + }); + + mockRegistration = { + post_keys_for_tde_registration: mockPostKeysForTdeRegistration, + }; + + mockAuth = { + registration: jest.fn().mockReturnValue(mockRegistration), + }; + + mockSdkValue = { + auth: jest.fn().mockReturnValue(mockAuth), + }; + + mockSdkRef = { + value: mockSdkValue, + [Symbol.dispose]: jest.fn(), + }; + + mockSdk = { + take: jest.fn().mockReturnValue(mockSdkRef), + }; + + registerSdkService.registerClient$ = jest.fn((userId: UserId) => of(mockSdk)) as any; + + // Setup for new user state + userDecryptionOptionsService.userDecryptionOptionsById$.mockReturnValue( + of({ + trustedDeviceOption: { + hasAdminApproval: false, + hasLoginApprovingDevice: false, + hasManageResetPasswordPermission: false, + isTdeOffboarding: false, + }, + hasMasterPassword: false, + keyConnectorOption: undefined, + }), + ); + + ssoLoginService.getActiveUserOrganizationSsoIdentifier.mockResolvedValue("org-identifier"); + organizationApiService.getAutoEnrollStatus.mockResolvedValue({ + id: mockOrgId, + resetPasswordEnabled: true, + } as any); + + // Initialize component to set up new user state + await component.ngOnInit(); + }); + + it("should use SDK v2 registration when feature flag is enabled", async () => { + // Arrange + configService.getFeatureFlag.mockResolvedValue(true); + loginDecryptionOptionsService.handleCreateUserSuccess.mockResolvedValue(undefined); + router.navigate.mockResolvedValue(true); + appIdService.getAppId.mockResolvedValue("mock-app-id"); + organizationApiService.getKeys.mockResolvedValue({ + publicKey: "mock-org-public-key", + privateKey: "mock-org-private-key", + } as any); + + // Act + await component["createUser"](); + + // Assert + expect(configService.getFeatureFlag).toHaveBeenCalledWith( + FeatureFlag.PM27279_V2RegistrationTdeJit, + ); + expect(appIdService.getAppId).toHaveBeenCalled(); + expect(organizationApiService.getKeys).toHaveBeenCalledWith(mockOrgId); + expect(registerSdkService.registerClient$).toHaveBeenCalledWith(mockUserId); + + // Verify SDK registration was called with correct parameters + expect(mockSdkValue.auth).toHaveBeenCalled(); + expect(mockAuth.registration).toHaveBeenCalled(); + expect(mockPostKeysForTdeRegistration).toHaveBeenCalledWith({ + org_id: mockOrgId, + org_public_key: "mock-org-public-key", + user_id: mockUserId, + device_identifier: "mock-app-id", + trust_device: true, + }); + + const expectedDeviceKey = mockDeviceKeyObj; + const expectedUserKey = new SymmetricCryptoKey(new Uint8Array(mockUserKeyBytes)); + + // Verify keys were set + expect(keyService.setPrivateKey).toHaveBeenCalledWith(mockPrivateKey, mockUserId); + expect(keyService.setSignedPublicKey).toHaveBeenCalledWith(mockSignedPublicKey, mockUserId); + expect(keyService.setUserSigningKey).toHaveBeenCalledWith(mockSigningKey, mockUserId); + expect(securityStateService.setAccountSecurityState).toHaveBeenCalledWith( + mockSecurityState, + mockUserId, + ); + expect(accountCryptographicStateService.setAccountCryptographicState).toHaveBeenCalledWith( + expect.objectContaining({ + V2: { + private_key: mockPrivateKey, + signed_public_key: mockSignedPublicKey, + signing_key: mockSigningKey, + security_state: mockSecurityState, + }, + }), + mockUserId, + ); + + expect(validationService.showError).not.toHaveBeenCalled(); + + // Verify device and user keys were persisted + expect(deviceTrustService.setDeviceKey).toHaveBeenCalledWith( + mockUserId, + expect.any(SymmetricCryptoKey), + ); + expect(keyService.setUserKey).toHaveBeenCalledWith( + expect.any(SymmetricCryptoKey), + mockUserId, + ); + + const [, deviceKeyArg] = deviceTrustService.setDeviceKey.mock.calls[0]; + const [userKeyArg] = keyService.setUserKey.mock.calls[0]; + + expect((deviceKeyArg as SymmetricCryptoKey).keyB64).toBe(expectedDeviceKey.keyB64); + expect((userKeyArg as SymmetricCryptoKey).keyB64).toBe(expectedUserKey.keyB64); + + // Verify success toast and navigation + expect(toastService.showToast).toHaveBeenCalledWith({ + variant: "success", + title: null, + message: "accountSuccessfullyCreated", + }); + expect(loginDecryptionOptionsService.handleCreateUserSuccess).toHaveBeenCalled(); + expect(router.navigate).toHaveBeenCalledWith(["/tabs/vault"]); + }); + + it("should use legacy registration when feature flag is disabled", async () => { + // Arrange + configService.getFeatureFlag.mockResolvedValue(false); + + const mockPublicKey = "mock-public-key"; + const mockPrivateKey = { + encryptedString: "mock-encrypted-private-key", + } as any; + + keyService.initAccount.mockResolvedValue({ + publicKey: mockPublicKey, + privateKey: mockPrivateKey, + } as any); + + apiService.postAccountKeys.mockResolvedValue(undefined); + passwordResetEnrollmentService.enroll.mockResolvedValue(undefined); + deviceTrustService.trustDevice.mockResolvedValue(undefined); + loginDecryptionOptionsService.handleCreateUserSuccess.mockResolvedValue(undefined); + router.navigate.mockResolvedValue(true); + + // Act + await component["createUser"](); + + // Assert + expect(configService.getFeatureFlag).toHaveBeenCalledWith( + FeatureFlag.PM27279_V2RegistrationTdeJit, + ); + expect(keyService.initAccount).toHaveBeenCalledWith(mockUserId); + expect(apiService.postAccountKeys).toHaveBeenCalledWith( + expect.objectContaining({ + publicKey: mockPublicKey, + encryptedPrivateKey: mockPrivateKey.encryptedString, + }), + ); + expect(passwordResetEnrollmentService.enroll).toHaveBeenCalledWith(mockOrgId); + expect(deviceTrustService.trustDevice).toHaveBeenCalledWith(mockUserId); + + // Verify success toast + expect(toastService.showToast).toHaveBeenCalledWith({ + variant: "success", + title: null, + message: "accountSuccessfullyCreated", + }); + + // Verify navigation + expect(loginDecryptionOptionsService.handleCreateUserSuccess).toHaveBeenCalled(); + expect(router.navigate).toHaveBeenCalledWith(["/tabs/vault"]); + }); + }); +}); diff --git a/libs/auth/src/angular/login-decryption-options/login-decryption-options.component.ts b/libs/auth/src/angular/login-decryption-options/login-decryption-options.component.ts index fb07069998b..06263ef7371 100644 --- a/libs/auth/src/angular/login-decryption-options/login-decryption-options.component.ts +++ b/libs/auth/src/angular/login-decryption-options/login-decryption-options.component.ts @@ -5,7 +5,17 @@ import { Component, DestroyRef, OnInit } from "@angular/core"; import { takeUntilDestroyed } from "@angular/core/rxjs-interop"; import { FormBuilder, FormControl, ReactiveFormsModule } from "@angular/forms"; import { Router } from "@angular/router"; -import { catchError, defer, firstValueFrom, from, map, of, switchMap, throwError } from "rxjs"; +import { + catchError, + concatMap, + defer, + firstValueFrom, + from, + map, + of, + switchMap, + throwError, +} from "rxjs"; import { JslibModule } from "@bitwarden/angular/jslib.module"; import { @@ -20,13 +30,27 @@ import { AccountService } from "@bitwarden/common/auth/abstractions/account.serv import { PasswordResetEnrollmentServiceAbstraction } from "@bitwarden/common/auth/abstractions/password-reset-enrollment.service.abstraction"; import { SsoLoginServiceAbstraction } from "@bitwarden/common/auth/abstractions/sso-login.service.abstraction"; import { ClientType } from "@bitwarden/common/enums"; +import { FeatureFlag } from "@bitwarden/common/enums/feature-flag.enum"; +import { AccountCryptographicStateService } from "@bitwarden/common/key-management/account-cryptography/account-cryptographic-state.service"; import { DeviceTrustServiceAbstraction } from "@bitwarden/common/key-management/device-trust/abstractions/device-trust.service.abstraction"; +import { SecurityStateService } from "@bitwarden/common/key-management/security-state/abstractions/security-state.service"; +import { + SignedPublicKey, + SignedSecurityState, + WrappedSigningKey, +} from "@bitwarden/common/key-management/types"; import { KeysRequest } from "@bitwarden/common/models/request/keys.request"; +import { AppIdService } from "@bitwarden/common/platform/abstractions/app-id.service"; +import { ConfigService } from "@bitwarden/common/platform/abstractions/config/config.service"; import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.service"; import { MessagingService } from "@bitwarden/common/platform/abstractions/messaging.service"; import { PlatformUtilsService } from "@bitwarden/common/platform/abstractions/platform-utils.service"; +import { RegisterSdkService } from "@bitwarden/common/platform/abstractions/sdk/register-sdk.service"; +import { asUuid } from "@bitwarden/common/platform/abstractions/sdk/sdk.service"; import { ValidationService } from "@bitwarden/common/platform/abstractions/validation.service"; +import { SymmetricCryptoKey } from "@bitwarden/common/platform/models/domain/symmetric-crypto-key"; import { UserId } from "@bitwarden/common/types/guid"; +import { DeviceKey, UserKey } from "@bitwarden/common/types/key"; // This import has been flagged as unallowed for this class. It may be involved in a circular dependency loop. // eslint-disable-next-line no-restricted-imports import { @@ -40,6 +64,7 @@ import { TypographyModule, } from "@bitwarden/components"; import { KeyService } from "@bitwarden/key-management"; +import { OrganizationId as SdkOrganizationId, UserId as SdkUserId } from "@bitwarden/sdk-internal"; import { LoginDecryptionOptionsService } from "./login-decryption-options.service"; @@ -112,6 +137,11 @@ export class LoginDecryptionOptionsComponent implements OnInit { private userDecryptionOptionsService: UserDecryptionOptionsServiceAbstraction, private validationService: ValidationService, private logoutService: LogoutService, + private registerSdkService: RegisterSdkService, + private securityStateService: SecurityStateService, + private appIdService: AppIdService, + private configService: ConfigService, + private accountCryptographicStateService: AccountCryptographicStateService, ) { this.clientType = this.platformUtilsService.getClientType(); } @@ -251,9 +281,85 @@ export class LoginDecryptionOptionsComponent implements OnInit { } try { - const { publicKey, privateKey } = await this.keyService.initAccount(this.activeAccountId); - const keysRequest = new KeysRequest(publicKey, privateKey.encryptedString); - await this.apiService.postAccountKeys(keysRequest); + const useSdkV2Creation = await this.configService.getFeatureFlag( + FeatureFlag.PM27279_V2RegistrationTdeJit, + ); + if (useSdkV2Creation) { + const deviceIdentifier = await this.appIdService.getAppId(); + const userId = this.activeAccountId; + const organizationId = this.newUserOrgId; + + const orgKeyResponse = await this.organizationApiService.getKeys(organizationId); + const register_result = await firstValueFrom( + this.registerSdkService.registerClient$(userId).pipe( + concatMap(async (sdk) => { + if (!sdk) { + throw new Error("SDK not available"); + } + + using ref = sdk.take(); + return await ref.value + .auth() + .registration() + .post_keys_for_tde_registration({ + org_id: asUuid(organizationId), + org_public_key: orgKeyResponse.publicKey, + user_id: asUuid(userId), + device_identifier: deviceIdentifier, + trust_device: this.formGroup.value.rememberDevice, + }); + }), + ), + ); + // The keys returned here can only be v2 keys, since the SDK only implements returning V2 keys. + if ("V1" in register_result.account_cryptographic_state) { + throw new Error("Unexpected V1 account cryptographic state"); + } + + // Note: When SDK state management matures, these should be moved into post_keys_for_tde_registration + // Set account cryptography state + await this.accountCryptographicStateService.setAccountCryptographicState( + register_result.account_cryptographic_state, + userId, + ); + // Legacy individual states + await this.keyService.setPrivateKey( + register_result.account_cryptographic_state.V2.private_key, + userId, + ); + await this.keyService.setSignedPublicKey( + register_result.account_cryptographic_state.V2.signed_public_key as SignedPublicKey, + userId, + ); + await this.keyService.setUserSigningKey( + register_result.account_cryptographic_state.V2.signing_key as WrappedSigningKey, + userId, + ); + await this.securityStateService.setAccountSecurityState( + register_result.account_cryptographic_state.V2.security_state as SignedSecurityState, + userId, + ); + + // TDE unlock + await this.deviceTrustService.setDeviceKey( + userId, + SymmetricCryptoKey.fromString(register_result.device_key) as DeviceKey, + ); + + // Set user key - user is now unlocked + await this.keyService.setUserKey( + SymmetricCryptoKey.fromString(register_result.user_key) as UserKey, + userId, + ); + } else { + const { publicKey, privateKey } = await this.keyService.initAccount(this.activeAccountId); + const keysRequest = new KeysRequest(publicKey, privateKey.encryptedString); + await this.apiService.postAccountKeys(keysRequest); + await this.passwordResetEnrollmentService.enroll(this.newUserOrgId); + if (this.formGroup.value.rememberDevice) { + await this.deviceTrustService.trustDevice(this.activeAccountId); + } + } this.toastService.showToast({ variant: "success", @@ -261,12 +367,6 @@ export class LoginDecryptionOptionsComponent implements OnInit { message: this.i18nService.t("accountSuccessfullyCreated"), }); - await this.passwordResetEnrollmentService.enroll(this.newUserOrgId); - - if (this.formGroup.value.rememberDevice) { - await this.deviceTrustService.trustDevice(this.activeAccountId); - } - await this.loginDecryptionOptionsService.handleCreateUserSuccess(); if (this.clientType === ClientType.Desktop) { diff --git a/libs/common/spec/fake-account-service.ts b/libs/common/spec/fake-account-service.ts index ed8b7796966..db644e5e9d1 100644 --- a/libs/common/spec/fake-account-service.ts +++ b/libs/common/spec/fake-account-service.ts @@ -15,7 +15,7 @@ export function mockAccountInfoWith(info: Partial = {}): AccountInf name: "name", email: "email", emailVerified: true, - creationDate: "2024-01-01T00:00:00.000Z", + creationDate: new Date("2024-01-01T00:00:00.000Z"), ...info, }; } @@ -111,7 +111,7 @@ export class FakeAccountService implements AccountService { await this.mock.setAccountEmailVerified(userId, emailVerified); } - async setAccountCreationDate(userId: UserId, creationDate: string): Promise { + async setAccountCreationDate(userId: UserId, creationDate: Date): Promise { await this.mock.setAccountCreationDate(userId, creationDate); } diff --git a/libs/common/src/auth/abstractions/account.service.ts b/libs/common/src/auth/abstractions/account.service.ts index 78822f3ebd5..c80d6b0439c 100644 --- a/libs/common/src/auth/abstractions/account.service.ts +++ b/libs/common/src/auth/abstractions/account.service.ts @@ -2,33 +2,25 @@ import { Observable } from "rxjs"; import { UserId } from "../../types/guid"; +/** + * Holds state that represents a user's account with Bitwarden. + * Any additions here should be added to the equality check in the AccountService + * to ensure that emissions are done on every change. + * + * @property email - User's email address. + * @property emailVerified - Whether the email has been verified. + * @property name - User's display name (optional). + * @property creationDate - Date when the account was created. + * Will be undefined immediately after login until the first sync completes. + */ export type AccountInfo = { email: string; emailVerified: boolean; name: string | undefined; - creationDate: string | undefined; + creationDate: Date | undefined; }; export type Account = { id: UserId } & AccountInfo; - -export function accountInfoEqual(a: AccountInfo, b: AccountInfo) { - if (a == null && b == null) { - return true; - } - - if (a == null || b == null) { - return false; - } - - const keys = new Set([...Object.keys(a), ...Object.keys(b)]) as Set; - for (const key of keys) { - if (a[key] !== b[key]) { - return false; - } - } - return true; -} - export abstract class AccountService { abstract accounts$: Observable>; @@ -77,7 +69,7 @@ export abstract class AccountService { * @param userId * @param creationDate */ - abstract setAccountCreationDate(userId: UserId, creationDate: string): Promise; + abstract setAccountCreationDate(userId: UserId, creationDate: Date): Promise; /** * updates the `accounts$` observable with the new VerifyNewDeviceLogin property for the account. * @param userId diff --git a/libs/common/src/auth/models/response/identity-token.response.ts b/libs/common/src/auth/models/response/identity-token.response.ts index ae208ef1a36..e43697f9ebe 100644 --- a/libs/common/src/auth/models/response/identity-token.response.ts +++ b/libs/common/src/auth/models/response/identity-token.response.ts @@ -19,9 +19,21 @@ export class IdentityTokenResponse extends BaseResponse { tokenType: string; // Decryption Information - privateKey: string; // userKeyEncryptedPrivateKey + + /** + * privateKey is actually userKeyEncryptedPrivateKey + * @deprecated Use {@link accountKeysResponseModel} instead + */ + privateKey: string; + + // TODO: https://bitwarden.atlassian.net/browse/PM-30124 - Rename to just accountKeys accountKeysResponseModel: PrivateKeysResponseModel | null = null; - key?: EncString; // masterKeyEncryptedUserKey + + /** + * key is actually masterKeyEncryptedUserKey + * @deprecated Use {@link userDecryptionOptions.masterPasswordUnlock.masterKeyWrappedUserKey} instead + */ + key?: EncString; twoFactorToken: string; kdfConfig: KdfConfig; forcePasswordReset: boolean; diff --git a/libs/common/src/auth/services/account.service.spec.ts b/libs/common/src/auth/services/account.service.spec.ts index f517b61ffb6..6668b9c39de 100644 --- a/libs/common/src/auth/services/account.service.spec.ts +++ b/libs/common/src/auth/services/account.service.spec.ts @@ -17,7 +17,7 @@ import { LogService } from "../../platform/abstractions/log.service"; import { MessagingService } from "../../platform/abstractions/messaging.service"; import { Utils } from "../../platform/misc/utils"; import { UserId } from "../../types/guid"; -import { AccountInfo, accountInfoEqual } from "../abstractions/account.service"; +import { AccountInfo } from "../abstractions/account.service"; import { ACCOUNT_ACCOUNTS, @@ -27,63 +27,6 @@ import { AccountServiceImplementation, } from "./account.service"; -describe("accountInfoEqual", () => { - const accountInfo = mockAccountInfoWith(); - - it("compares nulls", () => { - expect(accountInfoEqual(null, null)).toBe(true); - expect(accountInfoEqual(null, accountInfo)).toBe(false); - expect(accountInfoEqual(accountInfo, null)).toBe(false); - }); - - it("compares all keys, not just those defined in AccountInfo", () => { - const different = { ...accountInfo, extra: "extra" }; - - expect(accountInfoEqual(accountInfo, different)).toBe(false); - }); - - it("compares name", () => { - const same = { ...accountInfo }; - const different = { ...accountInfo, name: "name2" }; - - expect(accountInfoEqual(accountInfo, same)).toBe(true); - expect(accountInfoEqual(accountInfo, different)).toBe(false); - }); - - it("compares email", () => { - const same = { ...accountInfo }; - const different = { ...accountInfo, email: "email2" }; - - expect(accountInfoEqual(accountInfo, same)).toBe(true); - expect(accountInfoEqual(accountInfo, different)).toBe(false); - }); - - it("compares emailVerified", () => { - const same = { ...accountInfo }; - const different = { ...accountInfo, emailVerified: false }; - - expect(accountInfoEqual(accountInfo, same)).toBe(true); - expect(accountInfoEqual(accountInfo, different)).toBe(false); - }); - - it("compares creationDate", () => { - const same = { ...accountInfo }; - const different = { ...accountInfo, creationDate: "2024-12-31T00:00:00.000Z" }; - - expect(accountInfoEqual(accountInfo, same)).toBe(true); - expect(accountInfoEqual(accountInfo, different)).toBe(false); - }); - - it("compares undefined creationDate", () => { - const accountWithoutCreationDate = mockAccountInfoWith({ creationDate: undefined }); - const same = { ...accountWithoutCreationDate }; - const different = { ...accountWithoutCreationDate, creationDate: "2024-01-01T00:00:00.000Z" }; - - expect(accountInfoEqual(accountWithoutCreationDate, same)).toBe(true); - expect(accountInfoEqual(accountWithoutCreationDate, different)).toBe(false); - }); -}); - describe("accountService", () => { let messagingService: MockProxy; let logService: MockProxy; @@ -121,6 +64,60 @@ describe("accountService", () => { jest.resetAllMocks(); }); + describe("accountInfoEqual", () => { + const accountInfo = mockAccountInfoWith(); + + it("compares nulls", () => { + expect((sut as any).accountInfoEqual(null, null)).toBe(true); + expect((sut as any).accountInfoEqual(null, accountInfo)).toBe(false); + expect((sut as any).accountInfoEqual(accountInfo, null)).toBe(false); + }); + + it("compares name", () => { + const same = { ...accountInfo }; + const different = { ...accountInfo, name: "name2" }; + + expect((sut as any).accountInfoEqual(accountInfo, same)).toBe(true); + expect((sut as any).accountInfoEqual(accountInfo, different)).toBe(false); + }); + + it("compares email", () => { + const same = { ...accountInfo }; + const different = { ...accountInfo, email: "email2" }; + + expect((sut as any).accountInfoEqual(accountInfo, same)).toBe(true); + expect((sut as any).accountInfoEqual(accountInfo, different)).toBe(false); + }); + + it("compares emailVerified", () => { + const same = { ...accountInfo }; + const different = { ...accountInfo, emailVerified: false }; + + expect((sut as any).accountInfoEqual(accountInfo, same)).toBe(true); + expect((sut as any).accountInfoEqual(accountInfo, different)).toBe(false); + }); + + it("compares creationDate", () => { + const same = { ...accountInfo }; + const different = { ...accountInfo, creationDate: new Date("2024-12-31T00:00:00.000Z") }; + + expect((sut as any).accountInfoEqual(accountInfo, same)).toBe(true); + expect((sut as any).accountInfoEqual(accountInfo, different)).toBe(false); + }); + + it("compares undefined creationDate", () => { + const accountWithoutCreationDate = mockAccountInfoWith({ creationDate: undefined }); + const same = { ...accountWithoutCreationDate }; + const different = { + ...accountWithoutCreationDate, + creationDate: new Date("2024-01-01T00:00:00.000Z"), + }; + + expect((sut as any).accountInfoEqual(accountWithoutCreationDate, same)).toBe(true); + expect((sut as any).accountInfoEqual(accountWithoutCreationDate, different)).toBe(false); + }); + }); + describe("activeAccount$", () => { it("should emit null if no account is active", () => { const emissions = trackEmissions(sut.activeAccount$); @@ -281,7 +278,7 @@ describe("accountService", () => { }); it("should update the account with a new creation date", async () => { - const newCreationDate = "2024-12-31T00:00:00.000Z"; + const newCreationDate = new Date("2024-12-31T00:00:00.000Z"); await sut.setAccountCreationDate(userId, newCreationDate); const currentState = await firstValueFrom(accountsState.state$); @@ -297,6 +294,24 @@ describe("accountService", () => { expect(currentState).toEqual(initialState); }); + it("should not update if the creation date has the same timestamp but different Date object", async () => { + const sameTimestamp = new Date(userInfo.creationDate.getTime()); + await sut.setAccountCreationDate(userId, sameTimestamp); + const currentState = await firstValueFrom(accountsState.state$); + + expect(currentState).toEqual(initialState); + }); + + it("should update if the creation date has a different timestamp", async () => { + const differentDate = new Date(userInfo.creationDate.getTime() + 1000); + await sut.setAccountCreationDate(userId, differentDate); + const currentState = await firstValueFrom(accountsState.state$); + + expect(currentState).toEqual({ + [userId]: { ...userInfo, creationDate: differentDate }, + }); + }); + it("should update from undefined to a defined creation date", async () => { const accountWithoutCreationDate = mockAccountInfoWith({ ...userInfo, @@ -304,7 +319,7 @@ describe("accountService", () => { }); accountsState.stateSubject.next({ [userId]: accountWithoutCreationDate }); - const newCreationDate = "2024-06-15T12:30:00.000Z"; + const newCreationDate = new Date("2024-06-15T12:30:00.000Z"); await sut.setAccountCreationDate(userId, newCreationDate); const currentState = await firstValueFrom(accountsState.state$); @@ -313,14 +328,19 @@ describe("accountService", () => { }); }); - it("should update to a different creation date string format", async () => { - const newCreationDate = "2023-03-15T08:45:30.123Z"; - await sut.setAccountCreationDate(userId, newCreationDate); - const currentState = await firstValueFrom(accountsState.state$); - - expect(currentState).toEqual({ - [userId]: { ...userInfo, creationDate: newCreationDate }, + it("should not update when both creation dates are undefined", async () => { + const accountWithoutCreationDate = mockAccountInfoWith({ + ...userInfo, + creationDate: undefined, }); + accountsState.stateSubject.next({ [userId]: accountWithoutCreationDate }); + + // Attempt to set to undefined (shouldn't trigger update) + const currentStateBefore = await firstValueFrom(accountsState.state$); + + // We can't directly call setAccountCreationDate with undefined, but we can verify + // the behavior through setAccountInfo which accountInfoEqual uses internally + expect(currentStateBefore[userId].creationDate).toBeUndefined(); }); }); diff --git a/libs/common/src/auth/services/account.service.ts b/libs/common/src/auth/services/account.service.ts index 1b028d1eba9..ea22bb9dd2c 100644 --- a/libs/common/src/auth/services/account.service.ts +++ b/libs/common/src/auth/services/account.service.ts @@ -18,7 +18,6 @@ import { Account, AccountInfo, InternalAccountService, - accountInfoEqual, } from "../../auth/abstractions/account.service"; import { LogService } from "../../platform/abstractions/log.service"; import { MessagingService } from "../../platform/abstractions/messaging.service"; @@ -37,7 +36,10 @@ export const ACCOUNT_ACCOUNTS = KeyDefinition.record( ACCOUNT_DISK, "accounts", { - deserializer: (accountInfo) => accountInfo, + deserializer: (accountInfo) => ({ + ...accountInfo, + creationDate: accountInfo.creationDate ? new Date(accountInfo.creationDate) : undefined, + }), }, ); @@ -111,7 +113,7 @@ export class AccountServiceImplementation implements InternalAccountService { this.activeAccount$ = this.activeAccountIdState.state$.pipe( combineLatestWith(this.accounts$), map(([id, accounts]) => (id ? ({ id, ...(accounts[id] as AccountInfo) } as Account) : null)), - distinctUntilChanged((a, b) => a?.id === b?.id && accountInfoEqual(a, b)), + distinctUntilChanged((a, b) => a?.id === b?.id && this.accountInfoEqual(a, b)), shareReplay({ bufferSize: 1, refCount: false }), ); this.accountActivity$ = this.globalStateProvider @@ -168,7 +170,7 @@ export class AccountServiceImplementation implements InternalAccountService { await this.setAccountInfo(userId, { emailVerified }); } - async setAccountCreationDate(userId: UserId, creationDate: string): Promise { + async setAccountCreationDate(userId: UserId, creationDate: Date): Promise { await this.setAccountInfo(userId, { creationDate }); } @@ -274,6 +276,23 @@ export class AccountServiceImplementation implements InternalAccountService { this._showHeader$.next(visible); } + private accountInfoEqual(a: AccountInfo, b: AccountInfo) { + if (a == null && b == null) { + return true; + } + + if (a == null || b == null) { + return false; + } + + return ( + a.email === b.email && + a.emailVerified === b.emailVerified && + a.name === b.name && + a.creationDate?.getTime() === b.creationDate?.getTime() + ); + } + private async setAccountInfo(userId: UserId, update: Partial): Promise { function newAccountInfo(oldAccountInfo: AccountInfo): AccountInfo { return { ...oldAccountInfo, ...update }; @@ -291,7 +310,7 @@ export class AccountServiceImplementation implements InternalAccountService { throw new Error("Account does not exist"); } - return !accountInfoEqual(accounts[userId], newAccountInfo(accounts[userId])); + return !this.accountInfoEqual(accounts[userId], newAccountInfo(accounts[userId])); }, }, ); diff --git a/libs/common/src/enums/feature-flag.enum.ts b/libs/common/src/enums/feature-flag.enum.ts index 3bde0eada0a..e5c29636585 100644 --- a/libs/common/src/enums/feature-flag.enum.ts +++ b/libs/common/src/enums/feature-flag.enum.ts @@ -26,7 +26,6 @@ export enum FeatureFlag { /* Billing */ TrialPaymentOptional = "PM-8163-trial-payment", - PM22415_TaxIDWarnings = "pm-22415-tax-id-warnings", PM24032_NewNavigationPremiumUpgradeButton = "pm-24032-new-navigation-premium-upgrade-button", PM25379_UseNewOrganizationMetadataStructure = "pm-25379-use-new-organization-metadata-structure", PM24996_ImplementUpgradeFromFreeDialog = "pm-24996-implement-upgrade-from-free-dialog", @@ -45,6 +44,8 @@ export enum FeatureFlag { NoLogoutOnKdfChange = "pm-23995-no-logout-on-kdf-change", DataRecoveryTool = "pm-28813-data-recovery-tool", ConsolidatedSessionTimeoutComponent = "pm-26056-consolidated-session-timeout-component", + PM27279_V2RegistrationTdeJit = "pm-27279-v2-registration-tde-jit", + EnableAccountEncryptionV2KeyConnectorRegistration = "enable-account-encryption-v2-key-connector-registration", /* Tools */ DesktopSendUIRefresh = "desktop-send-ui-refresh", @@ -63,7 +64,6 @@ export enum FeatureFlag { PM22134SdkCipherListView = "pm-22134-sdk-cipher-list-view", PM22136_SdkCipherEncryption = "pm-22136-sdk-cipher-encryption", CipherKeyEncryption = "cipher-key-encryption", - AutofillConfirmation = "pm-25083-autofill-confirm-from-search", RiskInsightsForPremium = "pm-23904-risk-insights-for-premium", VaultLoadingSkeletons = "pm-25081-vault-skeleton-loaders", BrowserPremiumSpotlight = "pm-23384-browser-premium-spotlight", @@ -71,8 +71,6 @@ export enum FeatureFlag { /* Platform */ IpcChannelFramework = "ipc-channel-framework", - InactiveUserServerNotification = "pm-25130-receive-push-notifications-for-inactive-users", - PushNotificationsWhenLocked = "pm-19388-push-notifications-when-locked", /* Innovation */ PM19148_InnovationArchive = "pm-19148-innovation-archive", @@ -126,7 +124,6 @@ export const DefaultFeatureFlagValue = { [FeatureFlag.PM19941MigrateCipherDomainToSdk]: FALSE, [FeatureFlag.PM22134SdkCipherListView]: FALSE, [FeatureFlag.PM22136_SdkCipherEncryption]: FALSE, - [FeatureFlag.AutofillConfirmation]: FALSE, [FeatureFlag.RiskInsightsForPremium]: FALSE, [FeatureFlag.VaultLoadingSkeletons]: FALSE, [FeatureFlag.BrowserPremiumSpotlight]: FALSE, @@ -137,7 +134,6 @@ export const DefaultFeatureFlagValue = { /* Billing */ [FeatureFlag.TrialPaymentOptional]: FALSE, - [FeatureFlag.PM22415_TaxIDWarnings]: FALSE, [FeatureFlag.PM24032_NewNavigationPremiumUpgradeButton]: FALSE, [FeatureFlag.PM25379_UseNewOrganizationMetadataStructure]: FALSE, [FeatureFlag.PM24996_ImplementUpgradeFromFreeDialog]: FALSE, @@ -156,11 +152,11 @@ export const DefaultFeatureFlagValue = { [FeatureFlag.NoLogoutOnKdfChange]: FALSE, [FeatureFlag.DataRecoveryTool]: FALSE, [FeatureFlag.ConsolidatedSessionTimeoutComponent]: FALSE, + [FeatureFlag.PM27279_V2RegistrationTdeJit]: FALSE, + [FeatureFlag.EnableAccountEncryptionV2KeyConnectorRegistration]: FALSE, /* Platform */ [FeatureFlag.IpcChannelFramework]: FALSE, - [FeatureFlag.InactiveUserServerNotification]: FALSE, - [FeatureFlag.PushNotificationsWhenLocked]: FALSE, /* Innovation */ [FeatureFlag.PM19148_InnovationArchive]: FALSE, diff --git a/libs/common/src/key-management/device-trust/abstractions/device-trust.service.abstraction.ts b/libs/common/src/key-management/device-trust/abstractions/device-trust.service.abstraction.ts index 2bc99e5e5c2..ceff220fe42 100644 --- a/libs/common/src/key-management/device-trust/abstractions/device-trust.service.abstraction.ts +++ b/libs/common/src/key-management/device-trust/abstractions/device-trust.service.abstraction.ts @@ -39,6 +39,7 @@ export abstract class DeviceTrustServiceAbstraction { /** Retrieves the device key if it exists from state or secure storage if supported for the active user. */ abstract getDeviceKey(userId: UserId): Promise; + abstract setDeviceKey(userId: UserId, deviceKey: DeviceKey | null): Promise; abstract decryptUserKeyWithDeviceKey( userId: UserId, encryptedDevicePrivateKey: EncString, diff --git a/libs/common/src/key-management/device-trust/services/device-trust.service.implementation.ts b/libs/common/src/key-management/device-trust/services/device-trust.service.implementation.ts index 59bd7bc11f2..518d16781ab 100644 --- a/libs/common/src/key-management/device-trust/services/device-trust.service.implementation.ts +++ b/libs/common/src/key-management/device-trust/services/device-trust.service.implementation.ts @@ -356,7 +356,7 @@ export class DeviceTrustService implements DeviceTrustServiceAbstraction { } } - private async setDeviceKey(userId: UserId, deviceKey: DeviceKey | null): Promise { + async setDeviceKey(userId: UserId, deviceKey: DeviceKey | null): Promise { if (!userId) { throw new Error("UserId is required. Cannot set device key."); } diff --git a/libs/common/src/key-management/key-connector/models/new-sso-user-key-connector-conversion.ts b/libs/common/src/key-management/key-connector/models/new-sso-user-key-connector-conversion.ts index 12996747c96..3d686697a4e 100644 --- a/libs/common/src/key-management/key-connector/models/new-sso-user-key-connector-conversion.ts +++ b/libs/common/src/key-management/key-connector/models/new-sso-user-key-connector-conversion.ts @@ -5,5 +5,6 @@ import { KdfConfig } from "@bitwarden/key-management"; export interface NewSsoUserKeyConnectorConversion { kdfConfig: KdfConfig; keyConnectorUrl: string; + // SSO organization identifier, not UUID organizationId: string; } diff --git a/libs/common/src/key-management/key-connector/services/key-connector.service.spec.ts b/libs/common/src/key-management/key-connector/services/key-connector.service.spec.ts index 45b4f5e4ac6..b8ee5d7df64 100644 --- a/libs/common/src/key-management/key-connector/services/key-connector.service.spec.ts +++ b/libs/common/src/key-management/key-connector/services/key-connector.service.spec.ts @@ -7,7 +7,8 @@ import { SetKeyConnectorKeyRequest } from "@bitwarden/common/key-management/key- import { KeysRequest } from "@bitwarden/common/models/request/keys.request"; // This import has been flagged as unallowed for this class. It may be involved in a circular dependency loop. // eslint-disable-next-line no-restricted-imports -import { Argon2KdfConfig, PBKDF2KdfConfig, KeyService, KdfType } from "@bitwarden/key-management"; +import { Argon2KdfConfig, KdfType, KeyService, PBKDF2KdfConfig } from "@bitwarden/key-management"; +import { BitwardenClient } from "@bitwarden/sdk-internal"; import { FakeAccountService, FakeStateProvider, mockAccountServiceWith } from "../../../../spec"; import { ApiService } from "../../../abstractions/api.service"; @@ -16,21 +17,26 @@ import { Organization } from "../../../admin-console/models/domain/organization" import { ProfileOrganizationResponse } from "../../../admin-console/models/response/profile-organization.response"; import { KeyConnectorUserKeyResponse } from "../../../auth/models/response/key-connector-user-key.response"; import { TokenService } from "../../../auth/services/token.service"; +import { ConfigService } from "../../../platform/abstractions/config/config.service"; import { LogService } from "../../../platform/abstractions/log.service"; +import { RegisterSdkService } from "../../../platform/abstractions/sdk/register-sdk.service"; +import { Rc } from "../../../platform/misc/reference-counting/rc"; import { Utils } from "../../../platform/misc/utils"; import { SymmetricCryptoKey } from "../../../platform/models/domain/symmetric-crypto-key"; import { OrganizationId, UserId } from "../../../types/guid"; import { MasterKey, UserKey } from "../../../types/key"; +import { AccountCryptographicStateService } from "../../account-cryptography/account-cryptographic-state.service"; import { KeyGenerationService } from "../../crypto"; import { EncString } from "../../crypto/models/enc-string"; import { FakeMasterPasswordService } from "../../master-password/services/fake-master-password.service"; +import { SecurityStateService } from "../../security-state/abstractions/security-state.service"; import { KeyConnectorUserKeyRequest } from "../models/key-connector-user-key.request"; import { NewSsoUserKeyConnectorConversion } from "../models/new-sso-user-key-connector-conversion"; import { - USES_KEY_CONNECTOR, - NEW_SSO_USER_KEY_CONNECTOR_CONVERSION, KeyConnectorService, + NEW_SSO_USER_KEY_CONNECTOR_CONVERSION, + USES_KEY_CONNECTOR, } from "./key-connector.service"; describe("KeyConnectorService", () => { @@ -43,6 +49,10 @@ describe("KeyConnectorService", () => { const organizationService = mock(); const keyGenerationService = mock(); const logoutCallback = jest.fn(); + const configService = mock(); + const registerSdkService = mock(); + const securityStateService = mock(); + const accountCryptographicStateService = mock(); let stateProvider: FakeStateProvider; @@ -50,6 +60,7 @@ describe("KeyConnectorService", () => { let masterPasswordService: FakeMasterPasswordService; const mockUserId = Utils.newGuid() as UserId; + const mockSsoOrgIdentifier = "test-sso-org-id"; const mockOrgId = Utils.newGuid() as OrganizationId; const mockMasterKeyResponse: KeyConnectorUserKeyResponse = new KeyConnectorUserKeyResponse({ @@ -61,7 +72,7 @@ describe("KeyConnectorService", () => { const conversion: NewSsoUserKeyConnectorConversion = { kdfConfig: new PBKDF2KdfConfig(600_000), keyConnectorUrl, - organizationId: mockOrgId, + organizationId: mockSsoOrgIdentifier, }; beforeEach(() => { @@ -82,6 +93,10 @@ describe("KeyConnectorService", () => { keyGenerationService, logoutCallback, stateProvider, + configService, + registerSdkService, + securityStateService, + accountCryptographicStateService, ); }); @@ -419,44 +434,52 @@ describe("KeyConnectorService", () => { }); describe("convertNewSsoUserToKeyConnector", () => { - const passwordKey = new SymmetricCryptoKey(new Uint8Array(64)); - const mockUserKey = new SymmetricCryptoKey(new Uint8Array(64)) as UserKey; - const mockEmail = "test@example.com"; - const mockMasterKey = getMockMasterKey(); - const mockKeyPair = ["mockPubKey", new EncString("mockEncryptedPrivKey")] as [ - string, - EncString, - ]; - let mockMakeUserKeyResult: [UserKey, EncString]; + describe("V2", () => { + const mockKeyConnectorKey = Utils.fromBufferToB64(new Uint8Array(64)); + const mockUserKeyString = Utils.fromBufferToB64(new Uint8Array(64)); + const mockPrivateKey = "mockPrivateKey789"; + const mockKeyConnectorKeyWrappedUserKey = "2.mockWrappedUserKey"; + const mockSigningKey = "mockSigningKey"; + const mockSignedPublicKey = "mockSignedPublicKey"; + const mockSecurityState = "mockSecurityState"; - beforeEach(() => { - const mockUserKey = new SymmetricCryptoKey(new Uint8Array(64)) as UserKey; - const encString = new EncString("mockEncryptedString"); - mockMakeUserKeyResult = [mockUserKey, encString] as [UserKey, EncString]; + let mockSdkRef: any; + let mockSdk: any; - keyGenerationService.createKey.mockResolvedValue(passwordKey); - keyService.makeMasterKey.mockResolvedValue(mockMasterKey); - keyService.makeUserKey.mockResolvedValue(mockMakeUserKeyResult); - keyService.makeKeyPair.mockResolvedValue(mockKeyPair); - tokenService.getEmail.mockResolvedValue(mockEmail); - }); + beforeEach(() => { + configService.getFeatureFlag$.mockReturnValue(of(true)); - it.each([ - [KdfType.PBKDF2_SHA256, 700_000, undefined, undefined], - [KdfType.Argon2id, 11, 65, 5], - ])( - "sets up a new SSO user with key connector", - async (kdfType, kdfIterations, kdfMemory, kdfParallelism) => { - const expectedKdfConfig = - kdfType == KdfType.PBKDF2_SHA256 - ? new PBKDF2KdfConfig(kdfIterations) - : new Argon2KdfConfig(kdfIterations, kdfMemory, kdfParallelism); - - const conversion: NewSsoUserKeyConnectorConversion = { - kdfConfig: expectedKdfConfig, - keyConnectorUrl: keyConnectorUrl, - organizationId: mockOrgId, + mockSdkRef = { + value: { + auth: jest.fn().mockReturnValue({ + registration: jest.fn().mockReturnValue({ + post_keys_for_key_connector_registration: jest.fn().mockResolvedValue({ + key_connector_key: mockKeyConnectorKey, + user_key: mockUserKeyString, + key_connector_key_wrapped_user_key: mockKeyConnectorKeyWrappedUserKey, + account_cryptographic_state: { + V2: { + private_key: mockPrivateKey, + signing_key: mockSigningKey, + signed_public_key: mockSignedPublicKey, + security_state: mockSecurityState, + }, + }, + }), + }), + }), + }, + [Symbol.dispose]: jest.fn(), }; + + mockSdk = { + take: jest.fn().mockReturnValue(mockSdkRef), + }; + + registerSdkService.registerClient$.mockReturnValue(of(mockSdk)); + }); + + it("should set up a new SSO user with key connector using V2", async () => { const conversionState = stateProvider.singleUser.getFake( mockUserId, NEW_SSO_USER_KEY_CONNECTOR_CONVERSION, @@ -465,11 +488,253 @@ describe("KeyConnectorService", () => { await keyConnectorService.convertNewSsoUserToKeyConnector(mockUserId); + expect(registerSdkService.registerClient$).toHaveBeenCalledWith(mockUserId); + expect(mockSdk.take).toHaveBeenCalled(); + expect(mockSdkRef.value.auth).toHaveBeenCalled(); + + const mockRegistration = mockSdkRef.value + .auth() + .registration().post_keys_for_key_connector_registration; + expect(mockRegistration).toHaveBeenCalledWith( + keyConnectorUrl, + mockSsoOrgIdentifier, + mockUserId, + ); + + expect(masterPasswordService.mock.setMasterKey).toHaveBeenCalledWith( + expect.any(SymmetricCryptoKey), + mockUserId, + ); + expect(keyService.setUserKey).toHaveBeenCalledWith( + expect.any(SymmetricCryptoKey), + mockUserId, + ); + expect(masterPasswordService.mock.setMasterKeyEncryptedUserKey).toHaveBeenCalledWith( + expect.any(EncString), + mockUserId, + ); + expect(accountCryptographicStateService.setAccountCryptographicState).toHaveBeenCalledWith( + { + V2: { + private_key: mockPrivateKey, + signing_key: mockSigningKey, + signed_public_key: mockSignedPublicKey, + security_state: mockSecurityState, + }, + }, + mockUserId, + ); + expect(keyService.setPrivateKey).toHaveBeenCalledWith(mockPrivateKey, mockUserId); + expect(keyService.setUserSigningKey).toHaveBeenCalledWith(mockSigningKey, mockUserId); + expect(securityStateService.setAccountSecurityState).toHaveBeenCalledWith( + mockSecurityState, + mockUserId, + ); + expect(keyService.setSignedPublicKey).toHaveBeenCalledWith(mockSignedPublicKey, mockUserId); + + expect(await firstValueFrom(conversionState.state$)).toBeNull(); + }); + + it("should throw error when SDK is not available", async () => { + registerSdkService.registerClient$.mockReturnValue( + of(null as unknown as Rc), + ); + + const conversionState = stateProvider.singleUser.getFake( + mockUserId, + NEW_SSO_USER_KEY_CONNECTOR_CONVERSION, + ); + conversionState.nextState(conversion); + + await expect( + keyConnectorService.convertNewSsoUserToKeyConnector(mockUserId), + ).rejects.toThrow("SDK not available"); + + expect(await firstValueFrom(conversionState.state$)).toEqual(conversion); + expect(masterPasswordService.mock.setMasterKey).not.toHaveBeenCalled(); + expect(keyService.setUserKey).not.toHaveBeenCalled(); + expect(masterPasswordService.mock.setMasterKeyEncryptedUserKey).not.toHaveBeenCalled(); + expect( + accountCryptographicStateService.setAccountCryptographicState, + ).not.toHaveBeenCalled(); + expect(keyService.setPrivateKey).not.toHaveBeenCalled(); + expect(keyService.setUserSigningKey).not.toHaveBeenCalled(); + expect(securityStateService.setAccountSecurityState).not.toHaveBeenCalled(); + expect(keyService.setSignedPublicKey).not.toHaveBeenCalled(); + }); + + it("should throw error when account cryptographic state is not V2", async () => { + mockSdkRef.value + .auth() + .registration() + .post_keys_for_key_connector_registration.mockResolvedValue({ + key_connector_key: mockKeyConnectorKey, + user_key: mockUserKeyString, + key_connector_key_wrapped_user_key: mockKeyConnectorKeyWrappedUserKey, + account_cryptographic_state: { + V1: { + private_key: mockPrivateKey, + }, + }, + }); + + const conversionState = stateProvider.singleUser.getFake( + mockUserId, + NEW_SSO_USER_KEY_CONNECTOR_CONVERSION, + ); + conversionState.nextState(conversion); + + await expect( + keyConnectorService.convertNewSsoUserToKeyConnector(mockUserId), + ).rejects.toThrow("Unexpected account cryptographic state version"); + + expect(await firstValueFrom(conversionState.state$)).toEqual(conversion); + expect(masterPasswordService.mock.setMasterKey).not.toHaveBeenCalled(); + expect(keyService.setUserKey).not.toHaveBeenCalled(); + expect(masterPasswordService.mock.setMasterKeyEncryptedUserKey).not.toHaveBeenCalled(); + expect( + accountCryptographicStateService.setAccountCryptographicState, + ).not.toHaveBeenCalled(); + expect(keyService.setPrivateKey).not.toHaveBeenCalled(); + expect(keyService.setUserSigningKey).not.toHaveBeenCalled(); + expect(securityStateService.setAccountSecurityState).not.toHaveBeenCalled(); + expect(keyService.setSignedPublicKey).not.toHaveBeenCalled(); + }); + + it("should throw error when post_keys_for_key_connector_registration fails", async () => { + const sdkError = new Error("Key Connector registration failed"); + mockSdkRef.value + .auth() + .registration() + .post_keys_for_key_connector_registration.mockRejectedValue(sdkError); + + const conversionState = stateProvider.singleUser.getFake( + mockUserId, + NEW_SSO_USER_KEY_CONNECTOR_CONVERSION, + ); + conversionState.nextState(conversion); + + await expect( + keyConnectorService.convertNewSsoUserToKeyConnector(mockUserId), + ).rejects.toThrow("Key Connector registration failed"); + + expect(await firstValueFrom(conversionState.state$)).toEqual(conversion); + expect(masterPasswordService.mock.setMasterKey).not.toHaveBeenCalled(); + expect(keyService.setUserKey).not.toHaveBeenCalled(); + expect(masterPasswordService.mock.setMasterKeyEncryptedUserKey).not.toHaveBeenCalled(); + expect( + accountCryptographicStateService.setAccountCryptographicState, + ).not.toHaveBeenCalled(); + expect(keyService.setPrivateKey).not.toHaveBeenCalled(); + expect(keyService.setUserSigningKey).not.toHaveBeenCalled(); + expect(securityStateService.setAccountSecurityState).not.toHaveBeenCalled(); + expect(keyService.setSignedPublicKey).not.toHaveBeenCalled(); + }); + }); + + describe("V1", () => { + const passwordKey = new SymmetricCryptoKey(new Uint8Array(64)); + const mockUserKey = new SymmetricCryptoKey(new Uint8Array(64)) as UserKey; + const mockEmail = "test@example.com"; + const mockMasterKey = getMockMasterKey(); + const mockKeyPair = ["mockPubKey", new EncString("mockEncryptedPrivKey")] as [ + string, + EncString, + ]; + let mockMakeUserKeyResult: [UserKey, EncString]; + + beforeEach(() => { + const mockUserKey = new SymmetricCryptoKey(new Uint8Array(64)) as UserKey; + const encString = new EncString("mockEncryptedString"); + mockMakeUserKeyResult = [mockUserKey, encString] as [UserKey, EncString]; + + keyGenerationService.createKey.mockResolvedValue(passwordKey); + keyService.makeMasterKey.mockResolvedValue(mockMasterKey); + keyService.makeUserKey.mockResolvedValue(mockMakeUserKeyResult); + keyService.makeKeyPair.mockResolvedValue(mockKeyPair); + tokenService.getEmail.mockResolvedValue(mockEmail); + configService.getFeatureFlag$.mockReturnValue(of(false)); + }); + + it.each([ + [KdfType.PBKDF2_SHA256, 700_000, undefined, undefined], + [KdfType.Argon2id, 11, 65, 5], + ])( + "sets up a new SSO user with key connector", + async (kdfType, kdfIterations, kdfMemory, kdfParallelism) => { + const expectedKdfConfig = + kdfType == KdfType.PBKDF2_SHA256 + ? new PBKDF2KdfConfig(kdfIterations) + : new Argon2KdfConfig(kdfIterations, kdfMemory, kdfParallelism); + + const conversion: NewSsoUserKeyConnectorConversion = { + kdfConfig: expectedKdfConfig, + keyConnectorUrl: keyConnectorUrl, + organizationId: mockSsoOrgIdentifier, + }; + const conversionState = stateProvider.singleUser.getFake( + mockUserId, + NEW_SSO_USER_KEY_CONNECTOR_CONVERSION, + ); + conversionState.nextState(conversion); + + await keyConnectorService.convertNewSsoUserToKeyConnector(mockUserId); + + expect(keyGenerationService.createKey).toHaveBeenCalledWith(512); + expect(keyService.makeMasterKey).toHaveBeenCalledWith( + passwordKey.keyB64, + mockEmail, + expectedKdfConfig, + ); + expect(masterPasswordService.mock.setMasterKey).toHaveBeenCalledWith( + mockMasterKey, + mockUserId, + ); + expect(keyService.makeUserKey).toHaveBeenCalledWith(mockMasterKey); + expect(keyService.setUserKey).toHaveBeenCalledWith(mockUserKey, mockUserId); + expect(masterPasswordService.mock.setMasterKeyEncryptedUserKey).toHaveBeenCalledWith( + mockMakeUserKeyResult[1], + mockUserId, + ); + expect(keyService.makeKeyPair).toHaveBeenCalledWith(mockMakeUserKeyResult[0]); + expect(apiService.postUserKeyToKeyConnector).toHaveBeenCalledWith( + keyConnectorUrl, + new KeyConnectorUserKeyRequest( + Utils.fromBufferToB64(mockMasterKey.inner().encryptionKey), + ), + ); + expect(apiService.postSetKeyConnectorKey).toHaveBeenCalledWith( + new SetKeyConnectorKeyRequest( + mockMakeUserKeyResult[1].encryptedString!, + expectedKdfConfig, + mockSsoOrgIdentifier, + new KeysRequest(mockKeyPair[0], mockKeyPair[1].encryptedString!), + ), + ); + + // Verify that conversion data is cleared from conversionState + expect(await firstValueFrom(conversionState.state$)).toBeNull(); + }, + ); + + it("handles api error", async () => { + apiService.postUserKeyToKeyConnector.mockRejectedValue(new Error("API error")); + + const conversionState = stateProvider.singleUser.getFake( + mockUserId, + NEW_SSO_USER_KEY_CONNECTOR_CONVERSION, + ); + conversionState.nextState(conversion); + + await expect( + keyConnectorService.convertNewSsoUserToKeyConnector(mockUserId), + ).rejects.toThrow(new Error("Key Connector error")); + expect(keyGenerationService.createKey).toHaveBeenCalledWith(512); expect(keyService.makeMasterKey).toHaveBeenCalledWith( passwordKey.keyB64, mockEmail, - expectedKdfConfig, + new PBKDF2KdfConfig(600_000), ); expect(masterPasswordService.mock.setMasterKey).toHaveBeenCalledWith( mockMasterKey, @@ -488,76 +753,29 @@ describe("KeyConnectorService", () => { Utils.fromBufferToB64(mockMasterKey.inner().encryptionKey), ), ); - expect(apiService.postSetKeyConnectorKey).toHaveBeenCalledWith( - new SetKeyConnectorKeyRequest( - mockMakeUserKeyResult[1].encryptedString!, - expectedKdfConfig, - mockOrgId, - new KeysRequest(mockKeyPair[0], mockKeyPair[1].encryptedString!), - ), + expect(apiService.postSetKeyConnectorKey).not.toHaveBeenCalled(); + expect(await firstValueFrom(conversionState.state$)).toEqual(conversion); + + expect(logoutCallback).toHaveBeenCalledWith("keyConnectorError"); + }); + + it("should throw error when conversion data is null", async () => { + const conversionState = stateProvider.singleUser.getFake( + mockUserId, + NEW_SSO_USER_KEY_CONNECTOR_CONVERSION, ); + conversionState.nextState(null); - // Verify that conversion data is cleared from conversionState - expect(await firstValueFrom(conversionState.state$)).toBeNull(); - }, - ); + await expect( + keyConnectorService.convertNewSsoUserToKeyConnector(mockUserId), + ).rejects.toThrow(new Error("Key Connector conversion not found")); - it("handles api error", async () => { - apiService.postUserKeyToKeyConnector.mockRejectedValue(new Error("API error")); - - const conversionState = stateProvider.singleUser.getFake( - mockUserId, - NEW_SSO_USER_KEY_CONNECTOR_CONVERSION, - ); - conversionState.nextState(conversion); - - await expect(keyConnectorService.convertNewSsoUserToKeyConnector(mockUserId)).rejects.toThrow( - new Error("Key Connector error"), - ); - - expect(keyGenerationService.createKey).toHaveBeenCalledWith(512); - expect(keyService.makeMasterKey).toHaveBeenCalledWith( - passwordKey.keyB64, - mockEmail, - new PBKDF2KdfConfig(600_000), - ); - expect(masterPasswordService.mock.setMasterKey).toHaveBeenCalledWith( - mockMasterKey, - mockUserId, - ); - expect(keyService.makeUserKey).toHaveBeenCalledWith(mockMasterKey); - expect(keyService.setUserKey).toHaveBeenCalledWith(mockUserKey, mockUserId); - expect(masterPasswordService.mock.setMasterKeyEncryptedUserKey).toHaveBeenCalledWith( - mockMakeUserKeyResult[1], - mockUserId, - ); - expect(keyService.makeKeyPair).toHaveBeenCalledWith(mockMakeUserKeyResult[0]); - expect(apiService.postUserKeyToKeyConnector).toHaveBeenCalledWith( - keyConnectorUrl, - new KeyConnectorUserKeyRequest(Utils.fromBufferToB64(mockMasterKey.inner().encryptionKey)), - ); - expect(apiService.postSetKeyConnectorKey).not.toHaveBeenCalled(); - expect(await firstValueFrom(conversionState.state$)).toEqual(conversion); - - expect(logoutCallback).toHaveBeenCalledWith("keyConnectorError"); - }); - - it("should throw error when conversion data is null", async () => { - const conversionState = stateProvider.singleUser.getFake( - mockUserId, - NEW_SSO_USER_KEY_CONNECTOR_CONVERSION, - ); - conversionState.nextState(null); - - await expect(keyConnectorService.convertNewSsoUserToKeyConnector(mockUserId)).rejects.toThrow( - new Error("Key Connector conversion not found"), - ); - - // Verify that no key generation or API calls were made - expect(keyGenerationService.createKey).not.toHaveBeenCalled(); - expect(keyService.makeMasterKey).not.toHaveBeenCalled(); - expect(apiService.postUserKeyToKeyConnector).not.toHaveBeenCalled(); - expect(apiService.postSetKeyConnectorKey).not.toHaveBeenCalled(); + // Verify that no key generation or API calls were made + expect(keyGenerationService.createKey).not.toHaveBeenCalled(); + expect(keyService.makeMasterKey).not.toHaveBeenCalled(); + expect(apiService.postUserKeyToKeyConnector).not.toHaveBeenCalled(); + expect(apiService.postSetKeyConnectorKey).not.toHaveBeenCalled(); + }); }); }); diff --git a/libs/common/src/key-management/key-connector/services/key-connector.service.ts b/libs/common/src/key-management/key-connector/services/key-connector.service.ts index 8a75034cae1..751f1ec8594 100644 --- a/libs/common/src/key-management/key-connector/services/key-connector.service.ts +++ b/libs/common/src/key-management/key-connector/services/key-connector.service.ts @@ -9,22 +9,36 @@ import { AccountService } from "@bitwarden/common/auth/abstractions/account.serv import { NewSsoUserKeyConnectorConversion } from "@bitwarden/common/key-management/key-connector/models/new-sso-user-key-connector-conversion"; // This import has been flagged as unallowed for this class. It may be involved in a circular dependency loop. // eslint-disable-next-line no-restricted-imports -import { Argon2KdfConfig, KdfType, KeyService, PBKDF2KdfConfig } from "@bitwarden/key-management"; +import { + Argon2KdfConfig, + KdfConfig, + KdfType, + KeyService, + PBKDF2KdfConfig, +} from "@bitwarden/key-management"; +import { LogService } from "@bitwarden/logging"; import { ApiService } from "../../../abstractions/api.service"; import { OrganizationService } from "../../../admin-console/abstractions/organization/organization.service.abstraction"; import { OrganizationUserType } from "../../../admin-console/enums"; import { Organization } from "../../../admin-console/models/domain/organization"; import { TokenService } from "../../../auth/abstractions/token.service"; +import { FeatureFlag } from "../../../enums/feature-flag.enum"; import { KeysRequest } from "../../../models/request/keys.request"; -import { LogService } from "../../../platform/abstractions/log.service"; +import { ConfigService } from "../../../platform/abstractions/config/config.service"; +import { RegisterSdkService } from "../../../platform/abstractions/sdk/register-sdk.service"; +import { asUuid } from "../../../platform/abstractions/sdk/sdk.service"; import { Utils } from "../../../platform/misc/utils"; import { SymmetricCryptoKey } from "../../../platform/models/domain/symmetric-crypto-key"; import { KEY_CONNECTOR_DISK, StateProvider, UserKeyDefinition } from "../../../platform/state"; import { UserId } from "../../../types/guid"; -import { MasterKey } from "../../../types/key"; +import { MasterKey, UserKey } from "../../../types/key"; +import { AccountCryptographicStateService } from "../../account-cryptography/account-cryptographic-state.service"; import { KeyGenerationService } from "../../crypto"; +import { EncString } from "../../crypto/models/enc-string"; import { InternalMasterPasswordServiceAbstraction } from "../../master-password/abstractions/master-password.service.abstraction"; +import { SecurityStateService } from "../../security-state/abstractions/security-state.service"; +import { SignedPublicKey, SignedSecurityState, WrappedSigningKey } from "../../types"; import { KeyConnectorService as KeyConnectorServiceAbstraction } from "../abstractions/key-connector.service"; import { KeyConnectorDomainConfirmation } from "../models/key-connector-domain-confirmation"; import { KeyConnectorUserKeyRequest } from "../models/key-connector-user-key.request"; @@ -75,6 +89,10 @@ export class KeyConnectorService implements KeyConnectorServiceAbstraction { private keyGenerationService: KeyGenerationService, private logoutCallback: (logoutReason: LogoutReason, userId?: string) => Promise, private stateProvider: StateProvider, + private configService: ConfigService, + private registerSdkService: RegisterSdkService, + private securityStateService: SecurityStateService, + private accountCryptographicStateService: AccountCryptographicStateService, ) { this.convertAccountRequired$ = accountService.activeAccount$.pipe( filter((account) => account != null), @@ -152,8 +170,106 @@ export class KeyConnectorService implements KeyConnectorServiceAbstraction { throw new Error("Key Connector conversion not found"); } - const { kdfConfig, keyConnectorUrl, organizationId } = conversion; + const { kdfConfig, keyConnectorUrl, organizationId: ssoOrganizationIdentifier } = conversion; + if ( + await firstValueFrom( + this.configService.getFeatureFlag$( + FeatureFlag.EnableAccountEncryptionV2KeyConnectorRegistration, + ), + ) + ) { + await this.convertNewSsoUserToKeyConnectorV2( + userId, + keyConnectorUrl, + ssoOrganizationIdentifier, + ); + } else { + await this.convertNewSsoUserToKeyConnectorV1( + userId, + kdfConfig, + keyConnectorUrl, + ssoOrganizationIdentifier, + ); + } + + await this.stateProvider + .getUser(userId, NEW_SSO_USER_KEY_CONNECTOR_CONVERSION) + .update(() => null); + } + + async convertNewSsoUserToKeyConnectorV2( + userId: UserId, + keyConnectorUrl: string, + ssoOrganizationIdentifier: string, + ) { + const result = await firstValueFrom( + this.registerSdkService.registerClient$(userId).pipe( + map((sdk) => { + if (!sdk) { + throw new Error("SDK not available"); + } + + using ref = sdk.take(); + + return ref.value + .auth() + .registration() + .post_keys_for_key_connector_registration( + keyConnectorUrl, + ssoOrganizationIdentifier, + asUuid(userId), + ); + }), + ), + ); + + if (!("V2" in result.account_cryptographic_state)) { + const version = Object.keys(result.account_cryptographic_state); + throw new Error(`Unexpected account cryptographic state version ${version}`); + } + + await this.masterPasswordService.setMasterKey( + SymmetricCryptoKey.fromString(result.key_connector_key) as MasterKey, + userId, + ); + await this.keyService.setUserKey( + SymmetricCryptoKey.fromString(result.user_key) as UserKey, + userId, + ); + await this.masterPasswordService.setMasterKeyEncryptedUserKey( + new EncString(result.key_connector_key_wrapped_user_key), + userId, + ); + + await this.accountCryptographicStateService.setAccountCryptographicState( + result.account_cryptographic_state, + userId, + ); + // Legacy states + await this.keyService.setPrivateKey(result.account_cryptographic_state.V2.private_key, userId); + await this.keyService.setUserSigningKey( + result.account_cryptographic_state.V2.signing_key as WrappedSigningKey, + userId, + ); + await this.securityStateService.setAccountSecurityState( + result.account_cryptographic_state.V2.security_state as SignedSecurityState, + userId, + ); + if (result.account_cryptographic_state.V2.signed_public_key != null) { + await this.keyService.setSignedPublicKey( + result.account_cryptographic_state.V2.signed_public_key as SignedPublicKey, + userId, + ); + } + } + + async convertNewSsoUserToKeyConnectorV1( + userId: UserId, + kdfConfig: KdfConfig, + keyConnectorUrl: string, + ssoOrganizationIdentifier: string, + ) { const password = await this.keyGenerationService.createKey(512); const masterKey = await this.keyService.makeMasterKey( @@ -182,14 +298,10 @@ export class KeyConnectorService implements KeyConnectorServiceAbstraction { const setPasswordRequest = new SetKeyConnectorKeyRequest( userKey[1].encryptedString, kdfConfig, - organizationId, + ssoOrganizationIdentifier, keys, ); await this.apiService.postSetKeyConnectorKey(setPasswordRequest); - - await this.stateProvider - .getUser(userId, NEW_SSO_USER_KEY_CONNECTOR_CONVERSION) - .update(() => null); } async setNewSsoUserKeyConnectorConversionData( diff --git a/libs/common/src/platform/server-notifications/internal/default-server-notifications.multiuser.spec.ts b/libs/common/src/platform/server-notifications/internal/default-server-notifications.multiuser.spec.ts index 46178f62a07..7aacc783e65 100644 --- a/libs/common/src/platform/server-notifications/internal/default-server-notifications.multiuser.spec.ts +++ b/libs/common/src/platform/server-notifications/internal/default-server-notifications.multiuser.spec.ts @@ -5,7 +5,6 @@ import { BehaviorSubject, bufferCount, firstValueFrom, Subject, ObservedValueOf import { LogoutReason } from "@bitwarden/auth/common"; import { InternalPolicyService } from "@bitwarden/common/admin-console/abstractions/policy/policy.service.abstraction"; import { AuthRequestAnsweringServiceAbstraction } from "@bitwarden/common/auth/abstractions/auth-request-answering/auth-request-answering.service.abstraction"; -import { FeatureFlag } from "@bitwarden/common/enums/feature-flag.enum"; import { mockAccountInfoWith } from "../../../../spec"; import { AccountService } from "../../../auth/abstractions/account.service"; @@ -130,15 +129,6 @@ describe("DefaultServerNotificationsService (multi-user)", () => { authRequestAnsweringService = mock(); - configService = mock(); - configService.getFeatureFlag$.mockImplementation((flag: FeatureFlag) => { - const flagValueByFlag: Partial> = { - [FeatureFlag.InactiveUserServerNotification]: true, - [FeatureFlag.PushNotificationsWhenLocked]: true, - }; - return new BehaviorSubject(flagValueByFlag[flag] ?? false) as any; - }); - policyService = mock(); defaultServerNotificationsService = new DefaultServerNotificationsService( diff --git a/libs/common/src/platform/server-notifications/internal/default-server-notifications.service.ts b/libs/common/src/platform/server-notifications/internal/default-server-notifications.service.ts index 5ee288351d5..5b026add1a2 100644 --- a/libs/common/src/platform/server-notifications/internal/default-server-notifications.service.ts +++ b/libs/common/src/platform/server-notifications/internal/default-server-notifications.service.ts @@ -71,48 +71,20 @@ export class DefaultServerNotificationsService implements ServerNotificationsSer private readonly configService: ConfigService, private readonly policyService: InternalPolicyService, ) { - this.notifications$ = this.configService - .getFeatureFlag$(FeatureFlag.InactiveUserServerNotification) - .pipe( - distinctUntilChanged(), - switchMap((inactiveUserServerNotificationEnabled) => { - if (inactiveUserServerNotificationEnabled) { - return this.accountService.accounts$.pipe( - map((accounts: Record): Set => { - const validUserIds = Object.entries(accounts) - .filter( - ([_, accountInfo]) => accountInfo.email !== "" || accountInfo.emailVerified, - ) - .map(([userId, _]) => userId as UserId); - return new Set(validUserIds); - }), - trackedMerge((id: UserId) => { - return this.userNotifications$(id as UserId).pipe( - map( - (notification: NotificationResponse) => [notification, id as UserId] as const, - ), - ); - }), - ); - } - - return this.accountService.activeAccount$.pipe( - map((account) => account?.id), - distinctUntilChanged(), - switchMap((activeAccountId) => { - if (activeAccountId == null) { - // We don't emit server-notifications for inactive accounts currently - return EMPTY; - } - - return this.userNotifications$(activeAccountId).pipe( - map((notification) => [notification, activeAccountId] as const), - ); - }), - ); - }), - share(), // Multiple subscribers should only create a single connection to the server - ); + this.notifications$ = this.accountService.accounts$.pipe( + map((accounts: Record): Set => { + const validUserIds = Object.entries(accounts) + .filter(([_, accountInfo]) => accountInfo.email !== "" || accountInfo.emailVerified) + .map(([userId, _]) => userId as UserId); + return new Set(validUserIds); + }), + trackedMerge((id: UserId) => { + return this.userNotifications$(id as UserId).pipe( + map((notification: NotificationResponse) => [notification, id as UserId] as const), + ); + }), + share(), // Multiple subscribers should only create a single connection to the server + ); } /** @@ -175,25 +147,13 @@ export class DefaultServerNotificationsService implements ServerNotificationsSer } private hasAccessToken$(userId: UserId) { - return this.configService.getFeatureFlag$(FeatureFlag.PushNotificationsWhenLocked).pipe( + return this.authService.authStatusFor$(userId).pipe( + map( + (authStatus) => + authStatus === AuthenticationStatus.Locked || + authStatus === AuthenticationStatus.Unlocked, + ), distinctUntilChanged(), - switchMap((featureFlagEnabled) => { - if (featureFlagEnabled) { - return this.authService.authStatusFor$(userId).pipe( - map( - (authStatus) => - authStatus === AuthenticationStatus.Locked || - authStatus === AuthenticationStatus.Unlocked, - ), - distinctUntilChanged(), - ); - } else { - return this.authService.authStatusFor$(userId).pipe( - map((authStatus) => authStatus === AuthenticationStatus.Unlocked), - distinctUntilChanged(), - ); - } - }), ); } @@ -208,19 +168,13 @@ export class DefaultServerNotificationsService implements ServerNotificationsSer return; } - if ( - await firstValueFrom( - this.configService.getFeatureFlag$(FeatureFlag.InactiveUserServerNotification), - ) - ) { - const activeAccountId = await firstValueFrom( - this.accountService.activeAccount$.pipe(map((a) => a?.id)), - ); + const activeAccountId = await firstValueFrom( + this.accountService.activeAccount$.pipe(map((a) => a?.id)), + ); - const isActiveUser = activeAccountId === userId; - if (!isActiveUser && !AllowedMultiUserNotificationTypes.has(notification.type)) { - return; - } + const notificationIsForActiveUser = activeAccountId === userId; + if (!notificationIsForActiveUser && !AllowedMultiUserNotificationTypes.has(notification.type)) { + return; } switch (notification.type) { diff --git a/libs/common/src/platform/sync/default-sync.service.ts b/libs/common/src/platform/sync/default-sync.service.ts index 49fd33b8035..fdd05927b50 100644 --- a/libs/common/src/platform/sync/default-sync.service.ts +++ b/libs/common/src/platform/sync/default-sync.service.ts @@ -279,8 +279,8 @@ export class DefaultSyncService extends CoreSyncService { await this.avatarService.setSyncAvatarColor(response.id, response.avatarColor); await this.tokenService.setSecurityStamp(response.securityStamp, response.id); await this.accountService.setAccountEmailVerified(response.id, response.emailVerified); + await this.accountService.setAccountCreationDate(response.id, new Date(response.creationDate)); await this.accountService.setAccountVerifyNewDeviceLogin(response.id, response.verifyDevices); - await this.accountService.setAccountCreationDate(response.id, response.creationDate); await this.billingAccountProfileStateService.setHasPremium( response.premiumPersonally, diff --git a/libs/common/src/vault/abstractions/cipher.service.ts b/libs/common/src/vault/abstractions/cipher.service.ts index 8472a359c51..0d3a0b99fcb 100644 --- a/libs/common/src/vault/abstractions/cipher.service.ts +++ b/libs/common/src/vault/abstractions/cipher.service.ts @@ -207,9 +207,13 @@ export abstract class CipherService implements UserKeyRotationDataProvider>; + abstract upsert( + cipher: CipherData | CipherData[], + userId?: UserId, + ): Promise>; abstract replace(ciphers: { [id: string]: CipherData }, userId: UserId): Promise; abstract clear(userId?: string): Promise; abstract moveManyWithServer(ids: string[], folderId: string, userId: UserId): Promise; diff --git a/libs/common/src/vault/services/cipher.service.ts b/libs/common/src/vault/services/cipher.service.ts index 402b8ed1030..3c44b854de7 100644 --- a/libs/common/src/vault/services/cipher.service.ts +++ b/libs/common/src/vault/services/cipher.service.ts @@ -1196,12 +1196,15 @@ export class CipherService implements CipherServiceAbstraction { await this.encryptedCiphersState(userId).update(() => ciphers); } - async upsert(cipher: CipherData | CipherData[]): Promise> { + async upsert( + cipher: CipherData | CipherData[], + userId?: UserId, + ): Promise> { const ciphers = cipher instanceof CipherData ? [cipher] : cipher; const res = await this.updateEncryptedCipherState((current) => { ciphers.forEach((c) => (current[c.id as CipherId] = c)); return current; - }); + }, userId); // Some state storage providers (e.g. Electron) don't update the state immediately, wait for next tick // Otherwise, subscribers to cipherViews$ can get stale data await new Promise((resolve) => setTimeout(resolve, 0)); diff --git a/libs/common/src/vault/services/default-cipher-archive.service.spec.ts b/libs/common/src/vault/services/default-cipher-archive.service.spec.ts index 807311ca851..2f5e69d65ed 100644 --- a/libs/common/src/vault/services/default-cipher-archive.service.spec.ts +++ b/libs/common/src/vault/services/default-cipher-archive.service.spec.ts @@ -219,7 +219,7 @@ describe("DefaultCipherArchiveService", () => { } as any, }), ); - mockCipherService.replace.mockResolvedValue(undefined); + mockCipherService.upsert.mockResolvedValue(undefined); }); it("should archive single cipher", async () => { @@ -233,13 +233,13 @@ describe("DefaultCipherArchiveService", () => { true, ); expect(mockCipherService.ciphers$).toHaveBeenCalledWith(userId); - expect(mockCipherService.replace).toHaveBeenCalledWith( - expect.objectContaining({ - [cipherId]: expect.objectContaining({ + expect(mockCipherService.upsert).toHaveBeenCalledWith( + [ + expect.objectContaining({ archivedDate: "2024-01-15T10:30:00.000Z", revisionDate: "2024-01-15T10:31:00.000Z", }), - }), + ], userId, ); }); @@ -282,7 +282,7 @@ describe("DefaultCipherArchiveService", () => { } as any, }), ); - mockCipherService.replace.mockResolvedValue(undefined); + mockCipherService.upsert.mockResolvedValue(undefined); }); it("should unarchive single cipher", async () => { @@ -296,12 +296,12 @@ describe("DefaultCipherArchiveService", () => { true, ); expect(mockCipherService.ciphers$).toHaveBeenCalledWith(userId); - expect(mockCipherService.replace).toHaveBeenCalledWith( - expect.objectContaining({ - [cipherId]: expect.objectContaining({ + expect(mockCipherService.upsert).toHaveBeenCalledWith( + [ + expect.objectContaining({ revisionDate: "2024-01-15T10:31:00.000Z", }), - }), + ], userId, ); }); diff --git a/libs/common/src/vault/services/default-cipher-archive.service.ts b/libs/common/src/vault/services/default-cipher-archive.service.ts index 8076735c9e2..c1daade0dad 100644 --- a/libs/common/src/vault/services/default-cipher-archive.service.ts +++ b/libs/common/src/vault/services/default-cipher-archive.service.ts @@ -95,7 +95,7 @@ export class DefaultCipherArchiveService implements CipherArchiveService { localCipher.revisionDate = cipher.revisionDate; } - await this.cipherService.replace(currentCiphers, userId); + await this.cipherService.upsert(Object.values(currentCiphers), userId); } async unarchiveWithServer(ids: CipherId | CipherId[], userId: UserId): Promise { @@ -116,6 +116,6 @@ export class DefaultCipherArchiveService implements CipherArchiveService { localCipher.revisionDate = cipher.revisionDate; } - await this.cipherService.replace(currentCiphers, userId); + await this.cipherService.upsert(Object.values(currentCiphers), userId); } } diff --git a/libs/components/src/a11y/router-focus-manager.service.ts b/libs/components/src/a11y/router-focus-manager.service.ts index 27c4e0f9b1e..f7371e02a17 100644 --- a/libs/components/src/a11y/router-focus-manager.service.ts +++ b/libs/components/src/a11y/router-focus-manager.service.ts @@ -1,7 +1,7 @@ import { inject, Injectable } from "@angular/core"; import { takeUntilDestroyed } from "@angular/core/rxjs-interop"; import { NavigationEnd, Router } from "@angular/router"; -import { skip, filter, map, combineLatestWith, tap } from "rxjs"; +import { skip, filter, combineLatestWith, tap } from "rxjs"; import { FeatureFlag } from "@bitwarden/common/enums/feature-flag.enum"; import { ConfigService } from "@bitwarden/common/platform/abstractions/config/config.service"; @@ -19,8 +19,10 @@ export class RouterFocusManagerService { * * By default, we focus the `main` after an internal route navigation. * - * Consumers can opt out of the passing the following to the `info` input: - * `` + * Consumers can opt out of the passing the following to the `state` input. Using `state` + * allows us to access the value between browser back/forward arrows. + * In template: `` + * In typescript: `this.router.navigate([], { state: { focusMainAfterNav: false }})` * * Or, consumers can use the autofocus directive on an applicable interactive element. * The autofocus directive will take precedence over this route focus pipeline. @@ -44,15 +46,12 @@ export class RouterFocusManagerService { skip(1), combineLatestWith(this.configService.getFeatureFlag$(FeatureFlag.RouterFocusManagement)), filter(([_navEvent, flagEnabled]) => flagEnabled), - map(() => { - const currentNavData = this.router.getCurrentNavigation()?.extras; + filter(() => { + const currentNavExtras = this.router.currentNavigation()?.extras; - const info = currentNavData?.info as { focusMainAfterNav?: boolean } | undefined; + const focusMainAfterNav: boolean | undefined = currentNavExtras?.state?.focusMainAfterNav; - return info; - }), - filter((currentNavInfo) => { - return currentNavInfo === undefined ? true : currentNavInfo?.focusMainAfterNav !== false; + return focusMainAfterNav !== false; }), tap(() => { const mainEl = document.querySelector("main"); diff --git a/libs/components/src/dialog/dialog.service.stories.ts b/libs/components/src/dialog/dialog.service.stories.ts index 3b5bdc4d4e9..4e5c718e494 100644 --- a/libs/components/src/dialog/dialog.service.stories.ts +++ b/libs/components/src/dialog/dialog.service.stories.ts @@ -6,13 +6,14 @@ import { Meta, StoryObj, applicationConfig, moduleMetadata } from "@storybook/an import { getAllByRole, userEvent } from "storybook/test"; import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.service"; +import { GlobalStateProvider } from "@bitwarden/state"; import { ButtonModule } from "../button"; import { IconButtonModule } from "../icon-button"; import { LayoutComponent } from "../layout"; import { SharedModule } from "../shared"; import { positionFixedWrapperDecorator } from "../stories/storybook-decorators"; -import { I18nMockService } from "../utils/i18n-mock.service"; +import { I18nMockService, StorybookGlobalStateProvider } from "../utils"; import { DialogModule } from "./dialog.module"; import { DialogService } from "./dialog.service"; @@ -161,6 +162,10 @@ export default { }); }, }, + { + provide: GlobalStateProvider, + useClass: StorybookGlobalStateProvider, + }, ], }), ], diff --git a/libs/components/src/drawer/drawer.stories.ts b/libs/components/src/drawer/drawer.stories.ts index 727d16b5481..9904b77ee9f 100644 --- a/libs/components/src/drawer/drawer.stories.ts +++ b/libs/components/src/drawer/drawer.stories.ts @@ -1,7 +1,8 @@ import { RouterTestingModule } from "@angular/router/testing"; -import { Meta, StoryObj, moduleMetadata } from "@storybook/angular"; +import { Meta, StoryObj, applicationConfig, moduleMetadata } from "@storybook/angular"; import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.service"; +import { GlobalStateProvider } from "@bitwarden/state"; import { ButtonModule } from "../button"; import { CalloutModule } from "../callout"; @@ -9,7 +10,7 @@ import { LayoutComponent } from "../layout"; import { mockLayoutI18n } from "../layout/mocks"; import { positionFixedWrapperDecorator } from "../stories/storybook-decorators"; import { TypographyModule } from "../typography"; -import { I18nMockService } from "../utils"; +import { I18nMockService, StorybookGlobalStateProvider } from "../utils"; import { DrawerBodyComponent } from "./drawer-body.component"; import { DrawerHeaderComponent } from "./drawer-header.component"; @@ -47,6 +48,14 @@ export default { }, ], }), + applicationConfig({ + providers: [ + { + provide: GlobalStateProvider, + useClass: StorybookGlobalStateProvider, + }, + ], + }), ], } as Meta; diff --git a/libs/components/src/item/item.stories.ts b/libs/components/src/item/item.stories.ts index d2c197d0088..9498c163da7 100644 --- a/libs/components/src/item/item.stories.ts +++ b/libs/components/src/item/item.stories.ts @@ -1,16 +1,23 @@ import { ScrollingModule } from "@angular/cdk/scrolling"; import { CommonModule } from "@angular/common"; import { RouterTestingModule } from "@angular/router/testing"; -import { Meta, StoryObj, componentWrapperDecorator, moduleMetadata } from "@storybook/angular"; +import { + Meta, + StoryObj, + applicationConfig, + componentWrapperDecorator, + moduleMetadata, +} from "@storybook/angular"; import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.service"; +import { GlobalStateProvider } from "@bitwarden/state"; import { AvatarModule } from "../avatar"; import { BadgeModule } from "../badge"; import { IconButtonModule } from "../icon-button"; import { LayoutComponent } from "../layout"; import { TypographyModule } from "../typography"; -import { I18nMockService } from "../utils/i18n-mock.service"; +import { I18nMockService, StorybookGlobalStateProvider } from "../utils"; import { ItemActionComponent } from "./item-action.component"; import { ItemContentComponent } from "./item-content.component"; @@ -50,6 +57,14 @@ export default { }, ], }), + applicationConfig({ + providers: [ + { + provide: GlobalStateProvider, + useClass: StorybookGlobalStateProvider, + }, + ], + }), componentWrapperDecorator((story) => `
${story}
`), ], parameters: { diff --git a/libs/components/src/layout/layout.stories.ts b/libs/components/src/layout/layout.stories.ts index a059fd61b92..59770c21d2e 100644 --- a/libs/components/src/layout/layout.stories.ts +++ b/libs/components/src/layout/layout.stories.ts @@ -1,13 +1,15 @@ import { RouterTestingModule } from "@angular/router/testing"; -import { Meta, StoryObj, moduleMetadata } from "@storybook/angular"; +import { Meta, StoryObj, applicationConfig, moduleMetadata } from "@storybook/angular"; import { userEvent } from "storybook/test"; import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.service"; +import { GlobalStateProvider } from "@bitwarden/state"; import { CalloutModule } from "../callout"; import { NavigationModule } from "../navigation"; import { positionFixedWrapperDecorator } from "../stories/storybook-decorators"; import { I18nMockService } from "../utils/i18n-mock.service"; +import { StorybookGlobalStateProvider } from "../utils/state-mock"; import { LayoutComponent } from "./layout.component"; import { mockLayoutI18n } from "./mocks"; @@ -28,6 +30,14 @@ export default { }, ], }), + applicationConfig({ + providers: [ + { + provide: GlobalStateProvider, + useClass: StorybookGlobalStateProvider, + }, + ], + }), ], parameters: { chromatic: { viewports: [640, 1280] }, diff --git a/libs/components/src/layout/mocks.ts b/libs/components/src/layout/mocks.ts index 8b001eb8fd1..15b126ca718 100644 --- a/libs/components/src/layout/mocks.ts +++ b/libs/components/src/layout/mocks.ts @@ -5,4 +5,5 @@ export const mockLayoutI18n = { submenu: "submenu", toggleCollapse: "toggle collapse", loading: "Loading", + resizeSideNavigation: "Resize side navigation", }; diff --git a/libs/components/src/navigation/nav-group.stories.ts b/libs/components/src/navigation/nav-group.stories.ts index c0111c23fc1..fa1cb06dbfe 100644 --- a/libs/components/src/navigation/nav-group.stories.ts +++ b/libs/components/src/navigation/nav-group.stories.ts @@ -3,11 +3,13 @@ import { RouterModule } from "@angular/router"; import { StoryObj, Meta, moduleMetadata, applicationConfig } from "@storybook/angular"; import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.service"; +import { GlobalStateProvider } from "@bitwarden/state"; import { LayoutComponent } from "../layout"; import { SharedModule } from "../shared/shared.module"; import { positionFixedWrapperDecorator } from "../stories/storybook-decorators"; import { I18nMockService } from "../utils/i18n-mock.service"; +import { StorybookGlobalStateProvider } from "../utils/state-mock"; import { NavGroupComponent } from "./nav-group.component"; import { NavigationModule } from "./navigation.module"; @@ -42,6 +44,7 @@ export default { toggleSideNavigation: "Toggle side navigation", skipToContent: "Skip to content", loading: "Loading", + resizeSideNavigation: "Resize side navigation", }); }, }, @@ -58,6 +61,10 @@ export default { { useHash: true }, ), ), + { + provide: GlobalStateProvider, + useClass: StorybookGlobalStateProvider, + }, ], }), ], diff --git a/libs/components/src/navigation/nav-item.stories.ts b/libs/components/src/navigation/nav-item.stories.ts index 131dacc8142..3036ab26348 100644 --- a/libs/components/src/navigation/nav-item.stories.ts +++ b/libs/components/src/navigation/nav-item.stories.ts @@ -1,12 +1,14 @@ import { RouterTestingModule } from "@angular/router/testing"; -import { StoryObj, Meta, moduleMetadata } from "@storybook/angular"; +import { StoryObj, Meta, moduleMetadata, applicationConfig } from "@storybook/angular"; import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.service"; +import { GlobalStateProvider } from "@bitwarden/state"; import { IconButtonModule } from "../icon-button"; import { LayoutComponent } from "../layout"; import { positionFixedWrapperDecorator } from "../stories/storybook-decorators"; import { I18nMockService } from "../utils/i18n-mock.service"; +import { StorybookGlobalStateProvider } from "../utils/state-mock"; import { NavItemComponent } from "./nav-item.component"; import { NavigationModule } from "./navigation.module"; @@ -31,11 +33,20 @@ export default { toggleSideNavigation: "Toggle side navigation", skipToContent: "Skip to content", loading: "Loading", + resizeSideNavigation: "Resize side navigation", }); }, }, ], }), + applicationConfig({ + providers: [ + { + provide: GlobalStateProvider, + useClass: StorybookGlobalStateProvider, + }, + ], + }), ], parameters: { design: { diff --git a/libs/components/src/navigation/side-nav.component.html b/libs/components/src/navigation/side-nav.component.html index c8b20ecba77..84c7e3e7298 100644 --- a/libs/components/src/navigation/side-nav.component.html +++ b/libs/components/src/navigation/side-nav.component.html @@ -5,47 +5,64 @@ }; as data ) { - + +
} diff --git a/libs/components/src/navigation/side-nav.component.ts b/libs/components/src/navigation/side-nav.component.ts index cf3d20762fe..b13920d9749 100644 --- a/libs/components/src/navigation/side-nav.component.ts +++ b/libs/components/src/navigation/side-nav.component.ts @@ -1,4 +1,5 @@ import { CdkTrapFocus } from "@angular/cdk/a11y"; +import { DragDropModule, CdkDragMove } from "@angular/cdk/drag-drop"; import { CommonModule } from "@angular/common"; import { Component, ElementRef, inject, input, viewChild } from "@angular/core"; @@ -16,16 +17,26 @@ export type SideNavVariant = "primary" | "secondary"; @Component({ selector: "bit-side-nav", templateUrl: "side-nav.component.html", - imports: [CommonModule, CdkTrapFocus, NavDividerComponent, BitIconButtonComponent, I18nPipe], + imports: [ + CommonModule, + CdkTrapFocus, + NavDividerComponent, + BitIconButtonComponent, + I18nPipe, + DragDropModule, + ], host: { class: "tw-block tw-h-full", }, }) export class SideNavComponent { + protected sideNavService = inject(SideNavService); + readonly variant = input("primary"); private readonly toggleButton = viewChild("toggleButton", { read: ElementRef }); - protected sideNavService = inject(SideNavService); + + private elementRef = inject>(ElementRef); protected handleKeyDown = (event: KeyboardEvent) => { if (event.key === "Escape") { @@ -36,4 +47,21 @@ export class SideNavComponent { return true; }; + + protected onDragMoved(event: CdkDragMove) { + const rectX = this.elementRef.nativeElement.getBoundingClientRect().x; + const eventXPointer = event.pointerPosition.x; + + this.sideNavService.setWidthFromDrag(eventXPointer, rectX); + + // Fix for CDK applying a transform that can cause visual drifting + const element = event.source.element.nativeElement; + element.style.transform = "none"; + } + + protected onKeydown(event: KeyboardEvent) { + if (event.key === "ArrowRight" || event.key === "ArrowLeft") { + this.sideNavService.setWidthFromKeys(event.key); + } + } } diff --git a/libs/components/src/navigation/side-nav.service.ts b/libs/components/src/navigation/side-nav.service.ts index ce44811c7e0..63e54c81fe5 100644 --- a/libs/components/src/navigation/side-nav.service.ts +++ b/libs/components/src/navigation/side-nav.service.ts @@ -1,15 +1,37 @@ -import { Injectable } from "@angular/core"; +import { inject, Injectable } from "@angular/core"; import { takeUntilDestroyed } from "@angular/core/rxjs-interop"; -import { BehaviorSubject, Observable, combineLatest, fromEvent, map, startWith } from "rxjs"; +import { + BehaviorSubject, + Observable, + combineLatest, + fromEvent, + map, + startWith, + debounceTime, + first, +} from "rxjs"; + +import { BIT_SIDE_NAV_DISK, GlobalStateProvider, KeyDefinition } from "@bitwarden/state"; import { BREAKPOINTS, isAtOrLargerThanBreakpoint } from "../utils/responsive-utils"; type CollapsePreference = "open" | "closed" | null; +const BIT_SIDE_NAV_WIDTH_KEY_DEF = new KeyDefinition(BIT_SIDE_NAV_DISK, "side-nav-width", { + deserializer: (s) => s, +}); + @Injectable({ providedIn: "root", }) export class SideNavService { + // Units in rem + readonly DEFAULT_OPEN_WIDTH = 18; + readonly MIN_OPEN_WIDTH = 15; + readonly MAX_OPEN_WIDTH = 24; + + private rootFontSizePx: number; + private _open$ = new BehaviorSubject(isAtOrLargerThanBreakpoint("md")); open$ = this._open$.asObservable(); @@ -21,7 +43,30 @@ export class SideNavService { map(([open, isLargeScreen]) => open && !isLargeScreen), ); + /** + * Local component state width + * + * This observable has immediate pixel-perfect updates for the sidebar display width to use + */ + private readonly _width$ = new BehaviorSubject(this.DEFAULT_OPEN_WIDTH); + readonly width$ = this._width$.asObservable(); + + /** + * State provider width + * + * This observable is used to initialize the component state and will be periodically synced + * to the local _width$ state to avoid excessive writes + */ + private readonly widthState = inject(GlobalStateProvider).get(BIT_SIDE_NAV_WIDTH_KEY_DEF); + readonly widthState$ = this.widthState.state$.pipe( + map((width) => width ?? this.DEFAULT_OPEN_WIDTH), + ); + constructor() { + // Get computed root font size to support user-defined a11y font increases + this.rootFontSizePx = parseFloat(getComputedStyle(document.documentElement).fontSize || "16"); + + // Handle open/close state combineLatest([this.isLargeScreen$, this.userCollapsePreference$]) .pipe(takeUntilDestroyed()) .subscribe(([isLargeScreen, userCollapsePreference]) => { @@ -32,6 +77,16 @@ export class SideNavService { this.setOpen(); } }); + + // Initialize the resizable width from state provider + this.widthState$.pipe(first()).subscribe((width: number) => { + this._width$.next(width); + }); + + // Periodically sync to state provider when component state changes + this.width$.pipe(debounceTime(200), takeUntilDestroyed()).subscribe((width) => { + void this.widthState.update(() => width); + }); } get open() { @@ -46,6 +101,9 @@ export class SideNavService { this._open$.next(false); } + /** + * Toggle the open/close state of the side nav + */ toggle() { const curr = this._open$.getValue(); // Store user's preference based on what state they're toggling TO @@ -57,8 +115,51 @@ export class SideNavService { this.setOpen(); } } + + /** + * Set new side nav width from drag event coordinates + * + * @param eventXCoordinate x coordinate of the pointer's bounding client rect + * @param dragElementXCoordinate x coordinate of the drag element's bounding client rect + */ + setWidthFromDrag(eventXPointer: number, dragElementXCoordinate: number) { + const newWidthInPixels = eventXPointer - dragElementXCoordinate; + + const newWidthInRem = newWidthInPixels / this.rootFontSizePx; + + this._setWidthWithinMinMax(newWidthInRem); + } + + /** + * Set new side nav width from arrow key events + * + * @param key event key, must be either ArrowRight or ArrowLeft + */ + setWidthFromKeys(key: "ArrowRight" | "ArrowLeft") { + const currentWidth = this._width$.getValue(); + + const delta = key === "ArrowLeft" ? -1 : 1; + const newWidth = currentWidth + delta; + + this._setWidthWithinMinMax(newWidth); + } + + /** + * Calculate and set the new width, not going out of the min/max bounds + * @param newWidth desired new width: number + */ + private _setWidthWithinMinMax(newWidth: number) { + const width = Math.min(Math.max(newWidth, this.MIN_OPEN_WIDTH), this.MAX_OPEN_WIDTH); + + this._width$.next(width); + } } +/** + * Helper function for subscribing to media query events + * @param query media query to validate against + * @returns Observable + */ export const media = (query: string): Observable => { const mediaQuery = window.matchMedia(query); return fromEvent(mediaQuery, "change").pipe( diff --git a/libs/components/src/stories/colors.mdx b/libs/components/src/stories/colors.mdx index ca9a97b9071..3cf3b46215c 100644 --- a/libs/components/src/stories/colors.mdx +++ b/libs/components/src/stories/colors.mdx @@ -2,127 +2,772 @@ import { Meta } from "@storybook/addon-docs/blocks"; -export const Row = (name) => ( - - {name} - - -); +# Color System -export const Table = (args) => ( - - - - - - - - - {Row("background")} - {Row("background-alt")} - {Row("background-alt2")} - {Row("background-alt3")} - {Row("background-alt4")} - - - {Row("primary-100")} - {Row("primary-300")} - {Row("primary-600")} - {Row("primary-700")} - - - {Row("secondary-100")} - {Row("secondary-300")} - {Row("secondary-500")} - {Row("secondary-600")} - {Row("secondary-700")} - - - {Row("success-100")} - {Row("success-600")} - {Row("success-700")} - - - {Row("danger-100")} - {Row("danger-600")} - {Row("danger-700")} - - - {Row("warning-100")} - {Row("warning-600")} - {Row("warning-700")} - - - {Row("info-100")} - {Row("info-600")} - {Row("info-700")} - - - {Row("notification-100")} - {Row("notification-600")} - - - {Row("illustration-outline")} - {Row("illustration-bg-primary")} - {Row("illustration-bg-secondary")} - {Row("illustration-bg-tertiary")} - {Row("illustration-tertiary")} - {Row("illustration-logo")} - +Bitwarden uses a three-tier color token architecture: - - - - - - - - {Row("text-main")} - {Row("text-muted")} - {Row("text-contrast")} - {Row("text-alt2")} - {Row("text-code")} - +- **Primitive Colors** - Raw color values from the Figma design system +- **Semantic Tokens** - Meaningful names that reference primitives +- **Tailwind Utilities** - CSS classes for components -
General usage
Text
-); +## Color Token Structure - +### Semantic Foreground Tokens -# Colors +- **Neutral**: `fg-white`, `fg-dark`, `fg-contrast`, `fg-heading`, `fg-body`, `fg-body-subtle`, + `fg-disabled` +- **Brand**: `fg-brand-soft`, `fg-brand`, `fg-brand-strong` +- **Status**: `fg-success`, `fg-success-strong`, `fg-danger`, `fg-danger-strong`, `fg-warning`, + `fg-warning-strong`, `fg-sensitive` +- **Accent**: `fg-accent-primary`, `fg-accent-secondary`, `fg-accent-tertiary` (with `-soft` and + `-strong` variants) +- Format: `--color-fg-{name}` -Tailwind traditionally has a very large color palette. Bitwarden has their own more limited color -palette instead. +### Semantic Background Tokens -This has a couple of advantages: +- **Neutral**: `bg-white`, `bg-dark`, `bg-contrast`, `bg-contrast-strong`, `bg-primary`, + `bg-secondary`, `bg-tertiary`, `bg-quaternary`, `bg-gray`, `bg-disabled` +- **Brand**: `bg-brand-softer`, `bg-brand-soft`, `bg-brand-medium`, `bg-brand`, `bg-brand-strong` +- **Status**: `bg-success-soft`, `bg-success-medium`, `bg-success`, `bg-success-strong`, + `bg-danger-soft`, `bg-danger-medium`, `bg-danger`, `bg-danger-strong`, `bg-warning-soft`, + `bg-warning-medium`, `bg-warning`, `bg-warning-strong` +- **Accent**: `bg-accent-primary-soft`, `bg-accent-primary-medium`, `bg-accent-primary`, + `bg-accent-secondary-soft`, `bg-accent-secondary-medium`, `bg-accent-secondary`, + `bg-accent-tertiary-soft`, `bg-accent-tertiary-medium`, `bg-accent-tertiary` +- **Special**: `bg-hover`, `bg-overlay` +- Format: `--color-bg-{name}` -- Promotes consistency across the application. -- Easier to maintain and make adjustments. -- Allows us to support more than two themes light & dark, should it be needed. +### Semantic Border Tokens -Below are all the permited colors. Please consult design before considering adding a new color. +- **Neutral**: `border-muted`, `border-light`, `border-base`, `border-strong`, `border-buffer` +- **Brand**: `border-brand-soft`, `border-brand`, `border-brand-strong` +- **Status**: `border-success-soft`, `border-success`, `border-success-strong`, + `border-danger-soft`, `border-danger`, `border-danger-strong`, `border-warning-soft`, + `border-warning`, `border-warning-strong` +- **Accent**: `border-accent-primary-soft`, `border-accent-primary`, `border-accent-secondary-soft`, + `border-accent-secondary`, `border-accent-tertiary-soft`, `border-accent-tertiary` +- **Focus**: `border-focus` +- Format: `--color-border-{name}` -
- -
+## Semantic Color Tokens + +> **Note:** Due to Tailwind's utility naming and our semantic token structure, class names will +> appear repetitive (e.g., `tw-bg-bg-primary`). This repetition is intentional: +> +> - `tw-` = Tailwind prefix +> - `bg-` = Tailwind utility type (background) +> - `bg-primary` = Our semantic token name + +### Background Colors + +Use `tw-bg-bg-*` for background colors. These tokens automatically adapt to dark mode. + +export const Swatch = ({ name }) => { + const swatchClass = `tw-h-10 tw-w-10 tw-shrink-0 tw-rounded-lg tw-border tw-border-border-base tw-bg-${name}`; + return
; +}; + +export const BackgroundCard = ({ name, primitiveColor }) => { + const bgClass = `tw-flex tw-items-center tw-gap-3 tw-rounded-xl tw-p-4 tw-border tw-border-border-base tw-bg-bg-primary`; + const swatchClass = `tw-h-10 tw-w-10 tw-shrink-0 tw-rounded-lg tw-border tw-border-base tw-bg-bg-${name}`; + return ( +
+
+
bg-{name}
+
({primitiveColor})
+
+ +
+ ); +}; + +
+
+

Light mode

+ +
+

Neutral

+
+ + + + + + + + + + +
+
+ +
+

Brand

+
+ + + + + +
+
+ +
+

Status

+
+ + + + + + + + + + + + +
+
+ +
+

Accent

+
+ + + + + + + + + +
+
+ +
+

Hover

+
+ +
+
+ +
+

Overlay

+
+ +
+
+ +
+ +
+

Dark mode

+ +
+

Neutral

+
+ + + + + + + + + + +
+
+ +
+

Brand

+
+ + + + + +
+
+ +
+

Status

+
+ + + + + + + + + + + + +
+
+ +
+

Accent

+
+ + + + + + + + + +
+
+ +
+

Hover

+
+ +
+
+ +
+

Overlay

+
+ +
+
+ +
+
+ +--- + +### Foreground Colors + +Use `tw-text-fg-*` for text colors. These tokens automatically adapt to dark mode. + +export const ForegroundCard = ({ name, primitiveColor }) => { + const textClass = `tw-text-fg-${name} tw-text-2xl tw-font-bold tw-shrink-0`; + return ( +
+
+
fg-{name}
+
({primitiveColor})
+
+ +
+ ); +}; + +
+
+

Light mode

+ +
+

Neutral

+
+ + + + + + + +
+
+ +
+

Brand

+
+ + + +
+
+ +
+

Status

+
+ + + + + + + +
+
+ +
+

Accent

+
+ + + + + + + + + +
+
+ +
+ +
+

Dark mode

+ +
+

Neutral

+
+ + + + + + + +
+
+ +
+

Brand

+
+ + + +
+
+ +
+

Status

+
+ + + + + + + +
+
+ +
+

Accent

+
+ + + + + + + + + +
+
+ +
+
+ +--- + +### Border Colors + +Use `tw-border-border-*` for border colors. These tokens automatically adapt to dark mode. + +export const BorderCard = ({ name, primitiveColor }) => { + return ( +
+
+
+ border-{name} +
+
({primitiveColor})
+
+ +
+ ); +}; + +
+
+

Light mode

+ +
+

Neutral

+
+ + + + + +
+
+ +
+

Brand

+
+ + + +
+
+ +
+

Status

+
+ + + + + + + + + +
+
+ +
+

Accent

+
+ + + + + + +
+
+ +
+

Focus

+
+ +
+
+ +
+ +
+

Dark mode

+ +
+

Neutral

+
+ + + + + +
+
+ +
+

Brand

+
+ + + +
+
+ +
+

Status

+
+ + + + + + + + + +
+
+ +
+

Accent

+
+ + + + + + +
+
+ +
+

Focus

+
+ +
+
+ +
+
+ +--- + +## Usage Guidelines + +### ✅ DO - Use semantic tokens via Tailwind + +```html + +

Heading text

+

Body text

+ +Error message + + +
Primary background
+
Secondary background
+ +
Danger alert
+ + +
Base border
+ +
Brand border
+ + + +
+ Success alert with matching colors +
+ + +
Hover effect
+ + +
Modal overlay
+``` + +### ❌ DON'T - Use primitive colors directly + +```html + +

Text

+
Background
+ + +

Text

+
Background
+ + +Text +
Background
+``` + +**Why this is wrong:** Primitives aren't semantic and may change. Always use semantic tokens like +`tw-text-fg-brand`, `tw-bg-success`, etc. + +--- + +## Dark Mode + +- Semantic tokens automatically adapt to dark mode via `.theme_dark` class +- No component changes needed when theme switches +- The same semantic token name works in both light and dark themes +- All color values are automatically swapped based on the active theme + +--- + +## Migration Strategy + +- **New components:** Use semantic tokens (`fg-*`, `bg-*`, `border-*`) exclusively +- **Existing components:** Keep legacy tokens until refactoring +- **When refactoring:** Replace legacy tokens with semantic equivalents + +--- + +## Legacy Colors + +**Legacy colors (RGB format)** still exist for backwards compatibility: + +- `primary-*`, `secondary-*`, `success-*`, `danger-*`, `warning-*`, etc. +- Use these only when updating existing components +- Migrate to new semantic tokens when refactoring + +The following legacy colors are displayed below with both light and dark mode values: + +export const LegacyCard = ({ name }) => { + return ( +
+
+
{name}
+
(legacy RGB format)
+
+ +
+ ); +}; + +
+
+

Light mode

+ +
+

General

+
+ + + + + +
+
+ +
+

Primary

+
+ + + + +
+
+ +
+

+ Secondary +

+
+ + + + + +
+
+ +
+

Success

+
+ + + +
+
+ +
+

Danger

+
+ + + +
+
+ +
+

Warning

+
+ + + +
+
+ +
+

Info

+
+ + + +
+
+ +
+ +
+

Dark mode

+ +
+

General

+
+ + + + + +
+
+ +
+

Primary

+
+ + + + +
+
+ +
+

+ Secondary +

+
+ + + + + +
+
+ +
+

Success

+
+ + + +
+
+ +
+

Danger

+
+ + + +
+
+ +
+

Warning

+
+ + + +
+
+ +
+

Info

+
+ + + +
+
+ +
diff --git a/libs/components/src/stories/kitchen-sink/kitchen-sink.stories.ts b/libs/components/src/stories/kitchen-sink/kitchen-sink.stories.ts index fc6be00b0e0..08f4d875962 100644 --- a/libs/components/src/stories/kitchen-sink/kitchen-sink.stories.ts +++ b/libs/components/src/stories/kitchen-sink/kitchen-sink.stories.ts @@ -13,9 +13,11 @@ import { import { PasswordManagerLogo } from "@bitwarden/assets/svg"; import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.service"; +import { GlobalStateProvider } from "@bitwarden/state"; import { LayoutComponent } from "../../layout"; import { I18nMockService } from "../../utils/i18n-mock.service"; +import { StorybookGlobalStateProvider } from "../../utils/state-mock"; import { positionFixedWrapperDecorator } from "../storybook-decorators"; import { DialogVirtualScrollBlockComponent } from "./components/dialog-virtual-scroll-block.component"; @@ -65,9 +67,14 @@ export default { yes: "Yes", no: "No", loading: "Loading", + resizeSideNavigation: "Resize side navigation", }); }, }, + { + provide: GlobalStateProvider, + useClass: StorybookGlobalStateProvider, + }, ], }), ], diff --git a/libs/components/src/table/table.stories.ts b/libs/components/src/table/table.stories.ts index d696e6077dd..d20b5fd1cda 100644 --- a/libs/components/src/table/table.stories.ts +++ b/libs/components/src/table/table.stories.ts @@ -1,13 +1,14 @@ import { RouterTestingModule } from "@angular/router/testing"; -import { Meta, moduleMetadata, StoryObj } from "@storybook/angular"; +import { applicationConfig, Meta, moduleMetadata, StoryObj } from "@storybook/angular"; import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.service"; +import { GlobalStateProvider } from "@bitwarden/state"; import { countries } from "../form/countries"; import { LayoutComponent } from "../layout"; import { mockLayoutI18n } from "../layout/mocks"; import { positionFixedWrapperDecorator } from "../stories/storybook-decorators"; -import { I18nMockService } from "../utils"; +import { I18nMockService, StorybookGlobalStateProvider } from "../utils"; import { TableDataSource } from "./table-data-source"; import { TableModule } from "./table.module"; @@ -27,6 +28,14 @@ export default { }, ], }), + applicationConfig({ + providers: [ + { + provide: GlobalStateProvider, + useClass: StorybookGlobalStateProvider, + }, + ], + }), ], argTypes: { alignRowContent: { diff --git a/libs/components/src/tabs/tab-nav-bar/tab-link.component.html b/libs/components/src/tabs/tab-nav-bar/tab-link.component.html index f05ed31547b..aa36eb37f99 100644 --- a/libs/components/src/tabs/tab-nav-bar/tab-link.component.html +++ b/libs/components/src/tabs/tab-nav-bar/tab-link.component.html @@ -5,7 +5,7 @@ [routerLinkActiveOptions]="routerLinkMatchOptions" #rla="routerLinkActive" [active]="rla.isActive" - [info]="{ focusMainAfterNav: false }" + [state]="{ focusMainAfterNav: false }" [disabled]="disabled" [attr.aria-disabled]="disabled" ariaCurrentWhenActive="page" diff --git a/libs/components/src/tw-theme.css b/libs/components/src/tw-theme.css index f0e55ddd9e1..757859985d6 100644 --- a/libs/components/src/tw-theme.css +++ b/libs/components/src/tw-theme.css @@ -13,6 +13,12 @@ @tailwind utilities; :root { + /* ======================================== + * LEGACY COLORS (RGB format) + * These are the original colors used throughout the app. + * Use these for existing components until migration is complete. + * ======================================== */ + --color-transparent-hover: rgb(0 0 0 / 0.02); --color-shadow: 168 179 200; @@ -74,6 +80,279 @@ --color-illustration-bg-tertiary: 255 255 255; --color-illustration-tertiary: 255 191 0; --color-illustration-logo: 23 93 220; + + /* ======================================== + * NEW COLOR PALETTE (Hex format) + * These colors are from the new Figma design system. + * Use these for new components and features. + * Format: --color-{family}-{shade} where shade ranges from 050 to 950 + * ======================================== */ + + /* Brand Colors */ + --color-brand-050: #eef6ff; + --color-brand-100: #dbeafe; + --color-brand-200: #bedbff; + --color-brand-300: #8ec5ff; + --color-brand-400: #6baefa; + --color-brand-500: #418bfb; + --color-brand-600: #2a70f4; + --color-brand-700: #175ddc; + --color-brand-800: #0d43af; + --color-brand-900: #0c3276; + --color-brand-950: #162455; + + /* Gray Colors */ + --color-gray-050: #f9fafb; + --color-gray-100: #f3f4f6; + --color-gray-200: #e5e7eb; + --color-gray-300: #d1d5dc; + --color-gray-400: #99a1af; + --color-gray-500: #6a7282; + --color-gray-600: #4a5565; + --color-gray-700: #333e4f; + --color-gray-800: #1e2939; + --color-gray-900: #101828; + --color-gray-950: #070b18; + --color-gray-950-rgb: 7, 11, 24; + + /* Red Colors */ + --color-red-050: #fef2f2; + --color-red-100: #ffe2e2; + --color-red-200: #ffc9c9; + --color-red-300: #ffa2a2; + --color-red-400: #ff6467; + --color-red-500: #fb2c36; + --color-red-600: #e7000b; + --color-red-700: #c10007; + --color-red-800: #9f0712; + --color-red-900: #791112; + --color-red-950: #460809; + + /* Orange Colors */ + --color-orange-050: #fff8f1; + --color-orange-100: #feecdc; + --color-orange-200: #fcd9bd; + --color-orange-300: #fdba8c; + --color-orange-400: #ff8a4c; + --color-orange-500: #ff5a1f; + --color-orange-600: #d03801; + --color-orange-700: #b43403; + --color-orange-800: #8a2c0d; + --color-orange-900: #70240b; + --color-orange-950: #441306; + + /* Yellow Colors */ + --color-yellow-050: #fefce8; + --color-yellow-100: #fef9c2; + --color-yellow-200: #fff085; + --color-yellow-300: #ffdf20; + --color-yellow-400: #fdc700; + --color-yellow-500: #f0b100; + --color-yellow-600: #d08700; + --color-yellow-700: #a65f00; + --color-yellow-800: #894b00; + --color-yellow-900: #733e0a; + --color-yellow-950: #432004; + + /* Green Colors */ + --color-green-050: #f0fdf4; + --color-green-100: #dcfce7; + --color-green-200: #b9f8cf; + --color-green-300: #7bf1a8; + --color-green-400: #18dc7a; + --color-green-500: #0abf52; + --color-green-600: #00a63e; + --color-green-700: #008236; + --color-green-800: #016630; + --color-green-900: #0d542b; + --color-green-950: #032e15; + + /* Pink Colors */ + --color-pink-050: #fdf2f8; + --color-pink-100: #fce7f3; + --color-pink-200: #fccee8; + --color-pink-300: #fda5d5; + --color-pink-400: #fb64b6; + --color-pink-500: #f6339a; + --color-pink-600: #e60076; + --color-pink-700: #c6005c; + --color-pink-800: #a3004c; + --color-pink-900: #861043; + --color-pink-950: #510424; + + /* Coral Colors */ + --color-coral-050: #fff2f0; + --color-coral-100: #ffe0dc; + --color-coral-200: #ffc1b9; + --color-coral-300: #ff9585; + --color-coral-400: #ff6550; + --color-coral-500: #ff4026; + --color-coral-600: #e11f05; + --color-coral-700: #c71800; + --color-coral-800: #a81400; + --color-coral-900: #7e0f00; + --color-coral-950: #4d0900; + + /* Teal Colors */ + --color-teal-050: #ecfeff; + --color-teal-100: #cefafe; + --color-teal-200: #a2f4fd; + --color-teal-300: #70ecf5; + --color-teal-400: #2cdde9; + --color-teal-500: #00c5db; + --color-teal-600: #009cb8; + --color-teal-700: #007c95; + --color-teal-800: #006278; + --color-teal-900: #0f495c; + --color-teal-950: #042e3e; + + /* Purple Colors */ + --color-purple-050: #faf5ff; + --color-purple-100: #f3e8ff; + --color-purple-200: #e9d4ff; + --color-purple-300: #dab2ff; + --color-purple-400: #c27aff; + --color-purple-500: #ad46ff; + --color-purple-600: #9810fa; + --color-purple-700: #8200db; + --color-purple-800: #6e11b0; + --color-purple-900: #59168b; + --color-purple-950: #3c0366; + + /* White and Black */ + --color-white: #ffffff; + --color-white-rgb: 255, 255, 255; + --color-black: #000000; + + /* ======================================== + * SEMANTIC FOREGROUND COLORS (Light Mode) + * These are the tokens that should be exposed to Tailwind + * They reference the primitive colors above + * ======================================== */ + + /* Neutral Foreground */ + --color-fg-white: var(--color-white); + --color-fg-dark: var(--color-gray-900); + --color-fg-contrast: var(--color-white); + --color-fg-heading: var(--color-gray-900); + --color-fg-body: var(--color-gray-600); + --color-fg-body-subtle: var(--color-gray-500); + --color-fg-disabled: var(--color-gray-400); + + /* Brand Foreground */ + --color-fg-brand-soft: var(--color-brand-200); + --color-fg-brand: var(--color-brand-700); + --color-fg-brand-strong: var(--color-brand-900); + + /* Status Foreground */ + --color-fg-success: var(--color-green-700); + --color-fg-success-strong: var(--color-green-900); + --color-fg-danger: var(--color-red-700); + --color-fg-danger-strong: var(--color-red-900); + --color-fg-warning: var(--color-orange-600); + --color-fg-warning-strong: var(--color-orange-900); + --color-fg-sensitive: var(--color-pink-600); + + /* Accent Foreground */ + --color-fg-accent-primary-soft: var(--color-teal-200); + --color-fg-accent-primary: var(--color-teal-400); + --color-fg-accent-primary-strong: var(--color-teal-800); + --color-fg-accent-secondary-soft: var(--color-coral-200); + --color-fg-accent-secondary: var(--color-coral-400); + --color-fg-accent-secondary-strong: var(--color-coral-900); + --color-fg-accent-tertiary-soft: var(--color-purple-200); + --color-fg-accent-tertiary: var(--color-purple-700); + --color-fg-accent-tertiary-strong: var(--color-purple-900); + + /* ======================================== + * SEMANTIC BACKGROUND COLORS (Light Mode) + * ======================================== */ + + /* Neutral Background */ + --color-bg-white: var(--color-white); + --color-bg-dark: var(--color-gray-800); + --color-bg-contrast: var(--color-gray-800); + --color-bg-contrast-strong: var(--color-gray-950); + --color-bg-primary: var(--color-white); + --color-bg-secondary: var(--color-gray-050); + --color-bg-tertiary: var(--color-gray-050); + --color-bg-quaternary: var(--color-gray-200); + --color-bg-gray: var(--color-gray-300); + --color-bg-disabled: var(--color-gray-100); + + /* Brand Background */ + --color-bg-brand-softer: var(--color-brand-050); + --color-bg-brand-soft: var(--color-brand-100); + --color-bg-brand-medium: var(--color-brand-200); + --color-bg-brand: var(--color-brand-700); + --color-bg-brand-strong: var(--color-brand-800); + + /* Status Background */ + --color-bg-success-soft: var(--color-green-050); + --color-bg-success-medium: var(--color-green-100); + --color-bg-success: var(--color-green-700); + --color-bg-success-strong: var(--color-green-800); + --color-bg-danger-soft: var(--color-red-050); + --color-bg-danger-medium: var(--color-red-100); + --color-bg-danger: var(--color-red-700); + --color-bg-danger-strong: var(--color-red-800); + --color-bg-warning-soft: var(--color-orange-050); + --color-bg-warning-medium: var(--color-orange-100); + --color-bg-warning: var(--color-orange-600); + --color-bg-warning-strong: var(--color-orange-700); + + /* Accent Background */ + --color-bg-accent-primary-soft: var(--color-teal-050); + --color-bg-accent-primary-medium: var(--color-teal-100); + --color-bg-accent-primary: var(--color-teal-400); + --color-bg-accent-secondary-soft: var(--color-coral-050); + --color-bg-accent-secondary-medium: var(--color-coral-100); + --color-bg-accent-secondary: var(--color-coral-400); + --color-bg-accent-tertiary-soft: var(--color-purple-050); + --color-bg-accent-tertiary-medium: var(--color-purple-100); + --color-bg-accent-tertiary: var(--color-purple-600); + + /* Hover & Overlay */ + --color-bg-hover: rgba(var(--color-gray-950-rgb), 0.05); + --color-bg-overlay: rgba(var(--color-gray-950-rgb), 0.3); + + /* ======================================== + * SEMANTIC BORDER COLORS (Light Mode) + * ======================================== */ + + /* Neutral Border */ + --color-border-muted: var(--color-gray-050); + --color-border-light: var(--color-gray-100); + --color-border-base: var(--color-gray-200); + --color-border-strong: var(--color-gray-800); + --color-border-buffer: var(--color-white); + + /* Brand Border */ + --color-border-brand-soft: var(--color-brand-200); + --color-border-brand: var(--color-brand-700); + --color-border-brand-strong: var(--color-brand-900); + + /* Status Border */ + --color-border-success-soft: var(--color-green-200); + --color-border-success: var(--color-green-700); + --color-border-success-strong: var(--color-green-900); + --color-border-danger-soft: var(--color-red-200); + --color-border-danger: var(--color-red-700); + --color-border-danger-strong: var(--color-red-900); + --color-border-warning-soft: var(--color-orange-200); + --color-border-warning: var(--color-orange-600); + --color-border-warning-strong: var(--color-orange-900); + + /* Accent Border */ + --color-border-accent-primary-soft: var(--color-teal-200); + --color-border-accent-primary: var(--color-teal-600); + --color-border-accent-secondary-soft: var(--color-coral-200); + --color-border-accent-secondary: var(--color-coral-600); + --color-border-accent-tertiary-soft: var(--color-purple-200); + --color-border-accent-tertiary: var(--color-purple-600); + + /* Focus Border */ + --color-border-focus: var(--color-black); } .theme_light { @@ -140,6 +419,129 @@ --color-illustration-bg-tertiary: 243 246 249; --color-illustration-tertiary: 255 191 0; --color-illustration-logo: 255 255 255; + + /* ======================================== + * SEMANTIC FOREGROUND COLORS (Dark Mode Overrides) + * ======================================== */ + + /* Neutral Foreground */ + --color-fg-contrast: var(--color-gray-900); + --color-fg-heading: var(--color-gray-050); + --color-fg-body: var(--color-gray-200); + --color-fg-body-subtle: var(--color-gray-400); + --color-fg-disabled: var(--color-gray-600); + + /* Brand Foreground */ + --color-fg-brand-soft: var(--color-brand-500); + --color-fg-brand: var(--color-brand-400); + --color-fg-brand-strong: var(--color-brand-200); + + /* Status Foreground */ + --color-fg-success: var(--color-green-400); + --color-fg-success-strong: var(--color-green-100); + --color-fg-danger: var(--color-red-400); + --color-fg-danger-strong: var(--color-red-100); + --color-fg-warning: var(--color-orange-400); + --color-fg-warning-strong: var(--color-orange-100); + --color-fg-sensitive: var(--color-pink-300); + + /* Accent Foreground */ + --color-fg-accent-primary-soft: var(--color-teal-400); + --color-fg-accent-primary: var(--color-teal-300); + --color-fg-accent-primary-strong: var(--color-teal-100); + --color-fg-accent-secondary-soft: var(--color-coral-500); + --color-fg-accent-secondary: var(--color-coral-400); + --color-fg-accent-secondary-strong: var(--color-coral-100); + --color-fg-accent-tertiary-soft: var(--color-purple-500); + --color-fg-accent-tertiary: var(--color-purple-400); + --color-fg-accent-tertiary-strong: var(--color-purple-100); + + /* ======================================== + * SEMANTIC BACKGROUND COLORS (Dark Mode Overrides) + * ======================================== */ + + /* Neutral Background */ + --color-bg-contrast: var(--color-gray-050); + --color-bg-contrast-strong: var(--color-gray-050); + --color-bg-primary: var(--color-gray-900); + --color-bg-secondary: var(--color-gray-800); + --color-bg-tertiary: var(--color-gray-950); + --color-bg-quaternary: var(--color-gray-700); + --color-bg-gray: var(--color-gray-600); + --color-bg-disabled: var(--color-gray-950); + + /* Brand Background */ + --color-bg-brand-softer: var(--color-brand-950); + --color-bg-brand-soft: var(--color-brand-900); + --color-bg-brand-medium: var(--color-brand-800); + --color-bg-brand: var(--color-brand-400); + --color-bg-brand-strong: var(--color-brand-300); + + /* Status Background */ + --color-bg-success-soft: var(--color-green-950); + --color-bg-success-medium: var(--color-green-900); + --color-bg-success: var(--color-green-400); + --color-bg-success-strong: var(--color-green-300); + --color-bg-danger-soft: var(--color-red-950); + --color-bg-danger-medium: var(--color-red-900); + --color-bg-danger: var(--color-red-400); + --color-bg-danger-strong: var(--color-red-300); + --color-bg-warning-soft: var(--color-orange-950); + --color-bg-warning-medium: var(--color-orange-900); + --color-bg-warning: var(--color-orange-400); + --color-bg-warning-strong: var(--color-orange-300); + + /* Accent Background */ + --color-bg-accent-primary-soft: var(--color-teal-950); + --color-bg-accent-primary-medium: var(--color-teal-900); + --color-bg-accent-primary: var(--color-teal-400); + --color-bg-accent-secondary-soft: var(--color-coral-950); + --color-bg-accent-secondary-medium: var(--color-coral-900); + --color-bg-accent-secondary: var(--color-coral-400); + --color-bg-accent-tertiary-soft: var(--color-purple-950); + --color-bg-accent-tertiary-medium: var(--color-purple-900); + --color-bg-accent-tertiary: var(--color-purple-600); + + /* Hover & Overlay */ + --color-bg-hover: rgba(var(--color-white-rgb), 0.05); + --color-bg-overlay: rgba(var(--color-gray-950-rgb), 0.85); + + /* ======================================== + * SEMANTIC BORDER COLORS (Dark Mode Overrides) + * ======================================== */ + + /* Neutral Border */ + --color-border-muted: var(--color-gray-900); + --color-border-light: var(--color-gray-800); + --color-border-base: var(--color-gray-700); + --color-border-strong: var(--color-gray-400); + --color-border-buffer: var(--color-gray-950); + + /* Brand Border */ + --color-border-brand-soft: var(--color-brand-800); + --color-border-brand: var(--color-brand-400); + --color-border-brand-strong: var(--color-brand-200); + + /* Status Border */ + --color-border-success-soft: var(--color-green-800); + --color-border-success: var(--color-green-400); + --color-border-success-strong: var(--color-green-200); + --color-border-danger-soft: var(--color-red-800); + --color-border-danger: var(--color-red-400); + --color-border-danger-strong: var(--color-red-200); + --color-border-warning-soft: var(--color-orange-800); + --color-border-warning: var(--color-orange-400); + --color-border-warning-strong: var(--color-orange-200); + + /* Accent Border */ + --color-border-accent-primary-soft: var(--color-teal-800); + --color-border-accent-secondary-soft: var(--color-coral-800); + --color-border-accent-secondary: var(--color-coral-500); + --color-border-accent-tertiary-soft: var(--color-purple-800); + --color-border-accent-tertiary: var(--color-purple-500); + + /* Focus Border */ + --color-border-focus: var(--color-white); } @layer components { diff --git a/libs/components/src/utils/index.ts b/libs/components/src/utils/index.ts index 5ac6c6c0da0..c66d7761862 100644 --- a/libs/components/src/utils/index.ts +++ b/libs/components/src/utils/index.ts @@ -2,3 +2,4 @@ export * from "./aria-disable-element"; export * from "./function-to-observable"; export * from "./has-scrollable-content"; export * from "./i18n-mock.service"; +export * from "./state-mock"; diff --git a/libs/components/src/utils/state-mock.ts b/libs/components/src/utils/state-mock.ts new file mode 100644 index 00000000000..d82705f4d3b --- /dev/null +++ b/libs/components/src/utils/state-mock.ts @@ -0,0 +1,48 @@ +import { BehaviorSubject, Observable } from "rxjs"; + +import { + GlobalState, + StateUpdateOptions, + GlobalStateProvider, + KeyDefinition, +} from "@bitwarden/state"; + +export class StorybookGlobalState implements GlobalState { + private _state$ = new BehaviorSubject(null); + + constructor(initialValue?: T | null) { + this._state$.next(initialValue ?? null); + } + + async update( + configureState: (state: T | null, dependency: TCombine) => T | null, + options?: Partial>, + ): Promise { + const currentState = this._state$.value; + const newState = configureState(currentState, null as TCombine); + this._state$.next(newState); + return newState; + } + + get state$(): Observable { + return this._state$.asObservable(); + } + + setValue(value: T | null): void { + this._state$.next(value); + } +} + +export class StorybookGlobalStateProvider implements GlobalStateProvider { + private states = new Map>(); + + get(keyDefinition: KeyDefinition): GlobalState { + const key = `${keyDefinition.fullName}_${keyDefinition.stateDefinition.defaultStorageLocation}`; + + if (!this.states.has(key)) { + this.states.set(key, new StorybookGlobalState()); + } + + return this.states.get(key)!; + } +} diff --git a/libs/components/tailwind.config.base.js b/libs/components/tailwind.config.base.js index e41cff16e48..bd88f5471ff 100644 --- a/libs/components/tailwind.config.base.js +++ b/libs/components/tailwind.config.base.js @@ -9,9 +9,9 @@ function rgba(color) { module.exports = { prefix: "tw-", content: [ - "./src/**/*.{html,ts}", + "./src/**/*.{html,ts,mdx}", "../../libs/assets/src/**/*.{html,ts}", - "../../libs/components/src/**/*.{html,ts}", + "../../libs/components/src/**/*.{html,ts,mdx}", "../../libs/key-management-ui/src/**/*.{html,ts}", "../../libs/auth/src/**/*.{html,ts}", ], @@ -78,6 +78,46 @@ module.exports = { alt3: rgba("--color-background-alt3"), alt4: rgba("--color-background-alt4"), }, + bg: { + white: "var(--color-bg-white)", + dark: "var(--color-bg-dark)", + contrast: "var(--color-bg-contrast)", + "contrast-strong": "var(--color-bg-contrast-strong)", + primary: "var(--color-bg-primary)", + secondary: "var(--color-bg-secondary)", + tertiary: "var(--color-bg-tertiary)", + quaternary: "var(--color-bg-quaternary)", + gray: "var(--color-bg-gray)", + disabled: "var(--color-bg-disabled)", + "brand-softer": "var(--color-bg-brand-softer)", + "brand-soft": "var(--color-bg-brand-soft)", + "brand-medium": "var(--color-bg-brand-medium)", + brand: "var(--color-bg-brand)", + "brand-strong": "var(--color-bg-brand-strong)", + "success-soft": "var(--color-bg-success-soft)", + "success-medium": "var(--color-bg-success-medium)", + success: "var(--color-bg-success)", + "success-strong": "var(--color-bg-success-strong)", + "danger-soft": "var(--color-bg-danger-soft)", + "danger-medium": "var(--color-bg-danger-medium)", + danger: "var(--color-bg-danger)", + "danger-strong": "var(--color-bg-danger-strong)", + "warning-soft": "var(--color-bg-warning-soft)", + "warning-medium": "var(--color-bg-warning-medium)", + warning: "var(--color-bg-warning)", + "warning-strong": "var(--color-bg-warning-strong)", + "accent-primary-soft": "var(--color-bg-accent-primary-soft)", + "accent-primary-medium": "var(--color-bg-accent-primary-medium)", + "accent-primary": "var(--color-bg-accent-primary)", + "accent-secondary-soft": "var(--color-bg-accent-secondary-soft)", + "accent-secondary-medium": "var(--color-bg-accent-secondary-medium)", + "accent-secondary": "var(--color-bg-accent-secondary)", + "accent-tertiary-soft": "var(--color-bg-accent-tertiary-soft)", + "accent-tertiary-medium": "var(--color-bg-accent-tertiary-medium)", + "accent-tertiary": "var(--color-bg-accent-tertiary)", + hover: "var(--color-bg-hover)", + overlay: "var(--color-bg-overlay)", + }, hover: { default: "var(--color-hover-default)", contrast: "var(--color-hover-contrast)", @@ -92,8 +132,62 @@ module.exports = { tertiary: rgba("--color-illustration-tertiary"), logo: rgba("--color-illustration-logo"), }, + fg: { + white: "var(--color-fg-white)", + dark: "var(--color-fg-dark)", + contrast: "var(--color-fg-contrast)", + heading: "var(--color-fg-heading)", + body: "var(--color-fg-body)", + "body-subtle": "var(--color-fg-body-subtle)", + disabled: "var(--color-fg-disabled)", + "brand-soft": "var(--color-fg-brand-soft)", + brand: "var(--color-fg-brand)", + "brand-strong": "var(--color-fg-brand-strong)", + success: "var(--color-fg-success)", + "success-strong": "var(--color-fg-success-strong)", + danger: "var(--color-fg-danger)", + "danger-strong": "var(--color-fg-danger-strong)", + warning: "var(--color-fg-warning)", + "warning-strong": "var(--color-fg-warning-strong)", + sensitive: "var(--color-fg-sensitive)", + "accent-primary-soft": "var(--color-fg-accent-primary-soft)", + "accent-primary": "var(--color-fg-accent-primary)", + "accent-primary-strong": "var(--color-fg-accent-primary-strong)", + "accent-secondary-soft": "var(--color-fg-accent-secondary-soft)", + "accent-secondary": "var(--color-fg-accent-secondary)", + "accent-secondary-strong": "var(--color-fg-accent-secondary-strong)", + "accent-tertiary-soft": "var(--color-fg-accent-tertiary-soft)", + "accent-tertiary": "var(--color-fg-accent-tertiary)", + "accent-tertiary-strong": "var(--color-fg-accent-tertiary-strong)", + }, + border: { + muted: "var(--color-border-muted)", + light: "var(--color-border-light)", + base: "var(--color-border-base)", + strong: "var(--color-border-strong)", + buffer: "var(--color-border-buffer)", + "brand-soft": "var(--color-border-brand-soft)", + brand: "var(--color-border-brand)", + "brand-strong": "var(--color-border-brand-strong)", + "success-soft": "var(--color-border-success-soft)", + success: "var(--color-border-success)", + "success-strong": "var(--color-border-success-strong)", + "danger-soft": "var(--color-border-danger-soft)", + danger: "var(--color-border-danger)", + "danger-strong": "var(--color-border-danger-strong)", + "warning-soft": "var(--color-border-warning-soft)", + warning: "var(--color-border-warning)", + "warning-strong": "var(--color-border-warning-strong)", + "accent-primary-soft": "var(--color-border-accent-primary-soft)", + "accent-primary": "var(--color-border-accent-primary)", + "accent-secondary-soft": "var(--color-border-accent-secondary-soft)", + "accent-secondary": "var(--color-border-accent-secondary)", + "accent-tertiary-soft": "var(--color-border-accent-tertiary-soft)", + "accent-tertiary": "var(--color-border-accent-tertiary)", + focus: "var(--color-border-focus)", + }, }, - textColor: { + textColor: () => ({ main: rgba("--color-text-main"), muted: rgba("--color-text-muted"), contrast: rgba("--color-text-contrast"), @@ -132,7 +226,62 @@ module.exports = { notification: { 600: rgba("--color-notification-600"), }, - }, + // New semantic fg tokens - manually flattened to generate tw-text-fg-* utilities + "fg-white": "var(--color-fg-white)", + "fg-dark": "var(--color-fg-dark)", + "fg-contrast": "var(--color-fg-contrast)", + "fg-heading": "var(--color-fg-heading)", + "fg-body": "var(--color-fg-body)", + "fg-body-subtle": "var(--color-fg-body-subtle)", + "fg-disabled": "var(--color-fg-disabled)", + "fg-brand-soft": "var(--color-fg-brand-soft)", + "fg-brand": "var(--color-fg-brand)", + "fg-brand-strong": "var(--color-fg-brand-strong)", + "fg-success": "var(--color-fg-success)", + "fg-success-strong": "var(--color-fg-success-strong)", + "fg-danger": "var(--color-fg-danger)", + "fg-danger-strong": "var(--color-fg-danger-strong)", + "fg-warning": "var(--color-fg-warning)", + "fg-warning-strong": "var(--color-fg-warning-strong)", + "fg-sensitive": "var(--color-fg-sensitive)", + "fg-accent-primary-soft": "var(--color-fg-accent-primary-soft)", + "fg-accent-primary": "var(--color-fg-accent-primary)", + "fg-accent-primary-strong": "var(--color-fg-accent-primary-strong)", + "fg-accent-secondary-soft": "var(--color-fg-accent-secondary-soft)", + "fg-accent-secondary": "var(--color-fg-accent-secondary)", + "fg-accent-secondary-strong": "var(--color-fg-accent-secondary-strong)", + "fg-accent-tertiary-soft": "var(--color-fg-accent-tertiary-soft)", + "fg-accent-tertiary": "var(--color-fg-accent-tertiary)", + "fg-accent-tertiary-strong": "var(--color-fg-accent-tertiary-strong)", + }), + borderColor: ({ theme }) => ({ + ...theme("colors"), + // New semantic border tokens - manually flattened to generate tw-border-border-* utilities + "border-muted": "var(--color-border-muted)", + "border-light": "var(--color-border-light)", + "border-base": "var(--color-border-base)", + "border-strong": "var(--color-border-strong)", + "border-buffer": "var(--color-border-buffer)", + "border-brand-soft": "var(--color-border-brand-soft)", + "border-brand": "var(--color-border-brand)", + "border-brand-strong": "var(--color-border-brand-strong)", + "border-success-soft": "var(--color-border-success-soft)", + "border-success": "var(--color-border-success)", + "border-success-strong": "var(--color-border-success-strong)", + "border-danger-soft": "var(--color-border-danger-soft)", + "border-danger": "var(--color-border-danger)", + "border-danger-strong": "var(--color-border-danger-strong)", + "border-warning-soft": "var(--color-border-warning-soft)", + "border-warning": "var(--color-border-warning)", + "border-warning-strong": "var(--color-border-warning-strong)", + "border-accent-primary-soft": "var(--color-border-accent-primary-soft)", + "border-accent-primary": "var(--color-border-accent-primary)", + "border-accent-secondary-soft": "var(--color-border-accent-secondary-soft)", + "border-accent-secondary": "var(--color-border-accent-secondary)", + "border-accent-tertiary-soft": "var(--color-border-accent-tertiary-soft)", + "border-accent-tertiary": "var(--color-border-accent-tertiary)", + "border-focus": "var(--color-border-focus)", + }), fontFamily: { sans: "var(--font-sans)", serif: "var(--font-serif)", diff --git a/libs/components/tailwind.config.js b/libs/components/tailwind.config.js index d8cef6596dc..0fa5b259bb6 100644 --- a/libs/components/tailwind.config.js +++ b/libs/components/tailwind.config.js @@ -11,11 +11,16 @@ config.content = [ "bitwarden_license/bit-web/src/**/*.{html,ts,mdx}", ".storybook/preview.tsx", ]; + +// Safelist is required for dynamic color classes in Storybook color documentation (colors.mdx). +// Tailwind's JIT compiler cannot detect dynamically constructed class names like `tw-bg-${name}`, +// so we must explicitly safelist these patterns to ensure all color utilities are generated. config.safelist = [ { pattern: /tw-bg-(.*)/, }, ]; + config.corePlugins.preflight = true; module.exports = config; diff --git a/libs/importer/src/importers/bitwarden/bitwarden-encrypted-json-importer.ts b/libs/importer/src/importers/bitwarden/bitwarden-encrypted-json-importer.ts new file mode 100644 index 00000000000..4771f47b4c9 --- /dev/null +++ b/libs/importer/src/importers/bitwarden/bitwarden-encrypted-json-importer.ts @@ -0,0 +1,201 @@ +// FIXME: Update this file to be type safe and remove this and next line +// @ts-strict-ignore +import { filter, firstValueFrom } from "rxjs"; + +// This import has been flagged as unallowed for this class. It may be involved in a circular dependency loop. +// eslint-disable-next-line no-restricted-imports +import { Collection } from "@bitwarden/admin-console/common"; +import { AccountService } from "@bitwarden/common/auth/abstractions/account.service"; +import { EncryptService } from "@bitwarden/common/key-management/crypto/abstractions/encrypt.service"; +import { EncString } from "@bitwarden/common/key-management/crypto/models/enc-string"; +import { + CipherWithIdExport, + CollectionWithIdExport, + FolderWithIdExport, +} from "@bitwarden/common/models/export"; +import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.service"; +import { OrgKey, UserKey } from "@bitwarden/common/types/key"; +import { CipherService } from "@bitwarden/common/vault/abstractions/cipher.service"; +import { FolderView } from "@bitwarden/common/vault/models/view/folder.view"; +import { KeyService } from "@bitwarden/key-management"; +import { UserId } from "@bitwarden/user-core"; +import { + BitwardenEncryptedIndividualJsonExport, + BitwardenEncryptedJsonExport, + BitwardenEncryptedOrgJsonExport, + BitwardenJsonExport, + BitwardenPasswordProtectedFileFormat, + isOrgEncrypted, + isPasswordProtected, + isUnencrypted, +} from "@bitwarden/vault-export-core"; + +import { ImportResult } from "../../models/import-result"; +import { Importer } from "../importer"; + +import { BitwardenJsonImporter } from "./bitwarden-json-importer"; + +export class BitwardenEncryptedJsonImporter extends BitwardenJsonImporter implements Importer { + constructor( + protected keyService: KeyService, + protected encryptService: EncryptService, + protected i18nService: I18nService, + private cipherService: CipherService, + private accountService: AccountService, + ) { + super(); + } + + async parse(data: string): Promise { + const results: BitwardenPasswordProtectedFileFormat | BitwardenJsonExport = JSON.parse(data); + + if (isPasswordProtected(results)) { + throw new Error( + "Data is password-protected. Use BitwardenPasswordProtectedImporter instead.", + ); + } + + if (results == null || results.items == null) { + const result = new ImportResult(); + result.success = false; + return result; + } + + if (isUnencrypted(results)) { + return super.parse(data); + } + + return await this.parseEncrypted(results); + } + + private async parseEncrypted(data: BitwardenEncryptedJsonExport): Promise { + const result = new ImportResult(); + const account = await firstValueFrom(this.accountService.activeAccount$); + + if (this.isNullOrWhitespace(data.encKeyValidation_DO_NOT_EDIT)) { + result.success = false; + result.errorMessage = this.i18nService.t("importEncKeyError"); + return result; + } + + const orgKeys = await firstValueFrom(this.keyService.orgKeys$(account.id)); + let keyForDecryption: OrgKey | UserKey | null | undefined = orgKeys?.[this.organizationId]; + if (!keyForDecryption) { + keyForDecryption = await firstValueFrom(this.keyService.userKey$(account.id)); + } + + if (!keyForDecryption) { + result.success = false; + result.errorMessage = this.i18nService.t("importEncKeyError"); + return result; + } + const encKeyValidation = new EncString(data.encKeyValidation_DO_NOT_EDIT); + try { + await this.encryptService.decryptString(encKeyValidation, keyForDecryption); + } catch { + result.success = false; + result.errorMessage = this.i18nService.t("importEncKeyError"); + return result; + } + + let groupingsMap: Map | null = null; + if (isOrgEncrypted(data)) { + groupingsMap = await this.parseEncryptedCollections(account.id, data, result); + } else { + groupingsMap = await this.parseEncryptedFolders(account.id, data, result); + } + + for (const c of data.items) { + const cipher = CipherWithIdExport.toDomain(c); + // reset ids in case they were set for some reason + cipher.id = null; + cipher.organizationId = this.organizationId; + cipher.collectionIds = null; + + // make sure password history is limited + if (cipher.passwordHistory != null && cipher.passwordHistory.length > 5) { + cipher.passwordHistory = cipher.passwordHistory.slice(0, 5); + } + + if (!this.organization && c.folderId != null && groupingsMap.has(c.folderId)) { + result.folderRelationships.push([result.ciphers.length, groupingsMap.get(c.folderId)]); + } else if (this.organization && c.collectionIds != null) { + c.collectionIds.forEach((cId) => { + if (groupingsMap.has(cId)) { + result.collectionRelationships.push([result.ciphers.length, groupingsMap.get(cId)]); + } + }); + } + + const view = await this.cipherService.decrypt(cipher, account.id); + this.cleanupCipher(view); + result.ciphers.push(view); + } + + result.success = true; + return result; + } + + private async parseEncryptedFolders( + userId: UserId, + data: BitwardenEncryptedIndividualJsonExport, + importResult: ImportResult, + ): Promise> { + const groupingsMap = new Map(); + + if (data.folders == null) { + return groupingsMap; + } + + const userKey = await firstValueFrom(this.keyService.userKey$(userId)); + + for (const f of data.folders) { + let folderView: FolderView; + const folder = FolderWithIdExport.toDomain(f); + if (folder != null) { + folderView = await folder.decrypt(userKey); + } + + if (folderView != null) { + groupingsMap.set(f.id, importResult.folders.length); + importResult.folders.push(folderView); + } + } + return groupingsMap; + } + + private async parseEncryptedCollections( + userId: UserId, + data: BitwardenEncryptedOrgJsonExport, + importResult: ImportResult, + ): Promise> { + const groupingsMap = new Map(); + if (data.collections == null) { + return groupingsMap; + } + + const orgKeys = await firstValueFrom( + this.keyService.orgKeys$(userId).pipe(filter((orgKeys) => orgKeys != null)), + ); + + for (const c of data.collections) { + const collection = CollectionWithIdExport.toDomain( + c, + new Collection({ + id: c.id, + name: new EncString(c.name), + organizationId: this.organizationId, + }), + ); + + const orgKey = orgKeys[c.organizationId]; + const collectionView = await collection.decrypt(orgKey, this.encryptService); + + if (collectionView != null) { + groupingsMap.set(c.id, importResult.collections.length); + importResult.collections.push(collectionView); + } + } + return groupingsMap; + } +} diff --git a/libs/importer/src/importers/bitwarden/bitwarden-json-importer.ts b/libs/importer/src/importers/bitwarden/bitwarden-json-importer.ts index 1f5be7f18ab..ddeba885f88 100644 --- a/libs/importer/src/importers/bitwarden/bitwarden-json-importer.ts +++ b/libs/importer/src/importers/bitwarden/bitwarden-json-importer.ts @@ -1,30 +1,17 @@ // FIXME: Update this file to be type safe and remove this and next line // @ts-strict-ignore -import { filter, firstValueFrom } from "rxjs"; - -// This import has been flagged as unallowed for this class. It may be involved in a circular dependency loop. -// eslint-disable-next-line no-restricted-imports -import { Collection, CollectionView } from "@bitwarden/admin-console/common"; -import { AccountService } from "@bitwarden/common/auth/abstractions/account.service"; -import { EncryptService } from "@bitwarden/common/key-management/crypto/abstractions/encrypt.service"; -import { EncString } from "@bitwarden/common/key-management/crypto/models/enc-string"; import { CipherWithIdExport, CollectionWithIdExport, FolderWithIdExport, } from "@bitwarden/common/models/export"; -import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.service"; -import { SymmetricCryptoKey } from "@bitwarden/common/platform/models/domain/symmetric-crypto-key"; -import { UserId } from "@bitwarden/common/types/guid"; -import { CipherService } from "@bitwarden/common/vault/abstractions/cipher.service"; -import { FolderView } from "@bitwarden/common/vault/models/view/folder.view"; -import { KeyService } from "@bitwarden/key-management"; import { - BitwardenEncryptedIndividualJsonExport, - BitwardenEncryptedOrgJsonExport, BitwardenJsonExport, BitwardenUnEncryptedIndividualJsonExport, + BitwardenUnEncryptedJsonExport, BitwardenUnEncryptedOrgJsonExport, + isOrgUnEncrypted, + isUnencrypted, } from "@bitwarden/vault-export-core"; import { ImportResult } from "../../models/import-result"; @@ -32,103 +19,30 @@ import { BaseImporter } from "../base-importer"; import { Importer } from "../importer"; export class BitwardenJsonImporter extends BaseImporter implements Importer { - private result: ImportResult; - - protected constructor( - protected keyService: KeyService, - protected encryptService: EncryptService, - protected i18nService: I18nService, - protected cipherService: CipherService, - protected accountService: AccountService, - ) { + protected constructor() { super(); } async parse(data: string): Promise { - const account = await firstValueFrom(this.accountService.activeAccount$); - this.result = new ImportResult(); const results: BitwardenJsonExport = JSON.parse(data); if (results == null || results.items == null) { - this.result.success = false; - return this.result; + const result = new ImportResult(); + result.success = false; + return result; } - if (results.encrypted) { - await this.parseEncrypted(results as any, account.id); - } else { - await this.parseDecrypted(results as any, account.id); + if (!isUnencrypted(results)) { + throw new Error("Data is encrypted. Use BitwardenEncryptedJsonImporter instead."); } - - return this.result; + return await this.parseDecrypted(results); } - private async parseEncrypted( - results: BitwardenEncryptedIndividualJsonExport | BitwardenEncryptedOrgJsonExport, - userId: UserId, - ) { - if (results.encKeyValidation_DO_NOT_EDIT != null) { - const orgKeys = await firstValueFrom(this.keyService.orgKeys$(userId)); - let keyForDecryption: SymmetricCryptoKey = orgKeys?.[this.organizationId]; - if (keyForDecryption == null) { - keyForDecryption = await firstValueFrom(this.keyService.userKey$(userId)); - } - const encKeyValidation = new EncString(results.encKeyValidation_DO_NOT_EDIT); - try { - await this.encryptService.decryptString(encKeyValidation, keyForDecryption); - } catch { - this.result.success = false; - this.result.errorMessage = this.i18nService.t("importEncKeyError"); - return; - } - } + private async parseDecrypted(results: BitwardenUnEncryptedJsonExport): Promise { + const importResult = new ImportResult(); - const groupingsMap = this.organization - ? await this.parseCollections(results as BitwardenEncryptedOrgJsonExport, userId) - : await this.parseFolders(results as BitwardenEncryptedIndividualJsonExport, userId); - - for (const c of results.items) { - const cipher = CipherWithIdExport.toDomain(c); - // reset ids in case they were set for some reason - cipher.id = null; - cipher.organizationId = this.organizationId; - cipher.collectionIds = null; - - // make sure password history is limited - if (cipher.passwordHistory != null && cipher.passwordHistory.length > 5) { - cipher.passwordHistory = cipher.passwordHistory.slice(0, 5); - } - - if (!this.organization && c.folderId != null && groupingsMap.has(c.folderId)) { - this.result.folderRelationships.push([ - this.result.ciphers.length, - groupingsMap.get(c.folderId), - ]); - } else if (this.organization && c.collectionIds != null) { - c.collectionIds.forEach((cId) => { - if (groupingsMap.has(cId)) { - this.result.collectionRelationships.push([ - this.result.ciphers.length, - groupingsMap.get(cId), - ]); - } - }); - } - - const view = await this.cipherService.decrypt(cipher, userId); - this.cleanupCipher(view); - this.result.ciphers.push(view); - } - - this.result.success = true; - } - - private async parseDecrypted( - results: BitwardenUnEncryptedIndividualJsonExport | BitwardenUnEncryptedOrgJsonExport, - userId: UserId, - ) { - const groupingsMap = this.organization - ? await this.parseCollections(results as BitwardenUnEncryptedOrgJsonExport, userId) - : await this.parseFolders(results as BitwardenUnEncryptedIndividualJsonExport, userId); + const groupingsMap = isOrgUnEncrypted(results) + ? await this.parseCollections(results, importResult) + : await this.parseFolders(results, importResult); results.items.forEach((c) => { const cipher = CipherWithIdExport.toView(c); @@ -143,15 +57,15 @@ export class BitwardenJsonImporter extends BaseImporter implements Importer { } if (!this.organization && c.folderId != null && groupingsMap.has(c.folderId)) { - this.result.folderRelationships.push([ - this.result.ciphers.length, + importResult.folderRelationships.push([ + importResult.ciphers.length, groupingsMap.get(c.folderId), ]); } else if (this.organization && c.collectionIds != null) { c.collectionIds.forEach((cId) => { if (groupingsMap.has(cId)) { - this.result.collectionRelationships.push([ - this.result.ciphers.length, + importResult.collectionRelationships.push([ + importResult.ciphers.length, groupingsMap.get(cId), ]); } @@ -159,79 +73,48 @@ export class BitwardenJsonImporter extends BaseImporter implements Importer { } this.cleanupCipher(cipher); - this.result.ciphers.push(cipher); + importResult.ciphers.push(cipher); }); - this.result.success = true; + importResult.success = true; + return importResult; } private async parseFolders( - data: BitwardenUnEncryptedIndividualJsonExport | BitwardenEncryptedIndividualJsonExport, - userId: UserId, - ): Promise> | null { + data: BitwardenUnEncryptedIndividualJsonExport, + importResult: ImportResult, + ): Promise> { + const groupingsMap = new Map(); if (data.folders == null) { - return null; + return groupingsMap; } - const userKey = await firstValueFrom(this.keyService.userKey$(userId)); - - const groupingsMap = new Map(); - for (const f of data.folders) { - let folderView: FolderView; - if (data.encrypted) { - const folder = FolderWithIdExport.toDomain(f); - if (folder != null) { - folderView = await folder.decrypt(userKey); - } - } else { - folderView = FolderWithIdExport.toView(f); - } - + const folderView = FolderWithIdExport.toView(f); if (folderView != null) { - groupingsMap.set(f.id, this.result.folders.length); - this.result.folders.push(folderView); + groupingsMap.set(f.id, importResult.folders.length); + importResult.folders.push(folderView); } } return groupingsMap; } private async parseCollections( - data: BitwardenUnEncryptedOrgJsonExport | BitwardenEncryptedOrgJsonExport, - userId: UserId, - ): Promise> | null { + data: BitwardenUnEncryptedOrgJsonExport, + importResult: ImportResult, + ): Promise> { + const groupingsMap = new Map(); if (data.collections == null) { - return null; + return groupingsMap; } - const orgKeys = await firstValueFrom( - this.keyService.orgKeys$(userId).pipe(filter((orgKeys) => orgKeys != null)), - ); - - const groupingsMap = new Map(); - for (const c of data.collections) { - let collectionView: CollectionView; - if (data.encrypted) { - const collection = CollectionWithIdExport.toDomain( - c, - new Collection({ - id: c.id, - name: new EncString(c.name), - organizationId: this.organizationId, - }), - ); - - const orgKey = orgKeys[c.organizationId]; - collectionView = await collection.decrypt(orgKey, this.encryptService); - } else { - collectionView = CollectionWithIdExport.toView(c); - collectionView.organizationId = null; - } + const collectionView = CollectionWithIdExport.toView(c); + collectionView.organizationId = null; if (collectionView != null) { - groupingsMap.set(c.id, this.result.collections.length); - this.result.collections.push(collectionView); + groupingsMap.set(c.id, importResult.collections.length); + importResult.collections.push(collectionView); } } return groupingsMap; diff --git a/libs/importer/src/importers/bitwarden/bitwarden-password-protected-importer.spec.ts b/libs/importer/src/importers/bitwarden/bitwarden-password-protected-importer.spec.ts index fdf92cac751..ff6e3692640 100644 --- a/libs/importer/src/importers/bitwarden/bitwarden-password-protected-importer.spec.ts +++ b/libs/importer/src/importers/bitwarden/bitwarden-password-protected-importer.spec.ts @@ -16,6 +16,7 @@ import { UserId } from "@bitwarden/user-core"; import { emptyAccountEncrypted } from "../spec-data/bitwarden-json/account-encrypted.json"; import { emptyUnencryptedExport } from "../spec-data/bitwarden-json/unencrypted.json"; +import { BitwardenEncryptedJsonImporter } from "./bitwarden-encrypted-json-importer"; import { BitwardenJsonImporter } from "./bitwarden-json-importer"; import { BitwardenPasswordProtectedImporter } from "./bitwarden-password-protected-importer"; @@ -92,7 +93,7 @@ describe("BitwardenPasswordProtectedImporter", () => { describe("Account encrypted", () => { beforeAll(() => { - jest.spyOn(BitwardenJsonImporter.prototype, "parse"); + jest.spyOn(BitwardenEncryptedJsonImporter.prototype, "parse"); }); beforeEach(() => { @@ -114,9 +115,11 @@ describe("BitwardenPasswordProtectedImporter", () => { ); }); - it("Should call BitwardenJsonImporter", async () => { - expect((await importer.parse(emptyAccountEncrypted)).success).toEqual(true); - expect(BitwardenJsonImporter.prototype.parse).toHaveBeenCalledWith(emptyAccountEncrypted); + it("Should call BitwardenEncryptedJsonImporter", async () => { + expect((await importer.parse(emptyAccountEncrypted)).success).toEqual(false); + expect(BitwardenEncryptedJsonImporter.prototype.parse).toHaveBeenCalledWith( + emptyAccountEncrypted, + ); }); }); diff --git a/libs/importer/src/importers/bitwarden/bitwarden-password-protected-importer.ts b/libs/importer/src/importers/bitwarden/bitwarden-password-protected-importer.ts index b685ddf0fb5..cc38c420d9b 100644 --- a/libs/importer/src/importers/bitwarden/bitwarden-password-protected-importer.ts +++ b/libs/importer/src/importers/bitwarden/bitwarden-password-protected-importer.ts @@ -14,14 +14,21 @@ import { KeyService, KdfType, } from "@bitwarden/key-management"; -import { BitwardenPasswordProtectedFileFormat } from "@bitwarden/vault-export-core"; +import { + BitwardenJsonExport, + BitwardenPasswordProtectedFileFormat, + isPasswordProtected, +} from "@bitwarden/vault-export-core"; import { ImportResult } from "../../models/import-result"; import { Importer } from "../importer"; -import { BitwardenJsonImporter } from "./bitwarden-json-importer"; +import { BitwardenEncryptedJsonImporter } from "./bitwarden-encrypted-json-importer"; -export class BitwardenPasswordProtectedImporter extends BitwardenJsonImporter implements Importer { +export class BitwardenPasswordProtectedImporter + extends BitwardenEncryptedJsonImporter + implements Importer +{ private key: SymmetricCryptoKey; constructor( @@ -38,20 +45,14 @@ export class BitwardenPasswordProtectedImporter extends BitwardenJsonImporter im async parse(data: string): Promise { const result = new ImportResult(); - const parsedData: BitwardenPasswordProtectedFileFormat = JSON.parse(data); + const parsedData: BitwardenPasswordProtectedFileFormat | BitwardenJsonExport = JSON.parse(data); if (!parsedData) { result.success = false; return result; } - // File is unencrypted - if (!parsedData?.encrypted) { - return await super.parse(data); - } - - // File is account-encrypted - if (!parsedData?.passwordProtected) { + if (!isPasswordProtected(parsedData)) { return await super.parse(data); } diff --git a/libs/state/src/core/state-definitions.ts b/libs/state/src/core/state-definitions.ts index 156c03620b7..445e5fecde7 100644 --- a/libs/state/src/core/state-definitions.ts +++ b/libs/state/src/core/state-definitions.ts @@ -103,6 +103,7 @@ export const AUTOTYPE_SETTINGS_DISK = new StateDefinition("autotypeSettings", "d export const NEW_WEB_LAYOUT_BANNER_DISK = new StateDefinition("newWebLayoutBanner", "disk", { web: "disk-local", }); +export const BIT_SIDE_NAV_DISK = new StateDefinition("bitSideNav", "disk"); // DIRT diff --git a/libs/tools/export/vault-export/vault-export-core/src/types/bitwarden-json-export-types.ts b/libs/tools/export/vault-export/vault-export-core/src/types/bitwarden-json-export-types.ts index ab2bcbb9f1f..fd33bf96923 100644 --- a/libs/tools/export/vault-export/vault-export-core/src/types/bitwarden-json-export-types.ts +++ b/libs/tools/export/vault-export/vault-export-core/src/types/bitwarden-json-export-types.ts @@ -5,42 +5,48 @@ import { } from "@bitwarden/common/models/export"; // Base -export type BitwardenJsonExport = { - encrypted: boolean; - items: CipherWithIdExport[]; -}; +export type BitwardenJsonExport = BitwardenUnEncryptedJsonExport | BitwardenEncryptedJsonExport; // Decrypted -export type BitwardenUnEncryptedJsonExport = BitwardenJsonExport & { - encrypted: false; -}; +export type BitwardenUnEncryptedJsonExport = + | BitwardenUnEncryptedIndividualJsonExport + | BitwardenUnEncryptedOrgJsonExport; -export type BitwardenUnEncryptedIndividualJsonExport = BitwardenUnEncryptedJsonExport & { +export type BitwardenUnEncryptedIndividualJsonExport = { + encrypted: false; + items: CipherWithIdExport[]; folders: FolderWithIdExport[]; }; -export type BitwardenUnEncryptedOrgJsonExport = BitwardenUnEncryptedJsonExport & { +export type BitwardenUnEncryptedOrgJsonExport = { + encrypted: false; + items: CipherWithIdExport[]; collections: CollectionWithIdExport[]; }; // Account-encrypted -export type BitwardenEncryptedJsonExport = BitwardenJsonExport & { +export type BitwardenEncryptedJsonExport = + | BitwardenEncryptedIndividualJsonExport + | BitwardenEncryptedOrgJsonExport; + +export type BitwardenEncryptedIndividualJsonExport = { encrypted: true; encKeyValidation_DO_NOT_EDIT: string; -}; - -export type BitwardenEncryptedIndividualJsonExport = BitwardenEncryptedJsonExport & { + items: CipherWithIdExport[]; folders: FolderWithIdExport[]; }; -export type BitwardenEncryptedOrgJsonExport = BitwardenEncryptedJsonExport & { +export type BitwardenEncryptedOrgJsonExport = { + encrypted: true; + encKeyValidation_DO_NOT_EDIT: string; + items: CipherWithIdExport[]; collections: CollectionWithIdExport[]; }; // Password-protected export type BitwardenPasswordProtectedFileFormat = { - encrypted: boolean; - passwordProtected: boolean; + encrypted: true; + passwordProtected: true; salt: string; kdfIterations: number; kdfMemory?: number; @@ -49,3 +55,50 @@ export type BitwardenPasswordProtectedFileFormat = { encKeyValidation_DO_NOT_EDIT: string; data: string; }; + +// Unencrypted type guards +export function isUnencrypted( + data: BitwardenJsonExport | null | undefined, +): data is BitwardenUnEncryptedJsonExport { + return data != null && (data as { encrypted?: unknown }).encrypted !== true; +} + +export function isIndividualUnEncrypted( + data: BitwardenJsonExport | null | undefined, +): data is BitwardenUnEncryptedIndividualJsonExport { + return isUnencrypted(data) && (data as { folders?: unknown }).folders != null; +} + +export function isOrgUnEncrypted( + data: BitwardenJsonExport | null | undefined, +): data is BitwardenUnEncryptedOrgJsonExport { + return isUnencrypted(data) && (data as { collections?: unknown }).collections != null; +} + +// Encrypted type guards +export function isEncrypted( + data: BitwardenJsonExport | null | undefined, +): data is BitwardenEncryptedJsonExport { + return data != null && (data as { encrypted?: unknown }).encrypted === true; +} +export function isPasswordProtected( + data: BitwardenPasswordProtectedFileFormat | BitwardenJsonExport | null | undefined, +): data is BitwardenPasswordProtectedFileFormat { + return ( + data != null && + (data as { encrypted?: unknown }).encrypted === true && + (data as { passwordProtected?: unknown }).passwordProtected === true + ); +} + +export function isIndividualEncrypted( + data: BitwardenJsonExport | null | undefined, +): data is BitwardenEncryptedIndividualJsonExport { + return isEncrypted(data) && (data as { folders?: unknown }).folders != null; +} + +export function isOrgEncrypted( + data: BitwardenJsonExport | null | undefined, +): data is BitwardenEncryptedOrgJsonExport { + return isEncrypted(data) && (data as { collections?: unknown }).collections != null; +} diff --git a/libs/tools/send/send-ui/src/send-form/components/options/send-options.component.spec.ts b/libs/tools/send/send-ui/src/send-form/components/options/send-options.component.spec.ts new file mode 100644 index 00000000000..6724bb324c3 --- /dev/null +++ b/libs/tools/send/send-ui/src/send-form/components/options/send-options.component.spec.ts @@ -0,0 +1,67 @@ +import { ComponentFixture, TestBed } from "@angular/core/testing"; +import { mock } from "jest-mock-extended"; +import { of } from "rxjs"; + +import { PolicyService } from "@bitwarden/common/admin-console/abstractions/policy/policy.service.abstraction"; +import { Account, AccountService } from "@bitwarden/common/auth/abstractions/account.service"; +import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.service"; +import { PlatformUtilsService } from "@bitwarden/common/platform/abstractions/platform-utils.service"; +import { SendType } from "@bitwarden/common/tools/send/enums/send-type"; +import { SendView } from "@bitwarden/common/tools/send/models/view/send.view"; +import { SendApiService } from "@bitwarden/common/tools/send/services/send-api.service.abstraction"; +import { DialogService, ToastService } from "@bitwarden/components"; +import { CredentialGeneratorService } from "@bitwarden/generator-core"; + +import { SendFormContainer } from "../../send-form-container"; + +import { SendOptionsComponent } from "./send-options.component"; + +describe("SendOptionsComponent", () => { + let component: SendOptionsComponent; + let fixture: ComponentFixture; + const mockSendFormContainer = mock(); + const mockAccountService = mock(); + + beforeAll(() => { + mockAccountService.activeAccount$ = of({ id: "myTestAccount" } as Account); + }); + + beforeEach(async () => { + await TestBed.configureTestingModule({ + imports: [SendOptionsComponent], + declarations: [], + providers: [ + { provide: SendFormContainer, useValue: mockSendFormContainer }, + { provide: DialogService, useValue: mock() }, + { provide: SendApiService, useValue: mock() }, + { provide: PolicyService, useValue: mock() }, + { provide: I18nService, useValue: mock() }, + { provide: ToastService, useValue: mock() }, + { provide: CredentialGeneratorService, useValue: mock() }, + { provide: AccountService, useValue: mockAccountService }, + { provide: PlatformUtilsService, useValue: mock() }, + ], + }).compileComponents(); + fixture = TestBed.createComponent(SendOptionsComponent); + component = fixture.componentInstance; + component.config = { areSendsAllowed: true, mode: "add", sendType: SendType.Text }; + fixture.detectChanges(); + }); + + afterEach(() => { + jest.restoreAllMocks(); + }); + + it("should create", () => { + expect(component).toBeTruthy(); + }); + + it("should emit a null password when password textbox is empty", async () => { + const newSend = {} as SendView; + mockSendFormContainer.patchSend.mockImplementation((updateFn) => updateFn(newSend)); + component.sendOptionsForm.patchValue({ password: "testing" }); + expect(newSend.password).toBe("testing"); + component.sendOptionsForm.patchValue({ password: "" }); + expect(newSend.password).toBe(null); + }); +}); diff --git a/libs/tools/send/send-ui/src/send-form/components/options/send-options.component.ts b/libs/tools/send/send-ui/src/send-form/components/options/send-options.component.ts index 2ddb10dc80b..ae8706a375e 100644 --- a/libs/tools/send/send-ui/src/send-form/components/options/send-options.component.ts +++ b/libs/tools/send/send-ui/src/send-form/components/options/send-options.component.ts @@ -4,7 +4,7 @@ import { CommonModule } from "@angular/common"; import { Component, Input, OnInit } from "@angular/core"; import { takeUntilDestroyed } from "@angular/core/rxjs-interop"; import { FormBuilder, ReactiveFormsModule } from "@angular/forms"; -import { BehaviorSubject, firstValueFrom, map, switchMap } from "rxjs"; +import { BehaviorSubject, firstValueFrom, map, switchMap, tap } from "rxjs"; import { JslibModule } from "@bitwarden/angular/jslib.module"; import { PolicyService } from "@bitwarden/common/admin-console/abstractions/policy/policy.service.abstraction"; @@ -12,6 +12,7 @@ import { PolicyType } from "@bitwarden/common/admin-console/enums"; import { AccountService } from "@bitwarden/common/auth/abstractions/account.service"; import { getUserId } from "@bitwarden/common/auth/services/account.service"; import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.service"; +import { Utils } from "@bitwarden/common/platform/misc/utils"; import { pin } from "@bitwarden/common/tools/rx"; import { SendView } from "@bitwarden/common/tools/send/models/view/send.view"; import { SendApiService } from "@bitwarden/common/tools/send/services/send-api.service.abstraction"; @@ -112,18 +113,27 @@ export class SendOptionsComponent implements OnInit { this.disableHideEmail = disableHideEmail; }); - this.sendOptionsForm.valueChanges.pipe(takeUntilDestroyed()).subscribe((value) => { - this.sendFormContainer.patchSend((send) => { - Object.assign(send, { - maxAccessCount: value.maxAccessCount, - accessCount: value.accessCount, - password: value.password, - hideEmail: value.hideEmail, - notes: value.notes, + this.sendOptionsForm.valueChanges + .pipe( + tap((value) => { + if (Utils.isNullOrWhitespace(value.password)) { + value.password = null; + } + }), + takeUntilDestroyed(), + ) + .subscribe((value) => { + this.sendFormContainer.patchSend((send) => { + Object.assign(send, { + maxAccessCount: value.maxAccessCount, + accessCount: value.accessCount, + password: value.password, + hideEmail: value.hideEmail, + notes: value.notes, + }); + return send; }); - return send; }); - }); } generatePassword = async () => { diff --git a/libs/tools/send/send-ui/src/send-form/components/send-form.component.ts b/libs/tools/send/send-ui/src/send-form/components/send-form.component.ts index fcd3b0cb7ea..0471ed90eef 100644 --- a/libs/tools/send/send-ui/src/send-form/components/send-form.component.ts +++ b/libs/tools/send/send-ui/src/send-form/components/send-form.component.ts @@ -18,7 +18,6 @@ import { takeUntilDestroyed } from "@angular/core/rxjs-interop"; import { FormBuilder, ReactiveFormsModule } from "@angular/forms"; import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.service"; -import { Utils } from "@bitwarden/common/platform/misc/utils"; import { SendType } from "@bitwarden/common/tools/send/enums/send-type"; import { SendView } from "@bitwarden/common/tools/send/models/view/send.view"; import { @@ -227,10 +226,6 @@ export class SendFormComponent implements AfterViewInit, OnInit, OnChanges, Send return; } - if (Utils.isNullOrWhitespace(this.updatedSendView.password)) { - this.updatedSendView.password = null; - } - this.toastService.showToast({ variant: "success", title: null, diff --git a/package-lock.json b/package-lock.json index c24e8cc45a3..e2556015113 100644 --- a/package-lock.json +++ b/package-lock.json @@ -23,8 +23,8 @@ "@angular/platform-browser": "20.3.15", "@angular/platform-browser-dynamic": "20.3.15", "@angular/router": "20.3.15", - "@bitwarden/commercial-sdk-internal": "0.2.0-main.433", - "@bitwarden/sdk-internal": "0.2.0-main.433", + "@bitwarden/commercial-sdk-internal": "0.2.0-main.450", + "@bitwarden/sdk-internal": "0.2.0-main.450", "@electron/fuses": "1.8.0", "@emotion/css": "11.13.5", "@koa/multer": "4.0.0", @@ -32,11 +32,6 @@ "@microsoft/signalr": "8.0.7", "@microsoft/signalr-protocol-msgpack": "8.0.7", "@ng-select/ng-select": "20.7.0", - "@nx/devkit": "21.6.10", - "@nx/eslint": "21.6.10", - "@nx/jest": "21.6.10", - "@nx/js": "21.6.10", - "@nx/webpack": "21.6.10", "big-integer": "1.6.52", "braintree-web-drop-in": "1.46.0", "buffer": "6.0.3", @@ -88,6 +83,11 @@ "@eslint/compat": "2.0.0", "@lit-labs/signals": "0.1.3", "@ngtools/webpack": "20.3.12", + "@nx/devkit": "21.6.10", + "@nx/eslint": "21.6.10", + "@nx/jest": "21.6.10", + "@nx/js": "21.6.10", + "@nx/webpack": "21.6.10", "@storybook/addon-a11y": "9.1.16", "@storybook/addon-designs": "9.0.0-next.3", "@storybook/addon-docs": "9.1.16", @@ -192,11 +192,11 @@ }, "apps/browser": { "name": "@bitwarden/browser", - "version": "2025.12.0" + "version": "2025.12.1" }, "apps/cli": { "name": "@bitwarden/cli", - "version": "2025.12.0", + "version": "2025.12.1", "license": "SEE LICENSE IN LICENSE.txt", "dependencies": { "@koa/multer": "4.0.0", @@ -491,7 +491,7 @@ }, "apps/web": { "name": "@bitwarden/web-vault", - "version": "2025.12.1" + "version": "2025.12.2" }, "libs/admin-console": { "name": "@bitwarden/admin-console", @@ -3006,6 +3006,7 @@ "version": "7.28.5", "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.28.5.tgz", "integrity": "sha512-6uFXyCayocRbqhZOB+6XcuZbkMNimwfVGFji8CTZnCzOHVGvDqzvitu1re2AU5LROliz7eQPhB8CpAMvnx9EjA==", + "dev": true, "license": "MIT", "engines": { "node": ">=6.9.0" @@ -3015,6 +3016,7 @@ "version": "7.28.5", "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.28.5.tgz", "integrity": "sha512-e7jT4DxYvIDLk1ZHmU/m/mB19rex9sv0c2ftBtjSBv+kVM/902eh0fINUzD7UwLLNR+jU585GxUJ8/EBfAM5fw==", + "dev": true, "license": "MIT", "dependencies": { "@babel/code-frame": "^7.27.1", @@ -3045,6 +3047,7 @@ "version": "7.28.5", "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.28.5.tgz", "integrity": "sha512-3EwLFhZ38J4VyIP6WNtt2kUdW9dokXA9Cr4IVIFHuCpZ3H8/YFOl5JjZHisrn1fATPBmKKqXzDFvh9fUwHz6CQ==", + "dev": true, "license": "MIT", "dependencies": { "@babel/parser": "^7.28.5", @@ -3061,12 +3064,14 @@ "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, "license": "MIT" }, "node_modules/@babel/core/node_modules/semver": { "version": "6.3.1", "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", + "dev": true, "license": "ISC", "bin": { "semver": "bin/semver.js" @@ -3076,6 +3081,7 @@ "version": "7.28.3", "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.28.3.tgz", "integrity": "sha512-3lSpxGgvnmZznmBkCRnVREPUFJv2wrv9iAoFDvADJc0ypmdOxdUtcLeBgBJ6zE0PMeTKnxeQzyk0xTBq4Ep7zw==", + "dev": true, "license": "MIT", "dependencies": { "@babel/parser": "^7.28.3", @@ -3092,6 +3098,7 @@ "version": "7.27.3", "resolved": "https://registry.npmjs.org/@babel/helper-annotate-as-pure/-/helper-annotate-as-pure-7.27.3.tgz", "integrity": "sha512-fXSwMQqitTGeHLBC08Eq5yXz2m37E4pJX1qAU1+2cNedz/ifv/bVXft90VeSav5nFO61EcNgwr0aJxbyPaWBPg==", + "dev": true, "license": "MIT", "dependencies": { "@babel/types": "^7.27.3" @@ -3104,6 +3111,7 @@ "version": "7.27.2", "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.27.2.tgz", "integrity": "sha512-2+1thGUUWWjLTYTHZWK1n8Yga0ijBz1XAhUXcKy81rd5g6yh7hGqMp45v7cadSbEHc9G3OTv45SyneRN3ps4DQ==", + "dev": true, "license": "MIT", "dependencies": { "@babel/compat-data": "^7.27.2", @@ -3120,6 +3128,7 @@ "version": "6.3.1", "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", + "dev": true, "license": "ISC", "bin": { "semver": "bin/semver.js" @@ -3129,6 +3138,7 @@ "version": "7.28.5", "resolved": "https://registry.npmjs.org/@babel/helper-create-class-features-plugin/-/helper-create-class-features-plugin-7.28.5.tgz", "integrity": "sha512-q3WC4JfdODypvxArsJQROfupPBq9+lMwjKq7C33GhbFYJsufD0yd/ziwD+hJucLeWsnFPWZjsU2DNFqBPE7jwQ==", + "dev": true, "license": "MIT", "dependencies": { "@babel/helper-annotate-as-pure": "^7.27.3", @@ -3150,6 +3160,7 @@ "version": "6.3.1", "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", + "dev": true, "license": "ISC", "bin": { "semver": "bin/semver.js" @@ -3159,6 +3170,7 @@ "version": "7.27.1", "resolved": "https://registry.npmjs.org/@babel/helper-create-regexp-features-plugin/-/helper-create-regexp-features-plugin-7.27.1.tgz", "integrity": "sha512-uVDC72XVf8UbrH5qQTc18Agb8emwjTiZrQE11Nv3CuBEZmVvTwwE9CBUEvHku06gQCAyYf8Nv6ja1IN+6LMbxQ==", + "dev": true, "license": "MIT", "dependencies": { "@babel/helper-annotate-as-pure": "^7.27.1", @@ -3176,6 +3188,7 @@ "version": "6.3.1", "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", + "dev": true, "license": "ISC", "bin": { "semver": "bin/semver.js" @@ -3185,6 +3198,7 @@ "version": "0.6.5", "resolved": "https://registry.npmjs.org/@babel/helper-define-polyfill-provider/-/helper-define-polyfill-provider-0.6.5.tgz", "integrity": "sha512-uJnGFcPsWQK8fvjgGP5LZUZZsYGIoPeRjSF5PGwrelYgq7Q15/Ft9NGFp1zglwgIv//W0uG4BevRuSJRyylZPg==", + "dev": true, "license": "MIT", "dependencies": { "@babel/helper-compilation-targets": "^7.27.2", @@ -3210,6 +3224,7 @@ "version": "7.28.5", "resolved": "https://registry.npmjs.org/@babel/helper-member-expression-to-functions/-/helper-member-expression-to-functions-7.28.5.tgz", "integrity": "sha512-cwM7SBRZcPCLgl8a7cY0soT1SptSzAlMH39vwiRpOQkJlh53r5hdHwLSCZpQdVLT39sZt+CRpNwYG4Y2v77atg==", + "dev": true, "license": "MIT", "dependencies": { "@babel/traverse": "^7.28.5", @@ -3236,6 +3251,7 @@ "version": "7.28.3", "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.28.3.tgz", "integrity": "sha512-gytXUbs8k2sXS9PnQptz5o0QnpLL51SwASIORY6XaBKF88nsOT0Zw9szLqlSGQDP/4TljBAD5y98p2U1fqkdsw==", + "dev": true, "license": "MIT", "dependencies": { "@babel/helper-module-imports": "^7.27.1", @@ -3253,6 +3269,7 @@ "version": "7.27.1", "resolved": "https://registry.npmjs.org/@babel/helper-optimise-call-expression/-/helper-optimise-call-expression-7.27.1.tgz", "integrity": "sha512-URMGH08NzYFhubNSGJrpUEphGKQwMQYBySzat5cAByY1/YgIRkULnIy3tAMeszlL/so2HbeilYloUmSpd7GdVw==", + "dev": true, "license": "MIT", "dependencies": { "@babel/types": "^7.27.1" @@ -3265,6 +3282,7 @@ "version": "7.27.1", "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.27.1.tgz", "integrity": "sha512-1gn1Up5YXka3YYAHGKpbideQ5Yjf1tDa9qYcgysz+cNCXukyLl6DjPXhD3VRwSb8c0J9tA4b2+rHEZtc6R0tlw==", + "dev": true, "license": "MIT", "engines": { "node": ">=6.9.0" @@ -3274,6 +3292,7 @@ "version": "7.27.1", "resolved": "https://registry.npmjs.org/@babel/helper-remap-async-to-generator/-/helper-remap-async-to-generator-7.27.1.tgz", "integrity": "sha512-7fiA521aVw8lSPeI4ZOD3vRFkoqkJcS+z4hFo82bFSH/2tNd6eJ5qCVMS5OzDmZh/kaHQeBaeyxK6wljcPtveA==", + "dev": true, "license": "MIT", "dependencies": { "@babel/helper-annotate-as-pure": "^7.27.1", @@ -3291,6 +3310,7 @@ "version": "7.27.1", "resolved": "https://registry.npmjs.org/@babel/helper-replace-supers/-/helper-replace-supers-7.27.1.tgz", "integrity": "sha512-7EHz6qDZc8RYS5ElPoShMheWvEgERonFCs7IAonWLLUTXW59DP14bCZt89/GKyreYn8g3S83m21FelHKbeDCKA==", + "dev": true, "license": "MIT", "dependencies": { "@babel/helper-member-expression-to-functions": "^7.27.1", @@ -3308,6 +3328,7 @@ "version": "7.27.1", "resolved": "https://registry.npmjs.org/@babel/helper-skip-transparent-expression-wrappers/-/helper-skip-transparent-expression-wrappers-7.27.1.tgz", "integrity": "sha512-Tub4ZKEXqbPjXgWLl2+3JpQAYBJ8+ikpQ2Ocj/q/r0LwE3UhENh7EUabyHjz2kCEsrRY83ew2DQdHluuiDQFzg==", + "dev": true, "license": "MIT", "dependencies": { "@babel/traverse": "^7.27.1", @@ -3352,6 +3373,7 @@ "version": "7.27.1", "resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.27.1.tgz", "integrity": "sha512-YvjJow9FxbhFFKDSuFnVCe2WxXk1zWc22fFePVNEaWJEu8IrZVlda6N0uHwzZrUM1il7NC9Mlp4MaJYbYd9JSg==", + "dev": true, "license": "MIT", "engines": { "node": ">=6.9.0" @@ -3361,6 +3383,7 @@ "version": "7.27.1", "resolved": "https://registry.npmjs.org/@babel/helper-wrap-function/-/helper-wrap-function-7.27.1.tgz", "integrity": "sha512-NFJK2sHUvrjo8wAU/nQTWU890/zB2jj0qBcCbZbbf+005cAsv6tMjXz31fBign6M5ov1o0Bllu+9nbqkfsjjJQ==", + "dev": true, "license": "MIT", "dependencies": { "@babel/template": "^7.27.1", @@ -3375,6 +3398,7 @@ "version": "7.28.4", "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.28.4.tgz", "integrity": "sha512-HFN59MmQXGHVyYadKLVumYsA9dBFun/ldYxipEjzA4196jpLZd8UjEEBLkbEkvfYreDqJhZxYAWFPtrfhNpj4w==", + "dev": true, "license": "MIT", "dependencies": { "@babel/template": "^7.27.2", @@ -3403,6 +3427,7 @@ "version": "7.28.5", "resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-firefox-class-in-computed-class-key/-/plugin-bugfix-firefox-class-in-computed-class-key-7.28.5.tgz", "integrity": "sha512-87GDMS3tsmMSi/3bWOte1UblL+YUTFMV8SZPZ2eSEL17s74Cw/l63rR6NmGVKMYW2GYi85nE+/d6Hw5N0bEk2Q==", + "dev": true, "license": "MIT", "dependencies": { "@babel/helper-plugin-utils": "^7.27.1", @@ -3419,6 +3444,7 @@ "version": "7.27.1", "resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-safari-class-field-initializer-scope/-/plugin-bugfix-safari-class-field-initializer-scope-7.27.1.tgz", "integrity": "sha512-qNeq3bCKnGgLkEXUuFry6dPlGfCdQNZbn7yUAPCInwAJHMU7THJfrBSozkcWq5sNM6RcF3S8XyQL2A52KNR9IA==", + "dev": true, "license": "MIT", "dependencies": { "@babel/helper-plugin-utils": "^7.27.1" @@ -3434,6 +3460,7 @@ "version": "7.27.1", "resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression/-/plugin-bugfix-safari-id-destructuring-collision-in-function-expression-7.27.1.tgz", "integrity": "sha512-g4L7OYun04N1WyqMNjldFwlfPCLVkgB54A/YCXICZYBsvJJE3kByKv9c9+R/nAfmIfjl2rKYLNyMHboYbZaWaA==", + "dev": true, "license": "MIT", "dependencies": { "@babel/helper-plugin-utils": "^7.27.1" @@ -3449,6 +3476,7 @@ "version": "7.27.1", "resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining/-/plugin-bugfix-v8-spread-parameters-in-optional-chaining-7.27.1.tgz", "integrity": "sha512-oO02gcONcD5O1iTLi/6frMJBIwWEHceWGSGqrpCmEL8nogiS6J9PBlE48CaK20/Jx1LuRml9aDftLgdjXT8+Cw==", + "dev": true, "license": "MIT", "dependencies": { "@babel/helper-plugin-utils": "^7.27.1", @@ -3466,6 +3494,7 @@ "version": "7.28.3", "resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-v8-static-class-fields-redefine-readonly/-/plugin-bugfix-v8-static-class-fields-redefine-readonly-7.28.3.tgz", "integrity": "sha512-b6YTX108evsvE4YgWyQ921ZAFFQm3Bn+CA3+ZXlNVnPhx+UfsVURoPjfGAPCjBgrqo30yX/C2nZGX96DxvR9Iw==", + "dev": true, "license": "MIT", "dependencies": { "@babel/helper-plugin-utils": "^7.27.1", @@ -3482,6 +3511,7 @@ "version": "7.27.1", "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-decorators/-/plugin-proposal-decorators-7.27.1.tgz", "integrity": "sha512-DTxe4LBPrtFdsWzgpmbBKevg3e9PBy+dXRt19kSbucbZvL2uqtdqwwpluL1jfxYE0wIDTFp1nTy/q6gNLsxXrg==", + "dev": true, "license": "MIT", "dependencies": { "@babel/helper-create-class-features-plugin": "^7.27.1", @@ -3499,6 +3529,7 @@ "version": "7.21.0-placeholder-for-preset-env.2", "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-private-property-in-object/-/plugin-proposal-private-property-in-object-7.21.0-placeholder-for-preset-env.2.tgz", "integrity": "sha512-SOSkfJDddaM7mak6cPEpswyTRnuRltl429hMraQEglW+OkovnCzsiszTmsrlY//qLFjCpQDFRvjdm2wA5pPm9w==", + "dev": true, "license": "MIT", "engines": { "node": ">=6.9.0" @@ -3511,6 +3542,7 @@ "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, "license": "MIT", "dependencies": { "@babel/helper-plugin-utils": "^7.8.0" @@ -3523,6 +3555,7 @@ "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, "license": "MIT", "dependencies": { "@babel/helper-plugin-utils": "^7.8.0" @@ -3535,6 +3568,7 @@ "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, "license": "MIT", "dependencies": { "@babel/helper-plugin-utils": "^7.12.13" @@ -3547,6 +3581,7 @@ "version": "7.14.5", "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-class-static-block/-/plugin-syntax-class-static-block-7.14.5.tgz", "integrity": "sha512-b+YyPmr6ldyNnM6sqYeMWE+bgJcJpO6yS4QD7ymxgH34GBPNDM/THBh8iunyvKIZztiwLH4CJZ0RxTk9emgpjw==", + "dev": true, "license": "MIT", "dependencies": { "@babel/helper-plugin-utils": "^7.14.5" @@ -3562,6 +3597,7 @@ "version": "7.27.1", "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-decorators/-/plugin-syntax-decorators-7.27.1.tgz", "integrity": "sha512-YMq8Z87Lhl8EGkmb0MwYkt36QnxC+fzCgrl66ereamPlYToRpIk5nUjKUY3QKLWq8mwUB1BgbeXcTJhZOCDg5A==", + "dev": true, "license": "MIT", "dependencies": { "@babel/helper-plugin-utils": "^7.27.1" @@ -3577,6 +3613,7 @@ "version": "7.27.1", "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-import-assertions/-/plugin-syntax-import-assertions-7.27.1.tgz", "integrity": "sha512-UT/Jrhw57xg4ILHLFnzFpPDlMbcdEicaAtjPQpbj9wa8T4r5KVWCimHcL/460g8Ht0DMxDyjsLgiWSkVjnwPFg==", + "dev": true, "license": "MIT", "dependencies": { "@babel/helper-plugin-utils": "^7.27.1" @@ -3592,6 +3629,7 @@ "version": "7.27.1", "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-import-attributes/-/plugin-syntax-import-attributes-7.27.1.tgz", "integrity": "sha512-oFT0FrKHgF53f4vOsZGi2Hh3I35PfSmVs4IBFLFj4dnafP+hIWDLg3VyKmUHfLoLHlyxY4C7DGtmHuJgn+IGww==", + "dev": true, "license": "MIT", "dependencies": { "@babel/helper-plugin-utils": "^7.27.1" @@ -3607,6 +3645,7 @@ "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, "license": "MIT", "dependencies": { "@babel/helper-plugin-utils": "^7.10.4" @@ -3619,6 +3658,7 @@ "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, "license": "MIT", "dependencies": { "@babel/helper-plugin-utils": "^7.8.0" @@ -3631,6 +3671,7 @@ "version": "7.27.1", "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-jsx/-/plugin-syntax-jsx-7.27.1.tgz", "integrity": "sha512-y8YTNIeKoyhGd9O0Jiyzyyqk8gdjnumGTQPsz0xOZOQ2RmkVJeZ1vmmfIvFEKqucBG6axJGBZDE/7iI5suUI/w==", + "dev": true, "license": "MIT", "dependencies": { "@babel/helper-plugin-utils": "^7.27.1" @@ -3646,6 +3687,7 @@ "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, "license": "MIT", "dependencies": { "@babel/helper-plugin-utils": "^7.10.4" @@ -3658,6 +3700,7 @@ "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, "license": "MIT", "dependencies": { "@babel/helper-plugin-utils": "^7.8.0" @@ -3670,6 +3713,7 @@ "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, "license": "MIT", "dependencies": { "@babel/helper-plugin-utils": "^7.10.4" @@ -3682,6 +3726,7 @@ "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, "license": "MIT", "dependencies": { "@babel/helper-plugin-utils": "^7.8.0" @@ -3694,6 +3739,7 @@ "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, "license": "MIT", "dependencies": { "@babel/helper-plugin-utils": "^7.8.0" @@ -3706,6 +3752,7 @@ "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, "license": "MIT", "dependencies": { "@babel/helper-plugin-utils": "^7.8.0" @@ -3718,6 +3765,7 @@ "version": "7.14.5", "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-private-property-in-object/-/plugin-syntax-private-property-in-object-7.14.5.tgz", "integrity": "sha512-0wVnp9dxJ72ZUJDV27ZfbSj6iHLoytYZmh3rFcxNnvsJF3ktkzLDZPy/mA17HGsaQT3/DQsWYX1f1QGWkCoVUg==", + "dev": true, "license": "MIT", "dependencies": { "@babel/helper-plugin-utils": "^7.14.5" @@ -3733,6 +3781,7 @@ "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, "license": "MIT", "dependencies": { "@babel/helper-plugin-utils": "^7.14.5" @@ -3748,6 +3797,7 @@ "version": "7.27.1", "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-typescript/-/plugin-syntax-typescript-7.27.1.tgz", "integrity": "sha512-xfYCBMxveHrRMnAWl1ZlPXOZjzkN82THFvLhQhFXFt81Z5HnN+EtUkZhv/zcKpmT3fzmWZB0ywiBrbC3vogbwQ==", + "dev": true, "license": "MIT", "dependencies": { "@babel/helper-plugin-utils": "^7.27.1" @@ -3763,6 +3813,7 @@ "version": "7.18.6", "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-unicode-sets-regex/-/plugin-syntax-unicode-sets-regex-7.18.6.tgz", "integrity": "sha512-727YkEAPwSIQTv5im8QHz3upqp92JTWhidIC81Tdx4VJYIte/VndKf1qKrfnnhPLiPghStWfvC/iFaMCQu7Nqg==", + "dev": true, "license": "MIT", "dependencies": { "@babel/helper-create-regexp-features-plugin": "^7.18.6", @@ -3779,6 +3830,7 @@ "version": "7.27.1", "resolved": "https://registry.npmjs.org/@babel/plugin-transform-arrow-functions/-/plugin-transform-arrow-functions-7.27.1.tgz", "integrity": "sha512-8Z4TGic6xW70FKThA5HYEKKyBpOOsucTOD1DjU3fZxDg+K3zBJcXMFnt/4yQiZnf5+MiOMSXQ9PaEK/Ilh1DeA==", + "dev": true, "license": "MIT", "dependencies": { "@babel/helper-plugin-utils": "^7.27.1" @@ -3794,6 +3846,7 @@ "version": "7.28.0", "resolved": "https://registry.npmjs.org/@babel/plugin-transform-async-generator-functions/-/plugin-transform-async-generator-functions-7.28.0.tgz", "integrity": "sha512-BEOdvX4+M765icNPZeidyADIvQ1m1gmunXufXxvRESy/jNNyfovIqUyE7MVgGBjWktCoJlzvFA1To2O4ymIO3Q==", + "dev": true, "license": "MIT", "dependencies": { "@babel/helper-plugin-utils": "^7.27.1", @@ -3811,6 +3864,7 @@ "version": "7.27.1", "resolved": "https://registry.npmjs.org/@babel/plugin-transform-async-to-generator/-/plugin-transform-async-to-generator-7.27.1.tgz", "integrity": "sha512-NREkZsZVJS4xmTr8qzE5y8AfIPqsdQfRuUiLRTEzb7Qii8iFWCyDKaUV2c0rCuh4ljDZ98ALHP/PetiBV2nddA==", + "dev": true, "license": "MIT", "dependencies": { "@babel/helper-module-imports": "^7.27.1", @@ -3828,6 +3882,7 @@ "version": "7.27.1", "resolved": "https://registry.npmjs.org/@babel/plugin-transform-block-scoped-functions/-/plugin-transform-block-scoped-functions-7.27.1.tgz", "integrity": "sha512-cnqkuOtZLapWYZUYM5rVIdv1nXYuFVIltZ6ZJ7nIj585QsjKM5dhL2Fu/lICXZ1OyIAFc7Qy+bvDAtTXqGrlhg==", + "dev": true, "license": "MIT", "dependencies": { "@babel/helper-plugin-utils": "^7.27.1" @@ -3843,6 +3898,7 @@ "version": "7.28.5", "resolved": "https://registry.npmjs.org/@babel/plugin-transform-block-scoping/-/plugin-transform-block-scoping-7.28.5.tgz", "integrity": "sha512-45DmULpySVvmq9Pj3X9B+62Xe+DJGov27QravQJU1LLcapR6/10i+gYVAucGGJpHBp5mYxIMK4nDAT/QDLr47g==", + "dev": true, "license": "MIT", "dependencies": { "@babel/helper-plugin-utils": "^7.27.1" @@ -3858,6 +3914,7 @@ "version": "7.27.1", "resolved": "https://registry.npmjs.org/@babel/plugin-transform-class-properties/-/plugin-transform-class-properties-7.27.1.tgz", "integrity": "sha512-D0VcalChDMtuRvJIu3U/fwWjf8ZMykz5iZsg77Nuj821vCKI3zCyRLwRdWbsuJ/uRwZhZ002QtCqIkwC/ZkvbA==", + "dev": true, "license": "MIT", "dependencies": { "@babel/helper-create-class-features-plugin": "^7.27.1", @@ -3874,6 +3931,7 @@ "version": "7.28.3", "resolved": "https://registry.npmjs.org/@babel/plugin-transform-class-static-block/-/plugin-transform-class-static-block-7.28.3.tgz", "integrity": "sha512-LtPXlBbRoc4Njl/oh1CeD/3jC+atytbnf/UqLoqTDcEYGUPj022+rvfkbDYieUrSj3CaV4yHDByPE+T2HwfsJg==", + "dev": true, "license": "MIT", "dependencies": { "@babel/helper-create-class-features-plugin": "^7.28.3", @@ -3890,6 +3948,7 @@ "version": "7.28.4", "resolved": "https://registry.npmjs.org/@babel/plugin-transform-classes/-/plugin-transform-classes-7.28.4.tgz", "integrity": "sha512-cFOlhIYPBv/iBoc+KS3M6et2XPtbT2HiCRfBXWtfpc9OAyostldxIf9YAYB6ypURBBbx+Qv6nyrLzASfJe+hBA==", + "dev": true, "license": "MIT", "dependencies": { "@babel/helper-annotate-as-pure": "^7.27.3", @@ -3910,6 +3969,7 @@ "version": "7.27.1", "resolved": "https://registry.npmjs.org/@babel/plugin-transform-computed-properties/-/plugin-transform-computed-properties-7.27.1.tgz", "integrity": "sha512-lj9PGWvMTVksbWiDT2tW68zGS/cyo4AkZ/QTp0sQT0mjPopCmrSkzxeXkznjqBxzDI6TclZhOJbBmbBLjuOZUw==", + "dev": true, "license": "MIT", "dependencies": { "@babel/helper-plugin-utils": "^7.27.1", @@ -3926,6 +3986,7 @@ "version": "7.28.5", "resolved": "https://registry.npmjs.org/@babel/plugin-transform-destructuring/-/plugin-transform-destructuring-7.28.5.tgz", "integrity": "sha512-Kl9Bc6D0zTUcFUvkNuQh4eGXPKKNDOJQXVyyM4ZAQPMveniJdxi8XMJwLo+xSoW3MIq81bD33lcUe9kZpl0MCw==", + "dev": true, "license": "MIT", "dependencies": { "@babel/helper-plugin-utils": "^7.27.1", @@ -3942,6 +4003,7 @@ "version": "7.27.1", "resolved": "https://registry.npmjs.org/@babel/plugin-transform-dotall-regex/-/plugin-transform-dotall-regex-7.27.1.tgz", "integrity": "sha512-gEbkDVGRvjj7+T1ivxrfgygpT7GUd4vmODtYpbs0gZATdkX8/iSnOtZSxiZnsgm1YjTgjI6VKBGSJJevkrclzw==", + "dev": true, "license": "MIT", "dependencies": { "@babel/helper-create-regexp-features-plugin": "^7.27.1", @@ -3958,6 +4020,7 @@ "version": "7.27.1", "resolved": "https://registry.npmjs.org/@babel/plugin-transform-duplicate-keys/-/plugin-transform-duplicate-keys-7.27.1.tgz", "integrity": "sha512-MTyJk98sHvSs+cvZ4nOauwTTG1JeonDjSGvGGUNHreGQns+Mpt6WX/dVzWBHgg+dYZhkC4X+zTDfkTU+Vy9y7Q==", + "dev": true, "license": "MIT", "dependencies": { "@babel/helper-plugin-utils": "^7.27.1" @@ -3973,6 +4036,7 @@ "version": "7.27.1", "resolved": "https://registry.npmjs.org/@babel/plugin-transform-duplicate-named-capturing-groups-regex/-/plugin-transform-duplicate-named-capturing-groups-regex-7.27.1.tgz", "integrity": "sha512-hkGcueTEzuhB30B3eJCbCYeCaaEQOmQR0AdvzpD4LoN0GXMWzzGSuRrxR2xTnCrvNbVwK9N6/jQ92GSLfiZWoQ==", + "dev": true, "license": "MIT", "dependencies": { "@babel/helper-create-regexp-features-plugin": "^7.27.1", @@ -3989,6 +4053,7 @@ "version": "7.27.1", "resolved": "https://registry.npmjs.org/@babel/plugin-transform-dynamic-import/-/plugin-transform-dynamic-import-7.27.1.tgz", "integrity": "sha512-MHzkWQcEmjzzVW9j2q8LGjwGWpG2mjwaaB0BNQwst3FIjqsg8Ct/mIZlvSPJvfi9y2AC8mi/ktxbFVL9pZ1I4A==", + "dev": true, "license": "MIT", "dependencies": { "@babel/helper-plugin-utils": "^7.27.1" @@ -4004,6 +4069,7 @@ "version": "7.28.0", "resolved": "https://registry.npmjs.org/@babel/plugin-transform-explicit-resource-management/-/plugin-transform-explicit-resource-management-7.28.0.tgz", "integrity": "sha512-K8nhUcn3f6iB+P3gwCv/no7OdzOZQcKchW6N389V6PD8NUWKZHzndOd9sPDVbMoBsbmjMqlB4L9fm+fEFNVlwQ==", + "dev": true, "license": "MIT", "dependencies": { "@babel/helper-plugin-utils": "^7.27.1", @@ -4020,6 +4086,7 @@ "version": "7.28.5", "resolved": "https://registry.npmjs.org/@babel/plugin-transform-exponentiation-operator/-/plugin-transform-exponentiation-operator-7.28.5.tgz", "integrity": "sha512-D4WIMaFtwa2NizOp+dnoFjRez/ClKiC2BqqImwKd1X28nqBtZEyCYJ2ozQrrzlxAFrcrjxo39S6khe9RNDlGzw==", + "dev": true, "license": "MIT", "dependencies": { "@babel/helper-plugin-utils": "^7.27.1" @@ -4035,6 +4102,7 @@ "version": "7.27.1", "resolved": "https://registry.npmjs.org/@babel/plugin-transform-export-namespace-from/-/plugin-transform-export-namespace-from-7.27.1.tgz", "integrity": "sha512-tQvHWSZ3/jH2xuq/vZDy0jNn+ZdXJeM8gHvX4lnJmsc3+50yPlWdZXIc5ay+umX+2/tJIqHqiEqcJvxlmIvRvQ==", + "dev": true, "license": "MIT", "dependencies": { "@babel/helper-plugin-utils": "^7.27.1" @@ -4050,6 +4118,7 @@ "version": "7.27.1", "resolved": "https://registry.npmjs.org/@babel/plugin-transform-for-of/-/plugin-transform-for-of-7.27.1.tgz", "integrity": "sha512-BfbWFFEJFQzLCQ5N8VocnCtA8J1CLkNTe2Ms2wocj75dd6VpiqS5Z5quTYcUoo4Yq+DN0rtikODccuv7RU81sw==", + "dev": true, "license": "MIT", "dependencies": { "@babel/helper-plugin-utils": "^7.27.1", @@ -4066,6 +4135,7 @@ "version": "7.27.1", "resolved": "https://registry.npmjs.org/@babel/plugin-transform-function-name/-/plugin-transform-function-name-7.27.1.tgz", "integrity": "sha512-1bQeydJF9Nr1eBCMMbC+hdwmRlsv5XYOMu03YSWFwNs0HsAmtSxxF1fyuYPqemVldVyFmlCU7w8UE14LupUSZQ==", + "dev": true, "license": "MIT", "dependencies": { "@babel/helper-compilation-targets": "^7.27.1", @@ -4083,6 +4153,7 @@ "version": "7.27.1", "resolved": "https://registry.npmjs.org/@babel/plugin-transform-json-strings/-/plugin-transform-json-strings-7.27.1.tgz", "integrity": "sha512-6WVLVJiTjqcQauBhn1LkICsR2H+zm62I3h9faTDKt1qP4jn2o72tSvqMwtGFKGTpojce0gJs+76eZ2uCHRZh0Q==", + "dev": true, "license": "MIT", "dependencies": { "@babel/helper-plugin-utils": "^7.27.1" @@ -4098,6 +4169,7 @@ "version": "7.27.1", "resolved": "https://registry.npmjs.org/@babel/plugin-transform-literals/-/plugin-transform-literals-7.27.1.tgz", "integrity": "sha512-0HCFSepIpLTkLcsi86GG3mTUzxV5jpmbv97hTETW3yzrAij8aqlD36toB1D0daVFJM8NK6GvKO0gslVQmm+zZA==", + "dev": true, "license": "MIT", "dependencies": { "@babel/helper-plugin-utils": "^7.27.1" @@ -4113,6 +4185,7 @@ "version": "7.28.5", "resolved": "https://registry.npmjs.org/@babel/plugin-transform-logical-assignment-operators/-/plugin-transform-logical-assignment-operators-7.28.5.tgz", "integrity": "sha512-axUuqnUTBuXyHGcJEVVh9pORaN6wC5bYfE7FGzPiaWa3syib9m7g+/IT/4VgCOe2Upef43PHzeAvcrVek6QuuA==", + "dev": true, "license": "MIT", "dependencies": { "@babel/helper-plugin-utils": "^7.27.1" @@ -4128,6 +4201,7 @@ "version": "7.27.1", "resolved": "https://registry.npmjs.org/@babel/plugin-transform-member-expression-literals/-/plugin-transform-member-expression-literals-7.27.1.tgz", "integrity": "sha512-hqoBX4dcZ1I33jCSWcXrP+1Ku7kdqXf1oeah7ooKOIiAdKQ+uqftgCFNOSzA5AMS2XIHEYeGFg4cKRCdpxzVOQ==", + "dev": true, "license": "MIT", "dependencies": { "@babel/helper-plugin-utils": "^7.27.1" @@ -4143,6 +4217,7 @@ "version": "7.27.1", "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-amd/-/plugin-transform-modules-amd-7.27.1.tgz", "integrity": "sha512-iCsytMg/N9/oFq6n+gFTvUYDZQOMK5kEdeYxmxt91fcJGycfxVP9CnrxoliM0oumFERba2i8ZtwRUCMhvP1LnA==", + "dev": true, "license": "MIT", "dependencies": { "@babel/helper-module-transforms": "^7.27.1", @@ -4159,6 +4234,7 @@ "version": "7.27.1", "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-commonjs/-/plugin-transform-modules-commonjs-7.27.1.tgz", "integrity": "sha512-OJguuwlTYlN0gBZFRPqwOGNWssZjfIUdS7HMYtN8c1KmwpwHFBwTeFZrg9XZa+DFTitWOW5iTAG7tyCUPsCCyw==", + "dev": true, "license": "MIT", "dependencies": { "@babel/helper-module-transforms": "^7.27.1", @@ -4175,6 +4251,7 @@ "version": "7.28.5", "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-systemjs/-/plugin-transform-modules-systemjs-7.28.5.tgz", "integrity": "sha512-vn5Jma98LCOeBy/KpeQhXcV2WZgaRUtjwQmjoBuLNlOmkg0fB5pdvYVeWRYI69wWKwK2cD1QbMiUQnoujWvrew==", + "dev": true, "license": "MIT", "dependencies": { "@babel/helper-module-transforms": "^7.28.3", @@ -4193,6 +4270,7 @@ "version": "7.27.1", "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-umd/-/plugin-transform-modules-umd-7.27.1.tgz", "integrity": "sha512-iQBE/xC5BV1OxJbp6WG7jq9IWiD+xxlZhLrdwpPkTX3ydmXdvoCpyfJN7acaIBZaOqTfr76pgzqBJflNbeRK+w==", + "dev": true, "license": "MIT", "dependencies": { "@babel/helper-module-transforms": "^7.27.1", @@ -4209,6 +4287,7 @@ "version": "7.27.1", "resolved": "https://registry.npmjs.org/@babel/plugin-transform-named-capturing-groups-regex/-/plugin-transform-named-capturing-groups-regex-7.27.1.tgz", "integrity": "sha512-SstR5JYy8ddZvD6MhV0tM/j16Qds4mIpJTOd1Yu9J9pJjH93bxHECF7pgtc28XvkzTD6Pxcm/0Z73Hvk7kb3Ng==", + "dev": true, "license": "MIT", "dependencies": { "@babel/helper-create-regexp-features-plugin": "^7.27.1", @@ -4225,6 +4304,7 @@ "version": "7.27.1", "resolved": "https://registry.npmjs.org/@babel/plugin-transform-new-target/-/plugin-transform-new-target-7.27.1.tgz", "integrity": "sha512-f6PiYeqXQ05lYq3TIfIDu/MtliKUbNwkGApPUvyo6+tc7uaR4cPjPe7DFPr15Uyycg2lZU6btZ575CuQoYh7MQ==", + "dev": true, "license": "MIT", "dependencies": { "@babel/helper-plugin-utils": "^7.27.1" @@ -4240,6 +4320,7 @@ "version": "7.27.1", "resolved": "https://registry.npmjs.org/@babel/plugin-transform-nullish-coalescing-operator/-/plugin-transform-nullish-coalescing-operator-7.27.1.tgz", "integrity": "sha512-aGZh6xMo6q9vq1JGcw58lZ1Z0+i0xB2x0XaauNIUXd6O1xXc3RwoWEBlsTQrY4KQ9Jf0s5rgD6SiNkaUdJegTA==", + "dev": true, "license": "MIT", "dependencies": { "@babel/helper-plugin-utils": "^7.27.1" @@ -4255,6 +4336,7 @@ "version": "7.27.1", "resolved": "https://registry.npmjs.org/@babel/plugin-transform-numeric-separator/-/plugin-transform-numeric-separator-7.27.1.tgz", "integrity": "sha512-fdPKAcujuvEChxDBJ5c+0BTaS6revLV7CJL08e4m3de8qJfNIuCc2nc7XJYOjBoTMJeqSmwXJ0ypE14RCjLwaw==", + "dev": true, "license": "MIT", "dependencies": { "@babel/helper-plugin-utils": "^7.27.1" @@ -4270,6 +4352,7 @@ "version": "7.28.4", "resolved": "https://registry.npmjs.org/@babel/plugin-transform-object-rest-spread/-/plugin-transform-object-rest-spread-7.28.4.tgz", "integrity": "sha512-373KA2HQzKhQCYiRVIRr+3MjpCObqzDlyrM6u4I201wL8Mp2wHf7uB8GhDwis03k2ti8Zr65Zyyqs1xOxUF/Ew==", + "dev": true, "license": "MIT", "dependencies": { "@babel/helper-compilation-targets": "^7.27.2", @@ -4289,6 +4372,7 @@ "version": "7.27.1", "resolved": "https://registry.npmjs.org/@babel/plugin-transform-object-super/-/plugin-transform-object-super-7.27.1.tgz", "integrity": "sha512-SFy8S9plRPbIcxlJ8A6mT/CxFdJx/c04JEctz4jf8YZaVS2px34j7NXRrlGlHkN/M2gnpL37ZpGRGVFLd3l8Ng==", + "dev": true, "license": "MIT", "dependencies": { "@babel/helper-plugin-utils": "^7.27.1", @@ -4305,6 +4389,7 @@ "version": "7.27.1", "resolved": "https://registry.npmjs.org/@babel/plugin-transform-optional-catch-binding/-/plugin-transform-optional-catch-binding-7.27.1.tgz", "integrity": "sha512-txEAEKzYrHEX4xSZN4kJ+OfKXFVSWKB2ZxM9dpcE3wT7smwkNmXo5ORRlVzMVdJbD+Q8ILTgSD7959uj+3Dm3Q==", + "dev": true, "license": "MIT", "dependencies": { "@babel/helper-plugin-utils": "^7.27.1" @@ -4320,6 +4405,7 @@ "version": "7.28.5", "resolved": "https://registry.npmjs.org/@babel/plugin-transform-optional-chaining/-/plugin-transform-optional-chaining-7.28.5.tgz", "integrity": "sha512-N6fut9IZlPnjPwgiQkXNhb+cT8wQKFlJNqcZkWlcTqkcqx6/kU4ynGmLFoa4LViBSirn05YAwk+sQBbPfxtYzQ==", + "dev": true, "license": "MIT", "dependencies": { "@babel/helper-plugin-utils": "^7.27.1", @@ -4336,6 +4422,7 @@ "version": "7.27.7", "resolved": "https://registry.npmjs.org/@babel/plugin-transform-parameters/-/plugin-transform-parameters-7.27.7.tgz", "integrity": "sha512-qBkYTYCb76RRxUM6CcZA5KRu8K4SM8ajzVeUgVdMVO9NN9uI/GaVmBg/WKJJGnNokV9SY8FxNOVWGXzqzUidBg==", + "dev": true, "license": "MIT", "dependencies": { "@babel/helper-plugin-utils": "^7.27.1" @@ -4351,6 +4438,7 @@ "version": "7.27.1", "resolved": "https://registry.npmjs.org/@babel/plugin-transform-private-methods/-/plugin-transform-private-methods-7.27.1.tgz", "integrity": "sha512-10FVt+X55AjRAYI9BrdISN9/AQWHqldOeZDUoLyif1Kn05a56xVBXb8ZouL8pZ9jem8QpXaOt8TS7RHUIS+GPA==", + "dev": true, "license": "MIT", "dependencies": { "@babel/helper-create-class-features-plugin": "^7.27.1", @@ -4367,6 +4455,7 @@ "version": "7.27.1", "resolved": "https://registry.npmjs.org/@babel/plugin-transform-private-property-in-object/-/plugin-transform-private-property-in-object-7.27.1.tgz", "integrity": "sha512-5J+IhqTi1XPa0DXF83jYOaARrX+41gOewWbkPyjMNRDqgOCqdffGh8L3f/Ek5utaEBZExjSAzcyjmV9SSAWObQ==", + "dev": true, "license": "MIT", "dependencies": { "@babel/helper-annotate-as-pure": "^7.27.1", @@ -4384,6 +4473,7 @@ "version": "7.27.1", "resolved": "https://registry.npmjs.org/@babel/plugin-transform-property-literals/-/plugin-transform-property-literals-7.27.1.tgz", "integrity": "sha512-oThy3BCuCha8kDZ8ZkgOg2exvPYUlprMukKQXI1r1pJ47NCvxfkEy8vK+r/hT9nF0Aa4H1WUPZZjHTFtAhGfmQ==", + "dev": true, "license": "MIT", "dependencies": { "@babel/helper-plugin-utils": "^7.27.1" @@ -4399,6 +4489,7 @@ "version": "7.28.4", "resolved": "https://registry.npmjs.org/@babel/plugin-transform-regenerator/-/plugin-transform-regenerator-7.28.4.tgz", "integrity": "sha512-+ZEdQlBoRg9m2NnzvEeLgtvBMO4tkFBw5SQIUgLICgTrumLoU7lr+Oghi6km2PFj+dbUt2u1oby2w3BDO9YQnA==", + "dev": true, "license": "MIT", "dependencies": { "@babel/helper-plugin-utils": "^7.27.1" @@ -4414,6 +4505,7 @@ "version": "7.27.1", "resolved": "https://registry.npmjs.org/@babel/plugin-transform-regexp-modifiers/-/plugin-transform-regexp-modifiers-7.27.1.tgz", "integrity": "sha512-TtEciroaiODtXvLZv4rmfMhkCv8jx3wgKpL68PuiPh2M4fvz5jhsA7697N1gMvkvr/JTF13DrFYyEbY9U7cVPA==", + "dev": true, "license": "MIT", "dependencies": { "@babel/helper-create-regexp-features-plugin": "^7.27.1", @@ -4430,6 +4522,7 @@ "version": "7.27.1", "resolved": "https://registry.npmjs.org/@babel/plugin-transform-reserved-words/-/plugin-transform-reserved-words-7.27.1.tgz", "integrity": "sha512-V2ABPHIJX4kC7HegLkYoDpfg9PVmuWy/i6vUM5eGK22bx4YVFD3M5F0QQnWQoDs6AGsUWTVOopBiMFQgHaSkVw==", + "dev": true, "license": "MIT", "dependencies": { "@babel/helper-plugin-utils": "^7.27.1" @@ -4445,6 +4538,7 @@ "version": "7.28.3", "resolved": "https://registry.npmjs.org/@babel/plugin-transform-runtime/-/plugin-transform-runtime-7.28.3.tgz", "integrity": "sha512-Y6ab1kGqZ0u42Zv/4a7l0l72n9DKP/MKoKWaUSBylrhNZO2prYuqFOLbn5aW5SIFXwSH93yfjbgllL8lxuGKLg==", + "dev": true, "license": "MIT", "dependencies": { "@babel/helper-module-imports": "^7.27.1", @@ -4465,6 +4559,7 @@ "version": "6.3.1", "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", + "dev": true, "license": "ISC", "bin": { "semver": "bin/semver.js" @@ -4474,6 +4569,7 @@ "version": "7.27.1", "resolved": "https://registry.npmjs.org/@babel/plugin-transform-shorthand-properties/-/plugin-transform-shorthand-properties-7.27.1.tgz", "integrity": "sha512-N/wH1vcn4oYawbJ13Y/FxcQrWk63jhfNa7jef0ih7PHSIHX2LB7GWE1rkPrOnka9kwMxb6hMl19p7lidA+EHmQ==", + "dev": true, "license": "MIT", "dependencies": { "@babel/helper-plugin-utils": "^7.27.1" @@ -4489,6 +4585,7 @@ "version": "7.27.1", "resolved": "https://registry.npmjs.org/@babel/plugin-transform-spread/-/plugin-transform-spread-7.27.1.tgz", "integrity": "sha512-kpb3HUqaILBJcRFVhFUs6Trdd4mkrzcGXss+6/mxUd273PfbWqSDHRzMT2234gIg2QYfAjvXLSquP1xECSg09Q==", + "dev": true, "license": "MIT", "dependencies": { "@babel/helper-plugin-utils": "^7.27.1", @@ -4505,6 +4602,7 @@ "version": "7.27.1", "resolved": "https://registry.npmjs.org/@babel/plugin-transform-sticky-regex/-/plugin-transform-sticky-regex-7.27.1.tgz", "integrity": "sha512-lhInBO5bi/Kowe2/aLdBAawijx+q1pQzicSgnkB6dUPc1+RC8QmJHKf2OjvU+NZWitguJHEaEmbV6VWEouT58g==", + "dev": true, "license": "MIT", "dependencies": { "@babel/helper-plugin-utils": "^7.27.1" @@ -4520,6 +4618,7 @@ "version": "7.27.1", "resolved": "https://registry.npmjs.org/@babel/plugin-transform-template-literals/-/plugin-transform-template-literals-7.27.1.tgz", "integrity": "sha512-fBJKiV7F2DxZUkg5EtHKXQdbsbURW3DZKQUWphDum0uRP6eHGGa/He9mc0mypL680pb+e/lDIthRohlv8NCHkg==", + "dev": true, "license": "MIT", "dependencies": { "@babel/helper-plugin-utils": "^7.27.1" @@ -4535,6 +4634,7 @@ "version": "7.27.1", "resolved": "https://registry.npmjs.org/@babel/plugin-transform-typeof-symbol/-/plugin-transform-typeof-symbol-7.27.1.tgz", "integrity": "sha512-RiSILC+nRJM7FY5srIyc4/fGIwUhyDuuBSdWn4y6yT6gm652DpCHZjIipgn6B7MQ1ITOUnAKWixEUjQRIBIcLw==", + "dev": true, "license": "MIT", "dependencies": { "@babel/helper-plugin-utils": "^7.27.1" @@ -4550,6 +4650,7 @@ "version": "7.27.1", "resolved": "https://registry.npmjs.org/@babel/plugin-transform-typescript/-/plugin-transform-typescript-7.27.1.tgz", "integrity": "sha512-Q5sT5+O4QUebHdbwKedFBEwRLb02zJ7r4A5Gg2hUoLuU3FjdMcyqcywqUrLCaDsFCxzokf7u9kuy7qz51YUuAg==", + "dev": true, "license": "MIT", "dependencies": { "@babel/helper-annotate-as-pure": "^7.27.1", @@ -4569,6 +4670,7 @@ "version": "7.27.1", "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-escapes/-/plugin-transform-unicode-escapes-7.27.1.tgz", "integrity": "sha512-Ysg4v6AmF26k9vpfFuTZg8HRfVWzsh1kVfowA23y9j/Gu6dOuahdUVhkLqpObp3JIv27MLSii6noRnuKN8H0Mg==", + "dev": true, "license": "MIT", "dependencies": { "@babel/helper-plugin-utils": "^7.27.1" @@ -4584,6 +4686,7 @@ "version": "7.27.1", "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-property-regex/-/plugin-transform-unicode-property-regex-7.27.1.tgz", "integrity": "sha512-uW20S39PnaTImxp39O5qFlHLS9LJEmANjMG7SxIhap8rCHqu0Ik+tLEPX5DKmHn6CsWQ7j3lix2tFOa5YtL12Q==", + "dev": true, "license": "MIT", "dependencies": { "@babel/helper-create-regexp-features-plugin": "^7.27.1", @@ -4600,6 +4703,7 @@ "version": "7.27.1", "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-regex/-/plugin-transform-unicode-regex-7.27.1.tgz", "integrity": "sha512-xvINq24TRojDuyt6JGtHmkVkrfVV3FPT16uytxImLeBZqW3/H52yN+kM1MGuyPkIQxrzKwPHs5U/MP3qKyzkGw==", + "dev": true, "license": "MIT", "dependencies": { "@babel/helper-create-regexp-features-plugin": "^7.27.1", @@ -4616,6 +4720,7 @@ "version": "7.27.1", "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-sets-regex/-/plugin-transform-unicode-sets-regex-7.27.1.tgz", "integrity": "sha512-EtkOujbc4cgvb0mlpQefi4NTPBzhSIevblFevACNLUspmrALgmEBdL/XfnyyITfd8fKBZrZys92zOWcik7j9Tw==", + "dev": true, "license": "MIT", "dependencies": { "@babel/helper-create-regexp-features-plugin": "^7.27.1", @@ -4632,6 +4737,7 @@ "version": "7.28.5", "resolved": "https://registry.npmjs.org/@babel/preset-env/-/preset-env-7.28.5.tgz", "integrity": "sha512-S36mOoi1Sb6Fz98fBfE+UZSpYw5mJm0NUHtIKrOuNcqeFauy1J6dIvXm2KRVKobOSaGq4t/hBXdN4HGU3wL9Wg==", + "dev": true, "license": "MIT", "dependencies": { "@babel/compat-data": "^7.28.5", @@ -4716,6 +4822,7 @@ "version": "6.3.1", "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", + "dev": true, "license": "ISC", "bin": { "semver": "bin/semver.js" @@ -4725,6 +4832,7 @@ "version": "0.1.6-no-external-plugins", "resolved": "https://registry.npmjs.org/@babel/preset-modules/-/preset-modules-0.1.6-no-external-plugins.tgz", "integrity": "sha512-HrcgcIESLm9aIR842yhJ5RWan/gebQUJ6E/E5+rf0y9o6oj7w0Br+sWuL6kEQ/o/AdfvR1Je9jG18/gnpwjEyA==", + "dev": true, "license": "MIT", "dependencies": { "@babel/helper-plugin-utils": "^7.0.0", @@ -4739,6 +4847,7 @@ "version": "7.27.1", "resolved": "https://registry.npmjs.org/@babel/preset-typescript/-/preset-typescript-7.27.1.tgz", "integrity": "sha512-l7WfQfX0WK4M0v2RudjuQK4u99BS6yLHYEmdtVPP7lKV013zr9DygFuWNlnbvQ9LR+LS0Egz/XAvGx5U9MX0fQ==", + "dev": true, "license": "MIT", "dependencies": { "@babel/helper-plugin-utils": "^7.27.1", @@ -4828,6 +4937,7 @@ "version": "0.2.3", "resolved": "https://registry.npmjs.org/@bcoe/v8-coverage/-/v8-coverage-0.2.3.tgz", "integrity": "sha512-0hYQ8SB4Db5zvZB4axdMHGwEaQjkZzFjQiN9LVYvIFB2nSUHW9tYpxWriPrWDASIxiaXax83REcLxuSdnGPZtw==", + "dev": true, "license": "MIT" }, "node_modules/@bitwarden/admin-console": { @@ -4863,9 +4973,9 @@ "link": true }, "node_modules/@bitwarden/commercial-sdk-internal": { - "version": "0.2.0-main.433", - "resolved": "https://registry.npmjs.org/@bitwarden/commercial-sdk-internal/-/commercial-sdk-internal-0.2.0-main.433.tgz", - "integrity": "sha512-/eFzw+BUHxAmT75kKUn1r9MFsJH/GZpc3ljkjNjAqtvb3L+fz8VTHTe7FoloSoZEnAnp8OWOZy7n4DavT/XDiw==", + "version": "0.2.0-main.450", + "resolved": "https://registry.npmjs.org/@bitwarden/commercial-sdk-internal/-/commercial-sdk-internal-0.2.0-main.450.tgz", + "integrity": "sha512-WCihR6ykpIfaqJBHl4Wou4xDB8mp+5UPi94eEKYUdkx/9/19YyX33SX9H56zEriOuOMCD8l2fymhzAFjAAB++g==", "license": "BITWARDEN SOFTWARE DEVELOPMENT KIT LICENSE AGREEMENT", "dependencies": { "type-fest": "^4.41.0" @@ -4968,9 +5078,9 @@ "link": true }, "node_modules/@bitwarden/sdk-internal": { - "version": "0.2.0-main.433", - "resolved": "https://registry.npmjs.org/@bitwarden/sdk-internal/-/sdk-internal-0.2.0-main.433.tgz", - "integrity": "sha512-m2PnYR0ifF0BgZ63aAt8eag0v7LeEGTJ0sa7UMbTWLwmsNnHug4u7jxIJl0WaVILNeWWK8iD/WSiw3EJeb7Fmw==", + "version": "0.2.0-main.450", + "resolved": "https://registry.npmjs.org/@bitwarden/sdk-internal/-/sdk-internal-0.2.0-main.450.tgz", + "integrity": "sha512-XRhrBN0uoo66ONx7dYo9glhe9N451+VhwtC/oh3wo3j3qYxbPwf9yE98szlQ52u3iUExLisiYJY7sQNzhZrbZw==", "license": "GPL-3.0", "dependencies": { "type-fest": "^4.41.0" @@ -5096,6 +5206,7 @@ "version": "2.9.0", "resolved": "https://registry.npmjs.org/@bufbuild/protobuf/-/protobuf-2.9.0.tgz", "integrity": "sha512-rnJenoStJ8nvmt9Gzye8nkYd6V22xUAnu4086ER7h1zJ508vStko4pMvDeQ446ilDTFpV5wnoc5YS7XvMwwMqA==", + "dev": true, "license": "(Apache-2.0 AND BSD-3-Clause)" }, "node_modules/@compodoc/compodoc": { @@ -6358,6 +6469,7 @@ "version": "1.7.1", "resolved": "https://registry.npmjs.org/@emnapi/core/-/core-1.7.1.tgz", "integrity": "sha512-o1uhUASyo921r2XtHYOHy7gdkGLge8ghBEQHMWmyJFoXlpU58kIrhhN3w26lpQb6dspetweapMn2CSNwQ8I4wg==", + "dev": true, "license": "MIT", "dependencies": { "@emnapi/wasi-threads": "1.1.0", @@ -6368,6 +6480,7 @@ "version": "1.7.1", "resolved": "https://registry.npmjs.org/@emnapi/runtime/-/runtime-1.7.1.tgz", "integrity": "sha512-PVtJr5CmLwYAU9PZDMITZoR5iAOShYREoR45EyyLrbntV50mdePTgUn4AmOw90Ifcj+x2kRjdzr1HP3RrNiHGA==", + "dev": true, "license": "MIT", "dependencies": { "tslib": "^2.4.0" @@ -6377,6 +6490,7 @@ "version": "1.1.0", "resolved": "https://registry.npmjs.org/@emnapi/wasi-threads/-/wasi-threads-1.1.0.tgz", "integrity": "sha512-WI0DdZ8xFSbgMjR1sFsKABJ/C5OnRrjT06JXbZKexJGrDuPTzZdDYfFlsgcCXCyf+suG5QU2e/y1Wo2V/OapLQ==", + "dev": true, "license": "MIT", "dependencies": { "tslib": "^2.4.0" @@ -6938,6 +7052,7 @@ "version": "4.7.0", "resolved": "https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.7.0.tgz", "integrity": "sha512-dyybb3AcajC7uha6CvhdVRJqaKyn7w2YKqKyAN37NKYgZT36w+iRb0Dymmc5qEJ549c/S31cMMSFd75bteCpCw==", + "dev": true, "license": "MIT", "dependencies": { "eslint-visitor-keys": "^3.4.3" @@ -6956,6 +7071,7 @@ "version": "4.12.1", "resolved": "https://registry.npmjs.org/@eslint-community/regexpp/-/regexpp-4.12.1.tgz", "integrity": "sha512-CCZCDJuduB9OUkFkY2IgppNZMi2lBQgD2qzwXkEia16cge2pijY/aXi96CJMquDMn3nJdlPV1A5KrJEXwfLNzQ==", + "dev": true, "license": "MIT", "engines": { "node": "^12.0.0 || ^14.0.0 || >=16.0.0" @@ -6999,6 +7115,7 @@ "version": "0.20.1", "resolved": "https://registry.npmjs.org/@eslint/config-array/-/config-array-0.20.1.tgz", "integrity": "sha512-OL0RJzC/CBzli0DrrR31qzj6d6i6Mm3HByuhflhl4LOBiWxN+3i6/t/ZQQNii4tjksXi8r2CRW1wMpWA2ULUEw==", + "dev": true, "license": "Apache-2.0", "dependencies": { "@eslint/object-schema": "^2.1.6", @@ -7013,6 +7130,7 @@ "version": "1.1.12", "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.12.tgz", "integrity": "sha512-9T9UjW3r0UW5c1Q7GTwllptXwhvYmEzFhzMfZ9H7FQWt+uZePjZPjBP/W1ZEyZ1twGWom5/56TF4lPcqjnDHcg==", + "dev": true, "license": "MIT", "dependencies": { "balanced-match": "^1.0.0", @@ -7023,6 +7141,7 @@ "version": "3.1.2", "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "dev": true, "license": "ISC", "dependencies": { "brace-expansion": "^1.1.7" @@ -7035,6 +7154,7 @@ "version": "0.2.3", "resolved": "https://registry.npmjs.org/@eslint/config-helpers/-/config-helpers-0.2.3.tgz", "integrity": "sha512-u180qk2Um1le4yf0ruXH3PYFeEZeYC3p/4wCTKrr2U1CmGdzGi3KtY0nuPDH48UJxlKCC5RDzbcbh4X0XlqgHg==", + "dev": true, "license": "Apache-2.0", "engines": { "node": "^18.18.0 || ^20.9.0 || >=21.1.0" @@ -7044,6 +7164,7 @@ "version": "0.13.0", "resolved": "https://registry.npmjs.org/@eslint/core/-/core-0.13.0.tgz", "integrity": "sha512-yfkgDw1KR66rkT5A8ci4irzDysN7FRpq3ttJolR88OqQikAWqwA8j5VZyas+vjyBNFIJ7MfybJ9plMILI2UrCw==", + "dev": true, "license": "Apache-2.0", "dependencies": { "@types/json-schema": "^7.0.15" @@ -7056,6 +7177,7 @@ "version": "3.3.1", "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-3.3.1.tgz", "integrity": "sha512-gtF186CXhIl1p4pJNGZw8Yc6RlshoePRvE0X91oPGb3vZ8pM3qOS9W9NGPat9LziaBV7XrJWGylNQXkGcnM3IQ==", + "dev": true, "license": "MIT", "dependencies": { "ajv": "^6.12.4", @@ -7079,6 +7201,7 @@ "version": "6.12.6", "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", + "dev": true, "license": "MIT", "dependencies": { "fast-deep-equal": "^3.1.1", @@ -7095,6 +7218,7 @@ "version": "1.1.12", "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.12.tgz", "integrity": "sha512-9T9UjW3r0UW5c1Q7GTwllptXwhvYmEzFhzMfZ9H7FQWt+uZePjZPjBP/W1ZEyZ1twGWom5/56TF4lPcqjnDHcg==", + "dev": true, "license": "MIT", "dependencies": { "balanced-match": "^1.0.0", @@ -7105,6 +7229,7 @@ "version": "14.0.0", "resolved": "https://registry.npmjs.org/globals/-/globals-14.0.0.tgz", "integrity": "sha512-oahGvuMGQlPw/ivIYBjVSrWAfWLBeku5tpPE2fOPLi+WHffIWbuh2tCjhyQhTBPMf5E9jDEH4FOmTYgYwbKwtQ==", + "dev": true, "license": "MIT", "engines": { "node": ">=18" @@ -7117,6 +7242,7 @@ "version": "5.3.2", "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.3.2.tgz", "integrity": "sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g==", + "dev": true, "license": "MIT", "engines": { "node": ">= 4" @@ -7126,6 +7252,7 @@ "version": "4.1.0", "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==", + "dev": true, "license": "MIT", "dependencies": { "argparse": "^2.0.1" @@ -7138,12 +7265,14 @@ "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, "license": "MIT" }, "node_modules/@eslint/eslintrc/node_modules/minimatch": { "version": "3.1.2", "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "dev": true, "license": "ISC", "dependencies": { "brace-expansion": "^1.1.7" @@ -7156,6 +7285,7 @@ "version": "9.26.0", "resolved": "https://registry.npmjs.org/@eslint/js/-/js-9.26.0.tgz", "integrity": "sha512-I9XlJawFdSMvWjDt6wksMCrgns5ggLNfFwFvnShsleWruvXM514Qxk8V246efTw+eo9JABvVz+u3q2RiAowKxQ==", + "dev": true, "license": "MIT", "engines": { "node": "^18.18.0 || ^20.9.0 || >=21.1.0" @@ -7165,6 +7295,7 @@ "version": "2.1.6", "resolved": "https://registry.npmjs.org/@eslint/object-schema/-/object-schema-2.1.6.tgz", "integrity": "sha512-RBMg5FRL0I0gs51M/guSAj5/e14VQ4tpZnQNWwuDT66P14I43ItmPfIZRhO9fUVIPOAQXU47atlywZ/czoqFPA==", + "dev": true, "license": "Apache-2.0", "engines": { "node": "^18.18.0 || ^20.9.0 || >=21.1.0" @@ -7174,6 +7305,7 @@ "version": "0.2.8", "resolved": "https://registry.npmjs.org/@eslint/plugin-kit/-/plugin-kit-0.2.8.tgz", "integrity": "sha512-ZAoA40rNMPwSm+AeHpCq8STiNAwzWLJuP8Xv4CHIc9wv/PSuExjMrmjfYNj682vW0OOiZ1HKxzvjQr9XZIisQA==", + "dev": true, "license": "Apache-2.0", "dependencies": { "@eslint/core": "^0.13.0", @@ -7329,6 +7461,7 @@ "version": "0.19.1", "resolved": "https://registry.npmjs.org/@humanfs/core/-/core-0.19.1.tgz", "integrity": "sha512-5DyQ4+1JEUzejeK1JGICcideyfUbGixgS9jNgex5nqkW+cY7WZhxBigmieN5Qnw9ZosSNVC9KQKyb+GUaGyKUA==", + "dev": true, "license": "Apache-2.0", "engines": { "node": ">=18.18.0" @@ -7338,6 +7471,7 @@ "version": "0.16.6", "resolved": "https://registry.npmjs.org/@humanfs/node/-/node-0.16.6.tgz", "integrity": "sha512-YuI2ZHQL78Q5HbhDiBA1X4LmYdXCKCMQIfw0pw7piHJwyREFebJUvrQN4cMssyES6x+vfUbx1CIpaQUKYdQZOw==", + "dev": true, "license": "Apache-2.0", "dependencies": { "@humanfs/core": "^0.19.1", @@ -7351,6 +7485,7 @@ "version": "0.3.1", "resolved": "https://registry.npmjs.org/@humanwhocodes/retry/-/retry-0.3.1.tgz", "integrity": "sha512-JBxkERygn7Bv/GbN5Rv8Ul6LVknS+5Bp6RgDC/O8gEBU/yeH5Ui5C/OlWrTb6qct7LjjfT6Re2NxB0ln0yYybA==", + "dev": true, "license": "Apache-2.0", "engines": { "node": ">=18.18" @@ -7364,6 +7499,7 @@ "version": "1.0.1", "resolved": "https://registry.npmjs.org/@humanwhocodes/module-importer/-/module-importer-1.0.1.tgz", "integrity": "sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA==", + "dev": true, "license": "Apache-2.0", "engines": { "node": ">=12.22" @@ -7377,6 +7513,7 @@ "version": "0.4.3", "resolved": "https://registry.npmjs.org/@humanwhocodes/retry/-/retry-0.4.3.tgz", "integrity": "sha512-bV0Tgo9K4hfPCek+aMAn81RppFKv2ySDQeMoSZuvTASywNTnVJCArCZE2FWqpvIatKu7VMRLWlR1EazvVhDyhQ==", + "dev": true, "license": "Apache-2.0", "engines": { "node": ">=18.18" @@ -7787,6 +7924,7 @@ "version": "8.0.2", "resolved": "https://registry.npmjs.org/@isaacs/cliui/-/cliui-8.0.2.tgz", "integrity": "sha512-O8jcjabXaleOG9DQ0+ARXWZBTfnP4WNAqzuiJK7ll44AmxGKv/J2M4TPjxjY3znBCfvBXFzucm1twdyFybFqEA==", + "dev": true, "license": "ISC", "dependencies": { "string-width": "^5.1.2", @@ -7804,6 +7942,7 @@ "version": "6.1.0", "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.1.0.tgz", "integrity": "sha512-7HSX4QQb4CspciLpVFwyRe79O3xsIZDDLER21kERQ71oaPodF8jL725AgJMFAYbooIqolJoRLuM81SpeUkpkvA==", + "dev": true, "license": "MIT", "engines": { "node": ">=12" @@ -7816,6 +7955,7 @@ "version": "6.2.1", "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-6.2.1.tgz", "integrity": "sha512-bN798gFfQX+viw3R7yrGWRqnrN2oRkEkUjjl4JNn4E8GxxbjtG3FbrEIIY3l8/hrwUwIeCZvi4QuOTP4MErVug==", + "dev": true, "license": "MIT", "engines": { "node": ">=12" @@ -7828,12 +7968,14 @@ "version": "9.2.2", "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-9.2.2.tgz", "integrity": "sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==", + "dev": true, "license": "MIT" }, "node_modules/@isaacs/cliui/node_modules/string-width": { "version": "5.1.2", "resolved": "https://registry.npmjs.org/string-width/-/string-width-5.1.2.tgz", "integrity": "sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA==", + "dev": true, "license": "MIT", "dependencies": { "eastasianwidth": "^0.2.0", @@ -7851,6 +7993,7 @@ "version": "7.1.0", "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.1.0.tgz", "integrity": "sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ==", + "dev": true, "license": "MIT", "dependencies": { "ansi-regex": "^6.0.1" @@ -7866,6 +8009,7 @@ "version": "8.1.0", "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-8.1.0.tgz", "integrity": "sha512-si7QWI6zUMq56bESFvagtmzMdGOtoxfR+Sez11Mobfc7tm+VkUckk9bW2UeffTGVUbOksxmSw0AA2gs8g71NCQ==", + "dev": true, "license": "MIT", "dependencies": { "ansi-styles": "^6.1.0", @@ -7896,6 +8040,7 @@ "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, "license": "ISC", "dependencies": { "camelcase": "^5.3.1", @@ -7912,6 +8057,7 @@ "version": "4.1.0", "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz", "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==", + "dev": true, "license": "MIT", "dependencies": { "locate-path": "^5.0.0", @@ -7925,6 +8071,7 @@ "version": "5.0.0", "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz", "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==", + "dev": true, "license": "MIT", "dependencies": { "p-locate": "^4.1.0" @@ -7937,6 +8084,7 @@ "version": "2.3.0", "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz", "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==", + "dev": true, "license": "MIT", "dependencies": { "p-try": "^2.0.0" @@ -7952,6 +8100,7 @@ "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, "license": "MIT", "dependencies": { "p-limit": "^2.2.0" @@ -7964,6 +8113,7 @@ "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, "license": "MIT", "engines": { "node": ">=8" @@ -8087,6 +8237,7 @@ "version": "30.0.1", "resolved": "https://registry.npmjs.org/@jest/diff-sequences/-/diff-sequences-30.0.1.tgz", "integrity": "sha512-n5H8QLDJ47QqbCNn5SuFjCRDrOLEZ0h8vAHCK5RL9Ls7Xa8AQLa/YxAc9UjFqoEDM48muwtBGjtMY5cr0PLDCw==", + "dev": true, "license": "MIT", "engines": { "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" @@ -8157,6 +8308,7 @@ "version": "30.1.0", "resolved": "https://registry.npmjs.org/@jest/get-type/-/get-type-30.1.0.tgz", "integrity": "sha512-eMbZE2hUnx1WV0pmURZY9XoXPkUYjpc55mb0CrhtdWLtzMQPFvu/rZkTLZFTsdaVQa+Tr4eWAteqcUzoawq/uA==", + "dev": true, "license": "MIT", "engines": { "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" @@ -8182,6 +8334,7 @@ "version": "30.0.1", "resolved": "https://registry.npmjs.org/@jest/pattern/-/pattern-30.0.1.tgz", "integrity": "sha512-gWp7NfQW27LaBQz3TITS8L7ZCQ0TLvtmI//4OwlQRx4rnWxcPNIYjxZpDcN4+UlGxgm3jS5QPz8IPTCkb59wZA==", + "dev": true, "license": "MIT", "dependencies": { "@types/node": "*", @@ -8195,6 +8348,7 @@ "version": "30.0.1", "resolved": "https://registry.npmjs.org/jest-regex-util/-/jest-regex-util-30.0.1.tgz", "integrity": "sha512-jHEQgBXAgc+Gh4g0p3bCevgRCVRkB4VB70zhoAE48gxeSr1hfUOsM/C2WoJgVL7Eyg//hudYENbm3Ne+/dRVVA==", + "dev": true, "license": "MIT", "engines": { "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" @@ -8294,6 +8448,7 @@ "version": "29.6.3", "resolved": "https://registry.npmjs.org/@jest/schemas/-/schemas-29.6.3.tgz", "integrity": "sha512-mo5j5X+jIZmJQveBKeS/clAueipV7KgiX1vMgCxam1RNYiqE1w62n0/tJJnHtjW8ZHcQco5gY85jA3mi0L+nSA==", + "dev": true, "license": "MIT", "dependencies": { "@sinclair/typebox": "^0.27.8" @@ -8306,6 +8461,7 @@ "version": "30.2.0", "resolved": "https://registry.npmjs.org/@jest/snapshot-utils/-/snapshot-utils-30.2.0.tgz", "integrity": "sha512-0aVxM3RH6DaiLcjj/b0KrIBZhSX1373Xci4l3cW5xiUWPctZ59zQ7jj4rqcJQ/Z8JuN/4wX3FpJSa3RssVvCug==", + "dev": true, "license": "MIT", "dependencies": { "@jest/types": "30.2.0", @@ -8321,6 +8477,7 @@ "version": "30.0.5", "resolved": "https://registry.npmjs.org/@jest/schemas/-/schemas-30.0.5.tgz", "integrity": "sha512-DmdYgtezMkh3cpU8/1uyXakv3tJRcmcXxBOcO0tbaozPwpmh4YMsnWrQm9ZmZMfa5ocbxzbFk6O4bDPEc/iAnA==", + "dev": true, "license": "MIT", "dependencies": { "@sinclair/typebox": "^0.34.0" @@ -8333,6 +8490,7 @@ "version": "30.2.0", "resolved": "https://registry.npmjs.org/@jest/types/-/types-30.2.0.tgz", "integrity": "sha512-H9xg1/sfVvyfU7o3zMfBEjQ1gcsdeTMgqHoYdN79tuLqfTtuu7WckRA1R5whDwOzxaZAeMKTYWqP+WCAi0CHsg==", + "dev": true, "license": "MIT", "dependencies": { "@jest/pattern": "30.0.1", @@ -8351,6 +8509,7 @@ "version": "0.34.41", "resolved": "https://registry.npmjs.org/@sinclair/typebox/-/typebox-0.34.41.tgz", "integrity": "sha512-6gS8pZzSXdyRHTIqoqSVknxolr1kzfy4/CeDnrzsVz8TTIWUbOBr6gnzOmTYJ3eXQNh4IYHIGi5aIL7sOZ2G/g==", + "dev": true, "license": "MIT" }, "node_modules/@jest/source-map": { @@ -8438,6 +8597,7 @@ "version": "29.6.3", "resolved": "https://registry.npmjs.org/@jest/types/-/types-29.6.3.tgz", "integrity": "sha512-u3UPsIilWKOM3F9CXtrG8LEJmNxwoCQC/XVj4IKYXvvpx7QIi/Kg1LI5uDmDpKlac62NUtX7eLjRh+jVZcLOzw==", + "dev": true, "license": "MIT", "dependencies": { "@jest/schemas": "^29.6.3", @@ -8465,6 +8625,7 @@ "version": "2.3.5", "resolved": "https://registry.npmjs.org/@jridgewell/remapping/-/remapping-2.3.5.tgz", "integrity": "sha512-LI9u/+laYG4Ds1TDKSJW2YPrIlcVYOwi2fUC6xB43lueCjgxV4lffOCZCtYFiH6TNOX+tQKXx97T4IKHbhyHEQ==", + "dev": true, "license": "MIT", "dependencies": { "@jridgewell/gen-mapping": "^0.3.5", @@ -8484,6 +8645,7 @@ "version": "0.3.6", "resolved": "https://registry.npmjs.org/@jridgewell/source-map/-/source-map-0.3.6.tgz", "integrity": "sha512-1ZJTZebgqllO79ue2bm3rIGud/bOe0pP5BjSRCRxxYkEZS8STV7zN84UBbiYu7jy+eCKSnVIUgoWWE/tt+shMQ==", + "dev": true, "license": "MIT", "dependencies": { "@jridgewell/gen-mapping": "^0.3.5", @@ -8510,6 +8672,7 @@ "version": "1.1.2", "resolved": "https://registry.npmjs.org/@jsonjoy.com/base64/-/base64-1.1.2.tgz", "integrity": "sha512-q6XAnWQDIMA3+FTiOYajoYqySkO+JSat0ytXGSuRdq9uXE7o92gzuQwQM14xaCRlBLGq3v5miDGC4vkVTn54xA==", + "dev": true, "license": "Apache-2.0", "engines": { "node": ">=10.0" @@ -8526,6 +8689,7 @@ "version": "1.2.0", "resolved": "https://registry.npmjs.org/@jsonjoy.com/json-pack/-/json-pack-1.2.0.tgz", "integrity": "sha512-io1zEbbYcElht3tdlqEOFxZ0dMTYrHz9iMf0gqn1pPjZFTCgM5R4R5IMA20Chb2UPYYsxjzs8CgZ7Nb5n2K2rA==", + "dev": true, "license": "Apache-2.0", "dependencies": { "@jsonjoy.com/base64": "^1.1.1", @@ -8548,6 +8712,7 @@ "version": "1.6.0", "resolved": "https://registry.npmjs.org/@jsonjoy.com/util/-/util-1.6.0.tgz", "integrity": "sha512-sw/RMbehRhN68WRtcKCpQOPfnH6lLP4GJfqzi3iYej8tnzpZUDr6UkZYJjcjjC0FWEJOJbyM3PTIwxucUmDG2A==", + "dev": true, "license": "Apache-2.0", "engines": { "node": ">=10.0" @@ -8592,6 +8757,7 @@ "version": "2.0.5", "resolved": "https://registry.npmjs.org/@leichtgewicht/ip-codec/-/ip-codec-2.0.5.tgz", "integrity": "sha512-Vo+PSpZG2/fmgmiNzYK9qWRh8h/CHrwD0mo1h1DzL4yzHNSfWYujGTYsWGreD000gcgmZ7K4Ys6Tx9TxtsKdDw==", + "dev": true, "license": "MIT" }, "node_modules/@listr2/prompt-adapter-inquirer": { @@ -8878,6 +9044,7 @@ "version": "1.17.3", "resolved": "https://registry.npmjs.org/@modelcontextprotocol/sdk/-/sdk-1.17.3.tgz", "integrity": "sha512-JPwUKWSsbzx+DLFznf/QZ32Qa+ptfbUlHhRLrBQBAFu9iI1iYvizM4p+zhhRDceSsPutXp4z+R/HPVphlIiclg==", + "dev": true, "license": "MIT", "dependencies": { "ajv": "^6.12.6", @@ -8901,6 +9068,7 @@ "version": "6.12.6", "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", + "dev": true, "license": "MIT", "dependencies": { "fast-deep-equal": "^3.1.1", @@ -8917,6 +9085,7 @@ "version": "3.0.7", "resolved": "https://registry.npmjs.org/eventsource/-/eventsource-3.0.7.tgz", "integrity": "sha512-CRT1WTyuQoD771GW56XEZFQ/ZoSfWid1alKGDYMmkt2yl8UXrVR4pspqWNEcqKvVIzg6PAltWjxcSSPrboA4iA==", + "dev": true, "license": "MIT", "dependencies": { "eventsource-parser": "^3.0.1" @@ -8929,6 +9098,7 @@ "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, "license": "MIT" }, "node_modules/@msgpack/msgpack": { @@ -10082,6 +10252,7 @@ "version": "0.2.4", "resolved": "https://registry.npmjs.org/@napi-rs/wasm-runtime/-/wasm-runtime-0.2.4.tgz", "integrity": "sha512-9zESzOO5aDByvhIAsOy9TbpZ0Ur2AJbUI7UT73kcUTS2mxAMHOBaa1st/jAymNoCtvrit99kkzT1FZuXVcgfIQ==", + "dev": true, "license": "MIT", "dependencies": { "@emnapi/core": "^1.1.0", @@ -10397,6 +10568,7 @@ "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, "license": "MIT", "dependencies": { "@nodelib/fs.stat": "2.0.5", @@ -10410,6 +10582,7 @@ "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, "license": "MIT", "engines": { "node": ">= 8" @@ -10419,6 +10592,7 @@ "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, "license": "MIT", "dependencies": { "@nodelib/fs.scandir": "2.1.5", @@ -10875,6 +11049,7 @@ "version": "21.6.10", "resolved": "https://registry.npmjs.org/@nx/devkit/-/devkit-21.6.10.tgz", "integrity": "sha512-h2ZpwhKk9p1kWgokMXP6F4PVakUA3jPbKmjtY+wCsW2VZg72tIVVzs33DGUxTvN6WG6Z4xbLKc0LJkgaOdDTOw==", + "dev": true, "license": "MIT", "dependencies": { "ejs": "^3.1.7", @@ -10893,6 +11068,7 @@ "version": "5.3.2", "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.3.2.tgz", "integrity": "sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g==", + "dev": true, "license": "MIT", "engines": { "node": ">= 4" @@ -10902,6 +11078,7 @@ "version": "21.6.10", "resolved": "https://registry.npmjs.org/@nx/eslint/-/eslint-21.6.10.tgz", "integrity": "sha512-cZPXFZsgzGrOBetSdcIR9Kb28H9+lHsaubAGeCAjS8GSvRoQBKLdgtfuB5mpnmOLRqGsiIhZ701DfekLitRnmQ==", + "dev": true, "license": "MIT", "dependencies": { "@nx/devkit": "21.6.10", @@ -10924,6 +11101,7 @@ "version": "5.9.3", "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.9.3.tgz", "integrity": "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==", + "dev": true, "license": "Apache-2.0", "bin": { "tsc": "bin/tsc", @@ -10937,6 +11115,7 @@ "version": "21.6.10", "resolved": "https://registry.npmjs.org/@nx/jest/-/jest-21.6.10.tgz", "integrity": "sha512-JAYMD/RwKP/mgr7R0uC6R7/DGsluajiQsHipbp6JhbwmqxOK+tTdWBHrYzKWXyRZaCSqqmrN55ocVfuynZDP4Q==", + "dev": true, "license": "MIT", "dependencies": { "@jest/reporters": "^30.0.2", @@ -10960,6 +11139,7 @@ "version": "30.2.0", "resolved": "https://registry.npmjs.org/@jest/console/-/console-30.2.0.tgz", "integrity": "sha512-+O1ifRjkvYIkBqASKWgLxrpEhQAAE7hY77ALLUufSk5717KfOShg6IbqLmdsLMPdUiFvA2kTs0R7YZy+l0IzZQ==", + "dev": true, "license": "MIT", "dependencies": { "@jest/types": "30.2.0", @@ -10977,6 +11157,7 @@ "version": "30.2.0", "resolved": "https://registry.npmjs.org/@jest/environment/-/environment-30.2.0.tgz", "integrity": "sha512-/QPTL7OBJQ5ac09UDRa3EQes4gt1FTEG/8jZ/4v5IVzx+Cv7dLxlVIvfvSVRiiX2drWyXeBjkMSR8hvOWSog5g==", + "dev": true, "license": "MIT", "dependencies": { "@jest/fake-timers": "30.2.0", @@ -10992,6 +11173,7 @@ "version": "30.2.0", "resolved": "https://registry.npmjs.org/@jest/expect/-/expect-30.2.0.tgz", "integrity": "sha512-V9yxQK5erfzx99Sf+7LbhBwNWEZ9eZay8qQ9+JSC0TrMR1pMDHLMY+BnVPacWU6Jamrh252/IKo4F1Xn/zfiqA==", + "dev": true, "license": "MIT", "dependencies": { "expect": "30.2.0", @@ -11005,6 +11187,7 @@ "version": "30.2.0", "resolved": "https://registry.npmjs.org/@jest/expect-utils/-/expect-utils-30.2.0.tgz", "integrity": "sha512-1JnRfhqpD8HGpOmQp180Fo9Zt69zNtC+9lR+kT7NVL05tNXIi+QC8Csz7lfidMoVLPD3FnOtcmp0CEFnxExGEA==", + "dev": true, "license": "MIT", "dependencies": { "@jest/get-type": "30.1.0" @@ -11017,6 +11200,7 @@ "version": "30.2.0", "resolved": "https://registry.npmjs.org/@jest/fake-timers/-/fake-timers-30.2.0.tgz", "integrity": "sha512-HI3tRLjRxAbBy0VO8dqqm7Hb2mIa8d5bg/NJkyQcOk7V118ObQML8RC5luTF/Zsg4474a+gDvhce7eTnP4GhYw==", + "dev": true, "license": "MIT", "dependencies": { "@jest/types": "30.2.0", @@ -11034,6 +11218,7 @@ "version": "30.2.0", "resolved": "https://registry.npmjs.org/@jest/globals/-/globals-30.2.0.tgz", "integrity": "sha512-b63wmnKPaK+6ZZfpYhz9K61oybvbI1aMcIs80++JI1O1rR1vaxHUCNqo3ITu6NU0d4V34yZFoHMn/uoKr/Rwfw==", + "dev": true, "license": "MIT", "dependencies": { "@jest/environment": "30.2.0", @@ -11049,6 +11234,7 @@ "version": "30.2.0", "resolved": "https://registry.npmjs.org/@jest/reporters/-/reporters-30.2.0.tgz", "integrity": "sha512-DRyW6baWPqKMa9CzeiBjHwjd8XeAyco2Vt8XbcLFjiwCOEKOvy82GJ8QQnJE9ofsxCMPjH4MfH8fCWIHHDKpAQ==", + "dev": true, "license": "MIT", "dependencies": { "@bcoe/v8-coverage": "^0.2.3", @@ -11091,6 +11277,7 @@ "version": "30.0.5", "resolved": "https://registry.npmjs.org/@jest/schemas/-/schemas-30.0.5.tgz", "integrity": "sha512-DmdYgtezMkh3cpU8/1uyXakv3tJRcmcXxBOcO0tbaozPwpmh4YMsnWrQm9ZmZMfa5ocbxzbFk6O4bDPEc/iAnA==", + "dev": true, "license": "MIT", "dependencies": { "@sinclair/typebox": "^0.34.0" @@ -11103,6 +11290,7 @@ "version": "30.0.1", "resolved": "https://registry.npmjs.org/@jest/source-map/-/source-map-30.0.1.tgz", "integrity": "sha512-MIRWMUUR3sdbP36oyNyhbThLHyJ2eEDClPCiHVbrYAe5g3CHRArIVpBw7cdSB5fr+ofSfIb2Tnsw8iEHL0PYQg==", + "dev": true, "license": "MIT", "dependencies": { "@jridgewell/trace-mapping": "^0.3.25", @@ -11117,6 +11305,7 @@ "version": "30.2.0", "resolved": "https://registry.npmjs.org/@jest/test-result/-/test-result-30.2.0.tgz", "integrity": "sha512-RF+Z+0CCHkARz5HT9mcQCBulb1wgCP3FBvl9VFokMX27acKphwyQsNuWH3c+ojd1LeWBLoTYoxF0zm6S/66mjg==", + "dev": true, "license": "MIT", "dependencies": { "@jest/console": "30.2.0", @@ -11132,6 +11321,7 @@ "version": "30.2.0", "resolved": "https://registry.npmjs.org/@jest/test-sequencer/-/test-sequencer-30.2.0.tgz", "integrity": "sha512-wXKgU/lk8fKXMu/l5Hog1R61bL4q5GCdT6OJvdAFz1P+QrpoFuLU68eoKuVc4RbrTtNnTL5FByhWdLgOPSph+Q==", + "dev": true, "license": "MIT", "dependencies": { "@jest/test-result": "30.2.0", @@ -11147,6 +11337,7 @@ "version": "30.2.0", "resolved": "https://registry.npmjs.org/@jest/transform/-/transform-30.2.0.tgz", "integrity": "sha512-XsauDV82o5qXbhalKxD7p4TZYYdwcaEXC77PPD2HixEFF+6YGppjrAAQurTl2ECWcEomHBMMNS9AH3kcCFx8jA==", + "dev": true, "license": "MIT", "dependencies": { "@babel/core": "^7.27.4", @@ -11173,6 +11364,7 @@ "version": "30.2.0", "resolved": "https://registry.npmjs.org/@jest/types/-/types-30.2.0.tgz", "integrity": "sha512-H9xg1/sfVvyfU7o3zMfBEjQ1gcsdeTMgqHoYdN79tuLqfTtuu7WckRA1R5whDwOzxaZAeMKTYWqP+WCAi0CHsg==", + "dev": true, "license": "MIT", "dependencies": { "@jest/pattern": "30.0.1", @@ -11191,12 +11383,14 @@ "version": "0.34.41", "resolved": "https://registry.npmjs.org/@sinclair/typebox/-/typebox-0.34.41.tgz", "integrity": "sha512-6gS8pZzSXdyRHTIqoqSVknxolr1kzfy4/CeDnrzsVz8TTIWUbOBr6gnzOmTYJ3eXQNh4IYHIGi5aIL7sOZ2G/g==", + "dev": true, "license": "MIT" }, "node_modules/@nx/jest/node_modules/@sinonjs/fake-timers": { "version": "13.0.5", "resolved": "https://registry.npmjs.org/@sinonjs/fake-timers/-/fake-timers-13.0.5.tgz", "integrity": "sha512-36/hTbH2uaWuGVERyC6da9YwGWnzUZXuPro/F2LfsdOsLnCojz/iSH8MxUt/FD2S5XBSVPhmArFUXcpCQ2Hkiw==", + "dev": true, "license": "BSD-3-Clause", "dependencies": { "@sinonjs/commons": "^3.0.1" @@ -11206,6 +11400,7 @@ "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, "license": "MIT", "engines": { "node": ">=10" @@ -11218,6 +11413,7 @@ "version": "30.2.0", "resolved": "https://registry.npmjs.org/babel-jest/-/babel-jest-30.2.0.tgz", "integrity": "sha512-0YiBEOxWqKkSQWL9nNGGEgndoeL0ZpWrbLMNL5u/Kaxrli3Eaxlt3ZtIDktEvXt4L/R9r3ODr2zKwGM/2BjxVw==", + "dev": true, "license": "MIT", "dependencies": { "@jest/transform": "30.2.0", @@ -11239,6 +11435,7 @@ "version": "7.0.1", "resolved": "https://registry.npmjs.org/babel-plugin-istanbul/-/babel-plugin-istanbul-7.0.1.tgz", "integrity": "sha512-D8Z6Qm8jCvVXtIRkBnqNHX0zJ37rQcFJ9u8WOS6tkYOsRdHBzypCstaxWiu5ZIlqQtviRYbgnRLSoCEvjqcqbA==", + "dev": true, "license": "BSD-3-Clause", "workspaces": [ "test/babel-8" @@ -11258,6 +11455,7 @@ "version": "30.2.0", "resolved": "https://registry.npmjs.org/babel-plugin-jest-hoist/-/babel-plugin-jest-hoist-30.2.0.tgz", "integrity": "sha512-ftzhzSGMUnOzcCXd6WHdBGMyuwy15Wnn0iyyWGKgBDLxf9/s5ABuraCSpBX2uG0jUg4rqJnxsLc5+oYBqoxVaA==", + "dev": true, "license": "MIT", "dependencies": { "@types/babel__core": "^7.20.5" @@ -11270,6 +11468,7 @@ "version": "30.2.0", "resolved": "https://registry.npmjs.org/babel-preset-jest/-/babel-preset-jest-30.2.0.tgz", "integrity": "sha512-US4Z3NOieAQumwFnYdUWKvUKh8+YSnS/gB3t6YBiz0bskpu7Pine8pPCheNxlPEW4wnUkma2a94YuW2q3guvCQ==", + "dev": true, "license": "MIT", "dependencies": { "babel-plugin-jest-hoist": "30.2.0", @@ -11286,6 +11485,7 @@ "version": "6.3.0", "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-6.3.0.tgz", "integrity": "sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA==", + "dev": true, "license": "MIT", "engines": { "node": ">=10" @@ -11298,6 +11498,7 @@ "version": "4.3.1", "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-4.3.1.tgz", "integrity": "sha512-Wdy2Igu8OcBpI2pZePZ5oWjPC38tmDVx5WKUXKwlLYkA0ozo85sLsLvkBbBn/sZaSCMFOGZJ14fvW9t5/d7kdA==", + "dev": true, "funding": [ { "type": "github", @@ -11313,18 +11514,21 @@ "version": "2.1.1", "resolved": "https://registry.npmjs.org/cjs-module-lexer/-/cjs-module-lexer-2.1.1.tgz", "integrity": "sha512-+CmxIZ/L2vNcEfvNtLdU0ZQ6mbq3FZnwAP2PPTiKP+1QOoKwlKlPgb8UKV0Dds7QVaMnHm+FwSft2VB0s/SLjQ==", + "dev": true, "license": "MIT" }, "node_modules/@nx/jest/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, "license": "MIT" }, "node_modules/@nx/jest/node_modules/expect": { "version": "30.2.0", "resolved": "https://registry.npmjs.org/expect/-/expect-30.2.0.tgz", "integrity": "sha512-u/feCi0GPsI+988gU2FLcsHyAHTU0MX1Wg68NhAnN7z/+C5wqG+CY8J53N9ioe8RXgaoz0nBR/TYMf3AycUuPw==", + "dev": true, "license": "MIT", "dependencies": { "@jest/expect-utils": "30.2.0", @@ -11342,6 +11546,7 @@ "version": "10.5.0", "resolved": "https://registry.npmjs.org/glob/-/glob-10.5.0.tgz", "integrity": "sha512-DfXN8DfhJ7NH3Oe7cFmu3NCu1wKbkReJ8TorzSAFbSKrlNaQSKfIzqYqVY8zlbs2NLBbWpRiU52GX2PbaBVNkg==", + "dev": true, "license": "ISC", "dependencies": { "foreground-child": "^3.1.0", @@ -11362,6 +11567,7 @@ "version": "9.0.5", "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.5.tgz", "integrity": "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==", + "dev": true, "license": "ISC", "dependencies": { "brace-expansion": "^2.0.1" @@ -11377,6 +11583,7 @@ "version": "5.0.6", "resolved": "https://registry.npmjs.org/istanbul-lib-source-maps/-/istanbul-lib-source-maps-5.0.6.tgz", "integrity": "sha512-yg2d+Em4KizZC5niWhQaIomgf5WlL4vOOjZ5xGCmF8SnPE/mDWWXgvRExdcpCgh9lLRRa1/fSYp2ymmbJ1pI+A==", + "dev": true, "license": "BSD-3-Clause", "dependencies": { "@jridgewell/trace-mapping": "^0.3.23", @@ -11391,6 +11598,7 @@ "version": "3.4.3", "resolved": "https://registry.npmjs.org/jackspeak/-/jackspeak-3.4.3.tgz", "integrity": "sha512-OGlZQpz2yfahA/Rd1Y8Cd9SIEsqvXkLVoSw/cgwhnhFMDbsQFeZYoJJ7bIZBS9BcamUW96asq/npPWugM+RQBw==", + "dev": true, "license": "BlueOak-1.0.0", "dependencies": { "@isaacs/cliui": "^8.0.2" @@ -11406,6 +11614,7 @@ "version": "30.2.0", "resolved": "https://registry.npmjs.org/jest-circus/-/jest-circus-30.2.0.tgz", "integrity": "sha512-Fh0096NC3ZkFx05EP2OXCxJAREVxj1BcW/i6EWqqymcgYKWjyyDpral3fMxVcHXg6oZM7iULer9wGRFvfpl+Tg==", + "dev": true, "license": "MIT", "dependencies": { "@jest/environment": "30.2.0", @@ -11437,6 +11646,7 @@ "version": "30.2.0", "resolved": "https://registry.npmjs.org/jest-config/-/jest-config-30.2.0.tgz", "integrity": "sha512-g4WkyzFQVWHtu6uqGmQR4CQxz/CH3yDSlhzXMWzNjDx843gYjReZnMRanjRCq5XZFuQrGDxgUaiYWE8BRfVckA==", + "dev": true, "license": "MIT", "dependencies": { "@babel/core": "^7.27.4", @@ -11488,6 +11698,7 @@ "version": "30.2.0", "resolved": "https://registry.npmjs.org/jest-docblock/-/jest-docblock-30.2.0.tgz", "integrity": "sha512-tR/FFgZKS1CXluOQzZvNH3+0z9jXr3ldGSD8bhyuxvlVUwbeLOGynkunvlTMxchC5urrKndYiwCFC0DLVjpOCA==", + "dev": true, "license": "MIT", "dependencies": { "detect-newline": "^3.1.0" @@ -11500,6 +11711,7 @@ "version": "30.2.0", "resolved": "https://registry.npmjs.org/jest-each/-/jest-each-30.2.0.tgz", "integrity": "sha512-lpWlJlM7bCUf1mfmuqTA8+j2lNURW9eNafOy99knBM01i5CQeY5UH1vZjgT9071nDJac1M4XsbyI44oNOdhlDQ==", + "dev": true, "license": "MIT", "dependencies": { "@jest/get-type": "30.1.0", @@ -11516,6 +11728,7 @@ "version": "30.2.0", "resolved": "https://registry.npmjs.org/jest-environment-node/-/jest-environment-node-30.2.0.tgz", "integrity": "sha512-ElU8v92QJ9UrYsKrxDIKCxu6PfNj4Hdcktcn0JX12zqNdqWHB0N+hwOnnBBXvjLd2vApZtuLUGs1QSY+MsXoNA==", + "dev": true, "license": "MIT", "dependencies": { "@jest/environment": "30.2.0", @@ -11534,6 +11747,7 @@ "version": "30.2.0", "resolved": "https://registry.npmjs.org/jest-haste-map/-/jest-haste-map-30.2.0.tgz", "integrity": "sha512-sQA/jCb9kNt+neM0anSj6eZhLZUIhQgwDt7cPGjumgLM4rXsfb9kpnlacmvZz3Q5tb80nS+oG/if+NBKrHC+Xw==", + "dev": true, "license": "MIT", "dependencies": { "@jest/types": "30.2.0", @@ -11558,6 +11772,7 @@ "version": "30.2.0", "resolved": "https://registry.npmjs.org/jest-leak-detector/-/jest-leak-detector-30.2.0.tgz", "integrity": "sha512-M6jKAjyzjHG0SrQgwhgZGy9hFazcudwCNovY/9HPIicmNSBuockPSedAP9vlPK6ONFJ1zfyH/M2/YYJxOz5cdQ==", + "dev": true, "license": "MIT", "dependencies": { "@jest/get-type": "30.1.0", @@ -11571,6 +11786,7 @@ "version": "30.2.0", "resolved": "https://registry.npmjs.org/jest-matcher-utils/-/jest-matcher-utils-30.2.0.tgz", "integrity": "sha512-dQ94Nq4dbzmUWkQ0ANAWS9tBRfqCrn0bV9AMYdOi/MHW726xn7eQmMeRTpX2ViC00bpNaWXq+7o4lIQ3AX13Hg==", + "dev": true, "license": "MIT", "dependencies": { "@jest/get-type": "30.1.0", @@ -11586,6 +11802,7 @@ "version": "30.2.0", "resolved": "https://registry.npmjs.org/jest-message-util/-/jest-message-util-30.2.0.tgz", "integrity": "sha512-y4DKFLZ2y6DxTWD4cDe07RglV88ZiNEdlRfGtqahfbIjfsw1nMCPx49Uev4IA/hWn3sDKyAnSPwoYSsAEdcimw==", + "dev": true, "license": "MIT", "dependencies": { "@babel/code-frame": "^7.27.1", @@ -11606,6 +11823,7 @@ "version": "30.2.0", "resolved": "https://registry.npmjs.org/jest-mock/-/jest-mock-30.2.0.tgz", "integrity": "sha512-JNNNl2rj4b5ICpmAcq+WbLH83XswjPbjH4T7yvGzfAGCPh1rw+xVNbtk+FnRslvt9lkCcdn9i1oAoKUuFsOxRw==", + "dev": true, "license": "MIT", "dependencies": { "@jest/types": "30.2.0", @@ -11620,6 +11838,7 @@ "version": "30.0.1", "resolved": "https://registry.npmjs.org/jest-regex-util/-/jest-regex-util-30.0.1.tgz", "integrity": "sha512-jHEQgBXAgc+Gh4g0p3bCevgRCVRkB4VB70zhoAE48gxeSr1hfUOsM/C2WoJgVL7Eyg//hudYENbm3Ne+/dRVVA==", + "dev": true, "license": "MIT", "engines": { "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" @@ -11629,6 +11848,7 @@ "version": "30.2.0", "resolved": "https://registry.npmjs.org/jest-resolve/-/jest-resolve-30.2.0.tgz", "integrity": "sha512-TCrHSxPlx3tBY3hWNtRQKbtgLhsXa1WmbJEqBlTBrGafd5fiQFByy2GNCEoGR+Tns8d15GaL9cxEzKOO3GEb2A==", + "dev": true, "license": "MIT", "dependencies": { "chalk": "^4.1.2", @@ -11648,6 +11868,7 @@ "version": "30.2.0", "resolved": "https://registry.npmjs.org/jest-runner/-/jest-runner-30.2.0.tgz", "integrity": "sha512-PqvZ2B2XEyPEbclp+gV6KO/F1FIFSbIwewRgmROCMBo/aZ6J1w8Qypoj2pEOcg3G2HzLlaP6VUtvwCI8dM3oqQ==", + "dev": true, "license": "MIT", "dependencies": { "@jest/console": "30.2.0", @@ -11681,6 +11902,7 @@ "version": "30.2.0", "resolved": "https://registry.npmjs.org/jest-runtime/-/jest-runtime-30.2.0.tgz", "integrity": "sha512-p1+GVX/PJqTucvsmERPMgCPvQJpFt4hFbM+VN3n8TMo47decMUcJbt+rgzwrEme0MQUA/R+1de2axftTHkKckg==", + "dev": true, "license": "MIT", "dependencies": { "@jest/environment": "30.2.0", @@ -11714,6 +11936,7 @@ "version": "30.2.0", "resolved": "https://registry.npmjs.org/jest-snapshot/-/jest-snapshot-30.2.0.tgz", "integrity": "sha512-5WEtTy2jXPFypadKNpbNkZ72puZCa6UjSr/7djeecHWOu7iYhSXSnHScT8wBz3Rn8Ena5d5RYRcsyKIeqG1IyA==", + "dev": true, "license": "MIT", "dependencies": { "@babel/core": "^7.27.4", @@ -11746,6 +11969,7 @@ "version": "30.2.0", "resolved": "https://registry.npmjs.org/jest-util/-/jest-util-30.2.0.tgz", "integrity": "sha512-QKNsM0o3Xe6ISQU869e+DhG+4CK/48aHYdJZGlFQVTjnbvgpcKyxpzk29fGiO7i/J8VENZ+d2iGnSsvmuHywlA==", + "dev": true, "license": "MIT", "dependencies": { "@jest/types": "30.2.0", @@ -11763,6 +11987,7 @@ "version": "30.2.0", "resolved": "https://registry.npmjs.org/jest-validate/-/jest-validate-30.2.0.tgz", "integrity": "sha512-FBGWi7dP2hpdi8nBoWxSsLvBFewKAg0+uSQwBaof4Y4DPgBabXgpSYC5/lR7VmnIlSpASmCi/ntRWPbv7089Pw==", + "dev": true, "license": "MIT", "dependencies": { "@jest/get-type": "30.1.0", @@ -11780,6 +12005,7 @@ "version": "30.2.0", "resolved": "https://registry.npmjs.org/jest-watcher/-/jest-watcher-30.2.0.tgz", "integrity": "sha512-PYxa28dxJ9g777pGm/7PrbnMeA0Jr7osHP9bS7eJy9DuAjMgdGtxgf0uKMyoIsTWAkIbUW5hSDdJ3urmgXBqxg==", + "dev": true, "license": "MIT", "dependencies": { "@jest/test-result": "30.2.0", @@ -11799,6 +12025,7 @@ "version": "30.2.0", "resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-30.2.0.tgz", "integrity": "sha512-0Q4Uk8WF7BUwqXHuAjc23vmopWJw5WH7w2tqBoUOZpOjW/ZnR44GXXd1r82RvnmI2GZge3ivrYXk/BE2+VtW2g==", + "dev": true, "license": "MIT", "dependencies": { "@types/node": "*", @@ -11815,12 +12042,14 @@ "version": "10.4.3", "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-10.4.3.tgz", "integrity": "sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ==", + "dev": true, "license": "ISC" }, "node_modules/@nx/jest/node_modules/path-scurry": { "version": "1.11.1", "resolved": "https://registry.npmjs.org/path-scurry/-/path-scurry-1.11.1.tgz", "integrity": "sha512-Xa4Nw17FS9ApQFJ9umLiJS4orGjm7ZzwUrwamcGQuHSzDyth9boKDaycYdDcZDuqYATXw4HFXgaqWTctW/v1HA==", + "dev": true, "license": "BlueOak-1.0.0", "dependencies": { "lru-cache": "^10.2.0", @@ -11837,6 +12066,7 @@ "version": "30.2.0", "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-30.2.0.tgz", "integrity": "sha512-9uBdv/B4EefsuAL+pWqueZyZS2Ba+LxfFeQ9DN14HU4bN8bhaxKdkpjpB6fs9+pSjIBu+FXQHImEg8j/Lw0+vA==", + "dev": true, "license": "MIT", "dependencies": { "@jest/schemas": "30.0.5", @@ -11851,6 +12081,7 @@ "version": "7.0.1", "resolved": "https://registry.npmjs.org/pure-rand/-/pure-rand-7.0.1.tgz", "integrity": "sha512-oTUZM/NAZS8p7ANR3SHh30kXB+zK2r2BPcEn/awJIbOvq82WoMN4p62AWWp3Hhw50G0xMsw1mhIBLqHw64EcNQ==", + "dev": true, "funding": [ { "type": "individual", @@ -11867,12 +12098,14 @@ "version": "18.3.1", "resolved": "https://registry.npmjs.org/react-is/-/react-is-18.3.1.tgz", "integrity": "sha512-/LLMVyas0ljjAtoYiPqYiL8VWXzUUdThrmU5+n20DZv+a+ClRoevUzw5JxU+Ieh5/c87ytoTBV9G1FiKfNJdmg==", + "dev": true, "license": "MIT" }, "node_modules/@nx/jest/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==", + "dev": true, "license": "BSD-3-Clause", "engines": { "node": ">=0.10.0" @@ -11882,6 +12115,7 @@ "version": "0.5.13", "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.13.tgz", "integrity": "sha512-SHSKFHadjVA5oR4PPqhtAVdcBWwRYVd6g6cAXnIbRiIwc2EhPrTuKUBdSLvlEKyIP3GCf89fltvcZiP9MMFA1w==", + "dev": true, "license": "MIT", "dependencies": { "buffer-from": "^1.0.0", @@ -11892,6 +12126,7 @@ "version": "8.1.1", "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz", "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==", + "dev": true, "license": "MIT", "dependencies": { "has-flag": "^4.0.0" @@ -11907,6 +12142,7 @@ "version": "5.0.1", "resolved": "https://registry.npmjs.org/write-file-atomic/-/write-file-atomic-5.0.1.tgz", "integrity": "sha512-+QU2zd6OTD8XWIJCbffaiQeH9U73qIqafo1x6V1snCWYGJf6cVE0cDR4D8xRzcEnfI21IFrUPzPGtcPf8AC+Rw==", + "dev": true, "license": "ISC", "dependencies": { "imurmurhash": "^0.1.4", @@ -11920,6 +12156,7 @@ "version": "21.6.10", "resolved": "https://registry.npmjs.org/@nx/js/-/js-21.6.10.tgz", "integrity": "sha512-8d+Q5v/9/he8mq6aRfhHWORZb/WkJ7OTegF4QX2g+yVkocEKIyuUx/BC9rGBRvlZpB2xcJlU9kNcfrhuoKbehQ==", + "dev": true, "license": "MIT", "dependencies": { "@babel/core": "^7.23.2", @@ -11965,6 +12202,7 @@ "version": "7.0.2", "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-7.0.2.tgz", "integrity": "sha512-puUZAUKT5m8Zzvs72XWy3HtvVbTWljRE66cP60bxJzAqf2DgICo7lYTY2IHUmLnNpjYvw5bvmoHvPc0QO2a62w==", + "dev": true, "license": "ISC", "dependencies": { "lru-cache": "^10.0.1" @@ -11977,6 +12215,7 @@ "version": "5.3.2", "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.3.2.tgz", "integrity": "sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g==", + "dev": true, "license": "MIT", "engines": { "node": ">= 4" @@ -11986,18 +12225,21 @@ "version": "3.2.0", "resolved": "https://registry.npmjs.org/jsonc-parser/-/jsonc-parser-3.2.0.tgz", "integrity": "sha512-gfFQZrcTc8CnKXp6Y4/CBT3fTc0OVuDofpre4aEeEpSBPV5X5v4+Vmx+8snU7RLPrNHPKSgLxGo9YuQzz20o+w==", + "dev": true, "license": "MIT" }, "node_modules/@nx/js/node_modules/lru-cache": { "version": "10.4.3", "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-10.4.3.tgz", "integrity": "sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ==", + "dev": true, "license": "ISC" }, "node_modules/@nx/js/node_modules/npm-package-arg": { "version": "11.0.1", "resolved": "https://registry.npmjs.org/npm-package-arg/-/npm-package-arg-11.0.1.tgz", "integrity": "sha512-M7s1BD4NxdAvBKUPqqRW957Xwcl/4Zvo8Aj+ANrzvIPzGJZElrH7Z//rSaec2ORcND6FHHLnZeY8qgTpXDMFQQ==", + "dev": true, "license": "ISC", "dependencies": { "hosted-git-info": "^7.0.0", @@ -12013,6 +12255,7 @@ "version": "5.3.0", "resolved": "https://registry.npmjs.org/ora/-/ora-5.3.0.tgz", "integrity": "sha512-zAKMgGXUim0Jyd6CXK9lraBnD3H5yPGBPPOkC23a2BG6hsm4Zu6OQSjQuEtV0BHDf4aKHcUFvJiGRrFuW3MG8g==", + "dev": true, "license": "MIT", "dependencies": { "bl": "^4.0.3", @@ -12035,6 +12278,7 @@ "version": "3.0.0", "resolved": "https://registry.npmjs.org/proc-log/-/proc-log-3.0.0.tgz", "integrity": "sha512-++Vn7NS4Xf9NacaU9Xq3URUuqZETPsf8L4j5/ckhaRYsfPeRyzGw+iDjFhV/Jr3uNmTvvddEJFWh5R1gRgUH8A==", + "dev": true, "license": "ISC", "engines": { "node": "^14.17.0 || ^16.13.0 || >=18.0.0" @@ -12044,6 +12288,7 @@ "version": "0.6.1", "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true, "license": "BSD-3-Clause", "engines": { "node": ">=0.10.0" @@ -12053,6 +12298,7 @@ "version": "0.5.19", "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.19.tgz", "integrity": "sha512-Wonm7zOCIJzBGQdB+thsPar0kYuCIzYvxZwlBa87yi/Mdjv7Tip2cyVbLj5o0cFPN4EVkuTwb3GDDyUx2DGnGw==", + "dev": true, "license": "MIT", "dependencies": { "buffer-from": "^1.0.0", @@ -12063,6 +12309,7 @@ "version": "5.0.1", "resolved": "https://registry.npmjs.org/validate-npm-package-name/-/validate-npm-package-name-5.0.1.tgz", "integrity": "sha512-OljLrQ9SQdOUqTaQxqL5dEfZWrXExyyWsozYlAWFawPVNuD83igl7uJD2RTkNMbniIYgt8l81eCJGIdQF7avLQ==", + "dev": true, "license": "ISC", "engines": { "node": "^14.17.0 || ^16.13.0 || >=18.0.0" @@ -12075,6 +12322,7 @@ "cpu": [ "arm64" ], + "dev": true, "license": "MIT", "optional": true, "os": [ @@ -12088,6 +12336,7 @@ "cpu": [ "x64" ], + "dev": true, "license": "MIT", "optional": true, "os": [ @@ -12101,6 +12350,7 @@ "cpu": [ "x64" ], + "dev": true, "license": "MIT", "optional": true, "os": [ @@ -12114,6 +12364,7 @@ "cpu": [ "arm" ], + "dev": true, "license": "MIT", "optional": true, "os": [ @@ -12127,6 +12378,7 @@ "cpu": [ "arm64" ], + "dev": true, "license": "MIT", "optional": true, "os": [ @@ -12140,6 +12392,7 @@ "cpu": [ "arm64" ], + "dev": true, "license": "MIT", "optional": true, "os": [ @@ -12153,6 +12406,7 @@ "cpu": [ "x64" ], + "dev": true, "license": "MIT", "optional": true, "os": [ @@ -12166,6 +12420,7 @@ "cpu": [ "x64" ], + "dev": true, "license": "MIT", "optional": true, "os": [ @@ -12179,6 +12434,7 @@ "cpu": [ "arm64" ], + "dev": true, "license": "MIT", "optional": true, "os": [ @@ -12192,6 +12448,7 @@ "cpu": [ "x64" ], + "dev": true, "license": "MIT", "optional": true, "os": [ @@ -12202,6 +12459,7 @@ "version": "21.6.10", "resolved": "https://registry.npmjs.org/@nx/webpack/-/webpack-21.6.10.tgz", "integrity": "sha512-T+eB9c3lflqWuegrsW47zzkZlSQ6YNEucEknUpWyDrKLCihucKe9siuj5s2gPkgdY6DXX4sjZcA5xgnxHNBWag==", + "dev": true, "license": "MIT", "dependencies": { "@babel/core": "^7.23.2", @@ -12246,6 +12504,7 @@ "version": "1.1.12", "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.12.tgz", "integrity": "sha512-9T9UjW3r0UW5c1Q7GTwllptXwhvYmEzFhzMfZ9H7FQWt+uZePjZPjBP/W1ZEyZ1twGWom5/56TF4lPcqjnDHcg==", + "dev": true, "license": "MIT", "dependencies": { "balanced-match": "^1.0.0", @@ -12256,6 +12515,7 @@ "version": "3.6.0", "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.6.0.tgz", "integrity": "sha512-7VT13fmjotKpGipCW9JEQAusEPE+Ei8nl6/g4FBAmIm0GOOLMua9NDDo/DWp0ZAxCr3cPq5ZpBqmPAQgDda2Pw==", + "dev": true, "license": "MIT", "dependencies": { "anymatch": "~3.1.2", @@ -12280,6 +12540,7 @@ "version": "5.1.2", "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", + "dev": true, "license": "ISC", "dependencies": { "is-glob": "^4.0.1" @@ -12292,6 +12553,7 @@ "version": "10.2.4", "resolved": "https://registry.npmjs.org/copy-webpack-plugin/-/copy-webpack-plugin-10.2.4.tgz", "integrity": "sha512-xFVltahqlsRcyyJqQbDY6EYTtyQZF9rf+JPjwHObLdPFMEISqkFkr7mFoVOC6BfYS/dNThyoQKvziugm+OnwBg==", + "dev": true, "license": "MIT", "dependencies": { "fast-glob": "^3.2.7", @@ -12316,6 +12578,7 @@ "version": "7.1.0", "resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-7.1.0.tgz", "integrity": "sha512-AdmX6xUzdNASswsFtmwSt7Vj8po9IuqXm0UXz7QKPuEUmPB4XyjGfaAr2PSuELMwkRMVH1EpIkX5bTZGRB3eCA==", + "dev": true, "license": "MIT", "dependencies": { "@types/parse-json": "^4.0.0", @@ -12332,6 +12595,7 @@ "version": "6.11.0", "resolved": "https://registry.npmjs.org/css-loader/-/css-loader-6.11.0.tgz", "integrity": "sha512-CTJ+AEQJjq5NzLga5pE39qdiSV56F8ywCIsqNIRF0r7BDgWsN25aazToqAFg7ZrtA/U016xudB3ffgweORxX7g==", + "dev": true, "license": "MIT", "dependencies": { "icss-utils": "^5.1.0", @@ -12367,6 +12631,7 @@ "version": "7.2.13", "resolved": "https://registry.npmjs.org/fork-ts-checker-webpack-plugin/-/fork-ts-checker-webpack-plugin-7.2.13.tgz", "integrity": "sha512-fR3WRkOb4bQdWB/y7ssDUlVdrclvwtyCUIHCfivAoYxq9dF7XfrDKbMdZIfwJ7hxIAqkYSGeU7lLJE6xrxIBdg==", + "dev": true, "license": "MIT", "dependencies": { "@babel/code-frame": "^7.16.7", @@ -12401,6 +12666,7 @@ "version": "6.12.6", "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", + "dev": true, "license": "MIT", "dependencies": { "fast-deep-equal": "^3.1.1", @@ -12417,6 +12683,7 @@ "version": "3.5.2", "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-3.5.2.tgz", "integrity": "sha512-5p6WTN0DdTGVQk6VjcEju19IgaHudalcfabD7yhDGeA6bcQnmL+CpveLJq/3hvfwd1aof6L386Ougkx6RfyMIQ==", + "dev": true, "license": "MIT", "peerDependencies": { "ajv": "^6.9.1" @@ -12426,6 +12693,7 @@ "version": "3.3.0", "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-3.3.0.tgz", "integrity": "sha512-pN/yOAvcC+5rQ5nERGuwrjLlYvLTbCibnZ1I7B1LaiAz9BRBlE9GMgE/eqV30P7aJQUf7Ddimy/RsbYO/GrVGg==", + "dev": true, "license": "MIT", "dependencies": { "@types/json-schema": "^7.0.8", @@ -12444,6 +12712,7 @@ "version": "10.1.0", "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-10.1.0.tgz", "integrity": "sha512-oRXApq54ETRj4eMiFzGnHWGy+zo5raudjuxN0b8H7s/RU2oW0Wvsx9O0ACRN/kRq9E8Vu/ReskGB5o3ji+FzHQ==", + "dev": true, "license": "MIT", "dependencies": { "graceful-fs": "^4.2.0", @@ -12458,12 +12727,14 @@ "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, "license": "MIT" }, "node_modules/@nx/webpack/node_modules/less-loader": { "version": "11.1.4", "resolved": "https://registry.npmjs.org/less-loader/-/less-loader-11.1.4.tgz", "integrity": "sha512-6/GrYaB6QcW6Vj+/9ZPgKKs6G10YZai/l/eJ4SLwbzqNTBsAqt5hSLVF47TgsiBxV1P6eAU0GYRH3YRuQU9V3A==", + "dev": true, "license": "MIT", "engines": { "node": ">= 14.15.0" @@ -12481,6 +12752,7 @@ "version": "2.0.4", "resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-2.0.4.tgz", "integrity": "sha512-xXqpXoINfFhgua9xiqD8fPFHgkoq1mmmpE92WlDbm9rNRd/EbRb+Gqf908T2DMfuHjjJlksiK2RbHVOdD/MqSw==", + "dev": true, "license": "MIT", "dependencies": { "big.js": "^5.2.2", @@ -12495,6 +12767,7 @@ "version": "2.4.7", "resolved": "https://registry.npmjs.org/mini-css-extract-plugin/-/mini-css-extract-plugin-2.4.7.tgz", "integrity": "sha512-euWmddf0sk9Nv1O0gfeeUAvAkoSlWncNLF77C0TP2+WoPvy8mAHKOzMajcCz2dzvyt3CNgxb1obIEVFIRxaipg==", + "dev": true, "license": "MIT", "dependencies": { "schema-utils": "^4.0.0" @@ -12514,6 +12787,7 @@ "version": "3.1.2", "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "dev": true, "license": "ISC", "dependencies": { "brace-expansion": "^1.1.7" @@ -12526,12 +12800,14 @@ "version": "4.0.0", "resolved": "https://registry.npmjs.org/parse5/-/parse5-4.0.0.tgz", "integrity": "sha512-VrZ7eOd3T1Fk4XWNXMgiGBK/z0MG48BWG2uQNU4I72fkQuKUTZpl+u9k+CxEG0twMVzSmXEEz12z5Fnw1jIQFA==", + "dev": true, "license": "MIT" }, "node_modules/@nx/webpack/node_modules/picomatch": { "version": "2.3.1", "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", + "dev": true, "license": "MIT", "engines": { "node": ">=8.6" @@ -12544,6 +12820,7 @@ "version": "14.1.0", "resolved": "https://registry.npmjs.org/postcss-import/-/postcss-import-14.1.0.tgz", "integrity": "sha512-flwI+Vgm4SElObFVPpTIT7SU7R3qk2L7PyduMcokiaVKuWv9d/U+Gm/QAd8NDLuykTWTkcrjOeD2Pp1rMeBTGw==", + "dev": true, "license": "MIT", "dependencies": { "postcss-value-parser": "^4.0.0", @@ -12561,6 +12838,7 @@ "version": "6.2.1", "resolved": "https://registry.npmjs.org/postcss-loader/-/postcss-loader-6.2.1.tgz", "integrity": "sha512-WbbYpmAaKcux/P66bZ40bpWsBucjx/TTgVVzRZ9yUO8yQfVBlameJ0ZGVaPfH64hNSBh63a+ICP5nqOpBA0w+Q==", + "dev": true, "license": "MIT", "dependencies": { "cosmiconfig": "^7.0.0", @@ -12583,6 +12861,7 @@ "version": "3.6.0", "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz", "integrity": "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==", + "dev": true, "license": "MIT", "dependencies": { "picomatch": "^2.2.1" @@ -12595,6 +12874,7 @@ "version": "3.3.4", "resolved": "https://registry.npmjs.org/style-loader/-/style-loader-3.3.4.tgz", "integrity": "sha512-0WqXzrsMTyb8yjZJHDqwmnwRJvhALK9LfRtRc6B4UTWe8AijYLZYZ9thuJTZc2VfQWINADW/j+LiJnfy2RoC1w==", + "dev": true, "license": "MIT", "engines": { "node": ">= 12.13.0" @@ -12611,6 +12891,7 @@ "version": "1.10.2", "resolved": "https://registry.npmjs.org/yaml/-/yaml-1.10.2.tgz", "integrity": "sha512-r3vXyErRCYJ7wg28yvBY5VSoAF8ZvlcW9/BwUzEtUsjvX/DKs24dIkuwjtuprwJJHsbyUbLApepYTR1BN4uHrg==", + "dev": true, "license": "ISC", "engines": { "node": ">= 6" @@ -12620,6 +12901,7 @@ "version": "21.6.10", "resolved": "https://registry.npmjs.org/@nx/workspace/-/workspace-21.6.10.tgz", "integrity": "sha512-6OkXs4gAVjDtrfqhJf7lHZX/VlCFLRZpywfgvmije40wrExkJDNEHx3Gf6dvSVwl0vE6Gz8D2t6luO02hGGz4w==", + "dev": true, "license": "MIT", "dependencies": { "@nx/devkit": "21.6.10", @@ -12803,6 +13085,7 @@ "version": "2.5.1", "resolved": "https://registry.npmjs.org/@parcel/watcher/-/watcher-2.5.1.tgz", "integrity": "sha512-dfUnCxiN9H4ap84DvD2ubjw+3vUNpstxa0TneY/Paat8a3R4uQZDLSvWjmznAY/DoahqTHl9V46HF/Zs3F29pg==", + "dev": true, "hasInstallScript": true, "license": "MIT", "optional": true, @@ -12842,6 +13125,7 @@ "cpu": [ "arm64" ], + "dev": true, "license": "MIT", "optional": true, "os": [ @@ -12862,6 +13146,7 @@ "cpu": [ "arm64" ], + "dev": true, "license": "MIT", "optional": true, "os": [ @@ -12882,6 +13167,7 @@ "cpu": [ "x64" ], + "dev": true, "license": "MIT", "optional": true, "os": [ @@ -12902,6 +13188,7 @@ "cpu": [ "x64" ], + "dev": true, "license": "MIT", "optional": true, "os": [ @@ -12922,6 +13209,7 @@ "cpu": [ "arm" ], + "dev": true, "license": "MIT", "optional": true, "os": [ @@ -12942,6 +13230,7 @@ "cpu": [ "arm" ], + "dev": true, "license": "MIT", "optional": true, "os": [ @@ -12962,6 +13251,7 @@ "cpu": [ "arm64" ], + "dev": true, "license": "MIT", "optional": true, "os": [ @@ -12982,6 +13272,7 @@ "cpu": [ "arm64" ], + "dev": true, "license": "MIT", "optional": true, "os": [ @@ -13002,6 +13293,7 @@ "cpu": [ "x64" ], + "dev": true, "license": "MIT", "optional": true, "os": [ @@ -13022,6 +13314,7 @@ "cpu": [ "x64" ], + "dev": true, "license": "MIT", "optional": true, "os": [ @@ -13042,6 +13335,7 @@ "cpu": [ "arm64" ], + "dev": true, "license": "MIT", "optional": true, "os": [ @@ -13062,6 +13356,7 @@ "cpu": [ "ia32" ], + "dev": true, "license": "MIT", "optional": true, "os": [ @@ -13082,6 +13377,7 @@ "cpu": [ "x64" ], + "dev": true, "license": "MIT", "optional": true, "os": [ @@ -13099,6 +13395,7 @@ "version": "1.0.3", "resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-1.0.3.tgz", "integrity": "sha512-pGjwhsmsp4kL2RTz08wcOlGN83otlqHeD/Z5T8GXZB+/YcpQ/dgo+lbU8ZsGxV0HIvqqxo9l7mqYwyYMD9bKDg==", + "dev": true, "license": "Apache-2.0", "optional": true, "bin": { @@ -13112,6 +13409,7 @@ "version": "7.1.1", "resolved": "https://registry.npmjs.org/node-addon-api/-/node-addon-api-7.1.1.tgz", "integrity": "sha512-5m3bsyrjFWE1xf7nz7YXdN4udnVtXK6/Yfgn5qnahL6bCkf2yKt4k3nuTKAtT4r3IG8JNR2ncsIMdZuAzJjHQQ==", + "dev": true, "license": "MIT", "optional": true }, @@ -13149,6 +13447,7 @@ "version": "5.0.1", "resolved": "https://registry.npmjs.org/@phenomnomnominal/tsquery/-/tsquery-5.0.1.tgz", "integrity": "sha512-3nVv+e2FQwsW8Aw6qTU6f+1rfcJ3hrcnvH/mu9i8YhxO+9sqbOfpL8m6PbET5+xKOlz/VSbp0RoYWYCtIsnmuA==", + "dev": true, "license": "MIT", "dependencies": { "esquery": "^1.4.0" @@ -13161,6 +13460,7 @@ "version": "0.11.0", "resolved": "https://registry.npmjs.org/@pkgjs/parseargs/-/parseargs-0.11.0.tgz", "integrity": "sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg==", + "dev": true, "license": "MIT", "optional": true, "engines": { @@ -13171,6 +13471,7 @@ "version": "0.2.9", "resolved": "https://registry.npmjs.org/@pkgr/core/-/core-0.2.9.tgz", "integrity": "sha512-QNqXyfVS2wm9hweSYD2O7F0G06uurj9kZ96TRQE5Y9hU7+tgdZwIkbAKc5Ocy1HxEY2kuDQa6cQ1WRs/O5LFKA==", + "dev": true, "license": "MIT", "engines": { "node": "^12.20.0 || ^14.18.0 || >=16.0.0" @@ -13926,6 +14227,7 @@ "version": "0.27.8", "resolved": "https://registry.npmjs.org/@sinclair/typebox/-/typebox-0.27.8.tgz", "integrity": "sha512-+Fj43pSMwJs4KRrH/938Uf+uAELIgVBmQzg/q1YG10djyfA3TnrU8N8XzqCh/okZdszqBQTZf96idMfE5lnwTA==", + "dev": true, "license": "MIT" }, "node_modules/@sindresorhus/is": { @@ -13945,6 +14247,7 @@ "version": "3.0.1", "resolved": "https://registry.npmjs.org/@sinonjs/commons/-/commons-3.0.1.tgz", "integrity": "sha512-K3mCHKQ9sVh8o1C9cxkwxaOmXoAMlDxC1mYyHrjqOWEcBjYr76t96zL2zlj5dUGZ3HSw240X1qgH3Mjf1yJWpQ==", + "dev": true, "license": "BSD-3-Clause", "dependencies": { "type-detect": "4.0.8" @@ -14828,6 +15131,7 @@ "version": "0.2.0", "resolved": "https://registry.npmjs.org/@trysound/sax/-/sax-0.2.0.tgz", "integrity": "sha512-L7z9BgrNEcYyUYtF+HaEfiS5ebkh9jXqbszz7pC0hRBPaatV0XjSD3+eHrpqFemQfgwiFF0QPIarnIihIDn7OA==", + "dev": true, "license": "ISC", "engines": { "node": ">=10.13.0" @@ -14929,6 +15233,7 @@ "version": "0.9.0", "resolved": "https://registry.npmjs.org/@tybys/wasm-util/-/wasm-util-0.9.0.tgz", "integrity": "sha512-6+7nlbMVX/PVDCwaIQ8nTOPveOcFLSt8GcXdx8hD0bt39uWxYT88uXzqTd4fTvqta7oeUJqudepapKNt2DYJFw==", + "dev": true, "license": "MIT", "dependencies": { "tslib": "^2.4.0" @@ -14956,6 +15261,7 @@ "version": "7.20.5", "resolved": "https://registry.npmjs.org/@types/babel__core/-/babel__core-7.20.5.tgz", "integrity": "sha512-qoQprZvz5wQFJwMDqeseRXWv3rqMvhgpbXFfVyWhbx9X47POIA6i/+dXefEmZKoAgOaTdaIgNSMqMIU61yRyzA==", + "dev": true, "license": "MIT", "dependencies": { "@babel/parser": "^7.20.7", @@ -14969,6 +15275,7 @@ "version": "7.27.0", "resolved": "https://registry.npmjs.org/@types/babel__generator/-/babel__generator-7.27.0.tgz", "integrity": "sha512-ufFd2Xi92OAVPYsy+P4n7/U7e68fex0+Ee8gSG9KX7eo084CWiQ4sdxktvdl0bOPupXtVJPY19zk6EwWqUQ8lg==", + "dev": true, "license": "MIT", "dependencies": { "@babel/types": "^7.0.0" @@ -14978,6 +15285,7 @@ "version": "7.4.4", "resolved": "https://registry.npmjs.org/@types/babel__template/-/babel__template-7.4.4.tgz", "integrity": "sha512-h/NUaSyG5EyxBIp8YRxo4RMe2/qQgvyowRwVMzhYhBCONbW8PUsg4lkFMrhgZhUe5z3L3MiLDuvyJ/CaPa2A8A==", + "dev": true, "license": "MIT", "dependencies": { "@babel/parser": "^7.1.0", @@ -14988,6 +15296,7 @@ "version": "7.20.7", "resolved": "https://registry.npmjs.org/@types/babel__traverse/-/babel__traverse-7.20.7.tgz", "integrity": "sha512-dkO5fhS7+/oos4ciWxyEyjWe48zmG6wbCheo/G2ZnHx4fs3EU6YC6UM8rk56gAjNJ9P3MTH2jo5jb92/K6wbng==", + "dev": true, "license": "MIT", "dependencies": { "@babel/types": "^7.20.7" @@ -14997,6 +15306,7 @@ "version": "1.19.6", "resolved": "https://registry.npmjs.org/@types/body-parser/-/body-parser-1.19.6.tgz", "integrity": "sha512-HLFeCYgz89uk22N5Qg3dvGvsv46B8GLvKKo1zKG4NybA8U2DiEO3w9lqGg29t/tfLRJpJ6iQxnVw4OnB7MoM9g==", + "dev": true, "license": "MIT", "dependencies": { "@types/connect": "*", @@ -15007,6 +15317,7 @@ "version": "3.5.13", "resolved": "https://registry.npmjs.org/@types/bonjour/-/bonjour-3.5.13.tgz", "integrity": "sha512-z9fJ5Im06zvUL548KvYNecEVlA7cVDkGUi6kZusb04mpyEFKCIZJvloCcmpmLaIahDpOQGHaHmG6imtPMmPXGQ==", + "dev": true, "license": "MIT", "dependencies": { "@types/node": "*" @@ -15051,6 +15362,7 @@ "version": "3.4.38", "resolved": "https://registry.npmjs.org/@types/connect/-/connect-3.4.38.tgz", "integrity": "sha512-K6uROf1LD88uDQqJCktA4yzL1YYAK6NgfsI0v/mTgyPKWsX1CnJ0XPSDhViejru1GcRkLWb8RlzFYJRqGUbaug==", + "dev": true, "license": "MIT", "dependencies": { "@types/node": "*" @@ -15060,6 +15372,7 @@ "version": "1.5.4", "resolved": "https://registry.npmjs.org/@types/connect-history-api-fallback/-/connect-history-api-fallback-1.5.4.tgz", "integrity": "sha512-n6Cr2xS1h4uAulPRdlw6Jl6s1oG8KrVilPN2yUITEs+K48EzMJJ3W1xy8K5eWuFvjp3R74AOIGSmp2UfBJ8HFw==", + "dev": true, "license": "MIT", "dependencies": { "@types/express-serve-static-core": "*", @@ -15107,6 +15420,7 @@ "version": "9.6.1", "resolved": "https://registry.npmjs.org/@types/eslint/-/eslint-9.6.1.tgz", "integrity": "sha512-FXx2pKgId/WyYo2jXw63kk7/+TY7u7AziEJxJAnSFzHlqTAS3Ync6SvgYAN/k4/PQpnnVuzoMuVnByKK2qp0ag==", + "dev": true, "license": "MIT", "dependencies": { "@types/estree": "*", @@ -15117,6 +15431,7 @@ "version": "3.7.7", "resolved": "https://registry.npmjs.org/@types/eslint-scope/-/eslint-scope-3.7.7.tgz", "integrity": "sha512-MzMFlSLBqNF2gcHWO0G1vP/YQyfvrxZ0bF+u7mzUdZ1/xK4A4sru+nraZz5i3iEIk1l1uyicaDVTB4QbbEkAYg==", + "dev": true, "license": "MIT", "dependencies": { "@types/eslint": "*", @@ -15127,12 +15442,14 @@ "version": "1.0.8", "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.8.tgz", "integrity": "sha512-dWHzHa2WqEXI/O1E9OjrocMTKJl2mSrEolh1Iomrv6U+JuNwaHXsXx9bLu5gG7BUWFIN0skIQJQ/L1rIex4X6w==", + "devOptional": true, "license": "MIT" }, "node_modules/@types/express": { "version": "5.0.3", "resolved": "https://registry.npmjs.org/@types/express/-/express-5.0.3.tgz", "integrity": "sha512-wGA0NX93b19/dZC1J18tKWVIYWyyF2ZjT9vin/NRu0qzzvfVzWjs04iq2rQ3H65vCTQYlRqs3YHfY7zjdV+9Kw==", + "dev": true, "license": "MIT", "dependencies": { "@types/body-parser": "*", @@ -15144,6 +15461,7 @@ "version": "5.0.6", "resolved": "https://registry.npmjs.org/@types/express-serve-static-core/-/express-serve-static-core-5.0.6.tgz", "integrity": "sha512-3xhRnjJPkULekpSzgtoNYYcTWgEZkp4myc+Saevii5JPnHNvHMRlBSHDbs7Bh1iPPoVTERHEZXyhyLbMEsExsA==", + "dev": true, "license": "MIT", "dependencies": { "@types/node": "*", @@ -15190,7 +15508,7 @@ "version": "4.1.9", "resolved": "https://registry.npmjs.org/@types/graceful-fs/-/graceful-fs-4.1.9.tgz", "integrity": "sha512-olP3sd1qOEe5dXTSaFvQG+02VdRXcdytWLAZsAq1PecU8uqQAhkrnbli7DagjtXKW/Bl7YJbUsa8MPcuc8LHEQ==", - "devOptional": true, + "dev": true, "license": "MIT", "dependencies": { "@types/node": "*" @@ -15215,7 +15533,7 @@ "version": "6.1.0", "resolved": "https://registry.npmjs.org/@types/html-minifier-terser/-/html-minifier-terser-6.1.0.tgz", "integrity": "sha512-oh/6byDPnL1zeNXFrDXFLyZjkr1MsBG667IM792caf1L2UPOOMf65NFzjUH/ltyfwjAGfs1rsX1eftK0jC/KIg==", - "devOptional": true, + "dev": true, "license": "MIT" }, "node_modules/@types/http-assert": { @@ -15236,12 +15554,14 @@ "version": "2.0.5", "resolved": "https://registry.npmjs.org/@types/http-errors/-/http-errors-2.0.5.tgz", "integrity": "sha512-r8Tayk8HJnX0FztbZN7oVqGccWgw98T/0neJphO91KkmOzug1KkofZURD4UaD5uH8AqcFLfdPErnBod0u71/qg==", + "dev": true, "license": "MIT" }, "node_modules/@types/http-proxy": { "version": "1.17.16", "resolved": "https://registry.npmjs.org/@types/http-proxy/-/http-proxy-1.17.16.tgz", "integrity": "sha512-sdWoUajOB1cd0A8cRRQ1cfyWNbmFKLAqBB89Y8x5iYyG/mkJHc0YUH8pdWBy2omi9qtCpiIgGjuwO0dQST2l5w==", + "dev": true, "license": "MIT", "dependencies": { "@types/node": "*" @@ -15262,12 +15582,14 @@ "version": "2.0.6", "resolved": "https://registry.npmjs.org/@types/istanbul-lib-coverage/-/istanbul-lib-coverage-2.0.6.tgz", "integrity": "sha512-2QF/t/auWm0lsy8XtKVPG19v3sSOQlJe/YHZgfjb/KBBHOGSV+J2q/S671rcq9uTBrLAXmZpqJiaQbMT+zNU1w==", + "dev": true, "license": "MIT" }, "node_modules/@types/istanbul-lib-report": { "version": "3.0.3", "resolved": "https://registry.npmjs.org/@types/istanbul-lib-report/-/istanbul-lib-report-3.0.3.tgz", "integrity": "sha512-NQn7AHQnk/RSLOxrBbGyJM/aVQ+pjj5HCgasFxc0K/KhoATfQ/47AyUl15I2yBUpihjmas+a+VJBOqecrFH+uA==", + "dev": true, "license": "MIT", "dependencies": { "@types/istanbul-lib-coverage": "*" @@ -15277,6 +15599,7 @@ "version": "3.0.4", "resolved": "https://registry.npmjs.org/@types/istanbul-reports/-/istanbul-reports-3.0.4.tgz", "integrity": "sha512-pk2B1NWalF9toCRu6gjBzR69syFjP4Od8WRAX+0mmf9lAjCRicLOWc+ZrxZHx/0XRjotgkF9t6iaMJ+aXcOdZQ==", + "dev": true, "license": "MIT", "dependencies": { "@types/istanbul-lib-report": "*" @@ -15344,6 +15667,7 @@ "version": "7.0.15", "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.15.tgz", "integrity": "sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==", + "dev": true, "license": "MIT" }, "node_modules/@types/json5": { @@ -15489,6 +15813,7 @@ "version": "1.3.5", "resolved": "https://registry.npmjs.org/@types/mime/-/mime-1.3.5.tgz", "integrity": "sha512-/pyBZWSLD2n0dcHE3hq8s8ZvcETHtEuF+3E7XVt0Ig2nvsVQXdghHVcEkIWjy9A0wKfTn97a/PSDYohKIlnP/w==", + "dev": true, "license": "MIT" }, "node_modules/@types/ms": { @@ -15561,6 +15886,7 @@ "version": "1.3.14", "resolved": "https://registry.npmjs.org/@types/node-forge/-/node-forge-1.3.14.tgz", "integrity": "sha512-mhVF2BnD4BO+jtOp7z1CdzaK4mbuK0LLQYAvdOLqHTavxFNq4zA1EmYkpnFjP8HOUzedfQkRnp0E2ulSAYSzAw==", + "dev": true, "license": "MIT", "dependencies": { "@types/node": "*" @@ -15616,12 +15942,14 @@ "version": "6.14.0", "resolved": "https://registry.npmjs.org/@types/qs/-/qs-6.14.0.tgz", "integrity": "sha512-eOunJqu0K1923aExK6y8p6fsihYEn/BYuQ4g0CxAAgFc4b/ZLN4CrsRZ55srTdqoiLzU2B2evC+apEIxprEzkQ==", + "dev": true, "license": "MIT" }, "node_modules/@types/range-parser": { "version": "1.2.7", "resolved": "https://registry.npmjs.org/@types/range-parser/-/range-parser-1.2.7.tgz", "integrity": "sha512-hKormJbkJqzQGhziax5PItDUTMAM9uE2XXQmM37dyd4hVM+5aVl7oVxMVUiVQn2oCQFN/LKCZdvSM0pFRqbSmQ==", + "dev": true, "license": "MIT" }, "node_modules/@types/react": { @@ -15664,6 +15992,7 @@ "version": "0.17.5", "resolved": "https://registry.npmjs.org/@types/send/-/send-0.17.5.tgz", "integrity": "sha512-z6F2D3cOStZvuk2SaP6YrwkNO65iTZcwA2ZkSABegdkAh/lf+Aa/YQndZVfmEXT5vgAp6zv06VQ3ejSVjAny4w==", + "dev": true, "license": "MIT", "dependencies": { "@types/mime": "^1", @@ -15674,6 +16003,7 @@ "version": "1.9.4", "resolved": "https://registry.npmjs.org/@types/serve-index/-/serve-index-1.9.4.tgz", "integrity": "sha512-qLpGZ/c2fhSs5gnYsQxtDEq3Oy8SXPClIXkW5ghvAvsNuVSA8k+gCONcUCS/UjLEYvYps+e8uBtfgXgvhwfNug==", + "dev": true, "license": "MIT", "dependencies": { "@types/express": "*" @@ -15683,6 +16013,7 @@ "version": "1.15.8", "resolved": "https://registry.npmjs.org/@types/serve-static/-/serve-static-1.15.8.tgz", "integrity": "sha512-roei0UY3LhpOJvjbIP6ZZFngyLKl5dskOtDhxY5THRSpO+ZI+nzJ+m5yUMzGrp89YRa7lvknKkMYjqQFGwA7Sg==", + "dev": true, "license": "MIT", "dependencies": { "@types/http-errors": "*", @@ -15694,6 +16025,7 @@ "version": "0.3.36", "resolved": "https://registry.npmjs.org/@types/sockjs/-/sockjs-0.3.36.tgz", "integrity": "sha512-MK9V6NzAS1+Ud7JV9lJLFqW85VbC9dq3LmwZCuBe4wBDgKC0Kj/jd8Xl+nSviU+Qc3+m7umHHyHg//2KSa0a0Q==", + "dev": true, "license": "MIT", "dependencies": { "@types/node": "*" @@ -15703,6 +16035,7 @@ "version": "2.0.3", "resolved": "https://registry.npmjs.org/@types/stack-utils/-/stack-utils-2.0.3.tgz", "integrity": "sha512-9aEbYZ3TbYMznPdcdr3SmIrLXwC/AKZXQeCf9Pgao5CKb8CyHuEX5jzWPTkvregvhRJHcpRO6BFoGW9ycaOkYw==", + "dev": true, "license": "MIT" }, "node_modules/@types/through": { @@ -15757,6 +16090,7 @@ "version": "8.18.1", "resolved": "https://registry.npmjs.org/@types/ws/-/ws-8.18.1.tgz", "integrity": "sha512-ThVF6DCVhA8kUGy+aazFQ4kXQ7E1Ty7A3ypFOe0IcJV8O/M511G99AW24irKrW56Wt44yG9+ij8FaqoBGkuBXg==", + "dev": true, "license": "MIT", "dependencies": { "@types/node": "*" @@ -15766,6 +16100,7 @@ "version": "17.0.33", "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-17.0.33.tgz", "integrity": "sha512-WpxBCKWPLr4xSsHgz511rFJAM+wS28w2zEO1QDNY5zM/S8ok70NNfztH0xwhqKyaK0OHCbN98LDAZuy1ctxDkA==", + "dev": true, "license": "MIT", "dependencies": { "@types/yargs-parser": "*" @@ -15775,6 +16110,7 @@ "version": "21.0.3", "resolved": "https://registry.npmjs.org/@types/yargs-parser/-/yargs-parser-21.0.3.tgz", "integrity": "sha512-I4q9QU9MQv4oEOz4tAHJtNz1cwuLxn2F3xcc2iV5WdqLPpUnj30aUuxt1mAxYTG+oe8CZMV/+6rU4S4gRDzqtQ==", + "dev": true, "license": "MIT" }, "node_modules/@types/yauzl": { @@ -16318,6 +16654,7 @@ "version": "1.3.0", "resolved": "https://registry.npmjs.org/@ungap/structured-clone/-/structured-clone-1.3.0.tgz", "integrity": "sha512-WmoN8qaIAo7WTYWbAZuG8PYEhn5fkz7dZrqTBZ7dtt//lL2Gwms1IcnQ5yHqjDfX8Ft5j4YzDM23f87zBfDe9g==", + "dev": true, "license": "ISC" }, "node_modules/@unrs/resolver-binding-android-arm-eabi": { @@ -16327,6 +16664,7 @@ "cpu": [ "arm" ], + "dev": true, "license": "MIT", "optional": true, "os": [ @@ -16340,6 +16678,7 @@ "cpu": [ "arm64" ], + "dev": true, "license": "MIT", "optional": true, "os": [ @@ -16353,6 +16692,7 @@ "cpu": [ "arm64" ], + "dev": true, "license": "MIT", "optional": true, "os": [ @@ -16366,6 +16706,7 @@ "cpu": [ "x64" ], + "dev": true, "license": "MIT", "optional": true, "os": [ @@ -16379,6 +16720,7 @@ "cpu": [ "x64" ], + "dev": true, "license": "MIT", "optional": true, "os": [ @@ -16392,6 +16734,7 @@ "cpu": [ "arm" ], + "dev": true, "license": "MIT", "optional": true, "os": [ @@ -16405,6 +16748,7 @@ "cpu": [ "arm" ], + "dev": true, "license": "MIT", "optional": true, "os": [ @@ -16418,6 +16762,7 @@ "cpu": [ "arm64" ], + "dev": true, "license": "MIT", "optional": true, "os": [ @@ -16431,6 +16776,7 @@ "cpu": [ "arm64" ], + "dev": true, "license": "MIT", "optional": true, "os": [ @@ -16444,6 +16790,7 @@ "cpu": [ "ppc64" ], + "dev": true, "license": "MIT", "optional": true, "os": [ @@ -16457,6 +16804,7 @@ "cpu": [ "riscv64" ], + "dev": true, "license": "MIT", "optional": true, "os": [ @@ -16470,6 +16818,7 @@ "cpu": [ "riscv64" ], + "dev": true, "license": "MIT", "optional": true, "os": [ @@ -16483,6 +16832,7 @@ "cpu": [ "s390x" ], + "dev": true, "license": "MIT", "optional": true, "os": [ @@ -16496,6 +16846,7 @@ "cpu": [ "x64" ], + "dev": true, "license": "MIT", "optional": true, "os": [ @@ -16509,6 +16860,7 @@ "cpu": [ "x64" ], + "dev": true, "license": "MIT", "optional": true, "os": [ @@ -16522,6 +16874,7 @@ "cpu": [ "wasm32" ], + "dev": true, "license": "MIT", "optional": true, "dependencies": { @@ -16535,6 +16888,7 @@ "version": "0.2.11", "resolved": "https://registry.npmjs.org/@napi-rs/wasm-runtime/-/wasm-runtime-0.2.11.tgz", "integrity": "sha512-9DPkXtvHydrcOsopiYpUgPHpmj0HWZKMUnL2dZqpvC42lsratuBG06V5ipyno0fUek5VlFsNQ+AcFATSrJXgMA==", + "dev": true, "license": "MIT", "optional": true, "dependencies": { @@ -16550,6 +16904,7 @@ "cpu": [ "arm64" ], + "dev": true, "license": "MIT", "optional": true, "os": [ @@ -16563,6 +16918,7 @@ "cpu": [ "ia32" ], + "dev": true, "license": "MIT", "optional": true, "os": [ @@ -16576,6 +16932,7 @@ "cpu": [ "x64" ], + "dev": true, "license": "MIT", "optional": true, "os": [ @@ -16684,6 +17041,7 @@ "version": "1.14.1", "resolved": "https://registry.npmjs.org/@webassemblyjs/ast/-/ast-1.14.1.tgz", "integrity": "sha512-nuBEDgQfm1ccRp/8bCQrx1frohyufl4JlbMMZ4P1wpeOfDhF6FQkxZJ1b/e+PLwr6X1Nhw6OLme5usuBWYBvuQ==", + "dev": true, "license": "MIT", "dependencies": { "@webassemblyjs/helper-numbers": "1.13.2", @@ -16694,24 +17052,28 @@ "version": "1.13.2", "resolved": "https://registry.npmjs.org/@webassemblyjs/floating-point-hex-parser/-/floating-point-hex-parser-1.13.2.tgz", "integrity": "sha512-6oXyTOzbKxGH4steLbLNOu71Oj+C8Lg34n6CqRvqfS2O71BxY6ByfMDRhBytzknj9yGUPVJ1qIKhRlAwO1AovA==", + "dev": true, "license": "MIT" }, "node_modules/@webassemblyjs/helper-api-error": { "version": "1.13.2", "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-api-error/-/helper-api-error-1.13.2.tgz", "integrity": "sha512-U56GMYxy4ZQCbDZd6JuvvNV/WFildOjsaWD3Tzzvmw/mas3cXzRJPMjP83JqEsgSbyrmaGjBfDtV7KDXV9UzFQ==", + "dev": true, "license": "MIT" }, "node_modules/@webassemblyjs/helper-buffer": { "version": "1.14.1", "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-buffer/-/helper-buffer-1.14.1.tgz", "integrity": "sha512-jyH7wtcHiKssDtFPRB+iQdxlDf96m0E39yb0k5uJVhFGleZFoNw1c4aeIcVUPPbXUVJ94wwnMOAqUHyzoEPVMA==", + "dev": true, "license": "MIT" }, "node_modules/@webassemblyjs/helper-numbers": { "version": "1.13.2", "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-numbers/-/helper-numbers-1.13.2.tgz", "integrity": "sha512-FE8aCmS5Q6eQYcV3gI35O4J789wlQA+7JrqTTpJqn5emA4U2hvwJmvFRC0HODS+3Ye6WioDklgd6scJ3+PLnEA==", + "dev": true, "license": "MIT", "dependencies": { "@webassemblyjs/floating-point-hex-parser": "1.13.2", @@ -16723,12 +17085,14 @@ "version": "1.13.2", "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-wasm-bytecode/-/helper-wasm-bytecode-1.13.2.tgz", "integrity": "sha512-3QbLKy93F0EAIXLh0ogEVR6rOubA9AoZ+WRYhNbFyuB70j3dRdwH9g+qXhLAO0kiYGlg3TxDV+I4rQTr/YNXkA==", + "dev": true, "license": "MIT" }, "node_modules/@webassemblyjs/helper-wasm-section": { "version": "1.14.1", "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-wasm-section/-/helper-wasm-section-1.14.1.tgz", "integrity": "sha512-ds5mXEqTJ6oxRoqjhWDU83OgzAYjwsCV8Lo/N+oRsNDmx/ZDpqalmrtgOMkHwxsG0iI//3BwWAErYRHtgn0dZw==", + "dev": true, "license": "MIT", "dependencies": { "@webassemblyjs/ast": "1.14.1", @@ -16741,6 +17105,7 @@ "version": "1.13.2", "resolved": "https://registry.npmjs.org/@webassemblyjs/ieee754/-/ieee754-1.13.2.tgz", "integrity": "sha512-4LtOzh58S/5lX4ITKxnAK2USuNEvpdVV9AlgGQb8rJDHaLeHciwG4zlGr0j/SNWlr7x3vO1lDEsuePvtcDNCkw==", + "dev": true, "license": "MIT", "dependencies": { "@xtuc/ieee754": "^1.2.0" @@ -16750,6 +17115,7 @@ "version": "1.13.2", "resolved": "https://registry.npmjs.org/@webassemblyjs/leb128/-/leb128-1.13.2.tgz", "integrity": "sha512-Lde1oNoIdzVzdkNEAWZ1dZ5orIbff80YPdHx20mrHwHrVNNTjNr8E3xz9BdpcGqRQbAEa+fkrCb+fRFTl/6sQw==", + "dev": true, "license": "Apache-2.0", "dependencies": { "@xtuc/long": "4.2.2" @@ -16759,12 +17125,14 @@ "version": "1.13.2", "resolved": "https://registry.npmjs.org/@webassemblyjs/utf8/-/utf8-1.13.2.tgz", "integrity": "sha512-3NQWGjKTASY1xV5m7Hr0iPeXD9+RDobLll3T9d2AO+g3my8xy5peVyjSag4I50mR1bBSN/Ct12lo+R9tJk0NZQ==", + "dev": true, "license": "MIT" }, "node_modules/@webassemblyjs/wasm-edit": { "version": "1.14.1", "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-edit/-/wasm-edit-1.14.1.tgz", "integrity": "sha512-RNJUIQH/J8iA/1NzlE4N7KtyZNHi3w7at7hDjvRNm5rcUXa00z1vRz3glZoULfJ5mpvYhLybmVcwcjGrC1pRrQ==", + "dev": true, "license": "MIT", "dependencies": { "@webassemblyjs/ast": "1.14.1", @@ -16781,6 +17149,7 @@ "version": "1.14.1", "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-gen/-/wasm-gen-1.14.1.tgz", "integrity": "sha512-AmomSIjP8ZbfGQhumkNvgC33AY7qtMCXnN6bL2u2Js4gVCg8fp735aEiMSBbDR7UQIj90n4wKAFUSEd0QN2Ukg==", + "dev": true, "license": "MIT", "dependencies": { "@webassemblyjs/ast": "1.14.1", @@ -16794,6 +17163,7 @@ "version": "1.14.1", "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-opt/-/wasm-opt-1.14.1.tgz", "integrity": "sha512-PTcKLUNvBqnY2U6E5bdOQcSM+oVP/PmrDY9NzowJjislEjwP/C4an2303MCVS2Mg9d3AJpIGdUFIQQWbPds0Sw==", + "dev": true, "license": "MIT", "dependencies": { "@webassemblyjs/ast": "1.14.1", @@ -16806,6 +17176,7 @@ "version": "1.14.1", "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-parser/-/wasm-parser-1.14.1.tgz", "integrity": "sha512-JLBl+KZ0R5qB7mCnud/yyX08jWFw5MsoalJ1pQ4EdFlgj9VdXKGuENGsiCIjegI1W7p91rUlcB/LB5yRJKNTcQ==", + "dev": true, "license": "MIT", "dependencies": { "@webassemblyjs/ast": "1.14.1", @@ -16820,6 +17191,7 @@ "version": "1.14.1", "resolved": "https://registry.npmjs.org/@webassemblyjs/wast-printer/-/wast-printer-1.14.1.tgz", "integrity": "sha512-kPSSXE6De1XOR820C90RIo2ogvZG+c3KiHzqUoO/F34Y2shGzesfqv7o57xrxovZJH/MetF5UjroJ/R/3isoiw==", + "dev": true, "license": "MIT", "dependencies": { "@webassemblyjs/ast": "1.14.1", @@ -16894,12 +17266,14 @@ "version": "1.2.0", "resolved": "https://registry.npmjs.org/@xtuc/ieee754/-/ieee754-1.2.0.tgz", "integrity": "sha512-DX8nKgqcGwsc0eJSqYt5lwP4DH5FlHnmuWWBRy7X0NcaGR0ZtuyeESgMwTYVEtxmsNGY+qit4QYT/MIYTOTPeA==", + "dev": true, "license": "BSD-3-Clause" }, "node_modules/@xtuc/long": { "version": "4.2.2", "resolved": "https://registry.npmjs.org/@xtuc/long/-/long-4.2.2.tgz", "integrity": "sha512-NuHqBY1PB/D8xU6s/thBgOAiAP7HOYDQ32+BFZILJ8ivkUkAHQnWfn6WhL79Owj1qmUnoN/YPhktdIoucipkAQ==", + "dev": true, "license": "Apache-2.0" }, "node_modules/@yao-pkg/pkg": { @@ -17108,12 +17482,14 @@ "version": "1.1.0", "resolved": "https://registry.npmjs.org/@yarnpkg/lockfile/-/lockfile-1.1.0.tgz", "integrity": "sha512-GpSwvyXOcOOlV70vbnzjj4fW5xW/FdUF6nQEt1ENy7m4ZCczi1+/buVUPAqmGfqznsORNFzUMjctTIp8a9tuCQ==", + "dev": true, "license": "BSD-2-Clause" }, "node_modules/@yarnpkg/parsers": { "version": "3.0.2", "resolved": "https://registry.npmjs.org/@yarnpkg/parsers/-/parsers-3.0.2.tgz", "integrity": "sha512-/HcYgtUSiJiot/XWGLOlGxPYUG65+/31V8oqk17vZLW1xlCoR4PampyePljOxY2n8/3jz9+tIFzICsyGujJZoA==", + "dev": true, "license": "BSD-2-Clause", "dependencies": { "js-yaml": "^3.10.0", @@ -17127,6 +17503,7 @@ "version": "0.0.7", "resolved": "https://registry.npmjs.org/@zkochan/js-yaml/-/js-yaml-0.0.7.tgz", "integrity": "sha512-nrUSn7hzt7J6JWgWGz78ZYI8wj+gdIJdk0Ynjpp8l+trkn58Uqsf6RYrYkEK+3X18EX+TNdtJI0WxAtc+L84SQ==", + "dev": true, "license": "MIT", "dependencies": { "argparse": "^2.0.1" @@ -17173,6 +17550,7 @@ "version": "2.0.0", "resolved": "https://registry.npmjs.org/accepts/-/accepts-2.0.0.tgz", "integrity": "sha512-5cvg6CtKwfgdmVqY1WIiXKc3Q1bkRqGLi+2W/6ao+6Y7gu/RCwRuAhGEzh5B4KlszSuTLgZYuqFqo5bImjNKng==", + "dev": true, "license": "MIT", "dependencies": { "mime-types": "^3.0.0", @@ -17209,6 +17587,7 @@ "version": "1.0.4", "resolved": "https://registry.npmjs.org/acorn-import-phases/-/acorn-import-phases-1.0.4.tgz", "integrity": "sha512-wKmbr/DDiIXzEOiWrTTUcDm24kQ2vGfZQvM2fwg2vXqR5uW6aapr7ObPtj1th32b9u90/Pf4AItvdTh42fBmVQ==", + "dev": true, "license": "MIT", "engines": { "node": ">=10.13.0" @@ -17221,6 +17600,7 @@ "version": "5.3.2", "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.2.tgz", "integrity": "sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==", + "dev": true, "license": "MIT", "peerDependencies": { "acorn": "^6.0.0 || ^7.0.0 || ^8.0.0" @@ -17242,6 +17622,7 @@ "version": "1.2.2", "resolved": "https://registry.npmjs.org/address/-/address-1.2.2.tgz", "integrity": "sha512-4B/qKCfeE/ODUaAUpSwfzazo5x29WD4r3vXiWsB7I2mSDAihwEqKO+g8GELZUQSSAo5e1XTYh3ZVfLyxBc12nA==", + "dev": true, "license": "MIT", "engines": { "node": ">= 10.0.0" @@ -17316,6 +17697,7 @@ "version": "8.17.1", "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.17.1.tgz", "integrity": "sha512-B/gBuNg5SiMTrPkC+A2+cW0RszwxYmn6VYxB/inlBStS5nx6xHIt/ehKRhIMhqusl7a8LjQoZnjCs5vhwxOQ1g==", + "dev": true, "license": "MIT", "dependencies": { "fast-deep-equal": "^3.1.3", @@ -17350,6 +17732,7 @@ "version": "5.1.0", "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-5.1.0.tgz", "integrity": "sha512-YCS/JNFAUyr5vAuhk1DWm1CBxRHW9LbJ2ozWeemrIqpbsqKjHVxYPyi5GC0rjZIT5JxJ3virVTS8wk4i/Z+krw==", + "dev": true, "license": "MIT", "dependencies": { "fast-deep-equal": "^3.1.3" @@ -17411,6 +17794,7 @@ "version": "4.1.3", "resolved": "https://registry.npmjs.org/ansi-colors/-/ansi-colors-4.1.3.tgz", "integrity": "sha512-/6w/C21Pm1A7aZitlI5Ni/2J6FFQN8i1Cvz3kHABAAbw93v/NlvKdVOqz7CCWz/3iv/JplRSEEZ83XION15ovw==", + "dev": true, "license": "MIT", "engines": { "node": ">=6" @@ -17447,6 +17831,7 @@ "version": "0.0.8", "resolved": "https://registry.npmjs.org/ansi-html-community/-/ansi-html-community-0.0.8.tgz", "integrity": "sha512-1APHAyr3+PCamwNw3bXCPp4HFLONZt/yIH0sZp0/469KWNTEy+qN5jQ3GVX6DMZ1UXAi34yVwtTeaG/HpBuuzw==", + "dev": true, "engines": [ "node >= 0.8.0" ], @@ -17490,6 +17875,7 @@ "version": "3.1.3", "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.3.tgz", "integrity": "sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==", + "dev": true, "license": "ISC", "dependencies": { "normalize-path": "^3.0.0", @@ -17503,6 +17889,7 @@ "version": "2.3.1", "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", + "dev": true, "license": "MIT", "engines": { "node": ">=8.6" @@ -17731,6 +18118,7 @@ "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, "license": "Python-2.0" }, "node_modules/aria-query": { @@ -17764,6 +18152,7 @@ "version": "1.1.1", "resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-1.1.1.tgz", "integrity": "sha512-PCVAQswWemu6UdxsDFFX/+gVeYqKAod3D3UVm91jHwynguOwAvYPhx8nNlM++NqRcK6CxxpUafjmhIdKiHibqg==", + "dev": true, "license": "MIT" }, "node_modules/array-includes": { @@ -17930,6 +18319,7 @@ "version": "3.2.6", "resolved": "https://registry.npmjs.org/async/-/async-3.2.6.tgz", "integrity": "sha512-htCUDlxyyCLMgaM3xXg0C0LW2xqfuQ6p05pCEIsXuyQ+a1koYKTuBMzRNwmybfLgvJDMd0r1LTn4+E0Ti6C2AA==", + "dev": true, "license": "MIT" }, "node_modules/async-exit-hook": { @@ -17981,6 +18371,7 @@ "version": "10.4.22", "resolved": "https://registry.npmjs.org/autoprefixer/-/autoprefixer-10.4.22.tgz", "integrity": "sha512-ARe0v/t9gO28Bznv6GgqARmVqcWOV3mfgUPn9becPHMiD3o9BwlRgaeccZnwTpZ7Zwqrm+c1sUSsMxIzQzc8Xg==", + "dev": true, "funding": [ { "type": "opencollective", @@ -18018,6 +18409,7 @@ "version": "5.3.4", "resolved": "https://registry.npmjs.org/fraction.js/-/fraction.js-5.3.4.tgz", "integrity": "sha512-1X1NTtiJphryn/uLQz3whtY6jK3fTqoE3ohKs0tT+Ujr1W59oopxmoEh7Lu5p6vBaPbgoM0bzveAW4Qi5RyWDQ==", + "dev": true, "license": "MIT", "engines": { "node": "*" @@ -18090,6 +18482,7 @@ "version": "1.13.2", "resolved": "https://registry.npmjs.org/axios/-/axios-1.13.2.tgz", "integrity": "sha512-VPk9ebNqPcy5lRGuSlKx752IlDatOjT9paPlm8A7yOuW2Fbvp4X3JznJtT4f0GzGLLiWE9W8onz51SqLYwzGaA==", + "dev": true, "license": "MIT", "dependencies": { "follow-redirects": "^1.15.6", @@ -18133,6 +18526,7 @@ "version": "9.2.1", "resolved": "https://registry.npmjs.org/babel-loader/-/babel-loader-9.2.1.tgz", "integrity": "sha512-fqe8naHt46e0yIdkjUZYqddSXfej3AHajX+CSO5X7oy0EmPc6o5Xh+RClNoHjnieWz9AW4kZxW9yyFMhVB1QLA==", + "dev": true, "license": "MIT", "dependencies": { "find-cache-dir": "^4.0.0", @@ -18150,6 +18544,7 @@ "version": "1.2.0", "resolved": "https://registry.npmjs.org/babel-plugin-const-enum/-/babel-plugin-const-enum-1.2.0.tgz", "integrity": "sha512-o1m/6iyyFnp9MRsK1dHF3bneqyf3AlM2q3A/YbgQr2pCat6B6XJVDv2TXqzfY2RYUi4mak6WAksSBPlyYGx9dg==", + "dev": true, "license": "MIT", "dependencies": { "@babel/helper-plugin-utils": "^7.0.0", @@ -18264,6 +18659,7 @@ "version": "0.4.14", "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-corejs2/-/babel-plugin-polyfill-corejs2-0.4.14.tgz", "integrity": "sha512-Co2Y9wX854ts6U8gAAPXfn0GmAyctHuK8n0Yhfjd6t30g7yvKjspvvOo9yG+z52PZRgFErt7Ka2pYnXCjLKEpg==", + "dev": true, "license": "MIT", "dependencies": { "@babel/compat-data": "^7.27.7", @@ -18278,6 +18674,7 @@ "version": "6.3.1", "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", + "dev": true, "license": "ISC", "bin": { "semver": "bin/semver.js" @@ -18287,6 +18684,7 @@ "version": "0.13.0", "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-corejs3/-/babel-plugin-polyfill-corejs3-0.13.0.tgz", "integrity": "sha512-U+GNwMdSFgzVmfhNm8GJUX88AadB3uo9KpJqS3FaqNIPKgySuvMb+bHPsOmmuWyIcuqZj/pzt1RUIUZns4y2+A==", + "dev": true, "license": "MIT", "dependencies": { "@babel/helper-define-polyfill-provider": "^0.6.5", @@ -18300,6 +18698,7 @@ "version": "0.6.5", "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-regenerator/-/babel-plugin-polyfill-regenerator-0.6.5.tgz", "integrity": "sha512-ISqQ2frbiNU9vIJkzg7dlPpznPZ4jOiUQ1uSmB0fEHeowtN3COYRsXr/xexn64NpU13P06jc/L5TgiJXOgrbEg==", + "dev": true, "license": "MIT", "dependencies": { "@babel/helper-define-polyfill-provider": "^0.6.5" @@ -18312,6 +18711,7 @@ "version": "0.3.2", "resolved": "https://registry.npmjs.org/babel-plugin-transform-typescript-metadata/-/babel-plugin-transform-typescript-metadata-0.3.2.tgz", "integrity": "sha512-mWEvCQTgXQf48yDqgN7CH50waTyYBeP2Lpqx4nNWab9sxEpdXVeKgfj1qYI2/TgUPQtNFZ85i3PemRtnXVYYJg==", + "dev": true, "license": "MIT", "dependencies": { "@babel/helper-plugin-utils": "^7.0.0" @@ -18321,6 +18721,7 @@ "version": "1.2.0", "resolved": "https://registry.npmjs.org/babel-preset-current-node-syntax/-/babel-preset-current-node-syntax-1.2.0.tgz", "integrity": "sha512-E/VlAEzRrsLEb2+dv8yp3bo4scof3l9nR4lrld+Iy5NyVqgVYUJnDAmunkhPMisRI32Qc4iRiz425d8vM++2fg==", + "dev": true, "license": "MIT", "dependencies": { "@babel/plugin-syntax-async-generators": "^7.8.4", @@ -18375,6 +18776,7 @@ "version": "1.0.2", "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", + "dev": true, "license": "MIT" }, "node_modules/base64-js": { @@ -18408,6 +18810,7 @@ "version": "2.9.3", "resolved": "https://registry.npmjs.org/baseline-browser-mapping/-/baseline-browser-mapping-2.9.3.tgz", "integrity": "sha512-8QdH6czo+G7uBsNo0GiUfouPN1lRzKdJTGnKXwe12gkFbnnOUaUKGN55dMkfy+mnxmvjwl9zcI4VncczcVXDhA==", + "dev": true, "license": "Apache-2.0", "bin": { "baseline-browser-mapping": "dist/cli.js" @@ -18437,6 +18840,7 @@ "version": "0.6.1", "resolved": "https://registry.npmjs.org/batch/-/batch-0.6.1.tgz", "integrity": "sha512-x+VAiMRL6UPkx+kudNvxTl6hB2XNNCG2r+7wixVfIYwu/2HKRXimwQyaumLjMveWvT2Hkd/cAJw+QBMfJ/EKVw==", + "dev": true, "license": "MIT" }, "node_modules/bcryptjs": { @@ -18598,6 +19002,7 @@ "version": "5.2.2", "resolved": "https://registry.npmjs.org/big.js/-/big.js-5.2.2.tgz", "integrity": "sha512-vyL2OymJxmarO8gxMr0mhChsO9QGwhynfuu4+MHTAW6czfq9humCB7rKpUjDd9YUiDPU4mzpyupFSvOClAwbmQ==", + "dev": true, "license": "MIT", "engines": { "node": "*" @@ -18607,6 +19012,7 @@ "version": "2.3.0", "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.3.0.tgz", "integrity": "sha512-Ceh+7ox5qe7LJuLHoY0feh3pHuUDHAcRUeyL2VYghZwfpkNIy/+8Ocg0a3UuSoYzavmylwuLWQOf3hl0jjMMIw==", + "dev": true, "license": "MIT", "engines": { "node": ">=8" @@ -18675,6 +19081,7 @@ "version": "2.2.0", "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-2.2.0.tgz", "integrity": "sha512-02qvAaxv8tp7fBa/mw1ga98OGm+eCbqzJOKoRt70sLmfEEi+jyBYVTDGfCL/k06/4EMk/z01gCe7HoCH/f2LTg==", + "dev": true, "license": "MIT", "dependencies": { "bytes": "^3.1.2", @@ -18695,6 +19102,7 @@ "version": "1.3.0", "resolved": "https://registry.npmjs.org/bonjour-service/-/bonjour-service-1.3.0.tgz", "integrity": "sha512-3YuAUiSkWykd+2Azjgyxei8OWf8thdn8AITIog2M4UICzoqfjlqr64WIjEXZllf/W6vK1goqleSR6brGomxQqA==", + "dev": true, "license": "MIT", "dependencies": { "fast-deep-equal": "^3.1.3", @@ -18705,6 +19113,7 @@ "version": "1.0.0", "resolved": "https://registry.npmjs.org/boolbase/-/boolbase-1.0.0.tgz", "integrity": "sha512-JZOSA7Mo9sNGB8+UjSgzdLtokWAky1zbztM3WRLCbZ70/3cTANmQmOdR7y2g+J0e2WXywy1yS468tY+IruqEww==", + "dev": true, "license": "ISC" }, "node_modules/boolean": { @@ -18736,6 +19145,7 @@ "version": "2.0.2", "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.2.tgz", "integrity": "sha512-Jt0vHyM+jmUBqojB7E1NIYadt0vI0Qxjxd2TErW94wDz+E2LAm5vKMXXwg6ZZBTHPuUlDgQHKXvjGBdfcF1ZDQ==", + "dev": true, "license": "MIT", "dependencies": { "balanced-match": "^1.0.0" @@ -18745,6 +19155,7 @@ "version": "3.0.3", "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.3.tgz", "integrity": "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==", + "dev": true, "license": "MIT", "dependencies": { "fill-range": "^7.1.1" @@ -18800,6 +19211,7 @@ "version": "4.28.1", "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.28.1.tgz", "integrity": "sha512-ZC5Bd0LgJXgwGqUknZY/vkUQ04r8NXnJZ3yYi4vDmSiZmC/pdSN0NbNRPxZpbtO4uAfDUAFffO8IZoM3Gj8IkA==", + "dev": true, "funding": [ { "type": "opencollective", @@ -18846,6 +19258,7 @@ "version": "2.1.1", "resolved": "https://registry.npmjs.org/bser/-/bser-2.1.1.tgz", "integrity": "sha512-gQxTNE/GAfIIrmHLUE3oJyp5FO6HRBfhjnw4/wMmA63ZGDJnWBmgY/lyQBpnDUkGmAhbSe39tx2d/iTOAfglwQ==", + "dev": true, "license": "Apache-2.0", "dependencies": { "node-int64": "^0.4.0" @@ -18879,6 +19292,7 @@ "version": "0.2.0", "resolved": "https://registry.npmjs.org/buffer-builder/-/buffer-builder-0.2.0.tgz", "integrity": "sha512-7VPMEPuYznPSoR21NE1zvd2Xna6c/CloiZCfcMXR1Jny6PjX0N4Nsa38zcBFo/FMK+BlA+FLKbJCQ0i2yxp+Xg==", + "dev": true, "license": "MIT/X11" }, "node_modules/buffer-crc32": { @@ -19338,7 +19752,7 @@ "version": "4.1.2", "resolved": "https://registry.npmjs.org/camel-case/-/camel-case-4.1.2.tgz", "integrity": "sha512-gxGWBrTT1JuMx6R+o5PTXMmUnhnVzLQ9SNutD4YqKtI6ap897t3tKECYla6gCWEkplXnlNybEkZg9GEGxKFCgw==", - "devOptional": true, + "dev": true, "license": "MIT", "dependencies": { "pascal-case": "^3.1.2", @@ -19349,6 +19763,7 @@ "version": "5.3.1", "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz", "integrity": "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==", + "dev": true, "license": "MIT", "engines": { "node": ">=6" @@ -19368,6 +19783,7 @@ "version": "3.0.0", "resolved": "https://registry.npmjs.org/caniuse-api/-/caniuse-api-3.0.0.tgz", "integrity": "sha512-bsTwuIg/BZZK/vreVTYYbSWoe2F+71P7K5QGEX+pT250DZbfU1MQ5prOKpPR+LL6uWKK3KMwMCAS74QB3Um1uw==", + "dev": true, "license": "MIT", "dependencies": { "browserslist": "^4.0.0", @@ -19380,6 +19796,7 @@ "version": "1.0.30001759", "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001759.tgz", "integrity": "sha512-Pzfx9fOKoKvevQf8oCXoyNRQ5QyxJj+3O0Rqx2V5oxT61KGx8+n6hV/IUyJeifUci2clnmmKVpvtiqRzgiWjSw==", + "dev": true, "funding": [ { "type": "opencollective", @@ -19470,6 +19887,7 @@ "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, "license": "MIT", "engines": { "node": ">=10" @@ -19550,6 +19968,7 @@ "version": "4.0.3", "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-4.0.3.tgz", "integrity": "sha512-Qgzu8kfBvo+cA4962jnP1KkS6Dop5NS6g7R5LFYJr4b8Ub94PPQXUksCw9PvXoeXPRRddRNC5C1JQUR2SMGtnA==", + "dev": true, "license": "MIT", "dependencies": { "readdirp": "^4.0.1" @@ -19599,6 +20018,7 @@ "version": "1.0.4", "resolved": "https://registry.npmjs.org/chrome-trace-event/-/chrome-trace-event-1.0.4.tgz", "integrity": "sha512-rNjApaLzuwaOTjCiT8lSDdGN1APCiqkChLMJxJPWLunPAt5fy8xgU9/jNOchV84wfIxrA0lRQB7oCT8jrn/wrQ==", + "dev": true, "license": "MIT", "engines": { "node": ">=6.0" @@ -19615,6 +20035,7 @@ "version": "3.9.0", "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-3.9.0.tgz", "integrity": "sha512-NIxF55hv4nSqQswkAeiOi1r83xy8JldOFDTWiug55KBu9Jnblncd2U6ViHmYgHf01TPZS77NJBhBMKdWj9HQMQ==", + "dev": true, "funding": [ { "type": "github", @@ -19637,7 +20058,7 @@ "version": "5.3.3", "resolved": "https://registry.npmjs.org/clean-css/-/clean-css-5.3.3.tgz", "integrity": "sha512-D5J+kHaVb/wKSFcyyV75uCn8fiY4sV38XJoe4CUyGQ+mOU/fMVYUdH1hJC+CJQ5uY3EnW27SbJYS4X8BiLrAFg==", - "devOptional": true, + "dev": true, "license": "MIT", "dependencies": { "source-map": "~0.6.0" @@ -19650,7 +20071,7 @@ "version": "0.6.1", "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", - "devOptional": true, + "dev": true, "license": "BSD-3-Clause", "engines": { "node": ">=0.10.0" @@ -19738,6 +20159,7 @@ "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, "license": "ISC", "dependencies": { "string-width": "^4.2.0", @@ -19752,6 +20174,7 @@ "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, "license": "MIT", "dependencies": { "ansi-styles": "^4.0.0", @@ -19819,6 +20242,7 @@ "version": "4.6.0", "resolved": "https://registry.npmjs.org/co/-/co-4.6.0.tgz", "integrity": "sha512-QVb0dM5HvG+uaxitm8wONl7jltx8dqhfU33DcqtOZcLSVIKSDDLDi7+0LbAKiyI8hD9u42m2YxXSkMGWThaecQ==", + "dev": true, "license": "MIT", "engines": { "iojs": ">= 1.0.0", @@ -19922,6 +20346,7 @@ "version": "1.0.2", "resolved": "https://registry.npmjs.org/collect-v8-coverage/-/collect-v8-coverage-1.0.2.tgz", "integrity": "sha512-lHl4d5/ONEbLlJvaJNtsF/Lz+WvB07u2ycqTYbdrq7UypDXailES4valYb2eWiJFxZlVmpGekfqoxQhzyFdT4Q==", + "dev": true, "license": "MIT" }, "node_modules/color-convert": { @@ -19956,18 +20381,21 @@ "version": "2.9.3", "resolved": "https://registry.npmjs.org/colord/-/colord-2.9.3.tgz", "integrity": "sha512-jeC1axXpnb0/2nn/Y1LPuLdgXBLH7aDcHu4KEKfqw3CUhX7ZpfBSlPKyqXE6btIgEzfWtrX3/tyBCaCvXvMkOw==", + "dev": true, "license": "MIT" }, "node_modules/colorette": { "version": "2.0.20", "resolved": "https://registry.npmjs.org/colorette/-/colorette-2.0.20.tgz", "integrity": "sha512-IfEDxwoWIjkeXL1eXcDiow4UbKjhLdq6/EuSVR9GMN7KVH3r9gQ83e73hsz1Nd1T3ijd5xv1wcWRYO+D6kCI2w==", + "dev": true, "license": "MIT" }, "node_modules/colorjs.io": { "version": "0.5.2", "resolved": "https://registry.npmjs.org/colorjs.io/-/colorjs.io-0.5.2.tgz", "integrity": "sha512-twmVoizEW7ylZSN32OgKdXRmo1qg+wT5/6C3xu5b9QsWzSFAhHLn2xd8ro0diCsKfCj1RdaTP/nrcW+vAoQPIw==", + "dev": true, "license": "MIT" }, "node_modules/colors": { @@ -19984,6 +20412,7 @@ "version": "1.6.0", "resolved": "https://registry.npmjs.org/columnify/-/columnify-1.6.0.tgz", "integrity": "sha512-lomjuFZKfM6MSAnV9aCZC9sc0qGbmZdfygNv+nCpqVkSKdCxCklLtd16O0EILGkImHw9ZpHkAnHaB+8Zxq5W6Q==", + "dev": true, "license": "MIT", "dependencies": { "strip-ansi": "^6.0.1", @@ -20018,6 +20447,7 @@ "version": "3.0.0", "resolved": "https://registry.npmjs.org/common-path-prefix/-/common-path-prefix-3.0.0.tgz", "integrity": "sha512-QE33hToZseCH3jS0qN96O/bSh3kaw/h+Tq7ngyY9eWDUnTlTNUyqfqvCXioLe5Na5jFsL78ra/wuBU4iuEgd4w==", + "dev": true, "license": "ISC" }, "node_modules/common-tags": { @@ -20065,6 +20495,7 @@ "version": "2.0.18", "resolved": "https://registry.npmjs.org/compressible/-/compressible-2.0.18.tgz", "integrity": "sha512-AF3r7P5dWxL8MxyITRMlORQNaOA2IkAFaTr4k7BUumjPtRpGDTZpl0Pb1XCO6JeDCBdp126Cgs9sMxqSjgYyRg==", + "dev": true, "license": "MIT", "dependencies": { "mime-db": ">= 1.43.0 < 2" @@ -20077,6 +20508,7 @@ "version": "1.8.0", "resolved": "https://registry.npmjs.org/compression/-/compression-1.8.0.tgz", "integrity": "sha512-k6WLKfunuqCYD3t6AsuPGvQWaKwuLLh2/xHNcX4qE+vIfDNXpSqnrhwA7O53R7WVQUnt8dVAIW+YHr7xTgOgGA==", + "dev": true, "license": "MIT", "dependencies": { "bytes": "3.1.2", @@ -20095,6 +20527,7 @@ "version": "2.6.9", "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dev": true, "license": "MIT", "dependencies": { "ms": "2.0.0" @@ -20104,12 +20537,14 @@ "version": "2.0.0", "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", + "dev": true, "license": "MIT" }, "node_modules/compression/node_modules/negotiator": { "version": "0.6.4", "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.4.tgz", "integrity": "sha512-myRT3DiWPHqho5PrJaIRyaMv2kgYf0mUVgBNOYMuCH5Ki1yEiQaf/ZJuQ62nvpc44wL5WDbTX7yGJi1Neevw8w==", + "dev": true, "license": "MIT", "engines": { "node": ">= 0.6" @@ -20119,6 +20554,7 @@ "version": "0.0.1", "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==", + "dev": true, "license": "MIT" }, "node_modules/concat-stream": { @@ -20343,6 +20779,7 @@ "version": "2.0.0", "resolved": "https://registry.npmjs.org/connect-history-api-fallback/-/connect-history-api-fallback-2.0.0.tgz", "integrity": "sha512-U73+6lQFmfiNPrYbXqr6kZ1i1wiRqXnp2nhMsINseWXO8lDau0LGEffJ8kQi4EjLZympVgRdvqjAgiZ1tgzDDA==", + "dev": true, "license": "MIT", "engines": { "node": ">=0.8" @@ -20369,6 +20806,7 @@ "version": "1.0.0", "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-1.0.0.tgz", "integrity": "sha512-Au9nRL8VNUut/XSzbQA38+M78dzP4D+eqg3gfJHMIHHYa3bg067xj1KxMUWj+VULbiZMowKngFFbKczUrNJ1mg==", + "dev": true, "license": "MIT", "dependencies": { "safe-buffer": "5.2.1" @@ -20396,6 +20834,7 @@ "version": "0.7.2", "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.7.2.tgz", "integrity": "sha512-yki5XnKuf750l50uGTllt6kKILY4nQ1eNIQatoXEByZ5dWgnKqbnqmTrBE5B4N7lrMJKQ2ytWMiTO2o0v6Ew/w==", + "dev": true, "license": "MIT", "engines": { "node": ">= 0.6" @@ -20405,6 +20844,7 @@ "version": "1.2.2", "resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.2.2.tgz", "integrity": "sha512-D76uU73ulSXrD1UXF4KE2TMxVVwhsnCgfAyTg9k8P6KGZjlXKrOLe4dJQKI3Bxi5wjesZoFXJWElNWBjPZMbhg==", + "dev": true, "license": "MIT", "engines": { "node": ">=6.6.0" @@ -20427,6 +20867,7 @@ "version": "2.0.6", "resolved": "https://registry.npmjs.org/copy-anything/-/copy-anything-2.0.6.tgz", "integrity": "sha512-1j20GZTsvKNkc4BY3NpMOM8tt///wY3FpIzozTOFO2ffuZcV61nojHXVKIy3WM+7ADCy5FVhdZYHYDdgTU0yJw==", + "dev": true, "license": "MIT", "dependencies": { "is-what": "^3.14.1" @@ -20480,6 +20921,7 @@ "version": "3.43.0", "resolved": "https://registry.npmjs.org/core-js-compat/-/core-js-compat-3.43.0.tgz", "integrity": "sha512-2GML2ZsCc5LR7hZYz4AXmjQw8zuy2T//2QntwdnpuYI7jteT6GVYJL7F6C2C57R7gSYrcqVW3lAALefdbhBLDA==", + "dev": true, "license": "MIT", "dependencies": { "browserslist": "^4.25.0" @@ -20499,6 +20941,7 @@ "version": "2.8.5", "resolved": "https://registry.npmjs.org/cors/-/cors-2.8.5.tgz", "integrity": "sha512-KIHbLJqu73RGr/hnbrO9uBeixNGuvSQjul/jdFvS/KFSIH1hWVd1ng7zOHx+YrEfInLG7q4n6GHQ9cDtxv/P6g==", + "dev": true, "license": "MIT", "dependencies": { "object-assign": "^4", @@ -20650,6 +21093,7 @@ "version": "7.0.6", "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.6.tgz", "integrity": "sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==", + "dev": true, "license": "MIT", "dependencies": { "path-key": "^3.1.0", @@ -20670,6 +21114,7 @@ "version": "7.3.0", "resolved": "https://registry.npmjs.org/css-declaration-sorter/-/css-declaration-sorter-7.3.0.tgz", "integrity": "sha512-LQF6N/3vkAMYF4xoHLJfG718HRJh34Z8BnNhd6bosOMIVjMlhuZK5++oZa3uYAgrI5+7x2o27gUqTR2U/KjUOQ==", + "dev": true, "license": "ISC", "engines": { "node": "^14 || ^16 || >=18" @@ -20718,6 +21163,7 @@ "version": "5.0.1", "resolved": "https://registry.npmjs.org/css-minimizer-webpack-plugin/-/css-minimizer-webpack-plugin-5.0.1.tgz", "integrity": "sha512-3caImjKFQkS+ws1TGcFn0V1HyDJFq1Euy589JlD6/3rV2kj+w7r5G9WDMgSHvpvXHNZ2calVypZWuEDQd9wfLg==", + "dev": true, "license": "MIT", "dependencies": { "@jridgewell/trace-mapping": "^0.3.18", @@ -20762,6 +21208,7 @@ "version": "5.1.0", "resolved": "https://registry.npmjs.org/css-select/-/css-select-5.1.0.tgz", "integrity": "sha512-nwoRF1rvRRnnCqqY7updORDsuqKzqYJ28+oSMaJMMgOauh3fvwHqMS7EZpIPqK8GL+g9mKxF1vP/ZjSeNjEVHg==", + "dev": true, "license": "BSD-2-Clause", "dependencies": { "boolbase": "^1.0.0", @@ -20778,6 +21225,7 @@ "version": "2.3.1", "resolved": "https://registry.npmjs.org/css-tree/-/css-tree-2.3.1.tgz", "integrity": "sha512-6Fv1DV/TYw//QF5IzQdqsNDjx/wc8TrMBZsqjL9eW01tWb7R7k/mq+/VXfJCl7SoD5emsJop9cOByJZfs8hYIw==", + "dev": true, "license": "MIT", "dependencies": { "mdn-data": "2.0.30", @@ -20791,6 +21239,7 @@ "version": "6.1.0", "resolved": "https://registry.npmjs.org/css-what/-/css-what-6.1.0.tgz", "integrity": "sha512-HTUrgRJ7r4dsZKU6GjmpfRK1O76h97Z8MfS1G0FozR+oF2kG6Vfe8JE6zwrkbxigziPHinCJ+gCPjA9EaBDtRw==", + "dev": true, "license": "BSD-2-Clause", "engines": { "node": ">= 6" @@ -20810,6 +21259,7 @@ "version": "3.0.0", "resolved": "https://registry.npmjs.org/cssesc/-/cssesc-3.0.0.tgz", "integrity": "sha512-/Tb/JcjK111nNScGob5MNtsntNM1aCNUDipB/TkwZFhyDrrE47SOx/18wF2bbjgc3ZzCSKW1T5nt5EbFoAz/Vg==", + "dev": true, "license": "MIT", "bin": { "cssesc": "bin/cssesc" @@ -20822,6 +21272,7 @@ "version": "6.1.2", "resolved": "https://registry.npmjs.org/cssnano/-/cssnano-6.1.2.tgz", "integrity": "sha512-rYk5UeX7VAM/u0lNqewCdasdtPK81CgX8wJFLEIXHbV2oldWRgJAsZrdhRXkV1NJzA2g850KiFm9mMU2HxNxMA==", + "dev": true, "license": "MIT", "dependencies": { "cssnano-preset-default": "^6.1.2", @@ -20842,6 +21293,7 @@ "version": "6.1.2", "resolved": "https://registry.npmjs.org/cssnano-preset-default/-/cssnano-preset-default-6.1.2.tgz", "integrity": "sha512-1C0C+eNaeN8OcHQa193aRgYexyJtU8XwbdieEjClw+J9d94E41LwT6ivKH0WT+fYwYWB0Zp3I3IZ7tI/BbUbrg==", + "dev": true, "license": "MIT", "dependencies": { "browserslist": "^4.23.0", @@ -20886,6 +21338,7 @@ "version": "4.0.2", "resolved": "https://registry.npmjs.org/cssnano-utils/-/cssnano-utils-4.0.2.tgz", "integrity": "sha512-ZR1jHg+wZ8o4c3zqf1SIUSTIvm/9mU343FMR6Obe/unskbvpGhZOo1J6d/r8D1pzkRQYuwbcH3hToOuoA2G7oQ==", + "dev": true, "license": "MIT", "engines": { "node": "^14 || ^16 || >=18.0" @@ -20898,6 +21351,7 @@ "version": "5.0.5", "resolved": "https://registry.npmjs.org/csso/-/csso-5.0.5.tgz", "integrity": "sha512-0LrrStPOdJj+SPCCrGhzryycLjwcgUSHBtxNA8aIDxf0GLsRh1cKYhB00Gd1lDOS4yGH69+SNn13+TWbVHETFQ==", + "dev": true, "license": "MIT", "dependencies": { "css-tree": "~2.2.0" @@ -20911,6 +21365,7 @@ "version": "2.2.1", "resolved": "https://registry.npmjs.org/css-tree/-/css-tree-2.2.1.tgz", "integrity": "sha512-OA0mILzGc1kCOCSJerOeqDxDQ4HOh+G8NbOJFOTgOCzpw7fCBubk0fEyxp8AgOL/jvLgYA/uV0cMbe43ElF1JA==", + "dev": true, "license": "MIT", "dependencies": { "mdn-data": "2.0.28", @@ -20925,6 +21380,7 @@ "version": "2.0.28", "resolved": "https://registry.npmjs.org/mdn-data/-/mdn-data-2.0.28.tgz", "integrity": "sha512-aylIc7Z9y4yzHYAJNuESG3hfhC+0Ibp/MAMiaOZgNv4pmEdFyfZhhhny4MNiAfWdBQ1RQ2mfDWmM1x8SvGyp8g==", + "dev": true, "license": "CC0-1.0" }, "node_modules/cssom": { @@ -21143,6 +21599,7 @@ "version": "1.6.0", "resolved": "https://registry.npmjs.org/dedent/-/dedent-1.6.0.tgz", "integrity": "sha512-F1Z+5UCFpmQUzJa11agbyPVMbpgT/qA3/SKyJ1jyBgm7dUcUEa8v9JwDkerSQXfakBwFljIxhOJqGkjUwZ9FSA==", + "dev": true, "license": "MIT", "peerDependencies": { "babel-plugin-macros": "^3.1.0" @@ -21183,12 +21640,14 @@ "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, "license": "MIT" }, "node_modules/deepmerge": { "version": "4.3.1", "resolved": "https://registry.npmjs.org/deepmerge/-/deepmerge-4.3.1.tgz", "integrity": "sha512-3sUqbMEc77XqpdNO7FRyRog+eW3ph+GYCbj+rK+uYyRMuwsVy0rMiVtPn+QJlKFvWP/1PYpapqYn0Me2knFn+A==", + "dev": true, "license": "MIT", "engines": { "node": ">=0.10.0" @@ -21366,6 +21825,7 @@ "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, "license": "MIT", "engines": { "node": ">=8" @@ -21375,12 +21835,14 @@ "version": "2.1.0", "resolved": "https://registry.npmjs.org/detect-node/-/detect-node-2.1.0.tgz", "integrity": "sha512-T0NIuQpnTvFDATNuHN5roPwSBG83rFsuO+MXXH9/3N1eFbn4wcPjttvjMLEPWJ0RGUYgQE7cGgS3tNxbqCGM7g==", + "dev": true, "license": "MIT" }, "node_modules/detect-port": { "version": "1.6.1", "resolved": "https://registry.npmjs.org/detect-port/-/detect-port-1.6.1.tgz", "integrity": "sha512-CmnVc+Hek2egPx1PeTFVta2W78xy2K/9Rkf6cC4T59S50tVnzKj+tnx5mmx5lwvCkujZ4uRrpRSuV+IVs3f90Q==", + "dev": true, "license": "MIT", "dependencies": { "address": "^1.0.1", @@ -21582,6 +22044,7 @@ "version": "3.0.1", "resolved": "https://registry.npmjs.org/dir-glob/-/dir-glob-3.0.1.tgz", "integrity": "sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA==", + "dev": true, "license": "MIT", "dependencies": { "path-type": "^4.0.0" @@ -21700,6 +22163,7 @@ "version": "5.6.1", "resolved": "https://registry.npmjs.org/dns-packet/-/dns-packet-5.6.1.tgz", "integrity": "sha512-l4gcSouhcgIKRvyy99RNVOgxXiicE+2jZoNmaNmZ6JXiGajBOJAesk1OBlJuM5k2c+eudGdLxDqXuPCKIj6kpw==", + "dev": true, "license": "MIT", "dependencies": { "@leichtgewicht/ip-codec": "^2.0.1" @@ -21733,7 +22197,7 @@ "version": "0.2.0", "resolved": "https://registry.npmjs.org/dom-converter/-/dom-converter-0.2.0.tgz", "integrity": "sha512-gd3ypIPfOMr9h5jIKq8E3sHOTCjeirnl0WK5ZdS1AW0Odt0b1PaWaHdJ4Qk4klv+YB9aJBS7mESXjFoDQPu6DA==", - "devOptional": true, + "dev": true, "license": "MIT", "dependencies": { "utila": "~0.4" @@ -21743,6 +22207,7 @@ "version": "2.0.0", "resolved": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-2.0.0.tgz", "integrity": "sha512-wIkAryiqt/nV5EQKqQpo3SToSOV9J0DnbJqwK7Wv/Trc92zIAYZ4FlMu+JPFW1DfGFt81ZTCGgDEabffXeLyJg==", + "dev": true, "license": "MIT", "dependencies": { "domelementtype": "^2.3.0", @@ -21757,6 +22222,7 @@ "version": "2.3.0", "resolved": "https://registry.npmjs.org/domelementtype/-/domelementtype-2.3.0.tgz", "integrity": "sha512-OLETBj6w0OsagBwdXnPdN0cnMfF9opN69co+7ZrbfPGrdpPVNBUj02spi6B1N7wChLQiPn4CSH/zJvXw56gmHw==", + "dev": true, "funding": [ { "type": "github", @@ -21783,6 +22249,7 @@ "version": "5.0.3", "resolved": "https://registry.npmjs.org/domhandler/-/domhandler-5.0.3.tgz", "integrity": "sha512-cgwlv/1iFQiFnU96XXgROh8xTeetsnJiDsTc7TYCLFd9+/WNkIqPTxiM/8pSd8VIrhXGTf1Ny1q1hquVqDJB5w==", + "dev": true, "license": "BSD-2-Clause", "dependencies": { "domelementtype": "^2.3.0" @@ -21798,6 +22265,7 @@ "version": "3.2.2", "resolved": "https://registry.npmjs.org/domutils/-/domutils-3.2.2.tgz", "integrity": "sha512-6kZKyUajlDuqlHKVX1w7gyslj9MPIXzIFiz/rGu35uC1wMi+kMhQwGhl4lt9unC9Vb9INnY9Z3/ZA3+FhASLaw==", + "dev": true, "license": "BSD-2-Clause", "dependencies": { "dom-serializer": "^2.0.0", @@ -21819,7 +22287,7 @@ "version": "3.0.4", "resolved": "https://registry.npmjs.org/dot-case/-/dot-case-3.0.4.tgz", "integrity": "sha512-Kv5nKlh6yRrdrGvxeJ2e5y2eRUpkUosIW4A2AS38zwSz27zu7ufDwQPi5Jhs3XAlGNetl3bmnGhQsMtkKJnj3w==", - "devOptional": true, + "dev": true, "license": "MIT", "dependencies": { "no-case": "^3.0.4", @@ -21846,6 +22314,7 @@ "version": "16.5.0", "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-16.5.0.tgz", "integrity": "sha512-m/C+AwOAr9/W1UOIZUo232ejMNnJAJtYQjUbHoNTBNTJSvqzzDh7vnrei3o3r3m9blf6ZoDkvcw0VmozNRFJxg==", + "dev": true, "license": "BSD-2-Clause", "engines": { "node": ">=12" @@ -21858,6 +22327,7 @@ "version": "11.0.7", "resolved": "https://registry.npmjs.org/dotenv-expand/-/dotenv-expand-11.0.7.tgz", "integrity": "sha512-zIHwmZPRshsCdpMDyVsqGmgyP0yT8GAgXUnkdAoJisxvf33k7yO6OuoKmcTGuXPWSsm8Oh88nZicRLA9Y0rUeA==", + "dev": true, "license": "BSD-2-Clause", "dependencies": { "dotenv": "^16.4.5" @@ -21904,6 +22374,7 @@ "version": "0.2.0", "resolved": "https://registry.npmjs.org/eastasianwidth/-/eastasianwidth-0.2.0.tgz", "integrity": "sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==", + "dev": true, "license": "MIT" }, "node_modules/ee-first": { @@ -21916,6 +22387,7 @@ "version": "3.1.10", "resolved": "https://registry.npmjs.org/ejs/-/ejs-3.1.10.tgz", "integrity": "sha512-UeJmFfOrAQS8OJWPZ4qtgHyWExa088/MtK5UEyoJGFH67cDEXkZSviOiKRCZ4Xij0zxI3JECgYs3oKx+AizQBA==", + "dev": true, "license": "Apache-2.0", "dependencies": { "jake": "^10.8.5" @@ -22134,6 +22606,7 @@ "version": "1.5.266", "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.266.tgz", "integrity": "sha512-kgWEglXvkEfMH7rxP5OSZZwnaDWT7J9EoZCujhnpLbfi0bbNtRkgdX2E3gt0Uer11c61qCYktB3hwkAS325sJg==", + "dev": true, "license": "ISC" }, "node_modules/electron-updater": { @@ -22259,6 +22732,7 @@ "version": "0.13.1", "resolved": "https://registry.npmjs.org/emittery/-/emittery-0.13.1.tgz", "integrity": "sha512-DeWwawk6r5yR9jFgnDKYt4sLS0LmHJJi3ZOnb5/JdbYwj3nW+FxQnHIjhBKz8YLC7oRNPVM9NQ47I3CVx34eqQ==", + "dev": true, "license": "MIT", "engines": { "node": ">=12" @@ -22292,6 +22766,7 @@ "version": "3.0.0", "resolved": "https://registry.npmjs.org/emojis-list/-/emojis-list-3.0.0.tgz", "integrity": "sha512-/kyM18EfinwXZbno9FyUGeFh87KC8HRQBQGildHZbEuRyWFOmv1U10o9BBp8XVZDVNNuQKyIGIu5ZYAAXJ0V2Q==", + "dev": true, "license": "MIT", "engines": { "node": ">= 4" @@ -22334,6 +22809,7 @@ "version": "1.4.5", "resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.5.tgz", "integrity": "sha512-ooEGc6HP26xXq/N+GCGOT0JKCLDGrq2bQUZrQ7gyrJiZANJ/8YDTxTpQBXGMn+WbIQXNVpyWymm7KYVICQnyOg==", + "dev": true, "license": "MIT", "dependencies": { "once": "^1.4.0" @@ -22343,6 +22819,7 @@ "version": "5.18.1", "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.18.1.tgz", "integrity": "sha512-ZSW3ma5GkcQBIpwZTSRAI8N71Uuwgs93IezB7mf7R60tC8ZbJideoDNKjHn2O9KIlx6rkGTTEk1xUCK2E1Y2Yg==", + "dev": true, "license": "MIT", "dependencies": { "graceful-fs": "^4.2.4", @@ -22356,6 +22833,7 @@ "version": "2.3.6", "resolved": "https://registry.npmjs.org/enquirer/-/enquirer-2.3.6.tgz", "integrity": "sha512-yjNnPr315/FjS4zIsUxYguYUPP2e1NK4d7E7ZOLiyYCcbFBiTMyID+2wvm2w6+pZ/odMA7cRkjhsPbltwBOrLg==", + "dev": true, "license": "MIT", "dependencies": { "ansi-colors": "^4.1.1" @@ -22368,6 +22846,7 @@ "version": "4.5.0", "resolved": "https://registry.npmjs.org/entities/-/entities-4.5.0.tgz", "integrity": "sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw==", + "dev": true, "license": "BSD-2-Clause", "engines": { "node": ">=0.12" @@ -22436,6 +22915,7 @@ "version": "0.1.8", "resolved": "https://registry.npmjs.org/errno/-/errno-0.1.8.tgz", "integrity": "sha512-dJ6oBr5SQ1VSd9qkk7ByRgb/1SH4JZjCHSW/mr63/QcXO9zLVxvJ6Oy13nio03rxpSnVDDjFor75SjVeZWPW/A==", + "dev": true, "license": "MIT", "optional": true, "dependencies": { @@ -22545,6 +23025,7 @@ "version": "1.7.0", "resolved": "https://registry.npmjs.org/es-module-lexer/-/es-module-lexer-1.7.0.tgz", "integrity": "sha512-jEQoCwk8hyb2AZziIOLhDqpm5+2ww5uIE6lkO/6jcOCusfk6LhMHpXXfBLXTZ7Ydyt0j4VoUQv6uGNYbdW+kBA==", + "dev": true, "license": "MIT" }, "node_modules/es-object-atoms": { @@ -22676,7 +23157,7 @@ "version": "3.6.0", "resolved": "https://registry.npmjs.org/esbuild-register/-/esbuild-register-3.6.0.tgz", "integrity": "sha512-H2/S7Pm8a9CL1uhp9OvjwrBh5Pvx0H8qVOxNu8Wed9Y7qv56MPtq+GGM8RJpq6glYJn9Wspr8uw7l55uyinNeg==", - "devOptional": true, + "dev": true, "license": "MIT", "dependencies": { "debug": "^4.3.4" @@ -22702,6 +23183,7 @@ "version": "3.2.0", "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.2.0.tgz", "integrity": "sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==", + "dev": true, "license": "MIT", "engines": { "node": ">=6" @@ -22762,6 +23244,7 @@ "version": "9.26.0", "resolved": "https://registry.npmjs.org/eslint/-/eslint-9.26.0.tgz", "integrity": "sha512-Hx0MOjPh6uK9oq9nVsATZKE/Wlbai7KFjfCuw9UHaguDW3x+HF0O5nIi3ud39TWgrTjTO5nHxmL3R1eANinWHQ==", + "dev": true, "license": "MIT", "dependencies": { "@eslint-community/eslint-utils": "^4.2.0", @@ -23089,6 +23572,7 @@ "version": "8.4.0", "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-8.4.0.tgz", "integrity": "sha512-sNXOfKCn74rt8RICKMvJS7XKV/Xk9kA7DyJr8mJik3S7Cwgy3qlkkmyS2uQB3jiJg6VNdZd/pDBJu0nvG2NlTg==", + "dev": true, "license": "BSD-2-Clause", "dependencies": { "esrecurse": "^4.3.0", @@ -23105,6 +23589,7 @@ "version": "3.4.3", "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.4.3.tgz", "integrity": "sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==", + "dev": true, "license": "Apache-2.0", "engines": { "node": "^12.22.0 || ^14.17.0 || >=16.0.0" @@ -23117,6 +23602,7 @@ "version": "6.12.6", "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", + "dev": true, "license": "MIT", "dependencies": { "fast-deep-equal": "^3.1.1", @@ -23133,6 +23619,7 @@ "version": "1.1.12", "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.12.tgz", "integrity": "sha512-9T9UjW3r0UW5c1Q7GTwllptXwhvYmEzFhzMfZ9H7FQWt+uZePjZPjBP/W1ZEyZ1twGWom5/56TF4lPcqjnDHcg==", + "dev": true, "license": "MIT", "dependencies": { "balanced-match": "^1.0.0", @@ -23143,6 +23630,7 @@ "version": "4.2.1", "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-4.2.1.tgz", "integrity": "sha512-Uhdk5sfqcee/9H/rCOJikYz67o0a2Tw2hGRPOG2Y1R2dg7brRe1uG0yaNQDHu+TO/uQPF/5eCapvYSmHUjt7JQ==", + "dev": true, "license": "Apache-2.0", "engines": { "node": "^18.18.0 || ^20.9.0 || >=21.1.0" @@ -23155,6 +23643,7 @@ "version": "5.3.2", "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.3.2.tgz", "integrity": "sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g==", + "dev": true, "license": "MIT", "engines": { "node": ">= 4" @@ -23164,12 +23653,14 @@ "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, "license": "MIT" }, "node_modules/eslint/node_modules/minimatch": { "version": "3.1.2", "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "dev": true, "license": "ISC", "dependencies": { "brace-expansion": "^1.1.7" @@ -23182,6 +23673,7 @@ "version": "10.4.0", "resolved": "https://registry.npmjs.org/espree/-/espree-10.4.0.tgz", "integrity": "sha512-j6PAQ2uUr79PZhBjP5C5fhl8e39FmRnOjsD5lGnWrFU8i2G776tBK7+nP8KuQUTTyAZUwfQqXAgrVH5MbH9CYQ==", + "dev": true, "license": "BSD-2-Clause", "dependencies": { "acorn": "^8.15.0", @@ -23199,6 +23691,7 @@ "version": "4.2.1", "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-4.2.1.tgz", "integrity": "sha512-Uhdk5sfqcee/9H/rCOJikYz67o0a2Tw2hGRPOG2Y1R2dg7brRe1uG0yaNQDHu+TO/uQPF/5eCapvYSmHUjt7JQ==", + "dev": true, "license": "Apache-2.0", "engines": { "node": "^18.18.0 || ^20.9.0 || >=21.1.0" @@ -23224,6 +23717,7 @@ "version": "1.6.0", "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.6.0.tgz", "integrity": "sha512-ca9pw9fomFcKPvFLXhBKUK90ZvGibiGOvRJNbjljY7s7uq/5YO4BOzcYtJqExdx99rF6aAcnRxHmcUHcz6sQsg==", + "dev": true, "license": "BSD-3-Clause", "dependencies": { "estraverse": "^5.1.0" @@ -23236,6 +23730,7 @@ "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, "license": "BSD-2-Clause", "dependencies": { "estraverse": "^5.2.0" @@ -23248,6 +23743,7 @@ "version": "5.3.0", "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", + "dev": true, "license": "BSD-2-Clause", "engines": { "node": ">=4.0" @@ -23267,6 +23763,7 @@ "version": "2.0.3", "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz", "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==", + "dev": true, "license": "BSD-2-Clause", "engines": { "node": ">=0.10.0" @@ -23276,6 +23773,7 @@ "version": "1.8.1", "resolved": "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz", "integrity": "sha512-aIL5Fx7mawVa300al2BnEE4iNvo1qETxLrPI/o05L7z6go7fCw1J6EQmbK4FmJ2AS7kgVF/KEZWufBfdClMcPg==", + "dev": true, "license": "MIT", "engines": { "node": ">= 0.6" @@ -23310,12 +23808,14 @@ "version": "4.0.7", "resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-4.0.7.tgz", "integrity": "sha512-8guHBZCwKnFhYdHr2ysuRWErTwhoN2X8XELRlrRwpmfeY2jjuUN4taQMsULKUVo1K4DvZl+0pgfyoysHxvmvEw==", + "dev": true, "license": "MIT" }, "node_modules/events": { "version": "3.3.0", "resolved": "https://registry.npmjs.org/events/-/events-3.3.0.tgz", "integrity": "sha512-mQw+2fkQbALzQ7V0MY0IqdnXNOeTtP4r0lN9z7AAawCXgqea7bDii20AYrIBrFd/Hx0M2Ocz6S111CaFkUcb0Q==", + "dev": true, "license": "MIT", "engines": { "node": ">=0.8.x" @@ -23334,6 +23834,7 @@ "version": "3.0.2", "resolved": "https://registry.npmjs.org/eventsource-parser/-/eventsource-parser-3.0.2.tgz", "integrity": "sha512-6RxOBZ/cYgd8usLwsEl+EC09Au/9BcmCKYF2/xbml6DNczf7nv0MQb+7BA2F+li6//I+28VNlQR37XfQtcAJuA==", + "dev": true, "license": "MIT", "engines": { "node": ">=18.0.0" @@ -23396,6 +23897,7 @@ "version": "0.2.2", "resolved": "https://registry.npmjs.org/exit-x/-/exit-x-0.2.2.tgz", "integrity": "sha512-+I6B/IkJc1o/2tiURyz/ivu/O0nKNEArIUB5O7zBrlDVJr22SCLH3xTeEry428LvFhRzIA1g8izguxJ/gbNcVQ==", + "dev": true, "license": "MIT", "engines": { "node": ">= 0.8.0" @@ -23459,6 +23961,7 @@ "version": "5.1.0", "resolved": "https://registry.npmjs.org/express/-/express-5.1.0.tgz", "integrity": "sha512-DT9ck5YIRU+8GYzzU5kT3eHGA5iL+1Zd0EutOmTE9Dtk+Tvuzd23VBU+ec7HPNSTxXYO55gPV/hq4pSBJDjFpA==", + "dev": true, "license": "MIT", "dependencies": { "accepts": "^2.0.0", @@ -23501,6 +24004,7 @@ "version": "7.5.1", "resolved": "https://registry.npmjs.org/express-rate-limit/-/express-rate-limit-7.5.1.tgz", "integrity": "sha512-7iN8iPMDzOMHPUYllBEsQdWVB6fPDMPqwjBaFrgr4Jgr/+okjvzAy+UHlYYL/Vs0OsOrMkwS6PJDkFlJwoxUnw==", + "dev": true, "license": "MIT", "engines": { "node": ">= 16" @@ -23516,6 +24020,7 @@ "version": "2.1.0", "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-2.1.0.tgz", "integrity": "sha512-/t88Ty3d5JWQbWYgaOGCCYfXRwV1+be02WqYYlL6h0lEiUAMPM8o8qKGO01YIkOHzka2up08wvgYD0mDiI+q3Q==", + "dev": true, "license": "MIT", "dependencies": { "debug": "^4.4.0", @@ -23640,12 +24145,14 @@ "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, "license": "MIT" }, "node_modules/fast-glob": { "version": "3.3.3", "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.3.3.tgz", "integrity": "sha512-7MptL8U0cqcFdzIzwOTHoilX9x5BrNqye7Z/LuC7kCMRio1EMSyqRK3BEAUD7sXRq4iT4AzTVuZdhgQ2TCvYLg==", + "dev": true, "license": "MIT", "dependencies": { "@nodelib/fs.stat": "^2.0.2", @@ -23662,6 +24169,7 @@ "version": "5.1.2", "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", + "dev": true, "license": "ISC", "dependencies": { "is-glob": "^4.0.1" @@ -23674,18 +24182,21 @@ "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, "license": "MIT" }, "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, "license": "MIT" }, "node_modules/fast-uri": { "version": "3.0.6", "resolved": "https://registry.npmjs.org/fast-uri/-/fast-uri-3.0.6.tgz", "integrity": "sha512-Atfo14OibSv5wAp4VWNsFYE1AchQRTv9cBGWET4pZWHzYshFSS9NQI6I57rdKn9croWVMbYFbLhJ+yJvmZIIHw==", + "dev": true, "funding": [ { "type": "github", @@ -23712,6 +24223,7 @@ "version": "1.19.1", "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.19.1.tgz", "integrity": "sha512-GwLTyxkCXjXbxqIhTsMI2Nui8huMPtnxg7krajPJAjnEG/iiOS7i+zCtWGZR9G0NBKbXKh6X9m9UIsYX/N6vvQ==", + "dev": true, "license": "ISC", "dependencies": { "reusify": "^1.0.4" @@ -23721,6 +24233,7 @@ "version": "0.11.4", "resolved": "https://registry.npmjs.org/faye-websocket/-/faye-websocket-0.11.4.tgz", "integrity": "sha512-CzbClwlXAuiRQAlUyfqPgvPoNKTckTPGfwZV4ZdAhVcP2lh9KUxJg2b5GkE7XbjKQ3YJnQ9z6D9ntLAlB+tP8g==", + "dev": true, "license": "Apache-2.0", "dependencies": { "websocket-driver": ">=0.5.1" @@ -23733,6 +24246,7 @@ "version": "2.0.2", "resolved": "https://registry.npmjs.org/fb-watchman/-/fb-watchman-2.0.2.tgz", "integrity": "sha512-p5161BqbuCaSnB8jIbzQHOlpgsPmK5rJVDfDKO91Axs5NC1uu3HRQm6wt9cd9/+GtQQIO53JdGXXoyDpTAsgYA==", + "dev": true, "license": "Apache-2.0", "dependencies": { "bser": "2.1.1" @@ -23752,6 +24266,7 @@ "version": "6.5.0", "resolved": "https://registry.npmjs.org/fdir/-/fdir-6.5.0.tgz", "integrity": "sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg==", + "devOptional": true, "license": "MIT", "engines": { "node": ">=12.0.0" @@ -23803,6 +24318,7 @@ "version": "8.0.0", "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-8.0.0.tgz", "integrity": "sha512-XXTUwCvisa5oacNGRP9SfNtYBNAMi+RPwBFmblZEF7N7swHYQS6/Zfk7SRwx4D5j3CH211YNRco1DEMNVfZCnQ==", + "dev": true, "license": "MIT", "dependencies": { "flat-cache": "^4.0.0" @@ -23815,6 +24331,7 @@ "version": "1.0.4", "resolved": "https://registry.npmjs.org/filelist/-/filelist-1.0.4.tgz", "integrity": "sha512-w1cEuf3S+DrLCQL7ET6kz+gmlJdbq9J7yXCSjK/OZCPA+qEN1WyF4ZAf0YYJa4/shHJra2t/d/r8SV4Ji+x+8Q==", + "dev": true, "license": "Apache-2.0", "dependencies": { "minimatch": "^5.0.1" @@ -23824,6 +24341,7 @@ "version": "5.1.6", "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-5.1.6.tgz", "integrity": "sha512-lKwV/1brpG6mBUFHtb7NUmtABCb2WZZmm2wNiOA5hAb8VdCS4B3dtMWyvcoViccwAW/COERjXLt0zP1zXUN26g==", + "dev": true, "license": "ISC", "dependencies": { "brace-expansion": "^2.0.1" @@ -23836,6 +24354,7 @@ "version": "7.1.1", "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz", "integrity": "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==", + "dev": true, "license": "MIT", "dependencies": { "to-regex-range": "^5.0.1" @@ -23917,6 +24436,7 @@ "version": "4.0.0", "resolved": "https://registry.npmjs.org/find-cache-dir/-/find-cache-dir-4.0.0.tgz", "integrity": "sha512-9ZonPT4ZAK4a+1pUPVPZJapbi7O5qbbJPdYw/NOQWZZbVLdDTYM3A4R9z/DpAM08IDaFGsvPgiGZ82WEwUDWjg==", + "dev": true, "license": "MIT", "dependencies": { "common-path-prefix": "^3.0.0", @@ -23991,6 +24511,7 @@ "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, "license": "MIT", "dependencies": { "locate-path": "^6.0.0", @@ -24007,6 +24528,7 @@ "version": "5.0.2", "resolved": "https://registry.npmjs.org/flat/-/flat-5.0.2.tgz", "integrity": "sha512-b6suED+5/3rTpUBdG1gupIl8MPFCAMA0QXwmljLhvCUKcUvdE4gWky9zpuGCcXHOsz4J9wPGNWq6OKpmIzz3hQ==", + "dev": true, "license": "BSD-3-Clause", "bin": { "flat": "cli.js" @@ -24016,6 +24538,7 @@ "version": "4.0.1", "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-4.0.1.tgz", "integrity": "sha512-f7ccFPK3SXFHpx15UIGyRJ/FJQctuKZ0zVuN3frBo4HnK3cay9VEW0R6yPYFHC0AgqhukPzKjq22t5DmAyqGyw==", + "dev": true, "license": "MIT", "dependencies": { "flatted": "^3.2.9", @@ -24029,12 +24552,14 @@ "version": "3.3.3", "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.3.3.tgz", "integrity": "sha512-GX+ysw4PBCz0PzosHDepZGANEuFCMLrnRTiEy9McGjmkCQYwRq4A/X786G/fjM/+OjsWSU1ZrY5qyARZmO/uwg==", + "dev": true, "license": "ISC" }, "node_modules/follow-redirects": { "version": "1.15.9", "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.9.tgz", "integrity": "sha512-gew4GsXizNgdoRyqmyfMHyAmXsZDk6mHkSxZFCzW9gwlbtOW44CDtYavM+y+72qD/Vq2l550kMF52DT8fOLJqQ==", + "dev": true, "funding": [ { "type": "individual", @@ -24071,6 +24596,7 @@ "version": "3.3.1", "resolved": "https://registry.npmjs.org/foreground-child/-/foreground-child-3.3.1.tgz", "integrity": "sha512-gIXjKqtFuWEgzFRJA9WCQeSJLZDjgJUOMCMzxtvFq/37KojM1BFGufqsCy0r4qSQmYLsZYMeyRqzIWOMup03sw==", + "dev": true, "license": "ISC", "dependencies": { "cross-spawn": "^7.0.6", @@ -24336,6 +24862,7 @@ "version": "0.2.0", "resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.2.0.tgz", "integrity": "sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow==", + "dev": true, "license": "MIT", "engines": { "node": ">= 0.6" @@ -24368,6 +24895,7 @@ "version": "2.0.0", "resolved": "https://registry.npmjs.org/fresh/-/fresh-2.0.0.tgz", "integrity": "sha512-Rx/WycZ60HOaqLKAi6cHRKKI7zxWbJ31MhntmtwMoaTeF7XFH9hhBp8vITaMidfljRQ6eYWCKkaTK+ykVJHP2A==", + "dev": true, "license": "MIT", "engines": { "node": ">= 0.8" @@ -24416,6 +24944,7 @@ "version": "4.0.2", "resolved": "https://registry.npmjs.org/front-matter/-/front-matter-4.0.2.tgz", "integrity": "sha512-I8ZuJ/qG92NWX8i5x1Y8qyj3vizhXS31OxjKDu3LKP+7/qBgfIKValiZIEwoVoJKUHlhWtYrktkxV1XsX+pPlg==", + "dev": true, "license": "MIT", "dependencies": { "js-yaml": "^3.13.1" @@ -24425,6 +24954,7 @@ "version": "1.0.0", "resolved": "https://registry.npmjs.org/fs-constants/-/fs-constants-1.0.0.tgz", "integrity": "sha512-y6OAwoSIf7FyjMIv94u+b5rdheZEjzR63GTyZJm5qh4Bi+2YgwLCcI/fPFZkL5PSixOt6ZNKm+w+Hfp/Bciwow==", + "dev": true, "license": "MIT" }, "node_modules/fs-exists-sync": { @@ -24489,18 +25019,21 @@ "version": "1.0.6", "resolved": "https://registry.npmjs.org/fs-monkey/-/fs-monkey-1.0.6.tgz", "integrity": "sha512-b1FMfwetIKymC0eioW7mTywihSQE4oLzQn1dB6rZB5fx/3NpNEdAWeCSMB+60/AeT0TCXsxzAlcYVEFCTAksWg==", + "dev": true, "license": "Unlicense" }, "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, "license": "ISC" }, "node_modules/fsevents": { "version": "2.3.3", "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==", + "dev": true, "hasInstallScript": true, "license": "MIT", "optional": true, @@ -24555,6 +25088,7 @@ "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, "license": "MIT", "engines": { "node": ">=6.9.0" @@ -24564,6 +25098,7 @@ "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, "license": "ISC", "engines": { "node": "6.* || 8.* || >= 10.*" @@ -24610,6 +25145,7 @@ "version": "0.1.0", "resolved": "https://registry.npmjs.org/get-package-type/-/get-package-type-0.1.0.tgz", "integrity": "sha512-pjzuKtY64GYfWizNAJ0fr9VqttZkNiK2iS430LtIHzjBEr6bX8Am2zm4sW4Ro5wjWW5cAlRL1qAMTcXbjNAO2Q==", + "dev": true, "license": "MIT", "engines": { "node": ">=8.0.0" @@ -24710,6 +25246,7 @@ "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, "license": "ISC", "dependencies": { "is-glob": "^4.0.3" @@ -24722,6 +25259,7 @@ "version": "0.4.1", "resolved": "https://registry.npmjs.org/glob-to-regexp/-/glob-to-regexp-0.4.1.tgz", "integrity": "sha512-lkX1HJXwyMcprw/5YUZc2s7DrpAiHB21/V+E1rHUrVNokkvB6bqMzT0VfV6/86ZNabt1k14YOIaT7nDvOX3Iiw==", + "dev": true, "license": "BSD-2-Clause" }, "node_modules/glob/node_modules/minimatch": { @@ -24830,6 +25368,7 @@ "version": "12.2.0", "resolved": "https://registry.npmjs.org/globby/-/globby-12.2.0.tgz", "integrity": "sha512-wiSuFQLZ+urS9x2gGPl1H5drc5twabmm4m2gTR27XDFyjUHJUNsS8o/2aKyIF6IoBaR630atdher0XJ5g6OMmA==", + "dev": true, "license": "MIT", "dependencies": { "array-union": "^3.0.1", @@ -24850,6 +25389,7 @@ "version": "3.0.1", "resolved": "https://registry.npmjs.org/array-union/-/array-union-3.0.1.tgz", "integrity": "sha512-1OvF9IbWwaeiM9VhzYXVQacMibxpXOMYVNIvMtKRyX9SImBXpKcFr8XvFDeEslCyuH/t6KRt7HEO94AlP8Iatw==", + "dev": true, "license": "MIT", "engines": { "node": ">=12" @@ -24862,6 +25402,7 @@ "version": "5.3.2", "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.3.2.tgz", "integrity": "sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g==", + "dev": true, "license": "MIT", "engines": { "node": ">= 4" @@ -24871,6 +25412,7 @@ "version": "4.0.0", "resolved": "https://registry.npmjs.org/slash/-/slash-4.0.0.tgz", "integrity": "sha512-3dOsAHXXUkQTpOYcoAxLIorMTp4gIQr5IW3iVb7A7lFIp0VHhnynm9izx6TssdrIcVIESAlVjtnO2K8bg+Coew==", + "dev": true, "license": "MIT", "engines": { "node": ">=12" @@ -24940,6 +25482,7 @@ "version": "2.0.1", "resolved": "https://registry.npmjs.org/handle-thing/-/handle-thing-2.0.1.tgz", "integrity": "sha512-9Qn4yBxelxoh2Ow62nP+Ka/kMnOXRi8BXnRaUwezLNhqelnN49xKz4F/dPP8OYLxLxq6JDtZb2i9XznUQbNPTg==", + "dev": true, "license": "MIT" }, "node_modules/handlebars": { @@ -24978,6 +25521,7 @@ "version": "1.6.2", "resolved": "https://registry.npmjs.org/harmony-reflect/-/harmony-reflect-1.6.2.tgz", "integrity": "sha512-HIp/n38R9kQjDEziXyDTuW3vvoxxyxjxFzXLrBr18uB47GnSt+G9D29fqrpM5ZkspMcPICud3XsBJQ4Y2URg8g==", + "dev": true, "license": "(Apache-2.0 OR MPL-1.1)" }, "node_modules/has-bigints": { @@ -25101,7 +25645,7 @@ "version": "1.2.0", "resolved": "https://registry.npmjs.org/he/-/he-1.2.0.tgz", "integrity": "sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw==", - "devOptional": true, + "dev": true, "license": "MIT", "bin": { "he": "bin/he" @@ -25157,6 +25701,7 @@ "version": "2.1.6", "resolved": "https://registry.npmjs.org/hpack.js/-/hpack.js-2.1.6.tgz", "integrity": "sha512-zJxVehUdMGIKsRaNt7apO2Gqp0BdqW5yaiGHXXmbpvxgBYVZnAql+BJb4RO5ad2MgpbZKn5G6nMnegrH1FcNYQ==", + "dev": true, "license": "MIT", "dependencies": { "inherits": "^2.0.1", @@ -25198,6 +25743,7 @@ "version": "2.0.2", "resolved": "https://registry.npmjs.org/html-escaper/-/html-escaper-2.0.2.tgz", "integrity": "sha512-H2iMtd0I4Mt5eYiapRdIDjp+XzelXQ0tFE4JS7YFwFevXXMmOp9myNrUvCg0D6ws8iqkRPBfKHgbwig1SmlLfg==", + "dev": true, "license": "MIT" }, "node_modules/html-loader": { @@ -25264,7 +25810,7 @@ "version": "5.6.5", "resolved": "https://registry.npmjs.org/html-webpack-plugin/-/html-webpack-plugin-5.6.5.tgz", "integrity": "sha512-4xynFbKNNk+WlzXeQQ+6YYsH2g7mpfPszQZUi3ovKlj+pDmngQ7vRXjrrmGROabmKwyQkcgcX5hqfOwHbFmK5g==", - "devOptional": true, + "dev": true, "license": "MIT", "dependencies": { "@types/html-minifier-terser": "^6.0.0", @@ -25297,7 +25843,7 @@ "version": "8.3.0", "resolved": "https://registry.npmjs.org/commander/-/commander-8.3.0.tgz", "integrity": "sha512-OkTL9umf+He2DZkUq8f8J9of7yL6RJKI24dVITBmNfZBmri9zYZQrKkuXiKhyfPSu8tUhnVBB1iKXevvnlR4Ww==", - "devOptional": true, + "dev": true, "license": "MIT", "engines": { "node": ">= 12" @@ -25307,7 +25853,7 @@ "version": "6.1.0", "resolved": "https://registry.npmjs.org/html-minifier-terser/-/html-minifier-terser-6.1.0.tgz", "integrity": "sha512-YXxSlJBZTP7RS3tWnQw74ooKa6L9b9i9QYXY21eUEvhZ3u9XLfv6OnFsQq6RxkhHygsaUMvYsZRV5rU/OVNZxw==", - "devOptional": true, + "dev": true, "license": "MIT", "dependencies": { "camel-case": "^4.1.2", @@ -25452,6 +25998,7 @@ "version": "1.2.7", "resolved": "https://registry.npmjs.org/http-deceiver/-/http-deceiver-1.2.7.tgz", "integrity": "sha512-LmpOGxTfbpgtGVxJrj5k7asXHCgNZp5nLfp+hWc8QQRqtb7fUy6kRY3BO1h9ddF6yIPYUARgxGOwB42DnxIaNw==", + "dev": true, "license": "MIT" }, "node_modules/http-errors": { @@ -25483,12 +26030,14 @@ "version": "0.5.10", "resolved": "https://registry.npmjs.org/http-parser-js/-/http-parser-js-0.5.10.tgz", "integrity": "sha512-Pysuw9XpUq5dVc/2SMHpuTY01RFl8fttgcyunjL7eEMhGM3cI4eOmiCycJDVCo/7O7ClfQD3SaI6ftDzqOXYMA==", + "dev": true, "license": "MIT" }, "node_modules/http-proxy": { "version": "1.18.1", "resolved": "https://registry.npmjs.org/http-proxy/-/http-proxy-1.18.1.tgz", "integrity": "sha512-7mz/721AbnJwIVbnaSv1Cz3Am0ZLT/UBwkC92VlxhXv/k/BBQfM2fXElQNC27BVGr0uwUpplYPQM9LnaBMR5NQ==", + "dev": true, "license": "MIT", "dependencies": { "eventemitter3": "^4.0.0", @@ -25597,6 +26146,7 @@ "version": "1.2.0", "resolved": "https://registry.npmjs.org/hyperdyperid/-/hyperdyperid-1.2.0.tgz", "integrity": "sha512-Y93lCzHYgGWdrJ66yIktxiaGULYc6oGiABxhcO5AufBeOyoIdZF7bIfLaOrbM0iGIOXQQgxxRrFEnb+Y6w1n4A==", + "dev": true, "license": "MIT", "engines": { "node": ">=10.18" @@ -25676,6 +26226,7 @@ "version": "5.1.0", "resolved": "https://registry.npmjs.org/icss-utils/-/icss-utils-5.1.0.tgz", "integrity": "sha512-soFhflCVWLfRNOPU3iv5Z9VUdT44xFRbzjLsEzSr5AQmgqPMTHdU3PMT1Cf1ssx8fLNJDA1juftYl+PUcv3MqA==", + "dev": true, "license": "ISC", "engines": { "node": "^10 || ^12 || >= 14" @@ -25688,6 +26239,7 @@ "version": "3.0.0", "resolved": "https://registry.npmjs.org/identity-obj-proxy/-/identity-obj-proxy-3.0.0.tgz", "integrity": "sha512-00n6YnVHKrinT9t0d9+5yZC6UBNJANpYEQvL2LlX6Ab9lnmxzIRcEmTPuyGScvl1+jKuCICX1Z0Ab1pPKKdikA==", + "dev": true, "license": "MIT", "dependencies": { "harmony-reflect": "^1.4.6" @@ -25759,6 +26311,7 @@ "version": "0.5.5", "resolved": "https://registry.npmjs.org/image-size/-/image-size-0.5.5.tgz", "integrity": "sha512-6TDAlDPZxUFCv+fuOkIoXT/V/f3Qbq8e37p+YOiYrUv3v9cc3/6x78VdfPgFVaB9dZYeLUfKgHRebpkm/oP2VQ==", + "dev": true, "license": "MIT", "optional": true, "bin": { @@ -25778,6 +26331,7 @@ "version": "5.1.3", "resolved": "https://registry.npmjs.org/immutable/-/immutable-5.1.3.tgz", "integrity": "sha512-+chQdDfvscSF1SJqv2gn4SRO2ZyS3xL3r7IW/wWEEzrzLisnOlKiQu5ytC/BVNcS15C39WT2Hg/bjKjDMcu+zg==", + "dev": true, "license": "MIT" }, "node_modules/import-fresh": { @@ -25898,6 +26452,7 @@ "version": "0.1.4", "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", "integrity": "sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==", + "dev": true, "license": "MIT", "engines": { "node": ">=0.8.19" @@ -25934,6 +26489,7 @@ "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", "integrity": "sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==", "deprecated": "This module is not supported, and leaks memory. Do not use it. Check out lru-cache if you want a good and tested way to coalesce async requests by a key value, which is much more comprehensive and powerful.", + "dev": true, "license": "ISC", "dependencies": { "once": "^1.3.0", @@ -26063,6 +26619,7 @@ "version": "1.9.1", "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.9.1.tgz", "integrity": "sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g==", + "dev": true, "license": "MIT", "engines": { "node": ">= 0.10" @@ -26149,6 +26706,7 @@ "version": "2.1.0", "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz", "integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==", + "dev": true, "license": "MIT", "dependencies": { "binary-extensions": "^2.0.0" @@ -26279,6 +26837,7 @@ "version": "2.1.1", "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==", + "dev": true, "license": "MIT", "engines": { "node": ">=0.10.0" @@ -26313,6 +26872,7 @@ "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, "license": "MIT", "engines": { "node": ">=6" @@ -26341,6 +26901,7 @@ "version": "4.0.3", "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", + "dev": true, "license": "MIT", "dependencies": { "is-extglob": "^2.1.1" @@ -26425,6 +26986,7 @@ "version": "1.1.0", "resolved": "https://registry.npmjs.org/is-network-error/-/is-network-error-1.1.0.tgz", "integrity": "sha512-tUdRRAnhT+OtCZR/LxZelH/C7QtjtFrTu5tXCA8pl55eTUElUHT+GPYV8MBMBvea/j+NxQqVt3LbWMRir7Gx9g==", + "dev": true, "license": "MIT", "engines": { "node": ">=16" @@ -26437,6 +26999,7 @@ "version": "7.0.0", "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", + "dev": true, "license": "MIT", "engines": { "node": ">=0.12.0" @@ -26685,6 +27248,7 @@ "version": "3.14.1", "resolved": "https://registry.npmjs.org/is-what/-/is-what-3.14.1.tgz", "integrity": "sha512-sNxgpk9793nzSs7bA6JQJGeIuRBQhAaNGG77kzYQgMkrID+lS6SlK07K5LaptscDlSaIgH+GPFzf+d75FVxozA==", + "dev": true, "license": "MIT" }, "node_modules/is-windows": { @@ -26736,6 +27300,7 @@ "version": "2.0.0", "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==", + "dev": true, "license": "ISC" }, "node_modules/isobject": { @@ -26752,6 +27317,7 @@ "version": "3.2.2", "resolved": "https://registry.npmjs.org/istanbul-lib-coverage/-/istanbul-lib-coverage-3.2.2.tgz", "integrity": "sha512-O8dpsF+r0WV/8MNRKfnmrtCWhuKjxrq2w+jpzBL5UZKTi2LeVWnWOmWRxFlesJONmc+wLAGvKQZEOanko0LFTg==", + "dev": true, "license": "BSD-3-Clause", "engines": { "node": ">=8" @@ -26774,6 +27340,7 @@ "version": "6.0.3", "resolved": "https://registry.npmjs.org/istanbul-lib-instrument/-/istanbul-lib-instrument-6.0.3.tgz", "integrity": "sha512-Vtgk7L/R2JHyyGW07spoFlB8/lpjiOLTjMdms6AFMraYt3BaJauod/NGrfnVG/y4Ix1JEuMRPDPEj2ua+zz1/Q==", + "dev": true, "license": "BSD-3-Clause", "dependencies": { "@babel/core": "^7.23.9", @@ -26894,6 +27461,7 @@ "version": "3.0.1", "resolved": "https://registry.npmjs.org/istanbul-lib-report/-/istanbul-lib-report-3.0.1.tgz", "integrity": "sha512-GCfE1mtsHGOELCU8e/Z7YWzpmybrx/+dSTfLrvY8qRmaY6zXTKWn6WQIjaAFw069icm6GVMNkgu0NzI4iPZUNw==", + "dev": true, "license": "BSD-3-Clause", "dependencies": { "istanbul-lib-coverage": "^3.0.0", @@ -26933,6 +27501,7 @@ "version": "3.1.7", "resolved": "https://registry.npmjs.org/istanbul-reports/-/istanbul-reports-3.1.7.tgz", "integrity": "sha512-BewmUXImeuRk2YY0PVbxgKAysvhRPUQE0h5QRM++nVWyubKGV0l8qQ5op8+B2DOmwSe63Jivj0BjkPQVf8fP5g==", + "dev": true, "license": "BSD-3-Clause", "dependencies": { "html-escaper": "^2.0.0", @@ -26962,6 +27531,7 @@ "version": "10.9.2", "resolved": "https://registry.npmjs.org/jake/-/jake-10.9.2.tgz", "integrity": "sha512-2P4SQ0HrLQ+fw6llpLnOaGAvN2Zu6778SJMrCUwns4fOoG9ayrTiZk3VV8sCPkVZF8ab0zksVpS8FDY5pRCNBA==", + "dev": true, "license": "Apache-2.0", "dependencies": { "async": "^3.2.3", @@ -26980,6 +27550,7 @@ "version": "1.1.12", "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.12.tgz", "integrity": "sha512-9T9UjW3r0UW5c1Q7GTwllptXwhvYmEzFhzMfZ9H7FQWt+uZePjZPjBP/W1ZEyZ1twGWom5/56TF4lPcqjnDHcg==", + "dev": true, "license": "MIT", "dependencies": { "balanced-match": "^1.0.0", @@ -26990,6 +27561,7 @@ "version": "3.1.2", "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "dev": true, "license": "ISC", "dependencies": { "brace-expansion": "^1.1.7" @@ -27272,6 +27844,7 @@ "version": "30.2.0", "resolved": "https://registry.npmjs.org/jest-diff/-/jest-diff-30.2.0.tgz", "integrity": "sha512-dQHFo3Pt4/NLlG5z4PxZ/3yZTZ1C7s9hveiOj+GCN+uT109NC2QgsoVZsVOAvbJ3RgKkvyLGXZV9+piDpWbm6A==", + "dev": true, "license": "MIT", "dependencies": { "@jest/diff-sequences": "30.0.1", @@ -27287,6 +27860,7 @@ "version": "30.0.5", "resolved": "https://registry.npmjs.org/@jest/schemas/-/schemas-30.0.5.tgz", "integrity": "sha512-DmdYgtezMkh3cpU8/1uyXakv3tJRcmcXxBOcO0tbaozPwpmh4YMsnWrQm9ZmZMfa5ocbxzbFk6O4bDPEc/iAnA==", + "dev": true, "license": "MIT", "dependencies": { "@sinclair/typebox": "^0.34.0" @@ -27299,12 +27873,14 @@ "version": "0.34.41", "resolved": "https://registry.npmjs.org/@sinclair/typebox/-/typebox-0.34.41.tgz", "integrity": "sha512-6gS8pZzSXdyRHTIqoqSVknxolr1kzfy4/CeDnrzsVz8TTIWUbOBr6gnzOmTYJ3eXQNh4IYHIGi5aIL7sOZ2G/g==", + "dev": true, "license": "MIT" }, "node_modules/jest-diff/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, "license": "MIT", "engines": { "node": ">=10" @@ -27317,6 +27893,7 @@ "version": "30.2.0", "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-30.2.0.tgz", "integrity": "sha512-9uBdv/B4EefsuAL+pWqueZyZS2Ba+LxfFeQ9DN14HU4bN8bhaxKdkpjpB6fs9+pSjIBu+FXQHImEg8j/Lw0+vA==", + "dev": true, "license": "MIT", "dependencies": { "@jest/schemas": "30.0.5", @@ -27331,6 +27908,7 @@ "version": "18.3.1", "resolved": "https://registry.npmjs.org/react-is/-/react-is-18.3.1.tgz", "integrity": "sha512-/LLMVyas0ljjAtoYiPqYiL8VWXzUUdThrmU5+n20DZv+a+ClRoevUzw5JxU+Ieh5/c87ytoTBV9G1FiKfNJdmg==", + "dev": true, "license": "MIT" }, "node_modules/jest-docblock": { @@ -27669,7 +28247,7 @@ "version": "29.6.3", "resolved": "https://registry.npmjs.org/jest-get-type/-/jest-get-type-29.6.3.tgz", "integrity": "sha512-zrteXnqYxfQh7l5FHyL38jL39di8H8rHoecLH3JNxH3BwOrBsNeabdap5e0I23lD4HHI8W5VFBZqG4Eaq5LNcw==", - "devOptional": true, + "dev": true, "license": "MIT", "engines": { "node": "^14.15.0 || ^16.10.0 || >=18.0.0" @@ -27679,7 +28257,7 @@ "version": "29.7.0", "resolved": "https://registry.npmjs.org/jest-haste-map/-/jest-haste-map-29.7.0.tgz", "integrity": "sha512-fP8u2pyfqx0K1rGn1R9pyE0/KTn+G7PxktWidOBTqFPLYX0b9ksaMFkhK5vrS3DVun09pckLdlx90QthlW7AmA==", - "devOptional": true, + "dev": true, "license": "MIT", "dependencies": { "@jest/types": "^29.6.3", @@ -28026,6 +28604,7 @@ "version": "1.2.3", "resolved": "https://registry.npmjs.org/jest-pnp-resolver/-/jest-pnp-resolver-1.2.3.tgz", "integrity": "sha512-+3NpwQEnRoIBtx4fyhblQDPgJI0H1IEIkX7ShLUjPGA7TtUTvI1oiKi3SR4oBR0hQhQR80l4WAe5RrXBwWMA8w==", + "dev": true, "license": "MIT", "engines": { "node": ">=6" @@ -28158,7 +28737,7 @@ "version": "29.6.3", "resolved": "https://registry.npmjs.org/jest-regex-util/-/jest-regex-util-29.6.3.tgz", "integrity": "sha512-KJJBsRCyyLNWCNBOvZyRDnAIfUiRJ8v+hOBQYGn8gDyF3UegwiP4gwRR3/SDa42g1YbVycTidUF3rKjyLFDWbg==", - "devOptional": true, + "dev": true, "license": "MIT", "engines": { "node": "^14.15.0 || ^16.10.0 || >=18.0.0" @@ -28168,7 +28747,7 @@ "version": "29.7.0", "resolved": "https://registry.npmjs.org/jest-resolve/-/jest-resolve-29.7.0.tgz", "integrity": "sha512-IOVhZSrg+UvVAshDSDtHyFCCBUl/Q3AAJv8iZ6ZjnZ74xzvwuzLXid9IIIPgTnY62SJjfuupMKZsZQRsCvxEgA==", - "devOptional": true, + "dev": true, "license": "MIT", "dependencies": { "chalk": "^4.0.0", @@ -28430,6 +29009,7 @@ "version": "29.7.0", "resolved": "https://registry.npmjs.org/jest-util/-/jest-util-29.7.0.tgz", "integrity": "sha512-z6EbKajIpqGKU56y5KBUgy1dt1ihhQJgWzUlZHArA/+X2ad7Cb5iF+AK1EWVL/Bo7Rz9uurpqw6SiBCefUbCGA==", + "dev": true, "license": "MIT", "dependencies": { "@jest/types": "^29.6.3", @@ -28447,6 +29027,7 @@ "version": "2.3.1", "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", + "dev": true, "license": "MIT", "engines": { "node": ">=8.6" @@ -28459,7 +29040,7 @@ "version": "29.7.0", "resolved": "https://registry.npmjs.org/jest-validate/-/jest-validate-29.7.0.tgz", "integrity": "sha512-ZB7wHqaRGVw/9hST/OuFUReG7M8vKeq0/J2egIGLdvjHCmYqGARhzXmtgi+gVeZ5uXFF219aOc3Ls2yLg27tkw==", - "devOptional": true, + "dev": true, "license": "MIT", "dependencies": { "@jest/types": "^29.6.3", @@ -28477,7 +29058,7 @@ "version": "5.2.0", "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-5.2.0.tgz", "integrity": "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==", - "devOptional": true, + "dev": true, "license": "MIT", "engines": { "node": ">=10" @@ -28490,7 +29071,7 @@ "version": "6.3.0", "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-6.3.0.tgz", "integrity": "sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA==", - "devOptional": true, + "dev": true, "license": "MIT", "engines": { "node": ">=10" @@ -28503,7 +29084,7 @@ "version": "29.7.0", "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-29.7.0.tgz", "integrity": "sha512-Pdlw/oPxN+aXdmM9R00JVC9WVFoCLTKJvDVLgmJ+qAffBMxsV85l/Lu7sNx4zSzPyoL2euImuEwHhOXdEgNFZQ==", - "devOptional": true, + "dev": true, "license": "MIT", "dependencies": { "@jest/schemas": "^29.6.3", @@ -28518,7 +29099,7 @@ "version": "18.3.1", "resolved": "https://registry.npmjs.org/react-is/-/react-is-18.3.1.tgz", "integrity": "sha512-/LLMVyas0ljjAtoYiPqYiL8VWXzUUdThrmU5+n20DZv+a+ClRoevUzw5JxU+Ieh5/c87ytoTBV9G1FiKfNJdmg==", - "devOptional": true, + "dev": true, "license": "MIT" }, "node_modules/jest-watch-typeahead": { @@ -28662,6 +29243,7 @@ "version": "29.7.0", "resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-29.7.0.tgz", "integrity": "sha512-eIz2msL/EzL9UFTFFx7jBTkeZfku0yUAyZZZmJ93H2TYEiroIx2PQjEXcwYtYl8zXCxb+PAmA2hLIt/6ZEkPHw==", + "dev": true, "license": "MIT", "dependencies": { "@types/node": "*", @@ -28677,6 +29259,7 @@ "version": "8.1.1", "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz", "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==", + "dev": true, "license": "MIT", "dependencies": { "has-flag": "^4.0.0" @@ -28692,7 +29275,7 @@ "version": "1.21.7", "resolved": "https://registry.npmjs.org/jiti/-/jiti-1.21.7.tgz", "integrity": "sha512-/imKNG4EbWNrVjoNC/1H5/9GFy+tqjGBHCaSsN+P2RnPqjsLmv6UD3Ej+Kj8nBWaRAwyk7kK5ZUc+OEatnTR3A==", - "devOptional": true, + "dev": true, "license": "MIT", "bin": { "jiti": "bin/jiti.js" @@ -28722,6 +29305,7 @@ "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, "license": "MIT", "dependencies": { "argparse": "^1.0.7", @@ -28735,6 +29319,7 @@ "version": "1.0.10", "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz", "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==", + "dev": true, "license": "MIT", "dependencies": { "sprintf-js": "~1.0.2" @@ -28744,6 +29329,7 @@ "version": "1.0.3", "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz", "integrity": "sha512-D9cPgkvLlV3t3IzL0D0YLvGA9Ahk4PcvVwUbN0dSGr1aP0Nrt4AEnTUbuGvquEC0mA64Gqt1fzirlRs5ibXx8g==", + "dev": true, "license": "BSD-3-Clause" }, "node_modules/jsbn": { @@ -28838,6 +29424,7 @@ "version": "3.0.1", "resolved": "https://registry.npmjs.org/json-buffer/-/json-buffer-3.0.1.tgz", "integrity": "sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ==", + "dev": true, "license": "MIT" }, "node_modules/json-parse-even-better-errors": { @@ -28854,6 +29441,7 @@ "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, "license": "MIT" }, "node_modules/json-schema-typed": { @@ -28867,6 +29455,7 @@ "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, "license": "MIT" }, "node_modules/json-stringify-safe": { @@ -28879,6 +29468,7 @@ "version": "2.2.3", "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.3.tgz", "integrity": "sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==", + "dev": true, "license": "MIT", "bin": { "json5": "lib/cli.js" @@ -29014,6 +29604,7 @@ "version": "4.5.4", "resolved": "https://registry.npmjs.org/keyv/-/keyv-4.5.4.tgz", "integrity": "sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw==", + "dev": true, "license": "MIT", "dependencies": { "json-buffer": "3.0.1" @@ -29043,6 +29634,7 @@ "version": "2.0.6", "resolved": "https://registry.npmjs.org/klona/-/klona-2.0.6.tgz", "integrity": "sha512-dhG34DXATL5hSxJbIexCft8FChFXtmskoZYnoPWjXQuebWYCNkVeV3KkGegCK9CP1oswI/vQibS2GY7Em/sJJA==", + "dev": true, "license": "MIT", "engines": { "node": ">= 8" @@ -29224,6 +29816,7 @@ "version": "2.10.0", "resolved": "https://registry.npmjs.org/launch-editor/-/launch-editor-2.10.0.tgz", "integrity": "sha512-D7dBRJo/qcGX9xlvt/6wUYzQxjh5G1RvZPgPv8vi4KRU99DVQL/oW7tnVOCCTm2HGeo3C5HvGE5Yrh6UBoZ0vA==", + "dev": true, "license": "MIT", "dependencies": { "picocolors": "^1.0.0", @@ -29241,6 +29834,7 @@ "version": "4.4.0", "resolved": "https://registry.npmjs.org/less/-/less-4.4.0.tgz", "integrity": "sha512-kdTwsyRuncDfjEs0DlRILWNvxhDG/Zij4YLO4TMJgDLW+8OzpfkdPnRgrsRuY1o+oaxJGWsps5f/RVBgGmmN0w==", + "dev": true, "license": "Apache-2.0", "dependencies": { "copy-anything": "^2.0.1", @@ -29294,6 +29888,7 @@ "version": "2.1.0", "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-2.1.0.tgz", "integrity": "sha512-LS9X+dc8KLxXCb8dni79fLIIUA5VyZoyjSMCwTluaXA0o27cCK0bhXkpgw+sTXVpPy/lSO57ilRixqk0vDmtRA==", + "dev": true, "license": "MIT", "optional": true, "dependencies": { @@ -29308,6 +29903,7 @@ "version": "1.6.0", "resolved": "https://registry.npmjs.org/mime/-/mime-1.6.0.tgz", "integrity": "sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==", + "dev": true, "license": "MIT", "optional": true, "bin": { @@ -29321,6 +29917,7 @@ "version": "4.0.1", "resolved": "https://registry.npmjs.org/pify/-/pify-4.0.1.tgz", "integrity": "sha512-uB80kBFb/tfd68bVleG9T5GGsGPjJrLAUpR5PZIrhBnIaRTQRjqdJSsIKkOP6OAIFbj7GOrcudc5pNjZ+geV2g==", + "dev": true, "license": "MIT", "optional": true, "engines": { @@ -29331,6 +29928,7 @@ "version": "5.7.2", "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.2.tgz", "integrity": "sha512-cBznnQ9KjJqU67B52RMC65CMarK2600WFnbkcaiwWq3xy/5haFJlshgnpjovMVJ+Hff49d8GEn0b87C5pDQ10g==", + "dev": true, "license": "ISC", "optional": true, "bin": { @@ -29341,6 +29939,7 @@ "version": "0.6.1", "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true, "license": "BSD-3-Clause", "optional": true, "engines": { @@ -29351,6 +29950,7 @@ "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, "license": "MIT", "engines": { "node": ">=6" @@ -29360,6 +29960,7 @@ "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, "license": "MIT", "dependencies": { "prelude-ls": "^1.2.1", @@ -29373,6 +29974,7 @@ "version": "4.0.2", "resolved": "https://registry.npmjs.org/license-webpack-plugin/-/license-webpack-plugin-4.0.2.tgz", "integrity": "sha512-771TFWFD70G1wLTC4oU2Cw4qvtmNrIw+wRvBtn+okgHl7slJVi7zfNcdmqDL72BojM30VNJ2UHylr1o77U37Jw==", + "dev": true, "license": "ISC", "dependencies": { "webpack-sources": "^3.0.0" @@ -29399,6 +30001,7 @@ "version": "3.1.3", "resolved": "https://registry.npmjs.org/lilconfig/-/lilconfig-3.1.3.tgz", "integrity": "sha512-/vlFKAoH5Cgt3Ie+JLhRbwOsCQePABiU3tJ1egGvyQ+33R/vcwM2Zl2QR/LzjsBeItPt3oSVXapn+m4nQDvpzw==", + "dev": true, "license": "MIT", "engines": { "node": ">=14" @@ -29411,6 +30014,7 @@ "version": "2.0.3", "resolved": "https://registry.npmjs.org/lines-and-columns/-/lines-and-columns-2.0.3.tgz", "integrity": "sha512-cNOjgCnLB+FnvWWtyRTzmB3POJ+cXxTA81LoW7u8JdmhfXzriropYwpjShnz1QLLWsQwY7nIxoDmcPTwphDK9w==", + "dev": true, "license": "MIT", "engines": { "node": "^12.20.0 || ^14.13.1 || >=16.0.0" @@ -29844,6 +30448,7 @@ "version": "4.3.1", "resolved": "https://registry.npmjs.org/loader-runner/-/loader-runner-4.3.1.tgz", "integrity": "sha512-IWqP2SCPhyVFTBtRcgMHdzlf9ul25NwaFx4wCEH/KjAXuuHY4yNjvPXsBokp8jCB936PyWRaPKUNh8NvylLp2Q==", + "dev": true, "license": "MIT", "engines": { "node": ">=6.11.5" @@ -29867,6 +30472,7 @@ "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, "license": "MIT", "dependencies": { "p-locate": "^5.0.0" @@ -29888,6 +30494,7 @@ "version": "4.0.8", "resolved": "https://registry.npmjs.org/lodash.debounce/-/lodash.debounce-4.0.8.tgz", "integrity": "sha512-FT1yDzDYEoYWhnSGnpE/4Kj1fLZkDFyqRb7fNt6FdYOSxlUWAtp42Eh6Wb0rGIv/m9Bgo7x4GhQbm5Ys4SG5ow==", + "dev": true, "license": "MIT" }, "node_modules/lodash.escaperegexp": { @@ -29916,18 +30523,21 @@ "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, "license": "MIT" }, "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, "license": "MIT" }, "node_modules/lodash.uniq": { "version": "4.5.0", "resolved": "https://registry.npmjs.org/lodash.uniq/-/lodash.uniq-4.5.0.tgz", "integrity": "sha512-xfBaXQd9ryd9dlSDvnvI0lvxfLJlYAZzXomUYzLKtUeOQvOP5piqAWuGtrhWeqaXK9hhoM/iyJc5AV+XfsX3HQ==", + "dev": true, "license": "MIT" }, "node_modules/log-symbols": { @@ -30221,7 +30831,7 @@ "version": "2.0.2", "resolved": "https://registry.npmjs.org/lower-case/-/lower-case-2.0.2.tgz", "integrity": "sha512-7fm3l3NAF9WfN6W3JOmf5drwpVqX78JtoGJ3A6W0a6ZnldM41w2fV5D490psKFTpMds8TJse/eHLFFsNHHjHgg==", - "devOptional": true, + "dev": true, "license": "MIT", "dependencies": { "tslib": "^2.0.3" @@ -30241,6 +30851,7 @@ "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, "license": "ISC", "dependencies": { "yallist": "^3.0.2" @@ -30290,6 +30901,7 @@ "version": "4.0.0", "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-4.0.0.tgz", "integrity": "sha512-hXdUTZYIVOt1Ex//jAQi+wTZZpUpwBj/0QsOzqegb3rGMMeJiSEu5xLHnYfBrRV4RH2+OCSOO95Is/7x1WJ4bw==", + "dev": true, "license": "MIT", "dependencies": { "semver": "^7.5.3" @@ -30421,6 +31033,7 @@ "version": "1.0.12", "resolved": "https://registry.npmjs.org/makeerror/-/makeerror-1.0.12.tgz", "integrity": "sha512-JmqCvUhmt43madlpFzG4BQzG2Z3m6tvQDNKdClZnO3VbIudJYmxsT0FNJMeiB2+JTSlTQTSbU8QdesVmwJcmLg==", + "dev": true, "license": "BSD-3-Clause", "dependencies": { "tmpl": "1.0.5" @@ -30710,6 +31323,7 @@ "version": "2.0.30", "resolved": "https://registry.npmjs.org/mdn-data/-/mdn-data-2.0.30.tgz", "integrity": "sha512-GaqWWShW4kv/G9IEucWScBx9G1/vsFZZJUO+tD26M8J8z3Kw5RDQjaoZe03YAClgeS/SWPOcb4nkFBTEi5DUEA==", + "dev": true, "license": "CC0-1.0" }, "node_modules/media-typer": { @@ -30725,6 +31339,7 @@ "version": "3.5.3", "resolved": "https://registry.npmjs.org/memfs/-/memfs-3.5.3.tgz", "integrity": "sha512-UERzLsxzllchadvbPs5aolHh65ISpKpM+ccLbOJ8/vvpBKmAWf+la7dXFy7Mr0ySHbdHrFv5kGFCUHHe6GFEmw==", + "dev": true, "license": "Unlicense", "dependencies": { "fs-monkey": "^1.0.4" @@ -30737,6 +31352,7 @@ "version": "2.0.0", "resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-2.0.0.tgz", "integrity": "sha512-Snk314V5ayFLhp3fkUREub6WtjBfPdCPY1Ln8/8munuLuiYhsABgBVWsozAG+MWMbVEvcdcpbi9R7ww22l9Q3g==", + "dev": true, "license": "MIT", "engines": { "node": ">=18" @@ -30749,12 +31365,14 @@ "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, "license": "MIT" }, "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, "license": "MIT", "engines": { "node": ">= 8" @@ -30764,6 +31382,7 @@ "version": "1.1.2", "resolved": "https://registry.npmjs.org/methods/-/methods-1.1.2.tgz", "integrity": "sha512-iclAHeNqNm68zFtnZ0e+1L2yUIdvzNoauKU4WBA3VvH/vPFieF7qfRlwUZU+DA9P9bPXIS90ulxoUoCH23sV2w==", + "dev": true, "license": "MIT", "engines": { "node": ">= 0.6" @@ -31364,6 +31983,7 @@ "version": "4.0.8", "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.8.tgz", "integrity": "sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA==", + "dev": true, "license": "MIT", "dependencies": { "braces": "^3.0.3", @@ -31377,6 +31997,7 @@ "version": "2.3.1", "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", + "dev": true, "license": "MIT", "engines": { "node": ">=8.6" @@ -31487,12 +32108,14 @@ "version": "1.0.1", "resolved": "https://registry.npmjs.org/minimalistic-assert/-/minimalistic-assert-1.0.1.tgz", "integrity": "sha512-UtJcAD4yEaGtjPezWuO9wC4nwUnVH/8/Im3yEHQP4b67cXlD/Qr9hdITCU1xDbSEXg2XKNaP8jsReV7vQd00/A==", + "dev": true, "license": "ISC" }, "node_modules/minimatch": { "version": "9.0.3", "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.3.tgz", "integrity": "sha512-RHiac9mvaRw0x3AYRgDC1CxAP7HTcNrrECeA8YYJeWnpo+2Q5CegtZjaotWTWxDG3UeGA1coE05iH1mPjT/2mg==", + "dev": true, "license": "ISC", "dependencies": { "brace-expansion": "^2.0.1" @@ -31517,6 +32140,7 @@ "version": "7.1.2", "resolved": "https://registry.npmjs.org/minipass/-/minipass-7.1.2.tgz", "integrity": "sha512-qOOzS1cBTWYF4BH8fVePDBOO9iptMnGUEZwNc/cMWnTV2nVLZ7VoNWEPHkYczZA0pdoA7dl6e7FL659nX9S2aw==", + "dev": true, "license": "ISC", "engines": { "node": ">=16 || 14 >=14.17" @@ -31920,6 +32544,7 @@ "version": "7.2.5", "resolved": "https://registry.npmjs.org/multicast-dns/-/multicast-dns-7.2.5.tgz", "integrity": "sha512-2eznPJP8z2BFLX50tf0LuODrpINqP1RVIm/CObbTcBRITQgmC/TjcREF1NeTBzIcR5XO/ukWo+YHOjBbFwIupg==", + "dev": true, "license": "MIT", "dependencies": { "dns-packet": "^5.2.2", @@ -32018,6 +32643,7 @@ "version": "3.3.11", "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.11.tgz", "integrity": "sha512-N8SpfPUnUp1bK+PMYW8qSWdl9U+wwNWI4QKxOYDy9JAro3WMX7p2OeVRF9v+347pnakNevPmiHhNmZ2HbFA76w==", + "devOptional": true, "funding": [ { "type": "github", @@ -32043,6 +32669,7 @@ "version": "0.2.4", "resolved": "https://registry.npmjs.org/napi-postinstall/-/napi-postinstall-0.2.4.tgz", "integrity": "sha512-ZEzHJwBhZ8qQSbknHqYcdtQVr8zUgGyM/q6h6qAyhtyVMNrSgDhrC4disf03dYW0e+czXyLnZINnCTEkWy0eJg==", + "dev": true, "license": "MIT", "bin": { "napi-postinstall": "lib/cli.js" @@ -32058,12 +32685,14 @@ "version": "1.4.0", "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz", "integrity": "sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==", + "dev": true, "license": "MIT" }, "node_modules/needle": { "version": "3.3.1", "resolved": "https://registry.npmjs.org/needle/-/needle-3.3.1.tgz", "integrity": "sha512-6k0YULvhpw+RoLNiQCRKOl09Rv1dPLr8hHnVjHqdolKwDrdNyk+Hmrthi4lIGPPz3r39dLx0hsF5s40sZ3Us4Q==", + "dev": true, "license": "MIT", "optional": true, "dependencies": { @@ -32081,6 +32710,7 @@ "version": "1.0.0", "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-1.0.0.tgz", "integrity": "sha512-8Ofs/AUQh8MaEcrlq5xOX0CQ9ypTF5dl78mjlMNfOK08fzpgTHQRQPBxcPlEtIw0yRpws+Zo/3r+5WRby7u3Gg==", + "dev": true, "license": "MIT", "engines": { "node": ">= 0.6" @@ -32090,6 +32720,7 @@ "version": "2.6.2", "resolved": "https://registry.npmjs.org/neo-async/-/neo-async-2.6.2.tgz", "integrity": "sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw==", + "dev": true, "license": "MIT" }, "node_modules/neotraverse": { @@ -32120,7 +32751,7 @@ "version": "3.0.4", "resolved": "https://registry.npmjs.org/no-case/-/no-case-3.0.4.tgz", "integrity": "sha512-fgAN3jGAh+RoxUGZHTSOLJIqUc2wmoBwGR4tbpNAKmmovFoWq0OdRkb0VkldReO2a2iBT/OEulG9XSUc10r3zg==", - "devOptional": true, + "dev": true, "license": "MIT", "dependencies": { "lower-case": "^2.0.2", @@ -32144,6 +32775,7 @@ "version": "3.1.1", "resolved": "https://registry.npmjs.org/node-abort-controller/-/node-abort-controller-3.1.1.tgz", "integrity": "sha512-AGK2yQKIjRuqnc6VkX2Xj5d+QW8xZ87pa1UK6yA6ouUyuxfHuMP6umE5QK7UmTeOAymo+Zx1Fxiuw9rVx8taHQ==", + "dev": true, "license": "MIT" }, "node_modules/node-addon-api": { @@ -32633,12 +33265,14 @@ "version": "0.4.0", "resolved": "https://registry.npmjs.org/node-int64/-/node-int64-0.4.0.tgz", "integrity": "sha512-O5lz91xSOeoXP6DulyHfllpq+Eg00MWitZIbtPfoSEvqIHdl5gfcY6hYzDWnj0qD5tz52PI08u9qUvSVeUBeHw==", + "dev": true, "license": "MIT" }, "node_modules/node-machine-id": { "version": "1.1.12", "resolved": "https://registry.npmjs.org/node-machine-id/-/node-machine-id-1.1.12.tgz", "integrity": "sha512-QNABxbrPa3qEIfrE6GOJ7BYIuignnJw7iQ2YPbc3Nla1HzRJjXzZOiikfF8m7eAMfichLt3M4VgLOetqgDmgGQ==", + "dev": true, "license": "MIT" }, "node_modules/node-preload": { @@ -32658,6 +33292,7 @@ "version": "2.0.27", "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.27.tgz", "integrity": "sha512-nmh3lCkYZ3grZvqcCH+fjmQ7X+H0OeZgP40OierEaAptX4XofMh5kwNbWh7lBduUzCcV/8kZ+NDLCwm2iorIlA==", + "dev": true, "license": "MIT" }, "node_modules/nopt": { @@ -32680,6 +33315,7 @@ "version": "3.0.0", "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==", + "dev": true, "license": "MIT", "engines": { "node": ">=0.10.0" @@ -32689,6 +33325,7 @@ "version": "0.1.2", "resolved": "https://registry.npmjs.org/normalize-range/-/normalize-range-0.1.2.tgz", "integrity": "sha512-bdok/XvKII3nUpklnV6P2hxtMNrCboOjAcyBuQnWEhO665FwrSNRxU+AqpsyvO6LgGYPspN+lu5CLtw4jPRKNA==", + "dev": true, "license": "MIT", "engines": { "node": ">=0.10.0" @@ -33224,6 +33861,7 @@ "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, "license": "MIT", "dependencies": { "path-key": "^3.0.0" @@ -33236,6 +33874,7 @@ "version": "2.1.1", "resolved": "https://registry.npmjs.org/nth-check/-/nth-check-2.1.1.tgz", "integrity": "sha512-lqjrjmaOoAnWfMmBPL+XNnynZh2+swxiX3WUE0s4yEHI6m+AwrK2UZOimIRl3X/4QctVqS8AiZjFqyOGrMXb/w==", + "dev": true, "license": "BSD-2-Clause", "dependencies": { "boolbase": "^1.0.0" @@ -33254,6 +33893,7 @@ "version": "21.6.10", "resolved": "https://registry.npmjs.org/nx/-/nx-21.6.10.tgz", "integrity": "sha512-iKSyAg0VGG1MEOnlyyseMOt4n9J7I955VC+0UPQbNQTLdIUW8ibIHubpQyjd8Qvq4CfrLxzm+iq1AmbZ5vEG4A==", + "dev": true, "hasInstallScript": true, "license": "MIT", "dependencies": { @@ -33326,6 +33966,7 @@ "version": "2.0.0", "resolved": "https://registry.npmjs.org/define-lazy-prop/-/define-lazy-prop-2.0.0.tgz", "integrity": "sha512-Ds09qNh8yw3khSjiJjiUInaGX9xlqZDY7JVryGxdxV7NPeuqQfplOpQ66yJFZut3jLa5zOwkXw1g9EI2uKh4Og==", + "dev": true, "license": "MIT", "engines": { "node": ">=8" @@ -33335,6 +33976,7 @@ "version": "16.4.7", "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-16.4.7.tgz", "integrity": "sha512-47qPchRCykZC03FhkYAhrvwU4xDBFIj1QPqaarj6mdM/hgUzfPHcpkHJOn3mJAufFeeAxAzeGsr5X0M4k6fLZQ==", + "dev": true, "license": "BSD-2-Clause", "engines": { "node": ">=12" @@ -33347,6 +33989,7 @@ "version": "5.3.2", "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.3.2.tgz", "integrity": "sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g==", + "dev": true, "license": "MIT", "engines": { "node": ">= 4" @@ -33356,6 +33999,7 @@ "version": "2.2.1", "resolved": "https://registry.npmjs.org/is-docker/-/is-docker-2.2.1.tgz", "integrity": "sha512-F+i2BKsFrH66iaUFc0woD8sLy8getkwTwtOBjvs56Cx4CgJDeKQeqfz8wAYiSb8JOprWhHH5p77PbmYCvvUuXQ==", + "dev": true, "license": "MIT", "bin": { "is-docker": "cli.js" @@ -33371,6 +34015,7 @@ "version": "2.2.0", "resolved": "https://registry.npmjs.org/is-wsl/-/is-wsl-2.2.0.tgz", "integrity": "sha512-fKzAra0rGJUUBwGBgNkHZuToZcn+TtXHpeCgmkMJMMYx1sQDYaCSyjJBSCa2nH1DGm7s3n1oBnohoVTBaN7Lww==", + "dev": true, "license": "MIT", "dependencies": { "is-docker": "^2.0.0" @@ -33383,12 +34028,14 @@ "version": "3.2.0", "resolved": "https://registry.npmjs.org/jsonc-parser/-/jsonc-parser-3.2.0.tgz", "integrity": "sha512-gfFQZrcTc8CnKXp6Y4/CBT3fTc0OVuDofpre4aEeEpSBPV5X5v4+Vmx+8snU7RLPrNHPKSgLxGo9YuQzz20o+w==", + "dev": true, "license": "MIT" }, "node_modules/nx/node_modules/open": { "version": "8.4.2", "resolved": "https://registry.npmjs.org/open/-/open-8.4.2.tgz", "integrity": "sha512-7x81NCL719oNbsq/3mh+hVrAWmFuEYUqrq/Iw3kUzH8ReypT9QQ0BLoJS7/G9k6N81XjW4qHWtjWwe/9eLy1EQ==", + "dev": true, "license": "MIT", "dependencies": { "define-lazy-prop": "^2.0.0", @@ -33406,6 +34053,7 @@ "version": "5.3.0", "resolved": "https://registry.npmjs.org/ora/-/ora-5.3.0.tgz", "integrity": "sha512-zAKMgGXUim0Jyd6CXK9lraBnD3H5yPGBPPOkC23a2BG6hsm4Zu6OQSjQuEtV0BHDf4aKHcUFvJiGRrFuW3MG8g==", + "dev": true, "license": "MIT", "dependencies": { "bl": "^4.0.3", @@ -33428,6 +34076,7 @@ "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, "license": "MIT", "engines": { "node": ">=4" @@ -33437,6 +34086,7 @@ "version": "4.2.0", "resolved": "https://registry.npmjs.org/tsconfig-paths/-/tsconfig-paths-4.2.0.tgz", "integrity": "sha512-NoZ4roiN7LnbKn9QqE1amc9DJfzvZXxF4xDavcOWt1BPkdx+m+0gJuPM+S0vCe7zTJMYUP0R8pO2XMr+Y8oLIg==", + "dev": true, "license": "MIT", "dependencies": { "json5": "^2.2.2", @@ -33900,6 +34550,7 @@ "version": "1.1.2", "resolved": "https://registry.npmjs.org/obuf/-/obuf-1.1.2.tgz", "integrity": "sha512-PX1wu0AmAdPqOL1mWhqmlOd8kOIZQwGZw6rh7uby9fTc5lhaOWFLX3I6R1hrF9k3zUY40e6igsLGkDXK92LJNg==", + "dev": true, "license": "MIT" }, "node_modules/oidc-client-ts": { @@ -33931,6 +34582,7 @@ "version": "1.0.2", "resolved": "https://registry.npmjs.org/on-headers/-/on-headers-1.0.2.tgz", "integrity": "sha512-pZAE+FJLoyITytdqK0U5s+FIpjN0JP3OzFi/u8Rx+EV5/W+JTWGXG8xFzevE7AjBfDqHv/8vL8qQsIhHnqRkrA==", + "dev": true, "license": "MIT", "engines": { "node": ">= 0.8" @@ -33940,6 +34592,7 @@ "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, "license": "ISC", "dependencies": { "wrappy": "1" @@ -34019,6 +34672,7 @@ "version": "0.9.4", "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.4.tgz", "integrity": "sha512-6IpQ7mKUxRcZNLIObR0hz7lxsapSSIYNZJwXPGeF0mTVqGKFIXj1DQcMoT22S3ROcLyY/rz0PWaWZ9ayWmad9g==", + "dev": true, "license": "MIT", "dependencies": { "deep-is": "^0.1.3", @@ -34141,6 +34795,7 @@ "version": "3.1.0", "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz", "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==", + "dev": true, "license": "MIT", "dependencies": { "yocto-queue": "^0.1.0" @@ -34156,6 +34811,7 @@ "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, "license": "MIT", "dependencies": { "p-limit": "^3.0.2" @@ -34187,6 +34843,7 @@ "version": "6.2.1", "resolved": "https://registry.npmjs.org/p-retry/-/p-retry-6.2.1.tgz", "integrity": "sha512-hEt02O4hUct5wtwg4H4KcWgDdm+l1bOaEy/hWzd8xtXB9BqxTWBBhb+2ImAtH4Cv4rPjV76xN3Zumqk3k3AhhQ==", + "dev": true, "license": "MIT", "dependencies": { "@types/retry": "0.12.2", @@ -34204,12 +34861,14 @@ "version": "0.12.2", "resolved": "https://registry.npmjs.org/@types/retry/-/retry-0.12.2.tgz", "integrity": "sha512-XISRgDJ2Tc5q4TRqvgJtzsRkFYNJzZrhTdtMoGVBttwzzQJkPnS3WWTFc7kuDRoPtPakl+T+OfdEUjYJj7Jbow==", + "dev": true, "license": "MIT" }, "node_modules/p-retry/node_modules/retry": { "version": "0.13.1", "resolved": "https://registry.npmjs.org/retry/-/retry-0.13.1.tgz", "integrity": "sha512-XQBQ3I8W1Cge0Seh+6gjj03LbmRFWuoszgK9ooCpwYIrhhoO80pfq4cUkU5DkknwfOfFteRwlZ56PYOGYyFWdg==", + "dev": true, "license": "MIT", "engines": { "node": ">= 4" @@ -34219,6 +34878,7 @@ "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, "license": "MIT", "engines": { "node": ">=6" @@ -34244,6 +34904,7 @@ "version": "1.0.1", "resolved": "https://registry.npmjs.org/package-json-from-dist/-/package-json-from-dist-1.0.1.tgz", "integrity": "sha512-UEZIS3/by4OC8vL3P2dTXRETpebLI2NiI5vIrjaD/5UtrkFX/tNbwjTSRAGC/+7CAo2pIcBaRgWmcBBHcsaCIw==", + "dev": true, "license": "BlueOak-1.0.0" }, "node_modules/pacote": { @@ -34575,7 +35236,7 @@ "version": "3.0.4", "resolved": "https://registry.npmjs.org/param-case/-/param-case-3.0.4.tgz", "integrity": "sha512-RXlj7zCYokReqWpOPH9oYivUzLYZ5vAPIfEmCTNViosC78F8F0H9y7T7gG2M39ymgutxF5gcFEsyZQSph9Bp3A==", - "devOptional": true, + "dev": true, "license": "MIT", "dependencies": { "dot-case": "^3.0.4", @@ -34628,6 +35289,7 @@ "version": "1.0.1", "resolved": "https://registry.npmjs.org/parse-node-version/-/parse-node-version-1.0.1.tgz", "integrity": "sha512-3YHlOa/JgH6Mnpr05jP9eDG254US9ek25LyIxZlDItp2iJtwyaXQb57lBYLdT3MowkUFYEV2XXNAYIPlESvJlA==", + "dev": true, "license": "MIT", "engines": { "node": ">= 0.10" @@ -34787,7 +35449,7 @@ "version": "3.1.2", "resolved": "https://registry.npmjs.org/pascal-case/-/pascal-case-3.1.2.tgz", "integrity": "sha512-uWlGT3YSnK9x3BQJaOdcZwrnV6hPpd8jFH1/ucpiLRPh/2zCVJKS19E4GvYHvaCcACn3foXZ0cLB9Wrx1KGe5g==", - "devOptional": true, + "dev": true, "license": "MIT", "dependencies": { "no-case": "^3.0.4", @@ -34805,6 +35467,7 @@ "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, "license": "MIT", "engines": { "node": ">=8" @@ -34814,6 +35477,7 @@ "version": "1.0.1", "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", "integrity": "sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==", + "dev": true, "license": "MIT", "engines": { "node": ">=0.10.0" @@ -34823,6 +35487,7 @@ "version": "3.1.1", "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", + "dev": true, "license": "MIT", "engines": { "node": ">=8" @@ -34934,6 +35599,7 @@ "version": "4.0.2", "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.2.tgz", "integrity": "sha512-M7BAV6Rlcy5u+m6oPhAPFgJTzAioX/6B0DxyvDlo9l8+T3nLKbrczg2WLUyzd45L8RqfUMyGPzekbMvX2Ldkwg==", + "dev": true, "license": "MIT", "engines": { "node": ">=12" @@ -34968,6 +35634,7 @@ "version": "4.0.7", "resolved": "https://registry.npmjs.org/pirates/-/pirates-4.0.7.tgz", "integrity": "sha512-TfySrs/5nm8fQJDcBDuUng3VOUKsd7S+zqvbOTiGXHfxX4wK31ard+hoNuvkicM/2YFzlpDgABOevKSsB4G/FA==", + "dev": true, "license": "MIT", "engines": { "node": ">= 6" @@ -34990,6 +35657,7 @@ "version": "5.0.0", "resolved": "https://registry.npmjs.org/pkce-challenge/-/pkce-challenge-5.0.0.tgz", "integrity": "sha512-ueGLflrrnvwB3xuo/uGob5pd5FN7l0MsLf0Z87o/UQmRtwjvfylfc9MurIxRAWywCYTgrvpXBcqjV4OfCYGCIQ==", + "dev": true, "license": "MIT", "engines": { "node": ">=16.20.0" @@ -34999,6 +35667,7 @@ "version": "7.0.0", "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-7.0.0.tgz", "integrity": "sha512-Ie9z/WINcxxLp27BKOCHGde4ITq9UklYKDzVo1nhk5sqGEXU3FpkwP5GM2voTGJkGd9B3Otl+Q4uwSOeSUtOBA==", + "dev": true, "license": "MIT", "dependencies": { "find-up": "^6.3.0" @@ -35014,6 +35683,7 @@ "version": "6.3.0", "resolved": "https://registry.npmjs.org/find-up/-/find-up-6.3.0.tgz", "integrity": "sha512-v2ZsoEuVHYy8ZIlYqwPe/39Cy+cFDzp4dXPaxNvkEuouymu+2Jbz0PxpKarJHYJTmv2HWT3O382qY8l4jMWthw==", + "dev": true, "license": "MIT", "dependencies": { "locate-path": "^7.1.0", @@ -35030,6 +35700,7 @@ "version": "7.2.0", "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-7.2.0.tgz", "integrity": "sha512-gvVijfZvn7R+2qyPX8mAuKcFGDf6Nc61GdvGafQsHL0sBIxfKzA+usWn4GFC/bk+QdwPUD4kWFJLhElipq+0VA==", + "dev": true, "license": "MIT", "dependencies": { "p-locate": "^6.0.0" @@ -35045,6 +35716,7 @@ "version": "4.0.0", "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-4.0.0.tgz", "integrity": "sha512-5b0R4txpzjPWVw/cXXUResoD4hb6U/x9BH08L7nw+GN1sezDzPdxeRvpc9c433fZhBan/wusjbCsqwqm4EIBIQ==", + "dev": true, "license": "MIT", "dependencies": { "yocto-queue": "^1.0.0" @@ -35060,6 +35732,7 @@ "version": "6.0.0", "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-6.0.0.tgz", "integrity": "sha512-wPrq66Llhl7/4AGC6I+cqxT07LhXvWL08LNXz1fENOw0Ap4sRZZ/gZpTTJ5jpurzzzfS2W/Ge9BY3LgLjCShcw==", + "dev": true, "license": "MIT", "dependencies": { "p-limit": "^4.0.0" @@ -35075,6 +35748,7 @@ "version": "5.0.0", "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-5.0.0.tgz", "integrity": "sha512-RjhtfwJOxzcFmNOi6ltcbcu4Iu+FL3zEj83dk4kAS+fVpTxXLO1b38RvJgT/0QwvV/L3aY9TAnyv0EOqW4GoMQ==", + "dev": true, "license": "MIT", "engines": { "node": "^12.20.0 || ^14.13.1 || >=16.0.0" @@ -35084,6 +35758,7 @@ "version": "1.2.1", "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-1.2.1.tgz", "integrity": "sha512-AyeEbWOu/TAXdxlV9wmGcR0+yh2j3vYPGOECcIj2S7MkrLyC7ne+oye2BKTItt0ii2PHk4cDy+95+LshzbXnGg==", + "dev": true, "license": "MIT", "engines": { "node": ">=12.20" @@ -35258,6 +35933,7 @@ "version": "8.5.6", "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.6.tgz", "integrity": "sha512-3Ybi1tAuwAP9s0r1UQ2J4n5Y0G05bJkpUIO0/bI9MhwmD70S5aTWbXGBwxHrelT+XM1k6dM0pk+SwNkpTRN7Pg==", + "devOptional": true, "funding": [ { "type": "opencollective", @@ -35286,6 +35962,7 @@ "version": "9.0.1", "resolved": "https://registry.npmjs.org/postcss-calc/-/postcss-calc-9.0.1.tgz", "integrity": "sha512-TipgjGyzP5QzEhsOZUaIkeO5mKeMFpebWzRogWG/ysonUlnHcq5aJe0jOjpfzUU8PeSaBQnrE8ehR0QA5vs8PQ==", + "dev": true, "license": "MIT", "dependencies": { "postcss-selector-parser": "^6.0.11", @@ -35302,6 +35979,7 @@ "version": "6.1.2", "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-6.1.2.tgz", "integrity": "sha512-Q8qQfPiZ+THO/3ZrOrO0cJJKfpYCagtMUkXbnEfmgUjwXg6z/WBeOyS9APBBPCTSiDV+s4SwQGu8yFsiMRIudg==", + "dev": true, "license": "MIT", "dependencies": { "cssesc": "^3.0.0", @@ -35315,6 +35993,7 @@ "version": "6.1.0", "resolved": "https://registry.npmjs.org/postcss-colormin/-/postcss-colormin-6.1.0.tgz", "integrity": "sha512-x9yX7DOxeMAR+BgGVnNSAxmAj98NX/YxEMNFP+SDCEeNLb2r3i6Hh1ksMsnW8Ub5SLCpbescQqn9YEbE9554Sw==", + "dev": true, "license": "MIT", "dependencies": { "browserslist": "^4.23.0", @@ -35333,6 +36012,7 @@ "version": "6.1.0", "resolved": "https://registry.npmjs.org/postcss-convert-values/-/postcss-convert-values-6.1.0.tgz", "integrity": "sha512-zx8IwP/ts9WvUM6NkVSkiU902QZL1bwPhaVaLynPtCsOTqp+ZKbNi+s6XJg3rfqpKGA/oc7Oxk5t8pOQJcwl/w==", + "dev": true, "license": "MIT", "dependencies": { "browserslist": "^4.23.0", @@ -35349,6 +36029,7 @@ "version": "6.0.2", "resolved": "https://registry.npmjs.org/postcss-discard-comments/-/postcss-discard-comments-6.0.2.tgz", "integrity": "sha512-65w/uIqhSBBfQmYnG92FO1mWZjJ4GL5b8atm5Yw2UgrwD7HiNiSSNwJor1eCFGzUgYnN/iIknhNRVqjrrpuglw==", + "dev": true, "license": "MIT", "engines": { "node": "^14 || ^16 || >=18.0" @@ -35361,6 +36042,7 @@ "version": "6.0.3", "resolved": "https://registry.npmjs.org/postcss-discard-duplicates/-/postcss-discard-duplicates-6.0.3.tgz", "integrity": "sha512-+JA0DCvc5XvFAxwx6f/e68gQu/7Z9ud584VLmcgto28eB8FqSFZwtrLwB5Kcp70eIoWP/HXqz4wpo8rD8gpsTw==", + "dev": true, "license": "MIT", "engines": { "node": "^14 || ^16 || >=18.0" @@ -35373,6 +36055,7 @@ "version": "6.0.3", "resolved": "https://registry.npmjs.org/postcss-discard-empty/-/postcss-discard-empty-6.0.3.tgz", "integrity": "sha512-znyno9cHKQsK6PtxL5D19Fj9uwSzC2mB74cpT66fhgOadEUPyXFkbgwm5tvc3bt3NAy8ltE5MrghxovZRVnOjQ==", + "dev": true, "license": "MIT", "engines": { "node": "^14 || ^16 || >=18.0" @@ -35385,6 +36068,7 @@ "version": "6.0.2", "resolved": "https://registry.npmjs.org/postcss-discard-overridden/-/postcss-discard-overridden-6.0.2.tgz", "integrity": "sha512-j87xzI4LUggC5zND7KdjsI25APtyMuynXZSujByMaav2roV6OZX+8AaCUcZSWqckZpjAjRyFDdpqybgjFO0HJQ==", + "dev": true, "license": "MIT", "engines": { "node": "^14 || ^16 || >=18.0" @@ -35520,6 +36204,7 @@ "version": "6.0.5", "resolved": "https://registry.npmjs.org/postcss-merge-longhand/-/postcss-merge-longhand-6.0.5.tgz", "integrity": "sha512-5LOiordeTfi64QhICp07nzzuTDjNSO8g5Ksdibt44d+uvIIAE1oZdRn8y/W5ZtYgRH/lnLDlvi9F8btZcVzu3w==", + "dev": true, "license": "MIT", "dependencies": { "postcss-value-parser": "^4.2.0", @@ -35536,6 +36221,7 @@ "version": "6.1.1", "resolved": "https://registry.npmjs.org/postcss-merge-rules/-/postcss-merge-rules-6.1.1.tgz", "integrity": "sha512-KOdWF0gju31AQPZiD+2Ar9Qjowz1LTChSjFFbS+e2sFgc4uHOp3ZvVX4sNeTlk0w2O31ecFGgrFzhO0RSWbWwQ==", + "dev": true, "license": "MIT", "dependencies": { "browserslist": "^4.23.0", @@ -35554,6 +36240,7 @@ "version": "6.1.2", "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-6.1.2.tgz", "integrity": "sha512-Q8qQfPiZ+THO/3ZrOrO0cJJKfpYCagtMUkXbnEfmgUjwXg6z/WBeOyS9APBBPCTSiDV+s4SwQGu8yFsiMRIudg==", + "dev": true, "license": "MIT", "dependencies": { "cssesc": "^3.0.0", @@ -35567,6 +36254,7 @@ "version": "6.1.0", "resolved": "https://registry.npmjs.org/postcss-minify-font-values/-/postcss-minify-font-values-6.1.0.tgz", "integrity": "sha512-gklfI/n+9rTh8nYaSJXlCo3nOKqMNkxuGpTn/Qm0gstL3ywTr9/WRKznE+oy6fvfolH6dF+QM4nCo8yPLdvGJg==", + "dev": true, "license": "MIT", "dependencies": { "postcss-value-parser": "^4.2.0" @@ -35582,6 +36270,7 @@ "version": "6.0.3", "resolved": "https://registry.npmjs.org/postcss-minify-gradients/-/postcss-minify-gradients-6.0.3.tgz", "integrity": "sha512-4KXAHrYlzF0Rr7uc4VrfwDJ2ajrtNEpNEuLxFgwkhFZ56/7gaE4Nr49nLsQDZyUe+ds+kEhf+YAUolJiYXF8+Q==", + "dev": true, "license": "MIT", "dependencies": { "colord": "^2.9.3", @@ -35599,6 +36288,7 @@ "version": "6.1.0", "resolved": "https://registry.npmjs.org/postcss-minify-params/-/postcss-minify-params-6.1.0.tgz", "integrity": "sha512-bmSKnDtyyE8ujHQK0RQJDIKhQ20Jq1LYiez54WiaOoBtcSuflfK3Nm596LvbtlFcpipMjgClQGyGr7GAs+H1uA==", + "dev": true, "license": "MIT", "dependencies": { "browserslist": "^4.23.0", @@ -35616,6 +36306,7 @@ "version": "6.0.4", "resolved": "https://registry.npmjs.org/postcss-minify-selectors/-/postcss-minify-selectors-6.0.4.tgz", "integrity": "sha512-L8dZSwNLgK7pjTto9PzWRoMbnLq5vsZSTu8+j1P/2GB8qdtGQfn+K1uSvFgYvgh83cbyxT5m43ZZhUMTJDSClQ==", + "dev": true, "license": "MIT", "dependencies": { "postcss-selector-parser": "^6.0.16" @@ -35631,6 +36322,7 @@ "version": "6.1.2", "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-6.1.2.tgz", "integrity": "sha512-Q8qQfPiZ+THO/3ZrOrO0cJJKfpYCagtMUkXbnEfmgUjwXg6z/WBeOyS9APBBPCTSiDV+s4SwQGu8yFsiMRIudg==", + "dev": true, "license": "MIT", "dependencies": { "cssesc": "^3.0.0", @@ -35644,6 +36336,7 @@ "version": "3.1.0", "resolved": "https://registry.npmjs.org/postcss-modules-extract-imports/-/postcss-modules-extract-imports-3.1.0.tgz", "integrity": "sha512-k3kNe0aNFQDAZGbin48pL2VNidTF0w4/eASDsxlyspobzU3wZQLOGj7L9gfRe0Jo9/4uud09DsjFNH7winGv8Q==", + "dev": true, "license": "ISC", "engines": { "node": "^10 || ^12 || >= 14" @@ -35656,6 +36349,7 @@ "version": "4.2.0", "resolved": "https://registry.npmjs.org/postcss-modules-local-by-default/-/postcss-modules-local-by-default-4.2.0.tgz", "integrity": "sha512-5kcJm/zk+GJDSfw+V/42fJ5fhjL5YbFDl8nVdXkJPLLW+Vf9mTD5Xe0wqIaDnLuL2U6cDNpTr+UQ+v2HWIBhzw==", + "dev": true, "license": "MIT", "dependencies": { "icss-utils": "^5.0.0", @@ -35673,6 +36367,7 @@ "version": "3.2.1", "resolved": "https://registry.npmjs.org/postcss-modules-scope/-/postcss-modules-scope-3.2.1.tgz", "integrity": "sha512-m9jZstCVaqGjTAuny8MdgE88scJnCiQSlSrOWcTQgM2t32UBe+MUmFSO5t7VMSfAf/FJKImAxBav8ooCHJXCJA==", + "dev": true, "license": "ISC", "dependencies": { "postcss-selector-parser": "^7.0.0" @@ -35688,6 +36383,7 @@ "version": "4.0.0", "resolved": "https://registry.npmjs.org/postcss-modules-values/-/postcss-modules-values-4.0.0.tgz", "integrity": "sha512-RDxHkAiEGI78gS2ofyvCsu7iycRv7oqw5xMWn9iMoR0N/7mf9D50ecQqUo5BZ9Zh2vH4bCUR/ktCqbB9m8vJjQ==", + "dev": true, "license": "ISC", "dependencies": { "icss-utils": "^5.0.0" @@ -35743,6 +36439,7 @@ "version": "6.0.2", "resolved": "https://registry.npmjs.org/postcss-normalize-charset/-/postcss-normalize-charset-6.0.2.tgz", "integrity": "sha512-a8N9czmdnrjPHa3DeFlwqst5eaL5W8jYu3EBbTTkI5FHkfMhFZh1EGbku6jhHhIzTA6tquI2P42NtZ59M/H/kQ==", + "dev": true, "license": "MIT", "engines": { "node": "^14 || ^16 || >=18.0" @@ -35755,6 +36452,7 @@ "version": "6.0.2", "resolved": "https://registry.npmjs.org/postcss-normalize-display-values/-/postcss-normalize-display-values-6.0.2.tgz", "integrity": "sha512-8H04Mxsb82ON/aAkPeq8kcBbAtI5Q2a64X/mnRRfPXBq7XeogoQvReqxEfc0B4WPq1KimjezNC8flUtC3Qz6jg==", + "dev": true, "license": "MIT", "dependencies": { "postcss-value-parser": "^4.2.0" @@ -35770,6 +36468,7 @@ "version": "6.0.2", "resolved": "https://registry.npmjs.org/postcss-normalize-positions/-/postcss-normalize-positions-6.0.2.tgz", "integrity": "sha512-/JFzI441OAB9O7VnLA+RtSNZvQ0NCFZDOtp6QPFo1iIyawyXg0YI3CYM9HBy1WvwCRHnPep/BvI1+dGPKoXx/Q==", + "dev": true, "license": "MIT", "dependencies": { "postcss-value-parser": "^4.2.0" @@ -35785,6 +36484,7 @@ "version": "6.0.2", "resolved": "https://registry.npmjs.org/postcss-normalize-repeat-style/-/postcss-normalize-repeat-style-6.0.2.tgz", "integrity": "sha512-YdCgsfHkJ2jEXwR4RR3Tm/iOxSfdRt7jplS6XRh9Js9PyCR/aka/FCb6TuHT2U8gQubbm/mPmF6L7FY9d79VwQ==", + "dev": true, "license": "MIT", "dependencies": { "postcss-value-parser": "^4.2.0" @@ -35800,6 +36500,7 @@ "version": "6.0.2", "resolved": "https://registry.npmjs.org/postcss-normalize-string/-/postcss-normalize-string-6.0.2.tgz", "integrity": "sha512-vQZIivlxlfqqMp4L9PZsFE4YUkWniziKjQWUtsxUiVsSSPelQydwS8Wwcuw0+83ZjPWNTl02oxlIvXsmmG+CiQ==", + "dev": true, "license": "MIT", "dependencies": { "postcss-value-parser": "^4.2.0" @@ -35815,6 +36516,7 @@ "version": "6.0.2", "resolved": "https://registry.npmjs.org/postcss-normalize-timing-functions/-/postcss-normalize-timing-functions-6.0.2.tgz", "integrity": "sha512-a+YrtMox4TBtId/AEwbA03VcJgtyW4dGBizPl7e88cTFULYsprgHWTbfyjSLyHeBcK/Q9JhXkt2ZXiwaVHoMzA==", + "dev": true, "license": "MIT", "dependencies": { "postcss-value-parser": "^4.2.0" @@ -35830,6 +36532,7 @@ "version": "6.1.0", "resolved": "https://registry.npmjs.org/postcss-normalize-unicode/-/postcss-normalize-unicode-6.1.0.tgz", "integrity": "sha512-QVC5TQHsVj33otj8/JD869Ndr5Xcc/+fwRh4HAsFsAeygQQXm+0PySrKbr/8tkDKzW+EVT3QkqZMfFrGiossDg==", + "dev": true, "license": "MIT", "dependencies": { "browserslist": "^4.23.0", @@ -35846,6 +36549,7 @@ "version": "6.0.2", "resolved": "https://registry.npmjs.org/postcss-normalize-url/-/postcss-normalize-url-6.0.2.tgz", "integrity": "sha512-kVNcWhCeKAzZ8B4pv/DnrU1wNh458zBNp8dh4y5hhxih5RZQ12QWMuQrDgPRw3LRl8mN9vOVfHl7uhvHYMoXsQ==", + "dev": true, "license": "MIT", "dependencies": { "postcss-value-parser": "^4.2.0" @@ -35861,6 +36565,7 @@ "version": "6.0.2", "resolved": "https://registry.npmjs.org/postcss-normalize-whitespace/-/postcss-normalize-whitespace-6.0.2.tgz", "integrity": "sha512-sXZ2Nj1icbJOKmdjXVT9pnyHQKiSAyuNQHSgRCUgThn2388Y9cGVDR+E9J9iAYbSbLHI+UUwLVl1Wzco/zgv0Q==", + "dev": true, "license": "MIT", "dependencies": { "postcss-value-parser": "^4.2.0" @@ -35876,6 +36581,7 @@ "version": "6.0.2", "resolved": "https://registry.npmjs.org/postcss-ordered-values/-/postcss-ordered-values-6.0.2.tgz", "integrity": "sha512-VRZSOB+JU32RsEAQrO94QPkClGPKJEL/Z9PCBImXMhIeK5KAYo6slP/hBYlLgrCjFxyqvn5VC81tycFEDBLG1Q==", + "dev": true, "license": "MIT", "dependencies": { "cssnano-utils": "^4.0.2", @@ -35892,6 +36598,7 @@ "version": "6.1.0", "resolved": "https://registry.npmjs.org/postcss-reduce-initial/-/postcss-reduce-initial-6.1.0.tgz", "integrity": "sha512-RarLgBK/CrL1qZags04oKbVbrrVK2wcxhvta3GCxrZO4zveibqbRPmm2VI8sSgCXwoUHEliRSbOfpR0b/VIoiw==", + "dev": true, "license": "MIT", "dependencies": { "browserslist": "^4.23.0", @@ -35908,6 +36615,7 @@ "version": "6.0.2", "resolved": "https://registry.npmjs.org/postcss-reduce-transforms/-/postcss-reduce-transforms-6.0.2.tgz", "integrity": "sha512-sB+Ya++3Xj1WaT9+5LOOdirAxP7dJZms3GRcYheSPi1PiTMigsxHAdkrbItHxwYHr4kt1zL7mmcHstgMYT+aiA==", + "dev": true, "license": "MIT", "dependencies": { "postcss-value-parser": "^4.2.0" @@ -35923,6 +36631,7 @@ "version": "7.1.0", "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-7.1.0.tgz", "integrity": "sha512-8sLjZwK0R+JlxlYcTuVnyT2v+htpdrjDOKuMcOVdYjt52Lh8hWRYpxBPoKx/Zg+bcjc3wx6fmQevMmUztS/ccA==", + "dev": true, "license": "MIT", "dependencies": { "cssesc": "^3.0.0", @@ -35936,6 +36645,7 @@ "version": "6.0.3", "resolved": "https://registry.npmjs.org/postcss-svgo/-/postcss-svgo-6.0.3.tgz", "integrity": "sha512-dlrahRmxP22bX6iKEjOM+c8/1p+81asjKT+V5lrgOH944ryx/OHpclnIbGsKVd3uWOXFLYJwCVf0eEkJGvO96g==", + "dev": true, "license": "MIT", "dependencies": { "postcss-value-parser": "^4.2.0", @@ -35952,6 +36662,7 @@ "version": "6.0.4", "resolved": "https://registry.npmjs.org/postcss-unique-selectors/-/postcss-unique-selectors-6.0.4.tgz", "integrity": "sha512-K38OCaIrO8+PzpArzkLKB42dSARtC2tmG6PvD4b1o1Q2E9Os8jzfWFfSy/rixsHwohtsDdFtAWGjFVFUdwYaMg==", + "dev": true, "license": "MIT", "dependencies": { "postcss-selector-parser": "^6.0.16" @@ -35967,6 +36678,7 @@ "version": "6.1.2", "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-6.1.2.tgz", "integrity": "sha512-Q8qQfPiZ+THO/3ZrOrO0cJJKfpYCagtMUkXbnEfmgUjwXg6z/WBeOyS9APBBPCTSiDV+s4SwQGu8yFsiMRIudg==", + "dev": true, "license": "MIT", "dependencies": { "cssesc": "^3.0.0", @@ -35980,6 +36692,7 @@ "version": "4.2.0", "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-4.2.0.tgz", "integrity": "sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ==", + "dev": true, "license": "MIT" }, "node_modules/postject": { @@ -36055,6 +36768,7 @@ "version": "1.2.1", "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz", "integrity": "sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==", + "dev": true, "license": "MIT", "engines": { "node": ">= 0.8.0" @@ -36159,7 +36873,7 @@ "version": "4.0.0", "resolved": "https://registry.npmjs.org/pretty-error/-/pretty-error-4.0.0.tgz", "integrity": "sha512-AoJ5YMAcXKYxKhuJGdcvse+Voc6v1RgnsR3nWcYU7q4t6z0Q6T86sv5Zq8VIRbOWWFpvdGE83LtdSMNd+6Y0xw==", - "devOptional": true, + "dev": true, "license": "MIT", "dependencies": { "lodash": "^4.17.20", @@ -36317,6 +37031,7 @@ "version": "2.0.7", "resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.7.tgz", "integrity": "sha512-llQsMLSUDUPT44jdrU/O37qlnifitDP+ZwrmmZcoSKyLKvtZxpyV0n2/bD/N4tBAAZ/gJEdZU7KMraoK1+XYAg==", + "dev": true, "license": "MIT", "dependencies": { "forwarded": "0.2.0", @@ -36330,6 +37045,7 @@ "version": "1.1.0", "resolved": "https://registry.npmjs.org/proxy-from-env/-/proxy-from-env-1.1.0.tgz", "integrity": "sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==", + "dev": true, "license": "MIT" }, "node_modules/proxy-middleware": { @@ -36346,6 +37062,7 @@ "version": "1.0.1", "resolved": "https://registry.npmjs.org/prr/-/prr-1.0.1.tgz", "integrity": "sha512-yPw4Sng1gWghHQWj0B3ZggWUm4qVbPwPFcRG8KyxiU7J2OHFSoEHKS+EZ3fv5l1t9CyCiop6l/ZYeWbrgoQejw==", + "dev": true, "license": "MIT", "optional": true }, @@ -36438,6 +37155,7 @@ "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", @@ -36471,6 +37189,7 @@ "version": "2.1.0", "resolved": "https://registry.npmjs.org/randombytes/-/randombytes-2.1.0.tgz", "integrity": "sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ==", + "dev": true, "license": "MIT", "dependencies": { "safe-buffer": "^5.1.0" @@ -36480,6 +37199,7 @@ "version": "1.2.1", "resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.1.tgz", "integrity": "sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==", + "dev": true, "license": "MIT", "engines": { "node": ">= 0.6" @@ -36489,6 +37209,7 @@ "version": "3.0.0", "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-3.0.0.tgz", "integrity": "sha512-RmkhL8CAyCRPXCE28MMH0z2PNWQBNk2Q09ZdxM9IOOXwxwZbN+qbWaatPkdkWIKL2ZVDImrN/pK5HTRz2PcS4g==", + "dev": true, "license": "MIT", "dependencies": { "bytes": "3.1.2", @@ -36585,6 +37306,7 @@ "version": "1.0.0", "resolved": "https://registry.npmjs.org/read-cache/-/read-cache-1.0.0.tgz", "integrity": "sha512-Owdv/Ft7IjOgm/i0xvNDZ1LrRANRfew4b2prF3OWMQLxLfu3bS8FVhCsrSCMK4lR56Y9ya+AThoTpDCTxCmpRA==", + "dev": true, "license": "MIT", "dependencies": { "pify": "^2.3.0" @@ -36594,6 +37316,7 @@ "version": "2.3.0", "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz", "integrity": "sha512-udgsAY+fTnvv7kI7aaxbqwWNb0AHiB0qBO89PZKPkoTmGOgdbrHDKD+0B2X4uTfJ/FT1R09r9gTsjUjNJotuog==", + "dev": true, "license": "MIT", "engines": { "node": ">=0.10.0" @@ -36630,6 +37353,7 @@ "version": "4.1.2", "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-4.1.2.tgz", "integrity": "sha512-GDhwkLfywWL2s6vEjyhri+eXmfH6j1L7JE27WhqLeYzoh/A3DBaYGEj2H/HFZCn/kMfim73FXxEJTw06WtxQwg==", + "dev": true, "license": "MIT", "engines": { "node": ">= 14.18.0" @@ -36727,12 +37451,14 @@ "version": "1.4.2", "resolved": "https://registry.npmjs.org/regenerate/-/regenerate-1.4.2.tgz", "integrity": "sha512-zrceR/XhGYU/d/opr2EKO7aRHUeiBI8qjtfHqADTwZd6Szfy16la6kqD0MIUs5z5hx6AaKa+PixpPrR289+I0A==", + "dev": true, "license": "MIT" }, "node_modules/regenerate-unicode-properties": { "version": "10.2.0", "resolved": "https://registry.npmjs.org/regenerate-unicode-properties/-/regenerate-unicode-properties-10.2.0.tgz", "integrity": "sha512-DqHn3DwbmmPVzeKj9woBadqmXxLvQoQIwu7nopMc72ztvxVmVk2SBhSnx67zuye5TP+lJsb/TBQsjLKhnDf3MA==", + "dev": true, "license": "MIT", "dependencies": { "regenerate": "^1.4.2" @@ -36773,6 +37499,7 @@ "version": "6.2.0", "resolved": "https://registry.npmjs.org/regexpu-core/-/regexpu-core-6.2.0.tgz", "integrity": "sha512-H66BPQMrv+V16t8xtmq+UC0CBpiTBA60V8ibS1QVReIp8T1z8hwFxqcGzm9K6lgsN7sB5edVH8a+ze6Fqm4weA==", + "dev": true, "license": "MIT", "dependencies": { "regenerate": "^1.4.2", @@ -36790,12 +37517,14 @@ "version": "0.8.0", "resolved": "https://registry.npmjs.org/regjsgen/-/regjsgen-0.8.0.tgz", "integrity": "sha512-RvwtGe3d7LvWiDQXeQw8p5asZUmfU1G/l6WbUXeHta7Y2PEIvBTwH6E2EfmYUK8pxcxEdEmaomqyp0vZZ7C+3Q==", + "dev": true, "license": "MIT" }, "node_modules/regjsparser": { "version": "0.12.0", "resolved": "https://registry.npmjs.org/regjsparser/-/regjsparser-0.12.0.tgz", "integrity": "sha512-cnE+y8bz4NhMjISKbgeVJtqNbtf5QpjZP+Bslo+UqkIt9QPnX9q095eiRRASJG1/tz6dlNr6Z5NsBiWYokp6EQ==", + "dev": true, "license": "BSD-2-Clause", "dependencies": { "jsesc": "~3.0.2" @@ -36808,6 +37537,7 @@ "version": "3.0.2", "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-3.0.2.tgz", "integrity": "sha512-xKqzzWXDttJuOcawBt4KnKHHIf5oQ/Cxax+0PWFG+DFDgHNAdi+TXECADI+RYiFUMmx8792xsMbbgXj4CwnP4g==", + "dev": true, "license": "MIT", "bin": { "jsesc": "bin/jsesc" @@ -36820,7 +37550,7 @@ "version": "0.2.7", "resolved": "https://registry.npmjs.org/relateurl/-/relateurl-0.2.7.tgz", "integrity": "sha512-G08Dxvm4iDN3MLM0EsP62EDV9IuhXPR6blNz6Utcp7zyV3tr4HVNINt6MpaRWbxoOHT3Q7YN2P+jaHX8vUbgog==", - "devOptional": true, + "dev": true, "license": "MIT", "engines": { "node": ">= 0.10" @@ -36895,7 +37625,7 @@ "version": "3.0.0", "resolved": "https://registry.npmjs.org/renderkid/-/renderkid-3.0.0.tgz", "integrity": "sha512-q/7VIQA8lmM1hF+jn+sFSPWGlMkSAeNYcPLmDQx2zzuiDfaLrOmumR8iaUKlenFgh0XRPIUeSPlH3A+AW3Z5pg==", - "devOptional": true, + "dev": true, "license": "MIT", "dependencies": { "css-select": "^4.1.3", @@ -36909,7 +37639,7 @@ "version": "4.3.0", "resolved": "https://registry.npmjs.org/css-select/-/css-select-4.3.0.tgz", "integrity": "sha512-wPpOYtnsVontu2mODhA19JrqWxNsfdatRKd64kmpRbQgh1KtItko5sTnEpPdpSaJszTOhEMlF/RPz28qj4HqhQ==", - "devOptional": true, + "dev": true, "license": "BSD-2-Clause", "dependencies": { "boolbase": "^1.0.0", @@ -36926,7 +37656,7 @@ "version": "1.4.1", "resolved": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-1.4.1.tgz", "integrity": "sha512-VHwB3KfrcOOkelEG2ZOfxqLZdfkil8PtJi4P8N2MMXucZq2yLp75ClViUlOVwyoHEDjYU433Aq+5zWP61+RGag==", - "devOptional": true, + "dev": true, "license": "MIT", "dependencies": { "domelementtype": "^2.0.1", @@ -36941,7 +37671,7 @@ "version": "4.3.1", "resolved": "https://registry.npmjs.org/domhandler/-/domhandler-4.3.1.tgz", "integrity": "sha512-GrwoxYN+uWlzO8uhUXRl0P+kHE4GtVPfYzVLcUxPL7KNdHKj66vvlhiweIHqYYXWlw+T8iLMp42Lm67ghw4WMQ==", - "devOptional": true, + "dev": true, "license": "BSD-2-Clause", "dependencies": { "domelementtype": "^2.2.0" @@ -36957,7 +37687,7 @@ "version": "2.8.0", "resolved": "https://registry.npmjs.org/domutils/-/domutils-2.8.0.tgz", "integrity": "sha512-w96Cjofp72M5IIhpjgobBimYEfoPjx1Vx0BSX9P30WBdZW2WIKU0T1Bd0kz2eNZ9ikjKgHbEyKx8BB6H1L3h3A==", - "devOptional": true, + "dev": true, "license": "BSD-2-Clause", "dependencies": { "dom-serializer": "^1.0.1", @@ -36972,7 +37702,7 @@ "version": "2.2.0", "resolved": "https://registry.npmjs.org/entities/-/entities-2.2.0.tgz", "integrity": "sha512-p92if5Nz619I0w+akJrLZH0MX0Pb5DX39XOwQTtXSdQQOaYH03S1uIQp4mhOZtAXrxq4ViO67YTiLBo2638o9A==", - "devOptional": true, + "dev": true, "license": "BSD-2-Clause", "funding": { "url": "https://github.com/fb55/entities?sponsor=1" @@ -36982,7 +37712,7 @@ "version": "6.1.0", "resolved": "https://registry.npmjs.org/htmlparser2/-/htmlparser2-6.1.0.tgz", "integrity": "sha512-gyyPk6rgonLFEDGoeRgQNaEUvdJ4ktTmmUh/h2t7s+M8oPpIPxgNACWa+6ESR57kXstwqPiCut0V8NRpcwgU7A==", - "devOptional": true, + "dev": true, "funding": [ "https://github.com/fb55/htmlparser2?sponsor=1", { @@ -37002,6 +37732,7 @@ "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, "license": "MIT", "engines": { "node": ">=0.10.0" @@ -37011,6 +37742,7 @@ "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, "license": "MIT", "engines": { "node": ">=0.10.0" @@ -37115,6 +37847,7 @@ "version": "5.0.0", "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-5.0.0.tgz", "integrity": "sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==", + "dev": true, "license": "MIT", "engines": { "node": ">=8" @@ -37176,6 +37909,7 @@ "version": "2.0.3", "resolved": "https://registry.npmjs.org/resolve.exports/-/resolve.exports-2.0.3.tgz", "integrity": "sha512-OcXjMsGdhL4XnbShKpAcSqPMzQoYkYyhbEaeSko47MjRP9NfEQMhZkXL1DoFlt9LWQn4YttrdnV6X2OiyzBi+A==", + "dev": true, "license": "MIT", "engines": { "node": ">=10" @@ -37241,6 +37975,7 @@ "version": "1.1.0", "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.1.0.tgz", "integrity": "sha512-g6QUff04oZpHs0eG5p83rFLhHeV00ug/Yf9nZM6fLeUrPguBTkTQOdpAWWspMh55TZfVQDPaN3NQJfbVRAxdIw==", + "dev": true, "license": "MIT", "engines": { "iojs": ">=1.0.0", @@ -37373,6 +38108,7 @@ "version": "2.2.0", "resolved": "https://registry.npmjs.org/router/-/router-2.2.0.tgz", "integrity": "sha512-nLTrUKm2UyiL7rlhapu/Zl45FwNgkZGaCpZbIHajDYgwlJCOzLSk+cIPAnsEqV955GjILJnKbdQC1nVPz+gAYQ==", + "dev": true, "license": "MIT", "dependencies": { "debug": "^4.4.0", @@ -37389,6 +38125,7 @@ "version": "4.0.0", "resolved": "https://registry.npmjs.org/is-promise/-/is-promise-4.0.0.tgz", "integrity": "sha512-hvpoI6korhJMnej285dSg6nu1+e6uxs7zG3BYAm5byqDsgJNWwxzM6z6iZiAgQR4TJ30JmBTOwqZUw3WlyH3AQ==", + "dev": true, "license": "MIT" }, "node_modules/rrweb-cssom": { @@ -37422,6 +38159,7 @@ "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", @@ -37610,6 +38348,7 @@ "version": "1.95.1", "resolved": "https://registry.npmjs.org/sass/-/sass-1.95.1.tgz", "integrity": "sha512-uPoDh5NIEZV4Dp5GBodkmNY9tSQfXY02pmCcUo+FR1P+x953HGkpw+vV28D4IqYB6f8webZtwoSaZaiPtpTeMg==", + "dev": true, "license": "MIT", "dependencies": { "chokidar": "^4.0.0", @@ -37630,6 +38369,7 @@ "version": "1.93.2", "resolved": "https://registry.npmjs.org/sass-embedded/-/sass-embedded-1.93.2.tgz", "integrity": "sha512-FvQdkn2dZ8DGiLgi0Uf4zsj7r/BsiLImNa5QJ10eZalY6NfZyjrmWGFcuCN5jNwlDlXFJnftauv+UtvBKLvepQ==", + "dev": true, "license": "MIT", "dependencies": { "@bufbuild/protobuf": "^2.5.0", @@ -37678,6 +38418,7 @@ "!riscv64", "!x64" ], + "dev": true, "license": "MIT", "optional": true, "dependencies": { @@ -37688,6 +38429,7 @@ "version": "1.93.2", "resolved": "https://registry.npmjs.org/sass/-/sass-1.93.2.tgz", "integrity": "sha512-t+YPtOQHpGW1QWsh1CHQ5cPIr9lbbGZLZnbihP/D/qZj/yuV68m8qarcV17nvkOX81BCrvzAlq2klCQFZghyTg==", + "dev": true, "license": "MIT", "optional": true, "dependencies": { @@ -37712,6 +38454,7 @@ "cpu": [ "arm" ], + "dev": true, "license": "MIT", "optional": true, "os": [ @@ -37728,6 +38471,7 @@ "cpu": [ "arm64" ], + "dev": true, "license": "MIT", "optional": true, "os": [ @@ -37744,6 +38488,7 @@ "cpu": [ "riscv64" ], + "dev": true, "license": "MIT", "optional": true, "os": [ @@ -37760,6 +38505,7 @@ "cpu": [ "x64" ], + "dev": true, "license": "MIT", "optional": true, "os": [ @@ -37776,6 +38522,7 @@ "cpu": [ "arm64" ], + "dev": true, "license": "MIT", "optional": true, "os": [ @@ -37792,6 +38539,7 @@ "cpu": [ "x64" ], + "dev": true, "license": "MIT", "optional": true, "os": [ @@ -37808,6 +38556,7 @@ "cpu": [ "arm" ], + "dev": true, "license": "MIT", "optional": true, "os": [ @@ -37824,6 +38573,7 @@ "cpu": [ "arm64" ], + "dev": true, "license": "MIT", "optional": true, "os": [ @@ -37840,6 +38590,7 @@ "cpu": [ "arm" ], + "dev": true, "license": "MIT", "optional": true, "os": [ @@ -37856,6 +38607,7 @@ "cpu": [ "arm64" ], + "dev": true, "license": "MIT", "optional": true, "os": [ @@ -37872,6 +38624,7 @@ "cpu": [ "riscv64" ], + "dev": true, "license": "MIT", "optional": true, "os": [ @@ -37888,6 +38641,7 @@ "cpu": [ "x64" ], + "dev": true, "license": "MIT", "optional": true, "os": [ @@ -37904,6 +38658,7 @@ "cpu": [ "riscv64" ], + "dev": true, "license": "MIT", "optional": true, "os": [ @@ -37920,6 +38675,7 @@ "cpu": [ "x64" ], + "dev": true, "license": "MIT", "optional": true, "os": [ @@ -37933,6 +38689,7 @@ "version": "1.93.2", "resolved": "https://registry.npmjs.org/sass-embedded-unknown-all/-/sass-embedded-unknown-all-1.93.2.tgz", "integrity": "sha512-7VnaOmyewcXohiuoFagJ3SK5ddP9yXpU0rzz+pZQmS1/+5O6vzyFCUoEt3HDRaLctH4GT3nUGoK1jg0ae62IfQ==", + "dev": true, "license": "MIT", "optional": true, "os": [ @@ -37949,6 +38706,7 @@ "version": "1.93.2", "resolved": "https://registry.npmjs.org/sass/-/sass-1.93.2.tgz", "integrity": "sha512-t+YPtOQHpGW1QWsh1CHQ5cPIr9lbbGZLZnbihP/D/qZj/yuV68m8qarcV17nvkOX81BCrvzAlq2klCQFZghyTg==", + "dev": true, "license": "MIT", "optional": true, "dependencies": { @@ -37973,6 +38731,7 @@ "cpu": [ "arm64" ], + "dev": true, "license": "MIT", "optional": true, "os": [ @@ -37989,6 +38748,7 @@ "cpu": [ "x64" ], + "dev": true, "license": "MIT", "optional": true, "os": [ @@ -38002,6 +38762,7 @@ "version": "8.1.1", "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz", "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==", + "dev": true, "license": "MIT", "dependencies": { "has-flag": "^4.0.0" @@ -38017,6 +38778,7 @@ "version": "16.0.6", "resolved": "https://registry.npmjs.org/sass-loader/-/sass-loader-16.0.6.tgz", "integrity": "sha512-sglGzId5gmlfxNs4gK2U3h7HlVRfx278YK6Ono5lwzuvi1jxig80YiuHkaDBVsYIKFhx8wN7XSCI0M2IDS/3qA==", + "dev": true, "license": "MIT", "dependencies": { "neo-async": "^2.6.2" @@ -38057,7 +38819,7 @@ "version": "1.4.1", "resolved": "https://registry.npmjs.org/sax/-/sax-1.4.1.tgz", "integrity": "sha512-+aWOz7yVScEGoKNd4PA10LZ8sk0A/z5+nXQG5giUO5rprX9jgYsTdov9qCchZiPIZezbZH+jRut8nPodFAX4Jg==", - "devOptional": true, + "dev": true, "license": "ISC" }, "node_modules/saxes": { @@ -38086,6 +38848,7 @@ "version": "4.3.3", "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-4.3.3.tgz", "integrity": "sha512-eflK8wEtyOE6+hsaRVPxvUKYCpRgzLqDTb8krvAsRIwOGlHoSgYLgBXoubGgLd2fT41/OUYdb48v4k4WWHQurA==", + "dev": true, "license": "MIT", "dependencies": { "@types/json-schema": "^7.0.9", @@ -38105,6 +38868,7 @@ "version": "2.1.1", "resolved": "https://registry.npmjs.org/ajv-formats/-/ajv-formats-2.1.1.tgz", "integrity": "sha512-Wx0Kx52hxE7C18hkMEggYlEifqWZtYaRgouJor+WMdPnQyEK13vgEWyVNup7SoeeoLMsr4kf5h6dOW11I15MUA==", + "dev": true, "license": "MIT", "dependencies": { "ajv": "^8.0.0" @@ -38122,12 +38886,14 @@ "version": "2.0.0", "resolved": "https://registry.npmjs.org/select-hose/-/select-hose-2.0.0.tgz", "integrity": "sha512-mEugaLK+YfkijB4fx0e6kImuJdCIt2LxCRcbEYPqRGCs4F2ogyfZU5IAZRdjCP8JPq2AtdNoC/Dux63d9Kiryg==", + "dev": true, "license": "MIT" }, "node_modules/selfsigned": { "version": "2.4.1", "resolved": "https://registry.npmjs.org/selfsigned/-/selfsigned-2.4.1.tgz", "integrity": "sha512-th5B4L2U+eGLq1TVh7zNRGBapioSORUeymIydxgFpwww9d2qyKvtuPU2jJuHvYAwwqi2Y596QBL3eEqcPEYL8Q==", + "dev": true, "license": "MIT", "dependencies": { "@types/node-forge": "^1.3.0", @@ -38161,6 +38927,7 @@ "version": "1.2.0", "resolved": "https://registry.npmjs.org/send/-/send-1.2.0.tgz", "integrity": "sha512-uaW0WwXKpL9blXE2o0bRhoL2EGXIrZxQ2ZQ4mgcfoBxdFmQold+qWsD2jLrfZ0trjKL6vOw0j//eAwcALFjKSw==", + "dev": true, "license": "MIT", "dependencies": { "debug": "^4.3.5", @@ -38214,6 +38981,7 @@ "version": "6.0.2", "resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-6.0.2.tgz", "integrity": "sha512-Saa1xPByTTq2gdeFZYLLo+RFE35NHZkAbqZeWNd3BpzppeVisAqpDjcp8dyf6uIvEqJRd46jemmyA4iFIeVk8g==", + "dev": true, "license": "BSD-3-Clause", "dependencies": { "randombytes": "^2.1.0" @@ -38223,6 +38991,7 @@ "version": "1.9.1", "resolved": "https://registry.npmjs.org/serve-index/-/serve-index-1.9.1.tgz", "integrity": "sha512-pXHfKNP4qujrtteMrSBb0rc8HJ9Ms/GrXwcUtUtD5s4ewDJI8bT3Cz2zTVRMKtri49pLx2e0Ya8ziP5Ya2pZZw==", + "dev": true, "license": "MIT", "dependencies": { "accepts": "~1.3.4", @@ -38241,6 +39010,7 @@ "version": "1.3.8", "resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.8.tgz", "integrity": "sha512-PYAthTa2m2VKxuvSD3DPC/Gy+U+sOA1LAuT8mkmRuvw+NACSaeXEQ+NHcVF7rONl6qcaxV3Uuemwawk+7+SJLw==", + "dev": true, "license": "MIT", "dependencies": { "mime-types": "~2.1.34", @@ -38254,6 +39024,7 @@ "version": "2.6.9", "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dev": true, "license": "MIT", "dependencies": { "ms": "2.0.0" @@ -38263,6 +39034,7 @@ "version": "1.1.2", "resolved": "https://registry.npmjs.org/depd/-/depd-1.1.2.tgz", "integrity": "sha512-7emPTl6Dpo6JRXOXjLRxck+FlLRX5847cLKEn00PLAgc3g2hTZZgr+e4c2v6QpSmLeFP3n5yUo7ft6avBK/5jQ==", + "dev": true, "license": "MIT", "engines": { "node": ">= 0.6" @@ -38272,6 +39044,7 @@ "version": "1.6.3", "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-1.6.3.tgz", "integrity": "sha512-lks+lVC8dgGyh97jxvxeYTWQFvh4uw4yC12gVl63Cg30sjPX4wuGcdkICVXDAESr6OJGjqGA8Iz5mkeN6zlD7A==", + "dev": true, "license": "MIT", "dependencies": { "depd": "~1.1.2", @@ -38287,12 +39060,14 @@ "version": "2.0.3", "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz", "integrity": "sha512-x00IRNXNy63jwGkJmzPigoySHbaqpNuzKbBOmzK+g2OdZpQ9w+sxCN+VSB3ja7IAge2OP2qpfxTjeNcyjmW1uw==", + "dev": true, "license": "ISC" }, "node_modules/serve-index/node_modules/mime-db": { "version": "1.52.0", "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==", + "dev": true, "license": "MIT", "engines": { "node": ">= 0.6" @@ -38302,6 +39077,7 @@ "version": "2.1.35", "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz", "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==", + "dev": true, "license": "MIT", "dependencies": { "mime-db": "1.52.0" @@ -38314,12 +39090,14 @@ "version": "2.0.0", "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", + "dev": true, "license": "MIT" }, "node_modules/serve-index/node_modules/negotiator": { "version": "0.6.3", "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.3.tgz", "integrity": "sha512-+EUsqGPLsM+j/zdChZjsnX51g4XrHFOIXwfnCVPGlQk/k5giakcKsuxCObBRu6DSm9opw/O6slWbJdghQM4bBg==", + "dev": true, "license": "MIT", "engines": { "node": ">= 0.6" @@ -38329,12 +39107,14 @@ "version": "1.1.0", "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.1.0.tgz", "integrity": "sha512-BvE/TwpZX4FXExxOxZyRGQQv651MSwmWKZGqvmPcRIjDqWub67kTKuIMx43cZZrS/cBBzwBcNDWoFxt2XEFIpQ==", + "dev": true, "license": "ISC" }, "node_modules/serve-index/node_modules/statuses": { "version": "1.5.0", "resolved": "https://registry.npmjs.org/statuses/-/statuses-1.5.0.tgz", "integrity": "sha512-OpZ3zP+jT1PI7I8nemJX4AKmAX070ZkYPVWV/AaKTJl+tXCTGyVdC1a4SL8RUQYEwk/f34ZX8UTykN68FwrqAA==", + "dev": true, "license": "MIT", "engines": { "node": ">= 0.6" @@ -38344,6 +39124,7 @@ "version": "2.2.0", "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-2.2.0.tgz", "integrity": "sha512-61g9pCh0Vnh7IutZjtLGGpTA355+OPn2TyDv/6ivP2h/AdAVX9azsoxmg2/M6nZeQZNYBEwIcsne1mJd9oQItQ==", + "dev": true, "license": "MIT", "dependencies": { "encodeurl": "^2.0.0", @@ -38446,6 +39227,7 @@ "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, "license": "MIT", "dependencies": { "shebang-regex": "^3.0.0" @@ -38458,6 +39240,7 @@ "version": "3.0.0", "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", + "dev": true, "license": "MIT", "engines": { "node": ">=8" @@ -38467,6 +39250,7 @@ "version": "1.8.3", "resolved": "https://registry.npmjs.org/shell-quote/-/shell-quote-1.8.3.tgz", "integrity": "sha512-ObmnIF4hXNg1BqhnHmgbDETF8dLPCggZWBjkQfhZpbszZnYur5DUljTcCHii5LC3J5E0yeO/1LIMyH+UvHQgyw==", + "dev": true, "license": "MIT", "engines": { "node": ">= 0.4" @@ -38551,6 +39335,7 @@ "version": "4.1.0", "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-4.1.0.tgz", "integrity": "sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==", + "dev": true, "license": "ISC", "engines": { "node": ">=14" @@ -38677,6 +39462,7 @@ "version": "3.0.0", "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz", "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==", + "dev": true, "license": "MIT", "engines": { "node": ">=8" @@ -38713,6 +39499,7 @@ "version": "0.3.24", "resolved": "https://registry.npmjs.org/sockjs/-/sockjs-0.3.24.tgz", "integrity": "sha512-GJgLTZ7vYb/JtPSSZ10hsOYIvEYsjbNU+zPdIHcUaWVNUEPivzxku31865sSSud0Da0W4lEeOPlmw93zLQchuQ==", + "dev": true, "license": "MIT", "dependencies": { "faye-websocket": "^0.11.3", @@ -38724,6 +39511,7 @@ "version": "8.3.2", "resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz", "integrity": "sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==", + "dev": true, "license": "MIT", "bin": { "uuid": "dist/bin/uuid" @@ -38776,6 +39564,7 @@ "version": "0.7.6", "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.7.6.tgz", "integrity": "sha512-i5uvt8C3ikiWeNZSVZNWcfZPItFQOsYTUAOkcUPGd8DqDy1uOUikjt5dG+uRlwyvR108Fb9DOd4GvXfT0N2/uQ==", + "dev": true, "license": "BSD-3-Clause", "engines": { "node": ">= 12" @@ -38785,6 +39574,7 @@ "version": "1.2.1", "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.1.tgz", "integrity": "sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==", + "devOptional": true, "license": "BSD-3-Clause", "engines": { "node": ">=0.10.0" @@ -38794,6 +39584,7 @@ "version": "5.0.0", "resolved": "https://registry.npmjs.org/source-map-loader/-/source-map-loader-5.0.0.tgz", "integrity": "sha512-k2Dur7CbSLcAH73sBcIkV5xjPV4SzqO1NJ7+XaQl8if3VODDUj3FNchNGpqgJSKbvUfJuhVdv8K2Eu8/TNl2eA==", + "dev": true, "license": "MIT", "dependencies": { "iconv-lite": "^0.6.3", @@ -38814,6 +39605,7 @@ "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, "license": "MIT", "dependencies": { "buffer-from": "^1.0.0", @@ -38824,6 +39616,7 @@ "version": "0.6.1", "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true, "license": "BSD-3-Clause", "engines": { "node": ">=0.10.0" @@ -39027,6 +39820,7 @@ "version": "4.0.2", "resolved": "https://registry.npmjs.org/spdy/-/spdy-4.0.2.tgz", "integrity": "sha512-r46gZQZQV+Kl9oItvl1JZZqJKGr+oEkB08A6BzkiR7593/7IbtuncXHd2YoYeTsG4157ZssMu9KYvUHLcjcDoA==", + "dev": true, "license": "MIT", "dependencies": { "debug": "^4.1.0", @@ -39043,6 +39837,7 @@ "version": "3.0.0", "resolved": "https://registry.npmjs.org/spdy-transport/-/spdy-transport-3.0.0.tgz", "integrity": "sha512-hsLVFE5SjA6TCisWeJXFKniGGOpBgMLmerfO2aCyCU5s7nJ/rpAepqmFifv/GCbSbueEeAJJnmSQ2rKC/g8Fcw==", + "dev": true, "license": "MIT", "dependencies": { "debug": "^4.1.0", @@ -39057,6 +39852,7 @@ "version": "3.6.2", "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz", "integrity": "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==", + "dev": true, "license": "MIT", "dependencies": { "inherits": "^2.0.3", @@ -39131,6 +39927,7 @@ "version": "2.0.6", "resolved": "https://registry.npmjs.org/stack-utils/-/stack-utils-2.0.6.tgz", "integrity": "sha512-XlkWvfIm6RmsWtNJx+uqtKLS8eqFbxUg0ZzLXqY0caEy9l7hruX8IpiDnjsLavoBgqCCR71TqWO8MaXYheJ3RQ==", + "dev": true, "license": "MIT", "dependencies": { "escape-string-regexp": "^2.0.0" @@ -39143,6 +39940,7 @@ "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, "license": "MIT", "engines": { "node": ">=8" @@ -39307,6 +40105,7 @@ "version": "4.0.2", "resolved": "https://registry.npmjs.org/string-length/-/string-length-4.0.2.tgz", "integrity": "sha512-+l6rNN5fYHNhZZy41RXsYptCjA2Igmq4EG7kZAYFQI1E1VTXarr6ZPXBg6eq7Y6eK4FEhY6AJlyuFIb/v/S0VQ==", + "dev": true, "license": "MIT", "dependencies": { "char-regex": "^1.0.2", @@ -39335,6 +40134,7 @@ "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, "license": "MIT", "dependencies": { "emoji-regex": "^8.0.0", @@ -39421,6 +40221,7 @@ "version": "6.0.1", "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "dev": true, "license": "MIT", "dependencies": { "ansi-regex": "^5.0.1" @@ -39433,6 +40234,7 @@ "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, "license": "MIT", "engines": { "node": ">=8" @@ -39465,6 +40267,7 @@ "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, "license": "MIT", "engines": { "node": ">=8" @@ -39494,6 +40297,7 @@ "version": "6.1.1", "resolved": "https://registry.npmjs.org/stylehacks/-/stylehacks-6.1.1.tgz", "integrity": "sha512-gSTTEQ670cJNoaeIp9KX6lZmm8LJ3jPB5yJmX8Zq/wQxOsAFXV3qjWzHas3YYk1qesuVIyYWWUpZ0vSE/dTSGg==", + "dev": true, "license": "MIT", "dependencies": { "browserslist": "^4.23.0", @@ -39510,6 +40314,7 @@ "version": "6.1.2", "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-6.1.2.tgz", "integrity": "sha512-Q8qQfPiZ+THO/3ZrOrO0cJJKfpYCagtMUkXbnEfmgUjwXg6z/WBeOyS9APBBPCTSiDV+s4SwQGu8yFsiMRIudg==", + "dev": true, "license": "MIT", "dependencies": { "cssesc": "^3.0.0", @@ -39690,6 +40495,7 @@ "version": "3.3.2", "resolved": "https://registry.npmjs.org/svgo/-/svgo-3.3.2.tgz", "integrity": "sha512-OoohrmuUlBs8B8o6MB2Aevn+pRIH9zDALSR+6hhqVfa6fRwG/Qw9VUMSMW9VNg2CFc/MTIfabtdOVl9ODIJjpw==", + "dev": true, "license": "MIT", "dependencies": { "@trysound/sax": "0.2.0", @@ -39715,6 +40521,7 @@ "version": "7.2.0", "resolved": "https://registry.npmjs.org/commander/-/commander-7.2.0.tgz", "integrity": "sha512-QrWXB+ZQSVPmIWIhtEO9H+gwHaMGYiF5ChvoJ+K9ZGHG/sVsa6yiesAD1GC/x46sET00Xlwo1u49RVVVzvcSkw==", + "dev": true, "license": "MIT", "engines": { "node": ">= 10" @@ -39730,6 +40537,7 @@ "version": "1.0.2", "resolved": "https://registry.npmjs.org/sync-child-process/-/sync-child-process-1.0.2.tgz", "integrity": "sha512-8lD+t2KrrScJ/7KXCSyfhT3/hRq78rC0wBFqNJXv3mZyn6hW2ypM05JmlSvtqRbeq6jqA94oHbxAr2vYsJ8vDA==", + "dev": true, "license": "MIT", "dependencies": { "sync-message-port": "^1.0.0" @@ -39742,6 +40550,7 @@ "version": "1.1.3", "resolved": "https://registry.npmjs.org/sync-message-port/-/sync-message-port-1.1.3.tgz", "integrity": "sha512-GTt8rSKje5FilG+wEdfCkOcLL7LWqpMlr2c3LRuKt/YXxcJ52aGSbGBAdI4L3aaqfrBt6y711El53ItyH1NWzg==", + "dev": true, "license": "MIT", "engines": { "node": ">=16.0.0" @@ -39751,6 +40560,7 @@ "version": "0.11.11", "resolved": "https://registry.npmjs.org/synckit/-/synckit-0.11.11.tgz", "integrity": "sha512-MeQTA1r0litLUf0Rp/iisCaL8761lKAZHaimlbGK4j0HysC4PLfqygQj9srcs0m2RdtDYnF8UuYyKpbjHYp7Jw==", + "dev": true, "license": "MIT", "dependencies": { "@pkgr/core": "^0.2.9" @@ -39899,6 +40709,7 @@ "version": "2.3.0", "resolved": "https://registry.npmjs.org/tapable/-/tapable-2.3.0.tgz", "integrity": "sha512-g9ljZiwki/LfxmQADO3dEY1CbpmXT5Hm2fJ+QaGKwSXUylMybePR7/67YW7jOrrvjEgL1Fmz5kzyAjWVWLlucg==", + "dev": true, "license": "MIT", "engines": { "node": ">=6" @@ -39950,6 +40761,7 @@ "version": "2.2.0", "resolved": "https://registry.npmjs.org/tar-stream/-/tar-stream-2.2.0.tgz", "integrity": "sha512-ujeqbceABgwMZxEJnk2HDY2DlnUZ+9oEcb1KzTVfYHio0UE6dG71n60d8D2I4qNvleWrrXpmjpt7vZeF1LnMZQ==", + "dev": true, "license": "MIT", "dependencies": { "bl": "^4.0.3", @@ -39966,6 +40778,7 @@ "version": "3.6.2", "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz", "integrity": "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==", + "dev": true, "license": "MIT", "dependencies": { "inherits": "^2.0.3", @@ -40123,6 +40936,7 @@ "version": "5.43.1", "resolved": "https://registry.npmjs.org/terser/-/terser-5.43.1.tgz", "integrity": "sha512-+6erLbBm0+LROX2sPXlUYx/ux5PyE9K/a92Wrt6oA+WDAoFTdpHE5tCYCI5PNzq2y8df4rA+QgHLJuR4jNymsg==", + "dev": true, "license": "BSD-2-Clause", "dependencies": { "@jridgewell/source-map": "^0.3.3", @@ -40141,6 +40955,7 @@ "version": "5.3.14", "resolved": "https://registry.npmjs.org/terser-webpack-plugin/-/terser-webpack-plugin-5.3.14.tgz", "integrity": "sha512-vkZjpUjb6OMS7dhV+tILUW6BhpDR7P2L/aQSAv+Uwk+m8KATX9EccViHTJR2qDtACKPIYndLGCyl3FMo+r2LMw==", + "dev": true, "license": "MIT", "dependencies": { "@jridgewell/trace-mapping": "^0.3.25", @@ -40175,6 +40990,7 @@ "version": "27.5.1", "resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-27.5.1.tgz", "integrity": "sha512-7vuh85V5cdDofPyxn58nrPjBktZo0u9x1g8WtjQol+jZDaE+fhN+cIvTj11GndBnMnyfrUOG1sZQxCdjKh+DKg==", + "dev": true, "license": "MIT", "dependencies": { "@types/node": "*", @@ -40189,6 +41005,7 @@ "version": "8.1.1", "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz", "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==", + "dev": true, "license": "MIT", "dependencies": { "has-flag": "^4.0.0" @@ -40204,12 +41021,14 @@ "version": "2.20.3", "resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz", "integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==", + "dev": true, "license": "MIT" }, "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, "license": "ISC", "dependencies": { "@istanbuljs/schema": "^0.1.2", @@ -40224,6 +41043,7 @@ "version": "1.1.12", "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.12.tgz", "integrity": "sha512-9T9UjW3r0UW5c1Q7GTwllptXwhvYmEzFhzMfZ9H7FQWt+uZePjZPjBP/W1ZEyZ1twGWom5/56TF4lPcqjnDHcg==", + "dev": true, "license": "MIT", "dependencies": { "balanced-match": "^1.0.0", @@ -40235,6 +41055,7 @@ "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", "deprecated": "Glob versions prior to v9 are no longer supported", + "dev": true, "license": "ISC", "dependencies": { "fs.realpath": "^1.0.0", @@ -40255,6 +41076,7 @@ "version": "3.1.2", "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "dev": true, "license": "ISC", "dependencies": { "brace-expansion": "^1.1.7" @@ -40290,6 +41112,7 @@ "version": "1.21.0", "resolved": "https://registry.npmjs.org/thingies/-/thingies-1.21.0.tgz", "integrity": "sha512-hsqsJsFMsV+aD4s3CWKk85ep/3I9XzYV/IXaSouJMYIoDlgyi11cBhsqYe9/geRfB0YIikBQg6raRaM+nIMP9g==", + "dev": true, "license": "Unlicense", "engines": { "node": ">=10.18" @@ -40308,6 +41131,7 @@ "version": "1.1.0", "resolved": "https://registry.npmjs.org/thunky/-/thunky-1.1.0.tgz", "integrity": "sha512-eHY7nBftgThBqOyHGVN+l8gF0BucP09fMo0oO/Lb0w1OF80dJv+lDVpXG60WMQvkcxAkNybKsrEIE3ZtKGmPrA==", + "dev": true, "license": "MIT" }, "node_modules/tiny-async-pool": { @@ -40348,6 +41172,7 @@ "version": "0.2.14", "resolved": "https://registry.npmjs.org/tinyglobby/-/tinyglobby-0.2.14.tgz", "integrity": "sha512-tX5e7OM1HnYr2+a2C/4V0htOcSQcoSTH9KgJnVvNm5zm/cyEWKJ7j7YutsH9CxMdtOkkLFy2AHrMci9IM8IPZQ==", + "dev": true, "license": "MIT", "dependencies": { "fdir": "^6.4.4", @@ -40402,6 +41227,7 @@ "version": "0.2.3", "resolved": "https://registry.npmjs.org/tmp/-/tmp-0.2.3.tgz", "integrity": "sha512-nZD7m9iCPC5g0pYmcaxogYKggSfLsdxl8of3Q/oIbqCqLLIO9IAF0GWjX1z9NZRHPiXv8Wex4yDCaZsgEw0Y8w==", + "dev": true, "license": "MIT", "engines": { "node": ">=14.14" @@ -40421,12 +41247,14 @@ "version": "1.0.5", "resolved": "https://registry.npmjs.org/tmpl/-/tmpl-1.0.5.tgz", "integrity": "sha512-3f0uOEAQwIqGuWW2MVzYg8fV/QNnc/IpuJNG837rLuczAaLVHslWHZQj4IGiEl5Hs3kkbhwL9Ab7Hrsmuj+Smw==", + "dev": true, "license": "BSD-3-Clause" }, "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, "license": "MIT", "dependencies": { "is-number": "^7.0.0" @@ -40494,6 +41322,7 @@ "version": "1.0.3", "resolved": "https://registry.npmjs.org/tree-dump/-/tree-dump-1.0.3.tgz", "integrity": "sha512-il+Cv80yVHFBwokQSfd4bldvr1Md951DpgAGfmhydt04L+YzHgubm2tQ7zueWDcGENKHq0ZvGFR/hjvNXilHEg==", + "dev": true, "license": "Apache-2.0", "engines": { "node": ">=10.0" @@ -40510,6 +41339,7 @@ "version": "1.2.2", "resolved": "https://registry.npmjs.org/tree-kill/-/tree-kill-1.2.2.tgz", "integrity": "sha512-L0Orpi8qGpRG//Nd+H90vFB+3iHnue1zSSGmNOOCh1GLJ7rUKVwV2HvijphGQS2UmhUZewS9VgvxYIdgr+fG1A==", + "dev": true, "license": "MIT", "bin": { "tree-kill": "cli.js" @@ -40664,6 +41494,7 @@ "version": "9.5.4", "resolved": "https://registry.npmjs.org/ts-loader/-/ts-loader-9.5.4.tgz", "integrity": "sha512-nCz0rEwunlTZiy6rXFByQU1kVVpCIgUpc/psFiKVrUwrizdnIbRFu8w7bxhUF0X613DYwT4XzrZHpVyMe758hQ==", + "dev": true, "license": "MIT", "dependencies": { "chalk": "^4.1.0", @@ -40777,6 +41608,7 @@ "version": "4.2.0", "resolved": "https://registry.npmjs.org/tsconfig-paths-webpack-plugin/-/tsconfig-paths-webpack-plugin-4.2.0.tgz", "integrity": "sha512-zbem3rfRS8BgeNK50Zz5SIQgXzLafiHjOwUAvk/38/o1jHn/V5QAgVUcz884or7WYcPaH3N2CIfUc2u0ul7UcA==", + "dev": true, "license": "MIT", "dependencies": { "chalk": "^4.1.0", @@ -40792,6 +41624,7 @@ "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, "license": "MIT", "engines": { "node": ">=4" @@ -40801,6 +41634,7 @@ "version": "4.2.0", "resolved": "https://registry.npmjs.org/tsconfig-paths/-/tsconfig-paths-4.2.0.tgz", "integrity": "sha512-NoZ4roiN7LnbKn9QqE1amc9DJfzvZXxF4xDavcOWt1BPkdx+m+0gJuPM+S0vCe7zTJMYUP0R8pO2XMr+Y8oLIg==", + "dev": true, "license": "MIT", "dependencies": { "json5": "^2.2.2", @@ -41226,6 +42060,7 @@ "version": "0.4.0", "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz", "integrity": "sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==", + "dev": true, "license": "MIT", "dependencies": { "prelude-ls": "^1.2.1" @@ -41238,6 +42073,7 @@ "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, "license": "MIT", "engines": { "node": ">=4" @@ -41352,6 +42188,7 @@ "version": "1.0.9", "resolved": "https://registry.npmjs.org/typed-assert/-/typed-assert-1.0.9.tgz", "integrity": "sha512-KNNZtayBCtmnNmbo5mG47p1XsCyrx6iVqomjcZnec/1Y5GGARaxPs6r49RnSPeUP3YjNYiU9sQHAtY4BBvnZwg==", + "dev": true, "license": "MIT" }, "node_modules/typedarray": { @@ -41591,6 +42428,7 @@ "version": "2.0.1", "resolved": "https://registry.npmjs.org/unicode-canonical-property-names-ecmascript/-/unicode-canonical-property-names-ecmascript-2.0.1.tgz", "integrity": "sha512-dA8WbNeb2a6oQzAQ55YlT5vQAWGV9WXOsi3SskE3bcCdM0P4SDd+24zS/OCacdRq5BkdsRj9q3Pg6YyQoxIGqg==", + "dev": true, "license": "MIT", "engines": { "node": ">=4" @@ -41600,6 +42438,7 @@ "version": "2.0.0", "resolved": "https://registry.npmjs.org/unicode-match-property-ecmascript/-/unicode-match-property-ecmascript-2.0.0.tgz", "integrity": "sha512-5kaZCrbp5mmbz5ulBkDkbY0SsPOjKqVS35VpL9ulMPfSl0J0Xsm+9Evphv9CoIZFwre7aJoa94AY6seMKGVN5Q==", + "dev": true, "license": "MIT", "dependencies": { "unicode-canonical-property-names-ecmascript": "^2.0.0", @@ -41613,6 +42452,7 @@ "version": "2.2.0", "resolved": "https://registry.npmjs.org/unicode-match-property-value-ecmascript/-/unicode-match-property-value-ecmascript-2.2.0.tgz", "integrity": "sha512-4IehN3V/+kkr5YeSSDDQG8QLqO26XpL2XP3GQtqwlT/QYSECAwFztxVHjlbh0+gjJ3XmNLS0zDsbgs9jWKExLg==", + "dev": true, "license": "MIT", "engines": { "node": ">=4" @@ -41622,6 +42462,7 @@ "version": "2.1.0", "resolved": "https://registry.npmjs.org/unicode-property-aliases-ecmascript/-/unicode-property-aliases-ecmascript-2.1.0.tgz", "integrity": "sha512-6t3foTQI9qne+OZoVQB/8x8rk2k1eVy1gRXhV3oFQ5T6R1dqQ1xtin3XqSlx3+ATBkliTaR/hHyJBm+LVPNM8w==", + "dev": true, "license": "MIT", "engines": { "node": ">=4" @@ -41795,6 +42636,7 @@ "version": "1.9.1", "resolved": "https://registry.npmjs.org/unrs-resolver/-/unrs-resolver-1.9.1.tgz", "integrity": "sha512-4AZVxP05JGN6DwqIkSP4VKLOcwQa5l37SWHF/ahcuqBMbfxbpN1L1QKafEhWCziHhzKex9H/AR09H0OuVyU+9g==", + "dev": true, "hasInstallScript": true, "license": "MIT", "dependencies": { @@ -41843,6 +42685,7 @@ "version": "1.2.2", "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.2.2.tgz", "integrity": "sha512-E85pfNzMQ9jpKkA7+TJAi4TJN+tBCuWh5rUcS/sv6cFi+1q9LYDwDI5dpUL0u/73EElyQ8d3TEaeW4sPedBqYA==", + "dev": true, "funding": [ { "type": "opencollective", @@ -41873,6 +42716,7 @@ "version": "4.4.1", "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz", "integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==", + "dev": true, "license": "BSD-2-Clause", "dependencies": { "punycode": "^2.1.0" @@ -41953,13 +42797,14 @@ "version": "0.4.0", "resolved": "https://registry.npmjs.org/utila/-/utila-0.4.0.tgz", "integrity": "sha512-Z0DbgELS9/L/75wZbro8xAnT50pBVFQZ+hUEueGDU5FN51YSCYM+jdxsfCiHjwNP/4LCDD0i/graKpeBnOXKRA==", - "devOptional": true, + "dev": true, "license": "MIT" }, "node_modules/utils-merge": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/utils-merge/-/utils-merge-1.0.1.tgz", "integrity": "sha512-pMZTvIkT1d+TFGvDOqodOclx0QWkkgi6Tdoa8gC8ffGAAqz9pzPTZWAybbsHHoED/ztMtkv/VoYTYyShUn81hA==", + "dev": true, "license": "MIT", "engines": { "node": ">= 0.4.0" @@ -41989,6 +42834,7 @@ "version": "9.3.0", "resolved": "https://registry.npmjs.org/v8-to-istanbul/-/v8-to-istanbul-9.3.0.tgz", "integrity": "sha512-kiGUalWN+rgBJ/1OHZsBtU4rXZOfj/7rKQxULKlIzwzQSvMJUUNgPwJEEh7gU6xEVxC0ahoOBvN2YI8GH6FNgA==", + "dev": true, "license": "ISC", "dependencies": { "@jridgewell/trace-mapping": "^0.3.12", @@ -42003,6 +42849,7 @@ "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, "license": "MIT" }, "node_modules/validate-npm-package-license": { @@ -42030,6 +42877,7 @@ "version": "6.0.0", "resolved": "https://registry.npmjs.org/varint/-/varint-6.0.0.tgz", "integrity": "sha512-cXEIW6cfr15lFv563k4GuVuW/fiwjknytD37jIOLSdSWuOI6WnO/oKwmP2FQTU2l01LP8/M5TSAJpzUaGe3uWg==", + "dev": true, "license": "MIT" }, "node_modules/vary": { @@ -42458,6 +43306,7 @@ "version": "1.0.8", "resolved": "https://registry.npmjs.org/walker/-/walker-1.0.8.tgz", "integrity": "sha512-ts/8E8l5b7kY0vlWLewOkDXMmPdLcVV4GmOQLyxuSswIJsweeFZtAsMF7k1Nszz+TYBQrlYRmzOnr398y1JemQ==", + "dev": true, "license": "Apache-2.0", "dependencies": { "makeerror": "1.0.12" @@ -42467,6 +43316,7 @@ "version": "2.4.4", "resolved": "https://registry.npmjs.org/watchpack/-/watchpack-2.4.4.tgz", "integrity": "sha512-c5EGNOiyxxV5qmTtAB7rbiXxi1ooX1pQKMLX/MIabJjRA0SJBQOjKF+KSVfHkr9U1cADPon0mRiVe/riyaiDUA==", + "dev": true, "license": "MIT", "dependencies": { "glob-to-regexp": "^0.4.1", @@ -42480,6 +43330,7 @@ "version": "1.7.3", "resolved": "https://registry.npmjs.org/wbuf/-/wbuf-1.7.3.tgz", "integrity": "sha512-O84QOnr0icsbFGLS0O3bI5FswxzRr8/gHwWkDlQFskhSPryQXvrTMxjxGP4+iWYoauLoBvfDpkrOauZ+0iZpDA==", + "dev": true, "license": "MIT", "dependencies": { "minimalistic-assert": "^1.0.0" @@ -42515,6 +43366,7 @@ "version": "5.103.0", "resolved": "https://registry.npmjs.org/webpack/-/webpack-5.103.0.tgz", "integrity": "sha512-HU1JOuV1OavsZ+mfigY0j8d1TgQgbZ6M+J75zDkpEAwYeXjWSqrGJtgnPblJjd/mAyTNQ7ygw0MiKOn6etz8yw==", + "dev": true, "license": "MIT", "dependencies": { "@types/eslint-scope": "^3.7.7", @@ -42616,6 +43468,7 @@ "version": "7.4.2", "resolved": "https://registry.npmjs.org/webpack-dev-middleware/-/webpack-dev-middleware-7.4.2.tgz", "integrity": "sha512-xOO8n6eggxnwYpy1NlzUKpvrjfJTvae5/D6WOK0S2LSo7vjmo5gCM1DbLUmFqrMTJP+W/0YZNctm7jasWvLuBA==", + "dev": true, "license": "MIT", "dependencies": { "colorette": "^2.0.10", @@ -42645,6 +43498,7 @@ "version": "4.17.2", "resolved": "https://registry.npmjs.org/memfs/-/memfs-4.17.2.tgz", "integrity": "sha512-NgYhCOWgovOXSzvYgUW0LQ7Qy72rWQMGGFJDoWg4G30RHd3z77VbYdtJ4fembJXBy8pMIUA31XNAupobOQlwdg==", + "dev": true, "license": "Apache-2.0", "dependencies": { "@jsonjoy.com/json-pack": "^1.0.3", @@ -42664,6 +43518,7 @@ "version": "1.52.0", "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==", + "dev": true, "license": "MIT", "engines": { "node": ">= 0.6" @@ -42673,6 +43528,7 @@ "version": "2.1.35", "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz", "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==", + "dev": true, "license": "MIT", "dependencies": { "mime-db": "1.52.0" @@ -42685,6 +43541,7 @@ "version": "5.2.2", "resolved": "https://registry.npmjs.org/webpack-dev-server/-/webpack-dev-server-5.2.2.tgz", "integrity": "sha512-QcQ72gh8a+7JO63TAx/6XZf/CWhgMzu5m0QirvPfGvptOusAxG12w2+aua1Jkjr7hzaWDnJ2n6JFeexMHI+Zjg==", + "dev": true, "license": "MIT", "dependencies": { "@types/bonjour": "^3.5.13", @@ -42742,6 +43599,7 @@ "version": "4.17.25", "resolved": "https://registry.npmjs.org/@types/express/-/express-4.17.25.tgz", "integrity": "sha512-dVd04UKsfpINUnK0yBoYHDF3xu7xVH4BuDotC/xGuycx4CgbP48X/KF/586bcObxT0HENHXEU8Nqtu6NR+eKhw==", + "dev": true, "license": "MIT", "dependencies": { "@types/body-parser": "*", @@ -42754,6 +43612,7 @@ "version": "4.19.7", "resolved": "https://registry.npmjs.org/@types/express-serve-static-core/-/express-serve-static-core-4.19.7.tgz", "integrity": "sha512-FvPtiIf1LfhzsaIXhv/PHan/2FeQBbtBDtfX2QfvPxdUelMDEckK08SM6nqo1MIZY3RUlfA+HV8+hFUSio78qg==", + "dev": true, "license": "MIT", "dependencies": { "@types/node": "*", @@ -42766,6 +43625,7 @@ "version": "1.3.8", "resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.8.tgz", "integrity": "sha512-PYAthTa2m2VKxuvSD3DPC/Gy+U+sOA1LAuT8mkmRuvw+NACSaeXEQ+NHcVF7rONl6qcaxV3Uuemwawk+7+SJLw==", + "dev": true, "license": "MIT", "dependencies": { "mime-types": "~2.1.34", @@ -42779,6 +43639,7 @@ "version": "1.20.3", "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.20.3.tgz", "integrity": "sha512-7rAxByjUMqQ3/bHJy7D6OGXvx/MMc4IqBn/X0fcM1QUcAItpZrBEYhWGem+tzXH90c+G01ypMcYJBO9Y30203g==", + "dev": true, "license": "MIT", "dependencies": { "bytes": "3.1.2", @@ -42803,6 +43664,7 @@ "version": "3.6.0", "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.6.0.tgz", "integrity": "sha512-7VT13fmjotKpGipCW9JEQAusEPE+Ei8nl6/g4FBAmIm0GOOLMua9NDDo/DWp0ZAxCr3cPq5ZpBqmPAQgDda2Pw==", + "dev": true, "license": "MIT", "dependencies": { "anymatch": "~3.1.2", @@ -42827,6 +43689,7 @@ "version": "0.5.4", "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.4.tgz", "integrity": "sha512-FveZTNuGw04cxlAiWbzi6zTAL/lhehaWbTtgluJh4/E95DqMwTmha3KZN1aAWA8cFIhHzMZUvLevkw5Rqk+tSQ==", + "dev": true, "license": "MIT", "dependencies": { "safe-buffer": "5.2.1" @@ -42839,6 +43702,7 @@ "version": "0.7.1", "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.7.1.tgz", "integrity": "sha512-6DnInpx7SJ2AK3+CTUE/ZM0vWTUboZCegxhC2xiIydHR9jNuTAASBrfEpHhiGOZw/nX51bHt6YQl8jsGo4y/0w==", + "dev": true, "license": "MIT", "engines": { "node": ">= 0.6" @@ -42848,12 +43712,14 @@ "version": "1.0.6", "resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.6.tgz", "integrity": "sha512-QADzlaHc8icV8I7vbaJXJwod9HWYp8uCqf1xa4OfNu1T7JVxQIrUgOWtHdNDtPiywmFbiS12VjotIXLrKM3orQ==", + "dev": true, "license": "MIT" }, "node_modules/webpack-dev-server/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, "license": "MIT", "dependencies": { "ms": "2.0.0" @@ -42863,12 +43729,14 @@ "version": "2.0.0", "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", + "dev": true, "license": "MIT" }, "node_modules/webpack-dev-server/node_modules/express": { "version": "4.21.2", "resolved": "https://registry.npmjs.org/express/-/express-4.21.2.tgz", "integrity": "sha512-28HqgMZAmih1Czt9ny7qr6ek2qddF4FclbMzwhCREB6OFfH+rXAnuNCwo1/wFvrtbgsQDb4kSbX9de9lFbrXnA==", + "dev": true, "license": "MIT", "dependencies": { "accepts": "~1.3.8", @@ -42915,6 +43783,7 @@ "version": "1.3.1", "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.3.1.tgz", "integrity": "sha512-6BN9trH7bp3qvnrRyzsBz+g3lZxTNZTbVO2EV1CS0WIcDbawYVdYvGflME/9QP0h0pYlCDBCTjYa9nZzMDpyxQ==", + "dev": true, "license": "MIT", "dependencies": { "debug": "2.6.9", @@ -42933,6 +43802,7 @@ "version": "0.5.2", "resolved": "https://registry.npmjs.org/fresh/-/fresh-0.5.2.tgz", "integrity": "sha512-zJ2mQYM18rEFOudeV4GShTGIQ7RbzA7ozbU9I/XBpm7kqgMywgmylMwXHxZJmkVoYkna9d2pVXVXPdYTP9ej8Q==", + "dev": true, "license": "MIT", "engines": { "node": ">= 0.6" @@ -42942,6 +43812,7 @@ "version": "5.1.2", "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", + "dev": true, "license": "ISC", "dependencies": { "is-glob": "^4.0.1" @@ -42954,6 +43825,7 @@ "version": "2.0.9", "resolved": "https://registry.npmjs.org/http-proxy-middleware/-/http-proxy-middleware-2.0.9.tgz", "integrity": "sha512-c1IyJYLYppU574+YI7R4QyX2ystMtVXZwIdzazUIPIJsHuWNd+mho2j+bKoHftndicGj9yh+xjd+l0yj7VeT1Q==", + "dev": true, "license": "MIT", "dependencies": { "@types/http-proxy": "^1.17.8", @@ -42978,6 +43850,7 @@ "version": "0.4.24", "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz", "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==", + "dev": true, "license": "MIT", "dependencies": { "safer-buffer": ">= 2.1.2 < 3" @@ -42990,6 +43863,7 @@ "version": "2.2.0", "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-2.2.0.tgz", "integrity": "sha512-Ag3wB2o37wslZS19hZqorUnrnzSkpOVy+IiiDEiTqNubEYpYuHWIf6K4psgN2ZWKExS4xhVCrRVfb/wfW8fWJA==", + "dev": true, "license": "MIT", "engines": { "node": ">= 10" @@ -42999,6 +43873,7 @@ "version": "3.0.0", "resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-3.0.0.tgz", "integrity": "sha512-gwsOE28k+23GP1B6vFl1oVh/WOzmawBrKwo5Ev6wMKzPkaXaCDIQKzLnvsA42DRlbVTWorkgTKIviAKCWkfUwA==", + "dev": true, "license": "MIT", "engines": { "node": ">=10" @@ -43011,6 +43886,7 @@ "version": "0.3.0", "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz", "integrity": "sha512-dq+qelQ9akHpcOl/gUVRTxVIOkAJ1wR3QAvb4RsVjS8oVoFjDGTc679wJYmUmknUF5HwMLOgb5O+a3KxfWapPQ==", + "dev": true, "license": "MIT", "engines": { "node": ">= 0.6" @@ -43020,6 +43896,7 @@ "version": "1.0.3", "resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-1.0.3.tgz", "integrity": "sha512-gaNvAS7TZ897/rVaZ0nMtAyxNyi/pdbjbAwUpFQpN70GqnVfOiXpeUUMKRBmzXaSQ8DdTX4/0ms62r2K+hE6mQ==", + "dev": true, "license": "MIT", "funding": { "url": "https://github.com/sponsors/sindresorhus" @@ -43029,6 +43906,7 @@ "version": "1.6.0", "resolved": "https://registry.npmjs.org/mime/-/mime-1.6.0.tgz", "integrity": "sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==", + "dev": true, "license": "MIT", "bin": { "mime": "cli.js" @@ -43041,6 +43919,7 @@ "version": "1.52.0", "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==", + "dev": true, "license": "MIT", "engines": { "node": ">= 0.6" @@ -43050,6 +43929,7 @@ "version": "2.1.35", "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz", "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==", + "dev": true, "license": "MIT", "dependencies": { "mime-db": "1.52.0" @@ -43062,6 +43942,7 @@ "version": "0.6.3", "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.3.tgz", "integrity": "sha512-+EUsqGPLsM+j/zdChZjsnX51g4XrHFOIXwfnCVPGlQk/k5giakcKsuxCObBRu6DSm9opw/O6slWbJdghQM4bBg==", + "dev": true, "license": "MIT", "engines": { "node": ">= 0.6" @@ -43071,6 +43952,7 @@ "version": "10.2.0", "resolved": "https://registry.npmjs.org/open/-/open-10.2.0.tgz", "integrity": "sha512-YgBpdJHPyQ2UE5x+hlSXcnejzAvD0b22U2OuAP+8OnlJT+PjWPxtgmGqKKc+RgTM63U9gN0YzrYc71R2WT/hTA==", + "dev": true, "license": "MIT", "dependencies": { "default-browser": "^5.2.1", @@ -43089,12 +43971,14 @@ "version": "0.1.12", "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.12.tgz", "integrity": "sha512-RA1GjUVMnvYFxuqovrEqZoxxW5NUZqbwKtYz/Tt7nXerk0LbLblQmrsgdeOxV5SFHf0UDggjS/bSeOZwt1pmEQ==", + "dev": true, "license": "MIT" }, "node_modules/webpack-dev-server/node_modules/picomatch": { "version": "2.3.1", "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", + "dev": true, "license": "MIT", "engines": { "node": ">=8.6" @@ -43107,6 +43991,7 @@ "version": "6.13.0", "resolved": "https://registry.npmjs.org/qs/-/qs-6.13.0.tgz", "integrity": "sha512-+38qI9SOr8tfZ4QmJNplMUxqjbe7LKvvZgWdExBOmd+egZTtjLB67Gu0HRX3u/XOq7UU2Nx6nsjvS16Z9uwfpg==", + "dev": true, "license": "BSD-3-Clause", "dependencies": { "side-channel": "^1.0.6" @@ -43122,6 +44007,7 @@ "version": "2.5.2", "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.5.2.tgz", "integrity": "sha512-8zGqypfENjCIqGhgXToC8aB2r7YrBX+AQAfIPs/Mlk+BtPTztOvTS01NRW/3Eh60J+a48lt8qsCzirQ6loCVfA==", + "dev": true, "license": "MIT", "dependencies": { "bytes": "3.1.2", @@ -43137,6 +44023,7 @@ "version": "3.6.0", "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz", "integrity": "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==", + "dev": true, "license": "MIT", "dependencies": { "picomatch": "^2.2.1" @@ -43149,6 +44036,7 @@ "version": "0.19.0", "resolved": "https://registry.npmjs.org/send/-/send-0.19.0.tgz", "integrity": "sha512-dW41u5VfLXu8SJh5bwRmyYUbAoSB3c9uQh6L8h/KtsFREPWpbX1lrljJo186Jc4nmci/sGUZ9a0a0J2zgfq2hw==", + "dev": true, "license": "MIT", "dependencies": { "debug": "2.6.9", @@ -43173,6 +44061,7 @@ "version": "1.0.2", "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz", "integrity": "sha512-TPJXq8JqFaVYm2CWmPvnP2Iyo4ZSM7/QKcSmuMLDObfpH5fi7RUGmd/rTDf+rut/saiDiQEeVTNgAmJEdAOx0w==", + "dev": true, "license": "MIT", "engines": { "node": ">= 0.8" @@ -43182,6 +44071,7 @@ "version": "1.16.2", "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.16.2.tgz", "integrity": "sha512-VqpjJZKadQB/PEbEwvFdO43Ax5dFBZ2UECszz8bQ7pi7wt//PWe1P6MN7eCnjsatYtBT6EuiClbjSWP2WrIoTw==", + "dev": true, "license": "MIT", "dependencies": { "encodeurl": "~2.0.0", @@ -43197,6 +44087,7 @@ "version": "2.0.1", "resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.1.tgz", "integrity": "sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ==", + "dev": true, "license": "MIT", "engines": { "node": ">= 0.8" @@ -43206,6 +44097,7 @@ "version": "1.6.18", "resolved": "https://registry.npmjs.org/type-is/-/type-is-1.6.18.tgz", "integrity": "sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g==", + "dev": true, "license": "MIT", "dependencies": { "media-typer": "0.3.0", @@ -43246,6 +44138,7 @@ "version": "3.0.0", "resolved": "https://registry.npmjs.org/webpack-node-externals/-/webpack-node-externals-3.0.0.tgz", "integrity": "sha512-LnL6Z3GGDPht/AigwRh2dvL9PQPFQ8skEpVrWZXLWBYmqcaojHNN0onvHzie6rq7EWKrrBfPYqNEzTJgiwEQDQ==", + "dev": true, "license": "MIT", "engines": { "node": ">=6" @@ -43255,6 +44148,7 @@ "version": "3.3.3", "resolved": "https://registry.npmjs.org/webpack-sources/-/webpack-sources-3.3.3.tgz", "integrity": "sha512-yd1RBzSGanHkitROoPFd6qsrxt+oFhg/129YzheDGqeustzX0vTZJZsSsQjVQC4yzBQ56K55XU8gaNCtIzOnTg==", + "dev": true, "license": "MIT", "engines": { "node": ">=10.13.0" @@ -43264,6 +44158,7 @@ "version": "5.1.0", "resolved": "https://registry.npmjs.org/webpack-subresource-integrity/-/webpack-subresource-integrity-5.1.0.tgz", "integrity": "sha512-sacXoX+xd8r4WKsy9MvH/q/vBtEHr86cpImXwyg74pFIpERKt6FmB8cXpeuh0ZLgclOlHI4Wcll7+R5L02xk9Q==", + "dev": true, "license": "MIT", "dependencies": { "typed-assert": "^1.0.8" @@ -43292,6 +44187,7 @@ "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, "license": "BSD-2-Clause", "dependencies": { "esrecurse": "^4.3.0", @@ -43305,6 +44201,7 @@ "version": "4.3.0", "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.3.0.tgz", "integrity": "sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==", + "dev": true, "license": "BSD-2-Clause", "engines": { "node": ">=4.0" @@ -43314,12 +44211,14 @@ "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, "license": "MIT" }, "node_modules/webpack/node_modules/mime-db": { "version": "1.52.0", "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==", + "dev": true, "license": "MIT", "engines": { "node": ">= 0.6" @@ -43329,6 +44228,7 @@ "version": "2.1.35", "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz", "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==", + "dev": true, "license": "MIT", "dependencies": { "mime-db": "1.52.0" @@ -43341,6 +44241,7 @@ "version": "0.7.4", "resolved": "https://registry.npmjs.org/websocket-driver/-/websocket-driver-0.7.4.tgz", "integrity": "sha512-b17KeDIQVjvb0ssuSDF2cYXSg2iztliJ4B9WdsuB6J952qCPKmnVq4DyW5motImXHDC1cBT/1UezrJVsKw5zjg==", + "dev": true, "license": "Apache-2.0", "dependencies": { "http-parser-js": ">=0.5.1", @@ -43355,6 +44256,7 @@ "version": "0.1.4", "resolved": "https://registry.npmjs.org/websocket-extensions/-/websocket-extensions-0.1.4.tgz", "integrity": "sha512-OqedPIGOfsDlo31UNwYbCFMSaO9m9G/0faIHj5/dZFDMFqPTcx6UwqyOy3COEaEOg/9VsGIpdqn62W5KhoKSpg==", + "dev": true, "license": "Apache-2.0", "engines": { "node": ">=0.8.0" @@ -43398,6 +44300,7 @@ "version": "2.0.2", "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", + "dev": true, "license": "ISC", "dependencies": { "isexe": "^2.0.0" @@ -43573,6 +44476,7 @@ "version": "1.2.5", "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.5.tgz", "integrity": "sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA==", + "dev": true, "license": "MIT", "engines": { "node": ">=0.10.0" @@ -43604,6 +44508,7 @@ "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, "license": "MIT", "dependencies": { "ansi-styles": "^4.0.0", @@ -43621,6 +44526,7 @@ "version": "1.0.2", "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==", + "dev": true, "license": "ISC" }, "node_modules/write-file-atomic": { @@ -43669,6 +44575,7 @@ "version": "0.1.0", "resolved": "https://registry.npmjs.org/wsl-utils/-/wsl-utils-0.1.0.tgz", "integrity": "sha512-h3Fbisa2nKGPxCpm89Hk33lBLsnaGBvctQopaBSOW/uIs6FTe1ATyAnKFJrzVs9vpGdsTe73WF3V4lIsk4Gacw==", + "dev": true, "license": "MIT", "dependencies": { "is-wsl": "^3.1.0" @@ -43725,6 +44632,7 @@ "version": "5.0.8", "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz", "integrity": "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==", + "dev": true, "license": "ISC", "engines": { "node": ">=10" @@ -43734,12 +44642,14 @@ "version": "3.1.1", "resolved": "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz", "integrity": "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==", + "dev": true, "license": "ISC" }, "node_modules/yaml": { "version": "2.8.0", "resolved": "https://registry.npmjs.org/yaml/-/yaml-2.8.0.tgz", "integrity": "sha512-4lLa/EcQCB0cJkyts+FpIRx5G/llPxfP6VQU5KByHEhLxY3IJCH0f0Hy1MHI8sClTvsIb8qwRJ6R/ZdlDJ/leQ==", + "dev": true, "license": "ISC", "bin": { "yaml": "bin.mjs" @@ -43752,6 +44662,7 @@ "version": "17.7.2", "resolved": "https://registry.npmjs.org/yargs/-/yargs-17.7.2.tgz", "integrity": "sha512-7dSzzRQ++CKnNI/krKnYRV7JKKPUXMEh61soaHKg9mrWEhzFWhFnxPxGl+69cD1Ou63C13NUPCnmIcrvqCuM6w==", + "dev": true, "license": "MIT", "dependencies": { "cliui": "^8.0.1", @@ -43770,6 +44681,7 @@ "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, "license": "ISC", "engines": { "node": ">=12" @@ -43799,6 +44711,7 @@ "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, "license": "MIT", "engines": { "node": ">=10" @@ -43824,6 +44737,7 @@ "version": "3.25.76", "resolved": "https://registry.npmjs.org/zod/-/zod-3.25.76.tgz", "integrity": "sha512-gzUt/qt81nXsFGKIFcC3YnfEAx5NkunCfnDlvuBSSFS02bcXu4Lmea0AFIUwbLWxWPx3d9p8S5QoaujKcNQxcQ==", + "dev": true, "license": "MIT", "funding": { "url": "https://github.com/sponsors/colinhacks" @@ -43833,6 +44747,7 @@ "version": "3.24.5", "resolved": "https://registry.npmjs.org/zod-to-json-schema/-/zod-to-json-schema-3.24.5.tgz", "integrity": "sha512-/AuWwMP+YqiPbsJx5D6TfgRTc4kTLjsh5SOcd4bLsfUg2RcEXrFMJl1DGgdHy2aCfsIA/cr/1JM0xcB2GZji8g==", + "dev": true, "license": "ISC", "peerDependencies": { "zod": "^3.24.1" diff --git a/package.json b/package.json index 7b2b3701fdf..be6658964a0 100644 --- a/package.json +++ b/package.json @@ -50,6 +50,11 @@ "@eslint/compat": "2.0.0", "@lit-labs/signals": "0.1.3", "@ngtools/webpack": "20.3.12", + "@nx/devkit": "21.6.10", + "@nx/eslint": "21.6.10", + "@nx/jest": "21.6.10", + "@nx/js": "21.6.10", + "@nx/webpack": "21.6.10", "@storybook/addon-a11y": "9.1.16", "@storybook/addon-designs": "9.0.0-next.3", "@storybook/addon-docs": "9.1.16", @@ -157,8 +162,8 @@ "@angular/platform-browser": "20.3.15", "@angular/platform-browser-dynamic": "20.3.15", "@angular/router": "20.3.15", - "@bitwarden/sdk-internal": "0.2.0-main.433", - "@bitwarden/commercial-sdk-internal": "0.2.0-main.433", + "@bitwarden/sdk-internal": "0.2.0-main.450", + "@bitwarden/commercial-sdk-internal": "0.2.0-main.450", "@electron/fuses": "1.8.0", "@emotion/css": "11.13.5", "@koa/multer": "4.0.0", @@ -166,11 +171,6 @@ "@microsoft/signalr": "8.0.7", "@microsoft/signalr-protocol-msgpack": "8.0.7", "@ng-select/ng-select": "20.7.0", - "@nx/devkit": "21.6.10", - "@nx/eslint": "21.6.10", - "@nx/jest": "21.6.10", - "@nx/js": "21.6.10", - "@nx/webpack": "21.6.10", "big-integer": "1.6.52", "braintree-web-drop-in": "1.46.0", "buffer": "6.0.3",