diff --git a/.github/workflows/assistant-to-the-branch-manager.yml b/.github/workflows/assistant-to-the-branch-manager.yml index 2776b52166c7..4a9daab0a148 100644 --- a/.github/workflows/assistant-to-the-branch-manager.yml +++ b/.github/workflows/assistant-to-the-branch-manager.yml @@ -18,6 +18,6 @@ jobs: - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 with: persist-credentials: false - - uses: angular/dev-infra/github-actions/branch-manager@24ba9709ca4bf6548bba6a9abfe2799e90645a60 # main + - uses: angular/dev-infra/github-actions/branch-manager@0b701b31038419ad73422a9d9d3dff43a725a0d2 # main with: angular-robot-key: ${{ secrets.ANGULAR_ROBOT_PRIVATE_KEY }} diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 36989f0a514e..05fa1692e7c8 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -21,9 +21,9 @@ jobs: runs-on: ubuntu-latest steps: - name: Initialize environment - uses: angular/dev-infra/github-actions/npm/checkout-and-setup-node@24ba9709ca4bf6548bba6a9abfe2799e90645a60 # main + uses: angular/dev-infra/github-actions/npm/checkout-and-setup-node@0b701b31038419ad73422a9d9d3dff43a725a0d2 # main - name: Setup Bazel - uses: angular/dev-infra/github-actions/bazel/setup@24ba9709ca4bf6548bba6a9abfe2799e90645a60 # main + uses: angular/dev-infra/github-actions/bazel/setup@0b701b31038419ad73422a9d9d3dff43a725a0d2 # main - name: Install node modules run: pnpm install --frozen-lockfile - name: Generate JSON schema types @@ -44,11 +44,11 @@ jobs: runs-on: ubuntu-latest steps: - name: Initialize environment - uses: angular/dev-infra/github-actions/npm/checkout-and-setup-node@24ba9709ca4bf6548bba6a9abfe2799e90645a60 # main + uses: angular/dev-infra/github-actions/npm/checkout-and-setup-node@0b701b31038419ad73422a9d9d3dff43a725a0d2 # main - name: Setup Bazel - uses: angular/dev-infra/github-actions/bazel/setup@24ba9709ca4bf6548bba6a9abfe2799e90645a60 # main + uses: angular/dev-infra/github-actions/bazel/setup@0b701b31038419ad73422a9d9d3dff43a725a0d2 # main - name: Setup Bazel RBE - uses: angular/dev-infra/github-actions/bazel/configure-remote@24ba9709ca4bf6548bba6a9abfe2799e90645a60 # main + uses: angular/dev-infra/github-actions/bazel/configure-remote@0b701b31038419ad73422a9d9d3dff43a725a0d2 # main with: google_credential: ${{ secrets.RBE_TRUSTED_BUILDS_USER }} - name: Install node modules @@ -61,11 +61,11 @@ jobs: runs-on: ubuntu-latest steps: - name: Initialize environment - uses: angular/dev-infra/github-actions/npm/checkout-and-setup-node@24ba9709ca4bf6548bba6a9abfe2799e90645a60 # main + uses: angular/dev-infra/github-actions/npm/checkout-and-setup-node@0b701b31038419ad73422a9d9d3dff43a725a0d2 # main - name: Setup Bazel - uses: angular/dev-infra/github-actions/bazel/setup@24ba9709ca4bf6548bba6a9abfe2799e90645a60 # main + uses: angular/dev-infra/github-actions/bazel/setup@0b701b31038419ad73422a9d9d3dff43a725a0d2 # main - name: Setup Bazel RBE - uses: angular/dev-infra/github-actions/bazel/configure-remote@24ba9709ca4bf6548bba6a9abfe2799e90645a60 # main + uses: angular/dev-infra/github-actions/bazel/configure-remote@0b701b31038419ad73422a9d9d3dff43a725a0d2 # main with: google_credential: ${{ secrets.RBE_TRUSTED_BUILDS_USER }} - name: Install node modules @@ -84,13 +84,13 @@ jobs: runs-on: ubuntu-latest steps: - name: Initialize environment - uses: angular/dev-infra/github-actions/npm/checkout-and-setup-node@24ba9709ca4bf6548bba6a9abfe2799e90645a60 # main + uses: angular/dev-infra/github-actions/npm/checkout-and-setup-node@0b701b31038419ad73422a9d9d3dff43a725a0d2 # main - name: Install node modules run: pnpm install --frozen-lockfile - name: Setup Bazel - uses: angular/dev-infra/github-actions/bazel/setup@24ba9709ca4bf6548bba6a9abfe2799e90645a60 # main + uses: angular/dev-infra/github-actions/bazel/setup@0b701b31038419ad73422a9d9d3dff43a725a0d2 # main - name: Setup Bazel RBE - uses: angular/dev-infra/github-actions/bazel/configure-remote@24ba9709ca4bf6548bba6a9abfe2799e90645a60 # main + uses: angular/dev-infra/github-actions/bazel/configure-remote@0b701b31038419ad73422a9d9d3dff43a725a0d2 # main with: google_credential: ${{ secrets.RBE_TRUSTED_BUILDS_USER }} - name: Run CLI E2E tests @@ -100,11 +100,11 @@ jobs: runs-on: ubuntu-latest steps: - name: Initialize environment - uses: angular/dev-infra/github-actions/npm/checkout-and-setup-node@24ba9709ca4bf6548bba6a9abfe2799e90645a60 # main + uses: angular/dev-infra/github-actions/npm/checkout-and-setup-node@0b701b31038419ad73422a9d9d3dff43a725a0d2 # main - name: Setup Bazel - uses: angular/dev-infra/github-actions/bazel/setup@24ba9709ca4bf6548bba6a9abfe2799e90645a60 # main + uses: angular/dev-infra/github-actions/bazel/setup@0b701b31038419ad73422a9d9d3dff43a725a0d2 # main - name: Setup Bazel RBE - uses: angular/dev-infra/github-actions/bazel/configure-remote@24ba9709ca4bf6548bba6a9abfe2799e90645a60 # main + uses: angular/dev-infra/github-actions/bazel/configure-remote@0b701b31038419ad73422a9d9d3dff43a725a0d2 # main with: google_credential: ${{ secrets.RBE_TRUSTED_BUILDS_USER }} - name: Install node modules @@ -137,7 +137,7 @@ jobs: runs-on: windows-2025 steps: - name: Initialize environment - uses: angular/dev-infra/github-actions/npm/checkout-and-setup-node@24ba9709ca4bf6548bba6a9abfe2799e90645a60 # main + uses: angular/dev-infra/github-actions/npm/checkout-and-setup-node@0b701b31038419ad73422a9d9d3dff43a725a0d2 # main - name: Install node modules run: pnpm install --frozen-lockfile - name: Download built Windows E2E tests @@ -164,13 +164,13 @@ jobs: runs-on: ubuntu-latest steps: - name: Initialize environment - uses: angular/dev-infra/github-actions/npm/checkout-and-setup-node@24ba9709ca4bf6548bba6a9abfe2799e90645a60 # main + uses: angular/dev-infra/github-actions/npm/checkout-and-setup-node@0b701b31038419ad73422a9d9d3dff43a725a0d2 # main - name: Install node modules run: pnpm install --frozen-lockfile - name: Setup Bazel - uses: angular/dev-infra/github-actions/bazel/setup@24ba9709ca4bf6548bba6a9abfe2799e90645a60 # main + uses: angular/dev-infra/github-actions/bazel/setup@0b701b31038419ad73422a9d9d3dff43a725a0d2 # main - name: Setup Bazel RBE - uses: angular/dev-infra/github-actions/bazel/configure-remote@24ba9709ca4bf6548bba6a9abfe2799e90645a60 # main + uses: angular/dev-infra/github-actions/bazel/configure-remote@0b701b31038419ad73422a9d9d3dff43a725a0d2 # main with: google_credential: ${{ secrets.RBE_TRUSTED_BUILDS_USER }} - name: Run CLI E2E tests @@ -188,13 +188,13 @@ jobs: runs-on: ubuntu-latest steps: - name: Initialize environment - uses: angular/dev-infra/github-actions/npm/checkout-and-setup-node@24ba9709ca4bf6548bba6a9abfe2799e90645a60 # main + uses: angular/dev-infra/github-actions/npm/checkout-and-setup-node@0b701b31038419ad73422a9d9d3dff43a725a0d2 # main - name: Install node modules run: pnpm install --frozen-lockfile - name: Setup Bazel - uses: angular/dev-infra/github-actions/bazel/setup@24ba9709ca4bf6548bba6a9abfe2799e90645a60 # main + uses: angular/dev-infra/github-actions/bazel/setup@0b701b31038419ad73422a9d9d3dff43a725a0d2 # main - name: Setup Bazel RBE - uses: angular/dev-infra/github-actions/bazel/configure-remote@24ba9709ca4bf6548bba6a9abfe2799e90645a60 # main + uses: angular/dev-infra/github-actions/bazel/configure-remote@0b701b31038419ad73422a9d9d3dff43a725a0d2 # main with: google_credential: ${{ secrets.RBE_TRUSTED_BUILDS_USER }} - name: Run CLI E2E tests @@ -208,34 +208,35 @@ jobs: SAUCE_TUNNEL_IDENTIFIER: angular-cli-${{ github.workflow }}-${{ github.run_number }} steps: - name: Initialize environment - uses: angular/dev-infra/github-actions/npm/checkout-and-setup-node@24ba9709ca4bf6548bba6a9abfe2799e90645a60 # main + uses: angular/dev-infra/github-actions/npm/checkout-and-setup-node@0b701b31038419ad73422a9d9d3dff43a725a0d2 # main - name: Install node modules run: pnpm install --frozen-lockfile - name: Setup Bazel - uses: angular/dev-infra/github-actions/bazel/setup@24ba9709ca4bf6548bba6a9abfe2799e90645a60 # main + uses: angular/dev-infra/github-actions/bazel/setup@0b701b31038419ad73422a9d9d3dff43a725a0d2 # main - name: Setup Bazel RBE - uses: angular/dev-infra/github-actions/bazel/configure-remote@24ba9709ca4bf6548bba6a9abfe2799e90645a60 # main + uses: angular/dev-infra/github-actions/bazel/configure-remote@0b701b31038419ad73422a9d9d3dff43a725a0d2 # main with: google_credential: ${{ secrets.RBE_TRUSTED_BUILDS_USER }} + - name: Start Sauce Connect + uses: saucelabs/sauce-connect-action@cb88b508c6f9ff4d84490093733315dbd55de022 # v3 + timeout-minutes: 10 + with: + username: ${{ vars.SAUCE_USERNAME }} + accessKey: ${{ secrets.SAUCE_ACCESS_KEY }} + region: us-west-1 + tunnelName: ${{ env.SAUCE_TUNNEL_IDENTIFIER }} + proxyLocalhost: allow + # By default we disable SSL bumping for all requests. This is because SSL bumping is not needed + # for our test setup and in order to perform the SSL bumping, Saucelabs intercepts all HTTP + # requests in the tunnel VM and modifies them. This can cause flakiness as it makes all requests + # dependent on the SSL bumping middleware. + # See: https://wiki.saucelabs.com/display/DOCS/Troubleshooting+Sauce+Connect#TroubleshootingSauceConnect-DisablingSSLBumping + tlsPassthroughDomains: all - name: Run E2E Browser tests env: SAUCE_USERNAME: ${{ vars.SAUCE_USERNAME }} SAUCE_ACCESS_KEY: ${{ secrets.SAUCE_ACCESS_KEY }} - SAUCE_LOG_FILE: /tmp/angular/sauce-connect.log - SAUCE_READY_FILE: /tmp/angular/sauce-connect-ready-file.lock - SAUCE_PID_FILE: /tmp/angular/sauce-connect-pid-file.lock - SAUCE_TUNNEL_IDENTIFIER: 'angular-${{ github.run_number }}' - SAUCE_READY_FILE_TIMEOUT: 120 - run: | - ./scripts/saucelabs/start-tunnel.sh & - ./scripts/saucelabs/wait-for-tunnel.sh - pnpm bazel test --config=saucelabs //tests:e2e.saucelabs - ./scripts/saucelabs/stop-tunnel.sh - - uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1 - if: ${{ failure() }} - with: - name: sauce-connect-log - path: ${{ env.SAUCE_CONNECT_DIR_IN_HOST }}/sauce-connect.log + run: pnpm bazel test --config=saucelabs //tests:e2e.saucelabs publish-snapshots: needs: build @@ -244,11 +245,11 @@ jobs: CIRCLE_BRANCH: ${{ github.ref_name }} steps: - name: Initialize environment - uses: angular/dev-infra/github-actions/npm/checkout-and-setup-node@24ba9709ca4bf6548bba6a9abfe2799e90645a60 # main + uses: angular/dev-infra/github-actions/npm/checkout-and-setup-node@0b701b31038419ad73422a9d9d3dff43a725a0d2 # main - name: Install node modules run: pnpm install --frozen-lockfile - name: Setup Bazel - uses: angular/dev-infra/github-actions/bazel/setup@24ba9709ca4bf6548bba6a9abfe2799e90645a60 # main + uses: angular/dev-infra/github-actions/bazel/setup@0b701b31038419ad73422a9d9d3dff43a725a0d2 # main - run: pnpm admin snapshots --verbose env: SNAPSHOT_BUILDS_GITHUB_TOKEN: ${{ secrets.SNAPSHOT_BUILDS_GITHUB_TOKEN }} diff --git a/.github/workflows/dev-infra.yml b/.github/workflows/dev-infra.yml index 74f2c068b63d..0be73a55a51a 100644 --- a/.github/workflows/dev-infra.yml +++ b/.github/workflows/dev-infra.yml @@ -16,21 +16,21 @@ jobs: if: github.event_name == 'pull_request_target' runs-on: ubuntu-latest steps: - - uses: angular/dev-infra/github-actions/labeling/pull-request@24ba9709ca4bf6548bba6a9abfe2799e90645a60 # main + - uses: angular/dev-infra/github-actions/labeling/pull-request@0b701b31038419ad73422a9d9d3dff43a725a0d2 # main with: angular-robot-key: ${{ secrets.ANGULAR_ROBOT_PRIVATE_KEY }} post_approval_changes: if: github.event_name == 'pull_request_target' runs-on: ubuntu-latest steps: - - uses: angular/dev-infra/github-actions/post-approval-changes@24ba9709ca4bf6548bba6a9abfe2799e90645a60 # main + - uses: angular/dev-infra/github-actions/post-approval-changes@0b701b31038419ad73422a9d9d3dff43a725a0d2 # main with: angular-robot-key: ${{ secrets.ANGULAR_ROBOT_PRIVATE_KEY }} issue_labels: if: github.event_name == 'issues' runs-on: ubuntu-latest steps: - - uses: angular/dev-infra/github-actions/labeling/issue@24ba9709ca4bf6548bba6a9abfe2799e90645a60 # main + - uses: angular/dev-infra/github-actions/labeling/issue@0b701b31038419ad73422a9d9d3dff43a725a0d2 # main with: angular-robot-key: ${{ secrets.ANGULAR_ROBOT_PRIVATE_KEY }} google-generative-ai-key: ${{ secrets.GOOGLE_GENERATIVE_AI_KEY }} diff --git a/.github/workflows/perf.yml b/.github/workflows/perf.yml index f43583d2c5b1..5bca0fe665c8 100644 --- a/.github/workflows/perf.yml +++ b/.github/workflows/perf.yml @@ -22,7 +22,7 @@ jobs: workflows: ${{ steps.workflows.outputs.workflows }} steps: - name: Initialize environment - uses: angular/dev-infra/github-actions/npm/checkout-and-setup-node@24ba9709ca4bf6548bba6a9abfe2799e90645a60 # main + uses: angular/dev-infra/github-actions/npm/checkout-and-setup-node@0b701b31038419ad73422a9d9d3dff43a725a0d2 # main - name: Install node modules run: pnpm install --frozen-lockfile - id: workflows @@ -40,9 +40,9 @@ jobs: workflow: ${{ fromJSON(needs.list.outputs.workflows) }} steps: - name: Initialize environment - uses: angular/dev-infra/github-actions/npm/checkout-and-setup-node@24ba9709ca4bf6548bba6a9abfe2799e90645a60 # main + uses: angular/dev-infra/github-actions/npm/checkout-and-setup-node@0b701b31038419ad73422a9d9d3dff43a725a0d2 # main - name: Setup Bazel - uses: angular/dev-infra/github-actions/bazel/setup@24ba9709ca4bf6548bba6a9abfe2799e90645a60 # main + uses: angular/dev-infra/github-actions/bazel/setup@0b701b31038419ad73422a9d9d3dff43a725a0d2 # main - name: Install node modules run: pnpm install --frozen-lockfile # We utilize the google-github-actions/auth action to allow us to get an active credential using workflow diff --git a/.github/workflows/pr.yml b/.github/workflows/pr.yml index 351a1bbeed83..4100bed1bcc8 100644 --- a/.github/workflows/pr.yml +++ b/.github/workflows/pr.yml @@ -34,9 +34,9 @@ jobs: runs-on: ubuntu-latest steps: - name: Initialize environment - uses: angular/dev-infra/github-actions/npm/checkout-and-setup-node@24ba9709ca4bf6548bba6a9abfe2799e90645a60 # main + uses: angular/dev-infra/github-actions/npm/checkout-and-setup-node@0b701b31038419ad73422a9d9d3dff43a725a0d2 # main - name: Setup Bazel - uses: angular/dev-infra/github-actions/bazel/setup@24ba9709ca4bf6548bba6a9abfe2799e90645a60 # main + uses: angular/dev-infra/github-actions/bazel/setup@0b701b31038419ad73422a9d9d3dff43a725a0d2 # main - name: Setup ESLint Caching uses: actions/cache@55cc8345863c7cc4c66a329aec7e433d2d1c52a9 # v6.1.0 with: @@ -66,17 +66,17 @@ jobs: # it has been merged. run: pnpm ng-dev format changed --check ${{ github.event.pull_request.base.sha }} - name: Check Package Licenses - uses: angular/dev-infra/github-actions/linting/licenses@24ba9709ca4bf6548bba6a9abfe2799e90645a60 # main + uses: angular/dev-infra/github-actions/linting/licenses@0b701b31038419ad73422a9d9d3dff43a725a0d2 # main build: runs-on: ubuntu-latest steps: - name: Initialize environment - uses: angular/dev-infra/github-actions/npm/checkout-and-setup-node@24ba9709ca4bf6548bba6a9abfe2799e90645a60 # main + uses: angular/dev-infra/github-actions/npm/checkout-and-setup-node@0b701b31038419ad73422a9d9d3dff43a725a0d2 # main - name: Setup Bazel - uses: angular/dev-infra/github-actions/bazel/setup@24ba9709ca4bf6548bba6a9abfe2799e90645a60 # main + uses: angular/dev-infra/github-actions/bazel/setup@0b701b31038419ad73422a9d9d3dff43a725a0d2 # main - name: Setup Bazel RBE - uses: angular/dev-infra/github-actions/bazel/configure-remote@24ba9709ca4bf6548bba6a9abfe2799e90645a60 # main + uses: angular/dev-infra/github-actions/bazel/configure-remote@0b701b31038419ad73422a9d9d3dff43a725a0d2 # main - name: Install node modules run: pnpm install --frozen-lockfile - name: Build release targets @@ -93,11 +93,11 @@ jobs: runs-on: ubuntu-latest steps: - name: Initialize environment - uses: angular/dev-infra/github-actions/npm/checkout-and-setup-node@24ba9709ca4bf6548bba6a9abfe2799e90645a60 # main + uses: angular/dev-infra/github-actions/npm/checkout-and-setup-node@0b701b31038419ad73422a9d9d3dff43a725a0d2 # main - name: Setup Bazel - uses: angular/dev-infra/github-actions/bazel/setup@24ba9709ca4bf6548bba6a9abfe2799e90645a60 # main + uses: angular/dev-infra/github-actions/bazel/setup@0b701b31038419ad73422a9d9d3dff43a725a0d2 # main - name: Setup Bazel RBE - uses: angular/dev-infra/github-actions/bazel/configure-remote@24ba9709ca4bf6548bba6a9abfe2799e90645a60 # main + uses: angular/dev-infra/github-actions/bazel/configure-remote@0b701b31038419ad73422a9d9d3dff43a725a0d2 # main - name: Install node modules run: pnpm install --frozen-lockfile - name: Run module and package tests @@ -114,13 +114,13 @@ jobs: runs-on: ubuntu-latest steps: - name: Initialize environment - uses: angular/dev-infra/github-actions/npm/checkout-and-setup-node@24ba9709ca4bf6548bba6a9abfe2799e90645a60 # main + uses: angular/dev-infra/github-actions/npm/checkout-and-setup-node@0b701b31038419ad73422a9d9d3dff43a725a0d2 # main - name: Install node modules run: pnpm install --frozen-lockfile - name: Setup Bazel - uses: angular/dev-infra/github-actions/bazel/setup@24ba9709ca4bf6548bba6a9abfe2799e90645a60 # main + uses: angular/dev-infra/github-actions/bazel/setup@0b701b31038419ad73422a9d9d3dff43a725a0d2 # main - name: Setup Bazel RBE - uses: angular/dev-infra/github-actions/bazel/configure-remote@24ba9709ca4bf6548bba6a9abfe2799e90645a60 # main + uses: angular/dev-infra/github-actions/bazel/configure-remote@0b701b31038419ad73422a9d9d3dff43a725a0d2 # main - name: Run CLI E2E tests run: pnpm bazel test --test_env=E2E_SHARD_TOTAL=6 --test_env=E2E_SHARD_INDEX=${{ matrix.shard }} --config=e2e //tests:e2e.${{ matrix.subset }}_node${{ matrix.node }} @@ -128,11 +128,11 @@ jobs: runs-on: ubuntu-latest steps: - name: Initialize environment - uses: angular/dev-infra/github-actions/npm/checkout-and-setup-node@24ba9709ca4bf6548bba6a9abfe2799e90645a60 # main + uses: angular/dev-infra/github-actions/npm/checkout-and-setup-node@0b701b31038419ad73422a9d9d3dff43a725a0d2 # main - name: Setup Bazel - uses: angular/dev-infra/github-actions/bazel/setup@24ba9709ca4bf6548bba6a9abfe2799e90645a60 # main + uses: angular/dev-infra/github-actions/bazel/setup@0b701b31038419ad73422a9d9d3dff43a725a0d2 # main - name: Setup Bazel RBE - uses: angular/dev-infra/github-actions/bazel/configure-remote@24ba9709ca4bf6548bba6a9abfe2799e90645a60 # main + uses: angular/dev-infra/github-actions/bazel/configure-remote@0b701b31038419ad73422a9d9d3dff43a725a0d2 # main - name: Install node modules run: pnpm install --frozen-lockfile - name: Build E2E tests for Windows on Linux @@ -156,7 +156,7 @@ jobs: runs-on: windows-2025 steps: - name: Initialize environment - uses: angular/dev-infra/github-actions/npm/checkout-and-setup-node@24ba9709ca4bf6548bba6a9abfe2799e90645a60 # main + uses: angular/dev-infra/github-actions/npm/checkout-and-setup-node@0b701b31038419ad73422a9d9d3dff43a725a0d2 # main - name: Install node modules run: pnpm install --frozen-lockfile - name: Download built Windows E2E tests @@ -183,13 +183,13 @@ jobs: runs-on: ubuntu-latest steps: - name: Initialize environment - uses: angular/dev-infra/github-actions/npm/checkout-and-setup-node@24ba9709ca4bf6548bba6a9abfe2799e90645a60 # main + uses: angular/dev-infra/github-actions/npm/checkout-and-setup-node@0b701b31038419ad73422a9d9d3dff43a725a0d2 # main - name: Install node modules run: pnpm install --frozen-lockfile - name: Setup Bazel - uses: angular/dev-infra/github-actions/bazel/setup@24ba9709ca4bf6548bba6a9abfe2799e90645a60 # main + uses: angular/dev-infra/github-actions/bazel/setup@0b701b31038419ad73422a9d9d3dff43a725a0d2 # main - name: Setup Bazel RBE - uses: angular/dev-infra/github-actions/bazel/configure-remote@24ba9709ca4bf6548bba6a9abfe2799e90645a60 # main + uses: angular/dev-infra/github-actions/bazel/configure-remote@0b701b31038419ad73422a9d9d3dff43a725a0d2 # main - name: Run CLI E2E tests run: pnpm bazel test --test_env=E2E_SHARD_TOTAL=3 --test_env=E2E_SHARD_INDEX=${{ matrix.shard }} --config=e2e //tests:e2e.${{ matrix.subset }}_node${{ matrix.node }} @@ -205,12 +205,12 @@ jobs: runs-on: ubuntu-latest steps: - name: Initialize environment - uses: angular/dev-infra/github-actions/npm/checkout-and-setup-node@24ba9709ca4bf6548bba6a9abfe2799e90645a60 # main + uses: angular/dev-infra/github-actions/npm/checkout-and-setup-node@0b701b31038419ad73422a9d9d3dff43a725a0d2 # main - name: Install node modules run: pnpm install --frozen-lockfile - name: Setup Bazel - uses: angular/dev-infra/github-actions/bazel/setup@24ba9709ca4bf6548bba6a9abfe2799e90645a60 # main + uses: angular/dev-infra/github-actions/bazel/setup@0b701b31038419ad73422a9d9d3dff43a725a0d2 # main - name: Setup Bazel RBE - uses: angular/dev-infra/github-actions/bazel/configure-remote@24ba9709ca4bf6548bba6a9abfe2799e90645a60 # main + uses: angular/dev-infra/github-actions/bazel/configure-remote@0b701b31038419ad73422a9d9d3dff43a725a0d2 # main - name: Run CLI E2E tests run: pnpm bazel test --test_env=E2E_SHARD_TOTAL=6 --test_env=E2E_SHARD_INDEX=${{ matrix.shard }} --config=e2e //tests:e2e.snapshots.${{ matrix.subset }}_node${{ matrix.node }} diff --git a/.nvmrc b/.nvmrc index f9e7451e7715..c94711948a66 100644 --- a/.nvmrc +++ b/.nvmrc @@ -1 +1 @@ -22.23.1 +22.23.2 diff --git a/CHANGELOG.md b/CHANGELOG.md index 83391e1cfc3c..4f37cdba567a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,34 @@ + + +# 22.1.3 (2026-08-05) + +### @angular/cli + +| Commit | Type | Description | +| ---------------------------------------------------------------------------------------------------- | ---- | --------------------------------------------------------------------------------------------------------------------------------------------- | +| [f837b788c6](https://github.com/angular/angular-cli/commit/f837b788c6a23e7661db5455192f5a84d20e9b37) | fix | always install package during ng add to inspect manifest on disk for schematics ([#33718](https://github.com/angular/angular-cli/pull/33718)) | +| [72ae93638d](https://github.com/angular/angular-cli/commit/72ae93638dd83b3877773ac0d9f7e4c4e9056a33) | fix | correctly report available package updates during bare ng update | +| [a949e06568](https://github.com/angular/angular-cli/commit/a949e0656855786e4274159be09242ff9c4eb012) | fix | discover migrations from installed packages when omitted by registry metadata ([#33718](https://github.com/angular/angular-cli/pull/33718)) | +| [1d9122fd50](https://github.com/angular/angular-cli/commit/1d9122fd50f8a9b82199d44f9b0e075726279538) | fix | normalize Windows drive-letter casing for process.cwd | + +### @angular/build + +| Commit | Type | Description | +| ---------------------------------------------------------------------------------------------------- | ---- | ------------------------------------------------------------------------------------------------------------- | +| [a4860d505a](https://github.com/angular/angular-cli/commit/a4860d505aff0b43fc608cd0745ed187b1d407b5) | fix | prevent build process hang on unhandled error ([#33715](https://github.com/angular/angular-cli/pull/33715)) | +| [7686d66cab](https://github.com/angular/angular-cli/commit/7686d66cabcdfe90748ac405686d42674a19576f) | fix | retain watch files on error in load result cache | +| [25b7cf7504](https://github.com/angular/angular-cli/commit/25b7cf7504838d541abfba043d9ea3d616a23c04) | fix | support case-insensitive and alternative license file names | +| [4fd81402ce](https://github.com/angular/angular-cli/commit/4fd81402ce5f2f3db45a17ee0d116f12edf8d254) | perf | release build resources early in non-watch mode ([#33715](https://github.com/angular/angular-cli/pull/33715)) | + +### @angular/ssr + +| Commit | Type | Description | +| ---------------------------------------------------------------------------------------------------- | ---- | ---------------------------------------------------------- | +| [6af906cb94](https://github.com/angular/angular-cli/commit/6af906cb94bd0686b4c0431989e054711c74892a) | fix | settle writeResponseToNodeResponse when client disconnects | +| [917d3b2254](https://github.com/angular/angular-cli/commit/917d3b22549c19b91e03ceb0775a3a758142b9de) | perf | avoid buffering request body when sanitizing headers | + + + # 22.1.2 (2026-07-30) diff --git a/MODULE.bazel b/MODULE.bazel index cf3fa359b4d1..d4fb6902ff2a 100644 --- a/MODULE.bazel +++ b/MODULE.bazel @@ -19,36 +19,36 @@ bazel_dep(name = "aspect_rules_jasmine", version = "2.0.4") bazel_dep(name = "rules_angular") git_override( module_name = "rules_angular", - commit = "4768decdaefd4ba5206d8fa28f58d07bd8392479", + commit = "a0bbcceea19b7888114eeafe3f52f9822ca2b34a", remote = "https://github.com/angular/rules_angular.git", ) bazel_dep(name = "devinfra") git_override( module_name = "devinfra", - commit = "24ba9709ca4bf6548bba6a9abfe2799e90645a60", + commit = "0b701b31038419ad73422a9d9d3dff43a725a0d2", remote = "https://github.com/angular/dev-infra.git", ) bazel_dep(name = "rules_browsers") git_override( module_name = "rules_browsers", - commit = "566c60ccb543755029c4eb5a609fc8bfe4c5fc3f", + commit = "7fe4598226334b0809d3054f6948d72df4b5ed59", remote = "https://github.com/angular/rules_browsers.git", ) node = use_extension("@rules_nodejs//nodejs:extensions.bzl", "node") node.toolchain( node_repositories = { - "22.23.1-darwin_arm64": ("node-v22.23.1-darwin-arm64.tar.gz", "node-v22.23.1-darwin-arm64", "ef28d8fab2c0e4314522d4bb1b7173270aa3937e93b92cb7de79c112ac1fa953"), - "22.23.1-darwin_amd64": ("node-v22.23.1-darwin-x64.tar.gz", "node-v22.23.1-darwin-x64", "b8da981b8a0b1241b70249204916da76c63573ddf5814dbd2d1e41069105cb81"), - "22.23.1-linux_arm64": ("node-v22.23.1-linux-arm64.tar.xz", "node-v22.23.1-linux-arm64", "0294e8b915ab75f92c7513d2fcb830ae06e10684e6c603e99a87dbf8835389c1"), - "22.23.1-linux_ppc64le": ("node-v22.23.1-linux-ppc64le.tar.xz", "node-v22.23.1-linux-ppc64le", "a645bcb7bbc498d09ba9249b5c6414aa6d0a461d8854afc61e32096646ba5e66"), - "22.23.1-linux_s390x": ("node-v22.23.1-linux-s390x.tar.xz", "node-v22.23.1-linux-s390x", "f16b5636ba925b462e627c5e0ef47de3255bf4a7b38d56db58e2cf165df19c3c"), - "22.23.1-linux_amd64": ("node-v22.23.1-linux-x64.tar.xz", "node-v22.23.1-linux-x64", "9749e988f437343b7fa832c69ded82a312e41a03116d766797ac14f6f9eee578"), - "22.23.1-windows_amd64": ("node-v22.23.1-win-x64.zip", "node-v22.23.1-win-x64", "7df0bc9375723f4a86b3aa1b7cc73342423d9677a8df4538aca31a049e309c29"), + "22.23.2-darwin_arm64": ("node-v22.23.2-darwin-arm64.tar.gz", "node-v22.23.2-darwin-arm64", "61130f394c1630d211dd50aecc4353d379480f36d3ac913cd85dbba1aed585c6"), + "22.23.2-darwin_amd64": ("node-v22.23.2-darwin-x64.tar.gz", "node-v22.23.2-darwin-x64", "58e99022c2ff89395576cc7fd4d98cea24bb68081475d5f88b801ee8729fb026"), + "22.23.2-linux_arm64": ("node-v22.23.2-linux-arm64.tar.xz", "node-v22.23.2-linux-arm64", "fff4078c5def658577f92c88db7db3bc0072924bfb93fe52c1e744a54e94abb8"), + "22.23.2-linux_ppc64le": ("node-v22.23.2-linux-ppc64le.tar.xz", "node-v22.23.2-linux-ppc64le", "e2ba10110ad34096c051fe47134fcd12175ecc48e7e879d7d4c78b70cf66442c"), + "22.23.2-linux_s390x": ("node-v22.23.2-linux-s390x.tar.xz", "node-v22.23.2-linux-s390x", "50aa0935c7caee2f95434f84c2c19f16e4f223257eadb341a3a2d5aaa545bbe6"), + "22.23.2-linux_amd64": ("node-v22.23.2-linux-x64.tar.xz", "node-v22.23.2-linux-x64", "d60acfe00a2932254bb0ad20e01b0d74397a0875595de719654b214f4b03f307"), + "22.23.2-windows_amd64": ("node-v22.23.2-win-x64.zip", "node-v22.23.2-win-x64", "1177b4137ba5adaa56354ae40f1080c7450e8ae09cecb47da459d1c52ac99f97"), }, - node_version = "22.23.1", + node_version = "22.23.2", ) use_repo( node, @@ -131,8 +131,8 @@ use_repo( pnpm = use_extension("@aspect_rules_js//npm:extensions.bzl", "pnpm") pnpm.pnpm( name = "pnpm", - pnpm_version = "11.17.0", - pnpm_version_integrity = "sha512-zKPOozKtJUu4QUX5ZtGfSHlhUhA0b8kseaBH8joNezzKPDeS8AdrofGDHSd++88KkRmzGppg7Kf7PWIx8zHvcg==", + pnpm_version = "11.20.0", + pnpm_version_integrity = "sha512-mm8zCpW2ZEbqCI+vFSFAWooB8H/ecSTMmVjf7VLUu0NnN+ZbCPhfN7Rvy6N1CSVYrFEmK4FoRLIvY0Bu0Wa/7g==", ) use_repo(pnpm, "pnpm") diff --git a/MODULE.bazel.lock b/MODULE.bazel.lock index 3ea1381d3468..a30e6d148916 100644 --- a/MODULE.bazel.lock +++ b/MODULE.bazel.lock @@ -539,7 +539,7 @@ }, "@@rules_browsers+//browsers:extensions.bzl%browsers": { "general": { - "bzlTransitiveDigest": "WvB7GNrQ7jlXyl3ylGtiZfdi1oNh75x3hNfjjMcyCYM=", + "bzlTransitiveDigest": "w4tgtXA7WLl79lEQFfedhl7OVEGAKFqAFLnlI5c/Rtk=", "usagesDigest": "FmXYJVoVJlnfUU8x8gObSvu4qWcco/9Faw61aC/wBF0=", "recordedFileInputs": {}, "recordedDirentsInputs": {}, @@ -548,9 +548,9 @@ "rules_browsers_chrome_linux": { "repoRuleId": "@@rules_browsers+//browsers/private:browser_repo.bzl%browser_repo", "attributes": { - "sha256": "6b76900c3a3d65f178afd23f168da6f6d8194152cec17153ac599e1bcbd3c6e2", + "sha256": "7220f7149a01e85e631cb949b03fd472eba72fe0a92c6d8dab7833dd94e0c72c", "urls": [ - "https://storage.googleapis.com/chrome-for-testing-public/153.0.7979.0/linux64/chrome-headless-shell-linux64.zip" + "https://storage.googleapis.com/chrome-for-testing-public/153.0.7981.3/linux64/chrome-headless-shell-linux64.zip" ], "named_files": { "CHROME-HEADLESS-SHELL": "chrome-headless-shell-linux64/chrome-headless-shell" @@ -566,9 +566,9 @@ "rules_browsers_chrome_mac": { "repoRuleId": "@@rules_browsers+//browsers/private:browser_repo.bzl%browser_repo", "attributes": { - "sha256": "4cf740dc3e87bed680d1dfcb29d184866275cf7fdef2c49ad9371e02c6c5b858", + "sha256": "0d80d90379960943f3dc9f5eb966876010dd950736c97386e375581a56baf7c7", "urls": [ - "https://storage.googleapis.com/chrome-for-testing-public/153.0.7979.0/mac-x64/chrome-headless-shell-mac-x64.zip" + "https://storage.googleapis.com/chrome-for-testing-public/153.0.7981.3/mac-x64/chrome-headless-shell-mac-x64.zip" ], "named_files": { "CHROME-HEADLESS-SHELL": "chrome-headless-shell-mac-x64/chrome-headless-shell" @@ -584,9 +584,9 @@ "rules_browsers_chrome_mac_arm": { "repoRuleId": "@@rules_browsers+//browsers/private:browser_repo.bzl%browser_repo", "attributes": { - "sha256": "9f58dab0e03988de906ece512986bf7503086cb31ad2a6a85c22e42a1be74187", + "sha256": "7fad05ead762524231ed026cf40385cba80cb3daab2973622f3533308fc045fa", "urls": [ - "https://storage.googleapis.com/chrome-for-testing-public/153.0.7979.0/mac-arm64/chrome-headless-shell-mac-arm64.zip" + "https://storage.googleapis.com/chrome-for-testing-public/153.0.7981.3/mac-arm64/chrome-headless-shell-mac-arm64.zip" ], "named_files": { "CHROME-HEADLESS-SHELL": "chrome-headless-shell-mac-arm64/chrome-headless-shell" @@ -602,9 +602,9 @@ "rules_browsers_chrome_win64": { "repoRuleId": "@@rules_browsers+//browsers/private:browser_repo.bzl%browser_repo", "attributes": { - "sha256": "0baf0d0feacb5e683668a864467458a0a6f5e78cf7defa69c83d87fe94016874", + "sha256": "2c08f3f53115434e3dd623e2e1f1f54896fa4b2cbaf86518d7f4708dc80fe67d", "urls": [ - "https://storage.googleapis.com/chrome-for-testing-public/153.0.7979.0/win64/chrome-headless-shell-win64.zip" + "https://storage.googleapis.com/chrome-for-testing-public/153.0.7981.3/win64/chrome-headless-shell-win64.zip" ], "named_files": { "CHROME-HEADLESS-SHELL": "chrome-headless-shell-win64/chrome-headless-shell.exe" @@ -620,9 +620,9 @@ "rules_browsers_chromedriver_linux": { "repoRuleId": "@@rules_browsers+//browsers/private:browser_repo.bzl%browser_repo", "attributes": { - "sha256": "7f2e21830d670ad1ca9e67fc296246296cab741254c0ce42abd2e1f4c6af12f2", + "sha256": "8bab44616dd81669a7a99d77c6b7e952ee3ec3bfd01ddf864cf795a880cfbd92", "urls": [ - "https://storage.googleapis.com/chrome-for-testing-public/153.0.7979.0/linux64/chromedriver-linux64.zip" + "https://storage.googleapis.com/chrome-for-testing-public/153.0.7981.3/linux64/chromedriver-linux64.zip" ], "named_files": { "CHROMEDRIVER": "chromedriver-linux64/chromedriver" @@ -636,9 +636,9 @@ "rules_browsers_chromedriver_mac": { "repoRuleId": "@@rules_browsers+//browsers/private:browser_repo.bzl%browser_repo", "attributes": { - "sha256": "49674ac7c9479c70bd02798fe68cb97805cc86d64edc379fb96d62340547b0ac", + "sha256": "d1f8618664ec5b0433c19b36eef91b55671a1adf595ffd012da8b859c32dc7b1", "urls": [ - "https://storage.googleapis.com/chrome-for-testing-public/153.0.7979.0/mac-x64/chromedriver-mac-x64.zip" + "https://storage.googleapis.com/chrome-for-testing-public/153.0.7981.3/mac-x64/chromedriver-mac-x64.zip" ], "named_files": { "CHROMEDRIVER": "chromedriver-mac-x64/chromedriver" @@ -652,9 +652,9 @@ "rules_browsers_chromedriver_mac_arm": { "repoRuleId": "@@rules_browsers+//browsers/private:browser_repo.bzl%browser_repo", "attributes": { - "sha256": "df00e65e5890905835a15befb593efcbcb71575ae01c5c01fc7fac05e9a65a77", + "sha256": "3c8b50af153cf6e8de8f2ec9f4b9a1ce717cd76a3ca6c82f9e736d7b705bdbe2", "urls": [ - "https://storage.googleapis.com/chrome-for-testing-public/153.0.7979.0/mac-arm64/chromedriver-mac-arm64.zip" + "https://storage.googleapis.com/chrome-for-testing-public/153.0.7981.3/mac-arm64/chromedriver-mac-arm64.zip" ], "named_files": { "CHROMEDRIVER": "chromedriver-mac-arm64/chromedriver" @@ -668,9 +668,9 @@ "rules_browsers_chromedriver_win64": { "repoRuleId": "@@rules_browsers+//browsers/private:browser_repo.bzl%browser_repo", "attributes": { - "sha256": "caf7c63464f124a301f53bd3babd3f7553d8249886d3469687ab6d805622dac8", + "sha256": "2fdba8a5036173c57627b38df844e2f9c6634dd027eaa5a5f306033e14414e08", "urls": [ - "https://storage.googleapis.com/chrome-for-testing-public/153.0.7979.0/win64/chromedriver-win64.zip" + "https://storage.googleapis.com/chrome-for-testing-public/153.0.7981.3/win64/chromedriver-win64.zip" ], "named_files": { "CHROMEDRIVER": "chromedriver-win64/chromedriver.exe" diff --git a/modules/testing/builder/package.json b/modules/testing/builder/package.json index 09a8bd46fd3e..048981abdc06 100644 --- a/modules/testing/builder/package.json +++ b/modules/testing/builder/package.json @@ -8,7 +8,7 @@ "browser-sync": "3.0.4", "istanbul-lib-instrument": "6.0.3", "jsdom": "29.1.1", - "ng-packagr": "22.1.0", + "ng-packagr": "22.1.1", "rxjs": "7.8.2", "vitest": "4.1.10" } diff --git a/package.json b/package.json index c8a0debe6bd5..5ff4b5f8d2b8 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@angular/devkit-repo", - "version": "22.1.2", + "version": "22.1.3", "private": true, "description": "Software Development Kit for Angular", "keywords": [ @@ -28,12 +28,12 @@ "type": "git", "url": "git+https://github.com/angular/angular-cli.git" }, - "packageManager": "pnpm@11.17.0", + "packageManager": "pnpm@11.20.0", "engines": { "node": "^22.22.3 || ^24.15.0 || >=26.0.0", "npm": "Please use pnpm instead of NPM to install dependencies", "yarn": "Please use pnpm instead of Yarn to install dependencies", - "pnpm": "11.17.0" + "pnpm": "11.20.0" }, "author": "Angular Authors", "license": "MIT", @@ -54,7 +54,7 @@ "@angular/forms": "22.1.0", "@angular/localize": "22.1.0", "@angular/material": "22.1.0", - "@angular/ng-dev": "https://github.com/angular/dev-infra-private-ng-dev-builds.git#2af985ddb942b5928dfb730a6b8efaccd1798846", + "@angular/ng-dev": "https://github.com/angular/dev-infra-private-ng-dev-builds.git#dcf9b6776377d5d301e054111add3ef80f433b70", "@angular/platform-browser": "22.1.0", "@angular/platform-server": "22.1.0", "@angular/router": "22.1.0", diff --git a/packages/angular/build/package.json b/packages/angular/build/package.json index dd3b450de89d..667658bfb03b 100644 --- a/packages/angular/build/package.json +++ b/packages/angular/build/package.json @@ -55,8 +55,8 @@ "istanbul-lib-instrument": "6.0.3", "jsdom": "29.1.1", "less": "4.6.7", - "ng-packagr": "22.1.0", - "postcss": "8.5.19", + "ng-packagr": "22.1.1", + "postcss": "8.5.25", "rollup": "4.62.2", "rxjs": "7.8.2", "vitest": "4.1.10" diff --git a/packages/angular/build/src/builders/application/build-action.ts b/packages/angular/build/src/builders/application/build-action.ts index d7dbdc8cfe21..dbec8d687b9f 100644 --- a/packages/angular/build/src/builders/application/build-action.ts +++ b/packages/angular/build/src/builders/application/build-action.ts @@ -81,7 +81,7 @@ export async function* runEsBuildBuildAction( const withProgress: typeof withSpinner = progress ? withSpinner : withNoProgress; // Initial build - let result: ExecutionResult; + let result: ExecutionResult | undefined; try { // Perform the build action result = await withProgress('Building...', () => action()); @@ -89,8 +89,8 @@ export async function* runEsBuildBuildAction( // Log all diagnostic (error/warning/logs) messages await logMessages(logger, result, colors, jsonLogs); } finally { - // Ensure Sass workers are shutdown if not watching - if (!watch) { + // Ensure Sass workers are shutdown if not watching or if the initial build failed + if (!watch || !result) { shutdownSassWorkerPool(); } } diff --git a/packages/angular/build/src/builders/application/execute-build.ts b/packages/angular/build/src/builders/application/execute-build.ts index 21beb57bf478..faa61c6e523b 100644 --- a/packages/angular/build/src/builders/application/execute-build.ts +++ b/packages/angular/build/src/builders/application/execute-build.ts @@ -74,12 +74,19 @@ export async function executeBuild( let bundlingResult: BundleContextResult; let templateUpdates: Map | undefined; let angularCompilationContext: AngularCompilationContext | undefined; + let executionResult: ExecutionResult | undefined; try { if (rebuildState) { bundlerContexts = rebuildState.rebuildContexts; componentStyleBundler = rebuildState.componentStyleBundler; codeBundleCache = rebuildState.codeBundleCache; templateUpdates = rebuildState.templateUpdates; + executionResult = new ExecutionResult( + bundlerContexts, + componentStyleBundler, + codeBundleCache, + templateUpdates, + ); // Reset template updates for new rebuild templateUpdates?.clear(); @@ -122,6 +129,12 @@ export async function executeBuild( angularCompilationContext, templateUpdates, ); + executionResult = new ExecutionResult( + bundlerContexts, + componentStyleBundler, + codeBundleCache, + templateUpdates, + ); // Bundle everything on initial build bundlingResult = await BundlerContext.bundleAll([ @@ -138,234 +151,241 @@ export async function executeBuild( const componentResults = await componentStyleBundler.bundleAllFiles(true, true); bundlingResult = BundlerContext.mergeResults([bundlingResult, ...componentResults]); } - } catch (error) { - await angularCompilationContext?.dispose(); - throw error; - } - const executionResult = new ExecutionResult( - bundlerContexts, - componentStyleBundler, - codeBundleCache, - templateUpdates, - ); - executionResult.addWarnings(bundlingResult.warnings); - - // Add used external component style referenced files to be watched - if (options.externalRuntimeStyles) { - executionResult.extraWatchFiles.push(...componentStyleBundler.collectReferencedFiles()); - } - - // Return if the bundling has errors - if (bundlingResult.errors) { - executionResult.addErrors(bundlingResult.errors); - - return executionResult; - } + executionResult.addWarnings(bundlingResult.warnings); - // Optimize chunks if enabled and threshold is met. - // This pass uses Rollup/Rolldown to further optimize chunks generated by esbuild. - if (options.optimizationOptions.scripts) { - // Count lazy chunks (files not needed for initial load). - // Advanced chunk optimization is most beneficial when there are multiple lazy chunks. - const { metafile, initialFiles } = bundlingResult; - const lazyChunksCount = Object.keys(metafile.outputs).filter( - (path) => path.endsWith('.js') && !initialFiles.has(path), - ).length; - - // Only run if the number of lazy chunks meets the configured threshold. - // This avoids overhead for small projects with few chunks. - if (lazyChunksCount >= optimizeChunksThreshold) { - const { optimizeChunks } = await import('./chunk-optimizer'); - const optimizationResult = await profileAsync('OPTIMIZE_CHUNKS', () => - optimizeChunks( - bundlingResult, - options.sourcemapOptions.scripts ? !options.sourcemapOptions.hidden || 'hidden' : false, - ), - ); + // Add used external component style referenced files to be watched + if (options.externalRuntimeStyles) { + executionResult.extraWatchFiles.push(...componentStyleBundler.collectReferencedFiles()); + } - if (optimizationResult.errors) { - executionResult.addErrors(optimizationResult.errors); + // In non-watch mode, the bundler rebuild contexts and Angular compilation + // are no longer needed once bundling completes. Dispose them early to free + // worker processes, TypeScript ASTs, and caches before post-bundling steps + // execute or before returning bundling errors. + // This is fire-and-forget so worker teardown runs concurrently in the background + // without blocking the critical path of post-bundle optimization steps. + // Any in-flight disposal is awaited in the builder action's finally block. + if (!options.watch) { + void angularCompilationContext?.dispose(); + void executionResult.dispose(); + } - return executionResult; - } + // Return if the bundling has errors + if (bundlingResult.errors) { + executionResult.addErrors(bundlingResult.errors); - bundlingResult = optimizationResult; + return executionResult; } - } - // Analyze external imports if external options are enabled - if (options.externalPackages || bundlingResult.externalConfiguration) { - const { - externalConfiguration = [], - externalImports: { browser = [], server = [] }, - } = bundlingResult; - // Similar to esbuild, --external:@foo/bar automatically implies --external:@foo/bar/*, - // which matches import paths like @foo/bar/baz. - // This means all paths within the @foo/bar package are also marked as external. - const exclusionsPrefixes = externalConfiguration.map((exclusion) => exclusion + '/'); - const exclusions = new Set(externalConfiguration); - const explicitExternal = new Set(); - - const isExplicitExternal = (dep: string): boolean => { - // Locale-data imports are injected by the builder itself (see i18n-locale-plugin) and must stay resolvable - // even when the containing package is externalized by the user. - if (dep.startsWith(`${LOCALE_DATA_BASE_MODULE}/`)) { - return false; - } + // Optimize chunks if enabled and threshold is met. + // This pass uses Rollup/Rolldown to further optimize chunks generated by esbuild. + if (options.optimizationOptions.scripts) { + // Count lazy chunks (files not needed for initial load). + // Advanced chunk optimization is most beneficial when there are multiple lazy chunks. + const { metafile, initialFiles } = bundlingResult; + const lazyChunksCount = Object.keys(metafile.outputs).filter( + (path) => path.endsWith('.js') && !initialFiles.has(path), + ).length; + + // Only run if the number of lazy chunks meets the configured threshold. + // This avoids overhead for small projects with few chunks. + if (lazyChunksCount >= optimizeChunksThreshold) { + const { optimizeChunks } = await import('./chunk-optimizer'); + const optimizationResult = await profileAsync('OPTIMIZE_CHUNKS', () => + optimizeChunks( + bundlingResult, + options.sourcemapOptions.scripts ? !options.sourcemapOptions.hidden || 'hidden' : false, + ), + ); + + if (optimizationResult.errors) { + executionResult.addErrors(optimizationResult.errors); + + return executionResult; + } - if (exclusions.has(dep)) { - return true; + bundlingResult = optimizationResult; } + } - for (const prefix of exclusionsPrefixes) { - if (dep.startsWith(prefix)) { + // Analyze external imports if external options are enabled + if (options.externalPackages || bundlingResult.externalConfiguration) { + const { + externalConfiguration = [], + externalImports: { browser = [], server = [] }, + } = bundlingResult; + // Similar to esbuild, --external:@foo/bar automatically implies --external:@foo/bar/*, + // which matches import paths like @foo/bar/baz. + // This means all paths within the @foo/bar package are also marked as external. + const exclusionsPrefixes = externalConfiguration.map((exclusion) => exclusion + '/'); + const exclusions = new Set(externalConfiguration); + const explicitExternal = new Set(); + + const isExplicitExternal = (dep: string): boolean => { + // Locale-data imports are injected by the builder itself (see i18n-locale-plugin) and must stay resolvable + // even when the containing package is externalized by the user. + if (dep.startsWith(`${LOCALE_DATA_BASE_MODULE}/`)) { + return false; + } + + if (exclusions.has(dep)) { return true; } - } - return false; - }; + for (const prefix of exclusionsPrefixes) { + if (dep.startsWith(prefix)) { + return true; + } + } - const implicitBrowser: string[] = []; - for (const dep of browser) { - if (isExplicitExternal(dep)) { - explicitExternal.add(dep); - } else { - implicitBrowser.push(dep); + return false; + }; + + const implicitBrowser: string[] = []; + for (const dep of browser) { + if (isExplicitExternal(dep)) { + explicitExternal.add(dep); + } else { + implicitBrowser.push(dep); + } } - } - const implicitServer: string[] = []; - for (const dep of server) { - if (isExplicitExternal(dep)) { - explicitExternal.add(dep); - } else { - implicitServer.push(dep); + const implicitServer: string[] = []; + for (const dep of server) { + if (isExplicitExternal(dep)) { + explicitExternal.add(dep); + } else { + implicitServer.push(dep); + } } - } - executionResult.setExternalMetadata(implicitBrowser, implicitServer, [...explicitExternal]); - } + executionResult.setExternalMetadata(implicitBrowser, implicitServer, [...explicitExternal]); + } - const { metafile, initialFiles, outputFiles } = bundlingResult; + const { metafile, initialFiles, outputFiles } = bundlingResult; - executionResult.outputFiles.push(...outputFiles); + executionResult.outputFiles.push(...outputFiles); - // Analyze files for bundle budget failures if present - let budgetFailures: BudgetCalculatorResult[] | undefined; - if (options.budgets) { - const compatStats = generateBudgetStats(metafile, outputFiles, initialFiles); - budgetFailures = [...checkBudgets(options.budgets, compatStats, true)]; - for (const { message, severity } of budgetFailures) { - if (severity === 'error') { - executionResult.addError(message); - } else { - executionResult.addWarning(message); + // Analyze files for bundle budget failures if present + let budgetFailures: BudgetCalculatorResult[] | undefined; + if (options.budgets) { + const compatStats = generateBudgetStats(metafile, outputFiles, initialFiles); + budgetFailures = [...checkBudgets(options.budgets, compatStats, true)]; + for (const { message, severity } of budgetFailures) { + if (severity === 'error') { + executionResult.addError(message); + } else { + executionResult.addWarning(message); + } } } - } - // Calculate estimated transfer size if scripts are optimized - let estimatedTransferSizes; - if (optimizationOptions.scripts || optimizationOptions.styles.minify) { - estimatedTransferSizes = await calculateEstimatedTransferSizes(executionResult.outputFiles); - } - - // Check metafile for CommonJS module usage if optimizing scripts - if (optimizationOptions.scripts) { - const messages = checkCommonJSModules(metafile, options.allowedCommonJsDependencies); - executionResult.addWarnings(messages); - } + // Calculate estimated transfer size if scripts are optimized + let estimatedTransferSizes; + if (optimizationOptions.scripts || optimizationOptions.styles.minify) { + estimatedTransferSizes = await calculateEstimatedTransferSizes(executionResult.outputFiles); + } - // Copy assets - if (assets) { - executionResult.addAssets(await resolveAssets(assets, workspaceRoot)); - } + // Check metafile for CommonJS module usage if optimizing scripts + if (optimizationOptions.scripts) { + const messages = checkCommonJSModules(metafile, options.allowedCommonJsDependencies); + executionResult.addWarnings(messages); + } - // Extract and write licenses for used packages - if (options.extractLicenses) { - executionResult.addOutputFile( - '3rdpartylicenses.txt', - await extractLicenses(metafile, workspaceRoot), - BuildOutputFileType.Root, - ); - } + // Copy assets + if (assets) { + executionResult.addAssets(await resolveAssets(assets, workspaceRoot)); + } - // Watch input index HTML file if configured - if (options.indexHtmlOptions) { - executionResult.extraWatchFiles.push(options.indexHtmlOptions.input); - executionResult.htmlIndexPath = options.indexHtmlOptions.output; - executionResult.htmlBaseHref = options.baseHref; - } + // Extract and write licenses for used packages + if (options.extractLicenses) { + executionResult.addOutputFile( + '3rdpartylicenses.txt', + await extractLicenses(metafile, workspaceRoot), + BuildOutputFileType.Root, + ); + } - // Create server app engine manifest - if (serverEntryPoint) { - executionResult.addOutputFile( - SERVER_APP_ENGINE_MANIFEST_FILENAME, - generateAngularServerAppEngineManifest(i18nOptions, security.allowedHosts, baseHref), - BuildOutputFileType.ServerRoot, - ); - } + // Watch input index HTML file if configured + if (options.indexHtmlOptions) { + executionResult.extraWatchFiles.push(options.indexHtmlOptions.input); + executionResult.htmlIndexPath = options.indexHtmlOptions.output; + executionResult.htmlBaseHref = options.baseHref; + } - // Perform i18n translation inlining if enabled - if (i18nOptions.shouldInline) { - const result = await inlineI18n(metafile, options, executionResult, initialFiles); - executionResult.addErrors(result.errors); - executionResult.addWarnings(result.warnings); - executionResult.addPrerenderedRoutes(result.prerenderedRoutes); - } else { - const result = await executePostBundleSteps( - metafile, - options, - executionResult.outputFiles, - executionResult.assetFiles, - initialFiles, - // Set lang attribute to the defined source locale if present - i18nOptions.hasDefinedSourceLocale ? i18nOptions.sourceLocale : undefined, - ); + // Create server app engine manifest + if (serverEntryPoint) { + executionResult.addOutputFile( + SERVER_APP_ENGINE_MANIFEST_FILENAME, + generateAngularServerAppEngineManifest(i18nOptions, security.allowedHosts, baseHref), + BuildOutputFileType.ServerRoot, + ); + } - // Deduplicate and add errors and warnings - executionResult.addErrors([...new Set(result.errors)]); - executionResult.addWarnings([...new Set(result.warnings)]); + // Perform i18n translation inlining if enabled + if (i18nOptions.shouldInline) { + const result = await inlineI18n(metafile, options, executionResult, initialFiles); + executionResult.addErrors(result.errors); + executionResult.addWarnings(result.warnings); + executionResult.addPrerenderedRoutes(result.prerenderedRoutes); + } else { + const result = await executePostBundleSteps( + metafile, + options, + executionResult.outputFiles, + executionResult.assetFiles, + initialFiles, + // Set lang attribute to the defined source locale if present + i18nOptions.hasDefinedSourceLocale ? i18nOptions.sourceLocale : undefined, + ); - executionResult.addPrerenderedRoutes(result.prerenderedRoutes); - executionResult.outputFiles.push(...result.additionalOutputFiles); - executionResult.assetFiles.push(...result.additionalAssets); - } + // Deduplicate and add errors and warnings + executionResult.addErrors([...new Set(result.errors)]); + executionResult.addWarnings([...new Set(result.warnings)]); - executionResult.addOutputFile( - 'prerendered-routes.json', - JSON.stringify({ routes: executionResult.prerenderedRoutes }, null, 2), - BuildOutputFileType.Root, - ); + executionResult.addPrerenderedRoutes(result.prerenderedRoutes); + executionResult.outputFiles.push(...result.additionalOutputFiles); + executionResult.assetFiles.push(...result.additionalAssets); + } - // Write metafile if stats option is enabled - if (options.stats) { executionResult.addOutputFile( - 'stats.json', - JSON.stringify(metafile, null, 2), + 'prerendered-routes.json', + JSON.stringify({ routes: executionResult.prerenderedRoutes }, null, 2), BuildOutputFileType.Root, ); - } - if (!jsonLogs && !options.quiet) { - const changedFiles = - rebuildState && executionResult.findChangedFiles(rebuildState.previousOutputInfo); - executionResult.addLog( - logBuildStats( - metafile, - outputFiles, - initialFiles, - budgetFailures, - colors, - changedFiles, - estimatedTransferSizes, - !!ssrOptions, - verbose, - ), - ); - } + // Write metafile if stats option is enabled + if (options.stats) { + executionResult.addOutputFile( + 'stats.json', + JSON.stringify(metafile, null, 2), + BuildOutputFileType.Root, + ); + } + + if (!jsonLogs && !options.quiet) { + const changedFiles = + rebuildState && executionResult.findChangedFiles(rebuildState.previousOutputInfo); + executionResult.addLog( + logBuildStats( + metafile, + outputFiles, + initialFiles, + budgetFailures, + colors, + changedFiles, + estimatedTransferSizes, + !!ssrOptions, + verbose, + ), + ); + } - return executionResult; + return executionResult; + } catch (error) { + await Promise.allSettled([angularCompilationContext?.dispose(), executionResult?.dispose()]); + + throw error; + } } diff --git a/packages/angular/build/src/builders/application/tests/behavior/rebuild-global_styles_spec.ts b/packages/angular/build/src/builders/application/tests/behavior/rebuild-global_styles_spec.ts index 22c4c32202bd..2de5c5f229ca 100644 --- a/packages/angular/build/src/builders/application/tests/behavior/rebuild-global_styles_spec.ts +++ b/packages/angular/build/src/builders/application/tests/behavior/rebuild-global_styles_spec.ts @@ -132,5 +132,119 @@ describeBuilder(buildApplication, APPLICATION_BUILDER_INFO, (harness) => { { outputLogsOnFailure: false }, ); }); + + it('rebuilds PostCSS stylesheet after error on rebuild from plugin dependency', async () => { + harness.useTarget('build', { + ...BASE_OPTIONS, + watch: true, + styles: ['src/styles.css'], + }); + + await harness.writeFile( + 'test-plugin.js', + ` + const fs = require('fs'); + const path = require('path'); + module.exports = () => { + return { + postcssPlugin: 'test-plugin', + Once(root, { result }) { + const themePath = path.join(path.dirname(root.source.input.file), 'theme.json'); + result.messages.push({ + type: 'dependency', + file: themePath, + }); + const data = fs.readFileSync(themePath, 'utf-8'); + const json = JSON.parse(data); + root.append('body { color: ' + json.color + '; }'); + }, + }; + }; + module.exports.postcss = true; + `, + ); + await harness.writeFile( + '.postcssrc.json', + JSON.stringify({ + plugins: { + './test-plugin.js': {}, + }, + }), + ); + await harness.writeFile('src/styles.css', '/* base */'); + await harness.writeFile('src/theme.json', '{"color": "aqua"}'); + + await harness.executeWithCases( + [ + async ({ result }) => { + expect(result?.success).toBe(true); + harness.expectFile('dist/browser/styles.css').content.toContain('color: aqua'); + harness.expectFile('dist/browser/styles.css').content.not.toContain('color: blue'); + + await harness.writeFile('src/theme.json', 'invalid-json'); + }, + async ({ result }) => { + expect(result?.success).toBe(false); + + await harness.writeFile('src/theme.json', '{"color": "blue"}'); + }, + ({ result }) => { + expect(result?.success).toBe(true); + harness.expectFile('dist/browser/styles.css').content.not.toContain('color: aqua'); + harness.expectFile('dist/browser/styles.css').content.toContain('color: blue'); + }, + ], + { outputLogsOnFailure: false }, + ); + }); + + it('rebuilds PostCSS stylesheet after CSS syntax error on initial build from import', async () => { + harness.useTarget('build', { + ...BASE_OPTIONS, + watch: true, + styles: ['src/styles.css'], + }); + + await harness.writeFile( + 'noop-plugin.js', + ` + module.exports = () => ({ postcssPlugin: 'noop-plugin' }); + module.exports.postcss = true; + `, + ); + await harness.writeFile( + '.postcssrc.json', + JSON.stringify({ + plugins: { + './noop-plugin.js': {}, + }, + }), + ); + await harness.writeFile('src/styles.css', "@import './a.css';"); + await harness.writeFile('src/a.css', "a { ' }"); + + await harness.executeWithCases( + [ + async ({ result }) => { + expect(result?.success).toBe(false); + + await harness.writeFile('src/a.css', 'body { color: aqua; }'); + }, + async ({ result }) => { + expect(result?.success).toBe(true); + harness.expectFile('dist/browser/styles.css').content.toContain('color: aqua'); + harness.expectFile('dist/browser/styles.css').content.not.toContain('color: blue'); + + await harness.writeFile('src/a.css', 'body { color: blue; }'); + }, + ({ result }) => { + expect(result?.success).toBe(true); + harness.expectFile('dist/browser/styles.css').content.not.toContain('color: aqua'); + harness.expectFile('dist/browser/styles.css').content.toContain('color: blue'); + }, + ], + { outputLogsOnFailure: false }, + ); + }); }); }); diff --git a/packages/angular/build/src/builders/application/tests/options/extract-licenses_spec.ts b/packages/angular/build/src/builders/application/tests/options/extract-licenses_spec.ts index 402200a27f9d..2c495e703a7b 100644 --- a/packages/angular/build/src/builders/application/tests/options/extract-licenses_spec.ts +++ b/packages/angular/build/src/builders/application/tests/options/extract-licenses_spec.ts @@ -55,5 +55,96 @@ describeBuilder(buildApplication, APPLICATION_BUILDER_INFO, (harness) => { harness.expectFile('dist/3rdpartylicenses.txt').content.toContain('MIT'); harness.expectFile('dist/browser/en-US/main.js').toExist(); }); + + it(`should extract license from a package with a lowercase 'license' file`, async () => { + await harness.writeFile( + 'node_modules/test-package-a/package.json', + JSON.stringify({ + name: 'test-package-a', + version: '1.0.0', + main: 'index.js', + license: 'MIT', + }), + ); + await harness.writeFile( + 'node_modules/test-package-a/index.js', + 'console.log("test-package-a");', + ); + await harness.writeFile('node_modules/test-package-a/license', 'TEST_LOWERCASE_LICENSE_TEXT'); + await harness.appendToFile('src/main.ts', "\nimport 'test-package-a';\n"); + + harness.useTarget('build', { + ...BASE_OPTIONS, + extractLicenses: true, + }); + + const { result } = await harness.executeOnce(); + expect(result?.success).toBeTrue(); + harness + .expectFile('dist/3rdpartylicenses.txt') + .content.toContain('TEST_LOWERCASE_LICENSE_TEXT'); + }); + + it(`should extract license from a package with an alternative license file name (e.g., 'MIT-LICENCE.txt')`, async () => { + await harness.writeFile( + 'node_modules/test-package-b/package.json', + JSON.stringify({ + name: 'test-package-b', + version: '1.0.0', + main: 'index.js', + license: 'MIT', + }), + ); + await harness.writeFile( + 'node_modules/test-package-b/index.js', + 'console.log("test-package-b");', + ); + await harness.writeFile( + 'node_modules/test-package-b/MIT-LICENCE.txt', + 'TEST_ALTERNATIVE_LICENSE_TEXT', + ); + await harness.appendToFile('src/main.ts', "\nimport 'test-package-b';\n"); + + harness.useTarget('build', { + ...BASE_OPTIONS, + extractLicenses: true, + }); + + const { result } = await harness.executeOnce(); + expect(result?.success).toBeTrue(); + harness + .expectFile('dist/3rdpartylicenses.txt') + .content.toContain('TEST_ALTERNATIVE_LICENSE_TEXT'); + }); + + it(`should extract license from a package with a custom license file specified in package.json`, async () => { + await harness.writeFile( + 'node_modules/test-package-c/package.json', + JSON.stringify({ + name: 'test-package-c', + version: '1.0.0', + main: 'index.js', + license: 'SEE LICENSE IN custom-license.md', + }), + ); + await harness.writeFile( + 'node_modules/test-package-c/index.js', + 'console.log("test-package-c");', + ); + await harness.writeFile( + 'node_modules/test-package-c/custom-license.md', + 'TEST_CUSTOM_LICENSE_TEXT', + ); + await harness.appendToFile('src/main.ts', "\nimport 'test-package-c';\n"); + + harness.useTarget('build', { + ...BASE_OPTIONS, + extractLicenses: true, + }); + + const { result } = await harness.executeOnce(); + expect(result?.success).toBeTrue(); + harness.expectFile('dist/3rdpartylicenses.txt').content.toContain('TEST_CUSTOM_LICENSE_TEXT'); + }); }); }); diff --git a/packages/angular/build/src/builders/application/tests/options/index_spec.ts b/packages/angular/build/src/builders/application/tests/options/index_spec.ts index 11228658bbce..b53467caaec6 100644 --- a/packages/angular/build/src/builders/application/tests/options/index_spec.ts +++ b/packages/angular/build/src/builders/application/tests/options/index_spec.ts @@ -79,16 +79,17 @@ describeBuilder(buildApplication, APPLICATION_BUILDER_INFO, (harness) => { harness.expectFile('dist/browser/index.html').content.toContain('TEST_123'); }); - // TODO: Build needs to be fixed to not throw an unhandled exception for this case - xit('should fail build when a string path to non-existent file', async () => { + it('should fail build and terminate cleanly when a string path to non-existent file is provided', async () => { harness.useTarget('build', { ...BASE_OPTIONS, index: 'src/not-here.html', }); - const { result } = await harness.executeOnce({ outputLogsOnFailure: false }); + const { result, error } = await harness.executeOnce({ outputLogsOnException: false }); - expect(result?.success).toBe(false); + expect(result).toBeUndefined(); + expect(error).toEqual(jasmine.any(Error)); + expect(error?.message).toMatch(/Failed to read index HTML file/i); harness.expectFile('dist/browser/index.html').toNotExist(); }); diff --git a/packages/angular/build/src/tools/esbuild/angular/compilation-state.ts b/packages/angular/build/src/tools/esbuild/angular/compilation-state.ts index 79fb9715bdbd..286411a06057 100644 --- a/packages/angular/build/src/tools/esbuild/angular/compilation-state.ts +++ b/packages/angular/build/src/tools/esbuild/angular/compilation-state.ts @@ -46,13 +46,14 @@ export class AngularCompilationContext { this.#pendingCompilation = true; } - #disposed = false; + #disposal: Promise | undefined; - async dispose(): Promise { - if (this.#disposed) { - return; - } - this.#disposed = true; + dispose(): Promise { + // Reuse any in progress disposal to ensure all callers can await completion + return (this.#disposal ??= this.#close()); + } + + async #close(): Promise { this.markAsReady(true); try { await this.#compilation.close?.(); diff --git a/packages/angular/build/src/tools/esbuild/angular/source-file-cache.ts b/packages/angular/build/src/tools/esbuild/angular/source-file-cache.ts index 2bc38bd12a89..a408650a4f4f 100644 --- a/packages/angular/build/src/tools/esbuild/angular/source-file-cache.ts +++ b/packages/angular/build/src/tools/esbuild/angular/source-file-cache.ts @@ -25,6 +25,19 @@ export class SourceFileCache extends Map { super(); } + /** + * Releases all cached content. The cached data is only needed for incremental + * rebuilds and can include the emitted contents of every TypeScript file in the + * program. The cache is repopulated if a build is performed after this is called. + */ + override clear(): void { + super.clear(); + this.modifiedFiles.clear(); + this.typeScriptFileCache.clear(); + this.loadResultCache.clear(); + this.referencedFiles = undefined; + } + invalidate(files: Iterable): boolean { if (files !== this.modifiedFiles) { this.modifiedFiles.clear(); diff --git a/packages/angular/build/src/tools/esbuild/bundler-execution-result.ts b/packages/angular/build/src/tools/esbuild/bundler-execution-result.ts index bebfd6a3eedd..53e17e7e427c 100644 --- a/packages/angular/build/src/tools/esbuild/bundler-execution-result.ts +++ b/packages/angular/build/src/tools/esbuild/bundler-execution-result.ts @@ -194,11 +194,21 @@ export class ExecutionResult { return changed; } - async dispose(): Promise { - await Promise.allSettled([ - ...this.rebuildContexts.typescriptContexts.map((context) => context.dispose()), - ...this.rebuildContexts.otherContexts.map((context) => context.dispose()), - this.componentStyleBundler.dispose(), - ]); + #disposal?: Promise; + + dispose(): Promise { + return (this.#disposal ??= this.#dispose()); + } + + async #dispose(): Promise { + try { + await Promise.allSettled([ + ...this.rebuildContexts.typescriptContexts.map((context) => context.dispose()), + ...this.rebuildContexts.otherContexts.map((context) => context.dispose()), + this.componentStyleBundler.dispose(), + ]); + } finally { + this.codeBundleCache?.clear(); + } } } diff --git a/packages/angular/build/src/tools/esbuild/i18n-inliner.ts b/packages/angular/build/src/tools/esbuild/i18n-inliner.ts index af13226a68d4..a6d4b5aeccbb 100644 --- a/packages/angular/build/src/tools/esbuild/i18n-inliner.ts +++ b/packages/angular/build/src/tools/esbuild/i18n-inliner.ts @@ -252,8 +252,8 @@ export class I18nInliner { * Stops all active transformation tasks and shuts down all workers. * @returns A void promise that resolves when closing is complete. */ - close(): Promise { - return this.#workerPool.destroy(); + async close(): Promise { + await Promise.allSettled([this.#cache?.close(), this.#workerPool.destroy()]); } /** diff --git a/packages/angular/build/src/tools/esbuild/license-extractor.ts b/packages/angular/build/src/tools/esbuild/license-extractor.ts index 6629bbc387bf..890ebdd9826f 100644 --- a/packages/angular/build/src/tools/esbuild/license-extractor.ts +++ b/packages/angular/build/src/tools/esbuild/license-extractor.ts @@ -7,7 +7,7 @@ */ import type { Metafile } from 'esbuild'; -import { readFile } from 'node:fs/promises'; +import { readFile, readdir } from 'node:fs/promises'; import path from 'node:path'; /** @@ -30,9 +30,9 @@ const NODE_MODULE_SEGMENT = 'node_modules'; const CUSTOM_LICENSE_TEXT = 'SEE LICENSE IN '; /** - * A list of commonly named license files found within packages. + * A regular expression for commonly named license files found within packages. */ -const LICENSE_FILES = ['LICENSE', 'LICENSE.txt', 'LICENSE.md']; +const LICENSE_FILE_REGEXP = /^(?:mit-)?licen[cs]e(?:$|[-._])/i; /** * Header text that will be added to the top of the output license extraction file. @@ -64,6 +64,7 @@ export async function extractLicenses(metafile: Metafile, rootDirectory: string) let extractedLicenseContent = `${EXTRACTION_FILE_HEADER}\n${EXTRACTION_FILE_SEPARATOR}`; const seenPaths = new Set(); + const seenPackageDirectories = new Set(); const seenPackages = new Set(); for (const entry of Object.values(metafile.outputs)) { @@ -110,6 +111,11 @@ export async function extractLicenses(metafile: Metafile, rootDirectory: string) : nameOrScope; const packageDirectory = path.join(baseDirectory, packageName); + if (seenPackageDirectories.has(packageDirectory)) { + continue; + } + seenPackageDirectories.add(packageDirectory); + // Load the package's metadata to find the package's name, version, and license type const packageJsonPath = path.join(packageDirectory, 'package.json'); let packageJson; @@ -136,12 +142,12 @@ export async function extractLicenses(metafile: Metafile, rootDirectory: string) let licenseText = ''; if ( typeof packageJson.license === 'string' && - packageJson.license.toLowerCase().startsWith(CUSTOM_LICENSE_TEXT) + packageJson.license.toUpperCase().startsWith(CUSTOM_LICENSE_TEXT) ) { // Attempt to load the package's custom license let customLicensePath; const customLicenseFile = path.normalize( - packageJson.license.slice(CUSTOM_LICENSE_TEXT.length + 1).trim(), + packageJson.license.slice(CUSTOM_LICENSE_TEXT.length).trim(), ); if (customLicenseFile.startsWith('..') || path.isAbsolute(customLicenseFile)) { // Path is attempting to access files outside of the package @@ -150,17 +156,20 @@ export async function extractLicenses(metafile: Metafile, rootDirectory: string) customLicensePath = path.join(packageDirectory, customLicenseFile); try { licenseText = await readFile(customLicensePath, 'utf-8'); - break; } catch {} } } else { // Search for a license file within the root of the package - for (const potentialLicense of LICENSE_FILES) { - const packageLicensePath = path.join(packageDirectory, potentialLicense); - try { - licenseText = await readFile(packageLicensePath, 'utf-8'); - break; - } catch {} + const entries = await readdir(packageDirectory, { withFileTypes: true }).catch(() => []); + + for (const entry of entries) { + if ((entry.isFile() || entry.isSymbolicLink()) && LICENSE_FILE_REGEXP.test(entry.name)) { + const packageLicensePath = path.join(packageDirectory, entry.name); + try { + licenseText = await readFile(packageLicensePath, 'utf-8'); + break; + } catch {} + } } } diff --git a/packages/angular/build/src/tools/esbuild/load-result-cache.ts b/packages/angular/build/src/tools/esbuild/load-result-cache.ts index 30067486a384..40936c6a87d1 100644 --- a/packages/angular/build/src/tools/esbuild/load-result-cache.ts +++ b/packages/angular/build/src/tools/esbuild/load-result-cache.ts @@ -48,12 +48,26 @@ export function createCachedLoad( export class MemoryLoadResultCache implements LoadResultCache { #loadResults = new Map(); #fileDependencies = new Map>(); + #watchFilesPerKey = new Map>(); get(path: string): OnLoadResult | undefined { return this.#loadResults.get(path); } async put(path: string, result: OnLoadResult): Promise { + if (result.errors && result.errors.length > 0) { + const previousWatchFiles = this.#watchFilesPerKey.get(path); + if (previousWatchFiles) { + result.watchFiles = Array.from( + new Set([...(result.watchFiles ?? []), ...previousWatchFiles]), + ); + } + } else if (result.watchFiles && result.watchFiles.length > 0) { + this.#watchFilesPerKey.set(path, [...result.watchFiles]); + } else { + this.#watchFilesPerKey.delete(path); + } + this.#loadResults.set(path, result); if (result.watchFiles) { for (const watchFile of result.watchFiles) { @@ -90,4 +104,10 @@ export class MemoryLoadResultCache implements LoadResultCache { // are namespaced request paths and not disk-based file paths. return [...this.#fileDependencies.keys()]; } + + clear(): void { + this.#loadResults.clear(); + this.#fileDependencies.clear(); + this.#watchFilesPerKey.clear(); + } } diff --git a/packages/angular/build/src/tools/esbuild/load-result-cache_spec.ts b/packages/angular/build/src/tools/esbuild/load-result-cache_spec.ts new file mode 100644 index 000000000000..fb0396aea829 --- /dev/null +++ b/packages/angular/build/src/tools/esbuild/load-result-cache_spec.ts @@ -0,0 +1,85 @@ +/** + * @license + * Copyright Google LLC All Rights Reserved. + * + * Use of this source code is governed by an MIT-style license that can be + * found in the LICENSE file at https://angular.dev/license + */ + +import { MemoryLoadResultCache } from './load-result-cache'; + +describe('MemoryLoadResultCache', () => { + let cache: MemoryLoadResultCache; + + beforeEach(() => { + cache = new MemoryLoadResultCache(); + }); + + it('should store and retrieve results', async () => { + const result = { + contents: 'body { color: red; }', + loader: 'css' as const, + }; + + await cache.put('file:/test/styles.css', result); + const cached = cache.get('file:/test/styles.css'); + + expect(cached).toBe(result); + }); + + it('should track watch files in fileDependencies', async () => { + const result = { + contents: 'body { color: red; }', + loader: 'css' as const, + watchFiles: ['/test/styles.css', '/test/theme.json'], + }; + + await cache.put('file:/test/styles.css', result); + + expect(cache.watchFiles).toContain('/test/styles.css'); + expect(cache.watchFiles).toContain('/test/theme.json'); + }); + + it('should invalidate cached results when a dependency changes', async () => { + const result = { + contents: 'body { color: red; }', + loader: 'css' as const, + watchFiles: ['/test/styles.css', '/test/theme.json'], + }; + + await cache.put('file:/test/styles.css', result); + expect(cache.get('file:/test/styles.css')).toBe(result); + + const invalidated = cache.invalidate('/test/theme.json'); + expect(invalidated).toBeTrue(); + expect(cache.get('file:/test/styles.css')).toBeUndefined(); + }); + + it('should preserve previous watch files when caching an error result', async () => { + const successResult = { + contents: 'body { color: red; }', + loader: 'css' as const, + watchFiles: ['/test/styles.css', '/test/theme.json'], + }; + + await cache.put('file:/test/styles.css', successResult); + cache.invalidate('/test/theme.json'); + + // Simulate an incremental rebuild error result that only has the entry file in watchFiles + const errorResult = { + errors: [{ text: 'Syntax error in theme.json' }], + watchFiles: ['/test/styles.css'], + }; + + await cache.put('file:/test/styles.css', errorResult); + + // Both the entry file and the previous dependency should be tracked + expect(cache.watchFiles).toContain('/test/styles.css'); + expect(cache.watchFiles).toContain('/test/theme.json'); + + // Invalidating the dependency should clear the cached error result + const invalidated = cache.invalidate('/test/theme.json'); + expect(invalidated).toBeTrue(); + expect(cache.get('file:/test/styles.css')).toBeUndefined(); + }); +}); diff --git a/packages/angular/build/src/tools/esbuild/stylesheets/stylesheet-plugin-factory.ts b/packages/angular/build/src/tools/esbuild/stylesheets/stylesheet-plugin-factory.ts index 78925f35835e..2c40e007350e 100644 --- a/packages/angular/build/src/tools/esbuild/stylesheets/stylesheet-plugin-factory.ts +++ b/packages/angular/build/src/tools/esbuild/stylesheets/stylesheet-plugin-factory.ts @@ -427,6 +427,7 @@ async function compileString( }, }, ], + watchFiles: error.file && error.file !== filename ? [filename, error.file] : [filename], }; } else { assertIsError(error); diff --git a/packages/angular/cli/lib/init.ts b/packages/angular/cli/lib/init.ts index cd324b6df69b..ab6e9cf48589 100644 --- a/packages/angular/cli/lib/init.ts +++ b/packages/angular/cli/lib/init.ts @@ -24,6 +24,23 @@ import { VERSION } from '../src/utilities/version'; let forceExit = false; (async (): Promise => { + /** + * On Windows, ensure process.cwd() uses uppercase drive letter casing. + * Windows cmd.exe and VS Code terminals often preserve lowercase drive letters (e.g. c:\...), + * which causes ESM module duplication in Node.js (e.g. loading "vitest" twice) and path + * lookup mismatches in tools like Vite and esbuild. + */ + if (process.platform === 'win32') { + const cwd = process.cwd(); + if (/^[a-z]:/.test(cwd)) { + try { + process.chdir(cwd[0].toUpperCase() + cwd.slice(1)); + } catch { + // Ignore failure to change directory + } + } + } + /** * Disable Browserslist old data warning as otherwise with every release we'd need to update this dependency * which is cumbersome considering we pin versions and the warning is not user actionable. diff --git a/packages/angular/cli/src/commands/add/cli.ts b/packages/angular/cli/src/commands/add/cli.ts index 511223eb53b5..bc95f33ff8e7 100644 --- a/packages/angular/cli/src/commands/add/cli.ts +++ b/packages/angular/cli/src/commands/add/cli.ts @@ -224,29 +224,12 @@ export default class AddCommandModule { title: 'Confirming installation', enabled: !skipConfirmation && !options.dryRun, - skip: (context) => { - if (context.hasSchematics) { - return false; - } - - return `The ${color.blue(context.packageIdentifier.toString())} package does not provide \`ng add\` actions.`; - }, task: (context, task) => this.confirmInstallationTask(context, task), rendererOptions: { persistentOutput: true }, }, { title: 'Installing package', skip: (context) => { - if (!context.hasSchematics) { - const builtInSchematic = - BUILT_IN_SCHEMATICS[ - context.packageIdentifier.name as keyof typeof BUILT_IN_SCHEMATICS - ]; - if (builtInSchematic) { - return `Skipping package installation.`; - } - } - if (context.dryRun) { return `Skipping package installation. Would install package ${color.blue( context.packageIdentifier.toString(), @@ -278,6 +261,9 @@ export default class AddCommandModule if (localManifest['ng-add']?.save === false) { shouldCleanUp = true; } + } else { + await this.cleanUpTemporaryDependency(result.collectionName); + shouldCleanUp = false; } } catch {} } @@ -305,6 +291,9 @@ export default class AddCommandModule const builtInSchematic = BUILT_IN_SCHEMATICS[packageName as keyof typeof BUILT_IN_SCHEMATICS]; if (builtInSchematic) { + logger.info( + `The ${color.blue(packageName)} package does not provide \`ng add\` actions.`, + ); logger.info('The Angular CLI will use built-in actions to add it to your project.'); return this.executeSchematic({ diff --git a/packages/angular/cli/src/commands/update/cli.ts b/packages/angular/cli/src/commands/update/cli.ts index b886c287f2ec..005df998b501 100644 --- a/packages/angular/cli/src/commands/update/cli.ts +++ b/packages/angular/cli/src/commands/update/cli.ts @@ -634,7 +634,7 @@ export default class UpdateCommandModule extends CommandModule/package.json` after installation, + * we ensure that any migration collections defined by the package are discovered and queued. + */ +export async function resolveFallbackMigrations( + workspaceRoot: string, + plan: UpdatePlan, +): Promise<{ package: string; collection: string; from: string; to: string }[]> { + const migrations = [...plan.migrationsToRun]; + const existingMigrationPackages = new Set(migrations.map((m) => m.package)); + + for (const [packageName, targetVersion] of plan.packagesToUpdate) { + if (existingMigrationPackages.has(packageName)) { + continue; + } + + const packageJsonPath = findPackageJson(workspaceRoot, packageName); + if (packageJsonPath) { + try { + const packageJson = JSON.parse(await fs.readFile(packageJsonPath, 'utf8')); + const ngUpdate = packageJson?.['ng-update']; + if (ngUpdate && typeof ngUpdate === 'object' && typeof ngUpdate.migrations === 'string') { + const installedVersion = plan.packageInfoMap.get(packageName)?.installed.version; + if (installedVersion) { + migrations.push({ + package: packageName, + collection: ngUpdate.migrations, + from: installedVersion, + to: targetVersion, + }); + } + } + } catch { + // Ignore read/parse errors for optional fallback + } + } + } + + return migrations; +} diff --git a/packages/angular/cli/src/commands/update/cli_spec.ts b/packages/angular/cli/src/commands/update/cli_spec.ts new file mode 100644 index 000000000000..bae00d3dba24 --- /dev/null +++ b/packages/angular/cli/src/commands/update/cli_spec.ts @@ -0,0 +1,133 @@ +/** + * @license + * Copyright Google LLC All Rights Reserved. + * + * Use of this source code is governed by an MIT-style license that can be + * found in the LICENSE file at https://angular.dev/license + */ + +import assert from 'node:assert'; +import { mkdir, mkdtemp, rm, writeFile } from 'node:fs/promises'; +import path from 'path'; +import { resolveFallbackMigrations } from './cli'; +import type { PackageVersionInfo, UpdatePlan } from './update-resolver'; + +describe('resolveFallbackMigrations', () => { + let tempRoot: string; + let pkgDir: string; + beforeEach(async () => { + const baseTmpDir = process.env['TEST_TMPDIR']; + assert(baseTmpDir, 'TEST_TMPDIR is not set'); + tempRoot = await mkdtemp(path.join(baseTmpDir, 'angular-cli-update-cli-test-')); + pkgDir = path.join(tempRoot, 'node_modules/@company/library-name'); + await mkdir(pkgDir, { recursive: true }); + }); + + afterEach(async () => { + await rm(tempRoot, { recursive: true, force: true }); + }); + + it('discovers migrations from installed package.json when omitted from plan.migrationsToRun', async () => { + await writeFile( + path.join(pkgDir, 'package.json'), + JSON.stringify({ + name: '@company/library-name', + version: '21.2.0-next.1', + 'ng-update': { + migrations: './schematics/migration.json', + }, + }), + 'utf8', + ); + + const plan: UpdatePlan = { + packagesToUpdate: new Map([['@company/library-name', '21.2.0-next.1']]), + migrationsToRun: [], + packageInfoMap: new Map([ + [ + '@company/library-name', + { + name: '@company/library-name', + npmPackageJson: { + name: '@company/library-name', + versions: ['21.1.0', '21.2.0-next.1'], + 'dist-tags': {}, + }, + installed: { + version: '21.1.0' as unknown as PackageVersionInfo['version'], + packageJson: { name: '@company/library-name', version: '21.1.0' }, + updateMetadata: { packageGroup: {}, requirements: {} }, + }, + packageJsonRange: '^21.1.0', + }, + ], + ]), + registryClient: undefined as unknown as UpdatePlan['registryClient'], + }; + + const migrations = await resolveFallbackMigrations(tempRoot, plan); + + expect(migrations).toEqual([ + { + package: '@company/library-name', + collection: './schematics/migration.json', + from: '21.1.0', + to: '21.2.0-next.1', + }, + ]); + }); + + it('does not duplicate migration if package is already in plan.migrationsToRun', async () => { + await writeFile( + path.join(pkgDir, 'package.json'), + JSON.stringify({ + name: '@company/library-name', + version: '21.2.0-next.1', + 'ng-update': { + migrations: './schematics/migration.json', + }, + }), + 'utf8', + ); + + const plan: UpdatePlan = { + packagesToUpdate: new Map([['@company/library-name', '21.2.0-next.1']]), + migrationsToRun: [ + { + package: '@company/library-name', + collection: './schematics/migration.json', + from: '21.1.0', + to: '21.2.0-next.1', + }, + ], + packageInfoMap: new Map(), + registryClient: undefined as unknown as UpdatePlan['registryClient'], + }; + + const migrations = await resolveFallbackMigrations(tempRoot, plan); + + expect(migrations).toHaveSize(1); + }); + + it('returns unchanged migrations when package has no ng-update field on disk', async () => { + await writeFile( + path.join(pkgDir, 'package.json'), + JSON.stringify({ + name: '@company/library-name', + version: '21.2.0-next.1', + }), + 'utf8', + ); + + const plan: UpdatePlan = { + packagesToUpdate: new Map([['@company/library-name', '21.2.0-next.1']]), + migrationsToRun: [], + packageInfoMap: new Map(), + registryClient: undefined as unknown as UpdatePlan['registryClient'], + }; + + const migrations = await resolveFallbackMigrations(tempRoot, plan); + + expect(migrations).toHaveSize(0); + }); +}); diff --git a/packages/angular/cli/src/commands/update/update-resolver.ts b/packages/angular/cli/src/commands/update/update-resolver.ts index 7b75ab7a9e20..995762d92bc9 100644 --- a/packages/angular/cli/src/commands/update/update-resolver.ts +++ b/packages/angular/cli/src/commands/update/update-resolver.ts @@ -942,11 +942,7 @@ export async function resolveUserUpdatePlan( }; if (packages.size === 0) { - await Promise.all( - Array.from(npmDeps.keys()).map(async (depName) => { - await getOrFetchPackageMetadata(depName); - }), - ); + await Promise.all(Array.from(npmDeps.keys(), (depName) => getOrFetchPackageMetadata(depName))); } else { let lastPackagesSize; do { @@ -999,12 +995,13 @@ export async function resolveUserUpdatePlan( } while (packages.size > lastPackagesSize); } + const isListingUpdates = packages.size === 0; const packageInfoEntries = await Promise.all( Array.from(npmDeps.keys(), async (depName) => { const isUpdating = packages.has(depName); const localPkgJson = getInstalledPackageJson(depName, workspaceRoot); - if (isUpdating || !localPkgJson) { + if (isListingUpdates || isUpdating || !localPkgJson) { const metadata = await getOrFetchPackageMetadata(depName); if (metadata) { const info = await _buildPackageInfo( diff --git a/packages/angular/cli/src/commands/update/update-resolver_spec.ts b/packages/angular/cli/src/commands/update/update-resolver_spec.ts index e18cba641016..9ced5829587e 100644 --- a/packages/angular/cli/src/commands/update/update-resolver_spec.ts +++ b/packages/angular/cli/src/commands/update/update-resolver_spec.ts @@ -289,6 +289,29 @@ describe('UpdateResolver', () => { expect(plan.packagesToUpdate.size).toBe(0); }); + it('includes registry metadata when listing updates with locked dependency versions in package.json', async () => { + createMockWorkspace( + { + name: 'blah', + dependencies: { + '@angular-devkit-tests/update-base': '1.0.0', + }, + }, + { + '@angular-devkit-tests/update-base': { version: '1.0.0' }, + }, + ); + + const plan = await resolvePlan({ + packages: [], + workspaceRoot: tempRoot, + }); + + const info = plan.packageInfoMap.get('@angular-devkit-tests/update-base'); + expect(info?.npmPackageJson['dist-tags']?.['latest']).toBe('1.1.0'); + expect(info?.npmPackageJson.versions).toContain('1.1.0'); + }); + it('should not error with yarn 2.0 protocols', async () => { createMockWorkspace( { diff --git a/packages/angular/cli/src/commands/update/utilities/git.ts b/packages/angular/cli/src/commands/update/utilities/git.ts index 0998c9c61fff..1714846117d9 100644 --- a/packages/angular/cli/src/commands/update/utilities/git.ts +++ b/packages/angular/cli/src/commands/update/utilities/git.ts @@ -60,7 +60,7 @@ export function checkCleanGit(root: string): boolean { return false; } } - } catch {} // eslint-disable-line no-empty + } catch {} return true; } diff --git a/packages/angular/ssr/node/src/response.ts b/packages/angular/ssr/node/src/response.ts index 56f091deed5f..90ed5bb31a67 100644 --- a/packages/angular/ssr/node/src/response.ts +++ b/packages/angular/ssr/node/src/response.ts @@ -9,6 +9,24 @@ import type { ServerResponse } from 'node:http'; import type { Http2ServerResponse } from 'node:http2'; +/** + * Checks whether a Node.js `ServerResponse` or `Http2ServerResponse` is destroyed, closed, or ended. + * + * @param destination - The HTTP/1.1 or HTTP/2 server response to check. + * @returns `true` if the response or its underlying stream is destroyed, closed, or ended; otherwise `false`. + */ +function isResponseDestroyedOrClosed(destination: ServerResponse | Http2ServerResponse): boolean { + return ( + Boolean(destination.destroyed) || + Boolean(destination.closed) || + Boolean(destination.writableEnded) || + ('stream' in destination && + (!destination.stream || + Boolean(destination.stream.destroyed) || + Boolean(destination.stream.closed))) + ); +} + /** * Streams a web-standard `Response` into a Node.js `ServerResponse` * or `Http2ServerResponse`. @@ -24,6 +42,10 @@ export async function writeResponseToNodeResponse( source: Response, destination: ServerResponse | Http2ServerResponse, ): Promise { + if (isResponseDestroyedOrClosed(destination)) { + return; + } + const { status, headers, body } = source; destination.statusCode = status; @@ -48,27 +70,52 @@ export async function writeResponseToNodeResponse( } if (!body) { - destination.end(); + if (!isResponseDestroyedOrClosed(destination)) { + destination.end(); + } return; } - try { - const reader = body.getReader(); - - destination.on('close', () => { - reader.cancel().catch((error) => { - // eslint-disable-next-line no-console - console.error( - `An error occurred while writing the response body for: ${destination.req.url}.`, - error, - ); - }); + let isClosed = isResponseDestroyedOrClosed(destination); + const isDestroyedOrClosed = () => isClosed || isResponseDestroyedOrClosed(destination); + + let readerCancelled = false; + const reader = body.getReader(); + const cancelReader = (error?: unknown) => { + if (readerCancelled) { + return; + } + readerCancelled = true; + isClosed = true; + destination.off('close', cancelReader); + destination.off('error', cancelReader); + reader.cancel(error).catch((err) => { + // eslint-disable-next-line no-console + console.error( + `An error occurred while writing the response body for: ${destination.req.url}.`, + err, + ); }); + }; + + destination.once('close', cancelReader); + destination.once('error', cancelReader); + try { // eslint-disable-next-line no-constant-condition while (true) { + if (isDestroyedOrClosed()) { + cancelReader(); + break; + } + const { done, value } = await reader.read(); + if (isDestroyedOrClosed()) { + cancelReader(); + break; + } + if (done) { destination.end(); break; @@ -78,10 +125,39 @@ export async function writeResponseToNodeResponse( if (canContinue === false) { // Explicitly check for `false`, as AWS may return `undefined` even though this is not valid. // See: https://github.com/CodeGenieApp/serverless-express/issues/683 - await new Promise((resolve) => destination.once('drain', resolve)); + await new Promise((resolve) => { + if (isDestroyedOrClosed()) { + resolve(); + + return; + } + + const onDrain = () => { + destination.off('close', onClose); + destination.off('error', onClose); + resolve(); + }; + + const onClose = () => { + destination.off('drain', onDrain); + destination.off('close', onClose); + destination.off('error', onClose); + cancelReader(); + resolve(); + }; + + destination.once('drain', onDrain); + destination.once('close', onClose); + destination.once('error', onClose); + }); } } } catch { - destination.end('Internal server error.'); + if (!isDestroyedOrClosed()) { + destination.end('Internal server error.'); + } + } finally { + destination.off('close', cancelReader); + destination.off('error', cancelReader); } } diff --git a/packages/angular/ssr/node/test/response_http1_spec.ts b/packages/angular/ssr/node/test/response_http1_spec.ts index 8deae2b7e3b4..c7648f03a627 100644 --- a/packages/angular/ssr/node/test/response_http1_spec.ts +++ b/packages/angular/ssr/node/test/response_http1_spec.ts @@ -107,4 +107,48 @@ describe('writeResponseToNodeResponse (HTTP/1.1)', () => { expect(response.headers['set-cookie']).toEqual(cookieValue); }); + + it('should resolve and cancel reader when client disconnects while response is backpressured', async () => { + let writePromise!: Promise; + let readerCancelled = false; + const largeChunk = 'x'.repeat(1024 * 1024 * 4); // 4MB to ensure backpressure + const stream = new ReadableStream({ + start(controller) { + controller.enqueue(largeChunk); + controller.enqueue(largeChunk); + }, + cancel() { + readerCancelled = true; + }, + }); + + server.once('request', (_, nodeResponse) => { + writePromise = writeResponseToNodeResponse(new Response(stream), nodeResponse); + }); + + await new Promise((resolve) => { + const { port } = server.address() as AddressInfo; + const clientRequest = requestCb( + { + host: 'localhost', + port, + }, + (response) => { + response.once('data', () => { + clientRequest.destroy(); + resolve(); + }); + }, + ); + + clientRequest.on('error', () => { + // Expected when destroying the socket + }); + + clientRequest.end(); + }); + + await writePromise; + expect(readerCancelled).toBeTrue(); + }); }); diff --git a/packages/angular/ssr/node/test/response_http2_spec.ts b/packages/angular/ssr/node/test/response_http2_spec.ts index c2de8e977561..431bc9de0c38 100644 --- a/packages/angular/ssr/node/test/response_http2_spec.ts +++ b/packages/angular/ssr/node/test/response_http2_spec.ts @@ -116,4 +116,48 @@ describe('writeResponseToNodeResponse (HTTP/2)', () => { expect(resHeaders['set-cookie']).toEqual(cookieValue); }); + + it('should resolve and cancel reader when client disconnects while response is backpressured', async () => { + let writePromise!: Promise; + let readerCancelled = false; + const largeChunk = 'x'.repeat(1024 * 1024); // 1MB to exceed HTTP/2 flow control window + const stream = new ReadableStream({ + start(controller) { + controller.enqueue(largeChunk); + controller.enqueue(largeChunk); + }, + cancel() { + readerCancelled = true; + }, + }); + + server.once('request', (_, nodeResponse) => { + writePromise = writeResponseToNodeResponse(new Response(stream), nodeResponse); + }); + + await new Promise((resolve) => { + const { port } = server.address() as AddressInfo; + const client = connect(`http://localhost:${port}`); + const req = client.request({ + ':path': '/', + }); + + req.once('response', () => { + req.once('data', () => { + req.destroy(); + client.destroy(); + resolve(); + }); + }); + + req.on('error', () => { + // Expected when destroying/closing the stream + }); + + req.end(); + }); + + await writePromise; + expect(readerCancelled).toBeTrue(); + }); }); diff --git a/packages/angular/ssr/src/utils/validation.ts b/packages/angular/ssr/src/utils/validation.ts index 714042b52f76..73e6c712d80b 100644 --- a/packages/angular/ssr/src/utils/validation.ts +++ b/packages/angular/ssr/src/utils/validation.ts @@ -88,7 +88,7 @@ export function validateUrl(url: URL, allowedHosts: ReadonlySet): void { /** * Sanitizes the proxy headers of a request by removing unallowed `X-Forwarded-*` headers. - * If no headers need to be removed, the original request is returned without cloning. + * If no headers need to be removed, the original request is returned unchanged. * * @param request - The incoming `Request` object to sanitize. * @param trustProxyHeaders - A set of allowed proxy headers. @@ -117,8 +117,7 @@ export function sanitizeRequestHeaders( } return headersDeleted - ? new Request(request.clone(), { - signal: request.signal, + ? new Request(request, { headers, }) : request; diff --git a/packages/angular/ssr/test/utils/validation_spec.ts b/packages/angular/ssr/test/utils/validation_spec.ts index 0f44f8067aeb..c9986a9bd73a 100644 --- a/packages/angular/ssr/test/utils/validation_spec.ts +++ b/packages/angular/ssr/test/utils/validation_spec.ts @@ -493,5 +493,40 @@ describe('Validation Utils', () => { expect(secured.headers.get('host')).toBe('example.com'); expect(secured.headers.get('forwarded')).toBe('host=proxy.com;proto=https'); }); + + it('should transfer request body without teeing when removing unallowed headers', async () => { + const req = new Request('http://example.com', { + method: 'POST', + body: 'test body', + headers: { + 'host': 'example.com', + 'x-forwarded-host': 'evil.com', + }, + }); + + const secured = sanitizeRequestHeaders(req, normalizeTrustProxyHeaders(undefined)); + + // In the Fetch specification, calling `request.clone()` tees the body stream and leaves + // `req.bodyUsed` as `false`. Passing `req` directly to `new Request(req, ...)` transfers the + // underlying stream without teeing, immediately marking `req.bodyUsed` as `true`. + expect(req.bodyUsed).toBeTrue(); + expect(await secured.text()).toBe('test body'); + }); + + it('should preserve abort signal when removing unallowed headers', () => { + const controller = new AbortController(); + const req = new Request('http://example.com', { + signal: controller.signal, + headers: { + 'host': 'example.com', + 'x-forwarded-host': 'evil.com', + }, + }); + + const secured = sanitizeRequestHeaders(req, normalizeTrustProxyHeaders(undefined)); + + controller.abort(); + expect(secured.signal.aborted).toBeTrue(); + }); }); }); diff --git a/packages/angular_devkit/build_angular/package.json b/packages/angular_devkit/build_angular/package.json index 0025109eb774..d1acd78d2b22 100644 --- a/packages/angular_devkit/build_angular/package.json +++ b/packages/angular_devkit/build_angular/package.json @@ -42,7 +42,7 @@ "ora": "9.4.1", "picomatch": "4.0.5", "piscina": "5.2.0", - "postcss": "8.5.19", + "postcss": "8.5.25", "postcss-loader": "8.2.1", "resolve-url-loader": "5.0.0", "rxjs": "7.8.2", @@ -66,7 +66,7 @@ "devDependencies": { "@angular/ssr": "workspace:*", "browser-sync": "3.0.4", - "ng-packagr": "22.1.0", + "ng-packagr": "22.1.1", "undici": "8.7.0" }, "peerDependencies": { diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 20c29ebd3d56..396f45c57d26 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -50,8 +50,8 @@ importers: specifier: 22.1.0 version: 22.1.0(1d5b48d6601505eec7b597e3914980b4) '@angular/ng-dev': - specifier: https://github.com/angular/dev-infra-private-ng-dev-builds.git#2af985ddb942b5928dfb730a6b8efaccd1798846 - version: https://codeload.github.com/angular/dev-infra-private-ng-dev-builds/tar.gz/2af985ddb942b5928dfb730a6b8efaccd1798846(@modelcontextprotocol/sdk@1.29.0(supports-color@11.0.0)(zod@4.4.3)) + specifier: https://github.com/angular/dev-infra-private-ng-dev-builds.git#dcf9b6776377d5d301e054111add3ef80f433b70 + version: https://codeload.github.com/angular/dev-infra-private-ng-dev-builds/tar.gz/dcf9b6776377d5d301e054111add3ef80f433b70(@modelcontextprotocol/sdk@1.29.0(supports-color@11.0.0)(zod@4.4.3)) '@angular/platform-browser': specifier: 22.1.0 version: 22.1.0(@angular/animations@22.1.0(@angular/core@22.1.0(@angular/compiler@22.1.0)(rxjs@7.8.2)(zone.js@0.16.2)))(@angular/common@22.1.0(@angular/core@22.1.0(@angular/compiler@22.1.0)(rxjs@7.8.2)(zone.js@0.16.2))(rxjs@7.8.2))(@angular/core@22.1.0(@angular/compiler@22.1.0)(rxjs@7.8.2)(zone.js@0.16.2)) @@ -138,7 +138,7 @@ importers: version: 3.0.0(esbuild@0.28.1) '@types/lodash': specifier: ^4.17.0 - version: 4.17.24 + version: 4.17.25 '@types/node': specifier: ^22.12.0 version: 22.20.1 @@ -153,7 +153,7 @@ importers: version: 2.0.7 '@types/semver': specifier: ^7.3.12 - version: 7.7.1 + version: 7.8.0 '@types/watchpack': specifier: ^2.4.4 version: 2.4.5 @@ -285,7 +285,7 @@ importers: version: 6.8.0(encoding@0.1.13)(supports-color@11.0.0) verdaccio-auth-memory: specifier: ^13.0.0 - version: 13.1.0(supports-color@11.0.0) + version: 13.1.1(supports-color@11.0.0) zone.js: specifier: ^0.16.0 version: 0.16.2 @@ -317,14 +317,14 @@ importers: specifier: 29.1.1 version: 29.1.1 ng-packagr: - specifier: 22.1.0 - version: 22.1.0(@angular/compiler-cli@22.1.0(@angular/compiler@22.1.0)(typescript@6.0.3))(tslib@2.8.1)(typescript@6.0.3) + specifier: 22.1.1 + version: 22.1.1(@angular/compiler-cli@22.1.0(@angular/compiler@22.1.0)(typescript@6.0.3))(tslib@2.8.1)(typescript@6.0.3) rxjs: specifier: 7.8.2 version: 7.8.2 vitest: specifier: 4.1.10 - version: 4.1.10(@opentelemetry/api@1.9.1)(@types/node@24.13.3)(@vitest/coverage-v8@4.1.10)(esbuild@0.28.1)(jiti@2.7.0)(jsdom@29.1.1)(less@4.6.7)(sass@1.101.0)(terser@5.49.0)(tsx@4.23.1)(yaml@2.9.0) + version: 4.1.10(@opentelemetry/api@1.9.1)(@types/node@22.20.1)(@vitest/coverage-v8@4.1.10)(esbuild@0.28.1)(jiti@2.7.0)(jsdom@29.1.1)(less@4.6.7)(sass@1.101.0)(terser@5.49.0)(tsx@4.23.1)(yaml@2.9.0) packages/angular/build: dependencies: @@ -345,10 +345,10 @@ importers: version: 7.24.7 '@inquirer/confirm': specifier: 6.1.1 - version: 6.1.1(@types/node@24.13.3) + version: 6.1.1(@types/node@22.20.1) '@vitejs/plugin-basic-ssl': specifier: 2.3.0 - version: 2.3.0(vite@8.1.5(@types/node@24.13.3)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(terser@5.49.0)(tsx@4.23.1)(yaml@2.9.0)) + version: 2.3.0(vite@8.1.5(@types/node@22.20.1)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(terser@5.49.0)(tsx@4.23.1)(yaml@2.9.0)) beasties: specifier: 0.4.3 version: 0.4.3 @@ -402,7 +402,7 @@ importers: version: 0.2.17 vite: specifier: 8.1.5 - version: 8.1.5(@types/node@24.13.3)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(terser@5.49.0)(tsx@4.23.1)(yaml@2.9.0) + version: 8.1.5(@types/node@22.20.1)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(terser@5.49.0)(tsx@4.23.1)(yaml@2.9.0) watchpack: specifier: 2.5.2 version: 2.5.2 @@ -426,11 +426,11 @@ importers: specifier: 4.6.7 version: 4.6.7 ng-packagr: - specifier: 22.1.0 - version: 22.1.0(@angular/compiler-cli@22.1.0(@angular/compiler@22.1.0)(typescript@6.0.3))(tslib@2.8.1)(typescript@6.0.3) + specifier: 22.1.1 + version: 22.1.1(@angular/compiler-cli@22.1.0(@angular/compiler@22.1.0)(typescript@6.0.3))(tslib@2.8.1)(typescript@6.0.3) postcss: - specifier: 8.5.19 - version: 8.5.19 + specifier: 8.5.25 + version: 8.5.25 rollup: specifier: 4.62.2 version: 4.62.2 @@ -439,7 +439,7 @@ importers: version: 7.8.2 vitest: specifier: 4.1.10 - version: 4.1.10(@opentelemetry/api@1.9.1)(@types/node@24.13.3)(@vitest/coverage-v8@4.1.10)(esbuild@0.28.1)(jiti@2.7.0)(jsdom@29.1.1)(less@4.6.7)(sass@1.101.0)(terser@5.49.0)(tsx@4.23.1)(yaml@2.9.0) + version: 4.1.10(@opentelemetry/api@1.9.1)(@types/node@22.20.1)(@vitest/coverage-v8@4.1.10)(esbuild@0.28.1)(jiti@2.7.0)(jsdom@29.1.1)(less@4.6.7)(sass@1.101.0)(terser@5.49.0)(tsx@4.23.1)(yaml@2.9.0) optionalDependencies: lmdb: specifier: 3.5.6 @@ -458,10 +458,10 @@ importers: version: link:../../angular_devkit/schematics '@inquirer/prompts': specifier: 8.5.2 - version: 8.5.2(@types/node@24.13.3) + version: 8.5.2(@types/node@22.20.1) '@listr2/prompt-adapter-inquirer': specifier: 4.2.4 - version: 4.2.4(@inquirer/prompts@8.5.2(@types/node@24.13.3))(@types/node@24.13.3)(listr2@10.2.2) + version: 4.2.4(@inquirer/prompts@8.5.2(@types/node@22.20.1))(@types/node@22.20.1)(listr2@10.2.2) '@modelcontextprotocol/sdk': specifier: 1.29.0 version: 1.29.0(supports-color@11.0.0)(zod@4.4.3) @@ -600,19 +600,19 @@ importers: version: 4.1.3 autoprefixer: specifier: 10.5.4 - version: 10.5.4(postcss@8.5.19) + version: 10.5.4(postcss@8.5.25) babel-loader: specifier: 10.1.1 - version: 10.1.1(@babel/core@8.0.1)(webpack@5.109.2(esbuild@0.28.1)(lightningcss@1.33.0)(postcss@8.5.19)(uglify-js@3.19.3)) + version: 10.1.1(@babel/core@8.0.1)(webpack@5.109.2(esbuild@0.28.1)(lightningcss@1.33.0)(postcss@8.5.25)(uglify-js@3.19.3)) browserslist: specifier: ^4.26.0 version: 4.28.7 copy-webpack-plugin: specifier: 14.0.0 - version: 14.0.0(webpack@5.109.2(esbuild@0.28.1)(lightningcss@1.33.0)(postcss@8.5.19)(uglify-js@3.19.3)) + version: 14.0.0(webpack@5.109.2(esbuild@0.28.1)(lightningcss@1.33.0)(postcss@8.5.25)(uglify-js@3.19.3)) css-loader: specifier: 7.1.4 - version: 7.1.4(webpack@5.109.2(esbuild@0.28.1)(lightningcss@1.33.0)(postcss@8.5.19)(uglify-js@3.19.3)) + version: 7.1.4(webpack@5.109.2(esbuild@0.28.1)(lightningcss@1.33.0)(postcss@8.5.25)(uglify-js@3.19.3)) esbuild-wasm: specifier: 0.28.1 version: 0.28.1 @@ -633,16 +633,16 @@ importers: version: 4.6.7 less-loader: specifier: 13.0.0 - version: 13.0.0(less@4.6.7)(webpack@5.109.2(esbuild@0.28.1)(lightningcss@1.33.0)(postcss@8.5.19)(uglify-js@3.19.3)) + version: 13.0.0(less@4.6.7)(webpack@5.109.2(esbuild@0.28.1)(lightningcss@1.33.0)(postcss@8.5.25)(uglify-js@3.19.3)) license-webpack-plugin: specifier: 4.0.2 - version: 4.0.2(webpack@5.109.2(esbuild@0.28.1)(lightningcss@1.33.0)(postcss@8.5.19)(uglify-js@3.19.3)) + version: 4.0.2(webpack@5.109.2(esbuild@0.28.1)(lightningcss@1.33.0)(postcss@8.5.25)(uglify-js@3.19.3)) loader-utils: specifier: 3.3.1 version: 3.3.1 mini-css-extract-plugin: specifier: 2.10.2 - version: 2.10.2(webpack@5.109.2(esbuild@0.28.1)(lightningcss@1.33.0)(postcss@8.5.19)(uglify-js@3.19.3)) + version: 2.10.2(webpack@5.109.2(esbuild@0.28.1)(lightningcss@1.33.0)(postcss@8.5.25)(uglify-js@3.19.3)) open: specifier: 11.0.0 version: 11.0.0 @@ -656,11 +656,11 @@ importers: specifier: 5.2.0 version: 5.2.0 postcss: - specifier: 8.5.19 - version: 8.5.19 + specifier: 8.5.25 + version: 8.5.25 postcss-loader: specifier: 8.2.1 - version: 8.2.1(postcss@8.5.19)(typescript@6.0.3)(webpack@5.109.2(esbuild@0.28.1)(lightningcss@1.33.0)(postcss@8.5.19)(uglify-js@3.19.3)) + version: 8.2.1(postcss@8.5.25)(typescript@6.0.3)(webpack@5.109.2(esbuild@0.28.1)(lightningcss@1.33.0)(postcss@8.5.25)(uglify-js@3.19.3)) resolve-url-loader: specifier: 5.0.0 version: 5.0.0 @@ -672,13 +672,13 @@ importers: version: 1.101.0 sass-loader: specifier: 17.0.0 - version: 17.0.0(sass@1.101.0)(webpack@5.109.2(esbuild@0.28.1)(lightningcss@1.33.0)(postcss@8.5.19)(uglify-js@3.19.3)) + version: 17.0.0(sass@1.101.0)(webpack@5.109.2(esbuild@0.28.1)(lightningcss@1.33.0)(postcss@8.5.25)(uglify-js@3.19.3)) semver: specifier: 7.8.5 version: 7.8.5 source-map-loader: specifier: 5.0.0 - version: 5.0.0(webpack@5.109.2(esbuild@0.28.1)(lightningcss@1.33.0)(postcss@8.5.19)(uglify-js@3.19.3)) + version: 5.0.0(webpack@5.109.2(esbuild@0.28.1)(lightningcss@1.33.0)(postcss@8.5.25)(uglify-js@3.19.3)) source-map-support: specifier: 0.5.21 version: 0.5.21 @@ -693,19 +693,19 @@ importers: version: 2.8.1 webpack: specifier: 5.109.2 - version: 5.109.2(esbuild@0.28.1)(lightningcss@1.33.0)(postcss@8.5.19)(uglify-js@3.19.3) + version: 5.109.2(esbuild@0.28.1)(lightningcss@1.33.0)(postcss@8.5.25)(uglify-js@3.19.3) webpack-dev-middleware: specifier: 8.0.3 - version: 8.0.3(tslib@2.8.1)(webpack@5.109.2(esbuild@0.28.1)(lightningcss@1.33.0)(postcss@8.5.19)(uglify-js@3.19.3)) + version: 8.0.3(tslib@2.8.1)(webpack@5.109.2(esbuild@0.28.1)(lightningcss@1.33.0)(postcss@8.5.25)(uglify-js@3.19.3)) webpack-dev-server: specifier: 5.2.6 - version: 5.2.6(bufferutil@4.1.0)(debug@4.4.3(supports-color@11.0.0))(supports-color@11.0.0)(tslib@2.8.1)(utf-8-validate@6.0.6)(webpack@5.109.2(esbuild@0.28.1)(lightningcss@1.33.0)(postcss@8.5.19)(uglify-js@3.19.3)) + version: 5.2.6(bufferutil@4.1.0)(debug@4.4.3(supports-color@11.0.0))(supports-color@11.0.0)(tslib@2.8.1)(utf-8-validate@6.0.6)(webpack@5.109.2(esbuild@0.28.1)(lightningcss@1.33.0)(postcss@8.5.25)(uglify-js@3.19.3)) webpack-merge: specifier: 6.0.1 version: 6.0.1 webpack-subresource-integrity: specifier: 5.1.0 - version: 5.1.0(webpack@5.109.2(esbuild@0.28.1)(lightningcss@1.33.0)(postcss@8.5.19)(uglify-js@3.19.3)) + version: 5.1.0(webpack@5.109.2(esbuild@0.28.1)(lightningcss@1.33.0)(postcss@8.5.25)(uglify-js@3.19.3)) devDependencies: '@angular/ssr': specifier: workspace:* @@ -714,8 +714,8 @@ importers: specifier: 3.0.4 version: 3.0.4(bufferutil@4.1.0)(debug@4.4.3(supports-color@11.0.0))(supports-color@11.0.0)(utf-8-validate@6.0.6) ng-packagr: - specifier: 22.1.0 - version: 22.1.0(@angular/compiler-cli@22.1.0(@angular/compiler@22.1.0)(typescript@6.0.3))(tslib@2.8.1)(typescript@6.0.3) + specifier: 22.1.1 + version: 22.1.1(@angular/compiler-cli@22.1.0(@angular/compiler@22.1.0)(typescript@6.0.3))(tslib@2.8.1)(typescript@6.0.3) undici: specifier: 8.7.0 version: 8.7.0 @@ -741,10 +741,10 @@ importers: version: link:../../ngtools/webpack webpack: specifier: 5.109.2 - version: 5.109.2(esbuild@0.28.1)(lightningcss@1.33.0)(postcss@8.5.19)(uglify-js@3.19.3) + version: 5.109.2(esbuild@0.28.1)(lightningcss@1.33.0)(postcss@8.5.25)(uglify-js@3.19.3) webpack-dev-server: specifier: 5.2.6 - version: 5.2.6(bufferutil@4.1.0)(debug@4.4.3(supports-color@11.0.0))(supports-color@11.0.0)(tslib@2.8.1)(utf-8-validate@6.0.6)(webpack@5.109.2(esbuild@0.28.1)(lightningcss@1.33.0)(postcss@8.5.19)(uglify-js@3.19.3)) + version: 5.2.6(bufferutil@4.1.0)(debug@4.4.3(supports-color@11.0.0))(supports-color@11.0.0)(tslib@2.8.1)(utf-8-validate@6.0.6)(webpack@5.109.2(esbuild@0.28.1)(lightningcss@1.33.0)(postcss@8.5.25)(uglify-js@3.19.3)) packages/angular_devkit/core: dependencies: @@ -799,7 +799,7 @@ importers: version: link:../schematics '@inquirer/prompts': specifier: 8.5.2 - version: 8.5.2(@types/node@24.13.3) + version: 8.5.2(@types/node@22.20.1) packages/ngtools/webpack: devDependencies: @@ -817,7 +817,7 @@ importers: version: 6.0.3 webpack: specifier: 5.109.2 - version: 5.109.2(esbuild@0.28.1)(lightningcss@1.33.0)(postcss@8.5.19)(uglify-js@3.19.3) + version: 5.109.2(esbuild@0.28.1)(lightningcss@1.33.0)(postcss@8.5.25)(uglify-js@3.19.3) packages/schematics/angular: dependencies: @@ -941,9 +941,9 @@ packages: '@angular/platform-browser': ^22.0.0 || ^23.0.0 rxjs: ^6.5.3 || ^7.4.0 - '@angular/ng-dev@https://codeload.github.com/angular/dev-infra-private-ng-dev-builds/tar.gz/2af985ddb942b5928dfb730a6b8efaccd1798846': - resolution: {gitHosted: true, tarball: https://codeload.github.com/angular/dev-infra-private-ng-dev-builds/tar.gz/2af985ddb942b5928dfb730a6b8efaccd1798846} - version: 0.0.0-c279805293db7c28fe20709bc7ac3a3f3bbebb40 + '@angular/ng-dev@https://codeload.github.com/angular/dev-infra-private-ng-dev-builds/tar.gz/dcf9b6776377d5d301e054111add3ef80f433b70': + resolution: {gitHosted: true, tarball: https://codeload.github.com/angular/dev-infra-private-ng-dev-builds/tar.gz/dcf9b6776377d5d301e054111add3ef80f433b70} + version: 0.0.0-0b701b31038419ad73422a9d9d3dff43a725a0d2 hasBin: true '@angular/platform-browser@22.1.0': @@ -1023,8 +1023,8 @@ packages: resolution: {integrity: sha512-5FgxM4dLQpMJHSiVATk8foW263dVHQHBVpXYiimNECVWG01f4nFyEbQixeT6Mwvg7TayREJ2gpKl3o2RoMdnqw==} engines: {node: ^22.18.0 || >=24.11.0} - '@babel/generator@7.29.7': - resolution: {integrity: sha512-DkXD5OJQaAQIdZ1bt3UZdEnHAn9Imd3IVBdX03UFe+ony9Ojw5pzr9YVKGDY1jt+Gcn/FnGkNf8r+Vj5NOJWtQ==} + '@babel/generator@7.29.8': + resolution: {integrity: sha512-gZbepsdh3WDtgZKWL+vTPh71LSBrm/Y4/QDZBVCcYfmeTEEuoOYwlSy+G1StfJg+/Zy550u/3TATbm7qDbbMtg==} engines: {node: '>=6.9.0'} '@babel/generator@8.0.0': @@ -1159,8 +1159,8 @@ packages: resolution: {integrity: sha512-wfbi91pM3py96oIiJEz7qIpyXDytgr9zQC1HEWwlGNVRAEmItuU/0a41ZUKu1sJGyhhOIpc4t5vk4PYzt8wpsg==} engines: {node: ^22.18.0 || >=24.11.0} - '@babel/parser@7.29.7': - resolution: {integrity: sha512-hnORnjP/1P/zFEndoeX+n+t1RwWRJiJpM/jO7FW32Kn9r5+sJB2JWOdYo4L6k78j15eCwY3Gm/7364B1EMwtNg==} + '@babel/parser@7.29.8': + resolution: {integrity: sha512-E8lTAYNB1KW+FH+VGJuZM1ioAx2E6oVlvQFRrf5P8ZZmsiJXYAD9vTFV7yyEURNzgh1dFqMZuO6tUwcARbqFCA==} engines: {node: '>=6.0.0'} hasBin: true @@ -1539,16 +1539,16 @@ packages: resolution: {integrity: sha512-eAD0QW/AlbamBbw0FeGiwasbCVPq5ncW0HNVyLP3B9czqLyh4gvw+5JTSNt6le9+ziAU7mqDZsKTHf3jTb4chQ==} engines: {node: ^22.18.0 || >=24.11.0} - '@babel/traverse@7.29.7': - resolution: {integrity: sha512-EhlfNQtZ+NK22w5BM61ciuiq1m58ed33Wr1Xan//ZRTy6hgjnwyCffRYwzsGXdASJSUJ1guZILsErh1eQcl+zw==} + '@babel/traverse@7.29.8': + resolution: {integrity: sha512-I5z7H3bf/41ktsNVLtpN0wAa336HkqIHQ5BuPLEhTkt1jVSyZpeNKIzTgEWmlxjdg81R0IgUCcaE+Ok3NvrfZg==} engines: {node: '>=6.9.0'} '@babel/traverse@8.0.4': resolution: {integrity: sha512-bZnmqzGG8UZneG1lLxBoWIH0G6Gr1D846Yu4/3XnY6FhCndMR49u26nTY08u/dAxWmLWF9vGQOuC+84FfIUoeg==} engines: {node: ^22.18.0 || >=24.11.0} - '@babel/types@7.29.7': - resolution: {integrity: sha512-4zBIxpPzowiZpusoFkyGVwakdRJUyuH5PxQ/PrqghfdFWWasvnCdPfQXHrenDai+gyLARulZjZowCOj6fjT4pA==} + '@babel/types@7.29.8': + resolution: {integrity: sha512-Vj1jF3cPfxg7OAfoI7QnVKLoILlm2JF9pnVHrX8qx7AHMiYWT+NDAA7jChlNgRS4WTLc/fD1lXLmPixluj+3Gg==} engines: {node: '>=6.9.0'} '@babel/types@8.0.4': @@ -2084,16 +2084,16 @@ packages: resolution: {integrity: sha512-Ohjxjvusr65+SiEVBrilpyn1ir9CM8ZqWjcf7bA8ph1GCunxI6bbwtcl7iGl67A7Lr4Nz7WpNzITNETwggc7pw==} engines: {node: '>=18'} - '@google-cloud/precise-date@5.1.0': - resolution: {integrity: sha512-Z9RVpJUZR+aMF9gPel07xbLURjdT+G4HV6x7jJhreNarQGcT/ZYn1IIfo55rd+tncGvJ4qZDfZnaF6PzqgsQkw==} + '@google-cloud/precise-date@5.2.0': + resolution: {integrity: sha512-ckZ1elVT/JXbO4kxltiT8tumYnTXGIY7OFrDMAJyVWAte/rUYiCuH1YbaKLQrZpYDp522xgTfPqqW/VxfXFdgA==} engines: {node: '>=18'} '@google-cloud/projectify@4.0.0': resolution: {integrity: sha512-MmaX6HeSvyPbWGwFq7mXdo0uQZLGBYCwziiLIGq5JVX+/bdI3SAq6bP98trV5eTWfLuvsMcIC1YJOF2vfteLFA==} engines: {node: '>=14.0.0'} - '@google-cloud/projectify@5.1.0': - resolution: {integrity: sha512-61RXiUnoPBjeIXTzG+WgGLdJlnE3lS7p63rbePw0CEC0tjMGpODKHEr8vFUmuD+iEl7sUWYKbu/ZTk/N2dXw6w==} + '@google-cloud/projectify@5.2.0': + resolution: {integrity: sha512-u4lTO+UI9bwyd/qaVkhVpp57jVH0Pc7wkHE0snZkpQyoKheHDJwmfStao8cWXSF03DmrQltLLSoDjM2CGBpFJA==} engines: {node: '>=18'} '@google-cloud/promisify@4.1.0': @@ -2653,11 +2653,12 @@ packages: resolution: {integrity: sha512-xJIPs+bYuc9ASBl+cvGsKbGrJmS6fAKaSZCnT0lhahT5rhA2VVy9/EcIgd2JhtEuFOJNx7UHNn/qiTPTY4nrQw==} engines: {node: '>= 10'} - '@napi-rs/wasm-runtime@1.1.6': - resolution: {integrity: sha512-ZLv/JdUfkvOy9eCnnBaGfiO+XimbjebAeO+MRQqD/B+FR1tnRN0tpKSJHRbE8sFfS6aqsXZ67TQjfwfsxULVbg==} + '@napi-rs/wasm-runtime@1.2.2': + resolution: {integrity: sha512-JfB4kuJQjaoHuCTseIINHtHWeJnvgEcxjwA5t/Y00ZgaOO1Crz3fjT/p8kT28zA/Caz7oiUMn3d6H2yOVCVwuw==} + engines: {node: ^20.19.0 || ^22.13.0 || >=23.5.0} peerDependencies: - '@emnapi/core': ^1.7.1 - '@emnapi/runtime': ^1.7.1 + '@emnapi/core': ^1.7.1 || ^2.0.0-alpha.3 + '@emnapi/runtime': ^1.7.1 || ^2.0.0-alpha.3 '@noble/hashes@1.4.0': resolution: {integrity: sha512-V1JJ1WTRUqHHrOSh597hURcMqVKVGL/ea3kv0gSnEdsEZ0/+VyPghM1lMNGc00z7CIQorSvbKpuJkxvuHbvdbg==} @@ -2679,16 +2680,16 @@ packages: resolution: {integrity: sha512-vVjdtQQwomrZ4V46B9LaCsxsySxGoHsyw6IYBov/TqJVROrlYdyNgw5q6tQbB7KZt53v1l1W53RiqTvpzL907g==} engines: {node: '>= 20'} - '@octokit/auth-oauth-app@9.0.3': - resolution: {integrity: sha512-+yoFQquaF8OxJSxTb7rnytBIC2ZLbLqA/yb71I4ZXT9+Slw4TziV9j/kyGhUFRRTF2+7WlnIWsePZCWHs+OGjg==} + '@octokit/auth-oauth-app@9.0.4': + resolution: {integrity: sha512-Pe3du5LrC6dlv10b0RbarBlJtIT1Urq8BFoQklK8WmBw8YKnGgrANn7cQmHiA1v8AVihgi7YutV8MncP57I4og==} engines: {node: '>= 20'} - '@octokit/auth-oauth-device@8.0.3': - resolution: {integrity: sha512-zh2W0mKKMh/VWZhSqlaCzY7qFyrgd9oTWmTmHaXnHNeQRCZr/CXy2jCgHo4e4dJVTiuxP5dLa0YM5p5QVhJHbw==} + '@octokit/auth-oauth-device@8.0.4': + resolution: {integrity: sha512-M/+34rmkxMvUnnTo/uqNeVRCXJoJ+5N34eNTbL1KMtIyJpedCTsu/iFL1cWdL+w5hQMlYt6xzXoyux2gn0OVnw==} engines: {node: '>= 20'} - '@octokit/auth-oauth-user@6.0.2': - resolution: {integrity: sha512-qLoPPc6E6GJoz3XeDG/pnDhJpTkODTGG4kY0/Py154i/I003O9NazkrwJwRuzgCalhzyIeWQ+6MDvkUmKXjg/A==} + '@octokit/auth-oauth-user@6.0.3': + resolution: {integrity: sha512-t4OKUhrI5britmpRiSzPAz1TJPyUN/Hw1HEE3Hz/uElxcmnf/YCRSKtFRNc5gy4yJFTlXgk34H1lvxiotQJQvQ==} engines: {node: '>= 20'} '@octokit/auth-token@6.0.0': @@ -2699,8 +2700,8 @@ packages: resolution: {integrity: sha512-DhGl4xMVFGVIyMwswXeyzdL4uXD5OGILGX5N8Y+f6W7LhC1Ze2poSNrkF/fedpVDHEEZ+PHFW0vL14I+mm8K3Q==} engines: {node: '>= 20'} - '@octokit/endpoint@11.0.3': - resolution: {integrity: sha512-FWFlNxghg4HrXkD3ifYbS/IdL/mDHjh9QcsNyhQjN8dplUoZbejsdpmuqdA76nxj2xoWPs7p8uX2SNr9rYu0Ag==} + '@octokit/endpoint@11.0.4': + resolution: {integrity: sha512-f1cOWoHPmxryJFknxbtDdjODWfV8A9tc8Aae6ermXPNgHFZ/x91AtHIz4gicEjL8hkJiip+u21QHJORfBv/qiA==} engines: {node: '>= 20'} '@octokit/graphql-schema@15.26.1': @@ -2714,19 +2715,28 @@ packages: resolution: {integrity: sha512-7QoLPRh/ssEA/HuHBHdVdSgF8xNLz/Bc5m9fZkArJE5bb6NmVkDm3anKxXPmN1zh6b5WKZPRr3697xKT/yM3qQ==} engines: {node: '>= 20'} - '@octokit/oauth-methods@6.0.2': - resolution: {integrity: sha512-HiNOO3MqLxlt5Da5bZbLV8Zarnphi4y9XehrbaFMkcoJ+FL7sMxH/UlUsCVxpddVu4qvNDrBdaTVE2o4ITK8ng==} + '@octokit/oauth-methods@6.0.3': + resolution: {integrity: sha512-t7MBs34Ja16BBZlOSAFslFh4wBMuofD83wVLG9zIuuEGMv/U12XAJ8ESOifgEcC1ptjhNA3sorLA9BCtVfgPuw==} engines: {node: '>= 20'} '@octokit/openapi-types@27.0.0': resolution: {integrity: sha512-whrdktVs1h6gtR+09+QsNk2+FO+49j6ga1c55YZudfEG+oKJVvJLQi3zkOm5JjiUXAagWK2tI2kTGKJ2Ys7MGA==} + '@octokit/openapi-types@28.0.0': + resolution: {integrity: sha512-0rFyLuyHvIj6uuZWuDslxkowFYdPXoNIkeAv4b27dzm2Tf4vGWXnPsMcxs7d65kLdMERgP3wc1AEPlqMz8e1cQ==} + '@octokit/plugin-paginate-rest@14.0.0': resolution: {integrity: sha512-fNVRE7ufJiAA3XUrha2omTA39M6IXIc6GIZLvlbsm8QOQCYvpq/LkMNGyFlB1d8hTDzsAXa3OKtybdMAYsV/fw==} engines: {node: '>= 20'} peerDependencies: '@octokit/core': '>=6' + '@octokit/plugin-paginate-rest@15.0.0': + resolution: {integrity: sha512-lw9A9YL5s4VPj+VEx8uMxaxQm2YTgrPDkrLEuZuu18R8TK3oPcXF4K6t52nx6xn1RcogZC9i188sAr/4XYJaQQ==} + engines: {node: '>= 20'} + peerDependencies: + '@octokit/core': '>=6' + '@octokit/plugin-request-log@6.0.0': resolution: {integrity: sha512-UkOzeEN3W91/eBq9sPZNQ7sUBvYCqYbrrD8gTbBuGtHEuycE4/awMXcYvx6sVYo7LypPhmQwwpUe4Yyu4QZN5Q==} engines: {node: '>= 20'} @@ -2739,12 +2749,22 @@ packages: peerDependencies: '@octokit/core': '>=6' + '@octokit/plugin-rest-endpoint-methods@18.0.0': + resolution: {integrity: sha512-1wM02pQTHEarWYij0Bb4gu8X8fBy2FJdI4HMTSFDxtYLbOkJErGVx5ywmM6jeS8tOmC0iCiRLrn6YsSIecUeOQ==} + engines: {node: '>= 20'} + peerDependencies: + '@octokit/core': '>=6' + '@octokit/request-error@7.1.0': resolution: {integrity: sha512-KMQIfq5sOPpkQYajXHwnhjCC0slzCNScLHs9JafXc4RAJI+9f+jNDlBNaIMTvazOPLgb4BnlhGJOTbnN0wIjPw==} engines: {node: '>= 20'} - '@octokit/request@10.0.11': - resolution: {integrity: sha512-+s7HUxjfFqOMS9VlIwDffq0MikjSAK0gSpG73W+meAvVAvX4MBrHYTK5Bj3Uot55qFT4gzUtfzE4mGWY4Br8/Q==} + '@octokit/request-error@7.1.1': + resolution: {integrity: sha512-+eaY7G2VVpSf2pc5Gn1+mph837V/d/TYTJAgWL9Tb0ogGYcpN3IlAVFgjL+Vv93F/sevrxkvsYCedtpLdcFLzA==} + engines: {node: '>= 20'} + + '@octokit/request@10.0.13': + resolution: {integrity: sha512-v2269YxL9Yf+x3d+gRI63FP0vFQEiWgLyBzxe/Y+0yFDg2B/Tzf5dhh9VNfccVAQnfcfwQWyk/y6Bn7rUXXs7A==} engines: {node: '>= 20'} '@octokit/rest@22.0.1': @@ -2754,6 +2774,9 @@ packages: '@octokit/types@16.0.0': resolution: {integrity: sha512-sKq+9r1Mm4efXW1FCk7hFSeJo4QKreL/tTbR0rz/qx/r1Oa2VV83LTA/H/MuCOX7uCIJmQVRKBcbmWoySjAnSg==} + '@octokit/types@17.0.0': + resolution: {integrity: sha512-ByP1v7YL5SMveFPP7+sj0/ZuWCOOg/Chs4NafOMpq6WNIM/hdGY0S7C0TCGDBWu1aGmOxmUIhMx3cO+IdwYZ1Q==} + '@open-draft/deferred-promise@2.2.0': resolution: {integrity: sha512-CecwLWx3rhxVQF6V4bAgPS5t+So2sTbPgAzafKkVizyi7tlwpcFpdFqq+wqF2OwNBmqFuu6tOyouTuxgpMfzmA==} @@ -3585,8 +3608,8 @@ packages: '@types/express-serve-static-core@4.19.9': resolution: {integrity: sha512-QP2ESEe/ImWY0HDwNAnK9PvEffUyhLTnWkk7KXzHfyeWAnlrDe1fN77bXl6ia8KT3wPlmA7t9/VPRpnf4Ex9sg==} - '@types/express-serve-static-core@5.1.2': - resolution: {integrity: sha512-d3KvEXBSo/lOAMc2u6fkyDHBvetBHeqD7wm/AcXfLpSOQwlmG9D/aQ0SFswVjv05p7ullQS7Mjohj6/VdbZuTg==} + '@types/express-serve-static-core@5.1.3': + resolution: {integrity: sha512-dPfW8NFiOF4wOHc7+N/QSxlY9cfSsenewGbAz8C8U/MULPd/YZ27LvJUIlzaXie7e6Ove9YunJGgC9tbHD2cKw==} '@types/express@4.17.25': resolution: {integrity: sha512-dVd04UKsfpINUnK0yBoYHDF3xu7xVH4BuDotC/xGuycx4CgbP48X/KF/586bcObxT0HENHXEU8Nqtu6NR+eKhw==} @@ -3633,8 +3656,8 @@ packages: '@types/loader-utils@3.0.0': resolution: {integrity: sha512-oOi4OGpiLUbb+Q/cN9FIkkDFgOpOGZ2cUAzb5i03wrGstnG6Syx1WDMhSiB5rcP10XX7cw7Uev8mv++/aplnNg==} - '@types/lodash@4.17.24': - resolution: {integrity: sha512-gIW7lQLZbue7lRSWEFql49QJJWThrTFFeIMJdp3eH4tKoxm1OvEPg02rm4wCCSHS0cL3/Fizimb35b7k8atwsQ==} + '@types/lodash@4.17.25': + resolution: {integrity: sha512-+K1NIO8I+F9/wNulfVvu23QYd0Pe9/OCqRrim4NoYIf1VoEDL90Ve4ClzpyqBLc7NpGGWRvYNCKZ1BE/Jpf8dQ==} '@types/micromatch@2.3.35': resolution: {integrity: sha512-J749bHo/Zu56w0G0NI/IGHLQPiSsjx//0zJhfEVAN95K/xM5C8ZDmhkXtU3qns0sBOao7HuQzr8XV1/2o5LbXA==} @@ -3687,6 +3710,9 @@ packages: '@types/semver@7.7.1': resolution: {integrity: sha512-FmgJfu+MOcQ370SD0ev7EI8TlCAfKYU+B4m5T3yXc1CiRN94g/SZPtsCkk506aUDtlMnFZvasDwHHUcZUEaYuA==} + '@types/semver@7.8.0': + resolution: {integrity: sha512-1mAINjtQCXXeLkJ9ehXkwOcBpqtLxiVtKhpUf83DdRNdQKV0iXZpaHYqRr7nj+wvxuJzoAmAwXI+sCNMv1CzLQ==} + '@types/send@0.17.6': resolution: {integrity: sha512-Uqt8rPBE8SY0RK8JB1EzVOIZ32uqy8HwdxCnoCOsYrvnswqmFZ/k+9Ikidlk/ImhsdvBsloHbAlewb2IEBV/Og==} @@ -3807,8 +3833,8 @@ packages: resolution: {integrity: sha512-VtpBz9R61GTFUxPiQmBhCOffQZRJZMA2EXO/FzbaoNczm/Xt2KkDJq0PPwV5qmRGeouDRxEKUQ+caJGVN0W7Ww==} engines: {node: '>=18'} - '@verdaccio/core@8.2.0': - resolution: {integrity: sha512-tK1QgY3Kl8n71Q5lvPsMEe2Kv6Rk1Vd6SUUCP7om8ARuDvLkvRgJ1o8Tq7vqYWkPRIPiowdPt18uEjcJo1moAw==} + '@verdaccio/core@8.2.1': + resolution: {integrity: sha512-fcK9lGTXSxrNncbShtt5sCfFPiP2GdsQmhXdeu4HDIH9GU8cLF5Jj/QBpLjMuz+lB+qHg6QBFlUKS0pnio20jA==} engines: {node: '>=22'} '@verdaccio/file-locking@13.0.1': @@ -3997,8 +4023,8 @@ packages: peerDependencies: acorn: ^6.0.0 || ^7.0.0 || ^8.0.0 - acorn@8.17.0: - resolution: {integrity: sha512-xRQbDb9BnwDafYNn6Vwl839DYVjqXYb1XVGtWAZ1kcDc6iwAL4hg3B1dZlRiuENFeO2H53gFG3in621AdERVAg==} + acorn@8.18.0: + resolution: {integrity: sha512-lGq+9yr1/GuAWaVYIHRjvvySG5/4VfKIvC8EWxStPdcDh/Ka7FG3twP6v4d5BkravUilhIAsG4Qj83t02LWUPQ==} engines: {node: '>=0.4.0'} hasBin: true @@ -4254,8 +4280,8 @@ packages: bare-events: optional: true - bare-url@2.4.6: - resolution: {integrity: sha512-iQxPClE07hETVpbRoX7JXX3v/ZQViCxe/SYCxylRLzdEx1xJAufPptfiOqR8tqiCtmbtMDANKWszzjLu1PMAZQ==} + bare-url@2.4.7: + resolution: {integrity: sha512-o8CRCiJtib+ycO3mE4A5UChtGX4dDP2XxsWVu9P+Zc3H8tcmKwNVEDoDTXmwN+uuMhfKeT7/i7Y26xS8W7ohoA==} base64-js@1.5.1: resolution: {integrity: sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==} @@ -4264,8 +4290,8 @@ packages: resolution: {integrity: sha512-lGe34o6EHj9y3Kts9R4ZYs/Gr+6N7MCaMlIFA3F1R2O5/m7K06AxfSeO5530PEERE6/WyEg3lsuyw4GHlPZHog==} engines: {node: ^4.5.0 || >= 5.9} - baseline-browser-mapping@2.11.4: - resolution: {integrity: sha512-s4+sLr9mZ/CyqeRritFeYV/Zx73OAtmaHn6kkBS1XRoJn1hrg3xIDUcpicAEX68tkcIN0iBCgti31C8zxtkhsQ==} + baseline-browser-mapping@2.11.11: + resolution: {integrity: sha512-/yImnXwyTvgMkhgekLHok/Rx5vO6E0BmStWlSqKWMVm2a2ITuZ1Tn+9bgLS+gZRdZmWtd8nxuhHpdmCUOWsTQQ==} engines: {node: '>=6.0.0'} hasBin: true @@ -4309,20 +4335,20 @@ packages: resolution: {integrity: sha512-2cGmJupaNgg+QUwVLAucDuWuoMZ6EX9iHDRswZ5lsNYEmwPaRknMPCLZz07yTzVq/83p4o/wzbDZbBrTvGGTIw==} engines: {node: '>=18'} - bonjour-service@1.4.3: - resolution: {integrity: sha512-2Kd5UYlFUVgAKMTyuBLl6w49wqfOnbxHqmuH0oCl/n7TfAikR0zoowNOP5BU4dfXmm+Vr9JyEN370auSMx+CNg==} + bonjour-service@1.4.4: + resolution: {integrity: sha512-jCZcVv7eoc4QesRscwEZtSROBen+6LpKAmBIsQYQrsAeVHLyMXWX/t6eIV5KiRZYNUBl8eVqImEEMQ8L5+c/Kw==} boolbase@1.0.0: resolution: {integrity: sha512-JZOSA7Mo9sNGB8+UjSgzdLtokWAky1zbztM3WRLCbZ70/3cTANmQmOdR7y2g+J0e2WXywy1yS468tY+IruqEww==} - brace-expansion@1.1.16: - resolution: {integrity: sha512-IDw48K2/2kRkg9LdJxurvq3lV3aBgq0REY89duEqFRthjlPdXHKMj7EnQOXVckxzgisinf3nHfrcE2FufFLXMw==} + brace-expansion@1.1.18: + resolution: {integrity: sha512-Edep/X9fGqVNmzKBVsDYIOtD+z1tuezV70LBjdCst9Tqu76lsnvRiZ6oTic1n+/BIwX6QDGAO94PN4N2SADvtw==} - brace-expansion@2.1.2: - resolution: {integrity: sha512-w5JZcKgdhDOgOwm8H+KgbosopHMuGcl6qbulwjtz3SM7I7P3yW1eAjzMPLrIE+NQ9vjgANKHWeMHnrT0OXW1oA==} + brace-expansion@2.1.4: + resolution: {integrity: sha512-hGfVzPxthbf3+2yjg/RBs60cB0FhqBS/zvdV/4wn4/BmN0bNMMHPc4V/BbFieqf1TKAGGAHnY4eSjajCl0f2Xg==} - brace-expansion@5.0.8: - resolution: {integrity: sha512-JZyDyq3D4AUifKTPOB7DELf6XsB3WdPuNxCtob1vFXPsSXhdAiHBWJ/tJ8HAc9aH84BK+5JFZLNkJKx3G9kzQg==} + brace-expansion@5.0.9: + resolution: {integrity: sha512-ScQ4IuvIEF1TMlP7Zt+vjJ//9zlPb2SDcxWxM3bk8s6t6GGdJ7KO1dCcTidOPJKePW30LE/2cT7wCyPho9/Wxg==} engines: {node: 20 || >=22} braces@3.0.3: @@ -4868,8 +4894,8 @@ packages: engines: {node: '>=0.12.18'} hasBin: true - electron-to-chromium@1.5.396: - resolution: {integrity: sha512-yHiw2Y3C3H9U6TMbOfoWK/BPreiOPXRfTWPBwQBoZG6/8TB6eOPnsy5oaRYuatR7Fw2SJ4kKforgufeo7fq0EQ==} + electron-to-chromium@1.5.399: + resolution: {integrity: sha512-lEcqhErbHjXRvd41rnWLpzbyU/IXfIYo7QwaFWmxGeLiLyY2TBCdHnWY88vB+p3ubnihRypDm66panXl7TylLA==} emoji-regex@10.6.0: resolution: {integrity: sha512-toUI84YS5YmxW219erniWD0CIVOo46xGKColeNQRgOzDorgBi1v4D71/OFzgD9GO2UGKIv1C3Sp8DAn0+j5w7A==} @@ -4913,8 +4939,8 @@ packages: resolution: {integrity: sha512-clKkw4C7nJ22mGgoVcCg6V/W/TxdNyIOTr89k2ONZu81qqkddPFDF0LXcbAwhzPD8DjkiRCjzuiO6Y+fkpD4vg==} engines: {node: '>=10.2.0'} - enhanced-resolve@5.24.4: - resolution: {integrity: sha512-GVoi+ICHocoOIU7qVVM48wOJziRsqrsyqlI0Ce0LdowRn6v3bcH2zUa9kp85ncx0nwIb9/HOCOLS3fdThDG/XQ==} + enhanced-resolve@5.24.5: + resolution: {integrity: sha512-L1l8TNvomm6UVW5B253AGxQagSQr+vGwhMlrrfRS2qmhx46AMpMVJKQYLvWYbysTMY8VoicOvzHzoHMbyzB+4A==} engines: {node: '>=10.13.0'} ent@2.2.2: @@ -5199,8 +5225,8 @@ packages: fast-string-width@3.0.2: resolution: {integrity: sha512-gX8LrtNEI5hq8DVUfRQMbr5lpaS4nMIWV+7XEbXk2b8kiQIizgnlr12B4dA3ZEx3308ze0O4Q1R+cHts8kyUJg==} - fast-uri@3.1.4: - resolution: {integrity: sha512-8JnbkQ4juDyvYs4mgFGQqg4yCYtFDtUtmp2QIQq11ZZe5CFQ5wcqm1rqDgAh/QdMySuBnPzMUiJUNZG5N/AiQw==} + fast-uri@3.1.5: + resolution: {integrity: sha512-gHwA1O9LDIcKunMKhObS/HimwtehO1nPUECKAu5TpKgaO19fcWEl4bliWe1jWxVFvIXztJjjQ4L8XQ1EU9f7Jw==} fast-wrap-ansi@0.2.2: resolution: {integrity: sha512-7F2Fl+TjRSenLqlU3UjSH0iyqopqoZIu7eZVpEirP2g1GtWa2G/ecEmBdgz31+Mxr+ELclgg6sokpSFIQiZ02Q==} @@ -5272,8 +5298,8 @@ packages: resolution: {integrity: sha512-b6suED+5/3rTpUBdG1gupIl8MPFCAMA0QXwmljLhvCUKcUvdE4gWky9zpuGCcXHOsz4J9wPGNWq6OKpmIzz3hQ==} hasBin: true - flatted@3.4.3: - resolution: {integrity: sha512-/zipXxyO6rGvuNGDiULY9MvEGSkb2gaG4GGH4ygMi0ZZzyMHdUZBmntJmx5x1G2VuPytCwGN4xsJP6cw+sK+vQ==} + flatted@3.4.4: + resolution: {integrity: sha512-5+ybhBZANEJxaH3X5evAFatUxLfEHSr7n6kYJ+1Qd0mUqr4eu9gIf6GDbWHf8RJijHrjjO8G+la14SlL2SeS1Q==} folder-hash@4.1.3: resolution: {integrity: sha512-94fj+fXj1XHT8zGumUy/VlyFARc/yrslKJ2+vjrP/U6ftTdL7u68+gQhvSBjz9wrwTuty6BpZ7JsbEK5OU9RNw==} @@ -5541,8 +5567,8 @@ packages: resolution: {integrity: sha512-T2UbfbBEF32wiepXIsMlTW9+dDYC6wMh/t/vYA4tuOMKqWz/n3vr1NFSxQiyP+zk2mXsoMA/i/7qV6LKut1t1A==} engines: {node: '>= 0.4'} - hono@4.12.32: - resolution: {integrity: sha512-XcuyW9qE2kJn07PkecMOBd5Vq/hMy7mmGw+idz1yblbg9N17ijJODrvPkn7/dwL3Kulj8LcRJ69DLOWf91dRUg==} + hono@4.12.34: + resolution: {integrity: sha512-GqXJqY/xJkJmuloTrnV1ZEXG3fqte+VjkUqoRNZXcrUidiUOP4fMSIHHY4tsqZBK++kVyWmt/AAfSUuy57/eSA==} engines: {node: '>=16.9.0'} hosted-git-info@10.1.1: @@ -5707,8 +5733,8 @@ packages: resolution: {integrity: sha512-4gd7VpWNQNB4UKKCFFVcp1AVv+FMOgs9NKzjHKusc8jTMhd5eL1NqQqOpE0KzMds804/yHlglp3uxgluOqAPLw==} engines: {node: '>= 0.4'} - ip-address@10.3.1: - resolution: {integrity: sha512-1e9d3kb97NHJTIJDZW9rKqW2h6+dFa50Dy0fpPSMQp2ADje5gvKsXmdiK6dwY5t76TaTt5+P5N1Y/LoToIxP6g==} + ip-address@10.4.0: + resolution: {integrity: sha512-oSK96Grm3aP6OrS263xVxbNDGVL7rzBtYdpGqlDG8iQdoenDoTs/nkki+DflYbAEE8Xl6o5YxhxlrKvI3nqKXQ==} engines: {node: '>= 12'} ipaddr.js@1.9.1: @@ -6004,8 +6030,8 @@ packages: resolution: {integrity: sha512-AC/7JofJvZGrrneWNaEnJeOLUx+JlGt7tNa0wZiRPT4MY1wmfKjt2+6O2p2uz2+skll8OZZmJMNqeke7kKbNgQ==} hasBin: true - jose@6.2.4: - resolution: {integrity: sha512-N8acGzVsQy6M/fjFcxtysNc4Q379TcM5dM/qKkNtsHFji88yANnXTr7BLeP75iPnFwBfQzM/jg2BZ9+HZrHCZA==} + jose@6.2.7: + resolution: {integrity: sha512-hq1OB1bALKfydZNoViyg6hPVGV4i93ny9Op+n4zP5RSf7SCZEXa/TsG2O3IEr7+WlHRTPnpqDmHfMH6qXAD60w==} js-tokens@10.0.0: resolution: {integrity: sha512-lM/UBzQmfJRo9ABXbPWemivdCW8V2G8FHaHdypQaIy523snUjog0W71ayWXTjiR+ixeMyVHN2XcpnTd/liPg/Q==} @@ -6017,8 +6043,8 @@ packages: resolution: {integrity: sha512-qQKT4zQxXl8lLwBtHMWwaTcGfFOZviOJet3Oy/xmGk2gZH677CJM9EvtfdSkgWcATZhj/55JZ0rmy3myCT5lsA==} hasBin: true - js-yaml@4.3.0: - resolution: {integrity: sha512-1td788aAnnZ5qs7V2QIRl1owjtYpbKt749Y3xauqQgwIIGF/xXWz1wMTEBx5O3LK3lXLVuqXPdPxj2BoFHaW9Q==} + js-yaml@4.3.1: + resolution: {integrity: sha512-CY6crGq313MX8GkwvB7tzgp99vjQxY1++5y10/BKN/GUfHqWaOGQMNZkBvqSzsZKWk/ijwHlWzzkLulsGHhjWQ==} hasBin: true jsbn@0.1.1: @@ -6358,8 +6384,8 @@ packages: magic-string@1.0.0: resolution: {integrity: sha512-CGvjzMN08iv6w1mm4/x3Gh1hLb4VnyRUA15FFpl6CsCIGGoe36k7kY5KNz9QDbSBN5I/fWHM6ZlIkUTa5xdUEA==} - magicast@0.5.3: - resolution: {integrity: sha512-pVKE4UdSQ7DvHzivsCIFx2BJn1mHG6KsyrFcaxFx6tONdneEuThrDx0Cj3AMg58KyN4pzYT+LHOotxDQDjNvkw==} + magicast@0.5.4: + resolution: {integrity: sha512-llBEhWm1SacoRwgHUoQJYtwp4PBLF4faQi5TCpIGyGs9n4y5+juI0tDgyKIfpqxckRHaHzouUEph3THklWh03w==} make-dir@4.0.0: resolution: {integrity: sha512-hXdUTZYIVOt1Ex//jAQi+wTZZpUpwBj/0QsOzqegb3rGMMeJiSEu5xLHnYfBrRV4RH2+OCSOO95Is/7x1WJ4bw==} @@ -6608,8 +6634,8 @@ packages: neo-async@2.6.2: resolution: {integrity: sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw==} - ng-packagr@22.1.0: - resolution: {integrity: sha512-Vd4M/N0dDMYk3QTcKx8DAEiE7qOmM7WE04GICW7Kcr25XQYq0rQJGVSCsgpI/jmPV5V/UOANWMJARUiMlktyYg==} + ng-packagr@22.1.1: + resolution: {integrity: sha512-jZzpQckw2SFvuYI3aWfYMefSVKKG/04E+vrX2KD6coMx7ciLBotVWuLc0331Fjb6XNmAVcsmgQ5NY/Lf+9Himw==} engines: {node: ^22.22.3 || ^24.15.0 || >=26.0.0} hasBin: true peerDependencies: @@ -7000,8 +7026,8 @@ packages: postcss-value-parser@4.2.0: resolution: {integrity: sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ==} - postcss@8.5.19: - resolution: {integrity: sha512-Mz8SaolMd8nB+G13WkORcxQKHZ/NE4xXevtkJHVuG+guo9/wYKlIMTKAqGdEmYOXR2ijPjTYNHssizdaVSUNdQ==} + postcss@8.5.25: + resolution: {integrity: sha512-DTPx3RWSSnWyzLxQnlH0rJP+EW5ekl16ZU4/psbIhA0e53kJfdgaN5vKM+xP7yJtXVu+nfdVFmlgFDEKAe4Pyw==} engines: {node: ^10 || ^12 || >=14} powershell-utils@0.1.0: @@ -7027,8 +7053,8 @@ packages: process-warning@1.0.0: resolution: {integrity: sha512-du4wfLyj4yCZq1VupnVSZmRsPJsNuxoDQFdCFHLaYiEbFBD7QE0a+I4D7hOxrVnh78QE/YipFAj9lXHiXocV+Q==} - process-warning@5.0.0: - resolution: {integrity: sha512-a39t9ApHNx2L4+HBnQKqxxHNs1r7KF+Intd8Q/g1bUh6q0WIp9voPXJ/x0j+ZL45KF1pJd9+q2jLIRMfvEshkA==} + process-warning@5.1.0: + resolution: {integrity: sha512-jQSaVHsPgtyw60e1rQ/A+/ArPEj/S8pS/vFnyGa/gYFXrKk/6RuDkoqVDQ5NI5MmS01698ltlAk0NoDBNLujRw==} process@0.11.10: resolution: {integrity: sha512-cdGef/drWFoydD1JsMzuFf8100nZl+GT+yacc2bEced5f9Rjk4z+WtFUTBu9PhOi9j/jfmBPu0mMEY4wIdAF8A==} @@ -7758,30 +7784,30 @@ packages: tinybench@2.9.0: resolution: {integrity: sha512-0+DUvqWMValLmha6lr4kD8iAMK1HzV0/aKnCtWb9v9641TnP/MFb7Pc2bxoxQjTXAErryXVgUOfv2YqNllqGeg==} - tinyexec@1.2.4: - resolution: {integrity: sha512-SHf/r48b7vOrjve9PxJo3MN5v5yuyjHvdUcrQffT3WXMUfnGmHDVbC4k3sHJaJTgZCwpUplIaAo5ANtMyp3YHg==} + tinyexec@1.3.0: + resolution: {integrity: sha512-QKAl9m8gWWGHV8jZcPeym6j+XULi6tOf1mT83WYJ4Lk2ytW/uwAWkrP0uFsdoYMdueVJ0qs26wZ+23xeB4ibNQ==} engines: {node: '>=18'} tinyglobby@0.2.17: resolution: {integrity: sha512-wXR/dYpcqKmfWpEdZjiKJOwCNFndD0DMnrW/cYjVGttEkBfVgcLFHoNrlj47mjOVic9yyNu65alsgF4NQyTa2g==} engines: {node: '>=12.0.0'} - tinyrainbow@3.1.0: - resolution: {integrity: sha512-Bf+ILmBgretUrdJxzXM0SgXLZ3XfiaUuOj/IKQHuTXip+05Xn+uyEYdVg0kYDipTBcLrCVyUzAPz7QmArb0mmw==} + tinyrainbow@3.1.1: + resolution: {integrity: sha512-yau8yJdTt989Mm0Bd/236QnzEiPf2xLLTqUZRUJOo/3CB078LSwzei343DgtJVmfJKJE3TMINY1u42SQsP6mXw==} engines: {node: '>=14.0.0'} tldts-core@6.1.86: resolution: {integrity: sha512-Je6p7pkk+KMzMv2XXKmAE3McmolOQFdxkKw0R8EYNr7sELW46JqnNeTX8ybPiQgvg1ymCoF8LXs5fzFaZvJPTA==} - tldts-core@7.4.9: - resolution: {integrity: sha512-DxKfPBI52p2msTEu7MPhdpdDTBhhVQg1a/8PjQckeyAvO13eMYElX545grIp6nnTGIMZlRvFZPvFhvI/WIz2Vg==} + tldts-core@7.4.10: + resolution: {integrity: sha512-KnQjp53ZekKgm/r3l+u8kJGGzYgrWdP8+Mql7a4vijh2WE0IrZWspQj/TpTxDho/YxO+AnOZnIjQcCD+q6iJsw==} tldts@6.1.86: resolution: {integrity: sha512-WMi/OQ2axVTf/ykqCQgXiIct+mSQDFdH2fkwhPwgEwvJ1kSzZRiinb0zF2Xb8u4+OqPChmyI6MEu4EezNJz+FQ==} hasBin: true - tldts@7.4.9: - resolution: {integrity: sha512-3kZ8wQQ/k5DrChD4X4FVvr2D7E5uoRgAqkPyLpSCGUvqOvqu+JEdr3mwMUaVWb+vMHZaKhF5fp2PBigKsui7hA==} + tldts@7.4.10: + resolution: {integrity: sha512-GgouD1B+sWwvkaEq8vXC15DjQitxbvs12oIXELpconwm+Tg3zfcEv4jgzq3vtKverDXsg3VI8aRgNL2Nra0Iog==} hasBin: true tmp@0.2.7: @@ -8027,8 +8053,8 @@ packages: resolution: {integrity: sha512-n5VYOooGpXr3ZE2DjNx6lJPkCFd2sORDVMmbs0o7Mqx6g0kOHTkfkY5DygZAwOvGtFy0CecufRrl49RzAD9Jkg==} engines: {node: '>=18'} - verdaccio-auth-memory@13.1.0: - resolution: {integrity: sha512-DEbiZyJfxhnmf+Q168NJmQrF3YBM2d9MsIrnLqfQdpk5tWrxOEBn7/d3p26UPYecfgqRm22AvxSt8XcquDadEw==} + verdaccio-auth-memory@13.1.1: + resolution: {integrity: sha512-Oo3CsyIGaM2S0qCXMN0Coi1uVyvIplT5DAEqwYK22z9XTHAZQf3oUgiVPxEwpFGcqxYsIAq1kxH5COST3xxR6g==} engines: {node: '>=22'} verdaccio-htpasswd@13.0.3: @@ -8502,7 +8528,7 @@ snapshots: rxjs: 7.8.2 tslib: 2.8.1 - '@angular/ng-dev@https://codeload.github.com/angular/dev-infra-private-ng-dev-builds/tar.gz/2af985ddb942b5928dfb730a6b8efaccd1798846(@modelcontextprotocol/sdk@1.29.0(supports-color@11.0.0)(zod@4.4.3))': + '@angular/ng-dev@https://codeload.github.com/angular/dev-infra-private-ng-dev-builds/tar.gz/dcf9b6776377d5d301e054111add3ef80f433b70(@modelcontextprotocol/sdk@1.29.0(supports-color@11.0.0)(zod@4.4.3))': dependencies: '@actions/core': 3.0.1 '@conventional-changelog/git-client': 3.1.0(conventional-commits-filter@6.0.1)(conventional-commits-parser@7.1.1) @@ -8514,12 +8540,12 @@ snapshots: '@octokit/core': 7.0.6 '@octokit/graphql': 9.0.3 '@octokit/graphql-schema': 15.26.1 - '@octokit/openapi-types': 27.0.0 - '@octokit/plugin-paginate-rest': 14.0.0(@octokit/core@7.0.6) - '@octokit/plugin-rest-endpoint-methods': 17.0.0(@octokit/core@7.0.6) + '@octokit/openapi-types': 28.0.0 + '@octokit/plugin-paginate-rest': 15.0.0(@octokit/core@7.0.6) + '@octokit/plugin-rest-endpoint-methods': 18.0.0(@octokit/core@7.0.6) '@octokit/request-error': 7.1.0 '@octokit/rest': 22.0.1 - '@octokit/types': 16.0.0 + '@octokit/types': 17.0.0 '@pnpm/dependency-path': 1001.1.10 '@types/cli-progress': 3.11.6 '@types/ejs': 3.1.5 @@ -8632,14 +8658,14 @@ snapshots: '@babel/core@7.29.7(supports-color@11.0.0)': dependencies: '@babel/code-frame': 7.29.7 - '@babel/generator': 7.29.7 + '@babel/generator': 7.29.8 '@babel/helper-compilation-targets': 7.29.7 '@babel/helper-module-transforms': 7.29.7(@babel/core@7.29.7(supports-color@11.0.0))(supports-color@11.0.0) '@babel/helpers': 7.29.7 - '@babel/parser': 7.29.7 + '@babel/parser': 7.29.8 '@babel/template': 7.29.7 - '@babel/traverse': 7.29.7(supports-color@11.0.0) - '@babel/types': 7.29.7 + '@babel/traverse': 7.29.8(supports-color@11.0.0) + '@babel/types': 7.29.8 '@jridgewell/remapping': 2.3.5 convert-source-map: 2.0.0 debug: 4.4.3(supports-color@11.0.0) @@ -8668,10 +8694,10 @@ snapshots: obug: 2.1.4 semver: 7.8.5 - '@babel/generator@7.29.7': + '@babel/generator@7.29.8': dependencies: - '@babel/parser': 7.29.7 - '@babel/types': 7.29.7 + '@babel/parser': 7.29.8 + '@babel/types': 7.29.8 '@jridgewell/gen-mapping': 0.3.13 '@jridgewell/trace-mapping': 0.3.31 jsesc: 3.1.0 @@ -8741,8 +8767,8 @@ snapshots: '@babel/helper-module-imports@7.29.7(supports-color@11.0.0)': dependencies: - '@babel/traverse': 7.29.7(supports-color@11.0.0) - '@babel/types': 7.29.7 + '@babel/traverse': 7.29.8(supports-color@11.0.0) + '@babel/types': 7.29.8 transitivePeerDependencies: - supports-color @@ -8756,7 +8782,7 @@ snapshots: '@babel/core': 7.29.7(supports-color@11.0.0) '@babel/helper-module-imports': 7.29.7(supports-color@11.0.0) '@babel/helper-validator-identifier': 7.29.7 - '@babel/traverse': 7.29.7(supports-color@11.0.0) + '@babel/traverse': 7.29.8(supports-color@11.0.0) transitivePeerDependencies: - supports-color @@ -8796,7 +8822,7 @@ snapshots: '@babel/helper-split-export-declaration@7.24.7': dependencies: - '@babel/types': 7.29.7 + '@babel/types': 7.29.8 '@babel/helper-string-parser@7.29.7': {} @@ -8819,16 +8845,16 @@ snapshots: '@babel/helpers@7.29.7': dependencies: '@babel/template': 7.29.7 - '@babel/types': 7.29.7 + '@babel/types': 7.29.8 '@babel/helpers@8.0.0': dependencies: '@babel/template': 8.0.0 '@babel/types': 8.0.4 - '@babel/parser@7.29.7': + '@babel/parser@7.29.8': dependencies: - '@babel/types': 7.29.7 + '@babel/types': 7.29.8 '@babel/parser@8.0.4': dependencies: @@ -9246,8 +9272,8 @@ snapshots: '@babel/template@7.29.7': dependencies: '@babel/code-frame': 7.29.7 - '@babel/parser': 7.29.7 - '@babel/types': 7.29.7 + '@babel/parser': 7.29.8 + '@babel/types': 7.29.8 '@babel/template@8.0.0': dependencies: @@ -9255,14 +9281,14 @@ snapshots: '@babel/parser': 8.0.4 '@babel/types': 8.0.4 - '@babel/traverse@7.29.7(supports-color@11.0.0)': + '@babel/traverse@7.29.8(supports-color@11.0.0)': dependencies: '@babel/code-frame': 7.29.7 - '@babel/generator': 7.29.7 + '@babel/generator': 7.29.8 '@babel/helper-globals': 7.29.7 - '@babel/parser': 7.29.7 + '@babel/parser': 7.29.8 '@babel/template': 7.29.7 - '@babel/types': 7.29.7 + '@babel/types': 7.29.8 debug: 4.4.3(supports-color@11.0.0) transitivePeerDependencies: - supports-color @@ -9277,7 +9303,7 @@ snapshots: '@babel/types': 8.0.4 obug: 2.1.4 - '@babel/types@7.29.7': + '@babel/types@7.29.8': dependencies: '@babel/helper-string-parser': 7.29.7 '@babel/helper-validator-identifier': 7.29.7 @@ -9479,7 +9505,7 @@ snapshots: dependencies: '@eslint/object-schema': 3.0.5 debug: 4.4.3(supports-color@11.0.0) - minimatch: 10.2.5 + minimatch: 10.2.6 transitivePeerDependencies: - supports-color @@ -9499,7 +9525,7 @@ snapshots: globals: 14.0.0 ignore: 5.3.2 import-fresh: 3.3.1 - js-yaml: 4.3.0 + js-yaml: 4.3.1 minimatch: 3.1.5 strip-json-comments: 3.1.1 transitivePeerDependencies: @@ -9855,11 +9881,11 @@ snapshots: transitivePeerDependencies: - supports-color - '@google-cloud/precise-date@5.1.0': {} + '@google-cloud/precise-date@5.2.0': {} '@google-cloud/projectify@4.0.0': {} - '@google-cloud/projectify@5.1.0': {} + '@google-cloud/projectify@5.2.0': {} '@google-cloud/promisify@4.1.0': {} @@ -9868,8 +9894,8 @@ snapshots: '@google-cloud/spanner@8.0.0(supports-color@11.0.0)': dependencies: '@google-cloud/common': 6.1.0(supports-color@11.0.0) - '@google-cloud/precise-date': 5.1.0 - '@google-cloud/projectify': 5.1.0 + '@google-cloud/precise-date': 5.2.0 + '@google-cloud/projectify': 5.2.0 '@google-cloud/promisify': 5.1.0 '@grpc/proto-loader': 0.7.15 '@opentelemetry/api': 1.9.1 @@ -9940,9 +9966,9 @@ snapshots: '@harperfast/extended-iterable@1.0.3': optional: true - '@hono/node-server@1.19.17(hono@4.12.32)': + '@hono/node-server@1.19.17(hono@4.12.34)': dependencies: - hono: 4.12.32 + hono: 4.12.34 '@humanfs/core@0.19.2': dependencies: @@ -9962,6 +9988,15 @@ snapshots: '@inquirer/ansi@2.0.7': {} + '@inquirer/checkbox@5.2.1(@types/node@22.20.1)': + dependencies: + '@inquirer/ansi': 2.0.7 + '@inquirer/core': 11.2.1(@types/node@22.20.1) + '@inquirer/figures': 2.0.7 + '@inquirer/type': 4.0.7(@types/node@22.20.1) + optionalDependencies: + '@types/node': 22.20.1 + '@inquirer/checkbox@5.2.1(@types/node@24.13.3)': dependencies: '@inquirer/ansi': 2.0.7 @@ -9971,6 +10006,13 @@ snapshots: optionalDependencies: '@types/node': 24.13.3 + '@inquirer/confirm@6.1.1(@types/node@22.20.1)': + dependencies: + '@inquirer/core': 11.2.1(@types/node@22.20.1) + '@inquirer/type': 4.0.7(@types/node@22.20.1) + optionalDependencies: + '@types/node': 22.20.1 + '@inquirer/confirm@6.1.1(@types/node@24.13.3)': dependencies: '@inquirer/core': 11.2.1(@types/node@24.13.3) @@ -9978,6 +10020,18 @@ snapshots: optionalDependencies: '@types/node': 24.13.3 + '@inquirer/core@11.2.1(@types/node@22.20.1)': + dependencies: + '@inquirer/ansi': 2.0.7 + '@inquirer/figures': 2.0.7 + '@inquirer/type': 4.0.7(@types/node@22.20.1) + cli-width: 4.1.0 + fast-wrap-ansi: 0.2.2 + mute-stream: 3.0.0 + signal-exit: 4.1.0 + optionalDependencies: + '@types/node': 22.20.1 + '@inquirer/core@11.2.1(@types/node@24.13.3)': dependencies: '@inquirer/ansi': 2.0.7 @@ -9990,6 +10044,14 @@ snapshots: optionalDependencies: '@types/node': 24.13.3 + '@inquirer/editor@5.2.2(@types/node@22.20.1)': + dependencies: + '@inquirer/core': 11.2.1(@types/node@22.20.1) + '@inquirer/external-editor': 3.0.3(@types/node@22.20.1) + '@inquirer/type': 4.0.7(@types/node@22.20.1) + optionalDependencies: + '@types/node': 22.20.1 + '@inquirer/editor@5.2.2(@types/node@24.13.3)': dependencies: '@inquirer/core': 11.2.1(@types/node@24.13.3) @@ -9998,6 +10060,13 @@ snapshots: optionalDependencies: '@types/node': 24.13.3 + '@inquirer/expand@5.1.1(@types/node@22.20.1)': + dependencies: + '@inquirer/core': 11.2.1(@types/node@22.20.1) + '@inquirer/type': 4.0.7(@types/node@22.20.1) + optionalDependencies: + '@types/node': 22.20.1 + '@inquirer/expand@5.1.1(@types/node@24.13.3)': dependencies: '@inquirer/core': 11.2.1(@types/node@24.13.3) @@ -10005,6 +10074,13 @@ snapshots: optionalDependencies: '@types/node': 24.13.3 + '@inquirer/external-editor@3.0.3(@types/node@22.20.1)': + dependencies: + chardet: 2.2.0 + iconv-lite: 0.7.3 + optionalDependencies: + '@types/node': 22.20.1 + '@inquirer/external-editor@3.0.3(@types/node@24.13.3)': dependencies: chardet: 2.2.0 @@ -10014,6 +10090,13 @@ snapshots: '@inquirer/figures@2.0.7': {} + '@inquirer/input@5.1.2(@types/node@22.20.1)': + dependencies: + '@inquirer/core': 11.2.1(@types/node@22.20.1) + '@inquirer/type': 4.0.7(@types/node@22.20.1) + optionalDependencies: + '@types/node': 22.20.1 + '@inquirer/input@5.1.2(@types/node@24.13.3)': dependencies: '@inquirer/core': 11.2.1(@types/node@24.13.3) @@ -10021,6 +10104,13 @@ snapshots: optionalDependencies: '@types/node': 24.13.3 + '@inquirer/number@4.1.1(@types/node@22.20.1)': + dependencies: + '@inquirer/core': 11.2.1(@types/node@22.20.1) + '@inquirer/type': 4.0.7(@types/node@22.20.1) + optionalDependencies: + '@types/node': 22.20.1 + '@inquirer/number@4.1.1(@types/node@24.13.3)': dependencies: '@inquirer/core': 11.2.1(@types/node@24.13.3) @@ -10028,6 +10118,14 @@ snapshots: optionalDependencies: '@types/node': 24.13.3 + '@inquirer/password@5.1.1(@types/node@22.20.1)': + dependencies: + '@inquirer/ansi': 2.0.7 + '@inquirer/core': 11.2.1(@types/node@22.20.1) + '@inquirer/type': 4.0.7(@types/node@22.20.1) + optionalDependencies: + '@types/node': 22.20.1 + '@inquirer/password@5.1.1(@types/node@24.13.3)': dependencies: '@inquirer/ansi': 2.0.7 @@ -10036,6 +10134,21 @@ snapshots: optionalDependencies: '@types/node': 24.13.3 + '@inquirer/prompts@8.5.2(@types/node@22.20.1)': + dependencies: + '@inquirer/checkbox': 5.2.1(@types/node@22.20.1) + '@inquirer/confirm': 6.1.1(@types/node@22.20.1) + '@inquirer/editor': 5.2.2(@types/node@22.20.1) + '@inquirer/expand': 5.1.1(@types/node@22.20.1) + '@inquirer/input': 5.1.2(@types/node@22.20.1) + '@inquirer/number': 4.1.1(@types/node@22.20.1) + '@inquirer/password': 5.1.1(@types/node@22.20.1) + '@inquirer/rawlist': 5.3.1(@types/node@22.20.1) + '@inquirer/search': 4.2.1(@types/node@22.20.1) + '@inquirer/select': 5.2.1(@types/node@22.20.1) + optionalDependencies: + '@types/node': 22.20.1 + '@inquirer/prompts@8.5.2(@types/node@24.13.3)': dependencies: '@inquirer/checkbox': 5.2.1(@types/node@24.13.3) @@ -10051,6 +10164,13 @@ snapshots: optionalDependencies: '@types/node': 24.13.3 + '@inquirer/rawlist@5.3.1(@types/node@22.20.1)': + dependencies: + '@inquirer/core': 11.2.1(@types/node@22.20.1) + '@inquirer/type': 4.0.7(@types/node@22.20.1) + optionalDependencies: + '@types/node': 22.20.1 + '@inquirer/rawlist@5.3.1(@types/node@24.13.3)': dependencies: '@inquirer/core': 11.2.1(@types/node@24.13.3) @@ -10058,6 +10178,14 @@ snapshots: optionalDependencies: '@types/node': 24.13.3 + '@inquirer/search@4.2.1(@types/node@22.20.1)': + dependencies: + '@inquirer/core': 11.2.1(@types/node@22.20.1) + '@inquirer/figures': 2.0.7 + '@inquirer/type': 4.0.7(@types/node@22.20.1) + optionalDependencies: + '@types/node': 22.20.1 + '@inquirer/search@4.2.1(@types/node@24.13.3)': dependencies: '@inquirer/core': 11.2.1(@types/node@24.13.3) @@ -10066,6 +10194,15 @@ snapshots: optionalDependencies: '@types/node': 24.13.3 + '@inquirer/select@5.2.1(@types/node@22.20.1)': + dependencies: + '@inquirer/ansi': 2.0.7 + '@inquirer/core': 11.2.1(@types/node@22.20.1) + '@inquirer/figures': 2.0.7 + '@inquirer/type': 4.0.7(@types/node@22.20.1) + optionalDependencies: + '@types/node': 22.20.1 + '@inquirer/select@5.2.1(@types/node@24.13.3)': dependencies: '@inquirer/ansi': 2.0.7 @@ -10075,6 +10212,10 @@ snapshots: optionalDependencies: '@types/node': 24.13.3 + '@inquirer/type@4.0.7(@types/node@22.20.1)': + optionalDependencies: + '@types/node': 22.20.1 + '@inquirer/type@4.0.7(@types/node@24.13.3)': optionalDependencies: '@types/node': 24.13.3 @@ -10248,10 +10389,10 @@ snapshots: '@leichtgewicht/ip-codec@2.0.5': {} - '@listr2/prompt-adapter-inquirer@4.2.4(@inquirer/prompts@8.5.2(@types/node@24.13.3))(@types/node@24.13.3)(listr2@10.2.2)': + '@listr2/prompt-adapter-inquirer@4.2.4(@inquirer/prompts@8.5.2(@types/node@22.20.1))(@types/node@22.20.1)(listr2@10.2.2)': dependencies: - '@inquirer/prompts': 8.5.2(@types/node@24.13.3) - '@inquirer/type': 4.0.7(@types/node@24.13.3) + '@inquirer/prompts': 8.5.2(@types/node@22.20.1) + '@inquirer/type': 4.0.7(@types/node@22.20.1) listr2: 10.2.2 transitivePeerDependencies: - '@types/node' @@ -10279,7 +10420,7 @@ snapshots: '@modelcontextprotocol/sdk@1.29.0(supports-color@11.0.0)(zod@4.4.3)': dependencies: - '@hono/node-server': 1.19.17(hono@4.12.32) + '@hono/node-server': 1.19.17(hono@4.12.34) ajv: 8.20.0 ajv-formats: 3.0.1(ajv@8.20.0) content-type: 1.0.5 @@ -10289,8 +10430,8 @@ snapshots: eventsource-parser: 3.1.0 express: 5.2.1(supports-color@11.0.0) express-rate-limit: 8.6.1(express@5.2.1(supports-color@11.0.0))(supports-color@11.0.0) - hono: 4.12.32 - jose: 6.2.4 + hono: 4.12.34 + jose: 6.2.7 json-schema-typed: 8.0.2 pkce-challenge: 5.0.1 raw-body: 3.0.2 @@ -10398,14 +10539,14 @@ snapshots: '@napi-rs/nice-win32-x64-msvc': 1.1.1 optional: true - '@napi-rs/wasm-runtime@1.1.6(@emnapi/core@1.11.1)(@emnapi/runtime@1.11.1)': + '@napi-rs/wasm-runtime@1.2.2(@emnapi/core@1.11.1)(@emnapi/runtime@1.11.1)': dependencies: '@emnapi/core': 1.11.1 '@emnapi/runtime': 1.11.1 '@tybys/wasm-util': 0.10.3 optional: true - '@napi-rs/wasm-runtime@1.1.6(@emnapi/core@1.11.2)(@emnapi/runtime@1.11.2)': + '@napi-rs/wasm-runtime@1.2.2(@emnapi/core@1.11.2)(@emnapi/runtime@1.11.2)': dependencies: '@emnapi/core': 1.11.2 '@emnapi/runtime': 1.11.2 @@ -10428,36 +10569,36 @@ snapshots: '@octokit/auth-app@8.2.0': dependencies: - '@octokit/auth-oauth-app': 9.0.3 - '@octokit/auth-oauth-user': 6.0.2 - '@octokit/request': 10.0.11 - '@octokit/request-error': 7.1.0 + '@octokit/auth-oauth-app': 9.0.4 + '@octokit/auth-oauth-user': 6.0.3 + '@octokit/request': 10.0.13 + '@octokit/request-error': 7.1.1 '@octokit/types': 16.0.0 toad-cache: 3.7.4 universal-github-app-jwt: 2.2.2 universal-user-agent: 7.0.3 - '@octokit/auth-oauth-app@9.0.3': + '@octokit/auth-oauth-app@9.0.4': dependencies: - '@octokit/auth-oauth-device': 8.0.3 - '@octokit/auth-oauth-user': 6.0.2 - '@octokit/request': 10.0.11 - '@octokit/types': 16.0.0 + '@octokit/auth-oauth-device': 8.0.4 + '@octokit/auth-oauth-user': 6.0.3 + '@octokit/request': 10.0.13 + '@octokit/types': 17.0.0 universal-user-agent: 7.0.3 - '@octokit/auth-oauth-device@8.0.3': + '@octokit/auth-oauth-device@8.0.4': dependencies: - '@octokit/oauth-methods': 6.0.2 - '@octokit/request': 10.0.11 - '@octokit/types': 16.0.0 + '@octokit/oauth-methods': 6.0.3 + '@octokit/request': 10.0.13 + '@octokit/types': 17.0.0 universal-user-agent: 7.0.3 - '@octokit/auth-oauth-user@6.0.2': + '@octokit/auth-oauth-user@6.0.3': dependencies: - '@octokit/auth-oauth-device': 8.0.3 - '@octokit/oauth-methods': 6.0.2 - '@octokit/request': 10.0.11 - '@octokit/types': 16.0.0 + '@octokit/auth-oauth-device': 8.0.4 + '@octokit/oauth-methods': 6.0.3 + '@octokit/request': 10.0.13 + '@octokit/types': 17.0.0 universal-user-agent: 7.0.3 '@octokit/auth-token@6.0.0': {} @@ -10466,15 +10607,15 @@ snapshots: dependencies: '@octokit/auth-token': 6.0.0 '@octokit/graphql': 9.0.3 - '@octokit/request': 10.0.11 - '@octokit/request-error': 7.1.0 + '@octokit/request': 10.0.13 + '@octokit/request-error': 7.1.1 '@octokit/types': 16.0.0 before-after-hook: 4.0.0 universal-user-agent: 7.0.3 - '@octokit/endpoint@11.0.3': + '@octokit/endpoint@11.0.4': dependencies: - '@octokit/types': 16.0.0 + '@octokit/types': 17.0.0 universal-user-agent: 7.0.3 '@octokit/graphql-schema@15.26.1': @@ -10484,26 +10625,33 @@ snapshots: '@octokit/graphql@9.0.3': dependencies: - '@octokit/request': 10.0.11 + '@octokit/request': 10.0.13 '@octokit/types': 16.0.0 universal-user-agent: 7.0.3 '@octokit/oauth-authorization-url@8.0.0': {} - '@octokit/oauth-methods@6.0.2': + '@octokit/oauth-methods@6.0.3': dependencies: '@octokit/oauth-authorization-url': 8.0.0 - '@octokit/request': 10.0.11 - '@octokit/request-error': 7.1.0 - '@octokit/types': 16.0.0 + '@octokit/request': 10.0.13 + '@octokit/request-error': 7.1.1 + '@octokit/types': 17.0.0 '@octokit/openapi-types@27.0.0': {} + '@octokit/openapi-types@28.0.0': {} + '@octokit/plugin-paginate-rest@14.0.0(@octokit/core@7.0.6)': dependencies: '@octokit/core': 7.0.6 '@octokit/types': 16.0.0 + '@octokit/plugin-paginate-rest@15.0.0(@octokit/core@7.0.6)': + dependencies: + '@octokit/core': 7.0.6 + '@octokit/types': 17.0.0 + '@octokit/plugin-request-log@6.0.0(@octokit/core@7.0.6)': dependencies: '@octokit/core': 7.0.6 @@ -10513,15 +10661,24 @@ snapshots: '@octokit/core': 7.0.6 '@octokit/types': 16.0.0 + '@octokit/plugin-rest-endpoint-methods@18.0.0(@octokit/core@7.0.6)': + dependencies: + '@octokit/core': 7.0.6 + '@octokit/types': 17.0.0 + '@octokit/request-error@7.1.0': dependencies: '@octokit/types': 16.0.0 - '@octokit/request@10.0.11': + '@octokit/request-error@7.1.1': dependencies: - '@octokit/endpoint': 11.0.3 - '@octokit/request-error': 7.1.0 - '@octokit/types': 16.0.0 + '@octokit/types': 17.0.0 + + '@octokit/request@10.0.13': + dependencies: + '@octokit/endpoint': 11.0.4 + '@octokit/request-error': 7.1.1 + '@octokit/types': 17.0.0 content-type: 2.0.0 json-with-bigint: 3.5.10 universal-user-agent: 7.0.3 @@ -10537,6 +10694,10 @@ snapshots: dependencies: '@octokit/openapi-types': 27.0.0 + '@octokit/types@17.0.0': + dependencies: + '@octokit/openapi-types': 28.0.0 + '@open-draft/deferred-promise@2.2.0': {} '@open-draft/logger@0.3.0': @@ -10611,7 +10772,7 @@ snapshots: dependencies: '@emnapi/core': 1.11.2 '@emnapi/runtime': 1.11.2 - '@napi-rs/wasm-runtime': 1.1.6(@emnapi/core@1.11.2)(@emnapi/runtime@1.11.2) + '@napi-rs/wasm-runtime': 1.2.2(@emnapi/core@1.11.2)(@emnapi/runtime@1.11.2) optional: true '@oxc-parser/binding-win32-arm64-msvc@0.142.0': @@ -10906,14 +11067,14 @@ snapshots: dependencies: '@emnapi/core': 1.11.1 '@emnapi/runtime': 1.11.1 - '@napi-rs/wasm-runtime': 1.1.6(@emnapi/core@1.11.1)(@emnapi/runtime@1.11.1) + '@napi-rs/wasm-runtime': 1.2.2(@emnapi/core@1.11.1)(@emnapi/runtime@1.11.1) optional: true '@rolldown/binding-wasm32-wasi@1.2.0': dependencies: '@emnapi/core': 1.11.2 '@emnapi/runtime': 1.11.2 - '@napi-rs/wasm-runtime': 1.1.6(@emnapi/core@1.11.2)(@emnapi/runtime@1.11.2) + '@napi-rs/wasm-runtime': 1.2.2(@emnapi/core@1.11.2)(@emnapi/runtime@1.11.2) optional: true '@rolldown/binding-win32-arm64-msvc@1.1.5': @@ -11090,24 +11251,24 @@ snapshots: '@types/babel__core@7.20.5': dependencies: - '@babel/parser': 7.29.7 - '@babel/types': 7.29.7 + '@babel/parser': 7.29.8 + '@babel/types': 7.29.8 '@types/babel__generator': 7.27.0 '@types/babel__template': 7.4.4 '@types/babel__traverse': 7.28.0 '@types/babel__generator@7.27.0': dependencies: - '@babel/types': 7.29.7 + '@babel/types': 7.29.8 '@types/babel__template@7.4.4': dependencies: - '@babel/parser': 7.29.7 - '@babel/types': 7.29.7 + '@babel/parser': 7.29.8 + '@babel/types': 7.29.8 '@types/babel__traverse@7.28.0': dependencies: - '@babel/types': 7.29.7 + '@babel/types': 7.29.8 '@types/big.js@6.2.2': {} @@ -11170,7 +11331,7 @@ snapshots: '@types/range-parser': 1.2.7 '@types/send': 1.2.1 - '@types/express-serve-static-core@5.1.2': + '@types/express-serve-static-core@5.1.3': dependencies: '@types/node': 22.20.1 '@types/qs': 6.15.1 @@ -11187,7 +11348,7 @@ snapshots: '@types/express@5.0.6': dependencies: '@types/body-parser': 1.19.6 - '@types/express-serve-static-core': 5.1.2 + '@types/express-serve-static-core': 5.1.3 '@types/serve-static': 2.2.0 '@types/folder-hash@4.0.4': {} @@ -11244,7 +11405,7 @@ snapshots: - uglify-js - webpack-cli - '@types/lodash@4.17.24': {} + '@types/lodash@4.17.25': {} '@types/micromatch@2.3.35': dependencies: @@ -11296,6 +11457,8 @@ snapshots: '@types/semver@7.7.1': {} + '@types/semver@7.8.0': {} + '@types/send@0.17.6': dependencies: '@types/mime': 1.3.5 @@ -11420,7 +11583,7 @@ snapshots: '@typescript-eslint/types': 8.64.0 '@typescript-eslint/visitor-keys': 8.64.0 debug: 4.4.3(supports-color@11.0.0) - minimatch: 10.2.5 + minimatch: 10.2.6 semver: 7.8.5 tinyglobby: 0.2.17 ts-api-utils: 2.5.0(typescript@6.0.3) @@ -11474,14 +11637,14 @@ snapshots: process-warning: 1.0.0 semver: 7.7.4 - '@verdaccio/core@8.2.0': + '@verdaccio/core@8.2.1': dependencies: - ajv: 8.18.0 + ajv: 8.20.0 http-errors: 2.0.1 http-status-codes: 2.3.0 minimatch: 10.2.5 process-warning: 1.0.0 - semver: 7.7.4 + semver: 7.8.5 '@verdaccio/file-locking@13.0.1': dependencies: @@ -11615,9 +11778,9 @@ snapshots: lodash: 4.18.1 minimatch: 7.4.9 - '@vitejs/plugin-basic-ssl@2.3.0(vite@8.1.5(@types/node@24.13.3)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(terser@5.49.0)(tsx@4.23.1)(yaml@2.9.0))': + '@vitejs/plugin-basic-ssl@2.3.0(vite@8.1.5(@types/node@22.20.1)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(terser@5.49.0)(tsx@4.23.1)(yaml@2.9.0))': dependencies: - vite: 8.1.5(@types/node@24.13.3)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(terser@5.49.0)(tsx@4.23.1)(yaml@2.9.0) + vite: 8.1.5(@types/node@22.20.1)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(terser@5.49.0)(tsx@4.23.1)(yaml@2.9.0) '@vitest/coverage-v8@4.1.10(vitest@4.1.10)': dependencies: @@ -11627,11 +11790,11 @@ snapshots: istanbul-lib-coverage: 3.2.2 istanbul-lib-report: 3.0.1 istanbul-reports: 3.2.0 - magicast: 0.5.3 + magicast: 0.5.4 obug: 2.1.4 std-env: 4.2.0 - tinyrainbow: 3.1.0 - vitest: 4.1.10(@opentelemetry/api@1.9.1)(@types/node@24.13.3)(@vitest/coverage-v8@4.1.10)(esbuild@0.28.1)(jiti@2.7.0)(jsdom@29.1.1)(less@4.6.7)(sass@1.101.0)(terser@5.49.0)(tsx@4.23.1)(yaml@2.9.0) + tinyrainbow: 3.1.1 + vitest: 4.1.10(@opentelemetry/api@1.9.1)(@types/node@22.20.1)(@vitest/coverage-v8@4.1.10)(esbuild@0.28.1)(jiti@2.7.0)(jsdom@29.1.1)(less@4.6.7)(sass@1.101.0)(terser@5.49.0)(tsx@4.23.1)(yaml@2.9.0) '@vitest/expect@4.1.10': dependencies: @@ -11640,19 +11803,19 @@ snapshots: '@vitest/spy': 4.1.10 '@vitest/utils': 4.1.10 chai: 6.2.2 - tinyrainbow: 3.1.0 + tinyrainbow: 3.1.1 - '@vitest/mocker@4.1.10(vite@8.1.5(@types/node@24.13.3)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(terser@5.49.0)(tsx@4.23.1)(yaml@2.9.0))': + '@vitest/mocker@4.1.10(vite@8.1.5(@types/node@22.20.1)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(terser@5.49.0)(tsx@4.23.1)(yaml@2.9.0))': dependencies: '@vitest/spy': 4.1.10 estree-walker: 3.0.3 magic-string: 0.30.21 optionalDependencies: - vite: 8.1.5(@types/node@24.13.3)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(terser@5.49.0)(tsx@4.23.1)(yaml@2.9.0) + vite: 8.1.5(@types/node@22.20.1)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(terser@5.49.0)(tsx@4.23.1)(yaml@2.9.0) '@vitest/pretty-format@4.1.10': dependencies: - tinyrainbow: 3.1.0 + tinyrainbow: 3.1.1 '@vitest/runner@4.1.10': dependencies: @@ -11672,7 +11835,7 @@ snapshots: dependencies: '@vitest/pretty-format': 4.1.10 convert-source-map: 2.0.0 - tinyrainbow: 3.1.0 + tinyrainbow: 3.1.1 '@webassemblyjs/ast@1.14.1': dependencies: @@ -11777,11 +11940,11 @@ snapshots: mime-types: 3.0.2 negotiator: 1.0.0 - acorn-jsx@5.3.2(acorn@8.17.0): + acorn-jsx@5.3.2(acorn@8.18.0): dependencies: - acorn: 8.17.0 + acorn: 8.18.0 - acorn@8.17.0: {} + acorn@8.18.0: {} adjust-sourcemap-loader@4.0.0: dependencies: @@ -11821,14 +11984,14 @@ snapshots: ajv@8.18.0: dependencies: fast-deep-equal: 3.1.3 - fast-uri: 3.1.4 + fast-uri: 3.1.5 json-schema-traverse: 1.0.0 require-from-string: 2.0.2 ajv@8.20.0: dependencies: fast-deep-equal: 3.1.3 - fast-uri: 3.1.4 + fast-uri: 3.1.5 json-schema-traverse: 1.0.0 require-from-string: 2.0.2 @@ -11955,13 +12118,13 @@ snapshots: atomic-sleep@1.0.0: {} - autoprefixer@10.5.4(postcss@8.5.19): + autoprefixer@10.5.4(postcss@8.5.25): dependencies: browserslist: 4.28.7 caniuse-lite: 1.0.30001806 fraction.js: 5.3.4 picocolors: 1.1.1 - postcss: 8.5.19 + postcss: 8.5.25 postcss-value-parser: 4.2.0 available-typed-arrays@1.0.7: @@ -11974,12 +12137,12 @@ snapshots: b4a@1.8.1: {} - babel-loader@10.1.1(@babel/core@8.0.1)(webpack@5.109.2(esbuild@0.28.1)(lightningcss@1.33.0)(postcss@8.5.19)(uglify-js@3.19.3)): + babel-loader@10.1.1(@babel/core@8.0.1)(webpack@5.109.2(esbuild@0.28.1)(lightningcss@1.33.0)(postcss@8.5.25)(uglify-js@3.19.3)): dependencies: '@babel/core': 8.0.1 find-up: 5.0.0 optionalDependencies: - webpack: 5.109.2(esbuild@0.28.1)(lightningcss@1.33.0)(postcss@8.5.19)(uglify-js@3.19.3) + webpack: 5.109.2(esbuild@0.28.1)(lightningcss@1.33.0)(postcss@8.5.25)(uglify-js@3.19.3) babel-plugin-polyfill-corejs3@1.0.0(@babel/core@8.0.1): dependencies: @@ -11998,7 +12161,7 @@ snapshots: bare-events: 2.9.1 bare-path: 3.1.1 bare-stream: 2.13.3(bare-events@2.9.1) - bare-url: 2.4.6 + bare-url: 2.4.7 fast-fifo: 1.3.2 transitivePeerDependencies: - bare-abort-controller @@ -12016,7 +12179,7 @@ snapshots: transitivePeerDependencies: - react-native-b4a - bare-url@2.4.6: + bare-url@2.4.7: dependencies: bare-path: 3.1.1 @@ -12024,7 +12187,7 @@ snapshots: base64id@2.0.0: {} - baseline-browser-mapping@2.11.4: {} + baseline-browser-mapping@2.11.11: {} batch@0.6.1: {} @@ -12042,9 +12205,9 @@ snapshots: domhandler: 5.0.3 htmlparser2: 10.1.0 picocolors: 1.1.1 - postcss: 8.5.19 + postcss: 8.5.25 postcss-media-query-parser: 0.2.3 - postcss-safe-parser: 7.0.1(postcss@8.5.19) + postcss-safe-parser: 7.0.1(postcss@8.5.25) before-after-hook@4.0.0: {} @@ -12091,23 +12254,23 @@ snapshots: transitivePeerDependencies: - supports-color - bonjour-service@1.4.3: + bonjour-service@1.4.4: dependencies: fast-deep-equal: 3.1.3 multicast-dns: 7.2.5 boolbase@1.0.0: {} - brace-expansion@1.1.16: + brace-expansion@1.1.18: dependencies: balanced-match: 1.0.2 concat-map: 0.0.1 - brace-expansion@2.1.2: + brace-expansion@2.1.4: dependencies: balanced-match: 1.0.2 - brace-expansion@5.0.8: + brace-expansion@5.0.9: dependencies: balanced-match: 4.0.4 @@ -12179,9 +12342,9 @@ snapshots: browserslist@4.28.7: dependencies: - baseline-browser-mapping: 2.11.4 + baseline-browser-mapping: 2.11.11 caniuse-lite: 1.0.30001806 - electron-to-chromium: 1.5.396 + electron-to-chromium: 1.5.399 node-releases: 2.0.51 update-browserslist-db: 1.2.3(browserslist@4.28.7) @@ -12432,14 +12595,14 @@ snapshots: dependencies: is-what: 4.1.16 - copy-webpack-plugin@14.0.0(webpack@5.109.2(esbuild@0.28.1)(lightningcss@1.33.0)(postcss@8.5.19)(uglify-js@3.19.3)): + copy-webpack-plugin@14.0.0(webpack@5.109.2(esbuild@0.28.1)(lightningcss@1.33.0)(postcss@8.5.25)(uglify-js@3.19.3)): dependencies: glob-parent: 6.0.2 normalize-path: 3.0.0 schema-utils: 4.3.3 serialize-javascript: 7.0.7 tinyglobby: 0.2.17 - webpack: 5.109.2(esbuild@0.28.1)(lightningcss@1.33.0)(postcss@8.5.19)(uglify-js@3.19.3) + webpack: 5.109.2(esbuild@0.28.1)(lightningcss@1.33.0)(postcss@8.5.25)(uglify-js@3.19.3) core-js-compat@3.49.0: dependencies: @@ -12458,7 +12621,7 @@ snapshots: dependencies: env-paths: 2.2.1 import-fresh: 3.3.1 - js-yaml: 4.3.0 + js-yaml: 4.3.1 parse-json: 5.2.0 optionalDependencies: typescript: 6.0.3 @@ -12469,18 +12632,18 @@ snapshots: shebang-command: 2.0.0 which: 2.0.2 - css-loader@7.1.4(webpack@5.109.2(esbuild@0.28.1)(lightningcss@1.33.0)(postcss@8.5.19)(uglify-js@3.19.3)): + css-loader@7.1.4(webpack@5.109.2(esbuild@0.28.1)(lightningcss@1.33.0)(postcss@8.5.25)(uglify-js@3.19.3)): dependencies: - icss-utils: 5.1.0(postcss@8.5.19) - postcss: 8.5.19 - postcss-modules-extract-imports: 3.1.0(postcss@8.5.19) - postcss-modules-local-by-default: 4.2.0(postcss@8.5.19) - postcss-modules-scope: 3.2.1(postcss@8.5.19) - postcss-modules-values: 4.0.0(postcss@8.5.19) + icss-utils: 5.1.0(postcss@8.5.25) + postcss: 8.5.25 + postcss-modules-extract-imports: 3.1.0(postcss@8.5.25) + postcss-modules-local-by-default: 4.2.0(postcss@8.5.25) + postcss-modules-scope: 3.2.1(postcss@8.5.25) + postcss-modules-values: 4.0.0(postcss@8.5.25) postcss-value-parser: 4.2.0 semver: 7.8.5 optionalDependencies: - webpack: 5.109.2(esbuild@0.28.1)(lightningcss@1.33.0)(postcss@8.5.19)(uglify-js@3.19.3) + webpack: 5.109.2(esbuild@0.28.1)(lightningcss@1.33.0)(postcss@8.5.25)(uglify-js@3.19.3) css-select@6.0.0: dependencies: @@ -12695,7 +12858,7 @@ snapshots: ejs@6.0.1: {} - electron-to-chromium@1.5.396: {} + electron-to-chromium@1.5.399: {} emoji-regex@10.6.0: {} @@ -12750,7 +12913,7 @@ snapshots: - supports-color - utf-8-validate - enhanced-resolve@5.24.4: + enhanced-resolve@5.24.5: dependencies: graceful-fs: 4.2.11 tapable: 2.3.3 @@ -13012,7 +13175,7 @@ snapshots: imurmurhash: 0.1.4 is-glob: 4.0.3 json-stable-stringify-without-jsonify: 1.0.1 - minimatch: 10.2.5 + minimatch: 10.2.6 natural-compare: 1.4.0 optionator: 0.9.4 optionalDependencies: @@ -13022,14 +13185,14 @@ snapshots: espree@10.4.0: dependencies: - acorn: 8.17.0 - acorn-jsx: 5.3.2(acorn@8.17.0) + acorn: 8.18.0 + acorn-jsx: 5.3.2(acorn@8.18.0) eslint-visitor-keys: 4.2.1 espree@11.2.0: dependencies: - acorn: 8.17.0 - acorn-jsx: 5.3.2(acorn@8.17.0) + acorn: 8.18.0 + acorn-jsx: 5.3.2(acorn@8.18.0) eslint-visitor-keys: 5.0.1 esquery@1.7.0: @@ -13084,7 +13247,7 @@ snapshots: dependencies: debug: 4.4.3(supports-color@11.0.0) express: 5.2.1(supports-color@11.0.0) - ip-address: 10.3.1 + ip-address: 10.4.0 transitivePeerDependencies: - supports-color @@ -13219,7 +13382,7 @@ snapshots: dependencies: fast-string-truncated-width: 3.0.3 - fast-uri@3.1.4: {} + fast-uri@3.1.5: {} fast-wrap-ansi@0.2.2: dependencies: @@ -13344,12 +13507,12 @@ snapshots: flat-cache@4.0.1: dependencies: - flatted: 3.4.3 + flatted: 3.4.4 keyv: 4.5.4 flat@5.0.2: {} - flatted@3.4.3: {} + flatted@3.4.4: {} folder-hash@4.1.3(supports-color@11.0.0): dependencies: @@ -13530,7 +13693,7 @@ snapshots: glob@13.0.6: dependencies: - minimatch: 10.2.5 + minimatch: 10.2.6 minipass: 7.1.3 path-scurry: 2.0.2 @@ -13682,7 +13845,7 @@ snapshots: dependencies: function-bind: 1.1.2 - hono@4.12.32: {} + hono@4.12.34: {} hosted-git-info@10.1.1: dependencies: @@ -13825,9 +13988,9 @@ snapshots: dependencies: safer-buffer: 2.1.2 - icss-utils@5.1.0(postcss@8.5.19): + icss-utils@5.1.0(postcss@8.5.25): dependencies: - postcss: 8.5.19 + postcss: 8.5.25 idb@7.1.1: {} @@ -13870,7 +14033,7 @@ snapshots: hasown: 2.0.4 side-channel: 1.1.1 - ip-address@10.3.1: {} + ip-address@10.4.0: {} ipaddr.js@1.9.1: {} @@ -14079,7 +14242,7 @@ snapshots: istanbul-lib-instrument@5.2.1(supports-color@11.0.0): dependencies: '@babel/core': 7.29.7(supports-color@11.0.0) - '@babel/parser': 7.29.7 + '@babel/parser': 7.29.8 '@istanbuljs/schema': 0.1.6 istanbul-lib-coverage: 3.2.2 semver: 6.3.1 @@ -14089,7 +14252,7 @@ snapshots: istanbul-lib-instrument@6.0.3(supports-color@11.0.0): dependencies: '@babel/core': 7.29.7(supports-color@11.0.0) - '@babel/parser': 7.29.7 + '@babel/parser': 7.29.8 '@istanbuljs/schema': 0.1.6 istanbul-lib-coverage: 3.2.2 semver: 7.8.5 @@ -14148,7 +14311,7 @@ snapshots: jiti@2.7.0: {} - jose@6.2.4: {} + jose@6.2.7: {} js-tokens@10.0.0: {} @@ -14158,7 +14321,7 @@ snapshots: dependencies: argparse: 2.0.1 - js-yaml@4.3.0: + js-yaml@4.3.1: dependencies: argparse: 2.0.1 @@ -14336,12 +14499,12 @@ snapshots: picocolors: 1.1.1 shell-quote: 1.10.0 - less-loader@13.0.0(less@4.6.7)(webpack@5.109.2(esbuild@0.28.1)(lightningcss@1.33.0)(postcss@8.5.19)(uglify-js@3.19.3)): + less-loader@13.0.0(less@4.6.7)(webpack@5.109.2(esbuild@0.28.1)(lightningcss@1.33.0)(postcss@8.5.25)(uglify-js@3.19.3)): dependencies: '@types/less': 3.0.8 less: 4.6.7 optionalDependencies: - webpack: 5.109.2(esbuild@0.28.1)(lightningcss@1.33.0)(postcss@8.5.19)(uglify-js@3.19.3) + webpack: 5.109.2(esbuild@0.28.1)(lightningcss@1.33.0)(postcss@8.5.25)(uglify-js@3.19.3) less@4.6.7: dependencies: @@ -14361,11 +14524,11 @@ snapshots: prelude-ls: 1.2.1 type-check: 0.4.0 - license-webpack-plugin@4.0.2(webpack@5.109.2(esbuild@0.28.1)(lightningcss@1.33.0)(postcss@8.5.19)(uglify-js@3.19.3)): + license-webpack-plugin@4.0.2(webpack@5.109.2(esbuild@0.28.1)(lightningcss@1.33.0)(postcss@8.5.25)(uglify-js@3.19.3)): dependencies: webpack-sources: 3.5.1 optionalDependencies: - webpack: 5.109.2(esbuild@0.28.1)(lightningcss@1.33.0)(postcss@8.5.19)(uglify-js@3.19.3) + webpack: 5.109.2(esbuild@0.28.1)(lightningcss@1.33.0)(postcss@8.5.25)(uglify-js@3.19.3) lightningcss-android-arm64@1.33.0: optional: true @@ -14505,7 +14668,7 @@ snapshots: dependencies: date-format: 4.0.14 debug: 4.4.3(supports-color@11.0.0) - flatted: 3.4.3 + flatted: 3.4.4 rfdc: 1.4.1 streamroller: 3.1.5(supports-color@11.0.0) transitivePeerDependencies: @@ -14541,10 +14704,10 @@ snapshots: dependencies: '@jridgewell/sourcemap-codec': 1.5.5 - magicast@0.5.3: + magicast@0.5.4: dependencies: - '@babel/parser': 7.29.7 - '@babel/types': 7.29.7 + '@babel/parser': 7.29.8 + '@babel/types': 7.29.8 source-map-js: 1.2.1 make-dir@4.0.0: @@ -14618,47 +14781,47 @@ snapshots: mimic-response@3.1.0: {} - mini-css-extract-plugin@2.10.2(webpack@5.109.2(esbuild@0.28.1)(lightningcss@1.33.0)(postcss@8.5.19)(uglify-js@3.19.3)): + mini-css-extract-plugin@2.10.2(webpack@5.109.2(esbuild@0.28.1)(lightningcss@1.33.0)(postcss@8.5.25)(uglify-js@3.19.3)): dependencies: schema-utils: 4.3.3 tapable: 2.3.3 - webpack: 5.109.2(esbuild@0.28.1)(lightningcss@1.33.0)(postcss@8.5.19)(uglify-js@3.19.3) + webpack: 5.109.2(esbuild@0.28.1)(lightningcss@1.33.0)(postcss@8.5.25)(uglify-js@3.19.3) minimalistic-assert@1.0.1: {} minimatch@10.2.5: dependencies: - brace-expansion: 5.0.8 + brace-expansion: 5.0.9 minimatch@10.2.6: dependencies: - brace-expansion: 5.0.8 + brace-expansion: 5.0.9 minimatch@3.1.5: dependencies: - brace-expansion: 1.1.16 + brace-expansion: 1.1.18 minimatch@7.4.9: dependencies: - brace-expansion: 2.1.2 + brace-expansion: 2.1.4 minimatch@9.0.9: dependencies: - brace-expansion: 2.1.2 + brace-expansion: 2.1.4 minimist@1.2.8: {} - minimizer-webpack-plugin@5.6.1(esbuild@0.28.1)(lightningcss@1.33.0)(postcss@8.5.19)(uglify-js@3.19.3)(webpack@5.109.2(esbuild@0.28.1)(lightningcss@1.33.0)(postcss@8.5.19)(uglify-js@3.19.3)): + minimizer-webpack-plugin@5.6.1(esbuild@0.28.1)(lightningcss@1.33.0)(postcss@8.5.25)(uglify-js@3.19.3)(webpack@5.109.2(esbuild@0.28.1)(lightningcss@1.33.0)(postcss@8.5.25)(uglify-js@3.19.3)): dependencies: '@jridgewell/trace-mapping': 0.3.31 jest-worker: 27.5.1 schema-utils: 4.3.3 terser: 5.49.0 - webpack: 5.109.2(esbuild@0.28.1)(lightningcss@1.33.0)(postcss@8.5.19)(uglify-js@3.19.3) + webpack: 5.109.2(esbuild@0.28.1)(lightningcss@1.33.0)(postcss@8.5.25)(uglify-js@3.19.3) optionalDependencies: esbuild: 0.28.1 lightningcss: 1.33.0 - postcss: 8.5.19 + postcss: 8.5.25 uglify-js: 3.19.3 minimizer-webpack-plugin@5.6.1(esbuild@0.28.1)(webpack@5.109.2(esbuild@0.28.1)): @@ -14717,7 +14880,7 @@ snapshots: dependencies: array-differ: 4.0.0 array-union: 3.0.1 - minimatch: 10.2.5 + minimatch: 10.2.6 mute-stream@3.0.0: {} @@ -14739,7 +14902,7 @@ snapshots: neo-async@2.6.2: {} - ng-packagr@22.1.0(@angular/compiler-cli@22.1.0(@angular/compiler@22.1.0)(typescript@6.0.3))(tslib@2.8.1)(typescript@6.0.3): + ng-packagr@22.1.1(@angular/compiler-cli@22.1.0(@angular/compiler@22.1.0)(typescript@6.0.3))(tslib@2.8.1)(typescript@6.0.3): dependencies: '@ampproject/remapping': 2.3.0 '@angular/compiler-cli': 22.1.0(@angular/compiler@22.1.0)(typescript@6.0.3) @@ -14757,7 +14920,7 @@ snapshots: less: 4.6.7 ora: 9.4.1 piscina: 5.2.0 - postcss: 8.5.19 + postcss: 8.5.25 rollup-plugin-dts: 6.4.1(rollup@4.62.2)(typescript@6.0.3) rxjs: 7.8.2 sass: 1.101.0 @@ -15098,7 +15261,7 @@ snapshots: on-exit-leak-free: 2.1.2 pino-abstract-transport: 2.0.0 pino-std-serializers: 7.1.0 - process-warning: 5.0.0 + process-warning: 5.1.0 quick-format-unescaped: 4.0.4 real-require: 0.2.0 safe-stable-stringify: 2.5.0 @@ -15133,43 +15296,43 @@ snapshots: possible-typed-array-names@1.1.0: {} - postcss-loader@8.2.1(postcss@8.5.19)(typescript@6.0.3)(webpack@5.109.2(esbuild@0.28.1)(lightningcss@1.33.0)(postcss@8.5.19)(uglify-js@3.19.3)): + postcss-loader@8.2.1(postcss@8.5.25)(typescript@6.0.3)(webpack@5.109.2(esbuild@0.28.1)(lightningcss@1.33.0)(postcss@8.5.25)(uglify-js@3.19.3)): dependencies: cosmiconfig: 9.0.2(typescript@6.0.3) jiti: 2.7.0 - postcss: 8.5.19 + postcss: 8.5.25 semver: 7.8.5 optionalDependencies: - webpack: 5.109.2(esbuild@0.28.1)(lightningcss@1.33.0)(postcss@8.5.19)(uglify-js@3.19.3) + webpack: 5.109.2(esbuild@0.28.1)(lightningcss@1.33.0)(postcss@8.5.25)(uglify-js@3.19.3) transitivePeerDependencies: - typescript postcss-media-query-parser@0.2.3: {} - postcss-modules-extract-imports@3.1.0(postcss@8.5.19): + postcss-modules-extract-imports@3.1.0(postcss@8.5.25): dependencies: - postcss: 8.5.19 + postcss: 8.5.25 - postcss-modules-local-by-default@4.2.0(postcss@8.5.19): + postcss-modules-local-by-default@4.2.0(postcss@8.5.25): dependencies: - icss-utils: 5.1.0(postcss@8.5.19) - postcss: 8.5.19 + icss-utils: 5.1.0(postcss@8.5.25) + postcss: 8.5.25 postcss-selector-parser: 7.1.4 postcss-value-parser: 4.2.0 - postcss-modules-scope@3.2.1(postcss@8.5.19): + postcss-modules-scope@3.2.1(postcss@8.5.25): dependencies: - postcss: 8.5.19 + postcss: 8.5.25 postcss-selector-parser: 7.1.4 - postcss-modules-values@4.0.0(postcss@8.5.19): + postcss-modules-values@4.0.0(postcss@8.5.25): dependencies: - icss-utils: 5.1.0(postcss@8.5.19) - postcss: 8.5.19 + icss-utils: 5.1.0(postcss@8.5.25) + postcss: 8.5.25 - postcss-safe-parser@7.0.1(postcss@8.5.19): + postcss-safe-parser@7.0.1(postcss@8.5.25): dependencies: - postcss: 8.5.19 + postcss: 8.5.25 postcss-selector-parser@7.1.4: dependencies: @@ -15178,7 +15341,7 @@ snapshots: postcss-value-parser@4.2.0: {} - postcss@8.5.19: + postcss@8.5.25: dependencies: nanoid: 3.3.16 picocolors: 1.1.1 @@ -15196,7 +15359,7 @@ snapshots: process-warning@1.0.0: {} - process-warning@5.0.0: {} + process-warning@5.1.0: {} process@0.11.10: {} @@ -15437,7 +15600,7 @@ snapshots: adjust-sourcemap-loader: 4.0.0 convert-source-map: 1.9.0 loader-utils: 2.0.4 - postcss: 8.5.19 + postcss: 8.5.25 source-map: 0.6.1 resolve@1.22.12: @@ -15644,10 +15807,10 @@ snapshots: dependencies: truncate-utf8-bytes: 1.0.2 - sass-loader@17.0.0(sass@1.101.0)(webpack@5.109.2(esbuild@0.28.1)(lightningcss@1.33.0)(postcss@8.5.19)(uglify-js@3.19.3)): + sass-loader@17.0.0(sass@1.101.0)(webpack@5.109.2(esbuild@0.28.1)(lightningcss@1.33.0)(postcss@8.5.25)(uglify-js@3.19.3)): optionalDependencies: sass: 1.101.0 - webpack: 5.109.2(esbuild@0.28.1)(lightningcss@1.33.0)(postcss@8.5.19)(uglify-js@3.19.3) + webpack: 5.109.2(esbuild@0.28.1)(lightningcss@1.33.0)(postcss@8.5.25)(uglify-js@3.19.3) sass@1.101.0: dependencies: @@ -15891,11 +16054,11 @@ snapshots: source-map-js@1.2.1: {} - source-map-loader@5.0.0(webpack@5.109.2(esbuild@0.28.1)(lightningcss@1.33.0)(postcss@8.5.19)(uglify-js@3.19.3)): + source-map-loader@5.0.0(webpack@5.109.2(esbuild@0.28.1)(lightningcss@1.33.0)(postcss@8.5.25)(uglify-js@3.19.3)): dependencies: iconv-lite: 0.6.3 source-map-js: 1.2.1 - webpack: 5.109.2(esbuild@0.28.1)(lightningcss@1.33.0)(postcss@8.5.19)(uglify-js@3.19.3) + webpack: 5.109.2(esbuild@0.28.1)(lightningcss@1.33.0)(postcss@8.5.25)(uglify-js@3.19.3) source-map-support@0.5.21: dependencies: @@ -16144,7 +16307,7 @@ snapshots: terser@5.49.0: dependencies: '@jridgewell/source-map': 0.3.11 - acorn: 8.17.0 + acorn: 8.18.0 commander: 2.20.3 source-map-support: 0.5.21 @@ -16179,26 +16342,26 @@ snapshots: tinybench@2.9.0: {} - tinyexec@1.2.4: {} + tinyexec@1.3.0: {} tinyglobby@0.2.17: dependencies: fdir: 6.5.0(picomatch@4.0.5) picomatch: 4.0.5 - tinyrainbow@3.1.0: {} + tinyrainbow@3.1.1: {} tldts-core@6.1.86: {} - tldts-core@7.4.9: {} + tldts-core@7.4.10: {} tldts@6.1.86: dependencies: tldts-core: 6.1.86 - tldts@7.4.9: + tldts@7.4.10: dependencies: - tldts-core: 7.4.9 + tldts-core: 7.4.10 tmp@0.2.7: {} @@ -16216,7 +16379,7 @@ snapshots: tough-cookie@6.0.2: dependencies: - tldts: 7.4.9 + tldts: 7.4.10 tr46@0.0.3: {} @@ -16427,9 +16590,9 @@ snapshots: - encoding - supports-color - verdaccio-auth-memory@13.1.0(supports-color@11.0.0): + verdaccio-auth-memory@13.1.1(supports-color@11.0.0): dependencies: - '@verdaccio/core': 8.2.0 + '@verdaccio/core': 8.2.1 debug: 4.4.3(supports-color@11.0.0) transitivePeerDependencies: - supports-color @@ -16491,15 +16654,15 @@ snapshots: core-util-is: 1.0.2 extsprintf: 1.3.0 - vite@8.1.5(@types/node@24.13.3)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(terser@5.49.0)(tsx@4.23.1)(yaml@2.9.0): + vite@8.1.5(@types/node@22.20.1)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(terser@5.49.0)(tsx@4.23.1)(yaml@2.9.0): dependencies: lightningcss: 1.33.0 picomatch: 4.0.5 - postcss: 8.5.19 + postcss: 8.5.25 rolldown: 1.1.5 tinyglobby: 0.2.17 optionalDependencies: - '@types/node': 24.13.3 + '@types/node': 22.20.1 esbuild: 0.28.1 fsevents: 2.3.3 jiti: 2.7.0 @@ -16509,10 +16672,10 @@ snapshots: tsx: 4.23.1 yaml: 2.9.0 - vitest@4.1.10(@opentelemetry/api@1.9.1)(@types/node@24.13.3)(@vitest/coverage-v8@4.1.10)(esbuild@0.28.1)(jiti@2.7.0)(jsdom@29.1.1)(less@4.6.7)(sass@1.101.0)(terser@5.49.0)(tsx@4.23.1)(yaml@2.9.0): + vitest@4.1.10(@opentelemetry/api@1.9.1)(@types/node@22.20.1)(@vitest/coverage-v8@4.1.10)(esbuild@0.28.1)(jiti@2.7.0)(jsdom@29.1.1)(less@4.6.7)(sass@1.101.0)(terser@5.49.0)(tsx@4.23.1)(yaml@2.9.0): dependencies: '@vitest/expect': 4.1.10 - '@vitest/mocker': 4.1.10(vite@8.1.5(@types/node@24.13.3)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(terser@5.49.0)(tsx@4.23.1)(yaml@2.9.0)) + '@vitest/mocker': 4.1.10(vite@8.1.5(@types/node@22.20.1)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(terser@5.49.0)(tsx@4.23.1)(yaml@2.9.0)) '@vitest/pretty-format': 4.1.10 '@vitest/runner': 4.1.10 '@vitest/snapshot': 4.1.10 @@ -16526,14 +16689,14 @@ snapshots: picomatch: 4.0.5 std-env: 4.2.0 tinybench: 2.9.0 - tinyexec: 1.2.4 + tinyexec: 1.3.0 tinyglobby: 0.2.17 - tinyrainbow: 3.1.0 - vite: 8.1.5(@types/node@24.13.3)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(terser@5.49.0)(tsx@4.23.1)(yaml@2.9.0) + tinyrainbow: 3.1.1 + vite: 8.1.5(@types/node@22.20.1)(esbuild@0.28.1)(jiti@2.7.0)(less@4.6.7)(sass@1.101.0)(terser@5.49.0)(tsx@4.23.1)(yaml@2.9.0) why-is-node-running: 2.3.0 optionalDependencies: '@opentelemetry/api': 1.9.1 - '@types/node': 24.13.3 + '@types/node': 22.20.1 '@vitest/coverage-v8': 4.1.10(vitest@4.1.10) jsdom: 29.1.1 transitivePeerDependencies: @@ -16577,7 +16740,7 @@ snapshots: webidl-conversions@8.0.1: {} - webpack-dev-middleware@7.4.5(tslib@2.8.1)(webpack@5.109.2(esbuild@0.28.1)(lightningcss@1.33.0)(postcss@8.5.19)(uglify-js@3.19.3)): + webpack-dev-middleware@7.4.5(tslib@2.8.1)(webpack@5.109.2(esbuild@0.28.1)(lightningcss@1.33.0)(postcss@8.5.25)(uglify-js@3.19.3)): dependencies: colorette: 2.0.20 memfs: 4.64.0(tslib@2.8.1) @@ -16586,11 +16749,11 @@ snapshots: range-parser: 1.3.0 schema-utils: 4.3.3 optionalDependencies: - webpack: 5.109.2(esbuild@0.28.1)(lightningcss@1.33.0)(postcss@8.5.19)(uglify-js@3.19.3) + webpack: 5.109.2(esbuild@0.28.1)(lightningcss@1.33.0)(postcss@8.5.25)(uglify-js@3.19.3) transitivePeerDependencies: - tslib - webpack-dev-middleware@8.0.3(tslib@2.8.1)(webpack@5.109.2(esbuild@0.28.1)(lightningcss@1.33.0)(postcss@8.5.19)(uglify-js@3.19.3)): + webpack-dev-middleware@8.0.3(tslib@2.8.1)(webpack@5.109.2(esbuild@0.28.1)(lightningcss@1.33.0)(postcss@8.5.25)(uglify-js@3.19.3)): dependencies: memfs: 4.64.0(tslib@2.8.1) mime-types: 3.0.2 @@ -16598,11 +16761,11 @@ snapshots: range-parser: 1.3.0 schema-utils: 4.3.3 optionalDependencies: - webpack: 5.109.2(esbuild@0.28.1)(lightningcss@1.33.0)(postcss@8.5.19)(uglify-js@3.19.3) + webpack: 5.109.2(esbuild@0.28.1)(lightningcss@1.33.0)(postcss@8.5.25)(uglify-js@3.19.3) transitivePeerDependencies: - tslib - webpack-dev-server@5.2.6(bufferutil@4.1.0)(debug@4.4.3(supports-color@11.0.0))(supports-color@11.0.0)(tslib@2.8.1)(utf-8-validate@6.0.6)(webpack@5.109.2(esbuild@0.28.1)(lightningcss@1.33.0)(postcss@8.5.19)(uglify-js@3.19.3)): + webpack-dev-server@5.2.6(bufferutil@4.1.0)(debug@4.4.3(supports-color@11.0.0))(supports-color@11.0.0)(tslib@2.8.1)(utf-8-validate@6.0.6)(webpack@5.109.2(esbuild@0.28.1)(lightningcss@1.33.0)(postcss@8.5.25)(uglify-js@3.19.3)): dependencies: '@types/bonjour': 3.5.13 '@types/connect-history-api-fallback': 1.5.4 @@ -16613,7 +16776,7 @@ snapshots: '@types/sockjs': 0.3.36 '@types/ws': 8.18.1 ansi-html-community: 0.0.8 - bonjour-service: 1.4.3 + bonjour-service: 1.4.4 chokidar: 3.6.0 colorette: 2.0.20 compression: 1.8.1(supports-color@11.0.0) @@ -16630,10 +16793,10 @@ snapshots: serve-index: 1.9.2(supports-color@11.0.0) sockjs: 0.3.24 spdy: 4.0.2(supports-color@11.0.0) - webpack-dev-middleware: 7.4.5(tslib@2.8.1)(webpack@5.109.2(esbuild@0.28.1)(lightningcss@1.33.0)(postcss@8.5.19)(uglify-js@3.19.3)) + webpack-dev-middleware: 7.4.5(tslib@2.8.1)(webpack@5.109.2(esbuild@0.28.1)(lightningcss@1.33.0)(postcss@8.5.25)(uglify-js@3.19.3)) ws: 8.21.1(bufferutil@4.1.0)(utf-8-validate@6.0.6) optionalDependencies: - webpack: 5.109.2(esbuild@0.28.1)(lightningcss@1.33.0)(postcss@8.5.19)(uglify-js@3.19.3) + webpack: 5.109.2(esbuild@0.28.1)(lightningcss@1.33.0)(postcss@8.5.25)(uglify-js@3.19.3) transitivePeerDependencies: - bufferutil - debug @@ -16649,10 +16812,10 @@ snapshots: webpack-sources@3.5.1: {} - webpack-subresource-integrity@5.1.0(webpack@5.109.2(esbuild@0.28.1)(lightningcss@1.33.0)(postcss@8.5.19)(uglify-js@3.19.3)): + webpack-subresource-integrity@5.1.0(webpack@5.109.2(esbuild@0.28.1)(lightningcss@1.33.0)(postcss@8.5.25)(uglify-js@3.19.3)): dependencies: typed-assert: 1.0.9 - webpack: 5.109.2(esbuild@0.28.1)(lightningcss@1.33.0)(postcss@8.5.19)(uglify-js@3.19.3) + webpack: 5.109.2(esbuild@0.28.1)(lightningcss@1.33.0)(postcss@8.5.25)(uglify-js@3.19.3) webpack@5.109.2(esbuild@0.28.1): dependencies: @@ -16661,10 +16824,10 @@ snapshots: '@webassemblyjs/ast': 1.14.1 '@webassemblyjs/wasm-edit': 1.14.1 '@webassemblyjs/wasm-parser': 1.14.1 - acorn: 8.17.0 + acorn: 8.18.0 browserslist: 4.28.7 chrome-trace-event: 1.0.4 - enhanced-resolve: 5.24.4 + enhanced-resolve: 5.24.5 es-module-lexer: 2.3.1 eslint-scope: 5.1.1 events: 3.3.0 @@ -16690,23 +16853,23 @@ snapshots: - postcss - uglify-js - webpack@5.109.2(esbuild@0.28.1)(lightningcss@1.33.0)(postcss@8.5.19)(uglify-js@3.19.3): + webpack@5.109.2(esbuild@0.28.1)(lightningcss@1.33.0)(postcss@8.5.25)(uglify-js@3.19.3): dependencies: '@types/estree': 1.0.9 '@types/json-schema': 7.0.15 '@webassemblyjs/ast': 1.14.1 '@webassemblyjs/wasm-edit': 1.14.1 '@webassemblyjs/wasm-parser': 1.14.1 - acorn: 8.17.0 + acorn: 8.18.0 browserslist: 4.28.7 chrome-trace-event: 1.0.4 - enhanced-resolve: 5.24.4 + enhanced-resolve: 5.24.5 es-module-lexer: 2.3.1 eslint-scope: 5.1.1 events: 3.3.0 graceful-fs: 4.2.11 mime-db: 1.54.0 - minimizer-webpack-plugin: 5.6.1(esbuild@0.28.1)(lightningcss@1.33.0)(postcss@8.5.19)(uglify-js@3.19.3)(webpack@5.109.2(esbuild@0.28.1)(lightningcss@1.33.0)(postcss@8.5.19)(uglify-js@3.19.3)) + minimizer-webpack-plugin: 5.6.1(esbuild@0.28.1)(lightningcss@1.33.0)(postcss@8.5.25)(uglify-js@3.19.3)(webpack@5.109.2(esbuild@0.28.1)(lightningcss@1.33.0)(postcss@8.5.25)(uglify-js@3.19.3)) neo-async: 2.6.2 schema-utils: 4.3.3 tapable: 2.3.3 diff --git a/renovate.json b/renovate.json index 0299498febd8..2e0c41cacfbb 100644 --- a/renovate.json +++ b/renovate.json @@ -4,6 +4,10 @@ "extends": ["github>angular/dev-infra//renovate-presets/default.json5"], "ignorePaths": ["tests/e2e/assets/**", "tests/schematics/update/packages/**"], "packageRules": [ + { + "matchFileNames": ["tests/e2e/ng-snapshot/package.json"], + "schedule": ["before 8am"] + }, { "enabled": false, "matchFileNames": ["tests/e2e/ng-snapshot/package.json"], diff --git a/scripts/saucelabs/start-tunnel.sh b/scripts/saucelabs/start-tunnel.sh deleted file mode 100755 index badf130e6eea..000000000000 --- a/scripts/saucelabs/start-tunnel.sh +++ /dev/null @@ -1,40 +0,0 @@ -#!/usr/bin/env bash - -set -x -u -e -o pipefail - -readonly currentDir=$(cd $(dirname $0); pwd) -readonly connectVersion="sc-4.9.2-linux" -readonly connectHash="2f8a3f87e1da4dc9a41bc45ec7c3a2ecdba4c72d72b7d0193f04ad66c5809104" - -echo "Downloading Sauce Connect" - -curl https://saucelabs.com/downloads/${connectVersion}.tar.gz -o ${currentDir}/${connectVersion}.tar.gz -echo "${connectHash} ${currentDir}/${connectVersion}.tar.gz" | shasum -a 256 -c -tar -xzf ${currentDir}/${connectVersion}.tar.gz -C ${currentDir} - -# Command arguments that will be passed to sauce-connect. By default we disable SSL bumping for -# all requests. This is because SSL bumping is not needed for our test setup and in order -# to perform the SSL bumping, Saucelabs intercepts all HTTP requests in the tunnel VM and modifies -# them. This can cause flakiness as it makes all requests dependent on the SSL bumping middleware. -# See: https://wiki.saucelabs.com/display/DOCS/Troubleshooting+Sauce+Connect#TroubleshootingSauceConnect-DisablingSSLBumping -sauceArgs="--no-ssl-bump-domains all" - -if [[ ! -z "${SAUCE_LOG_FILE:-}" ]]; then - mkdir -p $(dirname ${SAUCE_LOG_FILE}) - sauceArgs="${sauceArgs} --logfile ${SAUCE_LOG_FILE}" -fi - -if [[ ! -z "${SAUCE_READY_FILE:-}" ]]; then - mkdir -p $(dirname ${SAUCE_READY_FILE}) - sauceArgs="${sauceArgs} --readyfile ${SAUCE_READY_FILE}" -fi - -if [[ ! -z "${SAUCE_PID_FILE:-}" ]]; then - mkdir -p $(dirname ${SAUCE_PID_FILE}) - sauceArgs="${sauceArgs} --pidfile ${SAUCE_PID_FILE}" -fi - - -echo "Starting Sauce Connect. Passed arguments: ${sauceArgs}" - -${currentDir}/${connectVersion}/bin/sc -u ${SAUCE_USERNAME} -k ${SAUCE_ACCESS_KEY} ${sauceArgs} diff --git a/scripts/saucelabs/stop-tunnel.sh b/scripts/saucelabs/stop-tunnel.sh deleted file mode 100755 index 4ea8d13c7e12..000000000000 --- a/scripts/saucelabs/stop-tunnel.sh +++ /dev/null @@ -1,27 +0,0 @@ -#!/usr/bin/env bash - -# Disable printing of any executed command because this would cause a lot -# of spam due to the loop. -set +x -u -e -o pipefail - -if [[ ! -f ${SAUCE_PID_FILE} ]]; then - echo "Could not find Saucelabs tunnel PID file. Cannot stop tunnel.." - exit 1 -fi - -echo "Shutting down Sauce Connect tunnel" - -# The process id for the sauce-connect instance is stored inside of the pidfile. -tunnelProcessId=$(cat ${SAUCE_PID_FILE}) - -# Kill the process by using the PID that has been read from the pidfile. Note that -# we cannot use killall because CI base container images don't have it installed. -kill ${tunnelProcessId} - -while (ps -p ${tunnelProcessId} &> /dev/null); do - printf "." - sleep .5 -done - -echo "" -echo "Sauce Connect tunnel has been shut down" diff --git a/scripts/saucelabs/wait-for-tunnel.sh b/scripts/saucelabs/wait-for-tunnel.sh deleted file mode 100755 index feda9a85b694..000000000000 --- a/scripts/saucelabs/wait-for-tunnel.sh +++ /dev/null @@ -1,28 +0,0 @@ -#!/usr/bin/env bash - -# Disable printing of any executed command because this would cause a lot -# of spam due to the loop. -set +x -u -e -o pipefail - -# Waits for Saucelabs Connect to be ready before executing any tests. -counter=0 - -while [[ ! -f ${SAUCE_READY_FILE} ]]; do - counter=$((counter + 1)) - - # Counter needs to be multiplied by two because the while loop only sleeps a half second. - # This has been made in favor of better progress logging (printing dots every half second) - if [ $counter -gt $[${SAUCE_READY_FILE_TIMEOUT} * 2] ]; then - echo "Timed out after ${SAUCE_READY_FILE_TIMEOUT} seconds waiting for tunnel ready file." - echo "Printing logfile output:" - echo "" - cat ${SAUCE_LOG_FILE} - exit 5 - fi - - printf "." - sleep 0.5 -done - -echo "" -echo "Connected to Saucelabs" diff --git a/tests/e2e/assets/protractor-saucelabs.conf.js b/tests/e2e/assets/protractor-saucelabs.conf.js index fb9ab42798a8..cb21d8a3be15 100644 --- a/tests/e2e/assets/protractor-saucelabs.conf.js +++ b/tests/e2e/assets/protractor-saucelabs.conf.js @@ -5,7 +5,50 @@ const { SpecReporter, StacktraceOption } = require('jasmine-spec-reporter'); -const tunnelIdentifier = process.env['SAUCE_TUNNEL_IDENTIFIER']; +const tunnelName = process.env['SAUCE_TUNNEL_IDENTIFIER']; + +const capabilities = [ + { + browserName: 'chrome', + version: '132', + platform: 'Windows 11', + }, + { + browserName: 'chrome', + version: '131', + platform: 'Windows 11', + }, + { + browserName: 'firefox', + version: '134', + platform: 'Windows 11', + }, + { + browserName: 'firefox', + version: '128', // Latest Firefox ESR version as of Jan 2025 + platform: 'Windows 11', + }, + { + browserName: 'safari', + platform: 'macOS 13', + version: '17', + }, + { + browserName: 'safari', + platform: 'macOS 12', + version: '16', + }, + { + browserName: 'MicrosoftEdge', + platform: 'Windows 11', + version: '132', + }, + { + browserName: 'MicrosoftEdge', + platform: 'Windows 11', + version: '131', + }, +]; /** * @type { import("protractor").Config } @@ -13,61 +56,16 @@ const tunnelIdentifier = process.env['SAUCE_TUNNEL_IDENTIFIER']; exports.config = { sauceUser: process.env['SAUCE_USERNAME'], sauceKey: process.env['SAUCE_ACCESS_KEY'], + sauceRegion: 'us', allScriptsTimeout: 11000, specs: ['./src/**/*.e2e-spec.ts'], // NOTE: https://saucelabs.com/products/platform-configurator can be used to determine configuration values - multiCapabilities: [ - { - browserName: 'chrome', - version: '132', - platform: 'Windows 11', - tunnelIdentifier, - }, - { - browserName: 'chrome', - version: '131', - platform: 'Windows 11', - tunnelIdentifier, - }, - { - browserName: 'firefox', - version: '134', - platform: 'Windows 11', - tunnelIdentifier, - }, - { - browserName: 'firefox', - version: '128', // Latest Firefox ESR version as of Jan 2025 - platform: 'Windows 11', - tunnelIdentifier, - }, - { - browserName: 'safari', - platform: 'macOS 13', - version: '17', - tunnelIdentifier, - }, - { - browserName: 'safari', - platform: 'macOS 12', - version: '16', - tunnelIdentifier, - }, - { - browserName: 'MicrosoftEdge', - platform: 'Windows 11', - version: '132', - tunnelIdentifier, - }, - { - browserName: 'MicrosoftEdge', - platform: 'Windows 11', - version: '131', - tunnelIdentifier, - }, - ], + multiCapabilities: capabilities.map((caps) => ({ + ...caps, + tunnelName, + })), // Only allow one session at a time to prevent over saturation of Saucelabs sessions. maxSessions: 1,