From 3cea706976b37ca27a3e7bcb1384bd456e4e187d Mon Sep 17 00:00:00 2001 From: Angular Robot Date: Wed, 22 Oct 2025 21:35:01 +0000 Subject: [PATCH 01/52] build: update cross-repo angular dependencies See associated pull request for more information. --- .../assistant-to-the-branch-manager.yml | 2 +- .github/workflows/ci.yml | 52 +- .github/workflows/dev-infra.yml | 4 +- .github/workflows/feature-requests.yml | 2 +- .github/workflows/perf.yml | 6 +- .github/workflows/pr.yml | 44 +- MODULE.bazel | 2 +- package.json | 28 +- packages/angular/ssr/package.json | 12 +- packages/ngtools/webpack/package.json | 4 +- pnpm-lock.yaml | 680 +++++++++--------- 11 files changed, 418 insertions(+), 418 deletions(-) diff --git a/.github/workflows/assistant-to-the-branch-manager.yml b/.github/workflows/assistant-to-the-branch-manager.yml index 7fc107f4320e..a9733b11fe7b 100644 --- a/.github/workflows/assistant-to-the-branch-manager.yml +++ b/.github/workflows/assistant-to-the-branch-manager.yml @@ -16,6 +16,6 @@ jobs: - uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0 with: persist-credentials: false - - uses: angular/dev-infra/github-actions/branch-manager@c584c3565b71c7a8cda81d55bb14e3e66ef934da + - uses: angular/dev-infra/github-actions/branch-manager@43d4ea5534ce399657a64c94a9dc1ea883324804 with: angular-robot-key: ${{ secrets.ANGULAR_ROBOT_PRIVATE_KEY }} diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index ce9874a2f8cf..9bcfc0802c60 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@c584c3565b71c7a8cda81d55bb14e3e66ef934da + uses: angular/dev-infra/github-actions/npm/checkout-and-setup-node@43d4ea5534ce399657a64c94a9dc1ea883324804 - name: Setup Bazel - uses: angular/dev-infra/github-actions/bazel/setup@c584c3565b71c7a8cda81d55bb14e3e66ef934da + uses: angular/dev-infra/github-actions/bazel/setup@43d4ea5534ce399657a64c94a9dc1ea883324804 - 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@c584c3565b71c7a8cda81d55bb14e3e66ef934da + uses: angular/dev-infra/github-actions/npm/checkout-and-setup-node@43d4ea5534ce399657a64c94a9dc1ea883324804 - name: Setup Bazel - uses: angular/dev-infra/github-actions/bazel/setup@c584c3565b71c7a8cda81d55bb14e3e66ef934da + uses: angular/dev-infra/github-actions/bazel/setup@43d4ea5534ce399657a64c94a9dc1ea883324804 - name: Setup Bazel RBE - uses: angular/dev-infra/github-actions/bazel/configure-remote@c584c3565b71c7a8cda81d55bb14e3e66ef934da + uses: angular/dev-infra/github-actions/bazel/configure-remote@43d4ea5534ce399657a64c94a9dc1ea883324804 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@c584c3565b71c7a8cda81d55bb14e3e66ef934da + uses: angular/dev-infra/github-actions/npm/checkout-and-setup-node@43d4ea5534ce399657a64c94a9dc1ea883324804 - name: Setup Bazel - uses: angular/dev-infra/github-actions/bazel/setup@c584c3565b71c7a8cda81d55bb14e3e66ef934da + uses: angular/dev-infra/github-actions/bazel/setup@43d4ea5534ce399657a64c94a9dc1ea883324804 - name: Setup Bazel RBE - uses: angular/dev-infra/github-actions/bazel/configure-remote@c584c3565b71c7a8cda81d55bb14e3e66ef934da + uses: angular/dev-infra/github-actions/bazel/configure-remote@43d4ea5534ce399657a64c94a9dc1ea883324804 with: google_credential: ${{ secrets.RBE_TRUSTED_BUILDS_USER }} - name: Install node modules @@ -85,13 +85,13 @@ jobs: runs-on: ${{ matrix.os }} steps: - name: Initialize environment - uses: angular/dev-infra/github-actions/npm/checkout-and-setup-node@c584c3565b71c7a8cda81d55bb14e3e66ef934da + uses: angular/dev-infra/github-actions/npm/checkout-and-setup-node@43d4ea5534ce399657a64c94a9dc1ea883324804 - name: Install node modules run: pnpm install --frozen-lockfile - name: Setup Bazel - uses: angular/dev-infra/github-actions/bazel/setup@c584c3565b71c7a8cda81d55bb14e3e66ef934da + uses: angular/dev-infra/github-actions/bazel/setup@43d4ea5534ce399657a64c94a9dc1ea883324804 - name: Setup Bazel RBE - uses: angular/dev-infra/github-actions/bazel/configure-remote@c584c3565b71c7a8cda81d55bb14e3e66ef934da + uses: angular/dev-infra/github-actions/bazel/configure-remote@43d4ea5534ce399657a64c94a9dc1ea883324804 with: google_credential: ${{ secrets.RBE_TRUSTED_BUILDS_USER }} - name: Run CLI E2E tests @@ -101,11 +101,11 @@ jobs: runs-on: ubuntu-latest steps: - name: Initialize environment - uses: angular/dev-infra/github-actions/npm/checkout-and-setup-node@c584c3565b71c7a8cda81d55bb14e3e66ef934da + uses: angular/dev-infra/github-actions/npm/checkout-and-setup-node@43d4ea5534ce399657a64c94a9dc1ea883324804 - name: Setup Bazel - uses: angular/dev-infra/github-actions/bazel/setup@c584c3565b71c7a8cda81d55bb14e3e66ef934da + uses: angular/dev-infra/github-actions/bazel/setup@43d4ea5534ce399657a64c94a9dc1ea883324804 - name: Setup Bazel RBE - uses: angular/dev-infra/github-actions/bazel/configure-remote@c584c3565b71c7a8cda81d55bb14e3e66ef934da + uses: angular/dev-infra/github-actions/bazel/configure-remote@43d4ea5534ce399657a64c94a9dc1ea883324804 with: google_credential: ${{ secrets.RBE_TRUSTED_BUILDS_USER }} - name: Install node modules @@ -139,7 +139,7 @@ jobs: runs-on: ${{ matrix.os }} steps: - name: Initialize environment - uses: angular/dev-infra/github-actions/npm/checkout-and-setup-node@c584c3565b71c7a8cda81d55bb14e3e66ef934da + uses: angular/dev-infra/github-actions/npm/checkout-and-setup-node@43d4ea5534ce399657a64c94a9dc1ea883324804 - name: Install node modules run: pnpm install --frozen-lockfile - name: Download built Windows E2E tests @@ -167,13 +167,13 @@ jobs: runs-on: ${{ matrix.os }} steps: - name: Initialize environment - uses: angular/dev-infra/github-actions/npm/checkout-and-setup-node@c584c3565b71c7a8cda81d55bb14e3e66ef934da + uses: angular/dev-infra/github-actions/npm/checkout-and-setup-node@43d4ea5534ce399657a64c94a9dc1ea883324804 - name: Install node modules run: pnpm install --frozen-lockfile - name: Setup Bazel - uses: angular/dev-infra/github-actions/bazel/setup@c584c3565b71c7a8cda81d55bb14e3e66ef934da + uses: angular/dev-infra/github-actions/bazel/setup@43d4ea5534ce399657a64c94a9dc1ea883324804 - name: Setup Bazel RBE - uses: angular/dev-infra/github-actions/bazel/configure-remote@c584c3565b71c7a8cda81d55bb14e3e66ef934da + uses: angular/dev-infra/github-actions/bazel/configure-remote@43d4ea5534ce399657a64c94a9dc1ea883324804 with: google_credential: ${{ secrets.RBE_TRUSTED_BUILDS_USER }} - name: Run CLI E2E tests @@ -192,13 +192,13 @@ jobs: runs-on: ${{ matrix.os }} steps: - name: Initialize environment - uses: angular/dev-infra/github-actions/npm/checkout-and-setup-node@c584c3565b71c7a8cda81d55bb14e3e66ef934da + uses: angular/dev-infra/github-actions/npm/checkout-and-setup-node@43d4ea5534ce399657a64c94a9dc1ea883324804 - name: Install node modules run: pnpm install --frozen-lockfile - name: Setup Bazel - uses: angular/dev-infra/github-actions/bazel/setup@c584c3565b71c7a8cda81d55bb14e3e66ef934da + uses: angular/dev-infra/github-actions/bazel/setup@43d4ea5534ce399657a64c94a9dc1ea883324804 - name: Setup Bazel RBE - uses: angular/dev-infra/github-actions/bazel/configure-remote@c584c3565b71c7a8cda81d55bb14e3e66ef934da + uses: angular/dev-infra/github-actions/bazel/configure-remote@43d4ea5534ce399657a64c94a9dc1ea883324804 with: google_credential: ${{ secrets.RBE_TRUSTED_BUILDS_USER }} - name: Run CLI E2E tests @@ -212,13 +212,13 @@ 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@c584c3565b71c7a8cda81d55bb14e3e66ef934da + uses: angular/dev-infra/github-actions/npm/checkout-and-setup-node@43d4ea5534ce399657a64c94a9dc1ea883324804 - name: Install node modules run: pnpm install --frozen-lockfile - name: Setup Bazel - uses: angular/dev-infra/github-actions/bazel/setup@c584c3565b71c7a8cda81d55bb14e3e66ef934da + uses: angular/dev-infra/github-actions/bazel/setup@43d4ea5534ce399657a64c94a9dc1ea883324804 - name: Setup Bazel RBE - uses: angular/dev-infra/github-actions/bazel/configure-remote@c584c3565b71c7a8cda81d55bb14e3e66ef934da + uses: angular/dev-infra/github-actions/bazel/configure-remote@43d4ea5534ce399657a64c94a9dc1ea883324804 with: google_credential: ${{ secrets.RBE_TRUSTED_BUILDS_USER }} - name: Run E2E Browser tests @@ -248,11 +248,11 @@ jobs: CIRCLE_BRANCH: ${{ github.ref_name }} steps: - name: Initialize environment - uses: angular/dev-infra/github-actions/npm/checkout-and-setup-node@c584c3565b71c7a8cda81d55bb14e3e66ef934da + uses: angular/dev-infra/github-actions/npm/checkout-and-setup-node@43d4ea5534ce399657a64c94a9dc1ea883324804 - name: Install node modules run: pnpm install --frozen-lockfile - name: Setup Bazel - uses: angular/dev-infra/github-actions/bazel/setup@c584c3565b71c7a8cda81d55bb14e3e66ef934da + uses: angular/dev-infra/github-actions/bazel/setup@43d4ea5534ce399657a64c94a9dc1ea883324804 - 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 13a2682927fc..200a6b3fd5e7 100644 --- a/.github/workflows/dev-infra.yml +++ b/.github/workflows/dev-infra.yml @@ -13,13 +13,13 @@ jobs: runs-on: ubuntu-latest steps: - uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0 - - uses: angular/dev-infra/github-actions/pull-request-labeling@c584c3565b71c7a8cda81d55bb14e3e66ef934da + - uses: angular/dev-infra/github-actions/pull-request-labeling@43d4ea5534ce399657a64c94a9dc1ea883324804 with: angular-robot-key: ${{ secrets.ANGULAR_ROBOT_PRIVATE_KEY }} post_approval_changes: runs-on: ubuntu-latest steps: - uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0 - - uses: angular/dev-infra/github-actions/post-approval-changes@c584c3565b71c7a8cda81d55bb14e3e66ef934da + - uses: angular/dev-infra/github-actions/post-approval-changes@43d4ea5534ce399657a64c94a9dc1ea883324804 with: angular-robot-key: ${{ secrets.ANGULAR_ROBOT_PRIVATE_KEY }} diff --git a/.github/workflows/feature-requests.yml b/.github/workflows/feature-requests.yml index 62c8bf4bee8c..83f9811ddb54 100644 --- a/.github/workflows/feature-requests.yml +++ b/.github/workflows/feature-requests.yml @@ -16,6 +16,6 @@ jobs: if: github.repository == 'angular/angular-cli' runs-on: ubuntu-latest steps: - - uses: angular/dev-infra/github-actions/feature-request@c584c3565b71c7a8cda81d55bb14e3e66ef934da + - uses: angular/dev-infra/github-actions/feature-request@43d4ea5534ce399657a64c94a9dc1ea883324804 with: angular-robot-key: ${{ secrets.ANGULAR_ROBOT_PRIVATE_KEY }} diff --git a/.github/workflows/perf.yml b/.github/workflows/perf.yml index bbbfd5dbc32a..17118598762c 100644 --- a/.github/workflows/perf.yml +++ b/.github/workflows/perf.yml @@ -23,7 +23,7 @@ jobs: workflows: ${{ steps.workflows.outputs.workflows }} steps: - name: Initialize environment - uses: angular/dev-infra/github-actions/npm/checkout-and-setup-node@c584c3565b71c7a8cda81d55bb14e3e66ef934da + uses: angular/dev-infra/github-actions/npm/checkout-and-setup-node@43d4ea5534ce399657a64c94a9dc1ea883324804 - name: Install node modules run: pnpm install --frozen-lockfile - id: workflows @@ -38,9 +38,9 @@ jobs: workflow: ${{ fromJSON(needs.list.outputs.workflows) }} steps: - name: Initialize environment - uses: angular/dev-infra/github-actions/npm/checkout-and-setup-node@c584c3565b71c7a8cda81d55bb14e3e66ef934da + uses: angular/dev-infra/github-actions/npm/checkout-and-setup-node@43d4ea5534ce399657a64c94a9dc1ea883324804 - name: Setup Bazel - uses: angular/dev-infra/github-actions/bazel/setup@c584c3565b71c7a8cda81d55bb14e3e66ef934da + uses: angular/dev-infra/github-actions/bazel/setup@43d4ea5534ce399657a64c94a9dc1ea883324804 - 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 b6402fb6102a..93723221e592 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@c584c3565b71c7a8cda81d55bb14e3e66ef934da + uses: angular/dev-infra/github-actions/npm/checkout-and-setup-node@43d4ea5534ce399657a64c94a9dc1ea883324804 - name: Setup Bazel - uses: angular/dev-infra/github-actions/bazel/setup@c584c3565b71c7a8cda81d55bb14e3e66ef934da + uses: angular/dev-infra/github-actions/bazel/setup@43d4ea5534ce399657a64c94a9dc1ea883324804 - name: Setup ESLint Caching uses: actions/cache@0057852bfaa89a56745cba8c7296529d2fc39830 # v4.3.0 with: @@ -56,7 +56,7 @@ jobs: - name: Run Validation run: pnpm admin validate - name: Check Package Licenses - uses: angular/dev-infra/github-actions/linting/licenses@c584c3565b71c7a8cda81d55bb14e3e66ef934da + uses: angular/dev-infra/github-actions/linting/licenses@43d4ea5534ce399657a64c94a9dc1ea883324804 - name: Check tooling setup run: pnpm check-tooling-setup - name: Check commit message @@ -72,11 +72,11 @@ jobs: runs-on: ubuntu-latest steps: - name: Initialize environment - uses: angular/dev-infra/github-actions/npm/checkout-and-setup-node@c584c3565b71c7a8cda81d55bb14e3e66ef934da + uses: angular/dev-infra/github-actions/npm/checkout-and-setup-node@43d4ea5534ce399657a64c94a9dc1ea883324804 - name: Setup Bazel - uses: angular/dev-infra/github-actions/bazel/setup@c584c3565b71c7a8cda81d55bb14e3e66ef934da + uses: angular/dev-infra/github-actions/bazel/setup@43d4ea5534ce399657a64c94a9dc1ea883324804 - name: Setup Bazel RBE - uses: angular/dev-infra/github-actions/bazel/configure-remote@c584c3565b71c7a8cda81d55bb14e3e66ef934da + uses: angular/dev-infra/github-actions/bazel/configure-remote@43d4ea5534ce399657a64c94a9dc1ea883324804 - 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@c584c3565b71c7a8cda81d55bb14e3e66ef934da + uses: angular/dev-infra/github-actions/npm/checkout-and-setup-node@43d4ea5534ce399657a64c94a9dc1ea883324804 - name: Setup Bazel - uses: angular/dev-infra/github-actions/bazel/setup@c584c3565b71c7a8cda81d55bb14e3e66ef934da + uses: angular/dev-infra/github-actions/bazel/setup@43d4ea5534ce399657a64c94a9dc1ea883324804 - name: Setup Bazel RBE - uses: angular/dev-infra/github-actions/bazel/configure-remote@c584c3565b71c7a8cda81d55bb14e3e66ef934da + uses: angular/dev-infra/github-actions/bazel/configure-remote@43d4ea5534ce399657a64c94a9dc1ea883324804 - name: Install node modules run: pnpm install --frozen-lockfile - name: Run module and package tests @@ -115,13 +115,13 @@ jobs: runs-on: ${{ matrix.os }} steps: - name: Initialize environment - uses: angular/dev-infra/github-actions/npm/checkout-and-setup-node@c584c3565b71c7a8cda81d55bb14e3e66ef934da + uses: angular/dev-infra/github-actions/npm/checkout-and-setup-node@43d4ea5534ce399657a64c94a9dc1ea883324804 - name: Install node modules run: pnpm install --frozen-lockfile - name: Setup Bazel - uses: angular/dev-infra/github-actions/bazel/setup@c584c3565b71c7a8cda81d55bb14e3e66ef934da + uses: angular/dev-infra/github-actions/bazel/setup@43d4ea5534ce399657a64c94a9dc1ea883324804 - name: Setup Bazel RBE - uses: angular/dev-infra/github-actions/bazel/configure-remote@c584c3565b71c7a8cda81d55bb14e3e66ef934da + uses: angular/dev-infra/github-actions/bazel/configure-remote@43d4ea5534ce399657a64c94a9dc1ea883324804 - 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/legacy-cli:e2e.${{ matrix.subset }}_node${{ matrix.node }} @@ -129,11 +129,11 @@ jobs: runs-on: ubuntu-latest steps: - name: Initialize environment - uses: angular/dev-infra/github-actions/npm/checkout-and-setup-node@c584c3565b71c7a8cda81d55bb14e3e66ef934da + uses: angular/dev-infra/github-actions/npm/checkout-and-setup-node@43d4ea5534ce399657a64c94a9dc1ea883324804 - name: Setup Bazel - uses: angular/dev-infra/github-actions/bazel/setup@c584c3565b71c7a8cda81d55bb14e3e66ef934da + uses: angular/dev-infra/github-actions/bazel/setup@43d4ea5534ce399657a64c94a9dc1ea883324804 - name: Setup Bazel RBE - uses: angular/dev-infra/github-actions/bazel/configure-remote@c584c3565b71c7a8cda81d55bb14e3e66ef934da + uses: angular/dev-infra/github-actions/bazel/configure-remote@43d4ea5534ce399657a64c94a9dc1ea883324804 - name: Install node modules run: pnpm install --frozen-lockfile - name: Build E2E tests for Windows on Linux @@ -157,7 +157,7 @@ jobs: runs-on: windows-2025 steps: - name: Initialize environment - uses: angular/dev-infra/github-actions/npm/checkout-and-setup-node@c584c3565b71c7a8cda81d55bb14e3e66ef934da + uses: angular/dev-infra/github-actions/npm/checkout-and-setup-node@43d4ea5534ce399657a64c94a9dc1ea883324804 - name: Install node modules run: pnpm install --frozen-lockfile - name: Download built Windows E2E tests @@ -185,13 +185,13 @@ jobs: runs-on: ${{ matrix.os }} steps: - name: Initialize environment - uses: angular/dev-infra/github-actions/npm/checkout-and-setup-node@c584c3565b71c7a8cda81d55bb14e3e66ef934da + uses: angular/dev-infra/github-actions/npm/checkout-and-setup-node@43d4ea5534ce399657a64c94a9dc1ea883324804 - name: Install node modules run: pnpm install --frozen-lockfile - name: Setup Bazel - uses: angular/dev-infra/github-actions/bazel/setup@c584c3565b71c7a8cda81d55bb14e3e66ef934da + uses: angular/dev-infra/github-actions/bazel/setup@43d4ea5534ce399657a64c94a9dc1ea883324804 - name: Setup Bazel RBE - uses: angular/dev-infra/github-actions/bazel/configure-remote@c584c3565b71c7a8cda81d55bb14e3e66ef934da + uses: angular/dev-infra/github-actions/bazel/configure-remote@43d4ea5534ce399657a64c94a9dc1ea883324804 - 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/legacy-cli:e2e.${{ matrix.subset }}_node${{ matrix.node }} @@ -208,12 +208,12 @@ jobs: runs-on: ${{ matrix.os }} steps: - name: Initialize environment - uses: angular/dev-infra/github-actions/npm/checkout-and-setup-node@c584c3565b71c7a8cda81d55bb14e3e66ef934da + uses: angular/dev-infra/github-actions/npm/checkout-and-setup-node@43d4ea5534ce399657a64c94a9dc1ea883324804 - name: Install node modules run: pnpm install --frozen-lockfile - name: Setup Bazel - uses: angular/dev-infra/github-actions/bazel/setup@c584c3565b71c7a8cda81d55bb14e3e66ef934da + uses: angular/dev-infra/github-actions/bazel/setup@43d4ea5534ce399657a64c94a9dc1ea883324804 - name: Setup Bazel RBE - uses: angular/dev-infra/github-actions/bazel/configure-remote@c584c3565b71c7a8cda81d55bb14e3e66ef934da + uses: angular/dev-infra/github-actions/bazel/configure-remote@43d4ea5534ce399657a64c94a9dc1ea883324804 - 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/legacy-cli:e2e.snapshots.${{ matrix.subset }}_node${{ matrix.node }} diff --git a/MODULE.bazel b/MODULE.bazel index 633ad946e375..5aef813e81ac 100644 --- a/MODULE.bazel +++ b/MODULE.bazel @@ -33,7 +33,7 @@ git_override( bazel_dep(name = "devinfra") git_override( module_name = "devinfra", - commit = "c584c3565b71c7a8cda81d55bb14e3e66ef934da", + commit = "43d4ea5534ce399657a64c94a9dc1ea883324804", remote = "https://github.com/angular/dev-infra.git", ) diff --git a/package.json b/package.json index 5594c777c8dc..145e02ed2d86 100644 --- a/package.json +++ b/package.json @@ -46,20 +46,20 @@ }, "homepage": "https://github.com/angular/angular-cli", "devDependencies": { - "@angular/animations": "20.3.6", - "@angular/cdk": "20.2.9", - "@angular/common": "20.3.6", - "@angular/compiler": "20.3.6", - "@angular/compiler-cli": "20.3.6", - "@angular/core": "20.3.6", - "@angular/forms": "20.3.6", - "@angular/localize": "20.3.6", - "@angular/material": "20.2.9", - "@angular/ng-dev": "https://github.com/angular/dev-infra-private-ng-dev-builds.git#3c4fd6f54f2c67ce5b9f1a32ce90e36ba2fada4e", - "@angular/platform-browser": "20.3.6", - "@angular/platform-server": "20.3.6", - "@angular/router": "20.3.6", - "@angular/service-worker": "20.3.6", + "@angular/animations": "20.3.7", + "@angular/cdk": "20.2.10", + "@angular/common": "20.3.7", + "@angular/compiler": "20.3.7", + "@angular/compiler-cli": "20.3.7", + "@angular/core": "20.3.7", + "@angular/forms": "20.3.7", + "@angular/localize": "20.3.7", + "@angular/material": "20.2.10", + "@angular/ng-dev": "https://github.com/angular/dev-infra-private-ng-dev-builds.git#a3426d37e6f9781b00650a767eb5b3967cdb94f7", + "@angular/platform-browser": "20.3.7", + "@angular/platform-server": "20.3.7", + "@angular/router": "20.3.7", + "@angular/service-worker": "20.3.7", "@bazel/bazelisk": "1.26.0", "@bazel/buildifier": "8.2.1", "@eslint/compat": "1.3.2", diff --git a/packages/angular/ssr/package.json b/packages/angular/ssr/package.json index f501294ddc4c..21259c1c2b94 100644 --- a/packages/angular/ssr/package.json +++ b/packages/angular/ssr/package.json @@ -29,12 +29,12 @@ }, "devDependencies": { "@angular-devkit/schematics": "workspace:*", - "@angular/common": "20.3.6", - "@angular/compiler": "20.3.6", - "@angular/core": "20.3.6", - "@angular/platform-browser": "20.3.6", - "@angular/platform-server": "20.3.6", - "@angular/router": "20.3.6", + "@angular/common": "20.3.7", + "@angular/compiler": "20.3.7", + "@angular/core": "20.3.7", + "@angular/platform-browser": "20.3.7", + "@angular/platform-server": "20.3.7", + "@angular/router": "20.3.7", "@schematics/angular": "workspace:*" }, "sideEffects": false, diff --git a/packages/ngtools/webpack/package.json b/packages/ngtools/webpack/package.json index 4971250018fd..83bbdfd6a3b9 100644 --- a/packages/ngtools/webpack/package.json +++ b/packages/ngtools/webpack/package.json @@ -27,8 +27,8 @@ }, "devDependencies": { "@angular-devkit/core": "workspace:0.0.0-PLACEHOLDER", - "@angular/compiler": "20.3.6", - "@angular/compiler-cli": "20.3.6", + "@angular/compiler": "20.3.7", + "@angular/compiler-cli": "20.3.7", "typescript": "5.9.2", "webpack": "5.101.2" } diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index f965aac8bfe2..de1d0e1e6804 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -20,47 +20,47 @@ importers: built: true devDependencies: '@angular/animations': - specifier: 20.3.6 - version: 20.3.6(@angular/core@20.3.6(@angular/compiler@20.3.6)(rxjs@7.8.2)(zone.js@0.15.1)) + specifier: 20.3.7 + version: 20.3.7(@angular/core@20.3.7(@angular/compiler@20.3.7)(rxjs@7.8.2)(zone.js@0.15.1)) '@angular/cdk': - specifier: 20.2.9 - version: 20.2.9(@angular/common@20.3.6(@angular/core@20.3.6(@angular/compiler@20.3.6)(rxjs@7.8.2)(zone.js@0.15.1))(rxjs@7.8.2))(@angular/core@20.3.6(@angular/compiler@20.3.6)(rxjs@7.8.2)(zone.js@0.15.1))(rxjs@7.8.2) + specifier: 20.2.10 + version: 20.2.10(@angular/common@20.3.7(@angular/core@20.3.7(@angular/compiler@20.3.7)(rxjs@7.8.2)(zone.js@0.15.1))(rxjs@7.8.2))(@angular/core@20.3.7(@angular/compiler@20.3.7)(rxjs@7.8.2)(zone.js@0.15.1))(rxjs@7.8.2) '@angular/common': - specifier: 20.3.6 - version: 20.3.6(@angular/core@20.3.6(@angular/compiler@20.3.6)(rxjs@7.8.2)(zone.js@0.15.1))(rxjs@7.8.2) + specifier: 20.3.7 + version: 20.3.7(@angular/core@20.3.7(@angular/compiler@20.3.7)(rxjs@7.8.2)(zone.js@0.15.1))(rxjs@7.8.2) '@angular/compiler': - specifier: 20.3.6 - version: 20.3.6 + specifier: 20.3.7 + version: 20.3.7 '@angular/compiler-cli': - specifier: 20.3.6 - version: 20.3.6(@angular/compiler@20.3.6)(typescript@5.9.2) + specifier: 20.3.7 + version: 20.3.7(@angular/compiler@20.3.7)(typescript@5.9.2) '@angular/core': - specifier: 20.3.6 - version: 20.3.6(@angular/compiler@20.3.6)(rxjs@7.8.2)(zone.js@0.15.1) + specifier: 20.3.7 + version: 20.3.7(@angular/compiler@20.3.7)(rxjs@7.8.2)(zone.js@0.15.1) '@angular/forms': - specifier: 20.3.6 - version: 20.3.6(@angular/common@20.3.6(@angular/core@20.3.6(@angular/compiler@20.3.6)(rxjs@7.8.2)(zone.js@0.15.1))(rxjs@7.8.2))(@angular/core@20.3.6(@angular/compiler@20.3.6)(rxjs@7.8.2)(zone.js@0.15.1))(@angular/platform-browser@20.3.6(@angular/animations@20.3.6(@angular/core@20.3.6(@angular/compiler@20.3.6)(rxjs@7.8.2)(zone.js@0.15.1)))(@angular/common@20.3.6(@angular/core@20.3.6(@angular/compiler@20.3.6)(rxjs@7.8.2)(zone.js@0.15.1))(rxjs@7.8.2))(@angular/core@20.3.6(@angular/compiler@20.3.6)(rxjs@7.8.2)(zone.js@0.15.1)))(rxjs@7.8.2) + specifier: 20.3.7 + version: 20.3.7(@angular/common@20.3.7(@angular/core@20.3.7(@angular/compiler@20.3.7)(rxjs@7.8.2)(zone.js@0.15.1))(rxjs@7.8.2))(@angular/core@20.3.7(@angular/compiler@20.3.7)(rxjs@7.8.2)(zone.js@0.15.1))(@angular/platform-browser@20.3.7(@angular/animations@20.3.7(@angular/core@20.3.7(@angular/compiler@20.3.7)(rxjs@7.8.2)(zone.js@0.15.1)))(@angular/common@20.3.7(@angular/core@20.3.7(@angular/compiler@20.3.7)(rxjs@7.8.2)(zone.js@0.15.1))(rxjs@7.8.2))(@angular/core@20.3.7(@angular/compiler@20.3.7)(rxjs@7.8.2)(zone.js@0.15.1)))(rxjs@7.8.2) '@angular/localize': - specifier: 20.3.6 - version: 20.3.6(@angular/compiler-cli@20.3.6(@angular/compiler@20.3.6)(typescript@5.9.2))(@angular/compiler@20.3.6) + specifier: 20.3.7 + version: 20.3.7(@angular/compiler-cli@20.3.7(@angular/compiler@20.3.7)(typescript@5.9.2))(@angular/compiler@20.3.7) '@angular/material': - specifier: 20.2.9 - version: 20.2.9(2a95e28ac5632fb7b160d9783a0bce26) + specifier: 20.2.10 + version: 20.2.10(72d1932aa29c0670c8359e3ed8a5ff55) '@angular/ng-dev': - specifier: https://github.com/angular/dev-infra-private-ng-dev-builds.git#3c4fd6f54f2c67ce5b9f1a32ce90e36ba2fada4e - version: https://codeload.github.com/angular/dev-infra-private-ng-dev-builds/tar.gz/3c4fd6f54f2c67ce5b9f1a32ce90e36ba2fada4e(@modelcontextprotocol/sdk@1.17.3) + specifier: https://github.com/angular/dev-infra-private-ng-dev-builds.git#a3426d37e6f9781b00650a767eb5b3967cdb94f7 + version: https://codeload.github.com/angular/dev-infra-private-ng-dev-builds/tar.gz/a3426d37e6f9781b00650a767eb5b3967cdb94f7(@modelcontextprotocol/sdk@1.17.3) '@angular/platform-browser': - specifier: 20.3.6 - version: 20.3.6(@angular/animations@20.3.6(@angular/core@20.3.6(@angular/compiler@20.3.6)(rxjs@7.8.2)(zone.js@0.15.1)))(@angular/common@20.3.6(@angular/core@20.3.6(@angular/compiler@20.3.6)(rxjs@7.8.2)(zone.js@0.15.1))(rxjs@7.8.2))(@angular/core@20.3.6(@angular/compiler@20.3.6)(rxjs@7.8.2)(zone.js@0.15.1)) + specifier: 20.3.7 + version: 20.3.7(@angular/animations@20.3.7(@angular/core@20.3.7(@angular/compiler@20.3.7)(rxjs@7.8.2)(zone.js@0.15.1)))(@angular/common@20.3.7(@angular/core@20.3.7(@angular/compiler@20.3.7)(rxjs@7.8.2)(zone.js@0.15.1))(rxjs@7.8.2))(@angular/core@20.3.7(@angular/compiler@20.3.7)(rxjs@7.8.2)(zone.js@0.15.1)) '@angular/platform-server': - specifier: 20.3.6 - version: 20.3.6(@angular/common@20.3.6(@angular/core@20.3.6(@angular/compiler@20.3.6)(rxjs@7.8.2)(zone.js@0.15.1))(rxjs@7.8.2))(@angular/compiler@20.3.6)(@angular/core@20.3.6(@angular/compiler@20.3.6)(rxjs@7.8.2)(zone.js@0.15.1))(@angular/platform-browser@20.3.6(@angular/animations@20.3.6(@angular/core@20.3.6(@angular/compiler@20.3.6)(rxjs@7.8.2)(zone.js@0.15.1)))(@angular/common@20.3.6(@angular/core@20.3.6(@angular/compiler@20.3.6)(rxjs@7.8.2)(zone.js@0.15.1))(rxjs@7.8.2))(@angular/core@20.3.6(@angular/compiler@20.3.6)(rxjs@7.8.2)(zone.js@0.15.1)))(rxjs@7.8.2) + specifier: 20.3.7 + version: 20.3.7(@angular/common@20.3.7(@angular/core@20.3.7(@angular/compiler@20.3.7)(rxjs@7.8.2)(zone.js@0.15.1))(rxjs@7.8.2))(@angular/compiler@20.3.7)(@angular/core@20.3.7(@angular/compiler@20.3.7)(rxjs@7.8.2)(zone.js@0.15.1))(@angular/platform-browser@20.3.7(@angular/animations@20.3.7(@angular/core@20.3.7(@angular/compiler@20.3.7)(rxjs@7.8.2)(zone.js@0.15.1)))(@angular/common@20.3.7(@angular/core@20.3.7(@angular/compiler@20.3.7)(rxjs@7.8.2)(zone.js@0.15.1))(rxjs@7.8.2))(@angular/core@20.3.7(@angular/compiler@20.3.7)(rxjs@7.8.2)(zone.js@0.15.1)))(rxjs@7.8.2) '@angular/router': - specifier: 20.3.6 - version: 20.3.6(@angular/common@20.3.6(@angular/core@20.3.6(@angular/compiler@20.3.6)(rxjs@7.8.2)(zone.js@0.15.1))(rxjs@7.8.2))(@angular/core@20.3.6(@angular/compiler@20.3.6)(rxjs@7.8.2)(zone.js@0.15.1))(@angular/platform-browser@20.3.6(@angular/animations@20.3.6(@angular/core@20.3.6(@angular/compiler@20.3.6)(rxjs@7.8.2)(zone.js@0.15.1)))(@angular/common@20.3.6(@angular/core@20.3.6(@angular/compiler@20.3.6)(rxjs@7.8.2)(zone.js@0.15.1))(rxjs@7.8.2))(@angular/core@20.3.6(@angular/compiler@20.3.6)(rxjs@7.8.2)(zone.js@0.15.1)))(rxjs@7.8.2) + specifier: 20.3.7 + version: 20.3.7(@angular/common@20.3.7(@angular/core@20.3.7(@angular/compiler@20.3.7)(rxjs@7.8.2)(zone.js@0.15.1))(rxjs@7.8.2))(@angular/core@20.3.7(@angular/compiler@20.3.7)(rxjs@7.8.2)(zone.js@0.15.1))(@angular/platform-browser@20.3.7(@angular/animations@20.3.7(@angular/core@20.3.7(@angular/compiler@20.3.7)(rxjs@7.8.2)(zone.js@0.15.1)))(@angular/common@20.3.7(@angular/core@20.3.7(@angular/compiler@20.3.7)(rxjs@7.8.2)(zone.js@0.15.1))(rxjs@7.8.2))(@angular/core@20.3.7(@angular/compiler@20.3.7)(rxjs@7.8.2)(zone.js@0.15.1)))(rxjs@7.8.2) '@angular/service-worker': - specifier: 20.3.6 - version: 20.3.6(@angular/core@20.3.6(@angular/compiler@20.3.6)(rxjs@7.8.2)(zone.js@0.15.1))(rxjs@7.8.2) + specifier: 20.3.7 + version: 20.3.7(@angular/core@20.3.7(@angular/compiler@20.3.7)(rxjs@7.8.2)(zone.js@0.15.1))(rxjs@7.8.2) '@bazel/bazelisk': specifier: 1.26.0 version: 1.26.0 @@ -342,7 +342,7 @@ importers: version: 7.8.2 vitest: specifier: 3.2.4 - version: 3.2.4(@types/node@24.8.1)(jiti@1.21.7)(jsdom@26.1.0(bufferutil@4.0.9)(utf-8-validate@6.0.5))(less@4.4.0)(sass@1.90.0)(terser@5.43.1)(tsx@4.20.6)(yaml@2.8.1) + version: 3.2.4(@types/node@24.9.1)(jiti@1.21.7)(jsdom@26.1.0(bufferutil@4.0.9)(utf-8-validate@6.0.5))(less@4.4.0)(sass@1.90.0)(terser@5.43.1)(tsx@4.20.6)(yaml@2.8.1) packages/angular/build: dependencies: @@ -363,10 +363,10 @@ importers: version: 7.24.7 '@inquirer/confirm': specifier: 5.1.14 - version: 5.1.14(@types/node@24.8.1) + version: 5.1.14(@types/node@24.9.1) '@vitejs/plugin-basic-ssl': specifier: 2.1.0 - version: 2.1.0(vite@7.1.11(@types/node@24.8.1)(jiti@1.21.7)(less@4.4.0)(sass@1.90.0)(terser@5.43.1)(tsx@4.20.6)(yaml@2.8.1)) + version: 2.1.0(vite@7.1.11(@types/node@24.9.1)(jiti@1.21.7)(less@4.4.0)(sass@1.90.0)(terser@5.43.1)(tsx@4.20.6)(yaml@2.8.1)) beasties: specifier: 0.3.5 version: 0.3.5 @@ -420,7 +420,7 @@ importers: version: 0.2.14 vite: specifier: 7.1.11 - version: 7.1.11(@types/node@24.8.1)(jiti@1.21.7)(less@4.4.0)(sass@1.90.0)(terser@5.43.1)(tsx@4.20.6)(yaml@2.8.1) + version: 7.1.11(@types/node@24.9.1)(jiti@1.21.7)(less@4.4.0)(sass@1.90.0)(terser@5.43.1)(tsx@4.20.6)(yaml@2.8.1) watchpack: specifier: 2.4.4 version: 2.4.4 @@ -439,7 +439,7 @@ importers: version: 4.4.0 ng-packagr: specifier: 20.3.0 - version: 20.3.0(@angular/compiler-cli@20.3.6(@angular/compiler@20.3.6)(typescript@5.9.2))(tslib@2.8.1)(typescript@5.9.2) + version: 20.3.0(@angular/compiler-cli@20.3.7(@angular/compiler@20.3.7)(typescript@5.9.2))(tslib@2.8.1)(typescript@5.9.2) postcss: specifier: 8.5.6 version: 8.5.6 @@ -448,7 +448,7 @@ importers: version: 7.8.2 vitest: specifier: 3.2.4 - version: 3.2.4(@types/node@24.8.1)(jiti@1.21.7)(jsdom@26.1.0(bufferutil@4.0.9)(utf-8-validate@6.0.5))(less@4.4.0)(sass@1.90.0)(terser@5.43.1)(tsx@4.20.6)(yaml@2.8.1) + version: 3.2.4(@types/node@24.9.1)(jiti@1.21.7)(jsdom@26.1.0(bufferutil@4.0.9)(utf-8-validate@6.0.5))(less@4.4.0)(sass@1.90.0)(terser@5.43.1)(tsx@4.20.6)(yaml@2.8.1) optionalDependencies: lmdb: specifier: 3.4.2 @@ -467,10 +467,10 @@ importers: version: link:../../angular_devkit/schematics '@inquirer/prompts': specifier: 7.8.2 - version: 7.8.2(@types/node@24.8.1) + version: 7.8.2(@types/node@24.9.1) '@listr2/prompt-adapter-inquirer': specifier: 3.0.1 - version: 3.0.1(@inquirer/prompts@7.8.2(@types/node@24.8.1))(@types/node@24.8.1)(listr2@9.0.1) + version: 3.0.1(@inquirer/prompts@7.8.2(@types/node@24.9.1))(@types/node@24.9.1)(listr2@9.0.1) '@modelcontextprotocol/sdk': specifier: 1.17.3 version: 1.17.3 @@ -533,23 +533,23 @@ importers: specifier: workspace:* version: link:../../angular_devkit/schematics '@angular/common': - specifier: 20.3.6 - version: 20.3.6(@angular/core@20.3.6(@angular/compiler@20.3.6)(rxjs@7.8.2)(zone.js@0.15.1))(rxjs@7.8.2) + specifier: 20.3.7 + version: 20.3.7(@angular/core@20.3.7(@angular/compiler@20.3.7)(rxjs@7.8.2)(zone.js@0.15.1))(rxjs@7.8.2) '@angular/compiler': - specifier: 20.3.6 - version: 20.3.6 + specifier: 20.3.7 + version: 20.3.7 '@angular/core': - specifier: 20.3.6 - version: 20.3.6(@angular/compiler@20.3.6)(rxjs@7.8.2)(zone.js@0.15.1) + specifier: 20.3.7 + version: 20.3.7(@angular/compiler@20.3.7)(rxjs@7.8.2)(zone.js@0.15.1) '@angular/platform-browser': - specifier: 20.3.6 - version: 20.3.6(@angular/animations@20.3.6(@angular/core@20.3.6(@angular/compiler@20.3.6)(rxjs@7.8.2)(zone.js@0.15.1)))(@angular/common@20.3.6(@angular/core@20.3.6(@angular/compiler@20.3.6)(rxjs@7.8.2)(zone.js@0.15.1))(rxjs@7.8.2))(@angular/core@20.3.6(@angular/compiler@20.3.6)(rxjs@7.8.2)(zone.js@0.15.1)) + specifier: 20.3.7 + version: 20.3.7(@angular/animations@20.3.7(@angular/core@20.3.7(@angular/compiler@20.3.7)(rxjs@7.8.2)(zone.js@0.15.1)))(@angular/common@20.3.7(@angular/core@20.3.7(@angular/compiler@20.3.7)(rxjs@7.8.2)(zone.js@0.15.1))(rxjs@7.8.2))(@angular/core@20.3.7(@angular/compiler@20.3.7)(rxjs@7.8.2)(zone.js@0.15.1)) '@angular/platform-server': - specifier: 20.3.6 - version: 20.3.6(@angular/common@20.3.6(@angular/core@20.3.6(@angular/compiler@20.3.6)(rxjs@7.8.2)(zone.js@0.15.1))(rxjs@7.8.2))(@angular/compiler@20.3.6)(@angular/core@20.3.6(@angular/compiler@20.3.6)(rxjs@7.8.2)(zone.js@0.15.1))(@angular/platform-browser@20.3.6(@angular/animations@20.3.6(@angular/core@20.3.6(@angular/compiler@20.3.6)(rxjs@7.8.2)(zone.js@0.15.1)))(@angular/common@20.3.6(@angular/core@20.3.6(@angular/compiler@20.3.6)(rxjs@7.8.2)(zone.js@0.15.1))(rxjs@7.8.2))(@angular/core@20.3.6(@angular/compiler@20.3.6)(rxjs@7.8.2)(zone.js@0.15.1)))(rxjs@7.8.2) + specifier: 20.3.7 + version: 20.3.7(@angular/common@20.3.7(@angular/core@20.3.7(@angular/compiler@20.3.7)(rxjs@7.8.2)(zone.js@0.15.1))(rxjs@7.8.2))(@angular/compiler@20.3.7)(@angular/core@20.3.7(@angular/compiler@20.3.7)(rxjs@7.8.2)(zone.js@0.15.1))(@angular/platform-browser@20.3.7(@angular/animations@20.3.7(@angular/core@20.3.7(@angular/compiler@20.3.7)(rxjs@7.8.2)(zone.js@0.15.1)))(@angular/common@20.3.7(@angular/core@20.3.7(@angular/compiler@20.3.7)(rxjs@7.8.2)(zone.js@0.15.1))(rxjs@7.8.2))(@angular/core@20.3.7(@angular/compiler@20.3.7)(rxjs@7.8.2)(zone.js@0.15.1)))(rxjs@7.8.2) '@angular/router': - specifier: 20.3.6 - version: 20.3.6(@angular/common@20.3.6(@angular/core@20.3.6(@angular/compiler@20.3.6)(rxjs@7.8.2)(zone.js@0.15.1))(rxjs@7.8.2))(@angular/core@20.3.6(@angular/compiler@20.3.6)(rxjs@7.8.2)(zone.js@0.15.1))(@angular/platform-browser@20.3.6(@angular/animations@20.3.6(@angular/core@20.3.6(@angular/compiler@20.3.6)(rxjs@7.8.2)(zone.js@0.15.1)))(@angular/common@20.3.6(@angular/core@20.3.6(@angular/compiler@20.3.6)(rxjs@7.8.2)(zone.js@0.15.1))(rxjs@7.8.2))(@angular/core@20.3.6(@angular/compiler@20.3.6)(rxjs@7.8.2)(zone.js@0.15.1)))(rxjs@7.8.2) + specifier: 20.3.7 + version: 20.3.7(@angular/common@20.3.7(@angular/core@20.3.7(@angular/compiler@20.3.7)(rxjs@7.8.2)(zone.js@0.15.1))(rxjs@7.8.2))(@angular/core@20.3.7(@angular/compiler@20.3.7)(rxjs@7.8.2)(zone.js@0.15.1))(@angular/platform-browser@20.3.7(@angular/animations@20.3.7(@angular/core@20.3.7(@angular/compiler@20.3.7)(rxjs@7.8.2)(zone.js@0.15.1)))(@angular/common@20.3.7(@angular/core@20.3.7(@angular/compiler@20.3.7)(rxjs@7.8.2)(zone.js@0.15.1))(rxjs@7.8.2))(@angular/core@20.3.7(@angular/compiler@20.3.7)(rxjs@7.8.2)(zone.js@0.15.1)))(rxjs@7.8.2) '@schematics/angular': specifier: workspace:* version: link:../../schematics/angular @@ -761,7 +761,7 @@ importers: version: 3.0.4(bufferutil@4.0.9) ng-packagr: specifier: 20.3.0 - version: 20.3.0(@angular/compiler-cli@20.3.6(@angular/compiler@20.3.6)(typescript@5.9.2))(tslib@2.8.1)(typescript@5.9.2) + version: 20.3.0(@angular/compiler-cli@20.3.7(@angular/compiler@20.3.7)(typescript@5.9.2))(tslib@2.8.1)(typescript@5.9.2) undici: specifier: 7.13.0 version: 7.13.0 @@ -845,7 +845,7 @@ importers: version: link:../schematics '@inquirer/prompts': specifier: 7.8.2 - version: 7.8.2(@types/node@24.8.1) + version: 7.8.2(@types/node@24.9.1) ansi-colors: specifier: 4.1.3 version: 4.1.3 @@ -859,11 +859,11 @@ importers: specifier: workspace:0.0.0-PLACEHOLDER version: link:../../angular_devkit/core '@angular/compiler': - specifier: 20.3.6 - version: 20.3.6 + specifier: 20.3.7 + version: 20.3.7 '@angular/compiler-cli': - specifier: 20.3.6 - version: 20.3.6(@angular/compiler@20.3.6)(typescript@5.9.2) + specifier: 20.3.7 + version: 20.3.7(@angular/compiler@20.3.7)(typescript@5.9.2) typescript: specifier: 5.9.2 version: 5.9.2 @@ -975,46 +975,46 @@ packages: resolution: {integrity: sha512-30iZtAPgz+LTIYoeivqYo853f02jBYSd5uGnGpkFV0M3xOt9aN73erkgYAmZU43x4VfqcnLxW9Kpg3R5LC4YYw==} engines: {node: '>=6.0.0'} - '@angular/animations@20.3.6': - resolution: {integrity: sha512-qNaVvEOKvigoCQMg0ABnq44HhiHqKD4WN3KoUcXneklcMYCzFE5nuQxKylfWzCRiI5XqiJ9pqiL1m2D7o+Vdiw==} + '@angular/animations@20.3.7': + resolution: {integrity: sha512-i655RaL0zmLE3OESUlDnRNBDRIMW/67nTQvMqP6V1cQ42l2+SMJtREsxmX6cWt55/qvvgeytAA6aBN4aerBl5A==} engines: {node: ^20.19.0 || ^22.12.0 || >=24.0.0} peerDependencies: - '@angular/core': 20.3.6 + '@angular/core': 20.3.7 - '@angular/cdk@20.2.9': - resolution: {integrity: sha512-rbY1AMz9389WJI29iAjWp4o0QKRQHCrQQUuP0ctNQzh1tgWpwiRLx8N4yabdVdsCA846vPsyKJtBlSNwKMsjJA==} + '@angular/cdk@20.2.10': + resolution: {integrity: sha512-d95C2r3JP11KCahouWmPaxswz/EE7Zn1k8ocoGt70jl33x42Sg96vAHeOpnQ4yfrdA4W7Q+eWB/NqqvAGCzOPQ==} peerDependencies: '@angular/common': ^20.0.0 || ^21.0.0 '@angular/core': ^20.0.0 || ^21.0.0 rxjs: ^6.5.3 || ^7.4.0 - '@angular/common@20.3.6': - resolution: {integrity: sha512-+gHMuFe0wz4f+vfGZ2q+fSQSYaY7KlN7QdDrFqLnA7H2sythzhXvRbXEtp4DkPjihh9gupXg2MeLh1ROy5AfSw==} + '@angular/common@20.3.7': + resolution: {integrity: sha512-uf8dXYTJbedk/wudkt2MfbtvN/T97aEZBtOTq8/IFQQZ3722rag6D+Cg76e5hBccROOn+ueGJX2gpxz02phTwA==} engines: {node: ^20.19.0 || ^22.12.0 || >=24.0.0} peerDependencies: - '@angular/core': 20.3.6 + '@angular/core': 20.3.7 rxjs: ^6.5.3 || ^7.4.0 - '@angular/compiler-cli@20.3.6': - resolution: {integrity: sha512-VOFRBx9fBt2jW9I8qD23fwGeKxBI8JssJBAMqnFPl3k59VJWHQi6LlXZCLCBNdfwflTJdKeRvdgT51Q0k6tnFQ==} + '@angular/compiler-cli@20.3.7': + resolution: {integrity: sha512-viZwWlwc1BAqryRJE0Wq2WgAxDaW9fuwtYHYrOWnIn9sy9KemKmR6RmU9VRydrwUROOlqK49R9+RC1wQ6sYwqA==} engines: {node: ^20.19.0 || ^22.12.0 || >=24.0.0} hasBin: true peerDependencies: - '@angular/compiler': 20.3.6 + '@angular/compiler': 20.3.7 typescript: 5.9.2 peerDependenciesMeta: typescript: optional: true - '@angular/compiler@20.3.6': - resolution: {integrity: sha512-OdjXBsAsnn7qiW6fSHClwn9XwjVxhtO9+RbDc6Mf+YPCnJq0s8T78H2fc8VdJFp/Rs+tMZcwwjd9VZPm8+2XWA==} + '@angular/compiler@20.3.7': + resolution: {integrity: sha512-EouHO15dUsgnFArj0M25R8cOPVoUfiFYSt6iXnMO8+S4dY1fDEmbFqkW5smlP66HL5Gys59Nwb5inejfIWHrLw==} engines: {node: ^20.19.0 || ^22.12.0 || >=24.0.0} - '@angular/core@20.3.6': - resolution: {integrity: sha512-sDURQWnjwE4Y750u/5qwkZEYMoI4CrKghnx4aKulxCnohR3//C78wvz6p8MtCuqYfzGkdQZDYFg8tgAz17qgPw==} + '@angular/core@20.3.7': + resolution: {integrity: sha512-2UuYzC2A5SUtu33tYTN411Wk0WilA+2Uld/GP3O6mragw1O7v/M8pMFmbe9TR5Ah/abRJIocWGlNqeztZmQmrw==} engines: {node: ^20.19.0 || ^22.12.0 || >=24.0.0} peerDependencies: - '@angular/compiler': 20.3.6 + '@angular/compiler': 20.3.7 rxjs: ^6.5.3 || ^7.4.0 zone.js: ~0.15.0 peerDependenciesMeta: @@ -1023,74 +1023,74 @@ packages: zone.js: optional: true - '@angular/forms@20.3.6': - resolution: {integrity: sha512-tBGo/LBtCtSrClMY4DTm/3UiSjqLLMEYXS/4E0nW1mFDv7ulKnaAQB+KbfBmmTHYxlKLs+SxjKv6GoydMPSurA==} + '@angular/forms@20.3.7': + resolution: {integrity: sha512-uOCGCoqXeAWIlQMWiIeed/W8g8h2tk91YemMI+Ce1VQ/36Xfft40Bouz4eKcvJV6kLXGygdpWjzFGz32CE+3Og==} engines: {node: ^20.19.0 || ^22.12.0 || >=24.0.0} peerDependencies: - '@angular/common': 20.3.6 - '@angular/core': 20.3.6 - '@angular/platform-browser': 20.3.6 + '@angular/common': 20.3.7 + '@angular/core': 20.3.7 + '@angular/platform-browser': 20.3.7 rxjs: ^6.5.3 || ^7.4.0 - '@angular/localize@20.3.6': - resolution: {integrity: sha512-isOHiGYHSK+ySK8ry21PGO3jpJpF90E3J2BZ+LUhzpi1SzFBguEVg7j8fvbCLodiwweOnuAiKEHO0F3WpfCQ9Q==} + '@angular/localize@20.3.7': + resolution: {integrity: sha512-FYuuwU9ujiVT+0xjMIutaUT2PErV4AvxeAPWMlYRA1/yQxqn1VyNUd6kHPjAV+yrZg9Q0MDco2/c0Lh8rmAhSA==} engines: {node: ^20.19.0 || ^22.12.0 || >=24.0.0} hasBin: true peerDependencies: - '@angular/compiler': 20.3.6 - '@angular/compiler-cli': 20.3.6 + '@angular/compiler': 20.3.7 + '@angular/compiler-cli': 20.3.7 - '@angular/material@20.2.9': - resolution: {integrity: sha512-xo/ozyRXCoJMi89XLTJI6fdPKBv2wBngWMiCrtTg23+pHbuyA/kDbk3v62eJkDD1xdhC4auXaIHu4Ddf5zTgSA==} + '@angular/material@20.2.10': + resolution: {integrity: sha512-WkJfUu7KiQY2lqHjMZtEKBG653sPmky0nytTMASsfQ/xUs56W3CAAEOuKhSyCNKsNeFJZS/NgJnvlpRzcE5k6g==} peerDependencies: - '@angular/cdk': 20.2.9 + '@angular/cdk': 20.2.10 '@angular/common': ^20.0.0 || ^21.0.0 '@angular/core': ^20.0.0 || ^21.0.0 '@angular/forms': ^20.0.0 || ^21.0.0 '@angular/platform-browser': ^20.0.0 || ^21.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/3c4fd6f54f2c67ce5b9f1a32ce90e36ba2fada4e': - resolution: {tarball: https://codeload.github.com/angular/dev-infra-private-ng-dev-builds/tar.gz/3c4fd6f54f2c67ce5b9f1a32ce90e36ba2fada4e} - version: 0.0.0-c584c3565b71c7a8cda81d55bb14e3e66ef934da + '@angular/ng-dev@https://codeload.github.com/angular/dev-infra-private-ng-dev-builds/tar.gz/a3426d37e6f9781b00650a767eb5b3967cdb94f7': + resolution: {tarball: https://codeload.github.com/angular/dev-infra-private-ng-dev-builds/tar.gz/a3426d37e6f9781b00650a767eb5b3967cdb94f7} + version: 0.0.0-43d4ea5534ce399657a64c94a9dc1ea883324804 hasBin: true - '@angular/platform-browser@20.3.6': - resolution: {integrity: sha512-gFp1yd+HtRN8XdpMatRLO5w6FLIzsnF31lD2Duo4BUTCoMAMdfaNT6FtcvNdKu7ANo27Ke26fxEEE2bh6FU98A==} + '@angular/platform-browser@20.3.7': + resolution: {integrity: sha512-AbLtyR7fVEGDYyrz95dP2pc69J5XIjLLsFNAuNQPzNX02WPoAxtrWrNY6UnTzGoSrCc5F52hiL2Uo6yPZTiJcg==} engines: {node: ^20.19.0 || ^22.12.0 || >=24.0.0} peerDependencies: - '@angular/animations': 20.3.6 - '@angular/common': 20.3.6 - '@angular/core': 20.3.6 + '@angular/animations': 20.3.7 + '@angular/common': 20.3.7 + '@angular/core': 20.3.7 peerDependenciesMeta: '@angular/animations': optional: true - '@angular/platform-server@20.3.6': - resolution: {integrity: sha512-fWF20pZYt8+4ZbNEwQsSgvBc11g8QWiVW7a0ybPvn7fy4LsTLWPzpolGK54k3FqWTQsZfzt+tVcNS709FPETfw==} + '@angular/platform-server@20.3.7': + resolution: {integrity: sha512-ADqOwqeUpTkp97SUpNO4jZ0o9Du7oBpi0mqzLx/c1dQYgL5hKAZYpa7bpG/edn2nSMHXwQAaGw7t+MTmU7elxQ==} engines: {node: ^20.19.0 || ^22.12.0 || >=24.0.0} peerDependencies: - '@angular/common': 20.3.6 - '@angular/compiler': 20.3.6 - '@angular/core': 20.3.6 - '@angular/platform-browser': 20.3.6 + '@angular/common': 20.3.7 + '@angular/compiler': 20.3.7 + '@angular/core': 20.3.7 + '@angular/platform-browser': 20.3.7 rxjs: ^6.5.3 || ^7.4.0 - '@angular/router@20.3.6': - resolution: {integrity: sha512-fSAYOR9nKpH5PoBYFNdII3nAFl2maUrYiISU33CnGwb7J7Q0s09k231c/P5tVN4URi+jdADVwiBI8cIYk8SVrg==} + '@angular/router@20.3.7': + resolution: {integrity: sha512-Lq7mCNcLP1npmNh2JlNEe02YS2jNnaLnCy/t//o+Qq0c6DGV78JRl7pHubiB2R6XXlgvOcZWg88v94Li+y85Iw==} engines: {node: ^20.19.0 || ^22.12.0 || >=24.0.0} peerDependencies: - '@angular/common': 20.3.6 - '@angular/core': 20.3.6 - '@angular/platform-browser': 20.3.6 + '@angular/common': 20.3.7 + '@angular/core': 20.3.7 + '@angular/platform-browser': 20.3.7 rxjs: ^6.5.3 || ^7.4.0 - '@angular/service-worker@20.3.6': - resolution: {integrity: sha512-utHJCoEO4EKH372BSMnNbcR96yDVkUeV7xcJb+cw9ruTOxGvCG/DUWR1h64xk3Ns6nvFmggTnIVgnBDn+92VpQ==} + '@angular/service-worker@20.3.7': + resolution: {integrity: sha512-q9Q77wBBqScRJJQ7T+F0RepMY543Hm0HCZGvOujT+vQNFK3aRlWLlYenOUIhq2vlLXOhszCt8e5dY7/R+1eRWw==} engines: {node: ^20.19.0 || ^22.12.0 || >=24.0.0} hasBin: true peerDependencies: - '@angular/core': 20.3.6 + '@angular/core': 20.3.7 rxjs: ^6.5.3 || ^7.4.0 '@asamuzakjp/css-color@3.2.0': @@ -2787,8 +2787,8 @@ packages: '@octokit/openapi-types@26.0.0': resolution: {integrity: sha512-7AtcfKtpo77j7Ts73b4OWhOZHTKo/gGY8bB3bNBQz4H+GRSWqx2yvj8TXRsbdTE0eRmYmXOEY66jM7mJ7LzfsA==} - '@octokit/plugin-paginate-rest@13.2.0': - resolution: {integrity: sha512-YuAlyjR8o5QoRSOvMHxSJzPtogkNMgeMv2mpccrvdUGeC3MKyfi/hS+KiFwyH/iRKIKyx+eIMsDjbt3p9r2GYA==} + '@octokit/plugin-paginate-rest@13.2.1': + resolution: {integrity: sha512-Tj4PkZyIL6eBMYcG/76QGsedF0+dWVeLhYprTmuFVVxzDW7PQh23tM0TP0z+1MvSkxB29YFZwnUX+cXfTiSdyw==} engines: {node: '>= 20'} peerDependencies: '@octokit/core': '>=6' @@ -2799,8 +2799,8 @@ packages: peerDependencies: '@octokit/core': '>=6' - '@octokit/plugin-rest-endpoint-methods@16.1.0': - resolution: {integrity: sha512-nCsyiKoGRnhH5LkH8hJEZb9swpqOcsW+VXv1QoyUNQXJeVODG4+xM6UICEqyqe9XFr6LkL8BIiFCPev8zMDXPw==} + '@octokit/plugin-rest-endpoint-methods@16.1.1': + resolution: {integrity: sha512-VztDkhM0ketQYSh5Im3IcKWFZl7VIrrsCaHbDINkdYeiiAsJzjhS2xRFCSJgfN6VOcsoW4laMtsmf3HcNqIimg==} engines: {node: '>= 20'} peerDependencies: '@octokit/core': '>=6' @@ -2817,8 +2817,8 @@ packages: resolution: {integrity: sha512-z6tmTu9BTnw51jYGulxrlernpsQYXpui1RK21vmXn8yF5bp6iX16yfTtJYGK5Mh1qDkvDOmp2n8sRMcQmR8jiA==} engines: {node: '>= 20'} - '@octokit/types@15.0.0': - resolution: {integrity: sha512-8o6yDfmoGJUIeR9OfYU0/TUJTnMPG2r68+1yEdUeG2Fdqpj8Qetg0ziKIgcBm0RW/j29H41WP37CYCEhp6GoHQ==} + '@octokit/types@15.0.1': + resolution: {integrity: sha512-sdiirM93IYJ9ODDCBgmRPIboLbSkpLa5i+WLuXH8b8Atg+YMLAyLvDDhNWLV4OYd08tlvYfVm/dw88cqHWtw1Q==} '@open-draft/deferred-promise@2.2.0': resolution: {integrity: sha512-CecwLWx3rhxVQF6V4bAgPS5t+So2sTbPgAzafKkVizyi7tlwpcFpdFqq+wqF2OwNBmqFuu6tOyouTuxgpMfzmA==} @@ -2949,16 +2949,16 @@ packages: resolution: {integrity: sha512-tNe7a6U4rCpxLMBaR0SIYTdjxGdL0Vwb3G1zY8++sPtHSvy7qd54u8CIB0Z+Y6t5tc9pNYMYCMwhE/wdSY7ltg==} engines: {node: '>=18.12'} - '@pnpm/dependency-path@1001.1.2': - resolution: {integrity: sha512-fih99/lY+HRRak0U0KMKAO7+nacilWMcvFTH6YDKzjCBTOhxDr6Eeap2mF7uf4ED4dnKsQVNUGmFpvaSXSuFCQ==} + '@pnpm/dependency-path@1001.1.3': + resolution: {integrity: sha512-ScPXDrlpNNrvV+l4Z1Mh7HjejkltQWfSa3PIaB+WJ3h+PoC1w5blbgfq6ENdHdkRU7L14ie/3MqUGMIx2gZldA==} engines: {node: '>=18.12'} '@pnpm/graceful-fs@1000.0.1': resolution: {integrity: sha512-JnzaAVFJIEgwTcB55eww8N3h5B6qJdZqDA2wYkSK+OcTvvMSQb9c2STMhBP6GfkWygG1fs3w8D7JRx9SPZnxJg==} engines: {node: '>=18.12'} - '@pnpm/types@1000.8.0': - resolution: {integrity: sha512-yx86CGHHquWAI0GgKIuV/RnYewcf5fVFZemC45C/K2cX0uV8GB8TUP541ZrokWola2fZx5sn1vL7xzbceRZfoQ==} + '@pnpm/types@1000.9.0': + resolution: {integrity: sha512-UvDTCxnbyqkTg2X0dBOuZ4IdFJ8g4UFu0Ybv/5/cZAxCWVhNl1hC/Xc9hR4tZrlBL0NRFePLRhO/iw9LmA1lbw==} engines: {node: '>=18.12'} '@protobufjs/aspromise@1.1.2': @@ -3536,8 +3536,8 @@ packages: '@types/node@22.18.10': resolution: {integrity: sha512-anNG/V/Efn/YZY4pRzbACnKxNKoBng2VTFydVu8RRs5hQjikP8CQfaeAV59VFSCzKNp90mXiVXW2QzV56rwMrg==} - '@types/node@24.8.1': - resolution: {integrity: sha512-alv65KGRadQVfVcG69MuB4IzdYVpRwMG/mq8KWOaoOdyY617P5ivaDiMCGOFDWD2sAn5Q0mR3mRtUOgm99hL9Q==} + '@types/node@24.9.1': + resolution: {integrity: sha512-QoiaXANRkSXK6p0Duvt56W208du4P9Uye9hWLWgGMDTEoKPhuenzNcC4vGUmrNkiOKTlIrBoyNQYNpSwfEZXSg==} '@types/npm-package-arg@6.1.4': resolution: {integrity: sha512-vDgdbMy2QXHnAruzlv68pUtXCjmqUk3WrBAsRboRovsOmxbfn/WiYCjmecyKjGztnMps5dWp4Uq2prp+Ilo17Q==} @@ -4660,8 +4660,8 @@ packages: resolution: {integrity: sha512-tQMagCOC59EVgNZcC5zl7XqO30Wki9i9J3acbUvkaosCT6JX3EeFwJD7Qqp4MCikRnzS18WXV3BLIQ66ytu6+Q==} engines: {node: '>=18'} - conventional-commits-parser@6.2.0: - resolution: {integrity: sha512-uLnoLeIW4XaoFtH37qEcg/SXMJmKF4vi7V0H2rnPueg+VEtFGA/asSCNTcq4M/GQ6QmlzchAEtOoDTtKqWeHag==} + conventional-commits-parser@6.2.1: + resolution: {integrity: sha512-20pyHgnO40rvfI0NGF/xiEoFMkXDtkF8FwHvk5BokoFoCuTQRI8vrNCNFWUOfuolKJMm1tPCHc8GgYEtr1XRNA==} engines: {node: '>=18'} hasBin: true @@ -8624,8 +8624,8 @@ packages: undici-types@6.21.0: resolution: {integrity: sha512-iwDZqg0QAGrg9Rav5H4n0M64c3mkR59cJ6wQp+7C4nI0gsmExaedaYLNO44eT4AtBBwjbTiGPMlt2Md0T9H9JQ==} - undici-types@7.14.0: - resolution: {integrity: sha512-QQiYxHuyZ9gQUIrmPo3IA+hUl4KYk8uSA7cHrcKd/l3p1OTpZcM0Tbp9x7FAtXdAYhlasd60ncPpgu6ihG6TOA==} + undici-types@7.16.0: + resolution: {integrity: sha512-Zz+aZWSj8LE6zoxD+xrjh4VfkIG8Ya6LvYkZqtUQGJPZjYl53ypCaUwWqo7eI0x66KBGeRo+mlBEkMSeSZ38Nw==} undici@5.29.0: resolution: {integrity: sha512-raqeBD6NQK4SkWhQzeYKd1KmIG6dllBOTt55Rmkt4HtI9mwdWtJljnrXjAFUBLTSN67HWrOIZ3EPF4kjUw80Bg==} @@ -9335,28 +9335,28 @@ snapshots: '@jridgewell/gen-mapping': 0.3.13 '@jridgewell/trace-mapping': 0.3.31 - '@angular/animations@20.3.6(@angular/core@20.3.6(@angular/compiler@20.3.6)(rxjs@7.8.2)(zone.js@0.15.1))': + '@angular/animations@20.3.7(@angular/core@20.3.7(@angular/compiler@20.3.7)(rxjs@7.8.2)(zone.js@0.15.1))': dependencies: - '@angular/core': 20.3.6(@angular/compiler@20.3.6)(rxjs@7.8.2)(zone.js@0.15.1) + '@angular/core': 20.3.7(@angular/compiler@20.3.7)(rxjs@7.8.2)(zone.js@0.15.1) tslib: 2.8.1 - '@angular/cdk@20.2.9(@angular/common@20.3.6(@angular/core@20.3.6(@angular/compiler@20.3.6)(rxjs@7.8.2)(zone.js@0.15.1))(rxjs@7.8.2))(@angular/core@20.3.6(@angular/compiler@20.3.6)(rxjs@7.8.2)(zone.js@0.15.1))(rxjs@7.8.2)': + '@angular/cdk@20.2.10(@angular/common@20.3.7(@angular/core@20.3.7(@angular/compiler@20.3.7)(rxjs@7.8.2)(zone.js@0.15.1))(rxjs@7.8.2))(@angular/core@20.3.7(@angular/compiler@20.3.7)(rxjs@7.8.2)(zone.js@0.15.1))(rxjs@7.8.2)': dependencies: - '@angular/common': 20.3.6(@angular/core@20.3.6(@angular/compiler@20.3.6)(rxjs@7.8.2)(zone.js@0.15.1))(rxjs@7.8.2) - '@angular/core': 20.3.6(@angular/compiler@20.3.6)(rxjs@7.8.2)(zone.js@0.15.1) + '@angular/common': 20.3.7(@angular/core@20.3.7(@angular/compiler@20.3.7)(rxjs@7.8.2)(zone.js@0.15.1))(rxjs@7.8.2) + '@angular/core': 20.3.7(@angular/compiler@20.3.7)(rxjs@7.8.2)(zone.js@0.15.1) parse5: 8.0.0 rxjs: 7.8.2 tslib: 2.8.1 - '@angular/common@20.3.6(@angular/core@20.3.6(@angular/compiler@20.3.6)(rxjs@7.8.2)(zone.js@0.15.1))(rxjs@7.8.2)': + '@angular/common@20.3.7(@angular/core@20.3.7(@angular/compiler@20.3.7)(rxjs@7.8.2)(zone.js@0.15.1))(rxjs@7.8.2)': dependencies: - '@angular/core': 20.3.6(@angular/compiler@20.3.6)(rxjs@7.8.2)(zone.js@0.15.1) + '@angular/core': 20.3.7(@angular/compiler@20.3.7)(rxjs@7.8.2)(zone.js@0.15.1) rxjs: 7.8.2 tslib: 2.8.1 - '@angular/compiler-cli@20.3.6(@angular/compiler@20.3.6)(typescript@5.9.2)': + '@angular/compiler-cli@20.3.7(@angular/compiler@20.3.7)(typescript@5.9.2)': dependencies: - '@angular/compiler': 20.3.6 + '@angular/compiler': 20.3.7 '@babel/core': 7.28.3 '@jridgewell/sourcemap-codec': 1.5.5 chokidar: 4.0.3 @@ -9370,30 +9370,30 @@ snapshots: transitivePeerDependencies: - supports-color - '@angular/compiler@20.3.6': + '@angular/compiler@20.3.7': dependencies: tslib: 2.8.1 - '@angular/core@20.3.6(@angular/compiler@20.3.6)(rxjs@7.8.2)(zone.js@0.15.1)': + '@angular/core@20.3.7(@angular/compiler@20.3.7)(rxjs@7.8.2)(zone.js@0.15.1)': dependencies: rxjs: 7.8.2 tslib: 2.8.1 optionalDependencies: - '@angular/compiler': 20.3.6 + '@angular/compiler': 20.3.7 zone.js: 0.15.1 - '@angular/forms@20.3.6(@angular/common@20.3.6(@angular/core@20.3.6(@angular/compiler@20.3.6)(rxjs@7.8.2)(zone.js@0.15.1))(rxjs@7.8.2))(@angular/core@20.3.6(@angular/compiler@20.3.6)(rxjs@7.8.2)(zone.js@0.15.1))(@angular/platform-browser@20.3.6(@angular/animations@20.3.6(@angular/core@20.3.6(@angular/compiler@20.3.6)(rxjs@7.8.2)(zone.js@0.15.1)))(@angular/common@20.3.6(@angular/core@20.3.6(@angular/compiler@20.3.6)(rxjs@7.8.2)(zone.js@0.15.1))(rxjs@7.8.2))(@angular/core@20.3.6(@angular/compiler@20.3.6)(rxjs@7.8.2)(zone.js@0.15.1)))(rxjs@7.8.2)': + '@angular/forms@20.3.7(@angular/common@20.3.7(@angular/core@20.3.7(@angular/compiler@20.3.7)(rxjs@7.8.2)(zone.js@0.15.1))(rxjs@7.8.2))(@angular/core@20.3.7(@angular/compiler@20.3.7)(rxjs@7.8.2)(zone.js@0.15.1))(@angular/platform-browser@20.3.7(@angular/animations@20.3.7(@angular/core@20.3.7(@angular/compiler@20.3.7)(rxjs@7.8.2)(zone.js@0.15.1)))(@angular/common@20.3.7(@angular/core@20.3.7(@angular/compiler@20.3.7)(rxjs@7.8.2)(zone.js@0.15.1))(rxjs@7.8.2))(@angular/core@20.3.7(@angular/compiler@20.3.7)(rxjs@7.8.2)(zone.js@0.15.1)))(rxjs@7.8.2)': dependencies: - '@angular/common': 20.3.6(@angular/core@20.3.6(@angular/compiler@20.3.6)(rxjs@7.8.2)(zone.js@0.15.1))(rxjs@7.8.2) - '@angular/core': 20.3.6(@angular/compiler@20.3.6)(rxjs@7.8.2)(zone.js@0.15.1) - '@angular/platform-browser': 20.3.6(@angular/animations@20.3.6(@angular/core@20.3.6(@angular/compiler@20.3.6)(rxjs@7.8.2)(zone.js@0.15.1)))(@angular/common@20.3.6(@angular/core@20.3.6(@angular/compiler@20.3.6)(rxjs@7.8.2)(zone.js@0.15.1))(rxjs@7.8.2))(@angular/core@20.3.6(@angular/compiler@20.3.6)(rxjs@7.8.2)(zone.js@0.15.1)) + '@angular/common': 20.3.7(@angular/core@20.3.7(@angular/compiler@20.3.7)(rxjs@7.8.2)(zone.js@0.15.1))(rxjs@7.8.2) + '@angular/core': 20.3.7(@angular/compiler@20.3.7)(rxjs@7.8.2)(zone.js@0.15.1) + '@angular/platform-browser': 20.3.7(@angular/animations@20.3.7(@angular/core@20.3.7(@angular/compiler@20.3.7)(rxjs@7.8.2)(zone.js@0.15.1)))(@angular/common@20.3.7(@angular/core@20.3.7(@angular/compiler@20.3.7)(rxjs@7.8.2)(zone.js@0.15.1))(rxjs@7.8.2))(@angular/core@20.3.7(@angular/compiler@20.3.7)(rxjs@7.8.2)(zone.js@0.15.1)) rxjs: 7.8.2 tslib: 2.8.1 - '@angular/localize@20.3.6(@angular/compiler-cli@20.3.6(@angular/compiler@20.3.6)(typescript@5.9.2))(@angular/compiler@20.3.6)': + '@angular/localize@20.3.7(@angular/compiler-cli@20.3.7(@angular/compiler@20.3.7)(typescript@5.9.2))(@angular/compiler@20.3.7)': dependencies: - '@angular/compiler': 20.3.6 - '@angular/compiler-cli': 20.3.6(@angular/compiler@20.3.6)(typescript@5.9.2) + '@angular/compiler': 20.3.7 + '@angular/compiler-cli': 20.3.7(@angular/compiler@20.3.7)(typescript@5.9.2) '@babel/core': 7.28.3 '@types/babel__core': 7.20.5 tinyglobby: 0.2.14 @@ -9401,41 +9401,41 @@ snapshots: transitivePeerDependencies: - supports-color - '@angular/material@20.2.9(2a95e28ac5632fb7b160d9783a0bce26)': + '@angular/material@20.2.10(72d1932aa29c0670c8359e3ed8a5ff55)': dependencies: - '@angular/cdk': 20.2.9(@angular/common@20.3.6(@angular/core@20.3.6(@angular/compiler@20.3.6)(rxjs@7.8.2)(zone.js@0.15.1))(rxjs@7.8.2))(@angular/core@20.3.6(@angular/compiler@20.3.6)(rxjs@7.8.2)(zone.js@0.15.1))(rxjs@7.8.2) - '@angular/common': 20.3.6(@angular/core@20.3.6(@angular/compiler@20.3.6)(rxjs@7.8.2)(zone.js@0.15.1))(rxjs@7.8.2) - '@angular/core': 20.3.6(@angular/compiler@20.3.6)(rxjs@7.8.2)(zone.js@0.15.1) - '@angular/forms': 20.3.6(@angular/common@20.3.6(@angular/core@20.3.6(@angular/compiler@20.3.6)(rxjs@7.8.2)(zone.js@0.15.1))(rxjs@7.8.2))(@angular/core@20.3.6(@angular/compiler@20.3.6)(rxjs@7.8.2)(zone.js@0.15.1))(@angular/platform-browser@20.3.6(@angular/animations@20.3.6(@angular/core@20.3.6(@angular/compiler@20.3.6)(rxjs@7.8.2)(zone.js@0.15.1)))(@angular/common@20.3.6(@angular/core@20.3.6(@angular/compiler@20.3.6)(rxjs@7.8.2)(zone.js@0.15.1))(rxjs@7.8.2))(@angular/core@20.3.6(@angular/compiler@20.3.6)(rxjs@7.8.2)(zone.js@0.15.1)))(rxjs@7.8.2) - '@angular/platform-browser': 20.3.6(@angular/animations@20.3.6(@angular/core@20.3.6(@angular/compiler@20.3.6)(rxjs@7.8.2)(zone.js@0.15.1)))(@angular/common@20.3.6(@angular/core@20.3.6(@angular/compiler@20.3.6)(rxjs@7.8.2)(zone.js@0.15.1))(rxjs@7.8.2))(@angular/core@20.3.6(@angular/compiler@20.3.6)(rxjs@7.8.2)(zone.js@0.15.1)) + '@angular/cdk': 20.2.10(@angular/common@20.3.7(@angular/core@20.3.7(@angular/compiler@20.3.7)(rxjs@7.8.2)(zone.js@0.15.1))(rxjs@7.8.2))(@angular/core@20.3.7(@angular/compiler@20.3.7)(rxjs@7.8.2)(zone.js@0.15.1))(rxjs@7.8.2) + '@angular/common': 20.3.7(@angular/core@20.3.7(@angular/compiler@20.3.7)(rxjs@7.8.2)(zone.js@0.15.1))(rxjs@7.8.2) + '@angular/core': 20.3.7(@angular/compiler@20.3.7)(rxjs@7.8.2)(zone.js@0.15.1) + '@angular/forms': 20.3.7(@angular/common@20.3.7(@angular/core@20.3.7(@angular/compiler@20.3.7)(rxjs@7.8.2)(zone.js@0.15.1))(rxjs@7.8.2))(@angular/core@20.3.7(@angular/compiler@20.3.7)(rxjs@7.8.2)(zone.js@0.15.1))(@angular/platform-browser@20.3.7(@angular/animations@20.3.7(@angular/core@20.3.7(@angular/compiler@20.3.7)(rxjs@7.8.2)(zone.js@0.15.1)))(@angular/common@20.3.7(@angular/core@20.3.7(@angular/compiler@20.3.7)(rxjs@7.8.2)(zone.js@0.15.1))(rxjs@7.8.2))(@angular/core@20.3.7(@angular/compiler@20.3.7)(rxjs@7.8.2)(zone.js@0.15.1)))(rxjs@7.8.2) + '@angular/platform-browser': 20.3.7(@angular/animations@20.3.7(@angular/core@20.3.7(@angular/compiler@20.3.7)(rxjs@7.8.2)(zone.js@0.15.1)))(@angular/common@20.3.7(@angular/core@20.3.7(@angular/compiler@20.3.7)(rxjs@7.8.2)(zone.js@0.15.1))(rxjs@7.8.2))(@angular/core@20.3.7(@angular/compiler@20.3.7)(rxjs@7.8.2)(zone.js@0.15.1)) rxjs: 7.8.2 tslib: 2.8.1 - '@angular/ng-dev@https://codeload.github.com/angular/dev-infra-private-ng-dev-builds/tar.gz/3c4fd6f54f2c67ce5b9f1a32ce90e36ba2fada4e(@modelcontextprotocol/sdk@1.17.3)': + '@angular/ng-dev@https://codeload.github.com/angular/dev-infra-private-ng-dev-builds/tar.gz/a3426d37e6f9781b00650a767eb5b3967cdb94f7(@modelcontextprotocol/sdk@1.17.3)': dependencies: '@actions/core': 1.11.1 '@google-cloud/spanner': 8.0.0(supports-color@10.2.2) '@google/genai': 1.25.0(@modelcontextprotocol/sdk@1.17.3)(bufferutil@4.0.9)(encoding@0.1.13)(supports-color@10.2.2)(utf-8-validate@6.0.5) - '@inquirer/prompts': 7.9.0(@types/node@24.8.1) - '@inquirer/type': 3.0.9(@types/node@24.8.1) + '@inquirer/prompts': 7.9.0(@types/node@24.9.1) + '@inquirer/type': 3.0.9(@types/node@24.9.1) '@octokit/auth-app': 8.1.1 '@octokit/core': 7.0.5 '@octokit/graphql': 9.0.2 '@octokit/graphql-schema': 15.26.0 '@octokit/openapi-types': 26.0.0 - '@octokit/plugin-paginate-rest': 13.2.0(@octokit/core@7.0.5) - '@octokit/plugin-rest-endpoint-methods': 16.1.0(@octokit/core@7.0.5) + '@octokit/plugin-paginate-rest': 13.2.1(@octokit/core@7.0.5) + '@octokit/plugin-rest-endpoint-methods': 16.1.1(@octokit/core@7.0.5) '@octokit/request-error': 7.0.1 '@octokit/rest': 22.0.0 - '@octokit/types': 15.0.0 - '@pnpm/dependency-path': 1001.1.2 + '@octokit/types': 15.0.1 + '@pnpm/dependency-path': 1001.1.3 '@types/cli-progress': 3.11.6 '@types/ejs': 3.1.5 '@types/events': 3.0.3 '@types/folder-hash': 4.0.4 '@types/git-raw-commits': 5.0.0 '@types/jasmine': 5.1.12 - '@types/node': 24.8.1 + '@types/node': 24.9.1 '@types/semver': 7.7.1 '@types/which': 3.0.4 '@types/yargs': 17.0.33 @@ -9445,13 +9445,13 @@ snapshots: chalk: 5.6.2 cli-progress: 3.12.0 conventional-commits-filter: 5.0.0 - conventional-commits-parser: 6.2.0 + conventional-commits-parser: 6.2.1 ejs: 3.1.10 encoding: 0.1.13 fast-glob: 3.3.3 firebase: 12.4.0 folder-hash: 4.1.1(supports-color@10.2.2) - git-raw-commits: 5.0.0(conventional-commits-filter@5.0.0)(conventional-commits-parser@6.2.0) + git-raw-commits: 5.0.0(conventional-commits-filter@5.0.0)(conventional-commits-parser@6.2.1) jasmine: 5.12.0 jasmine-core: 5.12.0 jasmine-reporters: 2.5.2 @@ -9472,35 +9472,35 @@ snapshots: - '@modelcontextprotocol/sdk' - '@react-native-async-storage/async-storage' - '@angular/platform-browser@20.3.6(@angular/animations@20.3.6(@angular/core@20.3.6(@angular/compiler@20.3.6)(rxjs@7.8.2)(zone.js@0.15.1)))(@angular/common@20.3.6(@angular/core@20.3.6(@angular/compiler@20.3.6)(rxjs@7.8.2)(zone.js@0.15.1))(rxjs@7.8.2))(@angular/core@20.3.6(@angular/compiler@20.3.6)(rxjs@7.8.2)(zone.js@0.15.1))': + '@angular/platform-browser@20.3.7(@angular/animations@20.3.7(@angular/core@20.3.7(@angular/compiler@20.3.7)(rxjs@7.8.2)(zone.js@0.15.1)))(@angular/common@20.3.7(@angular/core@20.3.7(@angular/compiler@20.3.7)(rxjs@7.8.2)(zone.js@0.15.1))(rxjs@7.8.2))(@angular/core@20.3.7(@angular/compiler@20.3.7)(rxjs@7.8.2)(zone.js@0.15.1))': dependencies: - '@angular/common': 20.3.6(@angular/core@20.3.6(@angular/compiler@20.3.6)(rxjs@7.8.2)(zone.js@0.15.1))(rxjs@7.8.2) - '@angular/core': 20.3.6(@angular/compiler@20.3.6)(rxjs@7.8.2)(zone.js@0.15.1) + '@angular/common': 20.3.7(@angular/core@20.3.7(@angular/compiler@20.3.7)(rxjs@7.8.2)(zone.js@0.15.1))(rxjs@7.8.2) + '@angular/core': 20.3.7(@angular/compiler@20.3.7)(rxjs@7.8.2)(zone.js@0.15.1) tslib: 2.8.1 optionalDependencies: - '@angular/animations': 20.3.6(@angular/core@20.3.6(@angular/compiler@20.3.6)(rxjs@7.8.2)(zone.js@0.15.1)) + '@angular/animations': 20.3.7(@angular/core@20.3.7(@angular/compiler@20.3.7)(rxjs@7.8.2)(zone.js@0.15.1)) - '@angular/platform-server@20.3.6(@angular/common@20.3.6(@angular/core@20.3.6(@angular/compiler@20.3.6)(rxjs@7.8.2)(zone.js@0.15.1))(rxjs@7.8.2))(@angular/compiler@20.3.6)(@angular/core@20.3.6(@angular/compiler@20.3.6)(rxjs@7.8.2)(zone.js@0.15.1))(@angular/platform-browser@20.3.6(@angular/animations@20.3.6(@angular/core@20.3.6(@angular/compiler@20.3.6)(rxjs@7.8.2)(zone.js@0.15.1)))(@angular/common@20.3.6(@angular/core@20.3.6(@angular/compiler@20.3.6)(rxjs@7.8.2)(zone.js@0.15.1))(rxjs@7.8.2))(@angular/core@20.3.6(@angular/compiler@20.3.6)(rxjs@7.8.2)(zone.js@0.15.1)))(rxjs@7.8.2)': + '@angular/platform-server@20.3.7(@angular/common@20.3.7(@angular/core@20.3.7(@angular/compiler@20.3.7)(rxjs@7.8.2)(zone.js@0.15.1))(rxjs@7.8.2))(@angular/compiler@20.3.7)(@angular/core@20.3.7(@angular/compiler@20.3.7)(rxjs@7.8.2)(zone.js@0.15.1))(@angular/platform-browser@20.3.7(@angular/animations@20.3.7(@angular/core@20.3.7(@angular/compiler@20.3.7)(rxjs@7.8.2)(zone.js@0.15.1)))(@angular/common@20.3.7(@angular/core@20.3.7(@angular/compiler@20.3.7)(rxjs@7.8.2)(zone.js@0.15.1))(rxjs@7.8.2))(@angular/core@20.3.7(@angular/compiler@20.3.7)(rxjs@7.8.2)(zone.js@0.15.1)))(rxjs@7.8.2)': dependencies: - '@angular/common': 20.3.6(@angular/core@20.3.6(@angular/compiler@20.3.6)(rxjs@7.8.2)(zone.js@0.15.1))(rxjs@7.8.2) - '@angular/compiler': 20.3.6 - '@angular/core': 20.3.6(@angular/compiler@20.3.6)(rxjs@7.8.2)(zone.js@0.15.1) - '@angular/platform-browser': 20.3.6(@angular/animations@20.3.6(@angular/core@20.3.6(@angular/compiler@20.3.6)(rxjs@7.8.2)(zone.js@0.15.1)))(@angular/common@20.3.6(@angular/core@20.3.6(@angular/compiler@20.3.6)(rxjs@7.8.2)(zone.js@0.15.1))(rxjs@7.8.2))(@angular/core@20.3.6(@angular/compiler@20.3.6)(rxjs@7.8.2)(zone.js@0.15.1)) + '@angular/common': 20.3.7(@angular/core@20.3.7(@angular/compiler@20.3.7)(rxjs@7.8.2)(zone.js@0.15.1))(rxjs@7.8.2) + '@angular/compiler': 20.3.7 + '@angular/core': 20.3.7(@angular/compiler@20.3.7)(rxjs@7.8.2)(zone.js@0.15.1) + '@angular/platform-browser': 20.3.7(@angular/animations@20.3.7(@angular/core@20.3.7(@angular/compiler@20.3.7)(rxjs@7.8.2)(zone.js@0.15.1)))(@angular/common@20.3.7(@angular/core@20.3.7(@angular/compiler@20.3.7)(rxjs@7.8.2)(zone.js@0.15.1))(rxjs@7.8.2))(@angular/core@20.3.7(@angular/compiler@20.3.7)(rxjs@7.8.2)(zone.js@0.15.1)) rxjs: 7.8.2 tslib: 2.8.1 xhr2: 0.2.1 - '@angular/router@20.3.6(@angular/common@20.3.6(@angular/core@20.3.6(@angular/compiler@20.3.6)(rxjs@7.8.2)(zone.js@0.15.1))(rxjs@7.8.2))(@angular/core@20.3.6(@angular/compiler@20.3.6)(rxjs@7.8.2)(zone.js@0.15.1))(@angular/platform-browser@20.3.6(@angular/animations@20.3.6(@angular/core@20.3.6(@angular/compiler@20.3.6)(rxjs@7.8.2)(zone.js@0.15.1)))(@angular/common@20.3.6(@angular/core@20.3.6(@angular/compiler@20.3.6)(rxjs@7.8.2)(zone.js@0.15.1))(rxjs@7.8.2))(@angular/core@20.3.6(@angular/compiler@20.3.6)(rxjs@7.8.2)(zone.js@0.15.1)))(rxjs@7.8.2)': + '@angular/router@20.3.7(@angular/common@20.3.7(@angular/core@20.3.7(@angular/compiler@20.3.7)(rxjs@7.8.2)(zone.js@0.15.1))(rxjs@7.8.2))(@angular/core@20.3.7(@angular/compiler@20.3.7)(rxjs@7.8.2)(zone.js@0.15.1))(@angular/platform-browser@20.3.7(@angular/animations@20.3.7(@angular/core@20.3.7(@angular/compiler@20.3.7)(rxjs@7.8.2)(zone.js@0.15.1)))(@angular/common@20.3.7(@angular/core@20.3.7(@angular/compiler@20.3.7)(rxjs@7.8.2)(zone.js@0.15.1))(rxjs@7.8.2))(@angular/core@20.3.7(@angular/compiler@20.3.7)(rxjs@7.8.2)(zone.js@0.15.1)))(rxjs@7.8.2)': dependencies: - '@angular/common': 20.3.6(@angular/core@20.3.6(@angular/compiler@20.3.6)(rxjs@7.8.2)(zone.js@0.15.1))(rxjs@7.8.2) - '@angular/core': 20.3.6(@angular/compiler@20.3.6)(rxjs@7.8.2)(zone.js@0.15.1) - '@angular/platform-browser': 20.3.6(@angular/animations@20.3.6(@angular/core@20.3.6(@angular/compiler@20.3.6)(rxjs@7.8.2)(zone.js@0.15.1)))(@angular/common@20.3.6(@angular/core@20.3.6(@angular/compiler@20.3.6)(rxjs@7.8.2)(zone.js@0.15.1))(rxjs@7.8.2))(@angular/core@20.3.6(@angular/compiler@20.3.6)(rxjs@7.8.2)(zone.js@0.15.1)) + '@angular/common': 20.3.7(@angular/core@20.3.7(@angular/compiler@20.3.7)(rxjs@7.8.2)(zone.js@0.15.1))(rxjs@7.8.2) + '@angular/core': 20.3.7(@angular/compiler@20.3.7)(rxjs@7.8.2)(zone.js@0.15.1) + '@angular/platform-browser': 20.3.7(@angular/animations@20.3.7(@angular/core@20.3.7(@angular/compiler@20.3.7)(rxjs@7.8.2)(zone.js@0.15.1)))(@angular/common@20.3.7(@angular/core@20.3.7(@angular/compiler@20.3.7)(rxjs@7.8.2)(zone.js@0.15.1))(rxjs@7.8.2))(@angular/core@20.3.7(@angular/compiler@20.3.7)(rxjs@7.8.2)(zone.js@0.15.1)) rxjs: 7.8.2 tslib: 2.8.1 - '@angular/service-worker@20.3.6(@angular/core@20.3.6(@angular/compiler@20.3.6)(rxjs@7.8.2)(zone.js@0.15.1))(rxjs@7.8.2)': + '@angular/service-worker@20.3.7(@angular/core@20.3.7(@angular/compiler@20.3.7)(rxjs@7.8.2)(zone.js@0.15.1))(rxjs@7.8.2)': dependencies: - '@angular/core': 20.3.6(@angular/compiler@20.3.6)(rxjs@7.8.2)(zone.js@0.15.1) + '@angular/core': 20.3.7(@angular/compiler@20.3.7)(rxjs@7.8.2)(zone.js@0.15.1) rxjs: 7.8.2 tslib: 2.8.1 @@ -10188,13 +10188,13 @@ snapshots: '@colors/colors@1.5.0': {} - '@conventional-changelog/git-client@1.0.1(conventional-commits-filter@5.0.0)(conventional-commits-parser@6.2.0)': + '@conventional-changelog/git-client@1.0.1(conventional-commits-filter@5.0.0)(conventional-commits-parser@6.2.1)': dependencies: '@types/semver': 7.7.1 semver: 7.7.2 optionalDependencies: conventional-commits-filter: 5.0.0 - conventional-commits-parser: 6.2.0 + conventional-commits-parser: 6.2.1 '@cspotcode/source-map-support@0.8.1': dependencies: @@ -10803,244 +10803,244 @@ snapshots: '@inquirer/ansi@1.0.1': {} - '@inquirer/checkbox@4.2.4(@types/node@24.8.1)': + '@inquirer/checkbox@4.2.4(@types/node@24.9.1)': dependencies: '@inquirer/ansi': 1.0.0 - '@inquirer/core': 10.2.2(@types/node@24.8.1) + '@inquirer/core': 10.2.2(@types/node@24.9.1) '@inquirer/figures': 1.0.13 - '@inquirer/type': 3.0.8(@types/node@24.8.1) + '@inquirer/type': 3.0.8(@types/node@24.9.1) yoctocolors-cjs: 2.1.3 optionalDependencies: - '@types/node': 24.8.1 + '@types/node': 24.9.1 - '@inquirer/checkbox@4.3.0(@types/node@24.8.1)': + '@inquirer/checkbox@4.3.0(@types/node@24.9.1)': dependencies: '@inquirer/ansi': 1.0.1 - '@inquirer/core': 10.3.0(@types/node@24.8.1) + '@inquirer/core': 10.3.0(@types/node@24.9.1) '@inquirer/figures': 1.0.14 - '@inquirer/type': 3.0.9(@types/node@24.8.1) + '@inquirer/type': 3.0.9(@types/node@24.9.1) yoctocolors-cjs: 2.1.3 optionalDependencies: - '@types/node': 24.8.1 + '@types/node': 24.9.1 - '@inquirer/confirm@5.1.14(@types/node@24.8.1)': + '@inquirer/confirm@5.1.14(@types/node@24.9.1)': dependencies: - '@inquirer/core': 10.2.2(@types/node@24.8.1) - '@inquirer/type': 3.0.8(@types/node@24.8.1) + '@inquirer/core': 10.2.2(@types/node@24.9.1) + '@inquirer/type': 3.0.8(@types/node@24.9.1) optionalDependencies: - '@types/node': 24.8.1 + '@types/node': 24.9.1 - '@inquirer/confirm@5.1.19(@types/node@24.8.1)': + '@inquirer/confirm@5.1.19(@types/node@24.9.1)': dependencies: - '@inquirer/core': 10.3.0(@types/node@24.8.1) - '@inquirer/type': 3.0.9(@types/node@24.8.1) + '@inquirer/core': 10.3.0(@types/node@24.9.1) + '@inquirer/type': 3.0.9(@types/node@24.9.1) optionalDependencies: - '@types/node': 24.8.1 + '@types/node': 24.9.1 - '@inquirer/core@10.2.2(@types/node@24.8.1)': + '@inquirer/core@10.2.2(@types/node@24.9.1)': dependencies: '@inquirer/ansi': 1.0.0 '@inquirer/figures': 1.0.13 - '@inquirer/type': 3.0.8(@types/node@24.8.1) + '@inquirer/type': 3.0.8(@types/node@24.9.1) cli-width: 4.1.0 mute-stream: 2.0.0 signal-exit: 4.1.0 wrap-ansi: 6.2.0 yoctocolors-cjs: 2.1.3 optionalDependencies: - '@types/node': 24.8.1 + '@types/node': 24.9.1 - '@inquirer/core@10.3.0(@types/node@24.8.1)': + '@inquirer/core@10.3.0(@types/node@24.9.1)': dependencies: '@inquirer/ansi': 1.0.1 '@inquirer/figures': 1.0.14 - '@inquirer/type': 3.0.9(@types/node@24.8.1) + '@inquirer/type': 3.0.9(@types/node@24.9.1) cli-width: 4.1.0 mute-stream: 2.0.0 signal-exit: 4.1.0 wrap-ansi: 6.2.0 yoctocolors-cjs: 2.1.3 optionalDependencies: - '@types/node': 24.8.1 + '@types/node': 24.9.1 - '@inquirer/editor@4.2.20(@types/node@24.8.1)': + '@inquirer/editor@4.2.20(@types/node@24.9.1)': dependencies: - '@inquirer/core': 10.2.2(@types/node@24.8.1) - '@inquirer/external-editor': 1.0.2(@types/node@24.8.1) - '@inquirer/type': 3.0.8(@types/node@24.8.1) + '@inquirer/core': 10.2.2(@types/node@24.9.1) + '@inquirer/external-editor': 1.0.2(@types/node@24.9.1) + '@inquirer/type': 3.0.8(@types/node@24.9.1) optionalDependencies: - '@types/node': 24.8.1 + '@types/node': 24.9.1 - '@inquirer/editor@4.2.21(@types/node@24.8.1)': + '@inquirer/editor@4.2.21(@types/node@24.9.1)': dependencies: - '@inquirer/core': 10.3.0(@types/node@24.8.1) - '@inquirer/external-editor': 1.0.2(@types/node@24.8.1) - '@inquirer/type': 3.0.9(@types/node@24.8.1) + '@inquirer/core': 10.3.0(@types/node@24.9.1) + '@inquirer/external-editor': 1.0.2(@types/node@24.9.1) + '@inquirer/type': 3.0.9(@types/node@24.9.1) optionalDependencies: - '@types/node': 24.8.1 + '@types/node': 24.9.1 - '@inquirer/expand@4.0.20(@types/node@24.8.1)': + '@inquirer/expand@4.0.20(@types/node@24.9.1)': dependencies: - '@inquirer/core': 10.2.2(@types/node@24.8.1) - '@inquirer/type': 3.0.8(@types/node@24.8.1) + '@inquirer/core': 10.2.2(@types/node@24.9.1) + '@inquirer/type': 3.0.8(@types/node@24.9.1) yoctocolors-cjs: 2.1.3 optionalDependencies: - '@types/node': 24.8.1 + '@types/node': 24.9.1 - '@inquirer/expand@4.0.21(@types/node@24.8.1)': + '@inquirer/expand@4.0.21(@types/node@24.9.1)': dependencies: - '@inquirer/core': 10.3.0(@types/node@24.8.1) - '@inquirer/type': 3.0.9(@types/node@24.8.1) + '@inquirer/core': 10.3.0(@types/node@24.9.1) + '@inquirer/type': 3.0.9(@types/node@24.9.1) yoctocolors-cjs: 2.1.3 optionalDependencies: - '@types/node': 24.8.1 + '@types/node': 24.9.1 - '@inquirer/external-editor@1.0.2(@types/node@24.8.1)': + '@inquirer/external-editor@1.0.2(@types/node@24.9.1)': dependencies: chardet: 2.1.0 iconv-lite: 0.7.0 optionalDependencies: - '@types/node': 24.8.1 + '@types/node': 24.9.1 '@inquirer/figures@1.0.13': {} '@inquirer/figures@1.0.14': {} - '@inquirer/input@4.2.4(@types/node@24.8.1)': + '@inquirer/input@4.2.4(@types/node@24.9.1)': dependencies: - '@inquirer/core': 10.2.2(@types/node@24.8.1) - '@inquirer/type': 3.0.8(@types/node@24.8.1) + '@inquirer/core': 10.2.2(@types/node@24.9.1) + '@inquirer/type': 3.0.8(@types/node@24.9.1) optionalDependencies: - '@types/node': 24.8.1 + '@types/node': 24.9.1 - '@inquirer/input@4.2.5(@types/node@24.8.1)': + '@inquirer/input@4.2.5(@types/node@24.9.1)': dependencies: - '@inquirer/core': 10.3.0(@types/node@24.8.1) - '@inquirer/type': 3.0.9(@types/node@24.8.1) + '@inquirer/core': 10.3.0(@types/node@24.9.1) + '@inquirer/type': 3.0.9(@types/node@24.9.1) optionalDependencies: - '@types/node': 24.8.1 + '@types/node': 24.9.1 - '@inquirer/number@3.0.20(@types/node@24.8.1)': + '@inquirer/number@3.0.20(@types/node@24.9.1)': dependencies: - '@inquirer/core': 10.2.2(@types/node@24.8.1) - '@inquirer/type': 3.0.8(@types/node@24.8.1) + '@inquirer/core': 10.2.2(@types/node@24.9.1) + '@inquirer/type': 3.0.8(@types/node@24.9.1) optionalDependencies: - '@types/node': 24.8.1 + '@types/node': 24.9.1 - '@inquirer/number@3.0.21(@types/node@24.8.1)': + '@inquirer/number@3.0.21(@types/node@24.9.1)': dependencies: - '@inquirer/core': 10.3.0(@types/node@24.8.1) - '@inquirer/type': 3.0.9(@types/node@24.8.1) + '@inquirer/core': 10.3.0(@types/node@24.9.1) + '@inquirer/type': 3.0.9(@types/node@24.9.1) optionalDependencies: - '@types/node': 24.8.1 + '@types/node': 24.9.1 - '@inquirer/password@4.0.20(@types/node@24.8.1)': + '@inquirer/password@4.0.20(@types/node@24.9.1)': dependencies: '@inquirer/ansi': 1.0.0 - '@inquirer/core': 10.2.2(@types/node@24.8.1) - '@inquirer/type': 3.0.8(@types/node@24.8.1) + '@inquirer/core': 10.2.2(@types/node@24.9.1) + '@inquirer/type': 3.0.8(@types/node@24.9.1) optionalDependencies: - '@types/node': 24.8.1 + '@types/node': 24.9.1 - '@inquirer/password@4.0.21(@types/node@24.8.1)': + '@inquirer/password@4.0.21(@types/node@24.9.1)': dependencies: '@inquirer/ansi': 1.0.1 - '@inquirer/core': 10.3.0(@types/node@24.8.1) - '@inquirer/type': 3.0.9(@types/node@24.8.1) + '@inquirer/core': 10.3.0(@types/node@24.9.1) + '@inquirer/type': 3.0.9(@types/node@24.9.1) optionalDependencies: - '@types/node': 24.8.1 - - '@inquirer/prompts@7.8.2(@types/node@24.8.1)': - dependencies: - '@inquirer/checkbox': 4.2.4(@types/node@24.8.1) - '@inquirer/confirm': 5.1.14(@types/node@24.8.1) - '@inquirer/editor': 4.2.20(@types/node@24.8.1) - '@inquirer/expand': 4.0.20(@types/node@24.8.1) - '@inquirer/input': 4.2.4(@types/node@24.8.1) - '@inquirer/number': 3.0.20(@types/node@24.8.1) - '@inquirer/password': 4.0.20(@types/node@24.8.1) - '@inquirer/rawlist': 4.1.8(@types/node@24.8.1) - '@inquirer/search': 3.1.3(@types/node@24.8.1) - '@inquirer/select': 4.3.4(@types/node@24.8.1) + '@types/node': 24.9.1 + + '@inquirer/prompts@7.8.2(@types/node@24.9.1)': + dependencies: + '@inquirer/checkbox': 4.2.4(@types/node@24.9.1) + '@inquirer/confirm': 5.1.14(@types/node@24.9.1) + '@inquirer/editor': 4.2.20(@types/node@24.9.1) + '@inquirer/expand': 4.0.20(@types/node@24.9.1) + '@inquirer/input': 4.2.4(@types/node@24.9.1) + '@inquirer/number': 3.0.20(@types/node@24.9.1) + '@inquirer/password': 4.0.20(@types/node@24.9.1) + '@inquirer/rawlist': 4.1.8(@types/node@24.9.1) + '@inquirer/search': 3.1.3(@types/node@24.9.1) + '@inquirer/select': 4.3.4(@types/node@24.9.1) optionalDependencies: - '@types/node': 24.8.1 - - '@inquirer/prompts@7.9.0(@types/node@24.8.1)': - dependencies: - '@inquirer/checkbox': 4.3.0(@types/node@24.8.1) - '@inquirer/confirm': 5.1.19(@types/node@24.8.1) - '@inquirer/editor': 4.2.21(@types/node@24.8.1) - '@inquirer/expand': 4.0.21(@types/node@24.8.1) - '@inquirer/input': 4.2.5(@types/node@24.8.1) - '@inquirer/number': 3.0.21(@types/node@24.8.1) - '@inquirer/password': 4.0.21(@types/node@24.8.1) - '@inquirer/rawlist': 4.1.9(@types/node@24.8.1) - '@inquirer/search': 3.2.0(@types/node@24.8.1) - '@inquirer/select': 4.4.0(@types/node@24.8.1) + '@types/node': 24.9.1 + + '@inquirer/prompts@7.9.0(@types/node@24.9.1)': + dependencies: + '@inquirer/checkbox': 4.3.0(@types/node@24.9.1) + '@inquirer/confirm': 5.1.19(@types/node@24.9.1) + '@inquirer/editor': 4.2.21(@types/node@24.9.1) + '@inquirer/expand': 4.0.21(@types/node@24.9.1) + '@inquirer/input': 4.2.5(@types/node@24.9.1) + '@inquirer/number': 3.0.21(@types/node@24.9.1) + '@inquirer/password': 4.0.21(@types/node@24.9.1) + '@inquirer/rawlist': 4.1.9(@types/node@24.9.1) + '@inquirer/search': 3.2.0(@types/node@24.9.1) + '@inquirer/select': 4.4.0(@types/node@24.9.1) optionalDependencies: - '@types/node': 24.8.1 + '@types/node': 24.9.1 - '@inquirer/rawlist@4.1.8(@types/node@24.8.1)': + '@inquirer/rawlist@4.1.8(@types/node@24.9.1)': dependencies: - '@inquirer/core': 10.2.2(@types/node@24.8.1) - '@inquirer/type': 3.0.8(@types/node@24.8.1) + '@inquirer/core': 10.2.2(@types/node@24.9.1) + '@inquirer/type': 3.0.8(@types/node@24.9.1) yoctocolors-cjs: 2.1.3 optionalDependencies: - '@types/node': 24.8.1 + '@types/node': 24.9.1 - '@inquirer/rawlist@4.1.9(@types/node@24.8.1)': + '@inquirer/rawlist@4.1.9(@types/node@24.9.1)': dependencies: - '@inquirer/core': 10.3.0(@types/node@24.8.1) - '@inquirer/type': 3.0.9(@types/node@24.8.1) + '@inquirer/core': 10.3.0(@types/node@24.9.1) + '@inquirer/type': 3.0.9(@types/node@24.9.1) yoctocolors-cjs: 2.1.3 optionalDependencies: - '@types/node': 24.8.1 + '@types/node': 24.9.1 - '@inquirer/search@3.1.3(@types/node@24.8.1)': + '@inquirer/search@3.1.3(@types/node@24.9.1)': dependencies: - '@inquirer/core': 10.2.2(@types/node@24.8.1) + '@inquirer/core': 10.2.2(@types/node@24.9.1) '@inquirer/figures': 1.0.13 - '@inquirer/type': 3.0.8(@types/node@24.8.1) + '@inquirer/type': 3.0.8(@types/node@24.9.1) yoctocolors-cjs: 2.1.3 optionalDependencies: - '@types/node': 24.8.1 + '@types/node': 24.9.1 - '@inquirer/search@3.2.0(@types/node@24.8.1)': + '@inquirer/search@3.2.0(@types/node@24.9.1)': dependencies: - '@inquirer/core': 10.3.0(@types/node@24.8.1) + '@inquirer/core': 10.3.0(@types/node@24.9.1) '@inquirer/figures': 1.0.14 - '@inquirer/type': 3.0.9(@types/node@24.8.1) + '@inquirer/type': 3.0.9(@types/node@24.9.1) yoctocolors-cjs: 2.1.3 optionalDependencies: - '@types/node': 24.8.1 + '@types/node': 24.9.1 - '@inquirer/select@4.3.4(@types/node@24.8.1)': + '@inquirer/select@4.3.4(@types/node@24.9.1)': dependencies: '@inquirer/ansi': 1.0.0 - '@inquirer/core': 10.2.2(@types/node@24.8.1) + '@inquirer/core': 10.2.2(@types/node@24.9.1) '@inquirer/figures': 1.0.13 - '@inquirer/type': 3.0.8(@types/node@24.8.1) + '@inquirer/type': 3.0.8(@types/node@24.9.1) yoctocolors-cjs: 2.1.3 optionalDependencies: - '@types/node': 24.8.1 + '@types/node': 24.9.1 - '@inquirer/select@4.4.0(@types/node@24.8.1)': + '@inquirer/select@4.4.0(@types/node@24.9.1)': dependencies: '@inquirer/ansi': 1.0.1 - '@inquirer/core': 10.3.0(@types/node@24.8.1) + '@inquirer/core': 10.3.0(@types/node@24.9.1) '@inquirer/figures': 1.0.14 - '@inquirer/type': 3.0.9(@types/node@24.8.1) + '@inquirer/type': 3.0.9(@types/node@24.9.1) yoctocolors-cjs: 2.1.3 optionalDependencies: - '@types/node': 24.8.1 + '@types/node': 24.9.1 - '@inquirer/type@3.0.8(@types/node@24.8.1)': + '@inquirer/type@3.0.8(@types/node@24.9.1)': optionalDependencies: - '@types/node': 24.8.1 + '@types/node': 24.9.1 - '@inquirer/type@3.0.9(@types/node@24.8.1)': + '@inquirer/type@3.0.9(@types/node@24.9.1)': optionalDependencies: - '@types/node': 24.8.1 + '@types/node': 24.9.1 '@isaacs/balanced-match@4.0.1': {} @@ -11126,10 +11126,10 @@ snapshots: '@leichtgewicht/ip-codec@2.0.5': {} - '@listr2/prompt-adapter-inquirer@3.0.1(@inquirer/prompts@7.8.2(@types/node@24.8.1))(@types/node@24.8.1)(listr2@9.0.1)': + '@listr2/prompt-adapter-inquirer@3.0.1(@inquirer/prompts@7.8.2(@types/node@24.9.1))(@types/node@24.9.1)(listr2@9.0.1)': dependencies: - '@inquirer/prompts': 7.8.2(@types/node@24.8.1) - '@inquirer/type': 3.0.8(@types/node@24.8.1) + '@inquirer/prompts': 7.8.2(@types/node@24.9.1) + '@inquirer/type': 3.0.8(@types/node@24.9.1) listr2: 9.0.1 transitivePeerDependencies: - '@types/node' @@ -11348,7 +11348,7 @@ snapshots: '@octokit/auth-oauth-user': 6.0.1 '@octokit/request': 10.0.5 '@octokit/request-error': 7.0.1 - '@octokit/types': 15.0.0 + '@octokit/types': 15.0.1 toad-cache: 3.7.0 universal-github-app-jwt: 2.2.2 universal-user-agent: 7.0.3 @@ -11358,14 +11358,14 @@ snapshots: '@octokit/auth-oauth-device': 8.0.2 '@octokit/auth-oauth-user': 6.0.1 '@octokit/request': 10.0.5 - '@octokit/types': 15.0.0 + '@octokit/types': 15.0.1 universal-user-agent: 7.0.3 '@octokit/auth-oauth-device@8.0.2': dependencies: '@octokit/oauth-methods': 6.0.1 '@octokit/request': 10.0.5 - '@octokit/types': 15.0.0 + '@octokit/types': 15.0.1 universal-user-agent: 7.0.3 '@octokit/auth-oauth-user@6.0.1': @@ -11373,7 +11373,7 @@ snapshots: '@octokit/auth-oauth-device': 8.0.2 '@octokit/oauth-methods': 6.0.1 '@octokit/request': 10.0.5 - '@octokit/types': 15.0.0 + '@octokit/types': 15.0.1 universal-user-agent: 7.0.3 '@octokit/auth-token@6.0.0': {} @@ -11384,13 +11384,13 @@ snapshots: '@octokit/graphql': 9.0.2 '@octokit/request': 10.0.5 '@octokit/request-error': 7.0.1 - '@octokit/types': 15.0.0 + '@octokit/types': 15.0.1 before-after-hook: 4.0.0 universal-user-agent: 7.0.3 '@octokit/endpoint@11.0.1': dependencies: - '@octokit/types': 15.0.0 + '@octokit/types': 15.0.1 universal-user-agent: 7.0.3 '@octokit/graphql-schema@15.26.0': @@ -11401,7 +11401,7 @@ snapshots: '@octokit/graphql@9.0.2': dependencies: '@octokit/request': 10.0.5 - '@octokit/types': 15.0.0 + '@octokit/types': 15.0.1 universal-user-agent: 7.0.3 '@octokit/oauth-authorization-url@8.0.0': {} @@ -11411,44 +11411,44 @@ snapshots: '@octokit/oauth-authorization-url': 8.0.0 '@octokit/request': 10.0.5 '@octokit/request-error': 7.0.1 - '@octokit/types': 15.0.0 + '@octokit/types': 15.0.1 '@octokit/openapi-types@26.0.0': {} - '@octokit/plugin-paginate-rest@13.2.0(@octokit/core@7.0.5)': + '@octokit/plugin-paginate-rest@13.2.1(@octokit/core@7.0.5)': dependencies: '@octokit/core': 7.0.5 - '@octokit/types': 15.0.0 + '@octokit/types': 15.0.1 '@octokit/plugin-request-log@6.0.0(@octokit/core@7.0.5)': dependencies: '@octokit/core': 7.0.5 - '@octokit/plugin-rest-endpoint-methods@16.1.0(@octokit/core@7.0.5)': + '@octokit/plugin-rest-endpoint-methods@16.1.1(@octokit/core@7.0.5)': dependencies: '@octokit/core': 7.0.5 - '@octokit/types': 15.0.0 + '@octokit/types': 15.0.1 '@octokit/request-error@7.0.1': dependencies: - '@octokit/types': 15.0.0 + '@octokit/types': 15.0.1 '@octokit/request@10.0.5': dependencies: '@octokit/endpoint': 11.0.1 '@octokit/request-error': 7.0.1 - '@octokit/types': 15.0.0 + '@octokit/types': 15.0.1 fast-content-type-parse: 3.0.0 universal-user-agent: 7.0.3 '@octokit/rest@22.0.0': dependencies: '@octokit/core': 7.0.5 - '@octokit/plugin-paginate-rest': 13.2.0(@octokit/core@7.0.5) + '@octokit/plugin-paginate-rest': 13.2.1(@octokit/core@7.0.5) '@octokit/plugin-request-log': 6.0.0(@octokit/core@7.0.5) - '@octokit/plugin-rest-endpoint-methods': 16.1.0(@octokit/core@7.0.5) + '@octokit/plugin-rest-endpoint-methods': 16.1.1(@octokit/core@7.0.5) - '@octokit/types@15.0.0': + '@octokit/types@15.0.1': dependencies: '@octokit/openapi-types': 26.0.0 @@ -11546,17 +11546,17 @@ snapshots: '@pnpm/crypto.polyfill@1000.1.0': {} - '@pnpm/dependency-path@1001.1.2': + '@pnpm/dependency-path@1001.1.3': dependencies: '@pnpm/crypto.hash': 1000.2.1 - '@pnpm/types': 1000.8.0 + '@pnpm/types': 1000.9.0 semver: 7.7.2 '@pnpm/graceful-fs@1000.0.1': dependencies: graceful-fs: 4.2.11 - '@pnpm/types@1000.8.0': {} + '@pnpm/types@1000.9.0': {} '@protobufjs/aspromise@1.1.2': {} @@ -12094,9 +12094,9 @@ snapshots: dependencies: undici-types: 6.21.0 - '@types/node@24.8.1': + '@types/node@24.9.1': dependencies: - undici-types: 7.14.0 + undici-types: 7.16.0 '@types/npm-package-arg@6.1.4': {} @@ -12485,9 +12485,9 @@ snapshots: lodash: 4.17.21 minimatch: 7.4.6 - '@vitejs/plugin-basic-ssl@2.1.0(vite@7.1.11(@types/node@24.8.1)(jiti@1.21.7)(less@4.4.0)(sass@1.90.0)(terser@5.43.1)(tsx@4.20.6)(yaml@2.8.1))': + '@vitejs/plugin-basic-ssl@2.1.0(vite@7.1.11(@types/node@24.9.1)(jiti@1.21.7)(less@4.4.0)(sass@1.90.0)(terser@5.43.1)(tsx@4.20.6)(yaml@2.8.1))': dependencies: - vite: 7.1.11(@types/node@24.8.1)(jiti@1.21.7)(less@4.4.0)(sass@1.90.0)(terser@5.43.1)(tsx@4.20.6)(yaml@2.8.1) + vite: 7.1.11(@types/node@24.9.1)(jiti@1.21.7)(less@4.4.0)(sass@1.90.0)(terser@5.43.1)(tsx@4.20.6)(yaml@2.8.1) '@vitest/expect@3.2.4': dependencies: @@ -12497,13 +12497,13 @@ snapshots: chai: 5.3.3 tinyrainbow: 2.0.0 - '@vitest/mocker@3.2.4(vite@7.1.5(@types/node@24.8.1)(jiti@1.21.7)(less@4.4.0)(sass@1.90.0)(terser@5.43.1)(tsx@4.20.6)(yaml@2.8.1))': + '@vitest/mocker@3.2.4(vite@7.1.5(@types/node@24.9.1)(jiti@1.21.7)(less@4.4.0)(sass@1.90.0)(terser@5.43.1)(tsx@4.20.6)(yaml@2.8.1))': dependencies: '@vitest/spy': 3.2.4 estree-walker: 3.0.3 magic-string: 0.30.17 optionalDependencies: - vite: 7.1.5(@types/node@24.8.1)(jiti@1.21.7)(less@4.4.0)(sass@1.90.0)(terser@5.43.1)(tsx@4.20.6)(yaml@2.8.1) + vite: 7.1.5(@types/node@24.9.1)(jiti@1.21.7)(less@4.4.0)(sass@1.90.0)(terser@5.43.1)(tsx@4.20.6)(yaml@2.8.1) '@vitest/pretty-format@3.2.4': dependencies: @@ -13603,7 +13603,7 @@ snapshots: conventional-commits-filter@5.0.0: {} - conventional-commits-parser@6.2.0: + conventional-commits-parser@6.2.1: dependencies: meow: 13.2.0 @@ -14791,9 +14791,9 @@ snapshots: dependencies: assert-plus: 1.0.0 - git-raw-commits@5.0.0(conventional-commits-filter@5.0.0)(conventional-commits-parser@6.2.0): + git-raw-commits@5.0.0(conventional-commits-filter@5.0.0)(conventional-commits-parser@6.2.1): dependencies: - '@conventional-changelog/git-client': 1.0.1(conventional-commits-filter@5.0.0)(conventional-commits-parser@6.2.0) + '@conventional-changelog/git-client': 1.0.1(conventional-commits-filter@5.0.0)(conventional-commits-parser@6.2.1) meow: 13.2.0 transitivePeerDependencies: - conventional-commits-filter @@ -16228,10 +16228,10 @@ snapshots: netmask@2.0.2: {} - ng-packagr@20.3.0(@angular/compiler-cli@20.3.6(@angular/compiler@20.3.6)(typescript@5.9.2))(tslib@2.8.1)(typescript@5.9.2): + ng-packagr@20.3.0(@angular/compiler-cli@20.3.7(@angular/compiler@20.3.7)(typescript@5.9.2))(tslib@2.8.1)(typescript@5.9.2): dependencies: '@ampproject/remapping': 2.3.0 - '@angular/compiler-cli': 20.3.6(@angular/compiler@20.3.6)(typescript@5.9.2) + '@angular/compiler-cli': 20.3.7(@angular/compiler@20.3.7)(typescript@5.9.2) '@rollup/plugin-json': 6.1.0(rollup@4.52.3) '@rollup/wasm-node': 4.52.4 ajv: 8.17.1 @@ -18192,7 +18192,7 @@ snapshots: undici-types@6.21.0: {} - undici-types@7.14.0: {} + undici-types@7.16.0: {} undici@5.29.0: dependencies: @@ -18368,13 +18368,13 @@ snapshots: core-util-is: 1.0.2 extsprintf: 1.3.0 - vite-node@3.2.4(@types/node@24.8.1)(jiti@1.21.7)(less@4.4.0)(sass@1.90.0)(terser@5.43.1)(tsx@4.20.6)(yaml@2.8.1): + vite-node@3.2.4(@types/node@24.9.1)(jiti@1.21.7)(less@4.4.0)(sass@1.90.0)(terser@5.43.1)(tsx@4.20.6)(yaml@2.8.1): dependencies: cac: 6.7.14 debug: 4.4.3(supports-color@10.2.2) es-module-lexer: 1.7.0 pathe: 2.0.3 - vite: 7.1.11(@types/node@24.8.1)(jiti@1.21.7)(less@4.4.0)(sass@1.90.0)(terser@5.43.1)(tsx@4.20.6)(yaml@2.8.1) + vite: 7.1.11(@types/node@24.9.1)(jiti@1.21.7)(less@4.4.0)(sass@1.90.0)(terser@5.43.1)(tsx@4.20.6)(yaml@2.8.1) transitivePeerDependencies: - '@types/node' - jiti @@ -18389,7 +18389,7 @@ snapshots: - tsx - yaml - vite@7.1.11(@types/node@24.8.1)(jiti@1.21.7)(less@4.4.0)(sass@1.90.0)(terser@5.43.1)(tsx@4.20.6)(yaml@2.8.1): + vite@7.1.11(@types/node@24.9.1)(jiti@1.21.7)(less@4.4.0)(sass@1.90.0)(terser@5.43.1)(tsx@4.20.6)(yaml@2.8.1): dependencies: esbuild: 0.25.9 fdir: 6.5.0(picomatch@4.0.3) @@ -18398,7 +18398,7 @@ snapshots: rollup: 4.52.3 tinyglobby: 0.2.15 optionalDependencies: - '@types/node': 24.8.1 + '@types/node': 24.9.1 fsevents: 2.3.3 jiti: 1.21.7 less: 4.4.0 @@ -18407,7 +18407,7 @@ snapshots: tsx: 4.20.6 yaml: 2.8.1 - vite@7.1.5(@types/node@24.8.1)(jiti@1.21.7)(less@4.4.0)(sass@1.90.0)(terser@5.43.1)(tsx@4.20.6)(yaml@2.8.1): + vite@7.1.5(@types/node@24.9.1)(jiti@1.21.7)(less@4.4.0)(sass@1.90.0)(terser@5.43.1)(tsx@4.20.6)(yaml@2.8.1): dependencies: esbuild: 0.25.9 fdir: 6.5.0(picomatch@4.0.3) @@ -18416,7 +18416,7 @@ snapshots: rollup: 4.52.3 tinyglobby: 0.2.15 optionalDependencies: - '@types/node': 24.8.1 + '@types/node': 24.9.1 fsevents: 2.3.3 jiti: 1.21.7 less: 4.4.0 @@ -18425,11 +18425,11 @@ snapshots: tsx: 4.20.6 yaml: 2.8.1 - vitest@3.2.4(@types/node@24.8.1)(jiti@1.21.7)(jsdom@26.1.0(bufferutil@4.0.9)(utf-8-validate@6.0.5))(less@4.4.0)(sass@1.90.0)(terser@5.43.1)(tsx@4.20.6)(yaml@2.8.1): + vitest@3.2.4(@types/node@24.9.1)(jiti@1.21.7)(jsdom@26.1.0(bufferutil@4.0.9)(utf-8-validate@6.0.5))(less@4.4.0)(sass@1.90.0)(terser@5.43.1)(tsx@4.20.6)(yaml@2.8.1): dependencies: '@types/chai': 5.2.2 '@vitest/expect': 3.2.4 - '@vitest/mocker': 3.2.4(vite@7.1.5(@types/node@24.8.1)(jiti@1.21.7)(less@4.4.0)(sass@1.90.0)(terser@5.43.1)(tsx@4.20.6)(yaml@2.8.1)) + '@vitest/mocker': 3.2.4(vite@7.1.5(@types/node@24.9.1)(jiti@1.21.7)(less@4.4.0)(sass@1.90.0)(terser@5.43.1)(tsx@4.20.6)(yaml@2.8.1)) '@vitest/pretty-format': 3.2.4 '@vitest/runner': 3.2.4 '@vitest/snapshot': 3.2.4 @@ -18447,11 +18447,11 @@ snapshots: tinyglobby: 0.2.14 tinypool: 1.1.1 tinyrainbow: 2.0.0 - vite: 7.1.5(@types/node@24.8.1)(jiti@1.21.7)(less@4.4.0)(sass@1.90.0)(terser@5.43.1)(tsx@4.20.6)(yaml@2.8.1) - vite-node: 3.2.4(@types/node@24.8.1)(jiti@1.21.7)(less@4.4.0)(sass@1.90.0)(terser@5.43.1)(tsx@4.20.6)(yaml@2.8.1) + vite: 7.1.5(@types/node@24.9.1)(jiti@1.21.7)(less@4.4.0)(sass@1.90.0)(terser@5.43.1)(tsx@4.20.6)(yaml@2.8.1) + vite-node: 3.2.4(@types/node@24.9.1)(jiti@1.21.7)(less@4.4.0)(sass@1.90.0)(terser@5.43.1)(tsx@4.20.6)(yaml@2.8.1) why-is-node-running: 2.3.0 optionalDependencies: - '@types/node': 24.8.1 + '@types/node': 24.9.1 jsdom: 26.1.0(bufferutil@4.0.9)(utf-8-validate@6.0.5) transitivePeerDependencies: - jiti From bdc584b5693090a3fc430e2c89af942eeb39b208 Mon Sep 17 00:00:00 2001 From: Angular Robot Date: Thu, 23 Oct 2025 05:06:19 +0000 Subject: [PATCH 02/52] build: update dependency aspect_rules_js to v2.7.0 See associated pull request for more information. --- MODULE.bazel | 2 +- MODULE.bazel.lock | 15 ++++++++------- 2 files changed, 9 insertions(+), 8 deletions(-) diff --git a/MODULE.bazel b/MODULE.bazel index 5aef813e81ac..b3af7007f9ad 100644 --- a/MODULE.bazel +++ b/MODULE.bazel @@ -6,7 +6,7 @@ module( bazel_dep(name = "yq.bzl", version = "0.3.1") bazel_dep(name = "rules_nodejs", version = "6.6.0") -bazel_dep(name = "aspect_rules_js", version = "2.6.2") +bazel_dep(name = "aspect_rules_js", version = "2.7.0") bazel_dep(name = "aspect_rules_ts", version = "3.7.0") bazel_dep(name = "rules_pkg", version = "0.8.1") diff --git a/MODULE.bazel.lock b/MODULE.bazel.lock index 5455a108bfcd..9d1fff2fa682 100644 --- a/MODULE.bazel.lock +++ b/MODULE.bazel.lock @@ -27,7 +27,8 @@ "https://bcr.bazel.build/modules/aspect_rules_js/2.0.0/MODULE.bazel": "b45b507574aa60a92796e3e13c195cd5744b3b8aff516a9c0cb5ae6a048161c5", "https://bcr.bazel.build/modules/aspect_rules_js/2.4.2/MODULE.bazel": "0d01db38b96d25df7ed952a5e96eac4b3802723d146961974bf020f6dd07591d", "https://bcr.bazel.build/modules/aspect_rules_js/2.6.2/MODULE.bazel": "ed2a871f4ab8fbde0cab67c425745069d84ea64b64313fa1a2954017326511f5", - "https://bcr.bazel.build/modules/aspect_rules_js/2.6.2/source.json": "59933fb8ddabd9740a3c12ff5552f06f2b8d68c3633883c681c757bf227c3763", + "https://bcr.bazel.build/modules/aspect_rules_js/2.7.0/MODULE.bazel": "ac879ee86f124c827e4e87942b3797ff4aaf90360eb9d7bff5321fc45d5ebefb", + "https://bcr.bazel.build/modules/aspect_rules_js/2.7.0/source.json": "20c34042beca8ea1e5996989dc163a75cb04ec4e75dc64f78d936497aea78e4b", "https://bcr.bazel.build/modules/aspect_rules_ts/3.6.3/MODULE.bazel": "d09db394970f076176ce7bab5b5fa7f0d560fd4f30b8432ea5e2c2570505b130", "https://bcr.bazel.build/modules/aspect_rules_ts/3.7.0/MODULE.bazel": "5aace216caf88638950ef061245d23c36f57c8359e56e97f02a36f70bb09c50f", "https://bcr.bazel.build/modules/aspect_rules_ts/3.7.0/source.json": "4a8115ea69dd796353232ff27a7e93e6d7d1ad43bea1eb33c6bd3acfa656bf2e", @@ -206,7 +207,7 @@ "moduleExtensions": { "@@aspect_rules_esbuild~//esbuild:extensions.bzl%esbuild": { "general": { - "bzlTransitiveDigest": "W+cy7GU3S29h8PPWylmMlPB5Z16vuZzJX4k0jlXGFoc=", + "bzlTransitiveDigest": "2t/OGeKfMCAl1xoAFVhaT+JKQb5zexk164MjT7t8SPE=", "usagesDigest": "H070ZIHhSlR+Han009l+GdDSuT9AJssdyVHQ7xjstSo=", "recordedFileInputs": {}, "recordedDirentsInputs": {}, @@ -391,8 +392,8 @@ }, "@@aspect_rules_js~//npm:extensions.bzl%pnpm": { "general": { - "bzlTransitiveDigest": "kFo9dd9KDRPKtK0RkVyoouzNI0l+bqG8cEaw+4+ZnVw=", - "usagesDigest": "dwcGULhCgltHeTzlHJu5cjVHXt6WfLzA3yTc6cHWmPo=", + "bzlTransitiveDigest": "SVyYFkMQbjQ0jUKo5pfA4RvHwE9U+087GVDEKYPcTSU=", + "usagesDigest": "IVicAE5kmPjEcCQ3BjtqveHxlxyM0WJ/OuayGov8SLE=", "recordedFileInputs": {}, "recordedDirentsInputs": {}, "envVariables": {}, @@ -604,7 +605,7 @@ "@@aspect_tools_telemetry~//:extension.bzl%telemetry": { "general": { "bzlTransitiveDigest": "gA7tPEdJXhskzPIEUxjX9IdDrM6+WjfbgXJ8Ez47umk=", - "usagesDigest": "uS24fACgJK/VGwdRorIVcVBYji/Ibx5tHzgIFCn5iZQ=", + "usagesDigest": "+Hur2pWe/TT3snEvJg4r10bQxD7lA5FHQPZQEHH32bY=", "recordedFileInputs": {}, "recordedDirentsInputs": {}, "envVariables": {}, @@ -614,7 +615,7 @@ "ruleClassName": "tel_repository", "attributes": { "deps": { - "aspect_rules_js": "2.6.2", + "aspect_rules_js": "2.7.0", "aspect_rules_ts": "3.7.0", "aspect_rules_esbuild": "0.23.0", "aspect_tools_telemetry": "0.2.8" @@ -1118,7 +1119,7 @@ "@@rules_nodejs~//nodejs:extensions.bzl%node": { "general": { "bzlTransitiveDigest": "71PwVsMlLx+RWdt1SI9nSqRHX7DX/NstWwr7/XBxEMs=", - "usagesDigest": "UMPJAxKFUmrhUd/xrzHapBiQuXI2tFY2p5YhjbyQDHY=", + "usagesDigest": "lqo/UXkPCwj19uB1o0D7KeWvm99ttcmhk7BOoYRXRp0=", "recordedFileInputs": {}, "recordedDirentsInputs": {}, "envVariables": {}, From e2543b1ea4d6859a5ec9b5bdd58ca4de629d191b Mon Sep 17 00:00:00 2001 From: Angular Robot Date: Thu, 23 Oct 2025 07:06:49 +0000 Subject: [PATCH 03/52] build: update cross-repo angular dependencies See associated pull request for more information. --- .../assistant-to-the-branch-manager.yml | 2 +- .github/workflows/ci.yml | 52 +++++++++---------- .github/workflows/dev-infra.yml | 4 +- .github/workflows/feature-requests.yml | 2 +- .github/workflows/perf.yml | 6 +-- .github/workflows/pr.yml | 44 ++++++++-------- MODULE.bazel | 2 +- package.json | 2 +- pnpm-lock.yaml | 12 ++--- 9 files changed, 63 insertions(+), 63 deletions(-) diff --git a/.github/workflows/assistant-to-the-branch-manager.yml b/.github/workflows/assistant-to-the-branch-manager.yml index a9733b11fe7b..b737d6c7a0f2 100644 --- a/.github/workflows/assistant-to-the-branch-manager.yml +++ b/.github/workflows/assistant-to-the-branch-manager.yml @@ -16,6 +16,6 @@ jobs: - uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0 with: persist-credentials: false - - uses: angular/dev-infra/github-actions/branch-manager@43d4ea5534ce399657a64c94a9dc1ea883324804 + - uses: angular/dev-infra/github-actions/branch-manager@e6f02a31dfb48ab1dfc1232da3ccbfce328fe2ae with: angular-robot-key: ${{ secrets.ANGULAR_ROBOT_PRIVATE_KEY }} diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 9bcfc0802c60..f868703aa90d 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@43d4ea5534ce399657a64c94a9dc1ea883324804 + uses: angular/dev-infra/github-actions/npm/checkout-and-setup-node@e6f02a31dfb48ab1dfc1232da3ccbfce328fe2ae - name: Setup Bazel - uses: angular/dev-infra/github-actions/bazel/setup@43d4ea5534ce399657a64c94a9dc1ea883324804 + uses: angular/dev-infra/github-actions/bazel/setup@e6f02a31dfb48ab1dfc1232da3ccbfce328fe2ae - 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@43d4ea5534ce399657a64c94a9dc1ea883324804 + uses: angular/dev-infra/github-actions/npm/checkout-and-setup-node@e6f02a31dfb48ab1dfc1232da3ccbfce328fe2ae - name: Setup Bazel - uses: angular/dev-infra/github-actions/bazel/setup@43d4ea5534ce399657a64c94a9dc1ea883324804 + uses: angular/dev-infra/github-actions/bazel/setup@e6f02a31dfb48ab1dfc1232da3ccbfce328fe2ae - name: Setup Bazel RBE - uses: angular/dev-infra/github-actions/bazel/configure-remote@43d4ea5534ce399657a64c94a9dc1ea883324804 + uses: angular/dev-infra/github-actions/bazel/configure-remote@e6f02a31dfb48ab1dfc1232da3ccbfce328fe2ae 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@43d4ea5534ce399657a64c94a9dc1ea883324804 + uses: angular/dev-infra/github-actions/npm/checkout-and-setup-node@e6f02a31dfb48ab1dfc1232da3ccbfce328fe2ae - name: Setup Bazel - uses: angular/dev-infra/github-actions/bazel/setup@43d4ea5534ce399657a64c94a9dc1ea883324804 + uses: angular/dev-infra/github-actions/bazel/setup@e6f02a31dfb48ab1dfc1232da3ccbfce328fe2ae - name: Setup Bazel RBE - uses: angular/dev-infra/github-actions/bazel/configure-remote@43d4ea5534ce399657a64c94a9dc1ea883324804 + uses: angular/dev-infra/github-actions/bazel/configure-remote@e6f02a31dfb48ab1dfc1232da3ccbfce328fe2ae with: google_credential: ${{ secrets.RBE_TRUSTED_BUILDS_USER }} - name: Install node modules @@ -85,13 +85,13 @@ jobs: runs-on: ${{ matrix.os }} steps: - name: Initialize environment - uses: angular/dev-infra/github-actions/npm/checkout-and-setup-node@43d4ea5534ce399657a64c94a9dc1ea883324804 + uses: angular/dev-infra/github-actions/npm/checkout-and-setup-node@e6f02a31dfb48ab1dfc1232da3ccbfce328fe2ae - name: Install node modules run: pnpm install --frozen-lockfile - name: Setup Bazel - uses: angular/dev-infra/github-actions/bazel/setup@43d4ea5534ce399657a64c94a9dc1ea883324804 + uses: angular/dev-infra/github-actions/bazel/setup@e6f02a31dfb48ab1dfc1232da3ccbfce328fe2ae - name: Setup Bazel RBE - uses: angular/dev-infra/github-actions/bazel/configure-remote@43d4ea5534ce399657a64c94a9dc1ea883324804 + uses: angular/dev-infra/github-actions/bazel/configure-remote@e6f02a31dfb48ab1dfc1232da3ccbfce328fe2ae with: google_credential: ${{ secrets.RBE_TRUSTED_BUILDS_USER }} - name: Run CLI E2E tests @@ -101,11 +101,11 @@ jobs: runs-on: ubuntu-latest steps: - name: Initialize environment - uses: angular/dev-infra/github-actions/npm/checkout-and-setup-node@43d4ea5534ce399657a64c94a9dc1ea883324804 + uses: angular/dev-infra/github-actions/npm/checkout-and-setup-node@e6f02a31dfb48ab1dfc1232da3ccbfce328fe2ae - name: Setup Bazel - uses: angular/dev-infra/github-actions/bazel/setup@43d4ea5534ce399657a64c94a9dc1ea883324804 + uses: angular/dev-infra/github-actions/bazel/setup@e6f02a31dfb48ab1dfc1232da3ccbfce328fe2ae - name: Setup Bazel RBE - uses: angular/dev-infra/github-actions/bazel/configure-remote@43d4ea5534ce399657a64c94a9dc1ea883324804 + uses: angular/dev-infra/github-actions/bazel/configure-remote@e6f02a31dfb48ab1dfc1232da3ccbfce328fe2ae with: google_credential: ${{ secrets.RBE_TRUSTED_BUILDS_USER }} - name: Install node modules @@ -139,7 +139,7 @@ jobs: runs-on: ${{ matrix.os }} steps: - name: Initialize environment - uses: angular/dev-infra/github-actions/npm/checkout-and-setup-node@43d4ea5534ce399657a64c94a9dc1ea883324804 + uses: angular/dev-infra/github-actions/npm/checkout-and-setup-node@e6f02a31dfb48ab1dfc1232da3ccbfce328fe2ae - name: Install node modules run: pnpm install --frozen-lockfile - name: Download built Windows E2E tests @@ -167,13 +167,13 @@ jobs: runs-on: ${{ matrix.os }} steps: - name: Initialize environment - uses: angular/dev-infra/github-actions/npm/checkout-and-setup-node@43d4ea5534ce399657a64c94a9dc1ea883324804 + uses: angular/dev-infra/github-actions/npm/checkout-and-setup-node@e6f02a31dfb48ab1dfc1232da3ccbfce328fe2ae - name: Install node modules run: pnpm install --frozen-lockfile - name: Setup Bazel - uses: angular/dev-infra/github-actions/bazel/setup@43d4ea5534ce399657a64c94a9dc1ea883324804 + uses: angular/dev-infra/github-actions/bazel/setup@e6f02a31dfb48ab1dfc1232da3ccbfce328fe2ae - name: Setup Bazel RBE - uses: angular/dev-infra/github-actions/bazel/configure-remote@43d4ea5534ce399657a64c94a9dc1ea883324804 + uses: angular/dev-infra/github-actions/bazel/configure-remote@e6f02a31dfb48ab1dfc1232da3ccbfce328fe2ae with: google_credential: ${{ secrets.RBE_TRUSTED_BUILDS_USER }} - name: Run CLI E2E tests @@ -192,13 +192,13 @@ jobs: runs-on: ${{ matrix.os }} steps: - name: Initialize environment - uses: angular/dev-infra/github-actions/npm/checkout-and-setup-node@43d4ea5534ce399657a64c94a9dc1ea883324804 + uses: angular/dev-infra/github-actions/npm/checkout-and-setup-node@e6f02a31dfb48ab1dfc1232da3ccbfce328fe2ae - name: Install node modules run: pnpm install --frozen-lockfile - name: Setup Bazel - uses: angular/dev-infra/github-actions/bazel/setup@43d4ea5534ce399657a64c94a9dc1ea883324804 + uses: angular/dev-infra/github-actions/bazel/setup@e6f02a31dfb48ab1dfc1232da3ccbfce328fe2ae - name: Setup Bazel RBE - uses: angular/dev-infra/github-actions/bazel/configure-remote@43d4ea5534ce399657a64c94a9dc1ea883324804 + uses: angular/dev-infra/github-actions/bazel/configure-remote@e6f02a31dfb48ab1dfc1232da3ccbfce328fe2ae with: google_credential: ${{ secrets.RBE_TRUSTED_BUILDS_USER }} - name: Run CLI E2E tests @@ -212,13 +212,13 @@ 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@43d4ea5534ce399657a64c94a9dc1ea883324804 + uses: angular/dev-infra/github-actions/npm/checkout-and-setup-node@e6f02a31dfb48ab1dfc1232da3ccbfce328fe2ae - name: Install node modules run: pnpm install --frozen-lockfile - name: Setup Bazel - uses: angular/dev-infra/github-actions/bazel/setup@43d4ea5534ce399657a64c94a9dc1ea883324804 + uses: angular/dev-infra/github-actions/bazel/setup@e6f02a31dfb48ab1dfc1232da3ccbfce328fe2ae - name: Setup Bazel RBE - uses: angular/dev-infra/github-actions/bazel/configure-remote@43d4ea5534ce399657a64c94a9dc1ea883324804 + uses: angular/dev-infra/github-actions/bazel/configure-remote@e6f02a31dfb48ab1dfc1232da3ccbfce328fe2ae with: google_credential: ${{ secrets.RBE_TRUSTED_BUILDS_USER }} - name: Run E2E Browser tests @@ -248,11 +248,11 @@ jobs: CIRCLE_BRANCH: ${{ github.ref_name }} steps: - name: Initialize environment - uses: angular/dev-infra/github-actions/npm/checkout-and-setup-node@43d4ea5534ce399657a64c94a9dc1ea883324804 + uses: angular/dev-infra/github-actions/npm/checkout-and-setup-node@e6f02a31dfb48ab1dfc1232da3ccbfce328fe2ae - name: Install node modules run: pnpm install --frozen-lockfile - name: Setup Bazel - uses: angular/dev-infra/github-actions/bazel/setup@43d4ea5534ce399657a64c94a9dc1ea883324804 + uses: angular/dev-infra/github-actions/bazel/setup@e6f02a31dfb48ab1dfc1232da3ccbfce328fe2ae - 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 200a6b3fd5e7..0f7de6bdbb5d 100644 --- a/.github/workflows/dev-infra.yml +++ b/.github/workflows/dev-infra.yml @@ -13,13 +13,13 @@ jobs: runs-on: ubuntu-latest steps: - uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0 - - uses: angular/dev-infra/github-actions/pull-request-labeling@43d4ea5534ce399657a64c94a9dc1ea883324804 + - uses: angular/dev-infra/github-actions/pull-request-labeling@e6f02a31dfb48ab1dfc1232da3ccbfce328fe2ae with: angular-robot-key: ${{ secrets.ANGULAR_ROBOT_PRIVATE_KEY }} post_approval_changes: runs-on: ubuntu-latest steps: - uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0 - - uses: angular/dev-infra/github-actions/post-approval-changes@43d4ea5534ce399657a64c94a9dc1ea883324804 + - uses: angular/dev-infra/github-actions/post-approval-changes@e6f02a31dfb48ab1dfc1232da3ccbfce328fe2ae with: angular-robot-key: ${{ secrets.ANGULAR_ROBOT_PRIVATE_KEY }} diff --git a/.github/workflows/feature-requests.yml b/.github/workflows/feature-requests.yml index 83f9811ddb54..3f83c558df51 100644 --- a/.github/workflows/feature-requests.yml +++ b/.github/workflows/feature-requests.yml @@ -16,6 +16,6 @@ jobs: if: github.repository == 'angular/angular-cli' runs-on: ubuntu-latest steps: - - uses: angular/dev-infra/github-actions/feature-request@43d4ea5534ce399657a64c94a9dc1ea883324804 + - uses: angular/dev-infra/github-actions/feature-request@e6f02a31dfb48ab1dfc1232da3ccbfce328fe2ae with: angular-robot-key: ${{ secrets.ANGULAR_ROBOT_PRIVATE_KEY }} diff --git a/.github/workflows/perf.yml b/.github/workflows/perf.yml index 17118598762c..693c0ce45a36 100644 --- a/.github/workflows/perf.yml +++ b/.github/workflows/perf.yml @@ -23,7 +23,7 @@ jobs: workflows: ${{ steps.workflows.outputs.workflows }} steps: - name: Initialize environment - uses: angular/dev-infra/github-actions/npm/checkout-and-setup-node@43d4ea5534ce399657a64c94a9dc1ea883324804 + uses: angular/dev-infra/github-actions/npm/checkout-and-setup-node@e6f02a31dfb48ab1dfc1232da3ccbfce328fe2ae - name: Install node modules run: pnpm install --frozen-lockfile - id: workflows @@ -38,9 +38,9 @@ jobs: workflow: ${{ fromJSON(needs.list.outputs.workflows) }} steps: - name: Initialize environment - uses: angular/dev-infra/github-actions/npm/checkout-and-setup-node@43d4ea5534ce399657a64c94a9dc1ea883324804 + uses: angular/dev-infra/github-actions/npm/checkout-and-setup-node@e6f02a31dfb48ab1dfc1232da3ccbfce328fe2ae - name: Setup Bazel - uses: angular/dev-infra/github-actions/bazel/setup@43d4ea5534ce399657a64c94a9dc1ea883324804 + uses: angular/dev-infra/github-actions/bazel/setup@e6f02a31dfb48ab1dfc1232da3ccbfce328fe2ae - 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 93723221e592..19a3df3fcbf3 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@43d4ea5534ce399657a64c94a9dc1ea883324804 + uses: angular/dev-infra/github-actions/npm/checkout-and-setup-node@e6f02a31dfb48ab1dfc1232da3ccbfce328fe2ae - name: Setup Bazel - uses: angular/dev-infra/github-actions/bazel/setup@43d4ea5534ce399657a64c94a9dc1ea883324804 + uses: angular/dev-infra/github-actions/bazel/setup@e6f02a31dfb48ab1dfc1232da3ccbfce328fe2ae - name: Setup ESLint Caching uses: actions/cache@0057852bfaa89a56745cba8c7296529d2fc39830 # v4.3.0 with: @@ -56,7 +56,7 @@ jobs: - name: Run Validation run: pnpm admin validate - name: Check Package Licenses - uses: angular/dev-infra/github-actions/linting/licenses@43d4ea5534ce399657a64c94a9dc1ea883324804 + uses: angular/dev-infra/github-actions/linting/licenses@e6f02a31dfb48ab1dfc1232da3ccbfce328fe2ae - name: Check tooling setup run: pnpm check-tooling-setup - name: Check commit message @@ -72,11 +72,11 @@ jobs: runs-on: ubuntu-latest steps: - name: Initialize environment - uses: angular/dev-infra/github-actions/npm/checkout-and-setup-node@43d4ea5534ce399657a64c94a9dc1ea883324804 + uses: angular/dev-infra/github-actions/npm/checkout-and-setup-node@e6f02a31dfb48ab1dfc1232da3ccbfce328fe2ae - name: Setup Bazel - uses: angular/dev-infra/github-actions/bazel/setup@43d4ea5534ce399657a64c94a9dc1ea883324804 + uses: angular/dev-infra/github-actions/bazel/setup@e6f02a31dfb48ab1dfc1232da3ccbfce328fe2ae - name: Setup Bazel RBE - uses: angular/dev-infra/github-actions/bazel/configure-remote@43d4ea5534ce399657a64c94a9dc1ea883324804 + uses: angular/dev-infra/github-actions/bazel/configure-remote@e6f02a31dfb48ab1dfc1232da3ccbfce328fe2ae - 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@43d4ea5534ce399657a64c94a9dc1ea883324804 + uses: angular/dev-infra/github-actions/npm/checkout-and-setup-node@e6f02a31dfb48ab1dfc1232da3ccbfce328fe2ae - name: Setup Bazel - uses: angular/dev-infra/github-actions/bazel/setup@43d4ea5534ce399657a64c94a9dc1ea883324804 + uses: angular/dev-infra/github-actions/bazel/setup@e6f02a31dfb48ab1dfc1232da3ccbfce328fe2ae - name: Setup Bazel RBE - uses: angular/dev-infra/github-actions/bazel/configure-remote@43d4ea5534ce399657a64c94a9dc1ea883324804 + uses: angular/dev-infra/github-actions/bazel/configure-remote@e6f02a31dfb48ab1dfc1232da3ccbfce328fe2ae - name: Install node modules run: pnpm install --frozen-lockfile - name: Run module and package tests @@ -115,13 +115,13 @@ jobs: runs-on: ${{ matrix.os }} steps: - name: Initialize environment - uses: angular/dev-infra/github-actions/npm/checkout-and-setup-node@43d4ea5534ce399657a64c94a9dc1ea883324804 + uses: angular/dev-infra/github-actions/npm/checkout-and-setup-node@e6f02a31dfb48ab1dfc1232da3ccbfce328fe2ae - name: Install node modules run: pnpm install --frozen-lockfile - name: Setup Bazel - uses: angular/dev-infra/github-actions/bazel/setup@43d4ea5534ce399657a64c94a9dc1ea883324804 + uses: angular/dev-infra/github-actions/bazel/setup@e6f02a31dfb48ab1dfc1232da3ccbfce328fe2ae - name: Setup Bazel RBE - uses: angular/dev-infra/github-actions/bazel/configure-remote@43d4ea5534ce399657a64c94a9dc1ea883324804 + uses: angular/dev-infra/github-actions/bazel/configure-remote@e6f02a31dfb48ab1dfc1232da3ccbfce328fe2ae - 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/legacy-cli:e2e.${{ matrix.subset }}_node${{ matrix.node }} @@ -129,11 +129,11 @@ jobs: runs-on: ubuntu-latest steps: - name: Initialize environment - uses: angular/dev-infra/github-actions/npm/checkout-and-setup-node@43d4ea5534ce399657a64c94a9dc1ea883324804 + uses: angular/dev-infra/github-actions/npm/checkout-and-setup-node@e6f02a31dfb48ab1dfc1232da3ccbfce328fe2ae - name: Setup Bazel - uses: angular/dev-infra/github-actions/bazel/setup@43d4ea5534ce399657a64c94a9dc1ea883324804 + uses: angular/dev-infra/github-actions/bazel/setup@e6f02a31dfb48ab1dfc1232da3ccbfce328fe2ae - name: Setup Bazel RBE - uses: angular/dev-infra/github-actions/bazel/configure-remote@43d4ea5534ce399657a64c94a9dc1ea883324804 + uses: angular/dev-infra/github-actions/bazel/configure-remote@e6f02a31dfb48ab1dfc1232da3ccbfce328fe2ae - name: Install node modules run: pnpm install --frozen-lockfile - name: Build E2E tests for Windows on Linux @@ -157,7 +157,7 @@ jobs: runs-on: windows-2025 steps: - name: Initialize environment - uses: angular/dev-infra/github-actions/npm/checkout-and-setup-node@43d4ea5534ce399657a64c94a9dc1ea883324804 + uses: angular/dev-infra/github-actions/npm/checkout-and-setup-node@e6f02a31dfb48ab1dfc1232da3ccbfce328fe2ae - name: Install node modules run: pnpm install --frozen-lockfile - name: Download built Windows E2E tests @@ -185,13 +185,13 @@ jobs: runs-on: ${{ matrix.os }} steps: - name: Initialize environment - uses: angular/dev-infra/github-actions/npm/checkout-and-setup-node@43d4ea5534ce399657a64c94a9dc1ea883324804 + uses: angular/dev-infra/github-actions/npm/checkout-and-setup-node@e6f02a31dfb48ab1dfc1232da3ccbfce328fe2ae - name: Install node modules run: pnpm install --frozen-lockfile - name: Setup Bazel - uses: angular/dev-infra/github-actions/bazel/setup@43d4ea5534ce399657a64c94a9dc1ea883324804 + uses: angular/dev-infra/github-actions/bazel/setup@e6f02a31dfb48ab1dfc1232da3ccbfce328fe2ae - name: Setup Bazel RBE - uses: angular/dev-infra/github-actions/bazel/configure-remote@43d4ea5534ce399657a64c94a9dc1ea883324804 + uses: angular/dev-infra/github-actions/bazel/configure-remote@e6f02a31dfb48ab1dfc1232da3ccbfce328fe2ae - 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/legacy-cli:e2e.${{ matrix.subset }}_node${{ matrix.node }} @@ -208,12 +208,12 @@ jobs: runs-on: ${{ matrix.os }} steps: - name: Initialize environment - uses: angular/dev-infra/github-actions/npm/checkout-and-setup-node@43d4ea5534ce399657a64c94a9dc1ea883324804 + uses: angular/dev-infra/github-actions/npm/checkout-and-setup-node@e6f02a31dfb48ab1dfc1232da3ccbfce328fe2ae - name: Install node modules run: pnpm install --frozen-lockfile - name: Setup Bazel - uses: angular/dev-infra/github-actions/bazel/setup@43d4ea5534ce399657a64c94a9dc1ea883324804 + uses: angular/dev-infra/github-actions/bazel/setup@e6f02a31dfb48ab1dfc1232da3ccbfce328fe2ae - name: Setup Bazel RBE - uses: angular/dev-infra/github-actions/bazel/configure-remote@43d4ea5534ce399657a64c94a9dc1ea883324804 + uses: angular/dev-infra/github-actions/bazel/configure-remote@e6f02a31dfb48ab1dfc1232da3ccbfce328fe2ae - 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/legacy-cli:e2e.snapshots.${{ matrix.subset }}_node${{ matrix.node }} diff --git a/MODULE.bazel b/MODULE.bazel index b3af7007f9ad..dc4d51b99f64 100644 --- a/MODULE.bazel +++ b/MODULE.bazel @@ -33,7 +33,7 @@ git_override( bazel_dep(name = "devinfra") git_override( module_name = "devinfra", - commit = "43d4ea5534ce399657a64c94a9dc1ea883324804", + commit = "e6f02a31dfb48ab1dfc1232da3ccbfce328fe2ae", remote = "https://github.com/angular/dev-infra.git", ) diff --git a/package.json b/package.json index 145e02ed2d86..cda94a985864 100644 --- a/package.json +++ b/package.json @@ -55,7 +55,7 @@ "@angular/forms": "20.3.7", "@angular/localize": "20.3.7", "@angular/material": "20.2.10", - "@angular/ng-dev": "https://github.com/angular/dev-infra-private-ng-dev-builds.git#a3426d37e6f9781b00650a767eb5b3967cdb94f7", + "@angular/ng-dev": "https://github.com/angular/dev-infra-private-ng-dev-builds.git#299992f45450bca8e547d90a4bf5e5d8ca60428a", "@angular/platform-browser": "20.3.7", "@angular/platform-server": "20.3.7", "@angular/router": "20.3.7", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index de1d0e1e6804..231292aa165c 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -47,8 +47,8 @@ importers: specifier: 20.2.10 version: 20.2.10(72d1932aa29c0670c8359e3ed8a5ff55) '@angular/ng-dev': - specifier: https://github.com/angular/dev-infra-private-ng-dev-builds.git#a3426d37e6f9781b00650a767eb5b3967cdb94f7 - version: https://codeload.github.com/angular/dev-infra-private-ng-dev-builds/tar.gz/a3426d37e6f9781b00650a767eb5b3967cdb94f7(@modelcontextprotocol/sdk@1.17.3) + specifier: https://github.com/angular/dev-infra-private-ng-dev-builds.git#299992f45450bca8e547d90a4bf5e5d8ca60428a + version: https://codeload.github.com/angular/dev-infra-private-ng-dev-builds/tar.gz/299992f45450bca8e547d90a4bf5e5d8ca60428a(@modelcontextprotocol/sdk@1.17.3) '@angular/platform-browser': specifier: 20.3.7 version: 20.3.7(@angular/animations@20.3.7(@angular/core@20.3.7(@angular/compiler@20.3.7)(rxjs@7.8.2)(zone.js@0.15.1)))(@angular/common@20.3.7(@angular/core@20.3.7(@angular/compiler@20.3.7)(rxjs@7.8.2)(zone.js@0.15.1))(rxjs@7.8.2))(@angular/core@20.3.7(@angular/compiler@20.3.7)(rxjs@7.8.2)(zone.js@0.15.1)) @@ -1050,9 +1050,9 @@ packages: '@angular/platform-browser': ^20.0.0 || ^21.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/a3426d37e6f9781b00650a767eb5b3967cdb94f7': - resolution: {tarball: https://codeload.github.com/angular/dev-infra-private-ng-dev-builds/tar.gz/a3426d37e6f9781b00650a767eb5b3967cdb94f7} - version: 0.0.0-43d4ea5534ce399657a64c94a9dc1ea883324804 + '@angular/ng-dev@https://codeload.github.com/angular/dev-infra-private-ng-dev-builds/tar.gz/299992f45450bca8e547d90a4bf5e5d8ca60428a': + resolution: {tarball: https://codeload.github.com/angular/dev-infra-private-ng-dev-builds/tar.gz/299992f45450bca8e547d90a4bf5e5d8ca60428a} + version: 0.0.0-e6f02a31dfb48ab1dfc1232da3ccbfce328fe2ae hasBin: true '@angular/platform-browser@20.3.7': @@ -9411,7 +9411,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/a3426d37e6f9781b00650a767eb5b3967cdb94f7(@modelcontextprotocol/sdk@1.17.3)': + '@angular/ng-dev@https://codeload.github.com/angular/dev-infra-private-ng-dev-builds/tar.gz/299992f45450bca8e547d90a4bf5e5d8ca60428a(@modelcontextprotocol/sdk@1.17.3)': dependencies: '@actions/core': 1.11.1 '@google-cloud/spanner': 8.0.0(supports-color@10.2.2) From 7b521ddb0eaad4906fe27bdd9e59faf5ddb649c6 Mon Sep 17 00:00:00 2001 From: Angular Robot Date: Thu, 23 Oct 2025 06:06:28 +0000 Subject: [PATCH 04/52] build: update pnpm to v10.19.0 See associated pull request for more information. --- package.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/package.json b/package.json index cda94a985864..dd7369dfdd50 100644 --- a/package.json +++ b/package.json @@ -32,12 +32,12 @@ "type": "git", "url": "https://github.com/angular/angular-cli.git" }, - "packageManager": "pnpm@10.18.3", + "packageManager": "pnpm@10.19.0", "engines": { "node": "^20.19.0 || ^22.12.0 || >=24.0.0", "npm": "Please use pnpm instead of NPM to install dependencies", "yarn": "Please use pnpm instead of Yarn to install dependencies", - "pnpm": "10.18.3" + "pnpm": "10.19.0" }, "author": "Angular Authors", "license": "MIT", From 813cba9b9bfe60e874595ce25608ca85a890f6bf Mon Sep 17 00:00:00 2001 From: Alan Agius <17563226+alan-agius4@users.noreply.github.com> Date: Thu, 23 Oct 2025 07:35:29 +0000 Subject: [PATCH 05/52] fix(@angular-devkit/build-angular): expand jest and jest-environment-jsdom to allow version 30 This commit expands the peer deps of these dependencies to allow version 30. --- packages/angular_devkit/build_angular/package.json | 4 ++-- .../angular_devkit/build_angular/src/builders/jest/index.ts | 2 +- tests/legacy-cli/e2e/utils/jest.ts | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/packages/angular_devkit/build_angular/package.json b/packages/angular_devkit/build_angular/package.json index 7d581aef8934..f37de4ae6ca2 100644 --- a/packages/angular_devkit/build_angular/package.json +++ b/packages/angular_devkit/build_angular/package.json @@ -81,8 +81,8 @@ "@angular/ssr": "^0.0.0-PLACEHOLDER", "@web/test-runner": "^0.20.0", "browser-sync": "^3.0.2", - "jest": "^29.5.0", - "jest-environment-jsdom": "^29.5.0", + "jest": "^29.5.0 || ^30.2.0", + "jest-environment-jsdom": "^29.5.0 || ^30.2.0", "karma": "^6.3.0", "ng-packagr": "0.0.0-NG-PACKAGR-PEER-DEP", "protractor": "^7.0.0", diff --git a/packages/angular_devkit/build_angular/src/builders/jest/index.ts b/packages/angular_devkit/build_angular/src/builders/jest/index.ts index c972dfa41a46..8cdcf59aad19 100644 --- a/packages/angular_devkit/build_angular/src/builders/jest/index.ts +++ b/packages/angular_devkit/build_angular/src/builders/jest/index.ts @@ -116,7 +116,7 @@ export default createBuilder( '--experimental-vm-modules', jest, - `--rootDir="${testOut}"`, + `--rootDir=${testOut}`, `--config=${path.join(__dirname, 'jest.config.mjs')}`, '--testEnvironment=jsdom', diff --git a/tests/legacy-cli/e2e/utils/jest.ts b/tests/legacy-cli/e2e/utils/jest.ts index 904cc6f903d6..db67b4aa9cb1 100644 --- a/tests/legacy-cli/e2e/utils/jest.ts +++ b/tests/legacy-cli/e2e/utils/jest.ts @@ -8,7 +8,7 @@ export async function applyJestBuilder( polyfills: ['zone.js', 'zone.js/testing'], }, ): Promise { - await silentNpm('install', 'jest@29.5.0', 'jest-environment-jsdom@29.5.0', '--save-dev'); + await silentNpm('install', 'jest@30.2.0', 'jest-environment-jsdom@30.2.0', '--save-dev'); await updateJsonFile('angular.json', (json) => { const projects = Object.values(json['projects']); From 15b449512f9585815711bf4b8b72d3a3f53af56f Mon Sep 17 00:00:00 2001 From: Angular Robot Date: Thu, 23 Oct 2025 12:07:52 +0000 Subject: [PATCH 06/52] build: update cross-repo angular dependencies See associated pull request for more information. --- .../assistant-to-the-branch-manager.yml | 2 +- .github/workflows/ci.yml | 52 +++++----- .github/workflows/dev-infra.yml | 4 +- .github/workflows/feature-requests.yml | 2 +- .github/workflows/perf.yml | 6 +- .github/workflows/pr.yml | 44 ++++----- MODULE.bazel | 2 +- package.json | 2 +- pnpm-lock.yaml | 95 +++---------------- 9 files changed, 69 insertions(+), 140 deletions(-) diff --git a/.github/workflows/assistant-to-the-branch-manager.yml b/.github/workflows/assistant-to-the-branch-manager.yml index b737d6c7a0f2..439bf1a78f22 100644 --- a/.github/workflows/assistant-to-the-branch-manager.yml +++ b/.github/workflows/assistant-to-the-branch-manager.yml @@ -16,6 +16,6 @@ jobs: - uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0 with: persist-credentials: false - - uses: angular/dev-infra/github-actions/branch-manager@e6f02a31dfb48ab1dfc1232da3ccbfce328fe2ae + - uses: angular/dev-infra/github-actions/branch-manager@ab6a00e9a219c2169ae0540cc5a32be5f481e004 with: angular-robot-key: ${{ secrets.ANGULAR_ROBOT_PRIVATE_KEY }} diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index f868703aa90d..ec086242138b 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@e6f02a31dfb48ab1dfc1232da3ccbfce328fe2ae + uses: angular/dev-infra/github-actions/npm/checkout-and-setup-node@ab6a00e9a219c2169ae0540cc5a32be5f481e004 - name: Setup Bazel - uses: angular/dev-infra/github-actions/bazel/setup@e6f02a31dfb48ab1dfc1232da3ccbfce328fe2ae + uses: angular/dev-infra/github-actions/bazel/setup@ab6a00e9a219c2169ae0540cc5a32be5f481e004 - 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@e6f02a31dfb48ab1dfc1232da3ccbfce328fe2ae + uses: angular/dev-infra/github-actions/npm/checkout-and-setup-node@ab6a00e9a219c2169ae0540cc5a32be5f481e004 - name: Setup Bazel - uses: angular/dev-infra/github-actions/bazel/setup@e6f02a31dfb48ab1dfc1232da3ccbfce328fe2ae + uses: angular/dev-infra/github-actions/bazel/setup@ab6a00e9a219c2169ae0540cc5a32be5f481e004 - name: Setup Bazel RBE - uses: angular/dev-infra/github-actions/bazel/configure-remote@e6f02a31dfb48ab1dfc1232da3ccbfce328fe2ae + uses: angular/dev-infra/github-actions/bazel/configure-remote@ab6a00e9a219c2169ae0540cc5a32be5f481e004 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@e6f02a31dfb48ab1dfc1232da3ccbfce328fe2ae + uses: angular/dev-infra/github-actions/npm/checkout-and-setup-node@ab6a00e9a219c2169ae0540cc5a32be5f481e004 - name: Setup Bazel - uses: angular/dev-infra/github-actions/bazel/setup@e6f02a31dfb48ab1dfc1232da3ccbfce328fe2ae + uses: angular/dev-infra/github-actions/bazel/setup@ab6a00e9a219c2169ae0540cc5a32be5f481e004 - name: Setup Bazel RBE - uses: angular/dev-infra/github-actions/bazel/configure-remote@e6f02a31dfb48ab1dfc1232da3ccbfce328fe2ae + uses: angular/dev-infra/github-actions/bazel/configure-remote@ab6a00e9a219c2169ae0540cc5a32be5f481e004 with: google_credential: ${{ secrets.RBE_TRUSTED_BUILDS_USER }} - name: Install node modules @@ -85,13 +85,13 @@ jobs: runs-on: ${{ matrix.os }} steps: - name: Initialize environment - uses: angular/dev-infra/github-actions/npm/checkout-and-setup-node@e6f02a31dfb48ab1dfc1232da3ccbfce328fe2ae + uses: angular/dev-infra/github-actions/npm/checkout-and-setup-node@ab6a00e9a219c2169ae0540cc5a32be5f481e004 - name: Install node modules run: pnpm install --frozen-lockfile - name: Setup Bazel - uses: angular/dev-infra/github-actions/bazel/setup@e6f02a31dfb48ab1dfc1232da3ccbfce328fe2ae + uses: angular/dev-infra/github-actions/bazel/setup@ab6a00e9a219c2169ae0540cc5a32be5f481e004 - name: Setup Bazel RBE - uses: angular/dev-infra/github-actions/bazel/configure-remote@e6f02a31dfb48ab1dfc1232da3ccbfce328fe2ae + uses: angular/dev-infra/github-actions/bazel/configure-remote@ab6a00e9a219c2169ae0540cc5a32be5f481e004 with: google_credential: ${{ secrets.RBE_TRUSTED_BUILDS_USER }} - name: Run CLI E2E tests @@ -101,11 +101,11 @@ jobs: runs-on: ubuntu-latest steps: - name: Initialize environment - uses: angular/dev-infra/github-actions/npm/checkout-and-setup-node@e6f02a31dfb48ab1dfc1232da3ccbfce328fe2ae + uses: angular/dev-infra/github-actions/npm/checkout-and-setup-node@ab6a00e9a219c2169ae0540cc5a32be5f481e004 - name: Setup Bazel - uses: angular/dev-infra/github-actions/bazel/setup@e6f02a31dfb48ab1dfc1232da3ccbfce328fe2ae + uses: angular/dev-infra/github-actions/bazel/setup@ab6a00e9a219c2169ae0540cc5a32be5f481e004 - name: Setup Bazel RBE - uses: angular/dev-infra/github-actions/bazel/configure-remote@e6f02a31dfb48ab1dfc1232da3ccbfce328fe2ae + uses: angular/dev-infra/github-actions/bazel/configure-remote@ab6a00e9a219c2169ae0540cc5a32be5f481e004 with: google_credential: ${{ secrets.RBE_TRUSTED_BUILDS_USER }} - name: Install node modules @@ -139,7 +139,7 @@ jobs: runs-on: ${{ matrix.os }} steps: - name: Initialize environment - uses: angular/dev-infra/github-actions/npm/checkout-and-setup-node@e6f02a31dfb48ab1dfc1232da3ccbfce328fe2ae + uses: angular/dev-infra/github-actions/npm/checkout-and-setup-node@ab6a00e9a219c2169ae0540cc5a32be5f481e004 - name: Install node modules run: pnpm install --frozen-lockfile - name: Download built Windows E2E tests @@ -167,13 +167,13 @@ jobs: runs-on: ${{ matrix.os }} steps: - name: Initialize environment - uses: angular/dev-infra/github-actions/npm/checkout-and-setup-node@e6f02a31dfb48ab1dfc1232da3ccbfce328fe2ae + uses: angular/dev-infra/github-actions/npm/checkout-and-setup-node@ab6a00e9a219c2169ae0540cc5a32be5f481e004 - name: Install node modules run: pnpm install --frozen-lockfile - name: Setup Bazel - uses: angular/dev-infra/github-actions/bazel/setup@e6f02a31dfb48ab1dfc1232da3ccbfce328fe2ae + uses: angular/dev-infra/github-actions/bazel/setup@ab6a00e9a219c2169ae0540cc5a32be5f481e004 - name: Setup Bazel RBE - uses: angular/dev-infra/github-actions/bazel/configure-remote@e6f02a31dfb48ab1dfc1232da3ccbfce328fe2ae + uses: angular/dev-infra/github-actions/bazel/configure-remote@ab6a00e9a219c2169ae0540cc5a32be5f481e004 with: google_credential: ${{ secrets.RBE_TRUSTED_BUILDS_USER }} - name: Run CLI E2E tests @@ -192,13 +192,13 @@ jobs: runs-on: ${{ matrix.os }} steps: - name: Initialize environment - uses: angular/dev-infra/github-actions/npm/checkout-and-setup-node@e6f02a31dfb48ab1dfc1232da3ccbfce328fe2ae + uses: angular/dev-infra/github-actions/npm/checkout-and-setup-node@ab6a00e9a219c2169ae0540cc5a32be5f481e004 - name: Install node modules run: pnpm install --frozen-lockfile - name: Setup Bazel - uses: angular/dev-infra/github-actions/bazel/setup@e6f02a31dfb48ab1dfc1232da3ccbfce328fe2ae + uses: angular/dev-infra/github-actions/bazel/setup@ab6a00e9a219c2169ae0540cc5a32be5f481e004 - name: Setup Bazel RBE - uses: angular/dev-infra/github-actions/bazel/configure-remote@e6f02a31dfb48ab1dfc1232da3ccbfce328fe2ae + uses: angular/dev-infra/github-actions/bazel/configure-remote@ab6a00e9a219c2169ae0540cc5a32be5f481e004 with: google_credential: ${{ secrets.RBE_TRUSTED_BUILDS_USER }} - name: Run CLI E2E tests @@ -212,13 +212,13 @@ 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@e6f02a31dfb48ab1dfc1232da3ccbfce328fe2ae + uses: angular/dev-infra/github-actions/npm/checkout-and-setup-node@ab6a00e9a219c2169ae0540cc5a32be5f481e004 - name: Install node modules run: pnpm install --frozen-lockfile - name: Setup Bazel - uses: angular/dev-infra/github-actions/bazel/setup@e6f02a31dfb48ab1dfc1232da3ccbfce328fe2ae + uses: angular/dev-infra/github-actions/bazel/setup@ab6a00e9a219c2169ae0540cc5a32be5f481e004 - name: Setup Bazel RBE - uses: angular/dev-infra/github-actions/bazel/configure-remote@e6f02a31dfb48ab1dfc1232da3ccbfce328fe2ae + uses: angular/dev-infra/github-actions/bazel/configure-remote@ab6a00e9a219c2169ae0540cc5a32be5f481e004 with: google_credential: ${{ secrets.RBE_TRUSTED_BUILDS_USER }} - name: Run E2E Browser tests @@ -248,11 +248,11 @@ jobs: CIRCLE_BRANCH: ${{ github.ref_name }} steps: - name: Initialize environment - uses: angular/dev-infra/github-actions/npm/checkout-and-setup-node@e6f02a31dfb48ab1dfc1232da3ccbfce328fe2ae + uses: angular/dev-infra/github-actions/npm/checkout-and-setup-node@ab6a00e9a219c2169ae0540cc5a32be5f481e004 - name: Install node modules run: pnpm install --frozen-lockfile - name: Setup Bazel - uses: angular/dev-infra/github-actions/bazel/setup@e6f02a31dfb48ab1dfc1232da3ccbfce328fe2ae + uses: angular/dev-infra/github-actions/bazel/setup@ab6a00e9a219c2169ae0540cc5a32be5f481e004 - 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 0f7de6bdbb5d..512efe35b754 100644 --- a/.github/workflows/dev-infra.yml +++ b/.github/workflows/dev-infra.yml @@ -13,13 +13,13 @@ jobs: runs-on: ubuntu-latest steps: - uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0 - - uses: angular/dev-infra/github-actions/pull-request-labeling@e6f02a31dfb48ab1dfc1232da3ccbfce328fe2ae + - uses: angular/dev-infra/github-actions/pull-request-labeling@ab6a00e9a219c2169ae0540cc5a32be5f481e004 with: angular-robot-key: ${{ secrets.ANGULAR_ROBOT_PRIVATE_KEY }} post_approval_changes: runs-on: ubuntu-latest steps: - uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0 - - uses: angular/dev-infra/github-actions/post-approval-changes@e6f02a31dfb48ab1dfc1232da3ccbfce328fe2ae + - uses: angular/dev-infra/github-actions/post-approval-changes@ab6a00e9a219c2169ae0540cc5a32be5f481e004 with: angular-robot-key: ${{ secrets.ANGULAR_ROBOT_PRIVATE_KEY }} diff --git a/.github/workflows/feature-requests.yml b/.github/workflows/feature-requests.yml index 3f83c558df51..c74b6262bf26 100644 --- a/.github/workflows/feature-requests.yml +++ b/.github/workflows/feature-requests.yml @@ -16,6 +16,6 @@ jobs: if: github.repository == 'angular/angular-cli' runs-on: ubuntu-latest steps: - - uses: angular/dev-infra/github-actions/feature-request@e6f02a31dfb48ab1dfc1232da3ccbfce328fe2ae + - uses: angular/dev-infra/github-actions/feature-request@ab6a00e9a219c2169ae0540cc5a32be5f481e004 with: angular-robot-key: ${{ secrets.ANGULAR_ROBOT_PRIVATE_KEY }} diff --git a/.github/workflows/perf.yml b/.github/workflows/perf.yml index 693c0ce45a36..4fcfe65f1417 100644 --- a/.github/workflows/perf.yml +++ b/.github/workflows/perf.yml @@ -23,7 +23,7 @@ jobs: workflows: ${{ steps.workflows.outputs.workflows }} steps: - name: Initialize environment - uses: angular/dev-infra/github-actions/npm/checkout-and-setup-node@e6f02a31dfb48ab1dfc1232da3ccbfce328fe2ae + uses: angular/dev-infra/github-actions/npm/checkout-and-setup-node@ab6a00e9a219c2169ae0540cc5a32be5f481e004 - name: Install node modules run: pnpm install --frozen-lockfile - id: workflows @@ -38,9 +38,9 @@ jobs: workflow: ${{ fromJSON(needs.list.outputs.workflows) }} steps: - name: Initialize environment - uses: angular/dev-infra/github-actions/npm/checkout-and-setup-node@e6f02a31dfb48ab1dfc1232da3ccbfce328fe2ae + uses: angular/dev-infra/github-actions/npm/checkout-and-setup-node@ab6a00e9a219c2169ae0540cc5a32be5f481e004 - name: Setup Bazel - uses: angular/dev-infra/github-actions/bazel/setup@e6f02a31dfb48ab1dfc1232da3ccbfce328fe2ae + uses: angular/dev-infra/github-actions/bazel/setup@ab6a00e9a219c2169ae0540cc5a32be5f481e004 - 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 19a3df3fcbf3..11599aae7ee6 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@e6f02a31dfb48ab1dfc1232da3ccbfce328fe2ae + uses: angular/dev-infra/github-actions/npm/checkout-and-setup-node@ab6a00e9a219c2169ae0540cc5a32be5f481e004 - name: Setup Bazel - uses: angular/dev-infra/github-actions/bazel/setup@e6f02a31dfb48ab1dfc1232da3ccbfce328fe2ae + uses: angular/dev-infra/github-actions/bazel/setup@ab6a00e9a219c2169ae0540cc5a32be5f481e004 - name: Setup ESLint Caching uses: actions/cache@0057852bfaa89a56745cba8c7296529d2fc39830 # v4.3.0 with: @@ -56,7 +56,7 @@ jobs: - name: Run Validation run: pnpm admin validate - name: Check Package Licenses - uses: angular/dev-infra/github-actions/linting/licenses@e6f02a31dfb48ab1dfc1232da3ccbfce328fe2ae + uses: angular/dev-infra/github-actions/linting/licenses@ab6a00e9a219c2169ae0540cc5a32be5f481e004 - name: Check tooling setup run: pnpm check-tooling-setup - name: Check commit message @@ -72,11 +72,11 @@ jobs: runs-on: ubuntu-latest steps: - name: Initialize environment - uses: angular/dev-infra/github-actions/npm/checkout-and-setup-node@e6f02a31dfb48ab1dfc1232da3ccbfce328fe2ae + uses: angular/dev-infra/github-actions/npm/checkout-and-setup-node@ab6a00e9a219c2169ae0540cc5a32be5f481e004 - name: Setup Bazel - uses: angular/dev-infra/github-actions/bazel/setup@e6f02a31dfb48ab1dfc1232da3ccbfce328fe2ae + uses: angular/dev-infra/github-actions/bazel/setup@ab6a00e9a219c2169ae0540cc5a32be5f481e004 - name: Setup Bazel RBE - uses: angular/dev-infra/github-actions/bazel/configure-remote@e6f02a31dfb48ab1dfc1232da3ccbfce328fe2ae + uses: angular/dev-infra/github-actions/bazel/configure-remote@ab6a00e9a219c2169ae0540cc5a32be5f481e004 - 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@e6f02a31dfb48ab1dfc1232da3ccbfce328fe2ae + uses: angular/dev-infra/github-actions/npm/checkout-and-setup-node@ab6a00e9a219c2169ae0540cc5a32be5f481e004 - name: Setup Bazel - uses: angular/dev-infra/github-actions/bazel/setup@e6f02a31dfb48ab1dfc1232da3ccbfce328fe2ae + uses: angular/dev-infra/github-actions/bazel/setup@ab6a00e9a219c2169ae0540cc5a32be5f481e004 - name: Setup Bazel RBE - uses: angular/dev-infra/github-actions/bazel/configure-remote@e6f02a31dfb48ab1dfc1232da3ccbfce328fe2ae + uses: angular/dev-infra/github-actions/bazel/configure-remote@ab6a00e9a219c2169ae0540cc5a32be5f481e004 - name: Install node modules run: pnpm install --frozen-lockfile - name: Run module and package tests @@ -115,13 +115,13 @@ jobs: runs-on: ${{ matrix.os }} steps: - name: Initialize environment - uses: angular/dev-infra/github-actions/npm/checkout-and-setup-node@e6f02a31dfb48ab1dfc1232da3ccbfce328fe2ae + uses: angular/dev-infra/github-actions/npm/checkout-and-setup-node@ab6a00e9a219c2169ae0540cc5a32be5f481e004 - name: Install node modules run: pnpm install --frozen-lockfile - name: Setup Bazel - uses: angular/dev-infra/github-actions/bazel/setup@e6f02a31dfb48ab1dfc1232da3ccbfce328fe2ae + uses: angular/dev-infra/github-actions/bazel/setup@ab6a00e9a219c2169ae0540cc5a32be5f481e004 - name: Setup Bazel RBE - uses: angular/dev-infra/github-actions/bazel/configure-remote@e6f02a31dfb48ab1dfc1232da3ccbfce328fe2ae + uses: angular/dev-infra/github-actions/bazel/configure-remote@ab6a00e9a219c2169ae0540cc5a32be5f481e004 - 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/legacy-cli:e2e.${{ matrix.subset }}_node${{ matrix.node }} @@ -129,11 +129,11 @@ jobs: runs-on: ubuntu-latest steps: - name: Initialize environment - uses: angular/dev-infra/github-actions/npm/checkout-and-setup-node@e6f02a31dfb48ab1dfc1232da3ccbfce328fe2ae + uses: angular/dev-infra/github-actions/npm/checkout-and-setup-node@ab6a00e9a219c2169ae0540cc5a32be5f481e004 - name: Setup Bazel - uses: angular/dev-infra/github-actions/bazel/setup@e6f02a31dfb48ab1dfc1232da3ccbfce328fe2ae + uses: angular/dev-infra/github-actions/bazel/setup@ab6a00e9a219c2169ae0540cc5a32be5f481e004 - name: Setup Bazel RBE - uses: angular/dev-infra/github-actions/bazel/configure-remote@e6f02a31dfb48ab1dfc1232da3ccbfce328fe2ae + uses: angular/dev-infra/github-actions/bazel/configure-remote@ab6a00e9a219c2169ae0540cc5a32be5f481e004 - name: Install node modules run: pnpm install --frozen-lockfile - name: Build E2E tests for Windows on Linux @@ -157,7 +157,7 @@ jobs: runs-on: windows-2025 steps: - name: Initialize environment - uses: angular/dev-infra/github-actions/npm/checkout-and-setup-node@e6f02a31dfb48ab1dfc1232da3ccbfce328fe2ae + uses: angular/dev-infra/github-actions/npm/checkout-and-setup-node@ab6a00e9a219c2169ae0540cc5a32be5f481e004 - name: Install node modules run: pnpm install --frozen-lockfile - name: Download built Windows E2E tests @@ -185,13 +185,13 @@ jobs: runs-on: ${{ matrix.os }} steps: - name: Initialize environment - uses: angular/dev-infra/github-actions/npm/checkout-and-setup-node@e6f02a31dfb48ab1dfc1232da3ccbfce328fe2ae + uses: angular/dev-infra/github-actions/npm/checkout-and-setup-node@ab6a00e9a219c2169ae0540cc5a32be5f481e004 - name: Install node modules run: pnpm install --frozen-lockfile - name: Setup Bazel - uses: angular/dev-infra/github-actions/bazel/setup@e6f02a31dfb48ab1dfc1232da3ccbfce328fe2ae + uses: angular/dev-infra/github-actions/bazel/setup@ab6a00e9a219c2169ae0540cc5a32be5f481e004 - name: Setup Bazel RBE - uses: angular/dev-infra/github-actions/bazel/configure-remote@e6f02a31dfb48ab1dfc1232da3ccbfce328fe2ae + uses: angular/dev-infra/github-actions/bazel/configure-remote@ab6a00e9a219c2169ae0540cc5a32be5f481e004 - 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/legacy-cli:e2e.${{ matrix.subset }}_node${{ matrix.node }} @@ -208,12 +208,12 @@ jobs: runs-on: ${{ matrix.os }} steps: - name: Initialize environment - uses: angular/dev-infra/github-actions/npm/checkout-and-setup-node@e6f02a31dfb48ab1dfc1232da3ccbfce328fe2ae + uses: angular/dev-infra/github-actions/npm/checkout-and-setup-node@ab6a00e9a219c2169ae0540cc5a32be5f481e004 - name: Install node modules run: pnpm install --frozen-lockfile - name: Setup Bazel - uses: angular/dev-infra/github-actions/bazel/setup@e6f02a31dfb48ab1dfc1232da3ccbfce328fe2ae + uses: angular/dev-infra/github-actions/bazel/setup@ab6a00e9a219c2169ae0540cc5a32be5f481e004 - name: Setup Bazel RBE - uses: angular/dev-infra/github-actions/bazel/configure-remote@e6f02a31dfb48ab1dfc1232da3ccbfce328fe2ae + uses: angular/dev-infra/github-actions/bazel/configure-remote@ab6a00e9a219c2169ae0540cc5a32be5f481e004 - 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/legacy-cli:e2e.snapshots.${{ matrix.subset }}_node${{ matrix.node }} diff --git a/MODULE.bazel b/MODULE.bazel index dc4d51b99f64..d78fba4fc6a2 100644 --- a/MODULE.bazel +++ b/MODULE.bazel @@ -33,7 +33,7 @@ git_override( bazel_dep(name = "devinfra") git_override( module_name = "devinfra", - commit = "e6f02a31dfb48ab1dfc1232da3ccbfce328fe2ae", + commit = "ab6a00e9a219c2169ae0540cc5a32be5f481e004", remote = "https://github.com/angular/dev-infra.git", ) diff --git a/package.json b/package.json index dd7369dfdd50..300bf966eeba 100644 --- a/package.json +++ b/package.json @@ -55,7 +55,7 @@ "@angular/forms": "20.3.7", "@angular/localize": "20.3.7", "@angular/material": "20.2.10", - "@angular/ng-dev": "https://github.com/angular/dev-infra-private-ng-dev-builds.git#299992f45450bca8e547d90a4bf5e5d8ca60428a", + "@angular/ng-dev": "https://github.com/angular/dev-infra-private-ng-dev-builds.git#b69a61793bd6ba935af262297688408d0b48252e", "@angular/platform-browser": "20.3.7", "@angular/platform-server": "20.3.7", "@angular/router": "20.3.7", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 231292aa165c..52eca2c2f2ad 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -47,8 +47,8 @@ importers: specifier: 20.2.10 version: 20.2.10(72d1932aa29c0670c8359e3ed8a5ff55) '@angular/ng-dev': - specifier: https://github.com/angular/dev-infra-private-ng-dev-builds.git#299992f45450bca8e547d90a4bf5e5d8ca60428a - version: https://codeload.github.com/angular/dev-infra-private-ng-dev-builds/tar.gz/299992f45450bca8e547d90a4bf5e5d8ca60428a(@modelcontextprotocol/sdk@1.17.3) + specifier: https://github.com/angular/dev-infra-private-ng-dev-builds.git#b69a61793bd6ba935af262297688408d0b48252e + version: https://codeload.github.com/angular/dev-infra-private-ng-dev-builds/tar.gz/b69a61793bd6ba935af262297688408d0b48252e '@angular/platform-browser': specifier: 20.3.7 version: 20.3.7(@angular/animations@20.3.7(@angular/core@20.3.7(@angular/compiler@20.3.7)(rxjs@7.8.2)(zone.js@0.15.1)))(@angular/common@20.3.7(@angular/core@20.3.7(@angular/compiler@20.3.7)(rxjs@7.8.2)(zone.js@0.15.1))(rxjs@7.8.2))(@angular/core@20.3.7(@angular/compiler@20.3.7)(rxjs@7.8.2)(zone.js@0.15.1)) @@ -1050,9 +1050,9 @@ packages: '@angular/platform-browser': ^20.0.0 || ^21.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/299992f45450bca8e547d90a4bf5e5d8ca60428a': - resolution: {tarball: https://codeload.github.com/angular/dev-infra-private-ng-dev-builds/tar.gz/299992f45450bca8e547d90a4bf5e5d8ca60428a} - version: 0.0.0-e6f02a31dfb48ab1dfc1232da3ccbfce328fe2ae + '@angular/ng-dev@https://codeload.github.com/angular/dev-infra-private-ng-dev-builds/tar.gz/b69a61793bd6ba935af262297688408d0b48252e': + resolution: {tarball: https://codeload.github.com/angular/dev-infra-private-ng-dev-builds/tar.gz/b69a61793bd6ba935af262297688408d0b48252e} + version: 0.0.0-ab6a00e9a219c2169ae0540cc5a32be5f481e004 hasBin: true '@angular/platform-browser@20.3.7': @@ -2113,11 +2113,11 @@ packages: resolution: {integrity: sha512-IJn+8A3QZJfe7FUtWqHVNo3xJs7KFpurCWGWCiCz3oEh+BkRymKZ1QxfAbU2yGMDzTytLGQ2IV6T2r3cuo75/w==} engines: {node: '>=18'} - '@google/genai@1.25.0': - resolution: {integrity: sha512-IBNyel/umavam98SQUfvQSvh/Rp6Ql2fysQLqPyWZr5K8d768X9AO+JZU4o+3qvFDUBA0dVYUSkxyYonVcICvA==} + '@google/genai@1.26.0': + resolution: {integrity: sha512-cy5y9RgN4jBK8zr+ePgZd0To1HDpzpjIgSM6aRCZnvYR+JupGtgc1SkkOCCi1MNZho7/MuKKdnQTLhhP8OQNvg==} engines: {node: '>=20.0.0'} peerDependencies: - '@modelcontextprotocol/sdk': ^1.11.4 + '@modelcontextprotocol/sdk': ^1.20.1 peerDependenciesMeta: '@modelcontextprotocol/sdk': optional: true @@ -5578,18 +5578,10 @@ packages: functions-have-names@1.2.3: resolution: {integrity: sha512-xckBUXyTIqT97tq2x2AMb+g163b5JFysYk0x4qxNFwbfQkmNZoiRHb6sPzI9/QV33WeuvVYBUIiD4NzNIyqaRQ==} - gaxios@6.7.1: - resolution: {integrity: sha512-LDODD4TMYx7XXdpwxAVRAIAuB0bzv0s+ywFonY46k126qzQHT9ygyoa9tncmOiQmmDrik65UYsEkv3lbfqQ3yQ==} - engines: {node: '>=14'} - gaxios@7.1.2: resolution: {integrity: sha512-/Szrn8nr+2TsQT1Gp8iIe/BEytJmbyfrbFh419DfGQSkEgNEhbPi7JRJuughjkTzPWgU9gBQf5AVu3DbHt0OXA==} engines: {node: '>=18'} - gcp-metadata@6.1.1: - resolution: {integrity: sha512-a4tiq7E0/5fTjxPAaH4jpjkSv/uCaU2p5KC6HVGrvl0cDjA8iBZv4vv1gyzlmK0ZUKqwpOyQMKzZQe3lTit77A==} - engines: {node: '>=14'} - gcp-metadata@7.0.1: resolution: {integrity: sha512-UcO3kefx6dCcZkgcTGgVOTFb7b1LlQ02hY1omMjjrrBzkajRMCFgYOjs7J71WqnuG1k2b+9ppGL7FsOfhZMQKQ==} engines: {node: '>=18'} @@ -5703,18 +5695,10 @@ packages: resolution: {integrity: sha512-CmIrSy1bqMQUsPmA9+hcSbAXL80cFhu40cGMUjCaLpNKVzzvi+0uAHq8GNZxkoGYIsTX4ZQ7e4aInAqWxgn4fg==} engines: {node: '>=18'} - google-auth-library@9.15.1: - resolution: {integrity: sha512-Jb6Z0+nvECVz+2lzSMt9u98UsoakXxA2HGHMCxh+so3n90XgYWkq5dur19JAJV7ONiJY22yBTyJB1TSkvPq9Ng==} - engines: {node: '>=14'} - google-gax@5.0.4: resolution: {integrity: sha512-HmQ6zIYBs2EikTk+kjeHmtHprNTEpsnVaKONw9cwZZwUNCkUb+D5RYrJpCxyjdvIDvJp3wLbVReolJLRZRms1g==} engines: {node: '>=18'} - google-logging-utils@0.0.2: - resolution: {integrity: sha512-NEgUnEcBiP5HrPzufUkBzJOD/Sxsco3rLNo1F1TNf7ieU8ryUzBhqba8r756CjLX7rn3fHl6iLEwPYuqpoKgQQ==} - engines: {node: '>=14'} - google-logging-utils@1.1.1: resolution: {integrity: sha512-rcX58I7nqpu4mbKztFeOAObbomBbHU2oIb/d3tJfF3dizGSApqtSwYJigGCooHdnMyQBIw8BrWyK96w3YXgr6A==} engines: {node: '>=14'} @@ -5745,10 +5729,6 @@ packages: peerDependencies: protobufjs: '*' - gtoken@7.1.0: - resolution: {integrity: sha512-pCcEwRi+TKpMlxAQObHDQ56KawURgyAf6jtIY046fJ5tIv3zDe/LEIubckAO8fj6JnAxLdmWkUfNyulQ2iKdEw==} - engines: {node: '>=14.0.0'} - gtoken@8.0.0: resolution: {integrity: sha512-+CqsMbHPiSTdtSO14O51eMNlrp9N79gmeqmXeouJOhfucAedHw9noVe/n5uJk3tbKE6a+6ZCQg3RPhVhHByAIw==} engines: {node: '>=18'} @@ -8717,10 +8697,6 @@ packages: resolution: {integrity: sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==} hasBin: true - uuid@9.0.1: - resolution: {integrity: sha512-b+1eJOlsR9K8HJpow9Ok3fiWOWSIcIzXodvv0rQjVoOVNpWMpxf1wZNpt4y9h10odCNrqnYp1OBzRktckBe3sA==} - hasBin: true - v8-compile-cache-lib@3.0.1: resolution: {integrity: sha512-wa7YjyUGfNZngI/vtK0UHAN+lgDCxBPCylVXGp0zu59Fz5aiGtNXaq3DhIov063MorB+VfufLh3JlF2KdTK3xg==} @@ -9411,11 +9387,11 @@ 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/299992f45450bca8e547d90a4bf5e5d8ca60428a(@modelcontextprotocol/sdk@1.17.3)': + '@angular/ng-dev@https://codeload.github.com/angular/dev-infra-private-ng-dev-builds/tar.gz/b69a61793bd6ba935af262297688408d0b48252e': dependencies: '@actions/core': 1.11.1 '@google-cloud/spanner': 8.0.0(supports-color@10.2.2) - '@google/genai': 1.25.0(@modelcontextprotocol/sdk@1.17.3)(bufferutil@4.0.9)(encoding@0.1.13)(supports-color@10.2.2)(utf-8-validate@6.0.5) + '@google/genai': 1.26.0(bufferutil@4.0.9)(supports-color@10.2.2)(utf-8-validate@6.0.5) '@inquirer/prompts': 7.9.0(@types/node@24.9.1) '@inquirer/type': 3.0.9(@types/node@24.9.1) '@octokit/auth-app': 8.1.1 @@ -10750,15 +10726,12 @@ snapshots: transitivePeerDependencies: - supports-color - '@google/genai@1.25.0(@modelcontextprotocol/sdk@1.17.3)(bufferutil@4.0.9)(encoding@0.1.13)(supports-color@10.2.2)(utf-8-validate@6.0.5)': + '@google/genai@1.26.0(bufferutil@4.0.9)(supports-color@10.2.2)(utf-8-validate@6.0.5)': dependencies: - google-auth-library: 9.15.1(encoding@0.1.13)(supports-color@10.2.2) + google-auth-library: 10.4.0(supports-color@10.2.2) ws: 8.18.3(bufferutil@4.0.9)(utf-8-validate@6.0.5) - optionalDependencies: - '@modelcontextprotocol/sdk': 1.17.3 transitivePeerDependencies: - bufferutil - - encoding - supports-color - utf-8-validate @@ -14699,17 +14672,6 @@ snapshots: functions-have-names@1.2.3: {} - gaxios@6.7.1(encoding@0.1.13)(supports-color@10.2.2): - dependencies: - extend: 3.0.2 - https-proxy-agent: 7.0.6(supports-color@10.2.2) - is-stream: 2.0.1 - node-fetch: 2.7.0(encoding@0.1.13) - uuid: 9.0.1 - transitivePeerDependencies: - - encoding - - supports-color - gaxios@7.1.2(supports-color@10.2.2): dependencies: extend: 3.0.2 @@ -14718,15 +14680,6 @@ snapshots: transitivePeerDependencies: - supports-color - gcp-metadata@6.1.1(encoding@0.1.13)(supports-color@10.2.2): - dependencies: - gaxios: 6.7.1(encoding@0.1.13)(supports-color@10.2.2) - google-logging-utils: 0.0.2 - json-bigint: 1.0.0 - transitivePeerDependencies: - - encoding - - supports-color - gcp-metadata@7.0.1(supports-color@10.2.2): dependencies: gaxios: 7.1.2(supports-color@10.2.2) @@ -14879,18 +14832,6 @@ snapshots: transitivePeerDependencies: - supports-color - google-auth-library@9.15.1(encoding@0.1.13)(supports-color@10.2.2): - dependencies: - base64-js: 1.5.1 - ecdsa-sig-formatter: 1.0.11 - gaxios: 6.7.1(encoding@0.1.13)(supports-color@10.2.2) - gcp-metadata: 6.1.1(encoding@0.1.13)(supports-color@10.2.2) - gtoken: 7.1.0(encoding@0.1.13)(supports-color@10.2.2) - jws: 4.0.0 - transitivePeerDependencies: - - encoding - - supports-color - google-gax@5.0.4(supports-color@10.2.2): dependencies: '@grpc/grpc-js': 1.14.0 @@ -14906,8 +14847,6 @@ snapshots: transitivePeerDependencies: - supports-color - google-logging-utils@0.0.2: {} - google-logging-utils@1.1.1: {} gopd@1.2.0: {} @@ -14928,14 +14867,6 @@ snapshots: '@grpc/grpc-js': 1.14.0 protobufjs: 7.5.4 - gtoken@7.1.0(encoding@0.1.13)(supports-color@10.2.2): - dependencies: - gaxios: 6.7.1(encoding@0.1.13)(supports-color@10.2.2) - jws: 4.0.0 - transitivePeerDependencies: - - encoding - - supports-color - gtoken@8.0.0(supports-color@10.2.2): dependencies: gaxios: 7.1.2(supports-color@10.2.2) @@ -18271,8 +18202,6 @@ snapshots: uuid@8.3.2: {} - uuid@9.0.1: {} - v8-compile-cache-lib@3.0.1: {} v8-to-istanbul@9.3.0: From 2c7581c4b5bb50b2354c0ceda71936487f9ee9ab Mon Sep 17 00:00:00 2001 From: Charles Lyding <19598772+clydin@users.noreply.github.com> Date: Fri, 17 Oct 2025 14:41:50 -0400 Subject: [PATCH 07/52] refactor(@angular/build): allow Bazel to inject a custom esbuild plugin Introduces a mechanism to dynamically load a custom esbuild plugin when the application builder is executed within a Bazel environment. This is enabled by a new `bazelEsbuildPluginPath` option, which is derived from the `NG_INTERNAL_ESBUILD_PLUGINS_DO_NOT_USE` environment variable. The path is only resolved if the `BAZEL_BINDIR` and `JS_BINARY__EXECROOT` environment variables are also present, ensuring the logic is only active during a Bazel build. The builder dynamically imports the plugin from the specified path and adds it to the esbuild pipeline, allowing for build-system-specific customizations. (cherry picked from commit ec739d79e042c2b33fd84ed9aede7c88a82e167e) --- .../angular/build/src/builders/application/index.ts | 10 +++++++++- .../angular/build/src/utils/environment-options.ts | 8 ++++++++ 2 files changed, 17 insertions(+), 1 deletion(-) diff --git a/packages/angular/build/src/builders/application/index.ts b/packages/angular/build/src/builders/application/index.ts index 8f11f2fd8001..b83e3b48f270 100644 --- a/packages/angular/build/src/builders/application/index.ts +++ b/packages/angular/build/src/builders/application/index.ts @@ -14,7 +14,7 @@ import { BuildOutputFileType } from '../../tools/esbuild/bundler-context'; import { createJsonBuildManifest, emitFilesToDisk } from '../../tools/esbuild/utils'; import { colors as ansiColors } from '../../utils/color'; import { deleteOutputDir } from '../../utils/delete-output-dir'; -import { useJSONBuildLogs } from '../../utils/environment-options'; +import { bazelEsbuildPluginPath, useJSONBuildLogs } from '../../utils/environment-options'; import { purgeStaleBuildCache } from '../../utils/purge-cache'; import { assertCompatibleAngularVersion } from '../../utils/version'; import { runEsBuildBuildAction } from './build-action'; @@ -56,6 +56,14 @@ export async function* buildApplicationInternal( return; } + if (bazelEsbuildPluginPath) { + extensions ??= {}; + extensions.codePlugins ??= []; + + const { default: bazelEsbuildPlugin } = await import(bazelEsbuildPluginPath); + extensions.codePlugins.push(bazelEsbuildPlugin); + } + const normalizedOptions = await normalizeOptions(context, projectName, options, extensions); if (!normalizedOptions.outputOptions.ignoreServer) { diff --git a/packages/angular/build/src/utils/environment-options.ts b/packages/angular/build/src/utils/environment-options.ts index ea06fea2d09f..d830a5095959 100644 --- a/packages/angular/build/src/utils/environment-options.ts +++ b/packages/angular/build/src/utils/environment-options.ts @@ -112,3 +112,11 @@ export const useComponentTemplateHmr = const partialSsrBuildVariable = process.env['NG_BUILD_PARTIAL_SSR']; export const usePartialSsrBuild = isPresent(partialSsrBuildVariable) && isEnabled(partialSsrBuildVariable); + +const bazelBinDirectory = process.env['BAZEL_BINDIR']; +const bazelExecRoot = process.env['JS_BINARY__EXECROOT']; + +export const bazelEsbuildPluginPath = + bazelBinDirectory && bazelExecRoot + ? process.env['NG_INTERNAL_ESBUILD_PLUGINS_DO_NOT_USE'] + : undefined; From e6ccc74cb471440f7c5851d7453ecfea298a1103 Mon Sep 17 00:00:00 2001 From: MeAkib Date: Sat, 25 Oct 2025 16:57:05 +0600 Subject: [PATCH 08/52] refactor(@schematics/angular): add trailing comma to generated services Ensures code consistency by including trailing commas in generated service (cherry picked from commit 6dfee716f5c01cc5c887f0c3a18625bf6d7729fb) --- .../files/__name@dasherize__.__type@dasherize__.ts.template | 2 +- packages/schematics/angular/service/index_spec.ts | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/schematics/angular/service/files/__name@dasherize__.__type@dasherize__.ts.template b/packages/schematics/angular/service/files/__name@dasherize__.__type@dasherize__.ts.template index 5c104786d178..056fdfea9385 100644 --- a/packages/schematics/angular/service/files/__name@dasherize__.__type@dasherize__.ts.template +++ b/packages/schematics/angular/service/files/__name@dasherize__.__type@dasherize__.ts.template @@ -1,7 +1,7 @@ import { Injectable } from '@angular/core'; @Injectable({ - providedIn: 'root' + providedIn: 'root', }) export class <%= classify(name) %><%= classify(type) %> { diff --git a/packages/schematics/angular/service/index_spec.ts b/packages/schematics/angular/service/index_spec.ts index b5a6856e1504..daa99df71145 100644 --- a/packages/schematics/angular/service/index_spec.ts +++ b/packages/schematics/angular/service/index_spec.ts @@ -55,7 +55,7 @@ describe('Service Schematic', () => { const tree = await schematicRunner.runSchematic('service', options, appTree); const content = tree.readContent('/projects/bar/src/app/foo/foo.ts'); - expect(content).toMatch(/providedIn: 'root'/); + expect(content).toMatch(/providedIn: 'root',/); }); it('should respect the skipTests flag', async () => { From 45e498f9576ff83eebe02deb235d36498ce06bde Mon Sep 17 00:00:00 2001 From: Alan Agius <17563226+alan-agius4@users.noreply.github.com> Date: Tue, 28 Oct 2025 13:49:33 +0000 Subject: [PATCH 09/52] fix(@angular/build): handle redirects from guards during prerendering During prerendering, if a route returns a redirect, a static HTML page with a meta refresh tag is generated to redirect the user to the specified URL. This now includes support for redirects returned from route guards. Closes #31618 (cherry picked from commit cc16b1006522522d8ad2f4735d18ca625a12ec1d) --- .../src/utils/server-rendering/prerender.ts | 26 +------------------ .../utils/server-rendering/render-worker.ts | 9 ++++++- .../build/src/utils/server-rendering/utils.ts | 25 ++++++++++++++++++ .../server-routes-output-mode-static.ts | 13 ++++++++-- 4 files changed, 45 insertions(+), 28 deletions(-) diff --git a/packages/angular/build/src/utils/server-rendering/prerender.ts b/packages/angular/build/src/utils/server-rendering/prerender.ts index e087262a7f0c..5ece379ec9c0 100644 --- a/packages/angular/build/src/utils/server-rendering/prerender.ts +++ b/packages/angular/build/src/utils/server-rendering/prerender.ts @@ -26,6 +26,7 @@ import { WritableSerializableRouteTreeNode, } from './models'; import type { RenderWorkerData } from './render-worker'; +import { generateRedirectStaticPage } from './utils'; type PrerenderOptions = NormalizedApplicationBuildOptions['prerenderOptions']; type AppShellOptions = NormalizedApplicationBuildOptions['appShellOptions']; @@ -380,28 +381,3 @@ function addTrailingSlash(url: string): string { function removeLeadingSlash(value: string): string { return value[0] === '/' ? value.slice(1) : value; } - -/** - * Generates a static HTML page with a meta refresh tag to redirect the user to a specified URL. - * - * This function creates a simple HTML page that performs a redirect using a meta tag. - * It includes a fallback link in case the meta-refresh doesn't work. - * - * @param url - The URL to which the page should redirect. - * @returns The HTML content of the static redirect page. - */ -function generateRedirectStaticPage(url: string): string { - return ` - - - - - Redirecting - - - -
Redirecting to ${url}
- - -`.trim(); -} diff --git a/packages/angular/build/src/utils/server-rendering/render-worker.ts b/packages/angular/build/src/utils/server-rendering/render-worker.ts index 92fad35df32a..1d604d4743fc 100644 --- a/packages/angular/build/src/utils/server-rendering/render-worker.ts +++ b/packages/angular/build/src/utils/server-rendering/render-worker.ts @@ -12,6 +12,7 @@ import type { ESMInMemoryFileLoaderWorkerData } from './esm-in-memory-loader/loa import { patchFetchToLoadInMemoryAssets } from './fetch-patch'; import { DEFAULT_URL, launchServer } from './launch-server'; import { loadEsmModuleFromMemory } from './load-esm-from-memory'; +import { generateRedirectStaticPage } from './utils'; export interface RenderWorkerData extends ESMInMemoryFileLoaderWorkerData { assetFiles: Record; @@ -48,7 +49,13 @@ async function renderPage({ url }: RenderOptions): Promise { new Request(new URL(url, serverURL), { signal: AbortSignal.timeout(30_000) }), ); - return response ? response.text() : null; + if (!response) { + return null; + } + + const location = response.headers.get('Location'); + + return location ? generateRedirectStaticPage(location) : response.text(); } async function initialize() { diff --git a/packages/angular/build/src/utils/server-rendering/utils.ts b/packages/angular/build/src/utils/server-rendering/utils.ts index 83c90187178b..a3229bb9b796 100644 --- a/packages/angular/build/src/utils/server-rendering/utils.ts +++ b/packages/angular/build/src/utils/server-rendering/utils.ts @@ -19,3 +19,28 @@ export function isSsrRequestHandler( ): value is ReturnType { return typeof value === 'function' && '__ng_request_handler__' in value; } + +/** + * Generates a static HTML page with a meta refresh tag to redirect the user to a specified URL. + * + * This function creates a simple HTML page that performs a redirect using a meta tag. + * It includes a fallback link in case the meta-refresh doesn't work. + * + * @param url - The URL to which the page should redirect. + * @returns The HTML content of the static redirect page. + */ +export function generateRedirectStaticPage(url: string): string { + return ` + + + + + Redirecting + + + +
Redirecting to ${url}
+ + +`.trim(); +} diff --git a/tests/legacy-cli/e2e/tests/build/server-rendering/server-routes-output-mode-static.ts b/tests/legacy-cli/e2e/tests/build/server-rendering/server-routes-output-mode-static.ts index 617776a94dc7..77f954be4f4d 100644 --- a/tests/legacy-cli/e2e/tests/build/server-rendering/server-routes-output-mode-static.ts +++ b/tests/legacy-cli/e2e/tests/build/server-rendering/server-routes-output-mode-static.ts @@ -29,7 +29,8 @@ export default async function () { await writeFile( 'src/app/app.routes.ts', ` - import { Routes } from '@angular/router'; + import { inject } from '@angular/core'; + import { Routes, Router } from '@angular/router'; import { Home } from './home/home'; import { Ssg } from './ssg/ssg'; import { SsgWithParams } from './ssg-with-params/ssg-with-params'; @@ -47,6 +48,12 @@ export default async function () { path: 'ssg-redirect', redirectTo: 'ssg' }, + { + path: 'ssg-redirect-via-guard', + canActivate: [() => { + return inject(Router).createUrlTree(['ssg'], { queryParams: { foo: 'bar' }}) + }], + }, { path: 'ssg/:id', component: SsgWithParams, @@ -106,8 +113,10 @@ export default async function () { 'ssg/index.html': /ng-server-context="ssg".+ssg works!/, 'ssg/one/index.html': /ng-server-context="ssg".+ssg-with-params works!/, 'ssg/two/index.html': /ng-server-context="ssg".+ssg-with-params works!/, - // When static redirects as generated as meta tags. + // When static redirects are generated as meta tags. 'ssg-redirect/index.html': '', + 'ssg-redirect-via-guard/index.html': + '', }; for (const [filePath, fileMatch] of Object.entries(expects)) { From 542973ab074ccd9a5f09f73ee7f2706a21db45fc Mon Sep 17 00:00:00 2001 From: Alan Agius <17563226+alan-agius4@users.noreply.github.com> Date: Wed, 29 Oct 2025 10:06:23 +0000 Subject: [PATCH 10/52] fix(@angular/build): add adapters to new reporter This commit add `adapters` field to the `ProgressNotifierReporter`. Closes #31629 --- .../angular/build/src/builders/karma/application_builder.ts | 2 ++ 1 file changed, 2 insertions(+) diff --git a/packages/angular/build/src/builders/karma/application_builder.ts b/packages/angular/build/src/builders/karma/application_builder.ts index b504146df2a4..365d5fec8ef0 100644 --- a/packages/angular/build/src/builders/karma/application_builder.ts +++ b/packages/angular/build/src/builders/karma/application_builder.ts @@ -215,6 +215,8 @@ function injectKarmaReporter( class ProgressNotifierReporter { static $inject = ['emitter', LATEST_BUILD_FILES_TOKEN]; + // Needed for the karma reporter interface, see https://github.com/angular/angular-cli/issues/31629 + adapters = []; constructor( private readonly emitter: KarmaEmitter, From f0885691d18b6575351774fcc50d746d981285f6 Mon Sep 17 00:00:00 2001 From: Alan Agius <17563226+alan-agius4@users.noreply.github.com> Date: Wed, 29 Oct 2025 17:06:56 +0000 Subject: [PATCH 11/52] fix(@angular/build): ensure locale data plugin runs before other plugins The Angular locale data plugin is responsible for resolving imports. In some cases, other plugins would attempt to resolve these imports first, leading to a 'Failed to resolve import' error. By ensuring that the Angular locale data plugin is prepended to the esbuild plugin list, we guarantee that it runs before other plugins, allowing it to correctly resolve the locale data imports. Closes #31579 (cherry picked from commit ccc598208cd2eccd18fa8c39564fcd3eea3547d7) --- .../angular/build/src/tools/esbuild/application-code-bundle.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/angular/build/src/tools/esbuild/application-code-bundle.ts b/packages/angular/build/src/tools/esbuild/application-code-bundle.ts index b17029f6c5e1..51d3702887f7 100644 --- a/packages/angular/build/src/tools/esbuild/application-code-bundle.ts +++ b/packages/angular/build/src/tools/esbuild/application-code-bundle.ts @@ -686,7 +686,7 @@ function getEsBuildCommonPolyfillsOptions( needLocaleDataPlugin = true; } if (needLocaleDataPlugin) { - buildOptions.plugins.push(createAngularLocaleDataPlugin()); + buildOptions.plugins.unshift(createAngularLocaleDataPlugin()); } if (polyfills.length === 0) { From 4ac89c5a609450f14c4d81cf344afe63a3c63432 Mon Sep 17 00:00:00 2001 From: Charles Lyding <19598772+clydin@users.noreply.github.com> Date: Wed, 29 Oct 2025 14:03:31 -0400 Subject: [PATCH 12/52] release: cut the v20.3.8 release --- CHANGELOG.md | 20 ++++++++++++++++++++ package.json | 2 +- 2 files changed, 21 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index b3eb54015455..a7bbfbaab97f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,23 @@ + + +# 20.3.8 (2025-10-29) + +### @angular-devkit/build-angular + +| Commit | Type | Description | +| --------------------------------------------------------------------------------------------------- | ---- | ---------------------------------------------------------- | +| [813cba9b9](https://github.com/angular/angular-cli/commit/813cba9b9bfe60e874595ce25608ca85a890f6bf) | fix | expand jest and jest-environment-jsdom to allow version 30 | + +### @angular/build + +| Commit | Type | Description | +| --------------------------------------------------------------------------------------------------- | ---- | --------------------------------------------------- | +| [542973ab0](https://github.com/angular/angular-cli/commit/542973ab074ccd9a5f09f73ee7f2706a21db45fc) | fix | add adapters to new reporter | +| [f0885691d](https://github.com/angular/angular-cli/commit/f0885691d18b6575351774fcc50d746d981285f6) | fix | ensure locale data plugin runs before other plugins | +| [45e498f95](https://github.com/angular/angular-cli/commit/45e498f9576ff83eebe02deb235d36498ce06bde) | fix | handle redirects from guards during prerendering | + + + # 20.3.7 (2025-10-22) diff --git a/package.json b/package.json index 300bf966eeba..c88f1c2927f7 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@angular/devkit-repo", - "version": "20.3.7", + "version": "20.3.8", "private": true, "description": "Software Development Kit for Angular", "keywords": [ From 08e07e338edd799400e18cd62cd131b6d408f4cf Mon Sep 17 00:00:00 2001 From: Alan Agius <17563226+alan-agius4@users.noreply.github.com> Date: Tue, 4 Nov 2025 09:48:11 +0000 Subject: [PATCH 13/52] fix(@angular/ssr): improve locale handling in app-engine Refactor app-engine to correctly handle single locale configurations and update manifest type definitions. Add new test cases for localized apps with a single locale. closes #31675 (cherry picked from commit 30efc56333f56a0feda418cee57eccbfbaf46936) --- packages/angular/ssr/src/app-engine.ts | 5 +- packages/angular/ssr/src/manifest.ts | 2 +- packages/angular/ssr/test/app-engine_spec.ts | 60 ++++++++++++++++++++ 3 files changed, 64 insertions(+), 3 deletions(-) diff --git a/packages/angular/ssr/src/app-engine.ts b/packages/angular/ssr/src/app-engine.ts index 0ce5d23c30d1..dd204a4b595f 100644 --- a/packages/angular/ssr/src/app-engine.ts +++ b/packages/angular/ssr/src/app-engine.ts @@ -191,9 +191,10 @@ export class AngularAppEngine { * @returns A promise that resolves to the entry point exports or `undefined` if not found. */ private getEntryPointExportsForUrl(url: URL): Promise | undefined { - const { basePath } = this.manifest; + const { basePath, supportedLocales } = this.manifest; + if (this.supportedLocales.length === 1) { - return this.getEntryPointExports(''); + return this.getEntryPointExports(supportedLocales[this.supportedLocales[0]]); } const potentialLocale = getPotentialLocaleIdFromUrl(url, basePath); diff --git a/packages/angular/ssr/src/manifest.ts b/packages/angular/ssr/src/manifest.ts index 8fc415546033..0de603bba104 100644 --- a/packages/angular/ssr/src/manifest.ts +++ b/packages/angular/ssr/src/manifest.ts @@ -73,7 +73,7 @@ export interface AngularAppEngineManifest { * - `key`: The locale identifier (e.g., 'en', 'fr'). * - `value`: The url segment associated with that locale. */ - readonly supportedLocales: Readonly>; + readonly supportedLocales: Readonly>; } /** diff --git a/packages/angular/ssr/test/app-engine_spec.ts b/packages/angular/ssr/test/app-engine_spec.ts index c8ebbc4446ea..76b68f6d4a82 100644 --- a/packages/angular/ssr/test/app-engine_spec.ts +++ b/packages/angular/ssr/test/app-engine_spec.ts @@ -160,6 +160,66 @@ describe('AngularAppEngine', () => { }); }); + describe('Localized app with single locale', () => { + beforeAll(() => { + setAngularAppEngineManifest({ + entryPoints: { + it: createEntryPoint('it'), + }, + supportedLocales: { 'it': 'it' }, + basePath: '/', + }); + + appEngine = new AngularAppEngine(); + }); + + describe('handle', () => { + it('should return null for requests to unknown pages', async () => { + const request = new Request('https://example.com/unknown/page'); + const response = await appEngine.handle(request); + expect(response).toBeNull(); + }); + + it('should return a rendered page with correct locale', async () => { + const request = new Request('https://example.com/it/ssr'); + const response = await appEngine.handle(request); + expect(await response?.text()).toContain('SSR works IT'); + }); + + it('should correctly render the content when the URL ends with "index.html" with correct locale', async () => { + const request = new Request('https://example.com/it/ssr/index.html'); + const response = await appEngine.handle(request); + expect(await response?.text()).toContain('SSR works IT'); + expect(response?.headers?.get('Content-Language')).toBe('it'); + }); + + it('should return a serve prerendered page with correct locale', async () => { + const request = new Request('https://example.com/it/ssg'); + const response = await appEngine.handle(request); + expect(await response?.text()).toContain('SSG works IT'); + expect(response?.headers?.get('Content-Language')).toBe('it'); + }); + + it('should correctly serve the prerendered content when the URL ends with "index.html" with correct locale', async () => { + const request = new Request('https://example.com/it/ssg/index.html'); + const response = await appEngine.handle(request); + expect(await response?.text()).toContain('SSG works IT'); + }); + + it('should return null for requests to unknown pages in a locale', async () => { + const request = new Request('https://example.com/it/unknown/page'); + const response = await appEngine.handle(request); + expect(response).toBeNull(); + }); + + it('should return null for requests to file-like resources in a locale', async () => { + const request = new Request('https://example.com/it/logo.png'); + const response = await appEngine.handle(request); + expect(response).toBeNull(); + }); + }); + }); + describe('Non-localized app', () => { beforeAll(() => { @Component({ From 683697ebc5e129d2b17bded9e4ff318d598e0bd3 Mon Sep 17 00:00:00 2001 From: Alan Agius <17563226+alan-agius4@users.noreply.github.com> Date: Tue, 4 Nov 2025 09:56:08 +0000 Subject: [PATCH 14/52] fix(@angular/ssr): improve route matching for wildcard routes Enhance the route traversal logic to correctly identify and process wildcard route matchers (e.g., '**'). This ensures that routes with matchers are properly marked as present in the client router and handled according to their render mode. closes #31666 (cherry picked from commit 4eb22bc2e6bb90aa8d9d617e864e7976da3feb5a) --- packages/angular/ssr/src/routes/ng-routes.ts | 19 ++++++--- .../angular/ssr/test/routes/ng-routes_spec.ts | 39 +++++++++++++++++++ 2 files changed, 52 insertions(+), 6 deletions(-) diff --git a/packages/angular/ssr/src/routes/ng-routes.ts b/packages/angular/ssr/src/routes/ng-routes.ts index a7ca0d137d88..8a91e47c0420 100644 --- a/packages/angular/ssr/src/routes/ng-routes.ts +++ b/packages/angular/ssr/src/routes/ng-routes.ts @@ -256,15 +256,22 @@ async function* traverseRoutesConfig(options: { const currentRoutePath = joinUrlParts(parentRoute, path); if (matcher && serverConfigRouteTree) { - let foundMatch = false; + const matches: (RouteTreeNodeMetadata & ServerConfigRouteTreeAdditionalMetadata)[] = []; for (const matchedMetaData of serverConfigRouteTree.traverse()) { - if (!matchedMetaData.route.startsWith(currentRoutePath)) { - continue; + if (matchedMetaData.route.startsWith(currentRoutePath)) { + matches.push(matchedMetaData); } + } - foundMatch = true; - matchedMetaData.presentInClientRouter = true; + if (!matches.length) { + const matchedMetaData = serverConfigRouteTree.match(currentRoutePath); + if (matchedMetaData) { + matches.push(matchedMetaData); + } + } + for (const matchedMetaData of matches) { + matchedMetaData.presentInClientRouter = true; if (matchedMetaData.renderMode === RenderMode.Prerender) { yield { error: @@ -287,7 +294,7 @@ async function* traverseRoutesConfig(options: { }); } - if (!foundMatch) { + if (!matches.length) { yield { error: `The route '${stripLeadingSlash(currentRoutePath)}' has a defined matcher but does not ` + diff --git a/packages/angular/ssr/test/routes/ng-routes_spec.ts b/packages/angular/ssr/test/routes/ng-routes_spec.ts index d9fae4bcfb41..4c961aac821b 100644 --- a/packages/angular/ssr/test/routes/ng-routes_spec.ts +++ b/packages/angular/ssr/test/routes/ng-routes_spec.ts @@ -429,6 +429,45 @@ describe('extractRoutesAndCreateRouteTree', () => { ]); }); + it('should extract routes with a route level matcher captured by "**"', async () => { + setAngularAppTestingManifest( + [ + { + path: '', + component: DummyComponent, + }, + { + path: 'list', + component: DummyComponent, + }, + { + path: 'product', + component: DummyComponent, + children: [ + { + matcher: () => null, + component: DummyComponent, + }, + ], + }, + ], + [ + { path: 'list', renderMode: RenderMode.Client }, + { path: '', renderMode: RenderMode.Client }, + { path: '**', renderMode: RenderMode.Server }, + ], + ); + + const { routeTree, errors } = await extractRoutesAndCreateRouteTree({ url }); + expect(errors).toHaveSize(0); + expect(routeTree.toObject()).toEqual([ + { route: '/', renderMode: RenderMode.Client }, + { route: '/list', renderMode: RenderMode.Client }, + { route: '/product', renderMode: RenderMode.Server }, + { route: '/**', renderMode: RenderMode.Server }, + ]); + }); + it('should extract nested redirects that are not explicitly defined.', async () => { setAngularAppTestingManifest( [ From bddf211f26d26ccc69b2f1350c367cb55813ac53 Mon Sep 17 00:00:00 2001 From: Alan Agius Date: Tue, 4 Nov 2025 16:31:28 +0100 Subject: [PATCH 15/52] docs: clarify `outputMode` description in application schema Updates the description for the property in the application builder's schema. This change clarifies that both 'static' and 'server' modes generate build artifacts, and specifies that the 'server' mode is required for applications using hybrid rendering or APIs. (cherry picked from commit 1c4af8d3d8806b8374d5035736de41faa5b1a955) --- packages/angular/build/src/builders/application/schema.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/angular/build/src/builders/application/schema.json b/packages/angular/build/src/builders/application/schema.json index c0a0f98313aa..8db4e6145b3f 100644 --- a/packages/angular/build/src/builders/application/schema.json +++ b/packages/angular/build/src/builders/application/schema.json @@ -611,7 +611,7 @@ }, "outputMode": { "type": "string", - "description": "Defines the build output target. 'static': Generates a static site for deployment on any static hosting service. 'server': Produces an application designed for deployment on a server that supports server-side rendering (SSR).", + "description": "Defines the type of build output artifact. 'static': Generates a static site build artifact for deployment on any static hosting service. 'server': Generates a server application build artifact, required for applications using hybrid rendering or APIs.", "enum": ["static", "server"] } }, From 2c0cafa9c51ff82674cffedbd09a273cff34a835 Mon Sep 17 00:00:00 2001 From: Alan Agius <17563226+alan-agius4@users.noreply.github.com> Date: Wed, 5 Nov 2025 14:40:46 +0000 Subject: [PATCH 16/52] release: cut the v20.3.9 release --- CHANGELOG.md | 13 +++++++++++++ package.json | 2 +- 2 files changed, 14 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index a7bbfbaab97f..4c7ac77303ac 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,16 @@ + + +# 20.3.9 (2025-11-05) + +### @angular/ssr + +| Commit | Type | Description | +| --------------------------------------------------------------------------------------------------- | ---- | ------------------------------------------ | +| [08e07e338](https://github.com/angular/angular-cli/commit/08e07e338edd799400e18cd62cd131b6d408f4cf) | fix | improve locale handling in app-engine | +| [683697ebc](https://github.com/angular/angular-cli/commit/683697ebc5e129d2b17bded9e4ff318d598e0bd3) | fix | improve route matching for wildcard routes | + + + # 20.3.8 (2025-10-29) diff --git a/package.json b/package.json index c88f1c2927f7..0d7040ce3ab3 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@angular/devkit-repo", - "version": "20.3.8", + "version": "20.3.9", "private": true, "description": "Software Development Kit for Angular", "keywords": [ From 7c11e0790a307813d70421caca8158e4cbedefc7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?L=C3=AA=20Nam=20Kh=C3=A1nh?= <55955273+khanhkhanhlele@users.noreply.github.com> Date: Fri, 7 Nov 2025 17:51:43 +0700 Subject: [PATCH 17/52] refactor: fix several typos (#31716) This commit fixes a number of typos in tests. (cherry picked from commit a8465d41d35f01349bed7b7c02be03c5dfbf1b34) --- .../application/tests/behavior/component-stylesheets_spec.ts | 2 +- .../application/tests/options/external-dependencies_spec.ts | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/packages/angular/build/src/builders/application/tests/behavior/component-stylesheets_spec.ts b/packages/angular/build/src/builders/application/tests/behavior/component-stylesheets_spec.ts index ecc460bcb405..ddae750a64a4 100644 --- a/packages/angular/build/src/builders/application/tests/behavior/component-stylesheets_spec.ts +++ b/packages/angular/build/src/builders/application/tests/behavior/component-stylesheets_spec.ts @@ -11,7 +11,7 @@ import { APPLICATION_BUILDER_INFO, BASE_OPTIONS, describeBuilder } from '../setu describeBuilder(buildApplication, APPLICATION_BUILDER_INFO, (harness) => { describe('Behavior: "Component Stylesheets"', () => { - it('should successfuly compile with an empty inline style', async () => { + it('should successfully compile with an empty inline style', async () => { await harness.modifyFile('src/app/app.component.ts', (content) => { return content.replace('styleUrls', 'styles').replace('./app.component.css', ''); }); diff --git a/packages/angular/build/src/builders/application/tests/options/external-dependencies_spec.ts b/packages/angular/build/src/builders/application/tests/options/external-dependencies_spec.ts index feb9b6447c3b..deb55e172109 100644 --- a/packages/angular/build/src/builders/application/tests/options/external-dependencies_spec.ts +++ b/packages/angular/build/src/builders/application/tests/options/external-dependencies_spec.ts @@ -24,7 +24,7 @@ describeBuilder(buildApplication, APPLICATION_BUILDER_INFO, (harness) => { .content.not.toMatch(/from ['"]@angular\/common['"]/); }); - it('should only externalize the listed depedencies when option is set', async () => { + it('should only externalize the listed dependencies when option is set', async () => { harness.useTarget('build', { ...BASE_OPTIONS, externalDependencies: ['@angular/core'], @@ -39,7 +39,7 @@ describeBuilder(buildApplication, APPLICATION_BUILDER_INFO, (harness) => { .content.not.toMatch(/from ['"]@angular\/common['"]/); }); - it('should externalize the listed depedencies in Web Workers when option is set', async () => { + it('should externalize the listed dependencies in Web Workers when option is set', async () => { harness.useTarget('build', { ...BASE_OPTIONS, externalDependencies: ['path'], From 6fbd106e5d2c7d0ed71443a9ba1a34828b5b79fd Mon Sep 17 00:00:00 2001 From: Alan Agius <17563226+alan-agius4@users.noreply.github.com> Date: Fri, 7 Nov 2025 17:46:05 +0000 Subject: [PATCH 18/52] build: migrate license file handling to `write_source_file` Migrate the handling of THIRD_PARTY_LICENSES.txt.golden in the SSR npm package from using `bazel_skylib`'s `diff_test` and `write_file` rules to `aspect_bazel_lib`'s `write_source_file` rule. This simplifies the Bazel configuration for managing the golden license file. (cherry picked from commit eca8236ef9188e9437f2b236ecc729db620c9b30) --- .../angular/ssr/test/npm_package/BUILD.bazel | 29 ++++--------------- 1 file changed, 5 insertions(+), 24 deletions(-) diff --git a/packages/angular/ssr/test/npm_package/BUILD.bazel b/packages/angular/ssr/test/npm_package/BUILD.bazel index d79cbf7d0105..ae1694d8caac 100644 --- a/packages/angular/ssr/test/npm_package/BUILD.bazel +++ b/packages/angular/ssr/test/npm_package/BUILD.bazel @@ -1,5 +1,4 @@ -load("@bazel_skylib//rules:diff_test.bzl", "diff_test") -load("@bazel_skylib//rules:write_file.bzl", "write_file") +load("@aspect_bazel_lib//lib:write_source_files.bzl", "write_source_file") load("//tools:defaults.bzl", "jasmine_test", "ts_project") ts_project( @@ -32,26 +31,8 @@ genrule( """, ) -diff_test( - name = "beasties_license_test", - failure_message = """ - - To accept the new golden file, execute: - pnpm bazel run //packages/angular/ssr/test/npm_package:beasties_license_test.accept - """, - file1 = ":THIRD_PARTY_LICENSES.txt.golden", - file2 = ":beasties_license_file", -) - -write_file( - name = "beasties_license_test.accept", - out = "beasties_license_file_accept.sh", - content = - [ - "#!/usr/bin/env bash", - "cd ${BUILD_WORKSPACE_DIRECTORY}", - "pnpm bazel build //packages/angular/ssr:npm_package", - "cp -fv dist/bin/packages/angular/ssr/npm_package/third_party/beasties/THIRD_PARTY_LICENSES.txt packages/angular/ssr/test/npm_package/THIRD_PARTY_LICENSES.txt.golden", - ], - is_executable = True, +write_source_file( + name = "beasties_license", + in_file = ":beasties_license_file", + out_file = ":THIRD_PARTY_LICENSES.txt.golden", ) From b3908f68ed2f05cee56cbf0d9895dcfc3dc0ac25 Mon Sep 17 00:00:00 2001 From: Claudio Roma <36543510+roma-claudio@users.noreply.github.com> Date: Sat, 8 Nov 2025 01:07:52 +0700 Subject: [PATCH 19/52] fix(@angular/build): do not remove `@angular/localize` when having external packages (#31721) The current bundle logic removes the `@angular/localize` polyfill if i18n inline is active. However, i18n inlining is not applied on external packages (e.g. during `ng serve` for prebundled dependencies) This causes an issue at runtime execution of the packages which are external and depend on localization. With this change the `@angular/localize` polyfill is retained when external packages is truthy. (cherry picked from commit 38c22001330eaf2b37b8a0a04fdda50666458664) --- .../build/src/tools/esbuild/application-code-bundle.ts | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/packages/angular/build/src/tools/esbuild/application-code-bundle.ts b/packages/angular/build/src/tools/esbuild/application-code-bundle.ts index 51d3702887f7..635faca8c82e 100644 --- a/packages/angular/build/src/tools/esbuild/application-code-bundle.ts +++ b/packages/angular/build/src/tools/esbuild/application-code-bundle.ts @@ -654,7 +654,7 @@ function getEsBuildCommonPolyfillsOptions( tryToResolvePolyfillsAsRelative: boolean, loadResultCache: LoadResultCache | undefined, ): BuildOptions | undefined { - const { jit, workspaceRoot, i18nOptions } = options; + const { jit, workspaceRoot, i18nOptions, externalPackages } = options; const buildOptions = getEsBuildCommonOptions(options); buildOptions.splitting = false; @@ -671,8 +671,10 @@ function getEsBuildCommonPolyfillsOptions( // Locale data should go first so that project provided polyfill code can augment if needed. let needLocaleDataPlugin = false; if (i18nOptions.shouldInline) { - // Remove localize polyfill as this is not needed for build time i18n. - polyfills = polyfills.filter((path) => !path.startsWith('@angular/localize')); + if (!externalPackages) { + // Remove localize polyfill when i18n inline transformation have been applied to all the packages. + polyfills = polyfills.filter((path) => !path.startsWith('@angular/localize')); + } // Add locale data for all active locales // TODO: Inject each individually within the inlining process itself From c854a719bb3a8d92fe42c8fba4b0b1789081b21c Mon Sep 17 00:00:00 2001 From: Alan Agius Date: Mon, 10 Nov 2025 08:23:39 +0100 Subject: [PATCH 20/52] fix(@schematics/angular): correct `tsconfig.spec.json` include for spec files Updates the files in both application and library schematics to specifically include instead of . This ensures that only test specification files are processed for testing, preventing unintended inclusion of other TypeScript files. (cherry picked from commit 5b0afb324d6fa0acfc4f53394f728f9ffb65dc63) --- .../application/files/common-files/tsconfig.spec.json.template | 3 ++- .../angular/library/files/tsconfig.spec.json.template | 3 ++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/packages/schematics/angular/application/files/common-files/tsconfig.spec.json.template b/packages/schematics/angular/application/files/common-files/tsconfig.spec.json.template index 11ab3b8614ff..6827bd77030c 100644 --- a/packages/schematics/angular/application/files/common-files/tsconfig.spec.json.template +++ b/packages/schematics/angular/application/files/common-files/tsconfig.spec.json.template @@ -9,6 +9,7 @@ ] }, "include": [ - "src/**/*.ts" + "src/**/*.d.ts", + "src/**/*<% if (standalone) { %>.spec<% } %>.ts" ] } diff --git a/packages/schematics/angular/library/files/tsconfig.spec.json.template b/packages/schematics/angular/library/files/tsconfig.spec.json.template index 11ab3b8614ff..6827bd77030c 100644 --- a/packages/schematics/angular/library/files/tsconfig.spec.json.template +++ b/packages/schematics/angular/library/files/tsconfig.spec.json.template @@ -9,6 +9,7 @@ ] }, "include": [ - "src/**/*.ts" + "src/**/*.d.ts", + "src/**/*<% if (standalone) { %>.spec<% } %>.ts" ] } From 904ef7a65ff80ee6b1921b96d11836b51d57c039 Mon Sep 17 00:00:00 2001 From: Jan Martin Date: Wed, 12 Nov 2025 09:56:45 -0800 Subject: [PATCH 21/52] release: cut the v20.3.10 release --- CHANGELOG.md | 18 ++++++++++++++++++ package.json | 2 +- 2 files changed, 19 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 4c7ac77303ac..2a2f81d06ccf 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,21 @@ + + +# 20.3.10 (2025-11-12) + +### @schematics/angular + +| Commit | Type | Description | +| --------------------------------------------------------------------------------------------------- | ---- | --------------------------------------------------- | +| [c854a719b](https://github.com/angular/angular-cli/commit/c854a719bb3a8d92fe42c8fba4b0b1789081b21c) | fix | correct `tsconfig.spec.json` include for spec files | + +### @angular/build + +| Commit | Type | Description | +| --------------------------------------------------------------------------------------------------- | ---- | ----------------------------------------------------------------------------------------------------------------------------- | +| [b3908f68e](https://github.com/angular/angular-cli/commit/b3908f68ed2f05cee56cbf0d9895dcfc3dc0ac25) | fix | do not remove `@angular/localize` when having external packages ([#31721](https://github.com/angular/angular-cli/pull/31721)) | + + + # 20.3.9 (2025-11-05) diff --git a/package.json b/package.json index 0d7040ce3ab3..51da7187e9fa 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@angular/devkit-repo", - "version": "20.3.9", + "version": "20.3.10", "private": true, "description": "Software Development Kit for Angular", "keywords": [ From 8053f2d92a68a8bd01854eb81aa472249f5a83b2 Mon Sep 17 00:00:00 2001 From: Alan Agius <17563226+alan-agius4@users.noreply.github.com> Date: Thu, 13 Nov 2025 19:19:21 +0000 Subject: [PATCH 22/52] =?UTF-8?q?fix(@angular/build):=20ensure=20`=C9=B5ge?= =?UTF-8?q?tOrCreateAngularServerApp`=20is=20always=20defined=20after=20er?= =?UTF-8?q?rors?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Addresses an issue where could become `ɵgetOrCreateAngularServerApp` undefined after an error, leading to subsequent rendering failures. This change modifies the HMR process to include a timestamp when loading. This ensures the server application is always re-evaluated, preventing stale application states. Closes #31671 --- .../angular/build/src/builders/dev-server/vite-server.ts | 9 ++++++--- .../build/src/tools/vite/middlewares/ssr-middleware.ts | 6 ------ 2 files changed, 6 insertions(+), 9 deletions(-) diff --git a/packages/angular/build/src/builders/dev-server/vite-server.ts b/packages/angular/build/src/builders/dev-server/vite-server.ts index 8000af9990ac..7f8665dd8061 100644 --- a/packages/angular/build/src/builders/dev-server/vite-server.ts +++ b/packages/angular/build/src/builders/dev-server/vite-server.ts @@ -598,9 +598,12 @@ async function invalidateUpdatedFiles( } if (serverApplicationChanged) { - // Clear the server app cache and - // trigger module evaluation before reload to initiate dependency optimization. - const { ɵdestroyAngularServerApp } = (await server.ssrLoadModule('/main.server.mjs')) as { + // Clear the server app cache and trigger module evaluation before reload to initiate dependency optimization. + // The querystring is needed as a workaround for: + // `ɵgetOrCreateAngularServerApp` can be undefined right after an error. + const { ɵdestroyAngularServerApp } = (await server.ssrLoadModule( + `/main.server.mjs?timestamp=${Date.now()}`, + )) as { ɵdestroyAngularServerApp: typeof destroyAngularServerApp; }; diff --git a/packages/angular/build/src/tools/vite/middlewares/ssr-middleware.ts b/packages/angular/build/src/tools/vite/middlewares/ssr-middleware.ts index 387a94a2ba53..91fafc2deb17 100644 --- a/packages/angular/build/src/tools/vite/middlewares/ssr-middleware.ts +++ b/packages/angular/build/src/tools/vite/middlewares/ssr-middleware.ts @@ -44,12 +44,6 @@ export function createAngularSsrInternalMiddleware( ɵgetOrCreateAngularServerApp: typeof getOrCreateAngularServerApp; }; - // `ɵgetOrCreateAngularServerApp` can be undefined right after an error. - // See: https://github.com/angular/angular-cli/issues/29907 - if (!ɵgetOrCreateAngularServerApp) { - return next(); - } - const angularServerApp = ɵgetOrCreateAngularServerApp({ allowStaticRouteRender: true, }); From 4dfc31451eaa92b90421d7cfc41620f330c7d2e6 Mon Sep 17 00:00:00 2001 From: Doug Parker Date: Wed, 19 Nov 2025 08:08:02 -0800 Subject: [PATCH 23/52] release: cut the v20.3.11 release --- CHANGELOG.md | 12 ++++++++++++ package.json | 2 +- 2 files changed, 13 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 2a2f81d06ccf..4be84a714b12 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,15 @@ + + +# 20.3.11 (2025-11-19) + +### @angular/build + +| Commit | Type | Description | +| --------------------------------------------------------------------------------------------------- | ---- | -------------------------------------------------------------------- | +| [8053f2d92](https://github.com/angular/angular-cli/commit/8053f2d92a68a8bd01854eb81aa472249f5a83b2) | fix | ensure `ɵgetOrCreateAngularServerApp` is always defined after errors | + + + # 20.3.10 (2025-11-12) diff --git a/package.json b/package.json index 51da7187e9fa..8c277a5e0c02 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@angular/devkit-repo", - "version": "20.3.10", + "version": "20.3.11", "private": true, "description": "Software Development Kit for Angular", "keywords": [ From 1abe68ad87f9b892734117a087b5775068bd232b Mon Sep 17 00:00:00 2001 From: Alan Agius <17563226+alan-agius4@users.noreply.github.com> Date: Thu, 20 Nov 2025 16:55:05 +0000 Subject: [PATCH 24/52] fix(@angular/ssr): prevent redirect loop with encoded query parameters Previously, encoded query parameters caused a mismatch between the requested URL and the reconstructed URL, leading to a redirect loop. This change ensures both URLs are decoded before comparison. Closes #31881 (cherry picked from commit 61a027dba7f3a569c1ac936c34956b8f96fd102a) --- packages/angular/ssr/src/utils/ng.ts | 30 +++++++++++++++++--- packages/angular/ssr/src/utils/url.ts | 15 ++++++++++ packages/angular/ssr/test/app-engine_spec.ts | 14 +++++++++ 3 files changed, 55 insertions(+), 4 deletions(-) diff --git a/packages/angular/ssr/src/utils/ng.ts b/packages/angular/ssr/src/utils/ng.ts index 44f17781be56..f0e200323436 100644 --- a/packages/angular/ssr/src/utils/ng.ts +++ b/packages/angular/ssr/src/utils/ng.ts @@ -107,13 +107,15 @@ export async function renderAngular( if (!routerIsProvided) { hasNavigationError = false; - } else if (lastSuccessfulNavigation) { + } else if (lastSuccessfulNavigation?.finalUrl) { hasNavigationError = false; + const { pathname, search, hash } = envInjector.get(PlatformLocation); - const finalUrl = [stripTrailingSlash(pathname), search, hash].join(''); + const finalUrl = constructDecodedUrl({ pathname, search, hash }); + const urlToRenderString = constructDecodedUrl(urlToRender); - if (urlToRender.href !== new URL(finalUrl, urlToRender.origin).href) { - redirectTo = finalUrl; + if (urlToRenderString !== finalUrl) { + redirectTo = [pathname, search, hash].join(''); } } @@ -171,3 +173,23 @@ function asyncDestroyPlatform(platformRef: PlatformRef): Promise { }, 0); }); } + +/** + * Constructs a decoded URL string from its components, ensuring consistency for comparison. + * + * This function takes a URL-like object (containing `pathname`, `search`, and `hash`), + * strips the trailing slash from the pathname, joins the components, and then decodes + * the entire string. This normalization is crucial for accurately comparing URLs + * that might differ only in encoding or trailing slashes. + * + * @param url - An object containing the URL components: + * - `pathname`: The path of the URL. + * - `search`: The query string of the URL (including '?'). + * - `hash`: The hash fragment of the URL (including '#'). + * @returns The constructed and decoded URL string. + */ +function constructDecodedUrl(url: { pathname: string; search: string; hash: string }): string { + const joinedUrl = [stripTrailingSlash(url.pathname), url.search, url.hash].join(''); + + return decodeURIComponent(joinedUrl); +} diff --git a/packages/angular/ssr/src/utils/url.ts b/packages/angular/ssr/src/utils/url.ts index 9b5edede7f8e..faabf15b1bd4 100644 --- a/packages/angular/ssr/src/utils/url.ts +++ b/packages/angular/ssr/src/utils/url.ts @@ -220,3 +220,18 @@ export function stripMatrixParams(pathname: string): string { // This regex finds all occurrences of a semicolon followed by any characters return pathname.includes(';') ? pathname.replace(MATRIX_PARAMS_REGEX, '') : pathname; } + +/** + * Constructs a decoded URL string from its components. + * + * This function joins the pathname (with trailing slash removed), search, and hash, + * and then decodes the result. + * + * @param pathname - The path of the URL. + * @param search - The query string of the URL (including '?'). + * @param hash - The hash fragment of the URL (including '#'). + * @returns The constructed and decoded URL string. + */ +export function constructUrl(pathname: string, search: string, hash: string): string { + return decodeURIComponent([stripTrailingSlash(pathname), search, hash].join('')); +} diff --git a/packages/angular/ssr/test/app-engine_spec.ts b/packages/angular/ssr/test/app-engine_spec.ts index 76b68f6d4a82..0b970f7a309e 100644 --- a/packages/angular/ssr/test/app-engine_spec.ts +++ b/packages/angular/ssr/test/app-engine_spec.ts @@ -273,5 +273,19 @@ describe('AngularAppEngine', () => { const response = await appEngine.handle(request); expect(await response?.text()).toContain('Home works'); }); + + it('should work with encoded characters', async () => { + const request = new Request('https://example.com/home?email=xyz%40xyz.com'); + const response = await appEngine.handle(request); + expect(response?.status).toBe(200); + expect(await response?.text()).toContain('Home works'); + }); + + it('should work with decoded characters', async () => { + const request = new Request('https://example.com/home?email=xyz@xyz.com'); + const response = await appEngine.handle(request); + expect(response?.status).toBe(200); + expect(await response?.text()).toContain('Home works'); + }); }); }); From 25bb7e65c4fc7e401c658126c53b0b7a13d62965 Mon Sep 17 00:00:00 2001 From: Alan Agius <17563226+alan-agius4@users.noreply.github.com> Date: Thu, 20 Nov 2025 11:14:39 +0000 Subject: [PATCH 25/52] fix(@angular/build): ensure correct URL joining for prerender routes This commit addresses an issue where prerendering with i18n and a `routesFile` could lead to infinite redirect loops or failure to prerender `index.html`. The previous `urlJoin` utility was replaced with more robust URL manipulation functions (`joinUrlParts`, `addTrailingSlash`, `stripLeadingSlash`) to ensure that paths are correctly constructed, especially when dealing with base hrefs and locale subpaths. This ensures that routes from the `routesFile` are correctly joined with the base href, preventing malformed URLs that cause the redirection issues. Closes #31877 (cherry picked from commit 0fe572ed7121953300bec373ac2261c8da6f89a4) --- .../build/src/builders/application/options.ts | 6 +- .../src/utils/server-rendering/prerender.ts | 20 +-- packages/angular/build/src/utils/url.ts | 118 +++++++++++++++++- 3 files changed, 120 insertions(+), 24 deletions(-) diff --git a/packages/angular/build/src/builders/application/options.ts b/packages/angular/build/src/builders/application/options.ts index 1b3a15b8cd56..25bd87253357 100644 --- a/packages/angular/build/src/builders/application/options.ts +++ b/packages/angular/build/src/builders/application/options.ts @@ -25,7 +25,7 @@ import { loadPostcssConfiguration, } from '../../utils/postcss-configuration'; import { getProjectRootPaths, normalizeDirectoryPath } from '../../utils/project-metadata'; -import { urlJoin } from '../../utils/url'; +import { addTrailingSlash, joinUrlParts } from '../../utils/url'; import { Schema as ApplicationBuilderOptions, ExperimentalPlatform, @@ -681,7 +681,9 @@ export function getLocaleBaseHref( const baseHrefSuffix = localeData.baseHref ?? localeData.subPath + '/'; - return baseHrefSuffix !== '' ? urlJoin(baseHref, baseHrefSuffix) : undefined; + return baseHrefSuffix !== '' + ? addTrailingSlash(joinUrlParts(baseHref, baseHrefSuffix)) + : undefined; } /** diff --git a/packages/angular/build/src/utils/server-rendering/prerender.ts b/packages/angular/build/src/utils/server-rendering/prerender.ts index 5ece379ec9c0..f33f851f10c4 100644 --- a/packages/angular/build/src/utils/server-rendering/prerender.ts +++ b/packages/angular/build/src/utils/server-rendering/prerender.ts @@ -14,7 +14,7 @@ import { BuildOutputFile, BuildOutputFileType } from '../../tools/esbuild/bundle import { BuildOutputAsset } from '../../tools/esbuild/bundler-execution-result'; import { assertIsError } from '../error'; import { toPosixPath } from '../path'; -import { urlJoin } from '../url'; +import { addLeadingSlash, addTrailingSlash, joinUrlParts, stripLeadingSlash } from '../url'; import { WorkerPool } from '../worker-pool'; import { IMPORT_EXEC_ARGV } from './esm-in-memory-loader/utils'; import { SERVER_APP_MANIFEST_FILENAME } from './manifest'; @@ -240,7 +240,7 @@ async function renderPages( ? addLeadingSlash(route.slice(baseHrefPathnameWithLeadingSlash.length)) : route; - const outPath = posix.join(removeLeadingSlash(routeWithoutBaseHref), 'index.html'); + const outPath = stripLeadingSlash(posix.join(routeWithoutBaseHref, 'index.html')); if (typeof redirectTo === 'string') { output[outPath] = { content: generateRedirectStaticPage(redirectTo), appShellRoute: false }; @@ -298,7 +298,7 @@ async function getAllRoutes( let appShellRoute: string | undefined; if (appShellOptions) { - appShellRoute = urlJoin(baseHref, appShellOptions.route); + appShellRoute = joinUrlParts(baseHref, appShellOptions.route); routes.push({ renderMode: RouteRenderMode.Prerender, @@ -311,7 +311,7 @@ async function getAllRoutes( for (const route of routesFromFile) { routes.push({ renderMode: RouteRenderMode.Prerender, - route: urlJoin(baseHref, route.trim()), + route: joinUrlParts(baseHref, route.trim()), }); } } @@ -369,15 +369,3 @@ async function getAllRoutes( void renderWorker.destroy(); } } - -function addLeadingSlash(value: string): string { - return value[0] === '/' ? value : '/' + value; -} - -function addTrailingSlash(url: string): string { - return url[url.length - 1] === '/' ? url : `${url}/`; -} - -function removeLeadingSlash(value: string): string { - return value[0] === '/' ? value.slice(1) : value; -} diff --git a/packages/angular/build/src/utils/url.ts b/packages/angular/build/src/utils/url.ts index d3f1e5791276..9edbfb3a3de5 100644 --- a/packages/angular/build/src/utils/url.ts +++ b/packages/angular/build/src/utils/url.ts @@ -6,11 +6,117 @@ * found in the LICENSE file at https://angular.dev/license */ -export function urlJoin(...parts: string[]): string { - const [p, ...rest] = parts; +/** + * Removes the trailing slash from a URL if it exists. + * + * @param url - The URL string from which to remove the trailing slash. + * @returns The URL string without a trailing slash. + * + * @example + * ```js + * stripTrailingSlash('path/'); // 'path' + * stripTrailingSlash('/path'); // '/path' + * stripTrailingSlash('/'); // '/' + * stripTrailingSlash(''); // '' + * ``` + */ +export function stripTrailingSlash(url: string): string { + // Check if the last character of the URL is a slash + return url.length > 1 && url[url.length - 1] === '/' ? url.slice(0, -1) : url; +} + +/** + * Removes the leading slash from a URL if it exists. + * + * @param url - The URL string from which to remove the leading slash. + * @returns The URL string without a leading slash. + * + * @example + * ```js + * stripLeadingSlash('/path'); // 'path' + * stripLeadingSlash('/path/'); // 'path/' + * stripLeadingSlash('/'); // '/' + * stripLeadingSlash(''); // '' + * ``` + */ +export function stripLeadingSlash(url: string): string { + // Check if the first character of the URL is a slash + return url.length > 1 && url[0] === '/' ? url.slice(1) : url; +} + +/** + * Adds a leading slash to a URL if it does not already have one. + * + * @param url - The URL string to which the leading slash will be added. + * @returns The URL string with a leading slash. + * + * @example + * ```js + * addLeadingSlash('path'); // '/path' + * addLeadingSlash('/path'); // '/path' + * ``` + */ +export function addLeadingSlash(url: string): string { + // Check if the URL already starts with a slash + return url[0] === '/' ? url : `/${url}`; +} + +/** + * Adds a trailing slash to a URL if it does not already have one. + * + * @param url - The URL string to which the trailing slash will be added. + * @returns The URL string with a trailing slash. + * + * @example + * ```js + * addTrailingSlash('path'); // 'path/' + * addTrailingSlash('path/'); // 'path/' + * ``` + */ +export function addTrailingSlash(url: string): string { + // Check if the URL already end with a slash + return url[url.length - 1] === '/' ? url : `${url}/`; +} + +/** + * Joins URL parts into a single URL string. + * + * This function takes multiple URL segments, normalizes them by removing leading + * and trailing slashes where appropriate, and then joins them into a single URL. + * + * @param parts - The parts of the URL to join. Each part can be a string with or without slashes. + * @returns The joined URL string, with normalized slashes. + * + * @example + * ```js + * joinUrlParts('path/', '/to/resource'); // '/path/to/resource' + * joinUrlParts('/path/', 'to/resource'); // '/path/to/resource' + * joinUrlParts('http://localhost/path/', 'to/resource'); // 'http://localhost/path/to/resource' + * joinUrlParts('', ''); // '/' + * ``` + */ +export function joinUrlParts(...parts: string[]): string { + const normalizeParts: string[] = []; + for (const part of parts) { + if (part === '') { + // Skip any empty parts + continue; + } + + let normalizedPart = part; + if (part[0] === '/') { + normalizedPart = normalizedPart.slice(1); + } + if (part[part.length - 1] === '/') { + normalizedPart = normalizedPart.slice(0, -1); + } + if (normalizedPart !== '') { + normalizeParts.push(normalizedPart); + } + } + + const protocolMatch = normalizeParts.length && /^https?:\/\//.test(normalizeParts[0]); + const joinedParts = normalizeParts.join('/'); - // Remove trailing slash from first part - // Join all parts with `/` - // Dedupe double slashes from path names - return p.replace(/\/$/, '') + ('/' + rest.join('/')).replace(/\/\/+/g, '/'); + return protocolMatch ? joinedParts : addLeadingSlash(joinedParts); } From cceb862969e541a5f54b689a6439e32773eafe65 Mon Sep 17 00:00:00 2001 From: Alan Agius <17563226+alan-agius4@users.noreply.github.com> Date: Fri, 21 Nov 2025 09:40:33 +0000 Subject: [PATCH 26/52] fix(@angular/ssr): handle `X-Forwarded-Prefix` and `APP_BASE_HREF` in redirects This commit ensures that redirects correctly account for the X-Forwarded-Prefix header and APP_BASE_HREF, preventing incorrect redirect loops or invalid URLs when running behind a proxy or with a base href. Closes #31902 (cherry picked from commit 4dac5f25106162d9cbf20ec2bf4fe02c47409c41) --- packages/angular/ssr/src/app.ts | 9 +++- packages/angular/ssr/src/utils/ng.ts | 32 +++++++++--- packages/angular/ssr/test/app-engine_spec.ts | 14 ----- packages/angular/ssr/test/app_spec.ts | 55 +++++++++++++++++++- 4 files changed, 87 insertions(+), 23 deletions(-) diff --git a/packages/angular/ssr/src/app.ts b/packages/angular/ssr/src/app.ts index 4895866d715b..ee14f8a26105 100644 --- a/packages/angular/ssr/src/app.ts +++ b/packages/angular/ssr/src/app.ts @@ -175,8 +175,15 @@ export class AngularServerApp { } const { redirectTo, status, renderMode } = matchedRoute; + if (redirectTo !== undefined) { - return createRedirectResponse(buildPathWithParams(redirectTo, url.pathname), status); + return createRedirectResponse( + joinUrlParts( + request.headers.get('X-Forwarded-Prefix') ?? '', + buildPathWithParams(redirectTo, url.pathname), + ), + status, + ); } if (renderMode === RenderMode.Prerender) { diff --git a/packages/angular/ssr/src/utils/ng.ts b/packages/angular/ssr/src/utils/ng.ts index f0e200323436..a35beeff835b 100644 --- a/packages/angular/ssr/src/utils/ng.ts +++ b/packages/angular/ssr/src/utils/ng.ts @@ -6,10 +6,11 @@ * found in the LICENSE file at https://angular.dev/license */ -import { PlatformLocation } from '@angular/common'; +import { APP_BASE_HREF, PlatformLocation } from '@angular/common'; import { ApplicationRef, type PlatformRef, + REQUEST, type StaticProvider, type Type, ɵConsole, @@ -23,7 +24,7 @@ import { } from '@angular/platform-server'; import { ActivatedRoute, Router } from '@angular/router'; import { Console } from '../console'; -import { stripIndexHtmlFromURL, stripTrailingSlash } from './url'; +import { addTrailingSlash, joinUrlParts, stripIndexHtmlFromURL, stripTrailingSlash } from './url'; /** * Represents the bootstrap mechanism for an Angular application. @@ -110,9 +111,13 @@ export async function renderAngular( } else if (lastSuccessfulNavigation?.finalUrl) { hasNavigationError = false; + const requestPrefix = + envInjector.get(APP_BASE_HREF, null, { optional: true }) ?? + envInjector.get(REQUEST, null, { optional: true })?.headers.get('X-Forwarded-Prefix'); + const { pathname, search, hash } = envInjector.get(PlatformLocation); - const finalUrl = constructDecodedUrl({ pathname, search, hash }); - const urlToRenderString = constructDecodedUrl(urlToRender); + const finalUrl = constructDecodedUrl({ pathname, search, hash }, requestPrefix); + const urlToRenderString = constructDecodedUrl(urlToRender, requestPrefix); if (urlToRenderString !== finalUrl) { redirectTo = [pathname, search, hash].join(''); @@ -186,10 +191,23 @@ function asyncDestroyPlatform(platformRef: PlatformRef): Promise { * - `pathname`: The path of the URL. * - `search`: The query string of the URL (including '?'). * - `hash`: The hash fragment of the URL (including '#'). + * @param prefix - An optional prefix (e.g., `APP_BASE_HREF`) to prepend to the pathname + * if it is not already present. * @returns The constructed and decoded URL string. */ -function constructDecodedUrl(url: { pathname: string; search: string; hash: string }): string { - const joinedUrl = [stripTrailingSlash(url.pathname), url.search, url.hash].join(''); +function constructDecodedUrl( + url: { pathname: string; search: string; hash: string }, + prefix?: string | null, +): string { + const { pathname, hash, search } = url; + const urlParts: string[] = []; + if (prefix && !addTrailingSlash(pathname).startsWith(addTrailingSlash(prefix))) { + urlParts.push(joinUrlParts(prefix, pathname)); + } else { + urlParts.push(stripTrailingSlash(pathname)); + } + + urlParts.push(search, hash); - return decodeURIComponent(joinedUrl); + return decodeURIComponent(urlParts.join('')); } diff --git a/packages/angular/ssr/test/app-engine_spec.ts b/packages/angular/ssr/test/app-engine_spec.ts index 0b970f7a309e..76b68f6d4a82 100644 --- a/packages/angular/ssr/test/app-engine_spec.ts +++ b/packages/angular/ssr/test/app-engine_spec.ts @@ -273,19 +273,5 @@ describe('AngularAppEngine', () => { const response = await appEngine.handle(request); expect(await response?.text()).toContain('Home works'); }); - - it('should work with encoded characters', async () => { - const request = new Request('https://example.com/home?email=xyz%40xyz.com'); - const response = await appEngine.handle(request); - expect(response?.status).toBe(200); - expect(await response?.text()).toContain('Home works'); - }); - - it('should work with decoded characters', async () => { - const request = new Request('https://example.com/home?email=xyz@xyz.com'); - const response = await appEngine.handle(request); - expect(response?.status).toBe(200); - expect(await response?.text()).toContain('Home works'); - }); }); }); diff --git a/packages/angular/ssr/test/app_spec.ts b/packages/angular/ssr/test/app_spec.ts index b3ea250cae41..edf51e5e65fa 100644 --- a/packages/angular/ssr/test/app_spec.ts +++ b/packages/angular/ssr/test/app_spec.ts @@ -11,7 +11,8 @@ import '@angular/compiler'; /* eslint-enable import/no-unassigned-import */ -import { Component, inject } from '@angular/core'; +import { APP_BASE_HREF } from '@angular/common'; +import { Component, REQUEST, inject } from '@angular/core'; import { CanActivateFn, Router } from '@angular/router'; import { AngularServerApp } from '../src/app'; import { RenderMode } from '../src/routes/route-config'; @@ -125,6 +126,14 @@ describe('AngularServerApp', () => { hash: 'f799132d0a09e0fef93c68a12e443527700eb59e6f67fcb7854c3a60ff082fde', }, }, + undefined, + undefined, + [ + { + provide: APP_BASE_HREF, + useFactory: () => inject(REQUEST)?.headers.get('X-Forwarded-Prefix'), + }, + ], ); app = new AngularServerApp(); @@ -310,6 +319,50 @@ describe('AngularServerApp', () => { expect(response?.headers.get('location')).toBe('/redirect-via-guard?filter=test'); expect(response?.status).toBe(302); }); + + it('should work with encoded characters', async () => { + const request = new Request('http://localhost/home?email=xyz%40xyz.com'); + const response = await app.handle(request); + expect(response?.status).toBe(200); + expect(await response?.text()).toContain('Home works'); + }); + + it('should work with decoded characters', async () => { + const request = new Request('http://localhost/home?email=xyz@xyz.com'); + const response = await app.handle(request); + expect(response?.status).toBe(200); + expect(await response?.text()).toContain('Home works'); + }); + + describe('APP_BASE_HREF / X-Forwarded-Prefix', () => { + const headers = new Headers({ 'X-Forwarded-Prefix': '/base/' }); + + it('should return a rendered page for known paths', async () => { + const request = new Request('https://example.com/home', { headers }); + const response = await app.handle(request); + expect(await response?.text()).toContain('Home works'); + }); + + it('returns a 302 status and redirects to the correct location when `redirectTo` is a function', async () => { + const response = await app.handle( + new Request('http://localhost/redirect-to-function', { + headers, + }), + ); + expect(response?.headers.get('location')).toBe('/base/home'); + expect(response?.status).toBe(302); + }); + + it('returns a 302 status and redirects to the correct location when `redirectTo` is a string', async () => { + const response = await app.handle( + new Request('http://localhost/redirect', { + headers, + }), + ); + expect(response?.headers.get('location')).toBe('/base/home'); + expect(response?.status).toBe(302); + }); + }); }); }); }); From d4ca7b7afa0dca13738cf0c3fbf5be5055fac1b7 Mon Sep 17 00:00:00 2001 From: Alan Agius <17563226+alan-agius4@users.noreply.github.com> Date: Tue, 25 Nov 2025 10:58:28 +0000 Subject: [PATCH 27/52] release: cut the v20.3.12 release --- CHANGELOG.md | 19 +++++++++++++++++++ package.json | 2 +- 2 files changed, 20 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 4be84a714b12..75cf55112e3a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,22 @@ + + +# 20.3.12 (2025-11-25) + +### @angular/build + +| Commit | Type | Description | +| --------------------------------------------------------------------------------------------------- | ---- | ----------------------------------------------- | +| [25bb7e65c](https://github.com/angular/angular-cli/commit/25bb7e65c4fc7e401c658126c53b0b7a13d62965) | fix | ensure correct URL joining for prerender routes | + +### @angular/ssr + +| Commit | Type | Description | +| --------------------------------------------------------------------------------------------------- | ---- | ------------------------------------------------------------ | +| [cceb86296](https://github.com/angular/angular-cli/commit/cceb862969e541a5f54b689a6439e32773eafe65) | fix | handle `X-Forwarded-Prefix` and `APP_BASE_HREF` in redirects | +| [1abe68ad8](https://github.com/angular/angular-cli/commit/1abe68ad87f9b892734117a087b5775068bd232b) | fix | prevent redirect loop with encoded query parameters | + + + # 20.3.11 (2025-11-19) diff --git a/package.json b/package.json index 8c277a5e0c02..a4d839e71740 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@angular/devkit-repo", - "version": "20.3.11", + "version": "20.3.12", "private": true, "description": "Software Development Kit for Angular", "keywords": [ From cfbb61602daf32c5b942ea84702fc3638aa111e7 Mon Sep 17 00:00:00 2001 From: Charles Lyding <19598772+clydin@users.noreply.github.com> Date: Mon, 1 Dec 2025 08:59:18 -0500 Subject: [PATCH 28/52] fix(@angular/cli): update `@modelcontextprotocol/sdk` to v1.24.0 Also updates `zod` to v4.1.13. --- packages/angular/cli/package.json | 4 +- .../src/commands/mcp/tools/tool-registry.ts | 7 +-- pnpm-lock.yaml | 58 +++++++++++++------ 3 files changed, 44 insertions(+), 25 deletions(-) diff --git a/packages/angular/cli/package.json b/packages/angular/cli/package.json index 26e1186925ee..38a2e6e30394 100644 --- a/packages/angular/cli/package.json +++ b/packages/angular/cli/package.json @@ -27,7 +27,7 @@ "@angular-devkit/schematics": "workspace:0.0.0-PLACEHOLDER", "@inquirer/prompts": "7.8.2", "@listr2/prompt-adapter-inquirer": "3.0.1", - "@modelcontextprotocol/sdk": "1.17.3", + "@modelcontextprotocol/sdk": "1.24.0", "@schematics/angular": "workspace:0.0.0-PLACEHOLDER", "@yarnpkg/lockfile": "1.1.0", "algoliasearch": "5.35.0", @@ -39,7 +39,7 @@ "resolve": "1.22.10", "semver": "7.7.2", "yargs": "18.0.0", - "zod": "3.25.76" + "zod": "4.1.13" }, "ng-update": { "migrations": "@schematics/angular/migrations/migration-collection.json", diff --git a/packages/angular/cli/src/commands/mcp/tools/tool-registry.ts b/packages/angular/cli/src/commands/mcp/tools/tool-registry.ts index 340ec3f0c81d..f68db548f662 100644 --- a/packages/angular/cli/src/commands/mcp/tools/tool-registry.ts +++ b/packages/angular/cli/src/commands/mcp/tools/tool-registry.ts @@ -7,11 +7,10 @@ */ import type { McpServer, ToolCallback } from '@modelcontextprotocol/sdk/server/mcp.js'; -import { ZodRawShape } from 'zod'; +import type { ToolAnnotations } from '@modelcontextprotocol/sdk/types'; +import type { ZodRawShape } from 'zod'; import type { AngularWorkspace } from '../../../utilities/config'; -type ToolConfig = Parameters[1]; - export interface McpToolContext { workspace?: AngularWorkspace; logger: { warn(text: string): void }; @@ -26,7 +25,7 @@ export interface McpToolDeclaration; diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 52eca2c2f2ad..927032edd4ae 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -48,7 +48,7 @@ importers: version: 20.2.10(72d1932aa29c0670c8359e3ed8a5ff55) '@angular/ng-dev': specifier: https://github.com/angular/dev-infra-private-ng-dev-builds.git#b69a61793bd6ba935af262297688408d0b48252e - version: https://codeload.github.com/angular/dev-infra-private-ng-dev-builds/tar.gz/b69a61793bd6ba935af262297688408d0b48252e + version: https://codeload.github.com/angular/dev-infra-private-ng-dev-builds/tar.gz/b69a61793bd6ba935af262297688408d0b48252e(@modelcontextprotocol/sdk@1.24.0(zod@4.1.13)) '@angular/platform-browser': specifier: 20.3.7 version: 20.3.7(@angular/animations@20.3.7(@angular/core@20.3.7(@angular/compiler@20.3.7)(rxjs@7.8.2)(zone.js@0.15.1)))(@angular/common@20.3.7(@angular/core@20.3.7(@angular/compiler@20.3.7)(rxjs@7.8.2)(zone.js@0.15.1))(rxjs@7.8.2))(@angular/core@20.3.7(@angular/compiler@20.3.7)(rxjs@7.8.2)(zone.js@0.15.1)) @@ -472,8 +472,8 @@ importers: specifier: 3.0.1 version: 3.0.1(@inquirer/prompts@7.8.2(@types/node@24.9.1))(@types/node@24.9.1)(listr2@9.0.1) '@modelcontextprotocol/sdk': - specifier: 1.17.3 - version: 1.17.3 + specifier: 1.24.0 + version: 1.24.0(zod@4.1.13) '@schematics/angular': specifier: workspace:0.0.0-PLACEHOLDER version: link:../../schematics/angular @@ -508,8 +508,8 @@ importers: specifier: 18.0.0 version: 18.0.0 zod: - specifier: 3.25.76 - version: 3.25.76 + specifier: 4.1.13 + version: 4.1.13 packages/angular/pwa: dependencies: @@ -2541,9 +2541,15 @@ packages: cpu: [x64] os: [win32] - '@modelcontextprotocol/sdk@1.17.3': - resolution: {integrity: sha512-JPwUKWSsbzx+DLFznf/QZ32Qa+ptfbUlHhRLrBQBAFu9iI1iYvizM4p+zhhRDceSsPutXp4z+R/HPVphlIiclg==} + '@modelcontextprotocol/sdk@1.24.0': + resolution: {integrity: sha512-D8h5KXY2vHFW8zTuxn2vuZGN0HGrQ5No6LkHwlEA9trVgNdPL3TF1dSqKA7Dny6BbBYKSW/rOBDXdC8KJAjUCg==} engines: {node: '>=18'} + peerDependencies: + '@cfworker/json-schema': ^4.1.1 + zod: ^3.25 || ^4.0 + peerDependenciesMeta: + '@cfworker/json-schema': + optional: true '@msgpackr-extract/msgpackr-extract-darwin-arm64@3.0.3': resolution: {integrity: sha512-QZHtlVgbAdy2zAqNA9Gu1UpIuI8Xvsd1v8ic6B2pZmeFnFcMWiPLfWXh7TVw4eGEZ/C9TH281KwhVoeQUKbyjw==} @@ -6349,6 +6355,9 @@ packages: resolution: {integrity: sha512-/imKNG4EbWNrVjoNC/1H5/9GFy+tqjGBHCaSsN+P2RnPqjsLmv6UD3Ej+Kj8nBWaRAwyk7kK5ZUc+OEatnTR3A==} hasBin: true + jose@6.1.3: + resolution: {integrity: sha512-0TpaTfihd4QMNwrz/ob2Bp7X04yuxJkjRGi4aKmOqwhov54i6u79oCv7T+C7lo70MKH6BesI3vscD1yb/yzKXQ==} + js-base64@3.7.8: resolution: {integrity: sha512-hNngCeKxIUQiEUN3GPJOkz4wF/YvdUdbNL9hsBcMQTkKzboD7T/q3OYOuuPZLUE6dBxSGpwhk5mwuDud7JVAow==} @@ -9193,14 +9202,17 @@ packages: resolution: {integrity: sha512-U/PBtDf35ff0D8X8D0jfdzHYEPFxAI7jJlxZXwCSez5M3190m+QobIfh+sWDWSHMCWWJN2AWamkegn6vr6YBTw==} engines: {node: '>=18'} - zod-to-json-schema@3.24.6: - resolution: {integrity: sha512-h/z3PKvcTcTetyjl1fkj79MHNEjm+HpD6NXheWjzOekY7kV+lwDYnHw+ivHkijnCSMz1yJaWBD9vu/Fcmk+vEg==} + zod-to-json-schema@3.25.0: + resolution: {integrity: sha512-HvWtU2UG41LALjajJrML6uQejQhNJx+JBO9IflpSja4R03iNWfKXrj6W2h7ljuLyc1nKS+9yDyL/9tD1U/yBnQ==} peerDependencies: - zod: ^3.24.1 + zod: ^3.25 || ^4 zod@3.25.76: resolution: {integrity: sha512-gzUt/qt81nXsFGKIFcC3YnfEAx5NkunCfnDlvuBSSFS02bcXu4Lmea0AFIUwbLWxWPx3d9p8S5QoaujKcNQxcQ==} + zod@4.1.13: + resolution: {integrity: sha512-AvvthqfqrAhNH9dnfmrfKzX5upOdjUVJYFqNSlkmGf64gRaTzlPwz99IHYnVs28qYAybvAlBV+H7pn0saFY4Ig==} + zone.js@0.15.1: resolution: {integrity: sha512-XE96n56IQpJM7NAoXswY3XRLcWFW83xe0BiAOeMD7K5k5xecOeul3Qcpx6GqEeeHNkW5DWL5zOyTbEfB4eti8w==} @@ -9387,11 +9399,11 @@ 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/b69a61793bd6ba935af262297688408d0b48252e': + '@angular/ng-dev@https://codeload.github.com/angular/dev-infra-private-ng-dev-builds/tar.gz/b69a61793bd6ba935af262297688408d0b48252e(@modelcontextprotocol/sdk@1.24.0(zod@4.1.13))': dependencies: '@actions/core': 1.11.1 '@google-cloud/spanner': 8.0.0(supports-color@10.2.2) - '@google/genai': 1.26.0(bufferutil@4.0.9)(supports-color@10.2.2)(utf-8-validate@6.0.5) + '@google/genai': 1.26.0(@modelcontextprotocol/sdk@1.24.0(zod@4.1.13))(bufferutil@4.0.9)(supports-color@10.2.2)(utf-8-validate@6.0.5) '@inquirer/prompts': 7.9.0(@types/node@24.9.1) '@inquirer/type': 3.0.9(@types/node@24.9.1) '@octokit/auth-app': 8.1.1 @@ -10726,10 +10738,12 @@ snapshots: transitivePeerDependencies: - supports-color - '@google/genai@1.26.0(bufferutil@4.0.9)(supports-color@10.2.2)(utf-8-validate@6.0.5)': + '@google/genai@1.26.0(@modelcontextprotocol/sdk@1.24.0(zod@4.1.13))(bufferutil@4.0.9)(supports-color@10.2.2)(utf-8-validate@6.0.5)': dependencies: google-auth-library: 10.4.0(supports-color@10.2.2) ws: 8.18.3(bufferutil@4.0.9)(utf-8-validate@6.0.5) + optionalDependencies: + '@modelcontextprotocol/sdk': 1.24.0(zod@4.1.13) transitivePeerDependencies: - bufferutil - supports-color @@ -11128,9 +11142,10 @@ snapshots: '@lmdb/lmdb-win32-x64@3.4.2': optional: true - '@modelcontextprotocol/sdk@1.17.3': + '@modelcontextprotocol/sdk@1.24.0(zod@4.1.13)': dependencies: - ajv: 6.12.6 + ajv: 8.17.1 + ajv-formats: 3.0.1(ajv@8.17.1) content-type: 1.0.5 cors: 2.8.5 cross-spawn: 7.0.6 @@ -11138,10 +11153,11 @@ snapshots: eventsource-parser: 3.0.6 express: 5.1.0 express-rate-limit: 7.5.1(express@5.1.0) + jose: 6.1.3 pkce-challenge: 5.0.0 raw-body: 3.0.1 - zod: 3.25.76 - zod-to-json-schema: 3.24.6(zod@3.25.76) + zod: 4.1.13 + zod-to-json-schema: 3.25.0(zod@4.1.13) transitivePeerDependencies: - supports-color @@ -15484,6 +15500,8 @@ snapshots: jiti@1.21.7: {} + jose@6.1.3: {} + js-base64@3.7.8: {} js-tokens@4.0.0: {} @@ -18772,10 +18790,12 @@ snapshots: yoctocolors-cjs@2.1.3: {} - zod-to-json-schema@3.24.6(zod@3.25.76): + zod-to-json-schema@3.25.0(zod@4.1.13): dependencies: - zod: 3.25.76 + zod: 4.1.13 zod@3.25.76: {} + zod@4.1.13: {} + zone.js@0.15.1: {} From 948869d2283d88502f7cb12bf3b97af145b701de Mon Sep 17 00:00:00 2001 From: Alan Agius <17563226+alan-agius4@users.noreply.github.com> Date: Wed, 3 Dec 2025 14:01:36 +0000 Subject: [PATCH 29/52] release: cut the v20.3.13 release --- CHANGELOG.md | 12 ++++++++++++ package.json | 2 +- 2 files changed, 13 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 75cf55112e3a..82043c029b3b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,15 @@ + + +# 20.3.13 (2025-12-03) + +### @angular/cli + +| Commit | Type | Description | +| --------------------------------------------------------------------------------------------------- | ---- | --------------------------------------------- | +| [cfbb61602](https://github.com/angular/angular-cli/commit/cfbb61602daf32c5b942ea84702fc3638aa111e7) | fix | update `@modelcontextprotocol/sdk` to v1.24.0 | + + + # 20.3.12 (2025-11-25) diff --git a/package.json b/package.json index a4d839e71740..3a070036b09b 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@angular/devkit-repo", - "version": "20.3.12", + "version": "20.3.13", "private": true, "description": "Software Development Kit for Angular", "keywords": [ From 66140c804093d68db24d9f40cec4c30b2bd01d59 Mon Sep 17 00:00:00 2001 From: Jan Martin Date: Wed, 7 Jan 2026 11:16:41 -0800 Subject: [PATCH 30/52] ci: force ipv4 resolutions first in Node.js Backport of https://github.com/angular/angular-cli/pull/32042 --- packages/angular/build/BUILD.bazel | 4 ++++ packages/angular_devkit/build_angular/BUILD.bazel | 3 +++ packages/angular_devkit/build_webpack/BUILD.bazel | 4 ++++ 3 files changed, 11 insertions(+) diff --git a/packages/angular/build/BUILD.bazel b/packages/angular/build/BUILD.bazel index 8102d101e166..059426ca38d1 100644 --- a/packages/angular/build/BUILD.bazel +++ b/packages/angular/build/BUILD.bazel @@ -300,6 +300,10 @@ jasmine_test( name = "dev-server_integration_tests", size = "medium", data = [":dev-server_integration_test_lib"], + env = { + # Force IPv4 to resolve RBE resolution issues + "NODE_OPTIONS": "--dns-result-order=ipv4first", + }, flaky = True, shard_count = 10, ) diff --git a/packages/angular_devkit/build_angular/BUILD.bazel b/packages/angular_devkit/build_angular/BUILD.bazel index 459197eaf149..f2f5ea56ac77 100644 --- a/packages/angular_devkit/build_angular/BUILD.bazel +++ b/packages/angular_devkit/build_angular/BUILD.bazel @@ -425,6 +425,9 @@ LARGE_SPECS = { "//modules/testing/builder:node_modules/@angular-devkit/build-angular", ], env = { + # Force IPv4 to resolve RBE resolution issues + "NODE_OPTIONS": "--dns-result-order=ipv4first", + # TODO: Replace Puppeteer downloaded browsers with Bazel-managed browsers, # or standardize to avoid complex configuration like this! "PUPPETEER_DOWNLOAD_PATH": "../../../node_modules/puppeteer/downloads", diff --git a/packages/angular_devkit/build_webpack/BUILD.bazel b/packages/angular_devkit/build_webpack/BUILD.bazel index f66ea94f1919..3a104c243a66 100644 --- a/packages/angular_devkit/build_webpack/BUILD.bazel +++ b/packages/angular_devkit/build_webpack/BUILD.bazel @@ -90,6 +90,10 @@ jasmine_test( "//:node_modules/typescript", "//:node_modules/zone.js", ], + env = { + # Force IPv4 to resolve RBE resolution issues + "NODE_OPTIONS": "--dns-result-order=ipv4first", + }, ) genrule( From ff366499eff87e9943e25904fd06d109a0fa0075 Mon Sep 17 00:00:00 2001 From: Jan Martin Date: Wed, 7 Jan 2026 10:14:07 -0800 Subject: [PATCH 31/52] fix(@angular/cli): update dependency @modelcontextprotocol/sdk to v1.25.2 This is a port of PR #32227 to the 20.3.x branch. --- packages/angular/cli/package.json | 2 +- pnpm-lock.yaml | 36 ++++++++++++++++++++++--------- pnpm-workspace.yaml | 1 + 3 files changed, 28 insertions(+), 11 deletions(-) diff --git a/packages/angular/cli/package.json b/packages/angular/cli/package.json index 38a2e6e30394..fc2b2ad08b2c 100644 --- a/packages/angular/cli/package.json +++ b/packages/angular/cli/package.json @@ -27,7 +27,7 @@ "@angular-devkit/schematics": "workspace:0.0.0-PLACEHOLDER", "@inquirer/prompts": "7.8.2", "@listr2/prompt-adapter-inquirer": "3.0.1", - "@modelcontextprotocol/sdk": "1.24.0", + "@modelcontextprotocol/sdk": "1.25.2", "@schematics/angular": "workspace:0.0.0-PLACEHOLDER", "@yarnpkg/lockfile": "1.1.0", "algoliasearch": "5.35.0", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 927032edd4ae..52ad43d56188 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -48,7 +48,7 @@ importers: version: 20.2.10(72d1932aa29c0670c8359e3ed8a5ff55) '@angular/ng-dev': specifier: https://github.com/angular/dev-infra-private-ng-dev-builds.git#b69a61793bd6ba935af262297688408d0b48252e - version: https://codeload.github.com/angular/dev-infra-private-ng-dev-builds/tar.gz/b69a61793bd6ba935af262297688408d0b48252e(@modelcontextprotocol/sdk@1.24.0(zod@4.1.13)) + version: https://codeload.github.com/angular/dev-infra-private-ng-dev-builds/tar.gz/b69a61793bd6ba935af262297688408d0b48252e(@modelcontextprotocol/sdk@1.25.2(zod@4.1.13)) '@angular/platform-browser': specifier: 20.3.7 version: 20.3.7(@angular/animations@20.3.7(@angular/core@20.3.7(@angular/compiler@20.3.7)(rxjs@7.8.2)(zone.js@0.15.1)))(@angular/common@20.3.7(@angular/core@20.3.7(@angular/compiler@20.3.7)(rxjs@7.8.2)(zone.js@0.15.1))(rxjs@7.8.2))(@angular/core@20.3.7(@angular/compiler@20.3.7)(rxjs@7.8.2)(zone.js@0.15.1)) @@ -472,8 +472,8 @@ importers: specifier: 3.0.1 version: 3.0.1(@inquirer/prompts@7.8.2(@types/node@24.9.1))(@types/node@24.9.1)(listr2@9.0.1) '@modelcontextprotocol/sdk': - specifier: 1.24.0 - version: 1.24.0(zod@4.1.13) + specifier: 1.25.2 + version: 1.25.2(zod@4.1.13) '@schematics/angular': specifier: workspace:0.0.0-PLACEHOLDER version: link:../../schematics/angular @@ -2143,6 +2143,12 @@ packages: '@hapi/bourne@3.0.0': resolution: {integrity: sha512-Waj1cwPXJDucOib4a3bAISsKJVb15MKi9IvmTI/7ssVEm6sywXGjVJDhl6/umt1pK1ZS7PacXU3A1PmFKHEZ2w==} + '@hono/node-server@1.19.7': + resolution: {integrity: sha512-vUcD0uauS7EU2caukW8z5lJKtoGMokxNbJtBiwHgpqxEXokaHCBkQUmCHhjFB1VUTWdqj25QoMkMKzgjq+uhrw==} + engines: {node: '>=18.14.1'} + peerDependencies: + hono: ^4 + '@humanfs/core@0.19.1': resolution: {integrity: sha512-5DyQ4+1JEUzejeK1JGICcideyfUbGixgS9jNgex5nqkW+cY7WZhxBigmieN5Qnw9ZosSNVC9KQKyb+GUaGyKUA==} engines: {node: '>=18.18.0'} @@ -2541,8 +2547,8 @@ packages: cpu: [x64] os: [win32] - '@modelcontextprotocol/sdk@1.24.0': - resolution: {integrity: sha512-D8h5KXY2vHFW8zTuxn2vuZGN0HGrQ5No6LkHwlEA9trVgNdPL3TF1dSqKA7Dny6BbBYKSW/rOBDXdC8KJAjUCg==} + '@modelcontextprotocol/sdk@1.25.2': + resolution: {integrity: sha512-LZFeo4F9M5qOhC/Uc1aQSrBHxMrvxett+9KLHt7OhcExtoiRN9DKgbZffMP/nxjutWDQpfMDfP3nkHI4X9ijww==} engines: {node: '>=18'} peerDependencies: '@cfworker/json-schema': ^4.1.1 @@ -6407,6 +6413,9 @@ packages: json-schema-traverse@1.0.0: resolution: {integrity: sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==} + json-schema-typed@8.0.2: + resolution: {integrity: sha512-fQhoXdcvc3V28x7C7BMs4P5+kNlgUURe2jmUT1T//oBRMDrqy1QPelJimwZGo7Hg9VPV3EQV5Bnq4hbFy2vetA==} + json-schema@0.4.0: resolution: {integrity: sha512-es94M3nTIfsEPisRafak+HDLfHXnKBhV3vU5eqPcS3flIWqcxJWgXHXiey3YrpaNsanY5ei1VoYEbOzijuq9BA==} @@ -9399,11 +9408,11 @@ 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/b69a61793bd6ba935af262297688408d0b48252e(@modelcontextprotocol/sdk@1.24.0(zod@4.1.13))': + '@angular/ng-dev@https://codeload.github.com/angular/dev-infra-private-ng-dev-builds/tar.gz/b69a61793bd6ba935af262297688408d0b48252e(@modelcontextprotocol/sdk@1.25.2(zod@4.1.13))': dependencies: '@actions/core': 1.11.1 '@google-cloud/spanner': 8.0.0(supports-color@10.2.2) - '@google/genai': 1.26.0(@modelcontextprotocol/sdk@1.24.0(zod@4.1.13))(bufferutil@4.0.9)(supports-color@10.2.2)(utf-8-validate@6.0.5) + '@google/genai': 1.26.0(@modelcontextprotocol/sdk@1.25.2(zod@4.1.13))(bufferutil@4.0.9)(supports-color@10.2.2)(utf-8-validate@6.0.5) '@inquirer/prompts': 7.9.0(@types/node@24.9.1) '@inquirer/type': 3.0.9(@types/node@24.9.1) '@octokit/auth-app': 8.1.1 @@ -10738,12 +10747,12 @@ snapshots: transitivePeerDependencies: - supports-color - '@google/genai@1.26.0(@modelcontextprotocol/sdk@1.24.0(zod@4.1.13))(bufferutil@4.0.9)(supports-color@10.2.2)(utf-8-validate@6.0.5)': + '@google/genai@1.26.0(@modelcontextprotocol/sdk@1.25.2(zod@4.1.13))(bufferutil@4.0.9)(supports-color@10.2.2)(utf-8-validate@6.0.5)': dependencies: google-auth-library: 10.4.0(supports-color@10.2.2) ws: 8.18.3(bufferutil@4.0.9)(utf-8-validate@6.0.5) optionalDependencies: - '@modelcontextprotocol/sdk': 1.24.0(zod@4.1.13) + '@modelcontextprotocol/sdk': 1.25.2(zod@4.1.13) transitivePeerDependencies: - bufferutil - supports-color @@ -10775,6 +10784,8 @@ snapshots: '@hapi/bourne@3.0.0': {} + '@hono/node-server@1.19.7': {} + '@humanfs/core@0.19.1': {} '@humanfs/node@0.16.7': @@ -11142,8 +11153,9 @@ snapshots: '@lmdb/lmdb-win32-x64@3.4.2': optional: true - '@modelcontextprotocol/sdk@1.24.0(zod@4.1.13)': + '@modelcontextprotocol/sdk@1.25.2(zod@4.1.13)': dependencies: + '@hono/node-server': 1.19.7 ajv: 8.17.1 ajv-formats: 3.0.1(ajv@8.17.1) content-type: 1.0.5 @@ -11154,11 +11166,13 @@ snapshots: express: 5.1.0 express-rate-limit: 7.5.1(express@5.1.0) jose: 6.1.3 + json-schema-typed: 8.0.2 pkce-challenge: 5.0.0 raw-body: 3.0.1 zod: 4.1.13 zod-to-json-schema: 3.25.0(zod@4.1.13) transitivePeerDependencies: + - hono - supports-color '@msgpackr-extract/msgpackr-extract-darwin-arm64@3.0.3': @@ -15557,6 +15571,8 @@ snapshots: json-schema-traverse@1.0.0: {} + json-schema-typed@8.0.2: {} + json-schema@0.4.0: {} json-stable-stringify-without-jsonify@1.0.1: {} diff --git a/pnpm-workspace.yaml b/pnpm-workspace.yaml index d1752e85bda6..554da06f4c78 100644 --- a/pnpm-workspace.yaml +++ b/pnpm-workspace.yaml @@ -23,6 +23,7 @@ minimumReleaseAge: 1440 minimumReleaseAgeExclude: - '@angular-devkit/*' - '@angular/*' + - '@modelcontextprotocol/sdk@1.25.2' # Fix: https://www.cve.org/CVERecord?id=CVE-2026-0621 - '@ngtools/webpack' - '@schematics/*' - 'ng-packagr' From 4963d9c34385251437816a06b7245cc56d19242e Mon Sep 17 00:00:00 2001 From: Jan Martin Date: Wed, 7 Jan 2026 13:09:13 -0800 Subject: [PATCH 32/52] release: cut the v20.3.14 release --- CHANGELOG.md | 12 ++++++++++++ package.json | 2 +- 2 files changed, 13 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 82043c029b3b..55d4a2fc9d24 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,15 @@ + + +# 20.3.14 (2026-01-07) + +### @angular/cli + +| Commit | Type | Description | +| --------------------------------------------------------------------------------------------------- | ---- | ------------------------------------------------------ | +| [ff366499e](https://github.com/angular/angular-cli/commit/ff366499eff87e9943e25904fd06d109a0fa0075) | fix | update dependency @modelcontextprotocol/sdk to v1.25.2 | + + + # 20.3.13 (2025-12-03) diff --git a/package.json b/package.json index 3a070036b09b..76d5deb23264 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@angular/devkit-repo", - "version": "20.3.13", + "version": "20.3.14", "private": true, "description": "Software Development Kit for Angular", "keywords": [ From ffc72cbc52e23cb545476b3fdefc7e5f170eb55d Mon Sep 17 00:00:00 2001 From: Alan Agius <17563226+alan-agius4@users.noreply.github.com> Date: Mon, 12 Jan 2026 09:58:34 +0000 Subject: [PATCH 33/52] fix(@angular-devkit/build-angular): update webpack to version 5.104.1 This fixes a performance regression. See: https://github.com/angular/angular-cli/issues/31350#issuecomment-3731724222 --- .../angular_devkit/build_webpack/index.api.md | 4 +- .../angular_devkit/build_angular/package.json | 2 +- .../angular_devkit/build_webpack/package.json | 2 +- .../src/builders/webpack-dev-server/index.ts | 21 ++- .../src/builders/webpack/index.ts | 6 +- packages/ngtools/webpack/package.json | 2 +- pnpm-lock.yaml | 159 ++++++++++++------ 7 files changed, 126 insertions(+), 70 deletions(-) diff --git a/goldens/public-api/angular_devkit/build_webpack/index.api.md b/goldens/public-api/angular_devkit/build_webpack/index.api.md index db2b47c9ed74..0d60187627d5 100644 --- a/goldens/public-api/angular_devkit/build_webpack/index.api.md +++ b/goldens/public-api/angular_devkit/build_webpack/index.api.md @@ -7,8 +7,8 @@ import { BuilderContext } from '@angular-devkit/architect'; import { BuilderOutput } from '@angular-devkit/architect'; import { Observable } from 'rxjs'; -import webpack from 'webpack'; -import WebpackDevServer from 'webpack-dev-server'; +import type webpack from 'webpack'; +import type WebpackDevServer from 'webpack-dev-server'; // @public (undocumented) export type BuildResult = BuilderOutput & { diff --git a/packages/angular_devkit/build_angular/package.json b/packages/angular_devkit/build_angular/package.json index f37de4ae6ca2..4696765d809c 100644 --- a/packages/angular_devkit/build_angular/package.json +++ b/packages/angular_devkit/build_angular/package.json @@ -55,7 +55,7 @@ "terser": "5.43.1", "tree-kill": "1.2.2", "tslib": "2.8.1", - "webpack": "5.101.2", + "webpack": "5.104.1", "webpack-dev-middleware": "7.4.2", "webpack-dev-server": "5.2.2", "webpack-merge": "6.0.1", diff --git a/packages/angular_devkit/build_webpack/package.json b/packages/angular_devkit/build_webpack/package.json index bc9afa203240..316b68533bf8 100644 --- a/packages/angular_devkit/build_webpack/package.json +++ b/packages/angular_devkit/build_webpack/package.json @@ -22,7 +22,7 @@ "devDependencies": { "@angular-devkit/core": "workspace:0.0.0-PLACEHOLDER", "@ngtools/webpack": "workspace:0.0.0-PLACEHOLDER", - "webpack": "5.101.2", + "webpack": "5.104.1", "webpack-dev-server": "5.2.2" }, "peerDependencies": { diff --git a/packages/angular_devkit/build_webpack/src/builders/webpack-dev-server/index.ts b/packages/angular_devkit/build_webpack/src/builders/webpack-dev-server/index.ts index f078b614796c..66a2f09a6422 100644 --- a/packages/angular_devkit/build_webpack/src/builders/webpack-dev-server/index.ts +++ b/packages/angular_devkit/build_webpack/src/builders/webpack-dev-server/index.ts @@ -10,8 +10,8 @@ import { Builder, BuilderContext, createBuilder } from '@angular-devkit/architec import assert from 'node:assert'; import { resolve as pathResolve } from 'node:path'; import { Observable, from, isObservable, of, switchMap } from 'rxjs'; -import webpack from 'webpack'; -import WebpackDevServer from 'webpack-dev-server'; +import type webpack from 'webpack'; +import type WebpackDevServer from 'webpack-dev-server'; import { getEmittedFiles, getWebpackConfig } from '../../utils'; import { BuildResult, WebpackFactory, WebpackLoggingCallback } from '../webpack'; import { Schema as WebpackDevServerBuilderSchema } from './schema'; @@ -44,7 +44,7 @@ export function runWebpackDevServer( return of(result); } } else { - return of(webpack(c)); + return from(import('webpack').then((mod) => mod.default(c))); } }; @@ -54,9 +54,9 @@ export function runWebpackDevServer( ) => { if (options.webpackDevServerFactory) { return new options.webpackDevServerFactory(config, webpack); + } else { + return from(import('webpack-dev-server').then((mod) => new mod.default(config, webpack))); } - - return new WebpackDevServer(config, webpack); }; const { @@ -70,8 +70,14 @@ export function runWebpackDevServer( } = options; return createWebpack({ ...config, watch: false }).pipe( + switchMap(async (webpackCompiler) => { + return [ + webpackCompiler, + options.webpackDevServerFactory ?? (await import('webpack-dev-server')).default, + ] as unknown as [webpack.Compiler | null, WebpackDevServerFactory]; + }), switchMap( - (webpackCompiler) => + ([webpackCompiler, webpackDevServerFactory]) => new Observable((obs) => { assert(webpackCompiler, 'Webpack compiler factory did not return a compiler instance.'); @@ -79,7 +85,6 @@ export function runWebpackDevServer( devServerConfig.host ??= 'localhost'; let result: Partial; - const statsOptions = typeof config.stats === 'boolean' ? undefined : config.stats; webpackCompiler.hooks.done.tap('build-webpack', (stats) => { @@ -94,7 +99,7 @@ export function runWebpackDevServer( } as unknown as DevServerBuildOutput); }); - const devServer = createWebpackDevServer(webpackCompiler, devServerConfig); + const devServer = new webpackDevServerFactory(devServerConfig, webpackCompiler); devServer.startCallback((err) => { if (err) { obs.error(err); diff --git a/packages/angular_devkit/build_webpack/src/builders/webpack/index.ts b/packages/angular_devkit/build_webpack/src/builders/webpack/index.ts index b6be070a9f92..ce3f91fd69d4 100644 --- a/packages/angular_devkit/build_webpack/src/builders/webpack/index.ts +++ b/packages/angular_devkit/build_webpack/src/builders/webpack/index.ts @@ -10,7 +10,7 @@ import { Builder, BuilderContext, BuilderOutput, createBuilder } from '@angular- import assert from 'node:assert'; import { resolve as pathResolve } from 'node:path'; import { Observable, from, isObservable, of, switchMap } from 'rxjs'; -import webpack from 'webpack'; +import type webpack from 'webpack'; import { EmittedFiles, getEmittedFiles, getWebpackConfig } from '../../utils'; import { Schema as RealWebpackBuilderSchema } from './schema'; @@ -57,7 +57,7 @@ export function runWebpack( return of(result); } } else { - return of(webpack(c)); + return from(import('webpack').then((mod) => mod.default(c))); } }; @@ -104,7 +104,7 @@ export function runWebpack( // Teardown logic. Close the watcher when unsubscribed from. return () => { - watching.close(() => {}); + watching?.close(() => {}); webpackCompiler.close(() => {}); }; } else { diff --git a/packages/ngtools/webpack/package.json b/packages/ngtools/webpack/package.json index 83bbdfd6a3b9..9a127f0bf8ea 100644 --- a/packages/ngtools/webpack/package.json +++ b/packages/ngtools/webpack/package.json @@ -30,6 +30,6 @@ "@angular/compiler": "20.3.7", "@angular/compiler-cli": "20.3.7", "typescript": "5.9.2", - "webpack": "5.101.2" + "webpack": "5.104.1" } } diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 52ad43d56188..7f8149340d7e 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -643,16 +643,16 @@ importers: version: 10.4.21(postcss@8.5.6) babel-loader: specifier: 10.0.0 - version: 10.0.0(@babel/core@7.28.3)(webpack@5.101.2(esbuild@0.25.9)) + version: 10.0.0(@babel/core@7.28.3)(webpack@5.104.1(esbuild@0.25.9)) browserslist: specifier: ^4.21.5 version: 4.26.3 copy-webpack-plugin: specifier: 13.0.1 - version: 13.0.1(webpack@5.101.2(esbuild@0.25.9)) + version: 13.0.1(webpack@5.104.1(esbuild@0.25.9)) css-loader: specifier: 7.1.2 - version: 7.1.2(webpack@5.101.2(esbuild@0.25.9)) + version: 7.1.2(webpack@5.104.1(esbuild@0.25.9)) esbuild-wasm: specifier: 0.25.9 version: 0.25.9 @@ -676,16 +676,16 @@ importers: version: 4.4.0 less-loader: specifier: 12.3.0 - version: 12.3.0(less@4.4.0)(webpack@5.101.2(esbuild@0.25.9)) + version: 12.3.0(less@4.4.0)(webpack@5.104.1(esbuild@0.25.9)) license-webpack-plugin: specifier: 4.0.2 - version: 4.0.2(webpack@5.101.2(esbuild@0.25.9)) + version: 4.0.2(webpack@5.104.1(esbuild@0.25.9)) loader-utils: specifier: 3.3.1 version: 3.3.1 mini-css-extract-plugin: specifier: 2.9.4 - version: 2.9.4(webpack@5.101.2(esbuild@0.25.9)) + version: 2.9.4(webpack@5.104.1(esbuild@0.25.9)) open: specifier: 10.2.0 version: 10.2.0 @@ -703,7 +703,7 @@ importers: version: 8.5.6 postcss-loader: specifier: 8.1.1 - version: 8.1.1(postcss@8.5.6)(typescript@5.9.2)(webpack@5.101.2(esbuild@0.25.9)) + version: 8.1.1(postcss@8.5.6)(typescript@5.9.2)(webpack@5.104.1(esbuild@0.25.9)) resolve-url-loader: specifier: 5.0.0 version: 5.0.0 @@ -715,13 +715,13 @@ importers: version: 1.90.0 sass-loader: specifier: 16.0.5 - version: 16.0.5(sass@1.90.0)(webpack@5.101.2(esbuild@0.25.9)) + version: 16.0.5(sass@1.90.0)(webpack@5.104.1(esbuild@0.25.9)) semver: specifier: 7.7.2 version: 7.7.2 source-map-loader: specifier: 5.0.0 - version: 5.0.0(webpack@5.101.2(esbuild@0.25.9)) + version: 5.0.0(webpack@5.104.1(esbuild@0.25.9)) source-map-support: specifier: 0.5.21 version: 0.5.21 @@ -735,20 +735,20 @@ importers: specifier: 2.8.1 version: 2.8.1 webpack: - specifier: 5.101.2 - version: 5.101.2(esbuild@0.25.9) + specifier: 5.104.1 + version: 5.104.1(esbuild@0.25.9) webpack-dev-middleware: specifier: 7.4.2 - version: 7.4.2(webpack@5.101.2(esbuild@0.25.9)) + version: 7.4.2(webpack@5.104.1(esbuild@0.25.9)) webpack-dev-server: specifier: 5.2.2 - version: 5.2.2(bufferutil@4.0.9)(utf-8-validate@6.0.5)(webpack@5.101.2(esbuild@0.25.9)) + version: 5.2.2(bufferutil@4.0.9)(utf-8-validate@6.0.5)(webpack@5.104.1(esbuild@0.25.9)) webpack-merge: specifier: 6.0.1 version: 6.0.1 webpack-subresource-integrity: specifier: 5.1.0 - version: 5.1.0(webpack@5.101.2(esbuild@0.25.9)) + version: 5.1.0(webpack@5.104.1(esbuild@0.25.9)) devDependencies: '@angular/ssr': specifier: workspace:* @@ -786,11 +786,11 @@ importers: specifier: workspace:0.0.0-PLACEHOLDER version: link:../../ngtools/webpack webpack: - specifier: 5.101.2 - version: 5.101.2(esbuild@0.25.9) + specifier: 5.104.1 + version: 5.104.1(esbuild@0.25.9) webpack-dev-server: specifier: 5.2.2 - version: 5.2.2(bufferutil@4.0.9)(utf-8-validate@6.0.5)(webpack@5.101.2(esbuild@0.25.9)) + version: 5.2.2(bufferutil@4.0.9)(utf-8-validate@6.0.5)(webpack@5.104.1(esbuild@0.25.9)) packages/angular_devkit/core: dependencies: @@ -868,8 +868,8 @@ importers: specifier: 5.9.2 version: 5.9.2 webpack: - specifier: 5.101.2 - version: 5.101.2(esbuild@0.25.9) + specifier: 5.104.1 + version: 5.104.1(esbuild@0.25.9) packages/schematics/angular: dependencies: @@ -4300,6 +4300,10 @@ packages: resolution: {integrity: sha512-OMu3BGQ4E7P1ErFsIPpbJh0qvDudM/UuJeHgkAvfWe+0HFJCXh+t/l8L6fVLR55RI/UbKrVLnAXZSVwd9ysWYw==} hasBin: true + baseline-browser-mapping@2.9.14: + resolution: {integrity: sha512-B0xUquLkiGLgHhpPBqvl7GWegWBUNuujQ6kXd/r1U38ElPT6Ok8KZ8e+FpUGEc2ZoRQUzq/aUnaKFc/svWUGSg==} + hasBin: true + basic-ftp@5.0.5: resolution: {integrity: sha512-4Bcg1P8xhUuqcii/S0Z9wiHIrQVPMermM1any+MX5GeGD7faD3/msQUDGLol9wOcz4/jbg/WJnGqoJF6LiBdtg==} engines: {node: '>=10.0.0'} @@ -4388,6 +4392,11 @@ packages: engines: {node: ^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7} hasBin: true + browserslist@4.28.1: + resolution: {integrity: sha512-ZC5Bd0LgJXgwGqUknZY/vkUQ04r8NXnJZ3yYi4vDmSiZmC/pdSN0NbNRPxZpbtO4uAfDUAFffO8IZoM3Gj8IkA==} + engines: {node: ^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7} + hasBin: true + browserstack@1.6.1: resolution: {integrity: sha512-GxtFjpIaKdbAyzHfFDKixKO8IBT7wR3NjbzrGc78nNs/Ciys9wU3/nBtsqsWv5nDSrdI5tz0peKuzCPuNXNUiw==} @@ -4460,6 +4469,9 @@ packages: caniuse-lite@1.0.30001750: resolution: {integrity: sha512-cuom0g5sdX6rw00qOoLNSFCJ9/mYIsuSOA+yzpDw8eopiFqcVwQvZHqov0vmEighRxX++cfC0Vg1G+1Iy/mSpQ==} + caniuse-lite@1.0.30001764: + resolution: {integrity: sha512-9JGuzl2M+vPL+pz70gtMF9sHdMFbY9FJaQBi186cHKH3pSzDvzoUJUPV6fqiKIMyXbud9ZLg4F3Yza1vJ1+93g==} + caseless@0.12.0: resolution: {integrity: sha512-4tYFyifaFfGacoiObjJegolkwSU4xQNGbVgUiNYVUxbQ2x2lUsFvY4hVgVzGiIe6WLOPqycWXA40l+PWsxthUw==} @@ -5063,6 +5075,9 @@ packages: electron-to-chromium@1.5.234: resolution: {integrity: sha512-RXfEp2x+VRYn8jbKfQlRImzoJU01kyDvVPBmG39eU2iuRVhuS6vQNocB8J0/8GrIMLnPzgz4eW6WiRnJkTuNWg==} + electron-to-chromium@1.5.267: + resolution: {integrity: sha512-0Drusm6MVRXSOJpGbaSVgcQsuB4hEkMpHXaVstcPmhu5LIedxs1xNK/nIxmQIU/RPC0+1/o0AVZfBTkTNJOdUw==} + emoji-regex@10.5.0: resolution: {integrity: sha512-lb49vf1Xzfx080OKA0o6l8DQQpV+6Vg95zyCJX9VB/BqKYlhG7N4wgROUUHRA+ZPUefLnteQOad7z1kT2bV7bg==} @@ -5158,6 +5173,9 @@ packages: es-module-lexer@1.7.0: resolution: {integrity: sha512-jEQoCwk8hyb2AZziIOLhDqpm5+2ww5uIE6lkO/6jcOCusfk6LhMHpXXfBLXTZ7Ydyt0j4VoUQv6uGNYbdW+kBA==} + es-module-lexer@2.0.0: + resolution: {integrity: sha512-5POEcUuZybH7IdmGsD8wlf0AI55wMecM9rVBTI/qEAy2c1kTOm3DjFYjrBdI2K3BaJjJYfYFeRtM0t9ssnRuxw==} + es-object-atoms@1.1.1: resolution: {integrity: sha512-FGgH2h8zKNim9ljj7dankFPcICIK9Cp5bm+c2gQSYePhpaG5+esrLODihIorn+Pe6FGJzWhXQotPv73jTaldXA==} engines: {node: '>= 0.4'} @@ -7028,6 +7046,9 @@ packages: node-releases@2.0.23: resolution: {integrity: sha512-cCmFDMSm26S6tQSDpBCg/NR8NENrVPhAJSf+XbxBG4rPFaaonlEoE9wHQmun+cls499TQGSb7ZyPBRlzgKfpeg==} + node-releases@2.0.27: + resolution: {integrity: sha512-nmh3lCkYZ3grZvqcCH+fjmQ7X+H0OeZgP40OierEaAptX4XofMh5kwNbWh7lBduUzCcV/8kZ+NDLCwm2iorIlA==} + nopt@8.1.0: resolution: {integrity: sha512-ieGu42u/Qsa4TFktmaKEwM6MQH0pOWnaB3htzh0JRtx84+Mebc0cbZYN5bC+6WTZ4+77xrL9Pn5m7CV6VIkV7A==} engines: {node: ^18.17.0 || >=20.5.0} @@ -8367,8 +8388,8 @@ packages: resolution: {integrity: sha512-3ZnLvgWF29jikg1sAQ1g0o+lr5JX6sVgYvfUJazn7ZjJroDBUTWp44/+cFVX0bULjv4vci+rBD+oGVAkWqhUbw==} engines: {node: '>=18'} - terser-webpack-plugin@5.3.14: - resolution: {integrity: sha512-vkZjpUjb6OMS7dhV+tILUW6BhpDR7P2L/aQSAv+Uwk+m8KATX9EccViHTJR2qDtACKPIYndLGCyl3FMo+r2LMw==} + terser-webpack-plugin@5.3.16: + resolution: {integrity: sha512-h9oBFCWrq78NyWWVcSwZarJkZ01c2AyGrzs1crmHZO3QUg9D61Wu4NPjBy69n7JqylFF5y+CsUZYmYEIZ3mR+Q==} engines: {node: '>= 10.13.0'} peerDependencies: '@swc/core': '*' @@ -8689,6 +8710,12 @@ packages: peerDependencies: browserslist: '>= 4.21.0' + update-browserslist-db@1.2.3: + resolution: {integrity: sha512-Js0m9cx+qOgDxo0eMiFGEueWztz+d4+M3rGlmKPT+T4IS/jP4ylw3Nwpu6cpTTP8R1MAC1kF4VbdLt3ARf209w==} + hasBin: true + peerDependencies: + browserslist: '>= 4.21.0' + uri-js@4.4.1: resolution: {integrity: sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==} @@ -8955,8 +8982,8 @@ packages: html-webpack-plugin: optional: true - webpack@5.101.2: - resolution: {integrity: sha512-4JLXU0tD6OZNVqlwzm3HGEhAHufSiyv+skb7q0d2367VDMzrU1Q/ZeepvkcHH0rZie6uqEtTQQe0OEOOluH3Mg==} + webpack@5.104.1: + resolution: {integrity: sha512-Qphch25abbMNtekmEGJmeRUhLDbe+QfiWTiqpKYkpCOWY64v9eyl+KRRLmqOFA2AvKPpc9DC6+u2n76tQLBoaA==} engines: {node: '>=10.13.0'} hasBin: true peerDependencies: @@ -13047,11 +13074,11 @@ snapshots: b4a@1.7.3: {} - babel-loader@10.0.0(@babel/core@7.28.3)(webpack@5.101.2(esbuild@0.25.9)): + babel-loader@10.0.0(@babel/core@7.28.3)(webpack@5.104.1(esbuild@0.25.9)): dependencies: '@babel/core': 7.28.3 find-up: 5.0.0 - webpack: 5.101.2(esbuild@0.25.9) + webpack: 5.104.1(esbuild@0.25.9) babel-plugin-polyfill-corejs2@0.4.14(@babel/core@7.28.3): dependencies: @@ -13124,6 +13151,8 @@ snapshots: baseline-browser-mapping@2.8.16: {} + baseline-browser-mapping@2.9.14: {} + basic-ftp@5.0.5: {} batch@0.6.1: {} @@ -13286,6 +13315,14 @@ snapshots: node-releases: 2.0.23 update-browserslist-db: 1.1.3(browserslist@4.26.3) + browserslist@4.28.1: + dependencies: + baseline-browser-mapping: 2.9.14 + caniuse-lite: 1.0.30001764 + electron-to-chromium: 1.5.267 + node-releases: 2.0.27 + update-browserslist-db: 1.2.3(browserslist@4.28.1) + browserstack@1.6.1: dependencies: https-proxy-agent: 2.2.4 @@ -13367,6 +13404,8 @@ snapshots: caniuse-lite@1.0.30001750: {} + caniuse-lite@1.0.30001764: {} + caseless@0.12.0: {} chai@5.3.3: @@ -13631,14 +13670,14 @@ snapshots: dependencies: is-what: 3.14.1 - copy-webpack-plugin@13.0.1(webpack@5.101.2(esbuild@0.25.9)): + copy-webpack-plugin@13.0.1(webpack@5.104.1(esbuild@0.25.9)): dependencies: glob-parent: 6.0.2 normalize-path: 3.0.0 schema-utils: 4.3.3 serialize-javascript: 6.0.2 tinyglobby: 0.2.14 - webpack: 5.101.2(esbuild@0.25.9) + webpack: 5.104.1(esbuild@0.25.9) core-js-compat@3.46.0: dependencies: @@ -13682,7 +13721,7 @@ snapshots: shebang-command: 2.0.0 which: 2.0.2 - css-loader@7.1.2(webpack@5.101.2(esbuild@0.25.9)): + css-loader@7.1.2(webpack@5.104.1(esbuild@0.25.9)): dependencies: icss-utils: 5.1.0(postcss@8.5.6) postcss: 8.5.6 @@ -13693,7 +13732,7 @@ snapshots: postcss-value-parser: 4.2.0 semver: 7.7.2 optionalDependencies: - webpack: 5.101.2(esbuild@0.25.9) + webpack: 5.104.1(esbuild@0.25.9) css-select@6.0.0: dependencies: @@ -13958,6 +13997,8 @@ snapshots: electron-to-chromium@1.5.234: {} + electron-to-chromium@1.5.267: {} + emoji-regex@10.5.0: {} emoji-regex@8.0.0: {} @@ -14106,6 +14147,8 @@ snapshots: es-module-lexer@1.7.0: {} + es-module-lexer@2.0.0: {} + es-object-atoms@1.1.1: dependencies: es-errors: 1.3.0 @@ -15784,11 +15827,11 @@ snapshots: picocolors: 1.1.1 shell-quote: 1.8.3 - less-loader@12.3.0(less@4.4.0)(webpack@5.101.2(esbuild@0.25.9)): + less-loader@12.3.0(less@4.4.0)(webpack@5.104.1(esbuild@0.25.9)): dependencies: less: 4.4.0 optionalDependencies: - webpack: 5.101.2(esbuild@0.25.9) + webpack: 5.104.1(esbuild@0.25.9) less@4.4.0: dependencies: @@ -15809,11 +15852,11 @@ snapshots: prelude-ls: 1.2.1 type-check: 0.4.0 - license-webpack-plugin@4.0.2(webpack@5.101.2(esbuild@0.25.9)): + license-webpack-plugin@4.0.2(webpack@5.104.1(esbuild@0.25.9)): dependencies: webpack-sources: 3.3.3 optionalDependencies: - webpack: 5.101.2(esbuild@0.25.9) + webpack: 5.104.1(esbuild@0.25.9) lie@3.3.0: dependencies: @@ -16046,11 +16089,11 @@ snapshots: mimic-function@5.0.1: {} - mini-css-extract-plugin@2.9.4(webpack@5.101.2(esbuild@0.25.9)): + mini-css-extract-plugin@2.9.4(webpack@5.104.1(esbuild@0.25.9)): dependencies: schema-utils: 4.3.3 tapable: 2.3.0 - webpack: 5.101.2(esbuild@0.25.9) + webpack: 5.104.1(esbuild@0.25.9) minimalistic-assert@1.0.1: {} @@ -16282,6 +16325,8 @@ snapshots: node-releases@2.0.23: {} + node-releases@2.0.27: {} + nopt@8.1.0: dependencies: abbrev: 3.0.1 @@ -16705,14 +16750,14 @@ snapshots: possible-typed-array-names@1.1.0: {} - postcss-loader@8.1.1(postcss@8.5.6)(typescript@5.9.2)(webpack@5.101.2(esbuild@0.25.9)): + postcss-loader@8.1.1(postcss@8.5.6)(typescript@5.9.2)(webpack@5.104.1(esbuild@0.25.9)): dependencies: cosmiconfig: 9.0.0(typescript@5.9.2) jiti: 1.21.7 postcss: 8.5.6 semver: 7.7.2 optionalDependencies: - webpack: 5.101.2(esbuild@0.25.9) + webpack: 5.104.1(esbuild@0.25.9) transitivePeerDependencies: - typescript @@ -17278,12 +17323,12 @@ snapshots: safer-buffer@2.1.2: {} - sass-loader@16.0.5(sass@1.90.0)(webpack@5.101.2(esbuild@0.25.9)): + sass-loader@16.0.5(sass@1.90.0)(webpack@5.104.1(esbuild@0.25.9)): dependencies: neo-async: 2.6.2 optionalDependencies: sass: 1.90.0 - webpack: 5.101.2(esbuild@0.25.9) + webpack: 5.104.1(esbuild@0.25.9) sass@1.90.0: dependencies: @@ -17604,11 +17649,11 @@ snapshots: source-map-js@1.2.1: {} - source-map-loader@5.0.0(webpack@5.101.2(esbuild@0.25.9)): + source-map-loader@5.0.0(webpack@5.104.1(esbuild@0.25.9)): dependencies: iconv-lite: 0.6.3 source-map-js: 1.2.1 - webpack: 5.101.2(esbuild@0.25.9) + webpack: 5.104.1(esbuild@0.25.9) source-map-support@0.4.18: dependencies: @@ -17908,14 +17953,14 @@ snapshots: transitivePeerDependencies: - supports-color - terser-webpack-plugin@5.3.14(esbuild@0.25.9)(webpack@5.101.2(esbuild@0.25.9)): + terser-webpack-plugin@5.3.16(esbuild@0.25.9)(webpack@5.104.1(esbuild@0.25.9)): dependencies: '@jridgewell/trace-mapping': 0.3.31 jest-worker: 27.5.1 schema-utils: 4.3.3 serialize-javascript: 6.0.2 terser: 5.43.1 - webpack: 5.101.2(esbuild@0.25.9) + webpack: 5.104.1(esbuild@0.25.9) optionalDependencies: esbuild: 0.25.9 @@ -18218,6 +18263,12 @@ snapshots: escalade: 3.2.0 picocolors: 1.1.1 + update-browserslist-db@1.2.3(browserslist@4.28.1): + dependencies: + browserslist: 4.28.1 + escalade: 3.2.0 + picocolors: 1.1.1 + uri-js@4.4.1: dependencies: punycode: 2.3.1 @@ -18477,7 +18528,7 @@ snapshots: webidl-conversions@7.0.0: {} - webpack-dev-middleware@7.4.2(webpack@5.101.2(esbuild@0.25.9)): + webpack-dev-middleware@7.4.2(webpack@5.104.1(esbuild@0.25.9)): dependencies: colorette: 2.0.20 memfs: 4.49.0 @@ -18486,9 +18537,9 @@ snapshots: range-parser: 1.2.1 schema-utils: 4.3.3 optionalDependencies: - webpack: 5.101.2(esbuild@0.25.9) + webpack: 5.104.1(esbuild@0.25.9) - webpack-dev-server@5.2.2(bufferutil@4.0.9)(utf-8-validate@6.0.5)(webpack@5.101.2(esbuild@0.25.9)): + webpack-dev-server@5.2.2(bufferutil@4.0.9)(utf-8-validate@6.0.5)(webpack@5.104.1(esbuild@0.25.9)): dependencies: '@types/bonjour': 3.5.13 '@types/connect-history-api-fallback': 1.5.4 @@ -18516,10 +18567,10 @@ snapshots: serve-index: 1.9.1 sockjs: 0.3.24 spdy: 4.0.2 - webpack-dev-middleware: 7.4.2(webpack@5.101.2(esbuild@0.25.9)) + webpack-dev-middleware: 7.4.2(webpack@5.104.1(esbuild@0.25.9)) ws: 8.18.3(bufferutil@4.0.9)(utf-8-validate@6.0.5) optionalDependencies: - webpack: 5.101.2(esbuild@0.25.9) + webpack: 5.104.1(esbuild@0.25.9) transitivePeerDependencies: - bufferutil - debug @@ -18534,12 +18585,12 @@ snapshots: webpack-sources@3.3.3: {} - webpack-subresource-integrity@5.1.0(webpack@5.101.2(esbuild@0.25.9)): + webpack-subresource-integrity@5.1.0(webpack@5.104.1(esbuild@0.25.9)): dependencies: typed-assert: 1.0.9 - webpack: 5.101.2(esbuild@0.25.9) + webpack: 5.104.1(esbuild@0.25.9) - webpack@5.101.2(esbuild@0.25.9): + webpack@5.104.1(esbuild@0.25.9): dependencies: '@types/eslint-scope': 3.7.7 '@types/estree': 1.0.8 @@ -18549,10 +18600,10 @@ snapshots: '@webassemblyjs/wasm-parser': 1.14.1 acorn: 8.15.0 acorn-import-phases: 1.0.4(acorn@8.15.0) - browserslist: 4.26.3 + browserslist: 4.28.1 chrome-trace-event: 1.0.4 enhanced-resolve: 5.18.3 - es-module-lexer: 1.7.0 + es-module-lexer: 2.0.0 eslint-scope: 5.1.1 events: 3.3.0 glob-to-regexp: 0.4.1 @@ -18563,7 +18614,7 @@ snapshots: neo-async: 2.6.2 schema-utils: 4.3.3 tapable: 2.3.0 - terser-webpack-plugin: 5.3.14(esbuild@0.25.9)(webpack@5.101.2(esbuild@0.25.9)) + terser-webpack-plugin: 5.3.16(esbuild@0.25.9)(webpack@5.104.1(esbuild@0.25.9)) watchpack: 2.4.4 webpack-sources: 3.3.3 transitivePeerDependencies: From 795d654138701a03d4d793d3299ff4f33e427a03 Mon Sep 17 00:00:00 2001 From: Charles Lyding <19598772+clydin@users.noreply.github.com> Date: Tue, 20 Jan 2026 18:45:18 -0500 Subject: [PATCH 34/52] fix(@angular/cli): update pacote to v21.0.4 Addresses https://github.com/advisories/GHSA-8qq5-rm4j-mr97 --- packages/angular/cli/package.json | 2 +- pnpm-lock.yaml | 543 +++++++++++++++--------------- 2 files changed, 267 insertions(+), 278 deletions(-) diff --git a/packages/angular/cli/package.json b/packages/angular/cli/package.json index fc2b2ad08b2c..b59dedcaf33e 100644 --- a/packages/angular/cli/package.json +++ b/packages/angular/cli/package.json @@ -35,7 +35,7 @@ "jsonc-parser": "3.3.1", "listr2": "9.0.1", "npm-package-arg": "13.0.0", - "pacote": "21.0.0", + "pacote": "21.0.4", "resolve": "1.22.10", "semver": "7.7.2", "yargs": "18.0.0", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 7f8149340d7e..b305c98274bd 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -496,8 +496,8 @@ importers: specifier: 13.0.0 version: 13.0.0 pacote: - specifier: 21.0.0 - version: 21.0.0 + specifier: 21.0.4 + version: 21.0.4 resolve: specifier: 1.22.10 version: 1.22.10 @@ -2716,42 +2716,42 @@ packages: resolution: {integrity: sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==} engines: {node: '>= 8'} - '@npmcli/agent@3.0.0': - resolution: {integrity: sha512-S79NdEgDQd/NGCay6TCoVzXSj74skRZIKJcpJjC5lOq34SZzyI6MqtiiWoiVWoVrTcGjNeC4ipbh1VIHlpfF5Q==} - engines: {node: ^18.17.0 || >=20.5.0} + '@npmcli/agent@4.0.0': + resolution: {integrity: sha512-kAQTcEN9E8ERLVg5AsGwLNoFb+oEG6engbqAU2P43gD4JEIkNGMHdVQ096FsOAAYpZPB0RSt0zgInKIAS1l5QA==} + engines: {node: ^20.17.0 || >=22.9.0} - '@npmcli/fs@4.0.0': - resolution: {integrity: sha512-/xGlezI6xfGO9NwuJlnwz/K14qD1kCSAGtacBHnGzeAIuJGazcp45KP5NuyARXoKb7cwulAGWVsbeSxdG/cb0Q==} - engines: {node: ^18.17.0 || >=20.5.0} + '@npmcli/fs@5.0.0': + resolution: {integrity: sha512-7OsC1gNORBEawOa5+j2pXN9vsicaIOH5cPXxoR6fJOmH6/EXpJB2CajXOu1fPRFun2m1lktEFX11+P89hqO/og==} + engines: {node: ^20.17.0 || >=22.9.0} - '@npmcli/git@6.0.3': - resolution: {integrity: sha512-GUYESQlxZRAdhs3UhbB6pVRNUELQOHXwK9ruDkwmCv2aZ5y0SApQzUJCg02p3A7Ue2J5hxvlk1YI53c00NmRyQ==} - engines: {node: ^18.17.0 || >=20.5.0} + '@npmcli/git@7.0.1': + resolution: {integrity: sha512-+XTFxK2jJF/EJJ5SoAzXk3qwIDfvFc5/g+bD274LZ7uY7LE8sTfG6Z8rOanPl2ZEvZWqNvmEdtXC25cE54VcoA==} + engines: {node: ^20.17.0 || >=22.9.0} - '@npmcli/installed-package-contents@3.0.0': - resolution: {integrity: sha512-fkxoPuFGvxyrH+OQzyTkX2LUEamrF4jZSmxjAtPPHHGO0dqsQ8tTKjnIS8SAnPHdk2I03BDtSMR5K/4loKg79Q==} - engines: {node: ^18.17.0 || >=20.5.0} + '@npmcli/installed-package-contents@4.0.0': + resolution: {integrity: sha512-yNyAdkBxB72gtZ4GrwXCM0ZUedo9nIbOMKfGjt6Cu6DXf0p8y1PViZAKDC8q8kv/fufx0WTjRBdSlyrvnP7hmA==} + engines: {node: ^20.17.0 || >=22.9.0} hasBin: true - '@npmcli/node-gyp@4.0.0': - resolution: {integrity: sha512-+t5DZ6mO/QFh78PByMq1fGSAub/agLJZDRfJRMeOSNCt8s9YVlTjmGpIPwPhvXTGUIJk+WszlT0rQa1W33yzNA==} - engines: {node: ^18.17.0 || >=20.5.0} + '@npmcli/node-gyp@5.0.0': + resolution: {integrity: sha512-uuG5HZFXLfyFKqg8QypsmgLQW7smiRjVc45bqD/ofZZcR/uxEjgQU8qDPv0s9TEeMUiAAU/GC5bR6++UdTirIQ==} + engines: {node: ^20.17.0 || >=22.9.0} - '@npmcli/package-json@6.2.0': - resolution: {integrity: sha512-rCNLSB/JzNvot0SEyXqWZ7tX2B5dD2a1br2Dp0vSYVo5jh8Z0EZ7lS9TsZ1UtziddB1UfNUaMCc538/HztnJGA==} - engines: {node: ^18.17.0 || >=20.5.0} + '@npmcli/package-json@7.0.4': + resolution: {integrity: sha512-0wInJG3j/K40OJt/33ax47WfWMzZTm6OQxB9cDhTt5huCP2a9g2GnlsxmfN+PulItNPIpPrZ+kfwwUil7eHcZQ==} + engines: {node: ^20.17.0 || >=22.9.0} - '@npmcli/promise-spawn@8.0.3': - resolution: {integrity: sha512-Yb00SWaL4F8w+K8YGhQ55+xE4RUNdMHV43WZGsiTM92gS+lC0mGsn7I4hLug7pbao035S6bj3Y3w0cUNGLfmkg==} - engines: {node: ^18.17.0 || >=20.5.0} + '@npmcli/promise-spawn@9.0.1': + resolution: {integrity: sha512-OLUaoqBuyxeTqUvjA3FZFiXUfYC1alp3Sa99gW3EUDz3tZ3CbXDdcZ7qWKBzicrJleIgucoWamWH1saAmH/l2Q==} + engines: {node: ^20.17.0 || >=22.9.0} - '@npmcli/redact@3.2.2': - resolution: {integrity: sha512-7VmYAmk4csGv08QzrDKScdzn11jHPFGyqJW39FyPgPuAp3zIaUmuCo1yxw9aGs+NEJuTGQ9Gwqpt93vtJubucg==} - engines: {node: ^18.17.0 || >=20.5.0} + '@npmcli/redact@4.0.0': + resolution: {integrity: sha512-gOBg5YHMfZy+TfHArfVogwgfBeQnKbbGo3pSUyK/gSI0AVu+pEiDVcKlQb0D8Mg1LNRZILZ6XG8I5dJ4KuAd9Q==} + engines: {node: ^20.17.0 || >=22.9.0} - '@npmcli/run-script@9.1.0': - resolution: {integrity: sha512-aoNSbxtkePXUlbZB+anS1LqsJdctG5n3UVhfU47+CDdwMi6uNTBMF9gPcQRnqghQd2FGzcwwIFBruFMxjhBewg==} - engines: {node: ^18.17.0 || >=20.5.0} + '@npmcli/run-script@10.0.3': + resolution: {integrity: sha512-ER2N6itRkzWbbtVmZ9WKaWxVlKlOeBFF1/7xx+KA5J1xKa4JjUwBdb6tDpk0v1qA+d+VDwHI9qmLcXSWcmi+Rw==} + engines: {node: ^20.17.0 || >=22.9.0} '@octokit/auth-app@8.1.1': resolution: {integrity: sha512-yW9YUy1cuqWlz8u7908ed498wJFt42VYsYWjvepjojM4BdZSp4t+5JehFds7LfvYi550O/GaUI94rgbhswvxfA==} @@ -3311,29 +3311,29 @@ packages: '@rtsao/scc@1.1.0': resolution: {integrity: sha512-zt6OdqaDoOnJ1ZYsCYGt9YmWzDXl4vQdKTyJev62gFhRGKdx7mcT54V9KIjg+d2wi9EXsPvAPKe7i7WjfVWB8g==} - '@sigstore/bundle@3.1.0': - resolution: {integrity: sha512-Mm1E3/CmDDCz3nDhFKTuYdB47EdRFRQMOE/EAbiG1MJW77/w1b3P7Qx7JSrVJs8PfwOLOVcKQCHErIwCTyPbag==} - engines: {node: ^18.17.0 || >=20.5.0} + '@sigstore/bundle@4.0.0': + resolution: {integrity: sha512-NwCl5Y0V6Di0NexvkTqdoVfmjTaQwoLM236r89KEojGmq/jMls8S+zb7yOwAPdXvbwfKDlP+lmXgAL4vKSQT+A==} + engines: {node: ^20.17.0 || >=22.9.0} - '@sigstore/core@2.0.0': - resolution: {integrity: sha512-nYxaSb/MtlSI+JWcwTHQxyNmWeWrUXJJ/G4liLrGG7+tS4vAz6LF3xRXqLH6wPIVUoZQel2Fs4ddLx4NCpiIYg==} - engines: {node: ^18.17.0 || >=20.5.0} + '@sigstore/core@3.1.0': + resolution: {integrity: sha512-o5cw1QYhNQ9IroioJxpzexmPjfCe7gzafd2RY3qnMpxr4ZEja+Jad/U8sgFpaue6bOaF+z7RVkyKVV44FN+N8A==} + engines: {node: ^20.17.0 || >=22.9.0} - '@sigstore/protobuf-specs@0.4.3': - resolution: {integrity: sha512-fk2zjD9117RL9BjqEwF7fwv7Q/P9yGsMV4MUJZ/DocaQJ6+3pKr+syBq1owU5Q5qGw5CUbXzm+4yJ2JVRDQeSA==} + '@sigstore/protobuf-specs@0.5.0': + resolution: {integrity: sha512-MM8XIwUjN2bwvCg1QvrMtbBmpcSHrkhFSCu1D11NyPvDQ25HEc4oG5/OcQfd/Tlf/OxmKWERDj0zGE23jQaMwA==} engines: {node: ^18.17.0 || >=20.5.0} - '@sigstore/sign@3.1.0': - resolution: {integrity: sha512-knzjmaOHOov1Ur7N/z4B1oPqZ0QX5geUfhrVaqVlu+hl0EAoL4o+l0MSULINcD5GCWe3Z0+YJO8ues6vFlW0Yw==} - engines: {node: ^18.17.0 || >=20.5.0} + '@sigstore/sign@4.1.0': + resolution: {integrity: sha512-Vx1RmLxLGnSUqx/o5/VsCjkuN5L7y+vxEEwawvc7u+6WtX2W4GNa7b9HEjmcRWohw/d6BpATXmvOwc78m+Swdg==} + engines: {node: ^20.17.0 || >=22.9.0} - '@sigstore/tuf@3.1.1': - resolution: {integrity: sha512-eFFvlcBIoGwVkkwmTi/vEQFSva3xs5Ot3WmBcjgjVdiaoelBLQaQ/ZBfhlG0MnG0cmTYScPpk7eDdGDWUcFUmg==} - engines: {node: ^18.17.0 || >=20.5.0} + '@sigstore/tuf@4.0.1': + resolution: {integrity: sha512-OPZBg8y5Vc9yZjmWCHrlWPMBqW5yd8+wFNl+thMdtcWz3vjVSoJQutF8YkrzI0SLGnkuFof4HSsWUhXrf219Lw==} + engines: {node: ^20.17.0 || >=22.9.0} - '@sigstore/verify@2.1.1': - resolution: {integrity: sha512-hVJD77oT67aowHxwT4+M6PGOp+E2LtLdTK3+FC0lBO9T7sYwItDMXZ7Z07IDCvR1M717a4axbIWckrW67KMP/w==} - engines: {node: ^18.17.0 || >=20.5.0} + '@sigstore/verify@3.1.0': + resolution: {integrity: sha512-mNe0Iigql08YupSOGv197YdHpPPr+EzDZmfCgMc7RPNaZTw5aLN01nBl6CHJOh3BGtnMIj83EeN4butBchc8Ag==} + engines: {node: ^20.17.0 || >=22.9.0} '@socket.io/component-emitter@3.1.2': resolution: {integrity: sha512-9BCxFwvbGg/RsZK9tjXd8s4UcwR0MWeFQ1XEKIQVVvAGJyINdrqKMcTRyLoK8Rse1GjzLV9cwjWV1olXRWEXVA==} @@ -3367,9 +3367,9 @@ packages: resolution: {integrity: sha512-yVtV8zsdo8qFHe+/3kw81dSLyF7D576A5cCFCi4X7B39tWT7SekaEFUnvnWJHz+9qO7qJTah1JbrDjWKqFtdWA==} engines: {node: ^16.14.0 || >=18.0.0} - '@tufjs/models@3.0.1': - resolution: {integrity: sha512-UUYHISyhCU3ZgN8yaear3cGATHb3SMuKHsQ/nVbHXcmnBf+LzQ/cQfhNG+rfaSHgqGKNEm2cOCLVLELStUQ1JA==} - engines: {node: ^18.17.0 || >=20.5.0} + '@tufjs/models@4.1.0': + resolution: {integrity: sha512-Y8cK9aggNRsqJVaKUlEYs4s7CvQ1b1ta2DVPyAimb0I2qhzjNk+A+mxvll/klL0RlfuIUei8BF7YWiua4kQqww==} + engines: {node: ^20.17.0 || >=22.9.0} '@types/accepts@1.3.7': resolution: {integrity: sha512-Pay9fq2lM2wXPWbteBsRAGiWH2hig4ZE2asK+mm7kUzlxRTfL961rj89I6zV/E3PcIkDqyuBEcMxFT7rccugeQ==} @@ -3954,9 +3954,9 @@ packages: resolution: {integrity: sha512-E+iruNOY8VV9s4JEbe1aNEm6MiszPRr/UfcHMz0TQh1BXSxHK+ASV1R6W4HpjBhSeS+54PIsAMCBmwD06LLsqQ==} hasBin: true - abbrev@3.0.1: - resolution: {integrity: sha512-AO2ac6pjRB3SJmGJo+v5/aK6Omggp6fsLrs6wN9bd35ulu4cCwaAU9+7ZhXjeqHVkaHThLuzH0nZr0YpCDhygg==} - engines: {node: ^18.17.0 || >=20.5.0} + abbrev@4.0.0: + resolution: {integrity: sha512-a1wflyaL0tHtJSmLSOVybYhy22vRih4eduhhrkcjgrWGnRfrZtovJ2FRjxuTtkkj47O/baf0R86QU5OuYpz8fA==} + engines: {node: ^20.17.0 || >=22.9.0} abort-controller@3.0.0: resolution: {integrity: sha512-h8lQ8tacZYnR3vNQTgibj+tODHI5/+l06Au2Pcriv/Gmet0eaj4TwWH41sO9wnHDiQsEj19q0drzdWdeAHtweg==} @@ -4434,9 +4434,9 @@ packages: resolution: {integrity: sha512-b6Ilus+c3RrdDk+JhLKUAQfzzgLEPy6wcXqS7f/xe1EETvsDP6GORG7SFuOs6cID5YkqchW/LXZbX5bc8j7ZcQ==} engines: {node: '>=8'} - cacache@19.0.1: - resolution: {integrity: sha512-hdsUxulXCi5STId78vRVYEtDAjq99ICAUktLTeTYsLoTE6Z8dS0c8pWNCxwdrk9YfJeobDZc2Y186hD/5ZQgFQ==} - engines: {node: ^18.17.0 || >=20.5.0} + cacache@20.0.3: + resolution: {integrity: sha512-3pUp4e8hv07k1QlijZu6Kn7c9+ZpWWk4j3F8N3xPuCExULobqJydKYOTj1FTq58srkJsXvO7LbGAH4C0ZU3WGw==} + engines: {node: ^20.17.0 || >=22.9.0} cache-content-type@1.0.1: resolution: {integrity: sha512-IKufZ1o4Ut42YUrZSo8+qnMTrFuKkvyoLXUywKz9GJ5BrhOFGhLdkx9sG4KAnVvbY6kEcSFjLQul+DVmBm2bgA==} @@ -4516,10 +4516,6 @@ packages: chownr@1.1.4: resolution: {integrity: sha512-jJ0bqzaylmJtVnNgzTeSOs8DPavpbYgEr/b0YL8/2GO3xJEhInFmhKMUnEJQjZumK7KXGFhUy89PrsJWlakBVg==} - chownr@2.0.0: - resolution: {integrity: sha512-bIomtDF5KGpdogkLd9VspvFzk9KfpyyGlS8YFVZl7TGPBHL5snIOnxeshwVgPteQ9b4Eydl+pVbIyE1DcvCWgQ==} - engines: {node: '>=10'} - chownr@3.0.0: resolution: {integrity: sha512-+IxzY9BZOQd/XuYPRmrvEVjF/nqj5kgT4kEq7VofrDoM1MxoRjEWkrCC3EtLi59TVawxTAn+orJwFQcrqEN1+g==} engines: {node: '>=18'} @@ -5582,10 +5578,6 @@ packages: resolution: {integrity: sha512-yhlQgA6mnOJUKOsRUFsgJdQCvkKhcz8tlZG5HBQfReYZy46OwLcY+Zia0mtdHsOo9y/hP+CxMN0TU9QxoOtG4g==} engines: {node: '>=6 <7 || >=8'} - fs-minipass@2.1.0: - resolution: {integrity: sha512-V/JgOLFCS+R6Vcq0slCuaeWEdNC3ouDlJMNIsacH2VtALiu9mV4LPrHc5cDl8k5aw6J8jwgWWpiTo5RYhmIzvg==} - engines: {node: '>= 8'} - fs-minipass@3.0.3: resolution: {integrity: sha512-XUBA9XClHbnJWSfBzjkm6RvPsyg3sryZt06BEQoXcF7EK/xpGaQYJgQKDJSUH5SGZ76Y7pFx1QBnXz09rU5Fbw==} engines: {node: ^14.17.0 || ^16.13.0 || >=18.0.0} @@ -5697,6 +5689,10 @@ packages: engines: {node: 20 || >=22} hasBin: true + glob@13.0.0: + resolution: {integrity: sha512-tvZgpqk6fz4BaNZ66ZsRaZnbHvP/jG3uKJvAZOwEVUL4RTA5nJeeLYfyN9/VA8NX/V3IBG+hkeuGpKjvELkVhA==} + engines: {node: 20 || >=22} + glob@7.2.3: resolution: {integrity: sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==} deprecated: Glob versions prior to v9 are no longer supported @@ -5815,10 +5811,6 @@ packages: resolution: {integrity: sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==} engines: {node: '>= 0.4'} - hosted-git-info@8.1.0: - resolution: {integrity: sha512-Rw/B2DNQaPBICNXEm8balFz9a6WpZrkCGpcWFpy7nCj+NyhSdqXipmfvtmWt9xGfp0wZnBxB+iVpLmQMYt47Tw==} - engines: {node: ^18.17.0 || >=20.5.0} - hosted-git-info@9.0.2: resolution: {integrity: sha512-M422h7o/BR3rmCQ8UHi7cyyMqKltdP9Uo+J2fXK+RSAY+wTcKOIRyhTuKv4qn+DJf3g+PL890AzId5KZpX+CBg==} engines: {node: ^20.17.0 || >=22.9.0} @@ -6008,6 +6000,10 @@ packages: resolution: {integrity: sha512-+N0ngpO3e7cRUWOJAS7qw0IZIVc6XPrW4MlFBdD066F2L4k1L6ker3hLqSq7iXxU5tgS4WGkIUElWn5vogAEnw==} engines: {node: ^18.17.0 || >=20.5.0} + ini@6.0.0: + resolution: {integrity: sha512-IBTdIkzZNOpqm7q3dRqJvMaldXjDHWkEDfrwGEQTs5eaQMWV+djAhR+wahyNNMAa+qpbDUhBMVt4ZKNwpPm7xQ==} + engines: {node: ^20.17.0 || >=22.9.0} + injection-js@2.5.0: resolution: {integrity: sha512-UpY2ONt4xbht4GhSqQ2zMJ1rBIQq4uOY+DlR6aOeYyqK7xadXt7UQbJIyxmgk288bPMkIZKjViieHm0O0i72Jw==} @@ -6421,9 +6417,9 @@ packages: json-parse-even-better-errors@2.3.1: resolution: {integrity: sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==} - json-parse-even-better-errors@4.0.0: - resolution: {integrity: sha512-lR4MXjGNgkJc7tkQ97kb2nuEMnNCyU//XYVH0MKTGcXEiSudQ5MKGKen3C5QubYy0vmq+JGitUg92uuywGEwIA==} - engines: {node: ^18.17.0 || >=20.5.0} + json-parse-even-better-errors@5.0.0: + resolution: {integrity: sha512-ZF1nxZ28VhQouRWhUcVlUIN3qwSgPuswK05s/HIaoetAoE/9tngVmCHjSxmSQPav1nd+lPtTL0YZ/2AFdR/iYQ==} + engines: {node: ^20.17.0 || >=22.9.0} json-schema-traverse@0.4.1: resolution: {integrity: sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==} @@ -6726,9 +6722,9 @@ packages: make-error@1.3.6: resolution: {integrity: sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw==} - make-fetch-happen@14.0.3: - resolution: {integrity: sha512-QMjGbFTP0blj97EeidG5hk/QhKQ3T4ICckQGLgz38QF7Vgbk6e6FTARN8KhKxyBbWn8R0HU+bnw8aSoFPD4qtQ==} - engines: {node: ^18.17.0 || >=20.5.0} + make-fetch-happen@15.0.3: + resolution: {integrity: sha512-iyyEpDty1mwW3dGlYXAJqC/azFn5PPvgKVwXayOGBSmKLxhKZ9fg4qIan2ePpp1vJIwfFiO34LAPZgq9SZW9Aw==} + engines: {node: ^20.17.0 || >=22.9.0} marky@1.3.0: resolution: {integrity: sha512-ocnPZQLNpvbedwTy9kNrQEsknEfgvcLMvOtz3sFeWApDq1MXH1TqkCIx58xlpESsfwQOnuBO9beyQuNGzVvuhQ==} @@ -6830,6 +6826,10 @@ packages: resolution: {integrity: sha512-IPZ167aShDZZUMdRk66cyQAW3qr0WzbHkPdMYa8bzZhlHhO3jALbKdxcaak7W9FfT2rZNpQuUu4Od7ILEpXSaw==} engines: {node: 20 || >=22} + minimatch@10.1.1: + resolution: {integrity: sha512-enIvLvRAFZYXJzkCYG5RKmPfrFArdLv+R+lbQ53BmIMLIry74bjKzX6iHAm8WYamJkhSSEabrWN5D97XnKObjQ==} + engines: {node: 20 || >=22} + minimatch@3.1.2: resolution: {integrity: sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==} @@ -6852,9 +6852,9 @@ packages: resolution: {integrity: sha512-D7V8PO9oaz7PWGLbCACuI1qEOsq7UKfLotx/C0Aet43fCUB/wfQ7DYeq2oR/svFJGYDHPr38SHATeaj/ZoKHKw==} engines: {node: '>=16 || 14 >=14.17'} - minipass-fetch@4.0.1: - resolution: {integrity: sha512-j7U11C5HXigVuutxebFadoYBbd7VSdZWggSe64NVdvWNBqGAiXPL2QVCehjmw7lY1oF9gOllYbORh+hiNgfPgQ==} - engines: {node: ^18.17.0 || >=20.5.0} + minipass-fetch@5.0.0: + resolution: {integrity: sha512-fiCdUALipqgPWrOVTz9fw0XhcazULXOSU6ie40DDbX1F49p1dBrSRBuswndTx1x3vEb/g0FT7vC4c4C2u/mh3A==} + engines: {node: ^20.17.0 || >=22.9.0} minipass-flush@1.0.5: resolution: {integrity: sha512-JmQSYYpPUqX5Jyn1mXaRwOda1uQ8HP5KAT/oDSLCzt1BYRhQU0/hDtsB1ufZfEEzMZ9aAVmsBw8+FWsIXlClWw==} @@ -6872,18 +6872,10 @@ packages: resolution: {integrity: sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw==} engines: {node: '>=8'} - minipass@5.0.0: - resolution: {integrity: sha512-3FnjYuehv9k6ovOEbyOswadCDPX1piCfhV8ncmYtHOjuPwylVWsghTLo7rabjC3Rx5xD4HDx8Wm1xnMF7S5qFQ==} - engines: {node: '>=8'} - minipass@7.1.2: resolution: {integrity: sha512-qOOzS1cBTWYF4BH8fVePDBOO9iptMnGUEZwNc/cMWnTV2nVLZ7VoNWEPHkYczZA0pdoA7dl6e7FL659nX9S2aw==} engines: {node: '>=16 || 14 >=14.17'} - minizlib@2.1.2: - resolution: {integrity: sha512-bAxsR8BVfj60DWXHE3u30oHzfl4G7khkSuPW+qvpd7jFRHm7dLxOjUk1EHACJ/hxLY8phGJ0YhYHZo7jil7Qdg==} - engines: {node: '>= 8'} - minizlib@3.1.0: resolution: {integrity: sha512-KZxYo1BUkWD2TVFLr0MQoM8vUUigWD3LlD83a/75BqC+4qE0Hb1Vo5v1FgcfaNXvfXzr+5EhQ6ing/CaBijTlw==} engines: {node: '>= 18'} @@ -7038,9 +7030,9 @@ packages: resolution: {integrity: sha512-LA4ZjwlnUblHVgq0oBF3Jl/6h/Nvs5fzBLwdEF4nuxnFdsfajde4WfxtJr3CaiH+F6ewcIB/q4jQ4UzPyid+CQ==} hasBin: true - node-gyp@11.4.2: - resolution: {integrity: sha512-3gD+6zsrLQH7DyYOUIutaauuXrcyxeTPyQuZQCQoNPZMHMMS5m4y0xclNpvYzoK3VNzuyxT6eF4mkIL4WSZ1eQ==} - engines: {node: ^18.17.0 || >=20.5.0} + node-gyp@12.1.0: + resolution: {integrity: sha512-W+RYA8jBnhSr2vrTtlPYPc1K+CSjGpVDRZxcqJcERZ8ND3A1ThWPHRwctTx3qC3oW99jt726jhdz3Y6ky87J4g==} + engines: {node: ^20.17.0 || >=22.9.0} hasBin: true node-releases@2.0.23: @@ -7049,9 +7041,9 @@ packages: node-releases@2.0.27: resolution: {integrity: sha512-nmh3lCkYZ3grZvqcCH+fjmQ7X+H0OeZgP40OierEaAptX4XofMh5kwNbWh7lBduUzCcV/8kZ+NDLCwm2iorIlA==} - nopt@8.1.0: - resolution: {integrity: sha512-ieGu42u/Qsa4TFktmaKEwM6MQH0pOWnaB3htzh0JRtx84+Mebc0cbZYN5bC+6WTZ4+77xrL9Pn5m7CV6VIkV7A==} - engines: {node: ^18.17.0 || >=20.5.0} + nopt@9.0.0: + resolution: {integrity: sha512-Zhq3a+yFKrYwSBluL4H9XP3m3y5uvQkB/09CwDruCiRmR/UJYnn9W4R48ry0uGC70aeTPKLynBtscP9efFFcPw==} + engines: {node: ^20.17.0 || >=22.9.0} hasBin: true normalize-path@3.0.0: @@ -7062,21 +7054,17 @@ packages: resolution: {integrity: sha512-bdok/XvKII3nUpklnV6P2hxtMNrCboOjAcyBuQnWEhO665FwrSNRxU+AqpsyvO6LgGYPspN+lu5CLtw4jPRKNA==} engines: {node: '>=0.10.0'} - npm-bundled@4.0.0: - resolution: {integrity: sha512-IxaQZDMsqfQ2Lz37VvyyEtKLe8FsRZuysmedy/N06TU1RyVppYKXrO4xIhR0F+7ubIBox6Q7nir6fQI3ej39iA==} - engines: {node: ^18.17.0 || >=20.5.0} - - npm-install-checks@7.1.2: - resolution: {integrity: sha512-z9HJBCYw9Zr8BqXcllKIs5nI+QggAImbBdHphOzVYrz2CB4iQ6FzWyKmlqDZua+51nAu7FcemlbTc9VgQN5XDQ==} - engines: {node: ^18.17.0 || >=20.5.0} + npm-bundled@5.0.0: + resolution: {integrity: sha512-JLSpbzh6UUXIEoqPsYBvVNVmyrjVZ1fzEFbqxKkTJQkWBO3xFzFT+KDnSKQWwOQNbuWRwt5LSD6HOTLGIWzfrw==} + engines: {node: ^20.17.0 || >=22.9.0} - npm-normalize-package-bin@4.0.0: - resolution: {integrity: sha512-TZKxPvItzai9kN9H/TkmCtx/ZN/hvr3vUycjlfmH0ootY9yFBzNOpiXAdIn1Iteqsvk4lQn6B5PTrt+n6h8k/w==} - engines: {node: ^18.17.0 || >=20.5.0} + npm-install-checks@8.0.0: + resolution: {integrity: sha512-ScAUdMpyzkbpxoNekQ3tNRdFI8SJ86wgKZSQZdUxT+bj0wVFpsEMWnkXP0twVe1gJyNF5apBWDJhhIbgrIViRA==} + engines: {node: ^20.17.0 || >=22.9.0} - npm-package-arg@12.0.2: - resolution: {integrity: sha512-f1NpFjNI9O4VbKMOlA5QoBq/vSQPORHcTZ2feJpFkTHJ9eQkdlmZEKSjcAhxTGInC7RlEyScT9ui67NaOsjFWA==} - engines: {node: ^18.17.0 || >=20.5.0} + npm-normalize-package-bin@5.0.0: + resolution: {integrity: sha512-CJi3OS4JLsNMmr2u07OJlhcrPxCeOeP/4xq67aWNai6TNWWbTrlNDgl8NcFKVlcBKp18GPj+EzbNIgrBfZhsag==} + engines: {node: ^20.17.0 || >=22.9.0} npm-package-arg@13.0.0: resolution: {integrity: sha512-+t2etZAGcB7TbbLHfDwooV9ppB2LhhcT6A+L9cahsf9mEUAoQ6CktLEVvEnpD0N5CkX7zJqnPGaFtoQDy9EkHQ==} @@ -7086,13 +7074,13 @@ packages: resolution: {integrity: sha512-DrIWNiWT0FTdDRjGOYfEEZUNe1IzaSZ+up7qBTKnrQDySpdmuOQvytrqQlpK5QrCA4IThMvL4wTumqaa1ZvVIQ==} engines: {node: ^20.17.0 || >=22.9.0} - npm-pick-manifest@10.0.0: - resolution: {integrity: sha512-r4fFa4FqYY8xaM7fHecQ9Z2nE9hgNfJR+EmoKv0+chvzWkBcORX3r0FpTByP+CbOVJDladMXnPQGVN8PBLGuTQ==} - engines: {node: ^18.17.0 || >=20.5.0} + npm-pick-manifest@11.0.3: + resolution: {integrity: sha512-buzyCfeoGY/PxKqmBqn1IUJrZnUi1VVJTdSSRPGI60tJdUhUoSQFhs0zycJokDdOznQentgrpf8LayEHyyYlqQ==} + engines: {node: ^20.17.0 || >=22.9.0} - npm-registry-fetch@18.0.2: - resolution: {integrity: sha512-LeVMZBBVy+oQb5R6FDV9OlJCcWDU+al10oKpe+nsvcHnG24Z3uM3SvJYKfGJlfGjVU8v9liejCrUR/M5HO5NEQ==} - engines: {node: ^18.17.0 || >=20.5.0} + npm-registry-fetch@19.1.1: + resolution: {integrity: sha512-TakBap6OM1w0H73VZVDf44iFXsOS3h+L4wVMXmbWOQroZgFhMch0juN6XSzBNlD965yIKvWg2dfu7NSiaYLxtw==} + engines: {node: ^20.17.0 || >=22.9.0} npm-run-path@4.0.1: resolution: {integrity: sha512-S48WzZW777zhNIrn7gxOlISNAqi9ZC/uQFnRdbeIHhZhCA6UqpkOT8T1G7BvfdgP4Er8gF4sUbaS0i7QvIfCWw==} @@ -7332,8 +7320,8 @@ packages: package-json-from-dist@1.0.1: resolution: {integrity: sha512-UEZIS3/by4OC8vL3P2dTXRETpebLI2NiI5vIrjaD/5UtrkFX/tNbwjTSRAGC/+7CAo2pIcBaRgWmcBBHcsaCIw==} - pacote@21.0.0: - resolution: {integrity: sha512-lcqexq73AMv6QNLo7SOpz0JJoaGdS3rBFgF122NZVl1bApo2mfu+XzUBU/X/XsiJu+iUmKpekRayqQYAs+PhkA==} + pacote@21.0.4: + resolution: {integrity: sha512-RplP/pDW0NNNDh3pnaoIWYPvNenS7UqMbXyvMqJczosiFWTeGGwJC2NQBLqKf4rGLFfwCOnntw1aEp9Jiqm1MA==} engines: {node: ^20.17.0 || >=22.9.0} hasBin: true @@ -7569,6 +7557,10 @@ packages: resolution: {integrity: sha512-Azwzvl90HaF0aCz1JrDdXQykFakSSNPaPoiZ9fm5qJIMHioDZEi7OAdRwSm6rSoPtY3Qutnm3L7ogmg3dc+wbQ==} engines: {node: ^18.17.0 || >=20.5.0} + proc-log@6.1.0: + resolution: {integrity: sha512-iG+GYldRf2BQ0UDUAd6JQ/RwzaQy6mXmsk/IzlYyal4A4SNFw54MeH4/tLkF4I5WoWG9SQwuqWzS99jaFQHBuQ==} + engines: {node: ^20.17.0 || >=22.9.0} + process-nextick-args@2.0.1: resolution: {integrity: sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==} @@ -8086,9 +8078,9 @@ packages: resolution: {integrity: sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==} engines: {node: '>=14'} - sigstore@3.1.0: - resolution: {integrity: sha512-ZpzWAFHIFqyFE56dXqgX/DkDRZdz+rRcjoIk/RQU4IX0wiCv1l8S7ZrXDHcCc+uaf+6o7w3h2l3g6GYG5TKN9Q==} - engines: {node: ^18.17.0 || >=20.5.0} + sigstore@4.1.0: + resolution: {integrity: sha512-/fUgUhYghuLzVT/gaJoeVehLCgZiUxPCPMcyVNY0lIf/cTCz58K/WTI7PefDarXxp9nUKpEwg1yyz3eSBMTtgA==} + engines: {node: ^20.17.0 || >=22.9.0} slash@3.0.0: resolution: {integrity: sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==} @@ -8211,9 +8203,9 @@ packages: resolution: {integrity: sha512-bSf16tAFkGeRlUNDjXu8FzaMQt6g2HZJrun7mtMbIPOddxt3GLMSz5VWUWcqTJUPfLEaDIepGxv+bYQW49596A==} engines: {node: ^14.17.0 || ^16.13.0 || >=18.0.0} - ssri@12.0.0: - resolution: {integrity: sha512-S7iGNosepx9RadX82oimUkvr0Ct7IjJbEbs4mJcTxst8um95J3sDYU1RBEOvdu6oL1Wek2ODI5i4MAw+dZ6cAQ==} - engines: {node: ^18.17.0 || >=20.5.0} + ssri@13.0.0: + resolution: {integrity: sha512-yizwGBpbCn4YomB2lzhZqrHLJoqFGXihNbib3ozhqF/cIp5ue+xSmOQrjNasEE62hFxsCcg/V/z23t4n8jMEng==} + engines: {node: ^20.17.0 || >=22.9.0} stack-trace@0.0.10: resolution: {integrity: sha512-KGzahc7puUKkzyMt+IqAep+TVNbKP+k2Lmwhub39m1AsTSkaDutx56aDCo+HLDzf/D26BIHTJWNiTG1KAJiQCg==} @@ -8376,14 +8368,14 @@ packages: tar-stream@3.1.7: resolution: {integrity: sha512-qJj60CXt7IU1Ffyc3NJMjh6EkuCFej46zUqJ4J7pqYlThyd9bO0XBTmcOIhSzZJVWfsLks0+nle/j538YAW9RQ==} - tar@6.2.1: - resolution: {integrity: sha512-DZ4yORTwrbTj/7MZYq2w+/ZFdI6OZ/f9SFHR+71gIVUZhOQPHzVCLpvRnPgyaMpfWxxk/4ONva3GQSyNIKRv6A==} - engines: {node: '>=10'} - tar@7.5.1: resolution: {integrity: sha512-nlGpxf+hv0v7GkWBK2V9spgactGOp0qvfWRxUMjqHyzrt3SgwE48DIv/FhqPHJYLHpgW1opq3nERbz5Anq7n1g==} engines: {node: '>=18'} + tar@7.5.4: + resolution: {integrity: sha512-AN04xbWGrSTDmVwlI4/GTlIIwMFk/XEv7uL8aa57zuvRy6s4hdBed+lVq2fAZ89XDa7Us3ANXcE3Tvqvja1kTA==} + engines: {node: '>=18'} + teeny-request@10.1.0: resolution: {integrity: sha512-3ZnLvgWF29jikg1sAQ1g0o+lr5JX6sVgYvfUJazn7ZjJroDBUTWp44/+cFVX0bULjv4vci+rBD+oGVAkWqhUbw==} engines: {node: '>=18'} @@ -8549,9 +8541,9 @@ packages: engines: {node: '>=18.0.0'} hasBin: true - tuf-js@3.1.0: - resolution: {integrity: sha512-3T3T04WzowbwV2FDiGXBbr81t64g1MUGGJRgT4x5o97N+8ArdhVCAF9IxFrxuSJmM3E5Asn7nKHkao0ibcZXAg==} - engines: {node: ^18.17.0 || >=20.5.0} + tuf-js@4.1.0: + resolution: {integrity: sha512-50QV99kCKH5P/Vs4E2Gzp7BopNV+KzTXqWeaxrfu5IQJBOULRsTIS9seSsOVT8ZnGXzCyx55nYWAi4qJzpZKEQ==} + engines: {node: ^20.17.0 || >=22.9.0} tunnel-agent@0.6.0: resolution: {integrity: sha512-McnNiV1l8RYeY8tBgEpuodCC1mLUdbSN+CYBL7kJsJNInOP8UjDDEwdk6Mw60vdLLrr5NHKZhMAOSrR2NZuQ+w==} @@ -8679,13 +8671,13 @@ packages: unicode-trie@2.0.0: resolution: {integrity: sha512-x7bc76x0bm4prf1VLg79uhAzKw8DVboClSN5VxJuQ+LKDOVEW9CdH+VY7SP+vX7xCYQqzzgQpFqz15zeLvAtZQ==} - unique-filename@4.0.0: - resolution: {integrity: sha512-XSnEewXmQ+veP7xX2dS5Q4yZAvO40cBN2MWkJ7D/6sW4Dg6wYBNwM1Vrnz1FhH5AdeLIlUXRI9e28z1YZi71NQ==} - engines: {node: ^18.17.0 || >=20.5.0} + unique-filename@5.0.0: + resolution: {integrity: sha512-2RaJTAvAb4owyjllTfXzFClJ7WsGxlykkPvCr9pA//LD9goVq+m4PPAeBgNodGZ7nSrntT/auWpJ6Y5IFXcfjg==} + engines: {node: ^20.17.0 || >=22.9.0} - unique-slug@5.0.0: - resolution: {integrity: sha512-9OdaqO5kwqR+1kVgHAhsp5vPNU0hnxRa26rBFNfNgM7M6pNtgzeBn3s/xbyCQL3dcjzOatcef6UUHpB/6MaETg==} - engines: {node: ^18.17.0 || >=20.5.0} + unique-slug@6.0.0: + resolution: {integrity: sha512-4Lup7Ezn8W3d52/xBhZBVdx323ckxa7DEvd9kPQHppTkLoJXw6ltrBCyj5pnrxj0qKDxYMJ56CoxNuFCscdTiw==} + engines: {node: ^20.17.0 || >=22.9.0} universal-github-app-jwt@2.2.2: resolution: {integrity: sha512-dcmbeSrOdTnsjGjUfAlqNDJrhxXizjAz94ija9Qw8YkZ1uu0d+GoZzyH+Jb9tIIqvGsadUfwg+22k5aDqqwzbw==} @@ -9048,6 +9040,11 @@ packages: engines: {node: ^18.17.0 || >=20.5.0} hasBin: true + which@6.0.0: + resolution: {integrity: sha512-f+gEpIKMR9faW/JgAgPK1D7mekkFoqbmiwvNzuhsHetni20QSgzg9Vhn0g2JSJkkfehQnqdUAx7/e15qS1lPxg==} + engines: {node: ^20.17.0 || >=22.9.0} + hasBin: true + why-is-node-running@2.3.0: resolution: {integrity: sha512-hUrmaWBdVDcxvYqnyh09zunKzROWjbZTiNy8dBEjkS7ehEDQibXJ7XvlmtbwuTclUiIyN+CyXQD4Vmko8fNm8w==} engines: {node: '>=8'} @@ -11313,62 +11310,62 @@ snapshots: '@nodelib/fs.scandir': 2.1.5 fastq: 1.19.1 - '@npmcli/agent@3.0.0': + '@npmcli/agent@4.0.0': dependencies: agent-base: 7.1.4 http-proxy-agent: 7.0.2 https-proxy-agent: 7.0.6(supports-color@10.2.2) - lru-cache: 10.4.3 + lru-cache: 11.2.2 socks-proxy-agent: 8.0.5 transitivePeerDependencies: - supports-color - '@npmcli/fs@4.0.0': + '@npmcli/fs@5.0.0': dependencies: semver: 7.7.2 - '@npmcli/git@6.0.3': + '@npmcli/git@7.0.1': dependencies: - '@npmcli/promise-spawn': 8.0.3 - ini: 5.0.0 - lru-cache: 10.4.3 - npm-pick-manifest: 10.0.0 - proc-log: 5.0.0 + '@npmcli/promise-spawn': 9.0.1 + ini: 6.0.0 + lru-cache: 11.2.2 + npm-pick-manifest: 11.0.3 + proc-log: 6.1.0 promise-retry: 2.0.1 semver: 7.7.2 - which: 5.0.0 + which: 6.0.0 - '@npmcli/installed-package-contents@3.0.0': + '@npmcli/installed-package-contents@4.0.0': dependencies: - npm-bundled: 4.0.0 - npm-normalize-package-bin: 4.0.0 + npm-bundled: 5.0.0 + npm-normalize-package-bin: 5.0.0 - '@npmcli/node-gyp@4.0.0': {} + '@npmcli/node-gyp@5.0.0': {} - '@npmcli/package-json@6.2.0': + '@npmcli/package-json@7.0.4': dependencies: - '@npmcli/git': 6.0.3 - glob: 10.4.5 - hosted-git-info: 8.1.0 - json-parse-even-better-errors: 4.0.0 - proc-log: 5.0.0 + '@npmcli/git': 7.0.1 + glob: 13.0.0 + hosted-git-info: 9.0.2 + json-parse-even-better-errors: 5.0.0 + proc-log: 6.1.0 semver: 7.7.2 validate-npm-package-license: 3.0.4 - '@npmcli/promise-spawn@8.0.3': + '@npmcli/promise-spawn@9.0.1': dependencies: - which: 5.0.0 + which: 6.0.0 - '@npmcli/redact@3.2.2': {} + '@npmcli/redact@4.0.0': {} - '@npmcli/run-script@9.1.0': + '@npmcli/run-script@10.0.3': dependencies: - '@npmcli/node-gyp': 4.0.0 - '@npmcli/package-json': 6.2.0 - '@npmcli/promise-spawn': 8.0.3 - node-gyp: 11.4.2 - proc-log: 5.0.0 - which: 5.0.0 + '@npmcli/node-gyp': 5.0.0 + '@npmcli/package-json': 7.0.4 + '@npmcli/promise-spawn': 9.0.1 + node-gyp: 12.1.0 + proc-log: 6.1.0 + which: 6.0.0 transitivePeerDependencies: - supports-color @@ -11832,37 +11829,37 @@ snapshots: '@rtsao/scc@1.1.0': {} - '@sigstore/bundle@3.1.0': + '@sigstore/bundle@4.0.0': dependencies: - '@sigstore/protobuf-specs': 0.4.3 + '@sigstore/protobuf-specs': 0.5.0 - '@sigstore/core@2.0.0': {} + '@sigstore/core@3.1.0': {} - '@sigstore/protobuf-specs@0.4.3': {} + '@sigstore/protobuf-specs@0.5.0': {} - '@sigstore/sign@3.1.0': + '@sigstore/sign@4.1.0': dependencies: - '@sigstore/bundle': 3.1.0 - '@sigstore/core': 2.0.0 - '@sigstore/protobuf-specs': 0.4.3 - make-fetch-happen: 14.0.3 - proc-log: 5.0.0 + '@sigstore/bundle': 4.0.0 + '@sigstore/core': 3.1.0 + '@sigstore/protobuf-specs': 0.5.0 + make-fetch-happen: 15.0.3 + proc-log: 6.1.0 promise-retry: 2.0.1 transitivePeerDependencies: - supports-color - '@sigstore/tuf@3.1.1': + '@sigstore/tuf@4.0.1': dependencies: - '@sigstore/protobuf-specs': 0.4.3 - tuf-js: 3.1.0 + '@sigstore/protobuf-specs': 0.5.0 + tuf-js: 4.1.0 transitivePeerDependencies: - supports-color - '@sigstore/verify@2.1.1': + '@sigstore/verify@3.1.0': dependencies: - '@sigstore/bundle': 3.1.0 - '@sigstore/core': 2.0.0 - '@sigstore/protobuf-specs': 0.4.3 + '@sigstore/bundle': 4.0.0 + '@sigstore/core': 3.1.0 + '@sigstore/protobuf-specs': 0.5.0 '@socket.io/component-emitter@3.1.2': {} @@ -11890,10 +11887,10 @@ snapshots: '@tufjs/canonical-json@2.0.0': {} - '@tufjs/models@3.0.1': + '@tufjs/models@4.1.0': dependencies: '@tufjs/canonical-json': 2.0.0 - minimatch: 9.0.5 + minimatch: 10.1.1 '@types/accepts@1.3.7': dependencies: @@ -12822,7 +12819,7 @@ snapshots: jsonparse: 1.3.1 through: 2.3.8 - abbrev@3.0.1: {} + abbrev@4.0.0: {} abort-controller@3.0.0: dependencies: @@ -13359,20 +13356,19 @@ snapshots: cac@6.7.14: {} - cacache@19.0.1: + cacache@20.0.3: dependencies: - '@npmcli/fs': 4.0.0 + '@npmcli/fs': 5.0.0 fs-minipass: 3.0.3 - glob: 10.4.5 - lru-cache: 10.4.3 + glob: 13.0.0 + lru-cache: 11.2.2 minipass: 7.1.2 minipass-collect: 2.0.1 minipass-flush: 1.0.5 minipass-pipeline: 1.2.4 p-map: 7.0.3 - ssri: 12.0.0 - tar: 7.5.1 - unique-filename: 4.0.0 + ssri: 13.0.0 + unique-filename: 5.0.0 cache-content-type@1.0.1: dependencies: @@ -13465,8 +13461,6 @@ snapshots: chownr@1.1.4: {} - chownr@2.0.0: {} - chownr@3.0.0: {} chrome-launcher@0.15.2: @@ -14719,10 +14713,6 @@ snapshots: jsonfile: 4.0.0 universalify: 0.1.2 - fs-minipass@2.1.0: - dependencies: - minipass: 3.3.6 - fs-minipass@3.0.3: dependencies: minipass: 7.1.2 @@ -14857,6 +14847,12 @@ snapshots: package-json-from-dist: 1.0.1 path-scurry: 2.0.0 + glob@13.0.0: + dependencies: + minimatch: 10.1.1 + minipass: 7.1.2 + path-scurry: 2.0.0 + glob@7.2.3: dependencies: fs.realpath: 1.0.0 @@ -15000,10 +14996,6 @@ snapshots: dependencies: function-bind: 1.1.2 - hosted-git-info@8.1.0: - dependencies: - lru-cache: 10.4.3 - hosted-git-info@9.0.2: dependencies: lru-cache: 11.2.2 @@ -15212,6 +15204,8 @@ snapshots: ini@5.0.0: {} + ini@6.0.0: {} + injection-js@2.5.0: dependencies: tslib: 2.8.1 @@ -15608,7 +15602,7 @@ snapshots: json-parse-even-better-errors@2.3.1: {} - json-parse-even-better-errors@4.0.0: {} + json-parse-even-better-errors@5.0.0: {} json-schema-traverse@0.4.1: {} @@ -16017,19 +16011,19 @@ snapshots: make-error@1.3.6: {} - make-fetch-happen@14.0.3: + make-fetch-happen@15.0.3: dependencies: - '@npmcli/agent': 3.0.0 - cacache: 19.0.1 + '@npmcli/agent': 4.0.0 + cacache: 20.0.3 http-cache-semantics: 4.2.0 minipass: 7.1.2 - minipass-fetch: 4.0.1 + minipass-fetch: 5.0.0 minipass-flush: 1.0.5 minipass-pipeline: 1.2.4 negotiator: 1.0.0 - proc-log: 5.0.0 + proc-log: 6.1.0 promise-retry: 2.0.1 - ssri: 12.0.0 + ssri: 13.0.0 transitivePeerDependencies: - supports-color @@ -16105,6 +16099,10 @@ snapshots: dependencies: '@isaacs/brace-expansion': 5.0.0 + minimatch@10.1.1: + dependencies: + '@isaacs/brace-expansion': 5.0.0 + minimatch@3.1.2: dependencies: brace-expansion: 1.1.12 @@ -16127,7 +16125,7 @@ snapshots: dependencies: minipass: 7.1.2 - minipass-fetch@4.0.1: + minipass-fetch@5.0.0: dependencies: minipass: 7.1.2 minipass-sized: 1.0.3 @@ -16151,15 +16149,8 @@ snapshots: dependencies: yallist: 4.0.0 - minipass@5.0.0: {} - minipass@7.1.2: {} - minizlib@2.1.2: - dependencies: - minipass: 3.3.6 - yallist: 4.0.0 - minizlib@3.1.0: dependencies: minipass: 7.1.2 @@ -16308,18 +16299,18 @@ snapshots: node-gyp-build@4.8.4: {} - node-gyp@11.4.2: + node-gyp@12.1.0: dependencies: env-paths: 2.2.1 exponential-backoff: 3.1.3 graceful-fs: 4.2.11 - make-fetch-happen: 14.0.3 - nopt: 8.1.0 - proc-log: 5.0.0 + make-fetch-happen: 15.0.3 + nopt: 9.0.0 + proc-log: 6.1.0 semver: 7.7.2 - tar: 7.5.1 + tar: 7.5.4 tinyglobby: 0.2.14 - which: 5.0.0 + which: 6.0.0 transitivePeerDependencies: - supports-color @@ -16327,30 +16318,23 @@ snapshots: node-releases@2.0.27: {} - nopt@8.1.0: + nopt@9.0.0: dependencies: - abbrev: 3.0.1 + abbrev: 4.0.0 normalize-path@3.0.0: {} normalize-range@0.1.2: {} - npm-bundled@4.0.0: + npm-bundled@5.0.0: dependencies: - npm-normalize-package-bin: 4.0.0 + npm-normalize-package-bin: 5.0.0 - npm-install-checks@7.1.2: + npm-install-checks@8.0.0: dependencies: semver: 7.7.2 - npm-normalize-package-bin@4.0.0: {} - - npm-package-arg@12.0.2: - dependencies: - hosted-git-info: 8.1.0 - proc-log: 5.0.0 - semver: 7.7.2 - validate-npm-package-name: 6.0.2 + npm-normalize-package-bin@5.0.0: {} npm-package-arg@13.0.0: dependencies: @@ -16364,23 +16348,23 @@ snapshots: ignore-walk: 8.0.0 proc-log: 5.0.0 - npm-pick-manifest@10.0.0: + npm-pick-manifest@11.0.3: dependencies: - npm-install-checks: 7.1.2 - npm-normalize-package-bin: 4.0.0 - npm-package-arg: 12.0.2 + npm-install-checks: 8.0.0 + npm-normalize-package-bin: 5.0.0 + npm-package-arg: 13.0.0 semver: 7.7.2 - npm-registry-fetch@18.0.2: + npm-registry-fetch@19.1.1: dependencies: - '@npmcli/redact': 3.2.2 + '@npmcli/redact': 4.0.0 jsonparse: 1.3.1 - make-fetch-happen: 14.0.3 + make-fetch-happen: 15.0.3 minipass: 7.1.2 - minipass-fetch: 4.0.1 + minipass-fetch: 5.0.0 minizlib: 3.1.0 - npm-package-arg: 12.0.2 - proc-log: 5.0.0 + npm-package-arg: 13.0.0 + proc-log: 6.1.0 transitivePeerDependencies: - supports-color @@ -16575,25 +16559,25 @@ snapshots: package-json-from-dist@1.0.1: {} - pacote@21.0.0: + pacote@21.0.4: dependencies: - '@npmcli/git': 6.0.3 - '@npmcli/installed-package-contents': 3.0.0 - '@npmcli/package-json': 6.2.0 - '@npmcli/promise-spawn': 8.0.3 - '@npmcli/run-script': 9.1.0 - cacache: 19.0.1 + '@npmcli/git': 7.0.1 + '@npmcli/installed-package-contents': 4.0.0 + '@npmcli/package-json': 7.0.4 + '@npmcli/promise-spawn': 9.0.1 + '@npmcli/run-script': 10.0.3 + cacache: 20.0.3 fs-minipass: 3.0.3 minipass: 7.1.2 - npm-package-arg: 12.0.2 + npm-package-arg: 13.0.0 npm-packlist: 10.0.2 - npm-pick-manifest: 10.0.0 - npm-registry-fetch: 18.0.2 - proc-log: 5.0.0 + npm-pick-manifest: 11.0.3 + npm-registry-fetch: 19.1.1 + proc-log: 6.1.0 promise-retry: 2.0.1 - sigstore: 3.1.0 - ssri: 12.0.0 - tar: 6.2.1 + sigstore: 4.1.0 + ssri: 13.0.0 + tar: 7.5.1 transitivePeerDependencies: - supports-color @@ -16803,6 +16787,8 @@ snapshots: proc-log@5.0.0: {} + proc-log@6.1.0: {} + process-nextick-args@2.0.1: {} process-warning@1.0.0: {} @@ -17548,14 +17534,14 @@ snapshots: signal-exit@4.1.0: {} - sigstore@3.1.0: + sigstore@4.1.0: dependencies: - '@sigstore/bundle': 3.1.0 - '@sigstore/core': 2.0.0 - '@sigstore/protobuf-specs': 0.4.3 - '@sigstore/sign': 3.1.0 - '@sigstore/tuf': 3.1.1 - '@sigstore/verify': 2.1.1 + '@sigstore/bundle': 4.0.0 + '@sigstore/core': 3.1.0 + '@sigstore/protobuf-specs': 0.5.0 + '@sigstore/sign': 4.1.0 + '@sigstore/tuf': 4.0.1 + '@sigstore/verify': 3.1.0 transitivePeerDependencies: - supports-color @@ -17736,7 +17722,7 @@ snapshots: dependencies: minipass: 7.1.2 - ssri@12.0.0: + ssri@13.0.0: dependencies: minipass: 7.1.2 @@ -17927,16 +17913,15 @@ snapshots: - bare-abort-controller - react-native-b4a - tar@6.2.1: + tar@7.5.1: dependencies: - chownr: 2.0.0 - fs-minipass: 2.1.0 - minipass: 5.0.0 - minizlib: 2.1.2 - mkdirp: 1.0.4 - yallist: 4.0.0 + '@isaacs/fs-minipass': 4.0.1 + chownr: 3.0.0 + minipass: 7.1.2 + minizlib: 3.1.0 + yallist: 5.0.0 - tar@7.5.1: + tar@7.5.4: dependencies: '@isaacs/fs-minipass': 4.0.1 chownr: 3.0.0 @@ -18101,11 +18086,11 @@ snapshots: optionalDependencies: fsevents: 2.3.3 - tuf-js@3.1.0: + tuf-js@4.1.0: dependencies: - '@tufjs/models': 3.0.1 + '@tufjs/models': 4.1.0 debug: 4.4.3(supports-color@10.2.2) - make-fetch-happen: 14.0.3 + make-fetch-happen: 15.0.3 transitivePeerDependencies: - supports-color @@ -18239,11 +18224,11 @@ snapshots: pako: 0.2.9 tiny-inflate: 1.0.3 - unique-filename@4.0.0: + unique-filename@5.0.0: dependencies: - unique-slug: 5.0.0 + unique-slug: 6.0.0 - unique-slug@5.0.0: + unique-slug@6.0.0: dependencies: imurmurhash: 0.1.4 @@ -18701,6 +18686,10 @@ snapshots: dependencies: isexe: 3.1.1 + which@6.0.0: + dependencies: + isexe: 3.1.1 + why-is-node-running@2.3.0: dependencies: siginfo: 2.0.0 From 279b1adcf9dd2918682f3e4897494eb7ca5769fd Mon Sep 17 00:00:00 2001 From: Charles Lyding <19598772+clydin@users.noreply.github.com> Date: Wed, 21 Jan 2026 09:36:16 -0500 Subject: [PATCH 35/52] release: cut the v20.3.15 release --- CHANGELOG.md | 18 ++++++++++++++++++ package.json | 2 +- 2 files changed, 19 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 55d4a2fc9d24..1d762a2ec9e6 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,21 @@ + + +# 20.3.15 (2026-01-21) + +### @angular/cli + +| Commit | Type | Description | +| --------------------------------------------------------------------------------------------------- | ---- | ------------------------ | +| [795d65413](https://github.com/angular/angular-cli/commit/795d654138701a03d4d793d3299ff4f33e427a03) | fix | update pacote to v21.0.4 | + +### @angular-devkit/build-angular + +| Commit | Type | Description | +| --------------------------------------------------------------------------------------------------- | ---- | --------------------------------- | +| [ffc72cbc5](https://github.com/angular/angular-cli/commit/ffc72cbc52e23cb545476b3fdefc7e5f170eb55d) | fix | update webpack to version 5.104.1 | + + + # 20.3.14 (2026-01-07) diff --git a/package.json b/package.json index 76d5deb23264..dbc169016987 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@angular/devkit-repo", - "version": "20.3.14", + "version": "20.3.15", "private": true, "description": "Software Development Kit for Angular", "keywords": [ From 656888a250af060c110ae87024b0e475b079c23d Mon Sep 17 00:00:00 2001 From: Alan Agius <17563226+alan-agius4@users.noreply.github.com> Date: Fri, 6 Feb 2026 10:50:46 +0000 Subject: [PATCH 36/52] fix(@angular/cli): update dependency @modelcontextprotocol/sdk to v1.26.0 Fixes https://github.com/modelcontextprotocol/typescript-sdk/security/advisories/GHSA-345p-7cg4-v4c7 --- packages/angular/cli/package.json | 2 +- pnpm-lock.yaml | 122 ++++++++++++++++++++++++------ 2 files changed, 98 insertions(+), 26 deletions(-) diff --git a/packages/angular/cli/package.json b/packages/angular/cli/package.json index b59dedcaf33e..3668dbef400a 100644 --- a/packages/angular/cli/package.json +++ b/packages/angular/cli/package.json @@ -27,7 +27,7 @@ "@angular-devkit/schematics": "workspace:0.0.0-PLACEHOLDER", "@inquirer/prompts": "7.8.2", "@listr2/prompt-adapter-inquirer": "3.0.1", - "@modelcontextprotocol/sdk": "1.25.2", + "@modelcontextprotocol/sdk": "1.26.0", "@schematics/angular": "workspace:0.0.0-PLACEHOLDER", "@yarnpkg/lockfile": "1.1.0", "algoliasearch": "5.35.0", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index b305c98274bd..5284747abb92 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -48,7 +48,7 @@ importers: version: 20.2.10(72d1932aa29c0670c8359e3ed8a5ff55) '@angular/ng-dev': specifier: https://github.com/angular/dev-infra-private-ng-dev-builds.git#b69a61793bd6ba935af262297688408d0b48252e - version: https://codeload.github.com/angular/dev-infra-private-ng-dev-builds/tar.gz/b69a61793bd6ba935af262297688408d0b48252e(@modelcontextprotocol/sdk@1.25.2(zod@4.1.13)) + version: https://codeload.github.com/angular/dev-infra-private-ng-dev-builds/tar.gz/b69a61793bd6ba935af262297688408d0b48252e(@modelcontextprotocol/sdk@1.26.0(zod@4.1.13)) '@angular/platform-browser': specifier: 20.3.7 version: 20.3.7(@angular/animations@20.3.7(@angular/core@20.3.7(@angular/compiler@20.3.7)(rxjs@7.8.2)(zone.js@0.15.1)))(@angular/common@20.3.7(@angular/core@20.3.7(@angular/compiler@20.3.7)(rxjs@7.8.2)(zone.js@0.15.1))(rxjs@7.8.2))(@angular/core@20.3.7(@angular/compiler@20.3.7)(rxjs@7.8.2)(zone.js@0.15.1)) @@ -472,8 +472,8 @@ importers: specifier: 3.0.1 version: 3.0.1(@inquirer/prompts@7.8.2(@types/node@24.9.1))(@types/node@24.9.1)(listr2@9.0.1) '@modelcontextprotocol/sdk': - specifier: 1.25.2 - version: 1.25.2(zod@4.1.13) + specifier: 1.26.0 + version: 1.26.0(zod@4.1.13) '@schematics/angular': specifier: workspace:0.0.0-PLACEHOLDER version: link:../../schematics/angular @@ -2143,8 +2143,8 @@ packages: '@hapi/bourne@3.0.0': resolution: {integrity: sha512-Waj1cwPXJDucOib4a3bAISsKJVb15MKi9IvmTI/7ssVEm6sywXGjVJDhl6/umt1pK1ZS7PacXU3A1PmFKHEZ2w==} - '@hono/node-server@1.19.7': - resolution: {integrity: sha512-vUcD0uauS7EU2caukW8z5lJKtoGMokxNbJtBiwHgpqxEXokaHCBkQUmCHhjFB1VUTWdqj25QoMkMKzgjq+uhrw==} + '@hono/node-server@1.19.9': + resolution: {integrity: sha512-vHL6w3ecZsky+8P5MD+eFfaGTyCeOHUIFYMGpQGbrBTSmNNoxv0if69rEZ5giu36weC5saFuznL411gRX7bJDw==} engines: {node: '>=18.14.1'} peerDependencies: hono: ^4 @@ -2547,8 +2547,8 @@ packages: cpu: [x64] os: [win32] - '@modelcontextprotocol/sdk@1.25.2': - resolution: {integrity: sha512-LZFeo4F9M5qOhC/Uc1aQSrBHxMrvxett+9KLHt7OhcExtoiRN9DKgbZffMP/nxjutWDQpfMDfP3nkHI4X9ijww==} + '@modelcontextprotocol/sdk@1.26.0': + resolution: {integrity: sha512-Y5RmPncpiDtTXDbLKswIJzTqu2hyBKxTNsgKqKclDbhIgg1wgtf1fRuvxgTnRfcnxtvvgbIEcqUOzZrJ6iSReg==} engines: {node: '>=18'} peerDependencies: '@cfworker/json-schema': ^4.1.1 @@ -4353,6 +4353,10 @@ packages: resolution: {integrity: sha512-02qvAaxv8tp7fBa/mw1ga98OGm+eCbqzJOKoRt70sLmfEEi+jyBYVTDGfCL/k06/4EMk/z01gCe7HoCH/f2LTg==} engines: {node: '>=18'} + body-parser@2.2.2: + resolution: {integrity: sha512-oP5VkATKlNwcgvxi0vM0p/D3n2C3EReYVX+DNYs5TjZFn/oQt2j+4sVJtSMr18pdRr8wjTcBl6LoV+FUwzPmNA==} + engines: {node: '>=18'} + bonjour-service@1.3.0: resolution: {integrity: sha512-3YuAUiSkWykd+2Azjgyxei8OWf8thdn8AITIog2M4UICzoqfjlqr64WIjEXZllf/W6vK1goqleSR6brGomxQqA==} @@ -5380,8 +5384,8 @@ packages: express-rate-limit@5.5.1: resolution: {integrity: sha512-MTjE2eIbHv5DyfuFz4zLYWxpqVhEhkTiwFGuB74Q9CSou2WHO52nlE5y3Zlg6SIsiYUIPj6ifFxnkPz6O3sIUg==} - express-rate-limit@7.5.1: - resolution: {integrity: sha512-7iN8iPMDzOMHPUYllBEsQdWVB6fPDMPqwjBaFrgr4Jgr/+okjvzAy+UHlYYL/Vs0OsOrMkwS6PJDkFlJwoxUnw==} + express-rate-limit@8.2.1: + resolution: {integrity: sha512-PCZEIEIxqwhzw4KF0n7QF4QqruVTcF73O5kFKUnGOyjbCCgizBBiFaYpd/fnBLUMPw/BWw9OsiN7GgrNYr7j6g==} engines: {node: '>= 16'} peerDependencies: express: '>= 4.11' @@ -5394,6 +5398,10 @@ packages: resolution: {integrity: sha512-DT9ck5YIRU+8GYzzU5kT3eHGA5iL+1Zd0EutOmTE9Dtk+Tvuzd23VBU+ec7HPNSTxXYO55gPV/hq4pSBJDjFpA==} engines: {node: '>= 18'} + express@5.2.1: + resolution: {integrity: sha512-hIS4idWWai69NezIdRt2xFVofaF4j+6INOpJlVOLDO8zXGpUVEVzIYk12UUi2JzjEzWL3IOAxcTubgz9Po0yXw==} + engines: {node: '>= 18'} + extend@3.0.2: resolution: {integrity: sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==} @@ -5811,6 +5819,10 @@ packages: resolution: {integrity: sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==} engines: {node: '>= 0.4'} + hono@4.11.7: + resolution: {integrity: sha512-l7qMiNee7t82bH3SeyUCt9UF15EVmaBvsppY2zQtrbIhl/yzBTny+YUxsVjSjQ6gaqaeVtZmGocom8TzBlA4Yw==} + engines: {node: '>=16.9.0'} + hosted-git-info@9.0.2: resolution: {integrity: sha512-M422h7o/BR3rmCQ8UHi7cyyMqKltdP9Uo+J2fXK+RSAY+wTcKOIRyhTuKv4qn+DJf3g+PL890AzId5KZpX+CBg==} engines: {node: ^20.17.0 || >=22.9.0} @@ -7666,6 +7678,10 @@ packages: resolution: {integrity: sha512-YWWTjgABSKcvs/nWBi9PycY/JiPJqOD4JA6o9Sej2AtvSGarXxKC3OQSk4pAarbdQlKAh5D4FCQkJNkW+GAn3w==} engines: {node: '>=0.6'} + qs@6.14.1: + resolution: {integrity: sha512-4EK3+xJl8Ts67nLYNwqw/dsFVnCf+qR7RgXSK9jEEm9unao3njwMDdmsdvoKBKHzxd7tCYz5e5M+SnMjdtXGQQ==} + engines: {node: '>=0.6'} + qs@6.5.3: resolution: {integrity: sha512-qxXIEh4pCGfHICj1mAJQ2/2XVZkjCDTcEgfoSQxc/fYivUZxTkk7L3bDBJSoNrEzXI17oUO5Dp07ktqE5KzczA==} engines: {node: '>=0.6'} @@ -9235,8 +9251,8 @@ packages: resolution: {integrity: sha512-U/PBtDf35ff0D8X8D0jfdzHYEPFxAI7jJlxZXwCSez5M3190m+QobIfh+sWDWSHMCWWJN2AWamkegn6vr6YBTw==} engines: {node: '>=18'} - zod-to-json-schema@3.25.0: - resolution: {integrity: sha512-HvWtU2UG41LALjajJrML6uQejQhNJx+JBO9IflpSja4R03iNWfKXrj6W2h7ljuLyc1nKS+9yDyL/9tD1U/yBnQ==} + zod-to-json-schema@3.25.1: + resolution: {integrity: sha512-pM/SU9d3YAggzi6MtR4h7ruuQlqKtad8e9S0fmxcMi+ueAK5Korys/aWcV9LIIHTVbj01NdzxcnXSN+O74ZIVA==} peerDependencies: zod: ^3.25 || ^4 @@ -9432,11 +9448,11 @@ 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/b69a61793bd6ba935af262297688408d0b48252e(@modelcontextprotocol/sdk@1.25.2(zod@4.1.13))': + '@angular/ng-dev@https://codeload.github.com/angular/dev-infra-private-ng-dev-builds/tar.gz/b69a61793bd6ba935af262297688408d0b48252e(@modelcontextprotocol/sdk@1.26.0(zod@4.1.13))': dependencies: '@actions/core': 1.11.1 '@google-cloud/spanner': 8.0.0(supports-color@10.2.2) - '@google/genai': 1.26.0(@modelcontextprotocol/sdk@1.25.2(zod@4.1.13))(bufferutil@4.0.9)(supports-color@10.2.2)(utf-8-validate@6.0.5) + '@google/genai': 1.26.0(@modelcontextprotocol/sdk@1.26.0(zod@4.1.13))(bufferutil@4.0.9)(supports-color@10.2.2)(utf-8-validate@6.0.5) '@inquirer/prompts': 7.9.0(@types/node@24.9.1) '@inquirer/type': 3.0.9(@types/node@24.9.1) '@octokit/auth-app': 8.1.1 @@ -10771,12 +10787,12 @@ snapshots: transitivePeerDependencies: - supports-color - '@google/genai@1.26.0(@modelcontextprotocol/sdk@1.25.2(zod@4.1.13))(bufferutil@4.0.9)(supports-color@10.2.2)(utf-8-validate@6.0.5)': + '@google/genai@1.26.0(@modelcontextprotocol/sdk@1.26.0(zod@4.1.13))(bufferutil@4.0.9)(supports-color@10.2.2)(utf-8-validate@6.0.5)': dependencies: google-auth-library: 10.4.0(supports-color@10.2.2) ws: 8.18.3(bufferutil@4.0.9)(utf-8-validate@6.0.5) optionalDependencies: - '@modelcontextprotocol/sdk': 1.25.2(zod@4.1.13) + '@modelcontextprotocol/sdk': 1.26.0(zod@4.1.13) transitivePeerDependencies: - bufferutil - supports-color @@ -10808,7 +10824,9 @@ snapshots: '@hapi/bourne@3.0.0': {} - '@hono/node-server@1.19.7': {} + '@hono/node-server@1.19.9(hono@4.11.7)': + dependencies: + hono: 4.11.7 '@humanfs/core@0.19.1': {} @@ -11177,9 +11195,9 @@ snapshots: '@lmdb/lmdb-win32-x64@3.4.2': optional: true - '@modelcontextprotocol/sdk@1.25.2(zod@4.1.13)': + '@modelcontextprotocol/sdk@1.26.0(zod@4.1.13)': dependencies: - '@hono/node-server': 1.19.7 + '@hono/node-server': 1.19.9(hono@4.11.7) ajv: 8.17.1 ajv-formats: 3.0.1(ajv@8.17.1) content-type: 1.0.5 @@ -11187,16 +11205,16 @@ snapshots: cross-spawn: 7.0.6 eventsource: 3.0.7 eventsource-parser: 3.0.6 - express: 5.1.0 - express-rate-limit: 7.5.1(express@5.1.0) + express: 5.2.1 + express-rate-limit: 8.2.1(express@5.2.1) + hono: 4.11.7 jose: 6.1.3 json-schema-typed: 8.0.2 pkce-challenge: 5.0.0 raw-body: 3.0.1 zod: 4.1.13 - zod-to-json-schema: 3.25.0(zod@4.1.13) + zod-to-json-schema: 3.25.1(zod@4.1.13) transitivePeerDependencies: - - hono - supports-color '@msgpackr-extract/msgpackr-extract-darwin-arm64@3.0.3': @@ -13222,6 +13240,20 @@ snapshots: transitivePeerDependencies: - supports-color + body-parser@2.2.2: + dependencies: + bytes: 3.1.2 + content-type: 1.0.5 + debug: 4.4.3(supports-color@10.2.2) + http-errors: 2.0.0 + iconv-lite: 0.7.0 + on-finished: 2.4.1 + qs: 6.14.1 + raw-body: 3.0.1 + type-is: 2.0.1 + transitivePeerDependencies: + - supports-color + bonjour-service@1.3.0: dependencies: fast-deep-equal: 3.1.3 @@ -14400,9 +14432,10 @@ snapshots: express-rate-limit@5.5.1: {} - express-rate-limit@7.5.1(express@5.1.0): + express-rate-limit@8.2.1(express@5.2.1): dependencies: - express: 5.1.0 + express: 5.2.1 + ip-address: 10.0.1 express@4.21.2: dependencies: @@ -14472,6 +14505,39 @@ snapshots: transitivePeerDependencies: - supports-color + express@5.2.1: + dependencies: + accepts: 2.0.0 + body-parser: 2.2.2 + content-disposition: 1.0.0 + content-type: 1.0.5 + cookie: 0.7.2 + cookie-signature: 1.2.2 + debug: 4.4.3(supports-color@10.2.2) + depd: 2.0.0 + encodeurl: 2.0.0 + escape-html: 1.0.3 + etag: 1.8.1 + finalhandler: 2.1.0 + fresh: 2.0.0 + http-errors: 2.0.0 + merge-descriptors: 2.0.0 + mime-types: 3.0.1 + on-finished: 2.4.1 + once: 1.4.0 + parseurl: 1.3.3 + proxy-addr: 2.0.7 + qs: 6.14.0 + range-parser: 1.2.1 + router: 2.2.0 + send: 1.2.0 + serve-static: 2.2.0 + statuses: 2.0.2 + type-is: 2.0.1 + vary: 1.1.2 + transitivePeerDependencies: + - supports-color + extend@3.0.2: {} extract-zip@2.0.1: @@ -14996,6 +15062,8 @@ snapshots: dependencies: function-bind: 1.1.2 + hono@4.11.7: {} + hosted-git-info@9.0.2: dependencies: lru-cache: 11.2.2 @@ -16951,6 +17019,10 @@ snapshots: dependencies: side-channel: 1.1.0 + qs@6.14.1: + dependencies: + side-channel: 1.1.0 + qs@6.5.3: {} queue-microtask@1.2.3: {} @@ -18846,7 +18918,7 @@ snapshots: yoctocolors-cjs@2.1.3: {} - zod-to-json-schema@3.25.0(zod@4.1.13): + zod-to-json-schema@3.25.1(zod@4.1.13): dependencies: zod: 4.1.13 From 0f02acac4f34609350f7ac0198ce6bf5279967a9 Mon Sep 17 00:00:00 2001 From: Charles Lyding <19598772+clydin@users.noreply.github.com> Date: Mon, 9 Feb 2026 07:39:21 -0500 Subject: [PATCH 37/52] build: update webpack to v5.105.0 --- .../angular_devkit/build_angular/package.json | 2 +- .../angular_devkit/build_webpack/package.json | 2 +- packages/ngtools/webpack/package.json | 2 +- packages/ngtools/webpack/src/paths-plugin.ts | 3 - pnpm-lock.yaml | 119 ++++++++++-------- 5 files changed, 67 insertions(+), 61 deletions(-) diff --git a/packages/angular_devkit/build_angular/package.json b/packages/angular_devkit/build_angular/package.json index 4696765d809c..e4253b78d121 100644 --- a/packages/angular_devkit/build_angular/package.json +++ b/packages/angular_devkit/build_angular/package.json @@ -55,7 +55,7 @@ "terser": "5.43.1", "tree-kill": "1.2.2", "tslib": "2.8.1", - "webpack": "5.104.1", + "webpack": "5.105.0", "webpack-dev-middleware": "7.4.2", "webpack-dev-server": "5.2.2", "webpack-merge": "6.0.1", diff --git a/packages/angular_devkit/build_webpack/package.json b/packages/angular_devkit/build_webpack/package.json index 316b68533bf8..5af189c9709c 100644 --- a/packages/angular_devkit/build_webpack/package.json +++ b/packages/angular_devkit/build_webpack/package.json @@ -22,7 +22,7 @@ "devDependencies": { "@angular-devkit/core": "workspace:0.0.0-PLACEHOLDER", "@ngtools/webpack": "workspace:0.0.0-PLACEHOLDER", - "webpack": "5.104.1", + "webpack": "5.105.0", "webpack-dev-server": "5.2.2" }, "peerDependencies": { diff --git a/packages/ngtools/webpack/package.json b/packages/ngtools/webpack/package.json index 9a127f0bf8ea..8e4d32703e20 100644 --- a/packages/ngtools/webpack/package.json +++ b/packages/ngtools/webpack/package.json @@ -30,6 +30,6 @@ "@angular/compiler": "20.3.7", "@angular/compiler-cli": "20.3.7", "typescript": "5.9.2", - "webpack": "5.104.1" + "webpack": "5.105.0" } } diff --git a/packages/ngtools/webpack/src/paths-plugin.ts b/packages/ngtools/webpack/src/paths-plugin.ts index a5e581b63c4d..612d70d4ad6e 100644 --- a/packages/ngtools/webpack/src/paths-plugin.ts +++ b/packages/ngtools/webpack/src/paths-plugin.ts @@ -17,9 +17,6 @@ export interface TypeScriptPathsPluginOptions extends Pick[4]>[2]>; interface PathPluginResolverRequest extends ResolverRequest { - context?: { - issuer?: string; - }; typescriptPathMapped?: boolean; } diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 5284747abb92..80137681a0e6 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -643,16 +643,16 @@ importers: version: 10.4.21(postcss@8.5.6) babel-loader: specifier: 10.0.0 - version: 10.0.0(@babel/core@7.28.3)(webpack@5.104.1(esbuild@0.25.9)) + version: 10.0.0(@babel/core@7.28.3)(webpack@5.105.0(esbuild@0.25.9)) browserslist: specifier: ^4.21.5 version: 4.26.3 copy-webpack-plugin: specifier: 13.0.1 - version: 13.0.1(webpack@5.104.1(esbuild@0.25.9)) + version: 13.0.1(webpack@5.105.0(esbuild@0.25.9)) css-loader: specifier: 7.1.2 - version: 7.1.2(webpack@5.104.1(esbuild@0.25.9)) + version: 7.1.2(webpack@5.105.0(esbuild@0.25.9)) esbuild-wasm: specifier: 0.25.9 version: 0.25.9 @@ -676,16 +676,16 @@ importers: version: 4.4.0 less-loader: specifier: 12.3.0 - version: 12.3.0(less@4.4.0)(webpack@5.104.1(esbuild@0.25.9)) + version: 12.3.0(less@4.4.0)(webpack@5.105.0(esbuild@0.25.9)) license-webpack-plugin: specifier: 4.0.2 - version: 4.0.2(webpack@5.104.1(esbuild@0.25.9)) + version: 4.0.2(webpack@5.105.0(esbuild@0.25.9)) loader-utils: specifier: 3.3.1 version: 3.3.1 mini-css-extract-plugin: specifier: 2.9.4 - version: 2.9.4(webpack@5.104.1(esbuild@0.25.9)) + version: 2.9.4(webpack@5.105.0(esbuild@0.25.9)) open: specifier: 10.2.0 version: 10.2.0 @@ -703,7 +703,7 @@ importers: version: 8.5.6 postcss-loader: specifier: 8.1.1 - version: 8.1.1(postcss@8.5.6)(typescript@5.9.2)(webpack@5.104.1(esbuild@0.25.9)) + version: 8.1.1(postcss@8.5.6)(typescript@5.9.2)(webpack@5.105.0(esbuild@0.25.9)) resolve-url-loader: specifier: 5.0.0 version: 5.0.0 @@ -715,13 +715,13 @@ importers: version: 1.90.0 sass-loader: specifier: 16.0.5 - version: 16.0.5(sass@1.90.0)(webpack@5.104.1(esbuild@0.25.9)) + version: 16.0.5(sass@1.90.0)(webpack@5.105.0(esbuild@0.25.9)) semver: specifier: 7.7.2 version: 7.7.2 source-map-loader: specifier: 5.0.0 - version: 5.0.0(webpack@5.104.1(esbuild@0.25.9)) + version: 5.0.0(webpack@5.105.0(esbuild@0.25.9)) source-map-support: specifier: 0.5.21 version: 0.5.21 @@ -735,20 +735,20 @@ importers: specifier: 2.8.1 version: 2.8.1 webpack: - specifier: 5.104.1 - version: 5.104.1(esbuild@0.25.9) + specifier: 5.105.0 + version: 5.105.0(esbuild@0.25.9) webpack-dev-middleware: specifier: 7.4.2 - version: 7.4.2(webpack@5.104.1(esbuild@0.25.9)) + version: 7.4.2(webpack@5.105.0(esbuild@0.25.9)) webpack-dev-server: specifier: 5.2.2 - version: 5.2.2(bufferutil@4.0.9)(utf-8-validate@6.0.5)(webpack@5.104.1(esbuild@0.25.9)) + version: 5.2.2(bufferutil@4.0.9)(utf-8-validate@6.0.5)(webpack@5.105.0(esbuild@0.25.9)) webpack-merge: specifier: 6.0.1 version: 6.0.1 webpack-subresource-integrity: specifier: 5.1.0 - version: 5.1.0(webpack@5.104.1(esbuild@0.25.9)) + version: 5.1.0(webpack@5.105.0(esbuild@0.25.9)) devDependencies: '@angular/ssr': specifier: workspace:* @@ -786,11 +786,11 @@ importers: specifier: workspace:0.0.0-PLACEHOLDER version: link:../../ngtools/webpack webpack: - specifier: 5.104.1 - version: 5.104.1(esbuild@0.25.9) + specifier: 5.105.0 + version: 5.105.0(esbuild@0.25.9) webpack-dev-server: specifier: 5.2.2 - version: 5.2.2(bufferutil@4.0.9)(utf-8-validate@6.0.5)(webpack@5.104.1(esbuild@0.25.9)) + version: 5.2.2(bufferutil@4.0.9)(utf-8-validate@6.0.5)(webpack@5.105.0(esbuild@0.25.9)) packages/angular_devkit/core: dependencies: @@ -868,8 +868,8 @@ importers: specifier: 5.9.2 version: 5.9.2 webpack: - specifier: 5.104.1 - version: 5.104.1(esbuild@0.25.9) + specifier: 5.105.0 + version: 5.105.0(esbuild@0.25.9) packages/schematics/angular: dependencies: @@ -5116,8 +5116,8 @@ packages: resolution: {integrity: sha512-ZCkIjSYNDyGn0R6ewHDtXgns/Zre/NT6Agvq1/WobF7JXgFff4SeDroKiCO3fNJreU9YG429Sc81o4w5ok/W5g==} engines: {node: '>=10.2.0'} - enhanced-resolve@5.18.3: - resolution: {integrity: sha512-d4lC8xfavMeBjzGr2vECC3fsGXziXZQyJxD868h2M/mBI3PwAuODxAkLkq5HYuvrPYcUtiLzsTo8U3PgX3Ocww==} + enhanced-resolve@5.19.0: + resolution: {integrity: sha512-phv3E1Xl4tQOShqSte26C7Fl84EwUdZsyOuSSk9qtAGyyQs2s3jJzComh+Abf4g187lUUAvH+H26omrqia2aGg==} engines: {node: '>=10.13.0'} ent@2.2.2: @@ -8918,6 +8918,10 @@ packages: resolution: {integrity: sha512-c5EGNOiyxxV5qmTtAB7rbiXxi1ooX1pQKMLX/MIabJjRA0SJBQOjKF+KSVfHkr9U1cADPon0mRiVe/riyaiDUA==} engines: {node: '>=10.13.0'} + watchpack@2.5.1: + resolution: {integrity: sha512-Zn5uXdcFNIA1+1Ei5McRd+iRzfhENPCe7LeABkJtNulSxjma+l7ltNx55BWZkRlwRnpOgHqxnjyaDgJnNXnqzg==} + engines: {node: '>=10.13.0'} + wbuf@1.7.3: resolution: {integrity: sha512-O84QOnr0icsbFGLS0O3bI5FswxzRr8/gHwWkDlQFskhSPryQXvrTMxjxGP4+iWYoauLoBvfDpkrOauZ+0iZpDA==} @@ -8990,8 +8994,8 @@ packages: html-webpack-plugin: optional: true - webpack@5.104.1: - resolution: {integrity: sha512-Qphch25abbMNtekmEGJmeRUhLDbe+QfiWTiqpKYkpCOWY64v9eyl+KRRLmqOFA2AvKPpc9DC6+u2n76tQLBoaA==} + webpack@5.105.0: + resolution: {integrity: sha512-gX/dMkRQc7QOMzgTe6KsYFM7DxeIONQSui1s0n/0xht36HvrgbxtM1xBlgx596NbpHuQU8P7QpKwrZYwUX48nw==} engines: {node: '>=10.13.0'} hasBin: true peerDependencies: @@ -13089,11 +13093,11 @@ snapshots: b4a@1.7.3: {} - babel-loader@10.0.0(@babel/core@7.28.3)(webpack@5.104.1(esbuild@0.25.9)): + babel-loader@10.0.0(@babel/core@7.28.3)(webpack@5.105.0(esbuild@0.25.9)): dependencies: '@babel/core': 7.28.3 find-up: 5.0.0 - webpack: 5.104.1(esbuild@0.25.9) + webpack: 5.105.0(esbuild@0.25.9) babel-plugin-polyfill-corejs2@0.4.14(@babel/core@7.28.3): dependencies: @@ -13696,14 +13700,14 @@ snapshots: dependencies: is-what: 3.14.1 - copy-webpack-plugin@13.0.1(webpack@5.104.1(esbuild@0.25.9)): + copy-webpack-plugin@13.0.1(webpack@5.105.0(esbuild@0.25.9)): dependencies: glob-parent: 6.0.2 normalize-path: 3.0.0 schema-utils: 4.3.3 serialize-javascript: 6.0.2 tinyglobby: 0.2.14 - webpack: 5.104.1(esbuild@0.25.9) + webpack: 5.105.0(esbuild@0.25.9) core-js-compat@3.46.0: dependencies: @@ -13747,7 +13751,7 @@ snapshots: shebang-command: 2.0.0 which: 2.0.2 - css-loader@7.1.2(webpack@5.104.1(esbuild@0.25.9)): + css-loader@7.1.2(webpack@5.105.0(esbuild@0.25.9)): dependencies: icss-utils: 5.1.0(postcss@8.5.6) postcss: 8.5.6 @@ -13758,7 +13762,7 @@ snapshots: postcss-value-parser: 4.2.0 semver: 7.7.2 optionalDependencies: - webpack: 5.104.1(esbuild@0.25.9) + webpack: 5.105.0(esbuild@0.25.9) css-select@6.0.0: dependencies: @@ -14075,7 +14079,7 @@ snapshots: - supports-color - utf-8-validate - enhanced-resolve@5.18.3: + enhanced-resolve@5.19.0: dependencies: graceful-fs: 4.2.11 tapable: 2.3.0 @@ -15889,11 +15893,11 @@ snapshots: picocolors: 1.1.1 shell-quote: 1.8.3 - less-loader@12.3.0(less@4.4.0)(webpack@5.104.1(esbuild@0.25.9)): + less-loader@12.3.0(less@4.4.0)(webpack@5.105.0(esbuild@0.25.9)): dependencies: less: 4.4.0 optionalDependencies: - webpack: 5.104.1(esbuild@0.25.9) + webpack: 5.105.0(esbuild@0.25.9) less@4.4.0: dependencies: @@ -15914,11 +15918,11 @@ snapshots: prelude-ls: 1.2.1 type-check: 0.4.0 - license-webpack-plugin@4.0.2(webpack@5.104.1(esbuild@0.25.9)): + license-webpack-plugin@4.0.2(webpack@5.105.0(esbuild@0.25.9)): dependencies: webpack-sources: 3.3.3 optionalDependencies: - webpack: 5.104.1(esbuild@0.25.9) + webpack: 5.105.0(esbuild@0.25.9) lie@3.3.0: dependencies: @@ -16151,11 +16155,11 @@ snapshots: mimic-function@5.0.1: {} - mini-css-extract-plugin@2.9.4(webpack@5.104.1(esbuild@0.25.9)): + mini-css-extract-plugin@2.9.4(webpack@5.105.0(esbuild@0.25.9)): dependencies: schema-utils: 4.3.3 tapable: 2.3.0 - webpack: 5.104.1(esbuild@0.25.9) + webpack: 5.105.0(esbuild@0.25.9) minimalistic-assert@1.0.1: {} @@ -16802,14 +16806,14 @@ snapshots: possible-typed-array-names@1.1.0: {} - postcss-loader@8.1.1(postcss@8.5.6)(typescript@5.9.2)(webpack@5.104.1(esbuild@0.25.9)): + postcss-loader@8.1.1(postcss@8.5.6)(typescript@5.9.2)(webpack@5.105.0(esbuild@0.25.9)): dependencies: cosmiconfig: 9.0.0(typescript@5.9.2) jiti: 1.21.7 postcss: 8.5.6 semver: 7.7.2 optionalDependencies: - webpack: 5.104.1(esbuild@0.25.9) + webpack: 5.105.0(esbuild@0.25.9) transitivePeerDependencies: - typescript @@ -17381,12 +17385,12 @@ snapshots: safer-buffer@2.1.2: {} - sass-loader@16.0.5(sass@1.90.0)(webpack@5.104.1(esbuild@0.25.9)): + sass-loader@16.0.5(sass@1.90.0)(webpack@5.105.0(esbuild@0.25.9)): dependencies: neo-async: 2.6.2 optionalDependencies: sass: 1.90.0 - webpack: 5.104.1(esbuild@0.25.9) + webpack: 5.105.0(esbuild@0.25.9) sass@1.90.0: dependencies: @@ -17707,11 +17711,11 @@ snapshots: source-map-js@1.2.1: {} - source-map-loader@5.0.0(webpack@5.104.1(esbuild@0.25.9)): + source-map-loader@5.0.0(webpack@5.105.0(esbuild@0.25.9)): dependencies: iconv-lite: 0.6.3 source-map-js: 1.2.1 - webpack: 5.104.1(esbuild@0.25.9) + webpack: 5.105.0(esbuild@0.25.9) source-map-support@0.4.18: dependencies: @@ -18010,14 +18014,14 @@ snapshots: transitivePeerDependencies: - supports-color - terser-webpack-plugin@5.3.16(esbuild@0.25.9)(webpack@5.104.1(esbuild@0.25.9)): + terser-webpack-plugin@5.3.16(esbuild@0.25.9)(webpack@5.105.0(esbuild@0.25.9)): dependencies: '@jridgewell/trace-mapping': 0.3.31 jest-worker: 27.5.1 schema-utils: 4.3.3 serialize-javascript: 6.0.2 terser: 5.43.1 - webpack: 5.104.1(esbuild@0.25.9) + webpack: 5.105.0(esbuild@0.25.9) optionalDependencies: esbuild: 0.25.9 @@ -18549,6 +18553,11 @@ snapshots: glob-to-regexp: 0.4.1 graceful-fs: 4.2.11 + watchpack@2.5.1: + dependencies: + glob-to-regexp: 0.4.1 + graceful-fs: 4.2.11 + wbuf@1.7.3: dependencies: minimalistic-assert: 1.0.1 @@ -18585,7 +18594,7 @@ snapshots: webidl-conversions@7.0.0: {} - webpack-dev-middleware@7.4.2(webpack@5.104.1(esbuild@0.25.9)): + webpack-dev-middleware@7.4.2(webpack@5.105.0(esbuild@0.25.9)): dependencies: colorette: 2.0.20 memfs: 4.49.0 @@ -18594,9 +18603,9 @@ snapshots: range-parser: 1.2.1 schema-utils: 4.3.3 optionalDependencies: - webpack: 5.104.1(esbuild@0.25.9) + webpack: 5.105.0(esbuild@0.25.9) - webpack-dev-server@5.2.2(bufferutil@4.0.9)(utf-8-validate@6.0.5)(webpack@5.104.1(esbuild@0.25.9)): + webpack-dev-server@5.2.2(bufferutil@4.0.9)(utf-8-validate@6.0.5)(webpack@5.105.0(esbuild@0.25.9)): dependencies: '@types/bonjour': 3.5.13 '@types/connect-history-api-fallback': 1.5.4 @@ -18624,10 +18633,10 @@ snapshots: serve-index: 1.9.1 sockjs: 0.3.24 spdy: 4.0.2 - webpack-dev-middleware: 7.4.2(webpack@5.104.1(esbuild@0.25.9)) + webpack-dev-middleware: 7.4.2(webpack@5.105.0(esbuild@0.25.9)) ws: 8.18.3(bufferutil@4.0.9)(utf-8-validate@6.0.5) optionalDependencies: - webpack: 5.104.1(esbuild@0.25.9) + webpack: 5.105.0(esbuild@0.25.9) transitivePeerDependencies: - bufferutil - debug @@ -18642,12 +18651,12 @@ snapshots: webpack-sources@3.3.3: {} - webpack-subresource-integrity@5.1.0(webpack@5.104.1(esbuild@0.25.9)): + webpack-subresource-integrity@5.1.0(webpack@5.105.0(esbuild@0.25.9)): dependencies: typed-assert: 1.0.9 - webpack: 5.104.1(esbuild@0.25.9) + webpack: 5.105.0(esbuild@0.25.9) - webpack@5.104.1(esbuild@0.25.9): + webpack@5.105.0(esbuild@0.25.9): dependencies: '@types/eslint-scope': 3.7.7 '@types/estree': 1.0.8 @@ -18659,7 +18668,7 @@ snapshots: acorn-import-phases: 1.0.4(acorn@8.15.0) browserslist: 4.28.1 chrome-trace-event: 1.0.4 - enhanced-resolve: 5.18.3 + enhanced-resolve: 5.19.0 es-module-lexer: 2.0.0 eslint-scope: 5.1.1 events: 3.3.0 @@ -18671,8 +18680,8 @@ snapshots: neo-async: 2.6.2 schema-utils: 4.3.3 tapable: 2.3.0 - terser-webpack-plugin: 5.3.16(esbuild@0.25.9)(webpack@5.104.1(esbuild@0.25.9)) - watchpack: 2.4.4 + terser-webpack-plugin: 5.3.16(esbuild@0.25.9)(webpack@5.105.0(esbuild@0.25.9)) + watchpack: 2.5.1 webpack-sources: 3.3.3 transitivePeerDependencies: - '@swc/core' From 750f037791e1b00879dcef91a6aae2e6466483e4 Mon Sep 17 00:00:00 2001 From: Charles Lyding <19598772+clydin@users.noreply.github.com> Date: Mon, 9 Feb 2026 09:20:54 -0500 Subject: [PATCH 38/52] release: cut the v20.3.16 release --- CHANGELOG.md | 12 ++++++++++++ package.json | 2 +- 2 files changed, 13 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 1d762a2ec9e6..71eb5de722cd 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,15 @@ + + +# 20.3.16 (2026-02-09) + +### @angular/cli + +| Commit | Type | Description | +| --------------------------------------------------------------------------------------------------- | ---- | ------------------------------------------------------ | +| [656888a25](https://github.com/angular/angular-cli/commit/656888a250af060c110ae87024b0e475b079c23d) | fix | update dependency @modelcontextprotocol/sdk to v1.26.0 | + + + # 20.3.15 (2026-01-21) diff --git a/package.json b/package.json index dbc169016987..b76fb7e75829 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@angular/devkit-repo", - "version": "20.3.15", + "version": "20.3.16", "private": true, "description": "Software Development Kit for Angular", "keywords": [ From 67582a946808d2c021cbcfacbf203ef58a6fbded Mon Sep 17 00:00:00 2001 From: Alan Agius Date: Mon, 23 Feb 2026 10:08:15 +0100 Subject: [PATCH 39/52] fix(@angular/ssr): validate host headers to prevent header-based SSRF This change introduces strict validation for `Host`, `X-Forwarded-Host`, `X-Forwarded-Proto`, and `X-Forwarded-Port` headers in the Angular SSR request handling pipeline, including `CommonEngine` and `AngularAppEngine`. --- goldens/public-api/angular/ssr/index.api.md | 6 + .../public-api/angular/ssr/node/index.api.md | 9 +- .../src/builders/application/execute-build.ts | 3 +- .../build/src/builders/application/options.ts | 3 +- .../src/builders/application/schema.json | 8 + .../src/builders/dev-server/vite-server.ts | 9 + .../src/utils/server-rendering/manifest.ts | 3 + .../src/utils/server-rendering/prerender.ts | 6 + packages/angular/ssr/BUILD.bazel | 2 +- packages/angular/ssr/node/public_api.ts | 2 +- packages/angular/ssr/node/src/app-engine.ts | 43 ++- .../node/src/common-engine/common-engine.ts | 45 +++ .../ssr/node/src/environment-options.ts | 29 ++ packages/angular/ssr/node/src/request.ts | 19 +- packages/angular/ssr/public_api.ts | 2 +- packages/angular/ssr/src/app-engine.ts | 92 ++++++- packages/angular/ssr/src/app.ts | 21 ++ packages/angular/ssr/src/manifest.ts | 6 +- packages/angular/ssr/src/utils/validation.ts | 256 ++++++++++++++++++ packages/angular/ssr/test/app-engine_spec.ts | 158 ++++++++++- .../angular/ssr/test/utils/validation_spec.ts | 240 ++++++++++++++++ .../src/builders/ssr-dev-server/index.ts | 11 +- .../ssr-dev-server/specs/proxy_spec.ts | 3 +- .../builders/ssr-dev-server/specs/ssl_spec.ts | 3 +- .../ssr-dev-server/specs/works_spec.ts | 3 +- .../files/server-builder/server.ts.template | 4 +- packages/schematics/angular/ssr/index.ts | 6 +- .../express-engine-csp-nonce.ts | 1 + .../express-engine-ngmodule.ts | 1 + .../express-engine-standalone.ts | 1 + ...outes-output-mode-server-i18n-base-href.ts | 1 + ...routes-output-mode-server-i18n-sub-path.ts | 1 + .../server-routes-output-mode-server-i18n.ts | 1 + ...tes-output-mode-server-platform-neutral.ts | 3 +- .../server-routes-output-mode-server.ts | 1 + .../server-routes-preload-links.ts | 1 + 36 files changed, 960 insertions(+), 43 deletions(-) create mode 100644 packages/angular/ssr/node/src/environment-options.ts create mode 100644 packages/angular/ssr/src/utils/validation.ts create mode 100644 packages/angular/ssr/test/utils/validation_spec.ts diff --git a/goldens/public-api/angular/ssr/index.api.md b/goldens/public-api/angular/ssr/index.api.md index 81764fcc1f62..cbdacabfd7f6 100644 --- a/goldens/public-api/angular/ssr/index.api.md +++ b/goldens/public-api/angular/ssr/index.api.md @@ -11,11 +11,17 @@ import { Type } from '@angular/core'; // @public export class AngularAppEngine { + constructor(options?: AngularAppEngineOptions); handle(request: Request, requestContext?: unknown): Promise; static ɵallowStaticRouteRender: boolean; static ɵhooks: Hooks; } +// @public +export interface AngularAppEngineOptions { + allowedHosts?: readonly string[]; +} + // @public export function createRequestHandler(handler: RequestHandlerFunction): RequestHandlerFunction; diff --git a/goldens/public-api/angular/ssr/node/index.api.md b/goldens/public-api/angular/ssr/node/index.api.md index eccb6396938e..2c52c06b47c1 100644 --- a/goldens/public-api/angular/ssr/node/index.api.md +++ b/goldens/public-api/angular/ssr/node/index.api.md @@ -15,8 +15,12 @@ import { Type } from '@angular/core'; // @public export class AngularNodeAppEngine { - constructor(); - handle(request: IncomingMessage | Http2ServerRequest, requestContext?: unknown): Promise; + constructor(options?: AngularNodeAppEngineOptions); + handle(request: IncomingMessage | Http2ServerRequest | Request, requestContext?: unknown): Promise; +} + +// @public +export interface AngularNodeAppEngineOptions extends AngularAppEngineOptions { } // @public @@ -27,6 +31,7 @@ export class CommonEngine { // @public (undocumented) export interface CommonEngineOptions { + allowedHosts?: readonly string[]; bootstrap?: Type<{}> | ((context: BootstrapContext) => Promise); enablePerformanceProfiler?: boolean; providers?: StaticProvider[]; diff --git a/packages/angular/build/src/builders/application/execute-build.ts b/packages/angular/build/src/builders/application/execute-build.ts index 0654cd965558..aaddc5b6ef7e 100644 --- a/packages/angular/build/src/builders/application/execute-build.ts +++ b/packages/angular/build/src/builders/application/execute-build.ts @@ -56,6 +56,7 @@ export async function executeBuild( verbose, colors, jsonLogs, + security, } = options; // TODO: Consider integrating into watch mode. Would require full rebuild on target changes. @@ -263,7 +264,7 @@ export async function executeBuild( if (serverEntryPoint) { executionResult.addOutputFile( SERVER_APP_ENGINE_MANIFEST_FILENAME, - generateAngularServerAppEngineManifest(i18nOptions, baseHref), + generateAngularServerAppEngineManifest(i18nOptions, security.allowedHosts, baseHref), BuildOutputFileType.ServerRoot, ); } diff --git a/packages/angular/build/src/builders/application/options.ts b/packages/angular/build/src/builders/application/options.ts index 25bd87253357..87bec31ed381 100644 --- a/packages/angular/build/src/builders/application/options.ts +++ b/packages/angular/build/src/builders/application/options.ts @@ -400,8 +400,9 @@ export async function normalizeOptions( } } - const autoCsp = options.security?.autoCsp; + const { autoCsp, allowedHosts = [] } = options.security ?? {}; const security = { + allowedHosts, autoCsp: autoCsp ? { unsafeEval: autoCsp === true ? false : !!autoCsp.unsafeEval, diff --git a/packages/angular/build/src/builders/application/schema.json b/packages/angular/build/src/builders/application/schema.json index 8db4e6145b3f..5498a21fe004 100644 --- a/packages/angular/build/src/builders/application/schema.json +++ b/packages/angular/build/src/builders/application/schema.json @@ -52,6 +52,14 @@ "type": "object", "additionalProperties": false, "properties": { + "allowedHosts": { + "description": "A list of hostnames that are allowed to access the server-side application. For more information, see https://angular.dev/best-practices/security#preventing-server-side-request-forgery-ssrf.", + "type": "array", + "uniqueItems": true, + "items": { + "type": "string" + } + }, "autoCsp": { "description": "Enables automatic generation of a hash-based Strict Content Security Policy (https://web.dev/articles/strict-csp#choose-hash) based on scripts in index.html. Will default to true once we are out of experimental/preview phases.", "default": false, diff --git a/packages/angular/build/src/builders/dev-server/vite-server.ts b/packages/angular/build/src/builders/dev-server/vite-server.ts index 7f8665dd8061..4df3cc3d4023 100644 --- a/packages/angular/build/src/builders/dev-server/vite-server.ts +++ b/packages/angular/build/src/builders/dev-server/vite-server.ts @@ -113,7 +113,16 @@ export async function* serveWithVite( } // Disable auto CSP. + const allowedHosts = Array.isArray(serverOptions.allowedHosts) + ? [...serverOptions.allowedHosts] + : []; + + // Always allow the dev server host + allowedHosts.push(serverOptions.host); + browserOptions.security = { + allowedHosts, + // Disable auto CSP. autoCsp: false, }; diff --git a/packages/angular/build/src/utils/server-rendering/manifest.ts b/packages/angular/build/src/utils/server-rendering/manifest.ts index 2dfad0ff2dfb..975f7718715d 100644 --- a/packages/angular/build/src/utils/server-rendering/manifest.ts +++ b/packages/angular/build/src/utils/server-rendering/manifest.ts @@ -53,11 +53,13 @@ function escapeUnsafeChars(str: string): string { * * @param i18nOptions - The internationalization options for the application build. This * includes settings for inlining locales and determining the output structure. + * @param allowedHosts - A list of hosts that are allowed to access the server-side application. * @param baseHref - The base HREF for the application. This is used to set the base URL * for all relative URLs in the application. */ export function generateAngularServerAppEngineManifest( i18nOptions: NormalizedApplicationBuildOptions['i18nOptions'], + allowedHosts: string[], baseHref: string | undefined, ): string { const entryPoints: Record = {}; @@ -84,6 +86,7 @@ export function generateAngularServerAppEngineManifest( const manifestContent = ` export default { basePath: '${basePath}', + allowedHosts: ${JSON.stringify(allowedHosts, undefined, 2)}, supportedLocales: ${JSON.stringify(supportedLocales, undefined, 2)}, entryPoints: { ${Object.entries(entryPoints) diff --git a/packages/angular/build/src/utils/server-rendering/prerender.ts b/packages/angular/build/src/utils/server-rendering/prerender.ts index f33f851f10c4..39d0f0934c92 100644 --- a/packages/angular/build/src/utils/server-rendering/prerender.ts +++ b/packages/angular/build/src/utils/server-rendering/prerender.ts @@ -225,6 +225,9 @@ async function renderPages( hasSsrEntry: !!outputFilesForWorker['server.mjs'], } as RenderWorkerData, execArgv: workerExecArgv, + env: { + 'NG_ALLOWED_HOSTS': 'localhost', + }, }); try { @@ -337,6 +340,9 @@ async function getAllRoutes( hasSsrEntry: !!outputFilesForWorker['server.mjs'], } as RoutesExtractorWorkerData, execArgv: workerExecArgv, + env: { + 'NG_ALLOWED_HOSTS': 'localhost', + }, }); try { diff --git a/packages/angular/ssr/BUILD.bazel b/packages/angular/ssr/BUILD.bazel index 2218488daeb6..982bdfbb577b 100644 --- a/packages/angular/ssr/BUILD.bazel +++ b/packages/angular/ssr/BUILD.bazel @@ -20,7 +20,7 @@ ts_project( ), args = [ "--lib", - "dom,es2020", + "dom.iterable,dom,es2022", ], data = [ "//packages/angular/ssr/third_party/beasties:beasties_bundled", diff --git a/packages/angular/ssr/node/public_api.ts b/packages/angular/ssr/node/public_api.ts index 81932873a440..89900f95cc5c 100644 --- a/packages/angular/ssr/node/public_api.ts +++ b/packages/angular/ssr/node/public_api.ts @@ -12,7 +12,7 @@ export { type CommonEngineOptions, } from './src/common-engine/common-engine'; -export { AngularNodeAppEngine } from './src/app-engine'; +export { AngularNodeAppEngine, type AngularNodeAppEngineOptions } from './src/app-engine'; export { createNodeRequestHandler, type NodeRequestHandlerFunction } from './src/handler'; export { writeResponseToNodeResponse } from './src/response'; diff --git a/packages/angular/ssr/node/src/app-engine.ts b/packages/angular/ssr/node/src/app-engine.ts index 8edac0ef69c6..29eb1fd366ab 100644 --- a/packages/angular/ssr/node/src/app-engine.ts +++ b/packages/angular/ssr/node/src/app-engine.ts @@ -9,9 +9,16 @@ import { AngularAppEngine } from '@angular/ssr'; import type { IncomingMessage } from 'node:http'; import type { Http2ServerRequest } from 'node:http2'; +import { AngularAppEngineOptions } from '../../src/app-engine'; +import { getAllowedHostsFromEnv } from './environment-options'; import { attachNodeGlobalErrorHandlers } from './errors'; import { createWebRequestFromNodeRequest } from './request'; +/** + * Options for the Angular Node.js server application engine. + */ +export interface AngularNodeAppEngineOptions extends AngularAppEngineOptions {} + /** * Angular server application engine. * Manages Angular server applications (including localized ones), handles rendering requests, @@ -21,9 +28,18 @@ import { createWebRequestFromNodeRequest } from './request'; * application to ensure consistent handling of rendering requests and resource management. */ export class AngularNodeAppEngine { - private readonly angularAppEngine = new AngularAppEngine(); + private readonly angularAppEngine: AngularAppEngine; + + /** + * Creates a new instance of the Angular Node.js server application engine. + * @param options Options for the Angular Node.js server application engine. + */ + constructor(options?: AngularNodeAppEngineOptions) { + this.angularAppEngine = new AngularAppEngine({ + ...options, + allowedHosts: [...getAllowedHostsFromEnv(), ...(options?.allowedHosts ?? [])], + }); - constructor() { attachNodeGlobalErrorHandlers(); } @@ -31,21 +47,36 @@ export class AngularNodeAppEngine { * Handles an incoming HTTP request by serving prerendered content, performing server-side rendering, * or delivering a static file for client-side rendered routes based on the `RenderMode` setting. * - * This method adapts Node.js's `IncomingMessage` or `Http2ServerRequest` + * This method adapts Node.js's `IncomingMessage`, `Http2ServerRequest` or `Request` * to a format compatible with the `AngularAppEngine` and delegates the handling logic to it. * - * @param request - The incoming HTTP request (`IncomingMessage` or `Http2ServerRequest`). + * @param request - The incoming HTTP request (`IncomingMessage`, `Http2ServerRequest` or `Request`). * @param requestContext - Optional context for rendering, such as metadata associated with the request. * @returns A promise that resolves to the resulting HTTP response object, or `null` if no matching Angular route is found. * * @remarks A request to `https://www.example.com/page/index.html` will serve or render the Angular route * corresponding to `https://www.example.com/page`. + * + * @remarks + * To prevent potential Server-Side Request Forgery (SSRF), this function verifies the hostname + * of the `request.url` against a list of authorized hosts. + * If the hostname is not recognized and `allowedHosts` is not empty, a Client-Side Rendered (CSR) version of the + * page is returned otherwise a 400 Bad Request is returned. + * + * Resolution: + * Authorize your hostname by configuring `allowedHosts` in `angular.json` in: + * `projects.[project-name].architect.build.options.security.allowedHosts`. + * Alternatively, you can define the allowed hostname via the environment variable `process.env['NG_ALLOWED_HOSTS']` + * or pass it directly through the configuration options of `AngularNodeAppEngine`. + * + * For more information see: https://angular.dev/best-practices/security#preventing-server-side-request-forgery-ssrf */ async handle( - request: IncomingMessage | Http2ServerRequest, + request: IncomingMessage | Http2ServerRequest | Request, requestContext?: unknown, ): Promise { - const webRequest = createWebRequestFromNodeRequest(request); + const webRequest = + request instanceof Request ? request : createWebRequestFromNodeRequest(request); return this.angularAppEngine.handle(webRequest, requestContext); } diff --git a/packages/angular/ssr/node/src/common-engine/common-engine.ts b/packages/angular/ssr/node/src/common-engine/common-engine.ts index 079c1187696b..1c130d9abe86 100644 --- a/packages/angular/ssr/node/src/common-engine/common-engine.ts +++ b/packages/angular/ssr/node/src/common-engine/common-engine.ts @@ -12,6 +12,8 @@ import { renderApplication, renderModule, ɵSERVER_CONTEXT } from '@angular/plat import * as fs from 'node:fs'; import { dirname, join, normalize, resolve } from 'node:path'; import { URL } from 'node:url'; +import { validateUrl } from '../../../src/utils/validation'; +import { getAllowedHostsFromEnv } from '../environment-options'; import { attachNodeGlobalErrorHandlers } from '../errors'; import { CommonEngineInlineCriticalCssProcessor } from './inline-css-processor'; import { @@ -31,6 +33,9 @@ export interface CommonEngineOptions { /** Enable request performance profiling data collection and printing the results in the server console. */ enablePerformanceProfiler?: boolean; + + /** A set of hostnames that are allowed to access the server. */ + allowedHosts?: readonly string[]; } export interface CommonEngineRenderOptions { @@ -64,8 +69,14 @@ export class CommonEngine { private readonly templateCache = new Map(); private readonly inlineCriticalCssProcessor = new CommonEngineInlineCriticalCssProcessor(); private readonly pageIsSSG = new Map(); + private readonly allowedHosts: ReadonlySet; constructor(private options?: CommonEngineOptions) { + this.allowedHosts = new Set([ + ...getAllowedHostsFromEnv(), + ...(this.options?.allowedHosts ?? []), + ]); + attachNodeGlobalErrorHandlers(); } @@ -74,6 +85,40 @@ export class CommonEngine { * render options */ async render(opts: CommonEngineRenderOptions): Promise { + const { url } = opts; + + if (url && URL.canParse(url)) { + const urlObj = new URL(url); + try { + validateUrl(urlObj, this.allowedHosts); + } catch (error) { + const isAllowedHostConfigured = this.allowedHosts.size > 0; + // eslint-disable-next-line no-console + console.error( + `ERROR: ${(error as Error).message}` + + 'Please provide a list of allowed hosts in the "allowedHosts" option in the "CommonEngine" constructor.', + isAllowedHostConfigured + ? '' + : '\nFalling back to client side rendering. This will become a 400 Bad Request in a future major version.', + ); + + if (!isAllowedHostConfigured) { + // Fallback to CSR to avoid a breaking change. + // TODO(alanagius): Return a 400 and remove this fallback in the next major version (v22). + let document = opts.document; + if (!document && opts.documentFilePath) { + document = opts.document ?? (await this.getDocument(opts.documentFilePath)); + } + + if (document) { + return document; + } + } + + throw error; + } + } + const enablePerformanceProfiler = this.options?.enablePerformanceProfiler; const runMethod = enablePerformanceProfiler diff --git a/packages/angular/ssr/node/src/environment-options.ts b/packages/angular/ssr/node/src/environment-options.ts new file mode 100644 index 000000000000..b18dcd08ebe6 --- /dev/null +++ b/packages/angular/ssr/node/src/environment-options.ts @@ -0,0 +1,29 @@ +/** + * @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 + */ + +/** + * Retrieves the list of allowed hosts from the environment variable `NG_ALLOWED_HOSTS`. + * @returns An array of allowed hosts. + */ +export function getAllowedHostsFromEnv(): ReadonlyArray { + const allowedHosts: string[] = []; + const envNgAllowedHosts = process.env['NG_ALLOWED_HOSTS']; + if (!envNgAllowedHosts) { + return allowedHosts; + } + + const hosts = envNgAllowedHosts.split(','); + for (const host of hosts) { + const trimmed = host.trim(); + if (trimmed.length > 0) { + allowedHosts.push(trimmed); + } + } + + return allowedHosts; +} diff --git a/packages/angular/ssr/node/src/request.ts b/packages/angular/ssr/node/src/request.ts index 32d90d0029fc..402ec29ba56d 100644 --- a/packages/angular/ssr/node/src/request.ts +++ b/packages/angular/ssr/node/src/request.ts @@ -8,6 +8,7 @@ import type { IncomingHttpHeaders, IncomingMessage } from 'node:http'; import type { Http2ServerRequest } from 'node:http2'; +import { getFirstHeaderValue } from '../../src/utils/validation'; /** * A set containing all the pseudo-headers defined in the HTTP/2 specification. @@ -103,21 +104,3 @@ export function createRequestUrl(nodeRequest: IncomingMessage | Http2ServerReque return new URL(`${protocol}://${hostnameWithPort}${originalUrl ?? url}`); } - -/** - * Extracts the first value from a multi-value header string. - * - * @param value - A string or an array of strings representing the header values. - * If it's a string, values are expected to be comma-separated. - * @returns The first trimmed value from the multi-value header, or `undefined` if the input is invalid or empty. - * - * @example - * ```typescript - * getFirstHeaderValue("value1, value2, value3"); // "value1" - * getFirstHeaderValue(["value1", "value2"]); // "value1" - * getFirstHeaderValue(undefined); // undefined - * ``` - */ -function getFirstHeaderValue(value: string | string[] | undefined): string | undefined { - return value?.toString().split(',', 1)[0]?.trim(); -} diff --git a/packages/angular/ssr/public_api.ts b/packages/angular/ssr/public_api.ts index e685f4ceabe3..e566d8414f2f 100644 --- a/packages/angular/ssr/public_api.ts +++ b/packages/angular/ssr/public_api.ts @@ -8,7 +8,7 @@ export * from './private_export'; -export { AngularAppEngine } from './src/app-engine'; +export { AngularAppEngine, type AngularAppEngineOptions } from './src/app-engine'; export { createRequestHandler, type RequestHandlerFunction } from './src/handler'; export { diff --git a/packages/angular/ssr/src/app-engine.ts b/packages/angular/ssr/src/app-engine.ts index dd204a4b595f..6242750b4c47 100644 --- a/packages/angular/ssr/src/app-engine.ts +++ b/packages/angular/ssr/src/app-engine.ts @@ -11,6 +11,17 @@ import { Hooks } from './hooks'; import { getPotentialLocaleIdFromUrl, getPreferredLocale } from './i18n'; import { EntryPointExports, getAngularAppEngineManifest } from './manifest'; import { joinUrlParts } from './utils/url'; +import { cloneRequestAndPatchHeaders, validateRequest } from './utils/validation'; + +/** + * Options for the Angular server application engine. + */ +export interface AngularAppEngineOptions { + /** + * A set of allowed hostnames for the server application. + */ + allowedHosts?: readonly string[]; +} /** * Angular server application engine. @@ -45,6 +56,11 @@ export class AngularAppEngine { */ private readonly manifest = getAngularAppEngineManifest(); + /** + * A set of allowed hostnames for the server application. + */ + private readonly allowedHosts: ReadonlySet; + /** * A map of supported locales from the server application's manifest. */ @@ -57,6 +73,14 @@ export class AngularAppEngine { */ private readonly entryPointsCache = new Map>(); + /** + * Creates a new instance of the Angular server application engine. + * @param options Options for the Angular server application engine. + */ + constructor(options?: AngularAppEngineOptions) { + this.allowedHosts = new Set([...(options?.allowedHosts ?? []), ...this.manifest.allowedHosts]); + } + /** * Handles an incoming HTTP request by serving prerendered content, performing server-side rendering, * or delivering a static file for client-side rendered routes based on the `RenderMode` setting. @@ -67,12 +91,38 @@ export class AngularAppEngine { * * @remarks A request to `https://www.example.com/page/index.html` will serve or render the Angular route * corresponding to `https://www.example.com/page`. + * + * @remarks + * To prevent potential Server-Side Request Forgery (SSRF), this function verifies the hostname + * of the `request.url` against a list of authorized hosts. + * If the hostname is not recognized and `allowedHosts` is not empty, a Client-Side Rendered (CSR) version of the + * page is returned otherwise a 400 Bad Request is returned. + * Resolution: + * Authorize your hostname by configuring `allowedHosts` in `angular.json` in: + * `projects.[project-name].architect.build.options.security.allowedHosts`. + * Alternatively, you pass it directly through the configuration options of `AngularAppEngine`. + * + * For more information see: https://angular.dev/best-practices/security#preventing-server-side-request-forgery-ssrf */ async handle(request: Request, requestContext?: unknown): Promise { - const serverApp = await this.getAngularServerAppForRequest(request); + const allowedHost = this.allowedHosts; + try { + validateRequest(request, allowedHost); + } catch (error) { + return this.handleValidationError(error as Error, request); + } + + // Clone request with patched headers to prevent unallowed host header access. + const { request: securedRequest, onError: onHeaderValidationError } = + cloneRequestAndPatchHeaders(request, allowedHost); + + const serverApp = await this.getAngularServerAppForRequest(securedRequest); if (serverApp) { - return serverApp.handle(request, requestContext); + return Promise.race([ + onHeaderValidationError.then((error) => this.handleValidationError(error, securedRequest)), + serverApp.handle(securedRequest, requestContext), + ]); } if (this.supportedLocales.length > 1) { @@ -201,4 +251,42 @@ export class AngularAppEngine { return this.getEntryPointExports(potentialLocale) ?? this.getEntryPointExports(''); } + + /** + * Handles validation errors by logging the error and returning an appropriate response. + * + * @param error - The validation error to handle. + * @param request - The HTTP request that caused the validation error. + * @returns A promise that resolves to a `Response` object with a 400 status code if allowed hosts are configured, + * or `null` if allowed hosts are not configured (in which case the request is served client-side). + */ + private async handleValidationError(error: Error, request: Request): Promise { + const isAllowedHostConfigured = this.allowedHosts.size > 0; + const errorMessage = error.message; + + // eslint-disable-next-line no-console + console.error( + `ERROR: Bad Request ("${request.url}").\n` + + errorMessage + + (isAllowedHostConfigured + ? '' + : '\nFalling back to client side rendering. This will become a 400 Bad Request in a future major version.') + + '\n\nFor more information, see https://angular.dev/best-practices/security#preventing-server-side-request-forgery-ssrf', + ); + + if (isAllowedHostConfigured) { + // Allowed hosts has been configured incorrectly, thus we can return a 400 bad request. + return new Response(errorMessage, { + status: 400, + statusText: 'Bad Request', + headers: { 'Content-Type': 'text/plain' }, + }); + } + + // Fallback to CSR to avoid a breaking change. + // TODO(alanagius): Return a 400 and remove this fallback in the next major version (v22). + const serverApp = await this.getAngularServerAppForRequest(request); + + return serverApp?.serveClientSidePage() ?? null; + } } diff --git a/packages/angular/ssr/src/app.ts b/packages/angular/ssr/src/app.ts index ee14f8a26105..85227a9d8a33 100644 --- a/packages/angular/ssr/src/app.ts +++ b/packages/angular/ssr/src/app.ts @@ -468,6 +468,27 @@ export class AngularServerApp { return html; } + + /** + * Serves the client-side version of the application. + * TODO(alanagius): Remove this method in version 22. + * @internal + */ + async serveClientSidePage(): Promise { + const { + manifest: { locale }, + assets, + } = this; + + const html = await assets.getServerAsset('index.csr.html').text(); + + return new Response(html, { + headers: new Headers({ + 'Content-Type': 'text/html;charset=UTF-8', + ...(locale !== undefined ? { 'Content-Language': locale } : {}), + }), + }); + } } let angularServerApp: AngularServerApp | undefined; diff --git a/packages/angular/ssr/src/manifest.ts b/packages/angular/ssr/src/manifest.ts index 0de603bba104..21ded49b3e10 100644 --- a/packages/angular/ssr/src/manifest.ts +++ b/packages/angular/ssr/src/manifest.ts @@ -6,7 +6,6 @@ * found in the LICENSE file at https://angular.dev/license */ -import type { BootstrapContext } from '@angular/platform-browser'; import type { SerializableRouteTreeNode } from './routes/route-tree'; import { AngularBootstrap } from './utils/ng'; @@ -74,6 +73,11 @@ export interface AngularAppEngineManifest { * - `value`: The url segment associated with that locale. */ readonly supportedLocales: Readonly>; + + /** + * A readonly array of allowed hostnames. + */ + readonly allowedHosts: Readonly; } /** diff --git a/packages/angular/ssr/src/utils/validation.ts b/packages/angular/ssr/src/utils/validation.ts new file mode 100644 index 000000000000..97ac8606f3b4 --- /dev/null +++ b/packages/angular/ssr/src/utils/validation.ts @@ -0,0 +1,256 @@ +/** + * @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 + */ + +/** + * The set of headers that should be validated for host header injection attacks. + */ +const HOST_HEADERS_TO_VALIDATE: ReadonlySet = new Set(['host', 'x-forwarded-host']); + +/** + * Regular expression to validate that the port is a numeric value. + */ +const VALID_PORT_REGEX = /^\d+$/; + +/** + * Regular expression to validate that the protocol is either http or https (case-insensitive). + */ +const VALID_PROTO_REGEX = /^https?$/i; + +/** + * Regular expression to validate that the host is a valid hostname. + */ +const VALID_HOST_REGEX = /^[a-z0-9.:-]+$/i; + +/** + * Extracts the first value from a multi-value header string. + * + * @param value - A string or an array of strings representing the header values. + * If it's a string, values are expected to be comma-separated. + * @returns The first trimmed value from the multi-value header, or `undefined` if the input is invalid or empty. + * + * @example + * ```typescript + * getFirstHeaderValue("value1, value2, value3"); // "value1" + * getFirstHeaderValue(["value1", "value2"]); // "value1" + * getFirstHeaderValue(undefined); // undefined + * ``` + */ +export function getFirstHeaderValue( + value: string | string[] | undefined | null, +): string | undefined { + return value?.toString().split(',', 1)[0]?.trim(); +} + +/** + * Validates a request. + * + * @param request - The incoming `Request` object to validate. + * @param allowedHosts - A set of allowed hostnames. + * @throws Error if any of the validated headers contain invalid values. + */ +export function validateRequest(request: Request, allowedHosts: ReadonlySet): void { + validateHeaders(request); + validateUrl(new URL(request.url), allowedHosts); +} + +/** + * Validates that the hostname of a given URL is allowed. + * + * @param url - The URL object to validate. + * @param allowedHosts - A set of allowed hostnames. + * @throws Error if the hostname is not in the allowlist. + */ +export function validateUrl(url: URL, allowedHosts: ReadonlySet): void { + const { hostname } = url; + if (!isHostAllowed(hostname, allowedHosts)) { + throw new Error(`URL with hostname "${hostname}" is not allowed.`); + } +} + +/** + * Clones a request and patches the `get` method of the request headers to validate the host headers. + * @param request - The request to validate. + * @param allowedHosts - A set of allowed hostnames. + * @returns An object containing the cloned request and a promise that resolves to an error + * if any of the validated headers contain invalid values. + */ +export function cloneRequestAndPatchHeaders( + request: Request, + allowedHosts: ReadonlySet, +): { request: Request; onError: Promise } { + let onError: (value: Error) => void; + const onErrorPromise = new Promise((resolve) => { + onError = resolve; + }); + + const clonedReq = new Request(request.clone(), { + signal: request.signal, + }); + + const headers = clonedReq.headers; + + const originalGet = headers.get; + // eslint-disable-next-line @typescript-eslint/no-unnecessary-type-assertion + (headers.get as typeof originalGet) = function (name) { + const value = originalGet.call(headers, name); + if (!value) { + return value; + } + + validateHeader(name, value, allowedHosts, onError); + + return value; + }; + + const originalValues = headers.values; + // eslint-disable-next-line @typescript-eslint/no-unnecessary-type-assertion + (headers.values as typeof originalValues) = function () { + for (const name of HOST_HEADERS_TO_VALIDATE) { + validateHeader(name, originalGet.call(headers, name), allowedHosts, onError); + } + + return originalValues.call(headers); + }; + + const originalEntries = headers.entries; + // eslint-disable-next-line @typescript-eslint/no-unnecessary-type-assertion + (headers.entries as typeof originalEntries) = function () { + const iterator = originalEntries.call(headers); + + return { + next() { + const result = iterator.next(); + if (!result.done) { + const [key, value] = result.value; + validateHeader(key, value, allowedHosts, onError); + } + + return result; + }, + [Symbol.iterator]() { + return this; + }, + }; + }; + + // Ensure for...of loops use the new patched entries + (headers[Symbol.iterator] as typeof originalEntries) = headers.entries; + + return { request: clonedReq, onError: onErrorPromise }; +} + +/** + * Validates a specific header value against the allowed hosts. + * @param name - The name of the header to validate. + * @param value - The value of the header to validate. + * @param allowedHosts - A set of allowed hostnames. + * @param onError - A callback function to call if the header value is invalid. + * @throws Error if the header value is invalid. + */ +function validateHeader( + name: string, + value: string | null, + allowedHosts: ReadonlySet, + onError: (value: Error) => void, +): void { + if (!value) { + return; + } + + if (!HOST_HEADERS_TO_VALIDATE.has(name.toLowerCase())) { + return; + } + + try { + verifyHostAllowed(name, value, allowedHosts); + } catch (error) { + onError(error as Error); + + throw error; + } +} + +/** + * Validates a specific host header value against the allowed hosts. + * + * @param headerName - The name of the header to validate (e.g., 'host', 'x-forwarded-host'). + * @param headerValue - The value of the header to validate. + * @param allowedHosts - A set of allowed hostnames. + * @throws Error if the header value is invalid or the hostname is not in the allowlist. + */ +function verifyHostAllowed( + headerName: string, + headerValue: string, + allowedHosts: ReadonlySet, +): void { + const value = getFirstHeaderValue(headerValue); + if (!value) { + return; + } + + const url = `http://${value}`; + if (!URL.canParse(url)) { + throw new Error(`Header "${headerName}" contains an invalid value and cannot be parsed.`); + } + + const { hostname } = new URL(url); + if (!isHostAllowed(hostname, allowedHosts)) { + throw new Error(`Header "${headerName}" with value "${value}" is not allowed.`); + } +} + +/** + * Checks if the hostname is allowed. + * @param hostname - The hostname to check. + * @param allowedHosts - A set of allowed hostnames. + * @returns `true` if the hostname is allowed, `false` otherwise. + */ +function isHostAllowed(hostname: string, allowedHosts: ReadonlySet): boolean { + if (allowedHosts.has(hostname)) { + return true; + } + + for (const allowedHost of allowedHosts) { + if (!allowedHost.startsWith('*.')) { + continue; + } + + const domain = allowedHost.slice(1); + if (hostname.endsWith(domain)) { + return true; + } + } + + return false; +} + +/** + * Validates the headers of an incoming request. + * + * @param request - The incoming `Request` object containing the headers to validate. + * @throws Error if any of the validated headers contain invalid values. + */ +function validateHeaders(request: Request): void { + const headers = request.headers; + for (const headerName of HOST_HEADERS_TO_VALIDATE) { + const headerValue = getFirstHeaderValue(headers.get(headerName)); + if (headerValue && !VALID_HOST_REGEX.test(headerValue)) { + throw new Error(`Header "${headerName}" contains characters that are not allowed.`); + } + } + + const xForwardedPort = getFirstHeaderValue(headers.get('x-forwarded-port')); + if (xForwardedPort && !VALID_PORT_REGEX.test(xForwardedPort)) { + throw new Error('Header "x-forwarded-port" must be a numeric value.'); + } + + const xForwardedProto = getFirstHeaderValue(headers.get('x-forwarded-proto')); + if (xForwardedProto && !VALID_PROTO_REGEX.test(xForwardedProto)) { + throw new Error('Header "x-forwarded-proto" must be either "http" or "https".'); + } +} diff --git a/packages/angular/ssr/test/app-engine_spec.ts b/packages/angular/ssr/test/app-engine_spec.ts index 76b68f6d4a82..738f7c695cc3 100644 --- a/packages/angular/ssr/test/app-engine_spec.ts +++ b/packages/angular/ssr/test/app-engine_spec.ts @@ -11,13 +11,26 @@ import '@angular/compiler'; /* eslint-enable import/no-unassigned-import */ -import { Component } from '@angular/core'; +import { Component, REQUEST, inject } from '@angular/core'; import { destroyAngularServerApp, getOrCreateAngularServerApp } from '../src/app'; import { AngularAppEngine } from '../src/app-engine'; import { setAngularAppEngineManifest } from '../src/manifest'; import { RenderMode } from '../src/routes/route-config'; import { setAngularAppTestingManifest } from './testing-utils'; +@Component({ + selector: 'app-home', + template: 'Home works', +}) +class TestHomeComponent { + private request = inject(REQUEST); + constructor() { + // Force header access to trigger validation + this.request?.headers.get('host'); + this.request?.headers.get('x-forwarded-host'); + } +} + function createEntryPoint(locale: string) { return async () => { @Component({ @@ -84,6 +97,7 @@ describe('AngularAppEngine', () => { describe('Localized app', () => { beforeAll(() => { setAngularAppEngineManifest({ + allowedHosts: ['example.com'], // Note: Although we are testing only one locale, we need to configure two or more // to ensure that we test a different code path. entryPoints: { @@ -163,6 +177,7 @@ describe('AngularAppEngine', () => { describe('Localized app with single locale', () => { beforeAll(() => { setAngularAppEngineManifest({ + allowedHosts: ['example.com'], entryPoints: { it: createEntryPoint('it'), }, @@ -230,6 +245,7 @@ describe('AngularAppEngine', () => { class HomeComponent {} setAngularAppEngineManifest({ + allowedHosts: ['example.com'], entryPoints: { '': async () => { setAngularAppTestingManifest( @@ -274,4 +290,144 @@ describe('AngularAppEngine', () => { expect(await response?.text()).toContain('Home works'); }); }); + + describe('Invalid host headers', () => { + let consoleErrorSpy: jasmine.Spy; + + describe('with allowed hosts configured', () => { + beforeAll(() => { + setAngularAppEngineManifest({ + allowedHosts: ['example.com'], + entryPoints: { + '': async () => { + setAngularAppTestingManifest( + [{ path: 'home', component: TestHomeComponent }], + [{ path: '**', renderMode: RenderMode.Server }], + ); + + return { + ɵgetOrCreateAngularServerApp: getOrCreateAngularServerApp, + ɵdestroyAngularServerApp: destroyAngularServerApp, + }; + }, + }, + basePath: '/', + supportedLocales: { 'en-US': '' }, + }); + + appEngine = new AngularAppEngine(); + }); + + beforeEach(() => { + consoleErrorSpy = spyOn(console, 'error'); + }); + + it('should return 400 when disallowed host', async () => { + const request = new Request('https://evil.com'); + const response = await appEngine.handle(request); + expect(response).not.toBeNull(); + expect(response?.status).toBe(400); + expect(await response?.text()).toContain('URL with hostname "evil.com" is not allowed.'); + expect(consoleErrorSpy).toHaveBeenCalledWith( + jasmine.stringMatching('URL with hostname "evil.com" is not allowed.'), + ); + }); + + it('should return 400 when disallowed host header', async () => { + const request = new Request('https://example.com/home', { + headers: { 'host': 'evil.com' }, + }); + const response = await appEngine.handle(request); + expect(response).not.toBeNull(); + expect(response?.status).toBe(400); + expect(await response?.text()).toContain( + 'Header "host" with value "evil.com" is not allowed.', + ); + expect(consoleErrorSpy).toHaveBeenCalledWith( + jasmine.stringMatching('Header "host" with value "evil.com" is not allowed.'), + ); + }); + + it('should return 400 when disallowed x-forwarded-host header', async () => { + const request = new Request('https://example.com/home', { + headers: { 'x-forwarded-host': 'evil.com' }, + }); + const response = await appEngine.handle(request); + expect(response).not.toBeNull(); + expect(response?.status).toBe(400); + expect(await response?.text()).toContain( + 'Header "x-forwarded-host" with value "evil.com" is not allowed.', + ); + expect(consoleErrorSpy).toHaveBeenCalledWith( + jasmine.stringMatching('Header "x-forwarded-host" with value "evil.com" is not allowed.'), + ); + }); + + it('should return 400 when host with path separator', async () => { + const request = new Request('https://example.com/home', { + headers: { 'host': 'example.com/evil' }, + }); + const response = await appEngine.handle(request); + expect(response).not.toBeNull(); + expect(response?.status).toBe(400); + expect(await response?.text()).toContain( + 'Header "host" contains characters that are not allowed.', + ); + expect(consoleErrorSpy).toHaveBeenCalledWith( + jasmine.stringMatching('Header "host" contains characters that are not allowed.'), + ); + }); + }); + + describe('without allowed hosts configured', () => { + beforeAll(() => { + setAngularAppEngineManifest({ + allowedHosts: [], + entryPoints: { + '': async () => { + setAngularAppTestingManifest( + [{ path: 'home', component: TestHomeComponent }], + [{ path: '**', renderMode: RenderMode.Server }], + ); + + return { + ɵgetOrCreateAngularServerApp: getOrCreateAngularServerApp, + ɵdestroyAngularServerApp: destroyAngularServerApp, + }; + }, + }, + basePath: '/', + supportedLocales: { 'en-US': '' }, + }); + + appEngine = new AngularAppEngine(); + }); + + beforeEach(() => { + consoleErrorSpy = spyOn(console, 'error'); + }); + + it('should log error and fallback to CSR when disallowed host', async () => { + const request = new Request('https://example.com'); + const response = await appEngine.handle(request); + expect(response).not.toBeNull(); + expect(await response?.text()).toContain('CSR page'); + expect(consoleErrorSpy).toHaveBeenCalledWith( + jasmine.stringMatching('URL with hostname "example.com" is not allowed.'), + ); + }); + + it('should log error and fallback to CSR when host with path separator', async () => { + const request = new Request('https://example.com/home', { + headers: { 'host': 'example.com/evil' }, + }); + const response = await appEngine.handle(request); + expect(response).not.toBeNull(); + expect(await response?.text()).toContain('CSR page'); + expect(consoleErrorSpy).toHaveBeenCalledWith( + jasmine.stringMatching('Header "host" contains characters that are not allowed.'), + ); + }); + }); + }); }); diff --git a/packages/angular/ssr/test/utils/validation_spec.ts b/packages/angular/ssr/test/utils/validation_spec.ts new file mode 100644 index 000000000000..99fbf517b60d --- /dev/null +++ b/packages/angular/ssr/test/utils/validation_spec.ts @@ -0,0 +1,240 @@ +/** + * @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 { + cloneRequestAndPatchHeaders, + getFirstHeaderValue, + validateRequest, + validateUrl, +} from '../../src/utils/validation'; + +describe('Validation Utils', () => { + describe('getFirstHeaderValue', () => { + it('should return the first value from a comma-separated string', () => { + expect(getFirstHeaderValue('value1, value2')).toBe('value1'); + }); + + it('should return the value if it is a single string', () => { + expect(getFirstHeaderValue('value1')).toBe('value1'); + }); + + it('should return the first value from an array of strings', () => { + expect(getFirstHeaderValue(['value1', 'value2'])).toBe('value1'); + }); + + it('should return undefined for null or undefined', () => { + expect(getFirstHeaderValue(null)).toBeUndefined(); + expect(getFirstHeaderValue(undefined)).toBeUndefined(); + }); + + it('should return empty string for empty string input', () => { + expect(getFirstHeaderValue('')).toBe(''); + }); + }); + + describe('validateUrl', () => { + const allowedHosts = new Set(['example.com', '*.google.com']); + + it('should pass for allowed hostname', () => { + expect(() => validateUrl(new URL('http://example.com'), allowedHosts)).not.toThrow(); + }); + + it('should pass for wildcard allowed hostname', () => { + expect(() => validateUrl(new URL('http://foo.google.com'), allowedHosts)).not.toThrow(); + }); + + it('should throw for disallowed hostname', () => { + expect(() => validateUrl(new URL('http://evil.com'), allowedHosts)).toThrowError( + /URL with hostname "evil.com" is not allowed/, + ); + }); + + it('should match subdomains for wildcard', () => { + expect(() => validateUrl(new URL('http://sub.foo.google.com'), allowedHosts)).not.toThrow(); + }); + + it('should not match base domain for wildcard (*.google.com vs google.com)', () => { + // Logic: hostname.endsWith('.google.com') -> 'google.com'.endsWith('.google.com') is false + expect(() => validateUrl(new URL('http://google.com'), allowedHosts)).toThrowError( + /URL with hostname "google.com" is not allowed/, + ); + }); + }); + + describe('validateRequest', () => { + const allowedHosts = new Set(['example.com']); + + it('should pass for valid request', () => { + const req = new Request('http://example.com', { + headers: { + 'x-forwarded-port': '443', + 'x-forwarded-proto': 'https', + }, + }); + + expect(() => validateRequest(req, allowedHosts)).not.toThrow(); + }); + + it('should throw if URL hostname is invalid', () => { + const req = new Request('http://evil.com'); + + expect(() => validateRequest(req, allowedHosts)).toThrowError( + /URL with hostname "evil.com" is not allowed/, + ); + }); + + it('should throw if x-forwarded-port is invalid', () => { + const req = new Request('http://example.com', { + headers: { 'x-forwarded-port': 'abc' }, + }); + + expect(() => validateRequest(req, allowedHosts)).toThrowError( + 'Header "x-forwarded-port" must be a numeric value.', + ); + }); + + it('should throw if x-forwarded-proto is invalid', () => { + const req = new Request('http://example.com', { + headers: { 'x-forwarded-proto': 'ftp' }, + }); + expect(() => validateRequest(req, allowedHosts)).toThrowError( + 'Header "x-forwarded-proto" must be either "http" or "https".', + ); + }); + + it('should throw if host contains path separators', () => { + const req = new Request('http://example.com', { + headers: { 'host': 'example.com/bad' }, + }); + expect(() => validateRequest(req, allowedHosts)).toThrowError( + 'Header "host" contains characters that are not allowed.', + ); + }); + + it('should throw if x-forwarded-host contains path separators', () => { + const req = new Request('http://example.com', { + headers: { 'x-forwarded-host': 'example.com/bad' }, + }); + expect(() => validateRequest(req, allowedHosts)).toThrowError( + 'Header "x-forwarded-host" contains characters that are not allowed.', + ); + }); + }); + + describe('cloneRequestAndPatchHeaders', () => { + const allowedHosts = new Set(['example.com', '*.valid.com']); + + it('should validate host header when accessed via get()', async () => { + const req = new Request('http://example.com', { + headers: { 'host': 'evil.com' }, + }); + const { request: secured, onError } = cloneRequestAndPatchHeaders(req, allowedHosts); + + expect(() => secured.headers.get('host')).toThrowError( + 'Header "host" with value "evil.com" is not allowed.', + ); + await expectAsync(onError).toBeResolvedTo( + jasmine.objectContaining({ + message: jasmine.stringMatching('Header "host" with value "evil.com" is not allowed'), + }), + ); + }); + + it('should allow valid host header', () => { + const req = new Request('http://example.com', { + headers: { 'host': 'example.com' }, + }); + const { request: secured } = cloneRequestAndPatchHeaders(req, allowedHosts); + expect(secured.headers.get('host')).toBe('example.com'); + }); + + it('should validate x-forwarded-host header', async () => { + const req = new Request('http://example.com', { + headers: { 'x-forwarded-host': 'evil.com' }, + }); + const { request: secured, onError } = cloneRequestAndPatchHeaders(req, allowedHosts); + + expect(() => secured.headers.get('x-forwarded-host')).toThrowError( + 'Header "x-forwarded-host" with value "evil.com" is not allowed.', + ); + await expectAsync(onError).toBeResolvedTo( + jasmine.objectContaining({ + message: jasmine.stringMatching( + 'Header "x-forwarded-host" with value "evil.com" is not allowed', + ), + }), + ); + }); + + it('should allow accessing other headers without validation', () => { + const req = new Request('http://example.com', { + headers: { 'accept': 'application/json' }, + }); + const { request: secured } = cloneRequestAndPatchHeaders(req, allowedHosts); + + expect(secured.headers.get('accept')).toBe('application/json'); + }); + + it('should validate headers when iterating with entries()', async () => { + const req = new Request('http://example.com', { + headers: { 'host': 'evil.com' }, + }); + const { request: secured, onError } = cloneRequestAndPatchHeaders(req, allowedHosts); + + expect(() => { + for (const _ of secured.headers.entries()) { + // access the header to trigger the validation + } + }).toThrowError('Header "host" with value "evil.com" is not allowed.'); + + await expectAsync(onError).toBeResolvedTo( + jasmine.objectContaining({ + message: jasmine.stringMatching('Header "host" with value "evil.com" is not allowed.'), + }), + ); + }); + + it('should validate headers when iterating with values()', async () => { + const req = new Request('http://example.com', { + headers: { 'host': 'evil.com' }, + }); + const { request: secured, onError } = cloneRequestAndPatchHeaders(req, allowedHosts); + + expect(() => { + for (const _ of secured.headers.values()) { + // access the header to trigger the validation + } + }).toThrowError('Header "host" with value "evil.com" is not allowed.'); + + await expectAsync(onError).toBeResolvedTo( + jasmine.objectContaining({ + message: jasmine.stringMatching('Header "host" with value "evil.com" is not allowed.'), + }), + ); + }); + + it('should validate headers when iterating with for...of', async () => { + const req = new Request('http://example.com', { + headers: { 'host': 'evil.com' }, + }); + const { request: secured, onError } = cloneRequestAndPatchHeaders(req, allowedHosts); + + expect(() => { + for (const _ of secured.headers) { + // access the header to trigger the validation + } + }).toThrowError('Header "host" with value "evil.com" is not allowed.'); + + await expectAsync(onError).toBeResolvedTo( + jasmine.objectContaining({ + message: jasmine.stringMatching('Header "host" with value "evil.com" is not allowed.'), + }), + ); + }); + }); +}); diff --git a/packages/angular_devkit/build_angular/src/builders/ssr-dev-server/index.ts b/packages/angular_devkit/build_angular/src/builders/ssr-dev-server/index.ts index 6219ea6a46a2..37e04171aed4 100644 --- a/packages/angular_devkit/build_angular/src/builders/ssr-dev-server/index.ts +++ b/packages/angular_devkit/build_angular/src/builders/ssr-dev-server/index.ts @@ -114,7 +114,13 @@ export function execute( return of([b, s]); } - return startNodeServer(s, nodeServerPort, context.logger, !!options.inspect).pipe( + return startNodeServer( + s, + nodeServerPort, + options.host, + context.logger, + !!options.inspect, + ).pipe( map(() => [b, s]), catchError((err) => { context.logger.error(`A server error has occurred.\n${mapErrorToMessage(err)}`); @@ -216,12 +222,13 @@ export function log( function startNodeServer( serverOutput: BuilderOutput, port: number, + host: string | undefined, logger: logging.LoggerApi, inspectMode = false, ): Observable { const outputPath = serverOutput.outputPath as string; const path = join(outputPath, 'main.js'); - const env = { ...process.env, PORT: '' + port }; + const env = { ...process.env, PORT: '' + port, NG_ALLOWED_HOSTS: host ?? 'localhost' }; const args = ['--enable-source-maps', `"${path}"`]; if (inspectMode) { diff --git a/packages/angular_devkit/build_angular/src/builders/ssr-dev-server/specs/proxy_spec.ts b/packages/angular_devkit/build_angular/src/builders/ssr-dev-server/specs/proxy_spec.ts index a4cafd66ee06..b125312653e9 100644 --- a/packages/angular_devkit/build_angular/src/builders/ssr-dev-server/specs/proxy_spec.ts +++ b/packages/angular_devkit/build_angular/src/builders/ssr-dev-server/specs/proxy_spec.ts @@ -54,11 +54,12 @@ describe('Serve SSR Builder', () => { })); server.use((req, res, next) => { + const { protocol, originalUrl, baseUrl, headers } = req; commonEngine .render({ bootstrap: AppServerModule, documentFilePath: indexHtml, - url: req.originalUrl, + url: \`\${protocol}://\${headers.host}\${originalUrl}\`, publicPath: distFolder, }) .then((html) => res.send(html)) diff --git a/packages/angular_devkit/build_angular/src/builders/ssr-dev-server/specs/ssl_spec.ts b/packages/angular_devkit/build_angular/src/builders/ssr-dev-server/specs/ssl_spec.ts index 3792d87f839c..4a358ee1c123 100644 --- a/packages/angular_devkit/build_angular/src/builders/ssr-dev-server/specs/ssl_spec.ts +++ b/packages/angular_devkit/build_angular/src/builders/ssr-dev-server/specs/ssl_spec.ts @@ -54,11 +54,12 @@ describe('Serve SSR Builder', () => { })); server.use((req, res, next) => { + const { protocol, originalUrl, baseUrl, headers } = req; commonEngine .render({ bootstrap: AppServerModule, documentFilePath: indexHtml, - url: req.originalUrl, + url: \`\${protocol}://\${headers.host}\${originalUrl}\`, publicPath: distFolder, }) .then((html) => res.send(html)) diff --git a/packages/angular_devkit/build_angular/src/builders/ssr-dev-server/specs/works_spec.ts b/packages/angular_devkit/build_angular/src/builders/ssr-dev-server/specs/works_spec.ts index 8e92c4d666e3..3feed5d3161a 100644 --- a/packages/angular_devkit/build_angular/src/builders/ssr-dev-server/specs/works_spec.ts +++ b/packages/angular_devkit/build_angular/src/builders/ssr-dev-server/specs/works_spec.ts @@ -53,11 +53,12 @@ describe('Serve SSR Builder', () => { })); server.use((req, res, next) => { + const { protocol, originalUrl, baseUrl, headers } = req; commonEngine .render({ bootstrap: AppServerModule, documentFilePath: indexHtml, - url: req.originalUrl, + url: \`\${protocol}://\${headers.host}\${originalUrl}\`, publicPath: distFolder, }) .then((html) => res.send(html)) diff --git a/packages/schematics/angular/ssr/files/server-builder/server.ts.template b/packages/schematics/angular/ssr/files/server-builder/server.ts.template index 7567fa65a81d..92272edc590d 100644 --- a/packages/schematics/angular/ssr/files/server-builder/server.ts.template +++ b/packages/schematics/angular/ssr/files/server-builder/server.ts.template @@ -15,7 +15,9 @@ export function app(): express.Express { ? join(distFolder, 'index.original.html') : join(distFolder, 'index.html'); - const commonEngine = new CommonEngine(); + const commonEngine = new CommonEngine({ + allowedHosts: [/* Configure your hosts here */] + }); server.set('view engine', 'html'); server.set('views', distFolder); diff --git a/packages/schematics/angular/ssr/index.ts b/packages/schematics/angular/ssr/index.ts index e589395dac73..90744240e43b 100644 --- a/packages/schematics/angular/ssr/index.ts +++ b/packages/schematics/angular/ssr/index.ts @@ -6,7 +6,7 @@ * found in the LICENSE file at https://angular.dev/license */ -import { isJsonObject, join, normalize, strings } from '@angular-devkit/core'; +import { JsonObject, isJsonObject, join, normalize, strings } from '@angular-devkit/core'; import { Rule, SchematicContext, @@ -204,6 +204,10 @@ function updateApplicationBuilderWorkspaceConfigRule( buildTarget.options = { ...buildTarget.options, + security: { + ...((buildTarget.options?.security as JsonObject | undefined) ?? {}), + allowedHosts: [], + }, outputPath, outputMode: 'server', ssr: { diff --git a/tests/legacy-cli/e2e/tests/build/server-rendering/express-engine-csp-nonce.ts b/tests/legacy-cli/e2e/tests/build/server-rendering/express-engine-csp-nonce.ts index 19e7dcd28b60..22befac99f9b 100644 --- a/tests/legacy-cli/e2e/tests/build/server-rendering/express-engine-csp-nonce.ts +++ b/tests/legacy-cli/e2e/tests/build/server-rendering/express-engine-csp-nonce.ts @@ -144,6 +144,7 @@ export default async function () { { ...process.env, 'PORT': String(port), + 'NG_ALLOWED_HOSTS': 'localhost', }, ); diff --git a/tests/legacy-cli/e2e/tests/build/server-rendering/express-engine-ngmodule.ts b/tests/legacy-cli/e2e/tests/build/server-rendering/express-engine-ngmodule.ts index f05d2182bbd2..f21690c47df9 100644 --- a/tests/legacy-cli/e2e/tests/build/server-rendering/express-engine-ngmodule.ts +++ b/tests/legacy-cli/e2e/tests/build/server-rendering/express-engine-ngmodule.ts @@ -157,6 +157,7 @@ export default async function () { /Node Express server listening on/, { ...process.env, + 'NG_ALLOWED_HOSTS': 'localhost', 'PORT': String(port), }, ); diff --git a/tests/legacy-cli/e2e/tests/build/server-rendering/express-engine-standalone.ts b/tests/legacy-cli/e2e/tests/build/server-rendering/express-engine-standalone.ts index 7c819e67693a..b8df3812f05c 100644 --- a/tests/legacy-cli/e2e/tests/build/server-rendering/express-engine-standalone.ts +++ b/tests/legacy-cli/e2e/tests/build/server-rendering/express-engine-standalone.ts @@ -114,6 +114,7 @@ export default async function () { { ...process.env, 'PORT': String(port), + 'NG_ALLOWED_HOSTS': 'localhost', }, ); diff --git a/tests/legacy-cli/e2e/tests/build/server-rendering/server-routes-output-mode-server-i18n-base-href.ts b/tests/legacy-cli/e2e/tests/build/server-rendering/server-routes-output-mode-server-i18n-base-href.ts index 6d0a45459a16..aa6f7e3426ee 100644 --- a/tests/legacy-cli/e2e/tests/build/server-rendering/server-routes-output-mode-server-i18n-base-href.ts +++ b/tests/legacy-cli/e2e/tests/build/server-rendering/server-routes-output-mode-server-i18n-base-href.ts @@ -111,6 +111,7 @@ async function spawnServer(): Promise { { ...process.env, 'PORT': String(port), + 'NG_ALLOWED_HOSTS': 'localhost', }, ); diff --git a/tests/legacy-cli/e2e/tests/build/server-rendering/server-routes-output-mode-server-i18n-sub-path.ts b/tests/legacy-cli/e2e/tests/build/server-rendering/server-routes-output-mode-server-i18n-sub-path.ts index 79fc755c4477..7bc323311b4f 100644 --- a/tests/legacy-cli/e2e/tests/build/server-rendering/server-routes-output-mode-server-i18n-sub-path.ts +++ b/tests/legacy-cli/e2e/tests/build/server-rendering/server-routes-output-mode-server-i18n-sub-path.ts @@ -146,6 +146,7 @@ async function spawnServer(): Promise { { ...process.env, 'PORT': String(port), + 'NG_ALLOWED_HOSTS': 'localhost', }, ); diff --git a/tests/legacy-cli/e2e/tests/build/server-rendering/server-routes-output-mode-server-i18n.ts b/tests/legacy-cli/e2e/tests/build/server-rendering/server-routes-output-mode-server-i18n.ts index 994d77343d1e..efbff9871bbc 100644 --- a/tests/legacy-cli/e2e/tests/build/server-rendering/server-routes-output-mode-server-i18n.ts +++ b/tests/legacy-cli/e2e/tests/build/server-rendering/server-routes-output-mode-server-i18n.ts @@ -122,6 +122,7 @@ async function spawnServer(): Promise { { ...process.env, 'PORT': String(port), + 'NG_ALLOWED_HOSTS': 'localhost', }, ); diff --git a/tests/legacy-cli/e2e/tests/build/server-rendering/server-routes-output-mode-server-platform-neutral.ts b/tests/legacy-cli/e2e/tests/build/server-rendering/server-routes-output-mode-server-platform-neutral.ts index 130ade10ba9f..6fdd1998cdd2 100644 --- a/tests/legacy-cli/e2e/tests/build/server-rendering/server-routes-output-mode-server-platform-neutral.ts +++ b/tests/legacy-cli/e2e/tests/build/server-rendering/server-routes-output-mode-server-platform-neutral.ts @@ -11,7 +11,6 @@ import { import { updateJsonFile, useSha } from '../../../utils/project'; import { getGlobalVariable } from '../../../utils/env'; import { findFreePort } from '../../../utils/network'; -import { readFile } from 'node:fs/promises'; export default async function () { assert( @@ -98,6 +97,8 @@ export default async function () { const options = buildTarget['options']; options['ssr']['experimentalPlatform'] = 'neutral'; options['outputMode'] = 'server'; + options['security'] ??= {}; + options['security']['allowedHosts'] = ['localhost']; }); await noSilentNg('build'); diff --git a/tests/legacy-cli/e2e/tests/build/server-rendering/server-routes-output-mode-server.ts b/tests/legacy-cli/e2e/tests/build/server-rendering/server-routes-output-mode-server.ts index 5205d20eeb0a..ff72cb8e8df2 100644 --- a/tests/legacy-cli/e2e/tests/build/server-rendering/server-routes-output-mode-server.ts +++ b/tests/legacy-cli/e2e/tests/build/server-rendering/server-routes-output-mode-server.ts @@ -206,6 +206,7 @@ async function spawnServer(): Promise { { ...process.env, 'PORT': String(port), + 'NG_ALLOWED_HOSTS': 'localhost', }, ); diff --git a/tests/legacy-cli/e2e/tests/build/server-rendering/server-routes-preload-links.ts b/tests/legacy-cli/e2e/tests/build/server-rendering/server-routes-preload-links.ts index f1437392492d..fe316e3cd157 100644 --- a/tests/legacy-cli/e2e/tests/build/server-rendering/server-routes-preload-links.ts +++ b/tests/legacy-cli/e2e/tests/build/server-rendering/server-routes-preload-links.ts @@ -196,6 +196,7 @@ async function spawnServer(): Promise { { ...process.env, 'PORT': String(port), + 'NG_ALLOWED_HOSTS': 'localhost', }, ); From 8700e18d7cf175d80fe6ce6205589767b7870c1c Mon Sep 17 00:00:00 2001 From: Alan Agius <17563226+alan-agius4@users.noreply.github.com> Date: Mon, 23 Feb 2026 09:41:08 +0000 Subject: [PATCH 40/52] fix(@angular/ssr): prevent open redirect via X-Forwarded-Prefix header This change addresses a security vulnerability where `joinUrlParts()` in `packages/angular/ssr/src/utils/url.ts` only stripped one leading slash from URL parts. When the `X-Forwarded-Prefix` header contains multiple leading slashes (e.g., `///evil.com`), the function previously produced a protocol-relative URL (e.g., `//evil.com/home`). If the application issues a redirect (e.g., via a generic redirect route), the browser interprets this 'Location' header as an external redirect to `https://evil.com/home`. This vulnerability poses a significant risk as open redirects can be used in phishing attacks. Additionally, since the redirect response may lack `Cache-Control` headers, intermediate CDNs could cache the poisoned redirect, serving it to other users. This commit fixes the issue by: 1. Updating `joinUrlParts` to internally strip *all* leading and trailing slashes from URL segments, preventing the formation of protocol-relative URLs from malicious input. 2. Adding strict validation for the `X-Forwarded-Prefix` header to immediately reject requests with values starting with multiple slashest pusfh: (`//`) or backslashes (`\\`). Closes #32501 --- packages/angular/ssr/src/utils/url.ts | 24 ++++--- packages/angular/ssr/src/utils/validation.ts | 12 ++++ packages/angular/ssr/test/utils/url_spec.ts | 12 ++++ .../angular/ssr/test/utils/validation_spec.ts | 67 +++++++++++++++++++ 4 files changed, 106 insertions(+), 9 deletions(-) diff --git a/packages/angular/ssr/src/utils/url.ts b/packages/angular/ssr/src/utils/url.ts index faabf15b1bd4..caf7f3aad310 100644 --- a/packages/angular/ssr/src/utils/url.ts +++ b/packages/angular/ssr/src/utils/url.ts @@ -95,26 +95,32 @@ export function addTrailingSlash(url: string): string { * ``` */ export function joinUrlParts(...parts: string[]): string { - const normalizeParts: string[] = []; + const normalizedParts: string[] = []; + for (const part of parts) { if (part === '') { // Skip any empty parts continue; } - let normalizedPart = part; - if (part[0] === '/') { - normalizedPart = normalizedPart.slice(1); + let start = 0; + let end = part.length; + + // Use "Pointers" to avoid intermediate slices + while (start < end && part[start] === '/') { + start++; } - if (part[part.length - 1] === '/') { - normalizedPart = normalizedPart.slice(0, -1); + + while (end > start && part[end - 1] === '/') { + end--; } - if (normalizedPart !== '') { - normalizeParts.push(normalizedPart); + + if (start < end) { + normalizedParts.push(part.slice(start, end)); } } - return addLeadingSlash(normalizeParts.join('/')); + return addLeadingSlash(normalizedParts.join('/')); } /** diff --git a/packages/angular/ssr/src/utils/validation.ts b/packages/angular/ssr/src/utils/validation.ts index 97ac8606f3b4..c89cdd6a64ed 100644 --- a/packages/angular/ssr/src/utils/validation.ts +++ b/packages/angular/ssr/src/utils/validation.ts @@ -26,6 +26,11 @@ const VALID_PROTO_REGEX = /^https?$/i; */ const VALID_HOST_REGEX = /^[a-z0-9.:-]+$/i; +/** + * Regular expression to validate that the prefix is valid. + */ +const INVALID_PREFIX_REGEX = /^[/\\]{2}|(?:^|[/\\])\.\.?(?:[/\\]|$)/; + /** * Extracts the first value from a multi-value header string. * @@ -253,4 +258,11 @@ function validateHeaders(request: Request): void { if (xForwardedProto && !VALID_PROTO_REGEX.test(xForwardedProto)) { throw new Error('Header "x-forwarded-proto" must be either "http" or "https".'); } + + const xForwardedPrefix = getFirstHeaderValue(headers.get('x-forwarded-prefix')); + if (xForwardedPrefix && INVALID_PREFIX_REGEX.test(xForwardedPrefix)) { + throw new Error( + 'Header "x-forwarded-prefix" must not start with multiple "/" or "\\" or contain ".", ".." path segments.', + ); + } } diff --git a/packages/angular/ssr/test/utils/url_spec.ts b/packages/angular/ssr/test/utils/url_spec.ts index 9a7a7cb3ad49..a108c7ff1df6 100644 --- a/packages/angular/ssr/test/utils/url_spec.ts +++ b/packages/angular/ssr/test/utils/url_spec.ts @@ -100,6 +100,18 @@ describe('URL Utils', () => { it('should handle an all-empty URL parts', () => { expect(joinUrlParts('', '')).toBe('/'); }); + + it('should normalize parts with multiple leading and trailing slashes', () => { + expect(joinUrlParts('//path//', '///to///', '//resource//')).toBe('/path/to/resource'); + }); + + it('should handle a single part', () => { + expect(joinUrlParts('path')).toBe('/path'); + }); + + it('should handle parts containing only slashes', () => { + expect(joinUrlParts('//', '///')).toBe('/'); + }); }); describe('stripIndexHtmlFromURL', () => { diff --git a/packages/angular/ssr/test/utils/validation_spec.ts b/packages/angular/ssr/test/utils/validation_spec.ts index 99fbf517b60d..10ab896e36f1 100644 --- a/packages/angular/ssr/test/utils/validation_spec.ts +++ b/packages/angular/ssr/test/utils/validation_spec.ts @@ -124,6 +124,73 @@ describe('Validation Utils', () => { 'Header "x-forwarded-host" contains characters that are not allowed.', ); }); + + it('should throw error if x-forwarded-prefix starts with multiple slashes or backslashes', () => { + const inputs = ['//evil', '\\\\evil', '/\\evil', '\\/evil']; + + for (const prefix of inputs) { + const request = new Request('https://example.com', { + headers: { + 'x-forwarded-prefix': prefix, + }, + }); + + expect(() => validateRequest(request, allowedHosts)) + .withContext(`Prefix: "${prefix}"`) + .toThrowError( + 'Header "x-forwarded-prefix" must not start with multiple "/" or "\\" or contain ".", ".." path segments.', + ); + } + }); + + it('should throw error if x-forwarded-prefix contains dot segments', () => { + const inputs = [ + '/./', + '/../', + '/foo/./bar', + '/foo/../bar', + '/.', + '/..', + './', + '../', + '.\\', + '..\\', + '/foo/.\\bar', + '/foo/..\\bar', + '.', + '..', + ]; + + for (const prefix of inputs) { + const request = new Request('https://example.com', { + headers: { + 'x-forwarded-prefix': prefix, + }, + }); + + expect(() => validateRequest(request, allowedHosts)) + .withContext(`Prefix: "${prefix}"`) + .toThrowError( + 'Header "x-forwarded-prefix" must not start with multiple "/" or "\\" or contain ".", ".." path segments.', + ); + } + }); + + it('should validate x-forwarded-prefix with valid dot usage', () => { + const inputs = ['/foo.bar', '/foo.bar/baz', '/v1.2', '/.well-known']; + + for (const prefix of inputs) { + const request = new Request('https://example.com', { + headers: { + 'x-forwarded-prefix': prefix, + }, + }); + + expect(() => validateRequest(request, allowedHosts)) + .withContext(`Prefix: "${prefix}"`) + .not.toThrow(); + } + }); }); describe('cloneRequestAndPatchHeaders', () => { From c0d1626e87b807845d898e30f52e2251aa81c2a0 Mon Sep 17 00:00:00 2001 From: Alan Agius <17563226+alan-agius4@users.noreply.github.com> Date: Mon, 23 Feb 2026 17:09:56 +0000 Subject: [PATCH 41/52] release: cut the v20.3.17 release --- CHANGELOG.md | 13 +++++++++++++ package.json | 2 +- 2 files changed, 14 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 71eb5de722cd..7e76df245531 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,16 @@ + + +# 20.3.17 (2026-02-23) + +### @angular/ssr + +| Commit | Type | Description | +| --------------------------------------------------------------------------------------------------- | ---- | --------------------------------------------------- | +| [8700e18d7](https://github.com/angular/angular-cli/commit/8700e18d7cf175d80fe6ce6205589767b7870c1c) | fix | prevent open redirect via X-Forwarded-Prefix header | +| [67582a946](https://github.com/angular/angular-cli/commit/67582a946808d2c021cbcfacbf203ef58a6fbded) | fix | validate host headers to prevent header-based SSRF | + + + # 20.3.16 (2026-02-09) diff --git a/package.json b/package.json index b76fb7e75829..558bedcec040 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@angular/devkit-repo", - "version": "20.3.16", + "version": "20.3.17", "private": true, "description": "Software Development Kit for Angular", "keywords": [ From f668e2778c4c4dbecc8a1c6831c092f5512d1ec1 Mon Sep 17 00:00:00 2001 From: Alan Agius <17563226+alan-agius4@users.noreply.github.com> Date: Thu, 26 Feb 2026 10:05:34 +0000 Subject: [PATCH 42/52] fix(@angular/build): update rollup to 4.59.0 This fixes GHSA-mw96-cpmx-2vgc Closes #32592 --- package.json | 2 +- packages/angular/build/package.json | 2 +- pnpm-lock.yaml | 487 +++++++++------------------- 3 files changed, 148 insertions(+), 343 deletions(-) diff --git a/package.json b/package.json index 558bedcec040..05e6c9c80384 100644 --- a/package.json +++ b/package.json @@ -132,7 +132,7 @@ "protractor": "~7.0.0", "puppeteer": "18.2.1", "quicktype-core": "23.2.6", - "rollup": "4.46.2", + "rollup": "4.59.0", "rollup-license-plugin": "~3.0.1", "semver": "7.7.2", "shelljs": "^0.10.0", diff --git a/packages/angular/build/package.json b/packages/angular/build/package.json index ea57319b5721..2a3a98d341da 100644 --- a/packages/angular/build/package.json +++ b/packages/angular/build/package.json @@ -37,7 +37,7 @@ "parse5-html-rewriting-stream": "8.0.0", "picomatch": "4.0.3", "piscina": "5.1.3", - "rollup": "4.52.3", + "rollup": "4.59.0", "sass": "1.90.0", "semver": "7.7.2", "source-map-support": "0.5.21", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 80137681a0e6..b9cf605c93f6 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -78,16 +78,16 @@ importers: version: 9.33.0 '@rollup/plugin-alias': specifier: ^5.1.1 - version: 5.1.1(rollup@4.46.2) + version: 5.1.1(rollup@4.59.0) '@rollup/plugin-commonjs': specifier: ^28.0.0 - version: 28.0.6(rollup@4.46.2) + version: 28.0.6(rollup@4.59.0) '@rollup/plugin-json': specifier: ^6.1.0 - version: 6.1.0(rollup@4.46.2) + version: 6.1.0(rollup@4.59.0) '@rollup/plugin-node-resolve': specifier: 16.0.1 - version: 16.0.1(rollup@4.46.2) + version: 16.0.1(rollup@4.59.0) '@stylistic/eslint-plugin': specifier: ^5.0.0 version: 5.4.0(eslint@9.33.0(jiti@1.21.7)) @@ -272,17 +272,17 @@ importers: specifier: 23.2.6 version: 23.2.6(encoding@0.1.13) rollup: - specifier: 4.46.2 - version: 4.46.2 + specifier: 4.59.0 + version: 4.59.0 rollup-license-plugin: specifier: ~3.0.1 version: 3.0.2 rollup-plugin-dts: specifier: 6.2.1 - version: 6.2.1(rollup@4.46.2)(typescript@5.9.2) + version: 6.2.1(rollup@4.59.0)(typescript@5.9.2) rollup-plugin-sourcemaps2: specifier: 0.5.3 - version: 0.5.3(@types/node@22.18.10)(rollup@4.46.2) + version: 0.5.3(@types/node@22.18.10)(rollup@4.59.0) semver: specifier: 7.7.2 version: 7.7.2 @@ -404,8 +404,8 @@ importers: specifier: 5.1.3 version: 5.1.3 rollup: - specifier: 4.52.3 - version: 4.52.3 + specifier: 4.59.0 + version: 4.59.0 sass: specifier: 1.90.0 version: 1.90.0 @@ -3071,235 +3071,141 @@ packages: rollup: optional: true - '@rollup/rollup-android-arm-eabi@4.46.2': - resolution: {integrity: sha512-Zj3Hl6sN34xJtMv7Anwb5Gu01yujyE/cLBDB2gnHTAHaWS1Z38L7kuSG+oAh0giZMqG060f/YBStXtMH6FvPMA==} + '@rollup/rollup-android-arm-eabi@4.59.0': + resolution: {integrity: sha512-upnNBkA6ZH2VKGcBj9Fyl9IGNPULcjXRlg0LLeaioQWueH30p6IXtJEbKAgvyv+mJaMxSm1l6xwDXYjpEMiLMg==} cpu: [arm] os: [android] - '@rollup/rollup-android-arm-eabi@4.52.3': - resolution: {integrity: sha512-h6cqHGZ6VdnwliFG1NXvMPTy/9PS3h8oLh7ImwR+kl+oYnQizgjxsONmmPSb2C66RksfkfIxEVtDSEcJiO0tqw==} - cpu: [arm] - os: [android] - - '@rollup/rollup-android-arm64@4.46.2': - resolution: {integrity: sha512-nTeCWY83kN64oQ5MGz3CgtPx8NSOhC5lWtsjTs+8JAJNLcP3QbLCtDDgUKQc/Ro/frpMq4SHUaHN6AMltcEoLQ==} - cpu: [arm64] - os: [android] - - '@rollup/rollup-android-arm64@4.52.3': - resolution: {integrity: sha512-wd+u7SLT/u6knklV/ifG7gr5Qy4GUbH2hMWcDauPFJzmCZUAJ8L2bTkVXC2niOIxp8lk3iH/QX8kSrUxVZrOVw==} + '@rollup/rollup-android-arm64@4.59.0': + resolution: {integrity: sha512-hZ+Zxj3SySm4A/DylsDKZAeVg0mvi++0PYVceVyX7hemkw7OreKdCvW2oQ3T1FMZvCaQXqOTHb8qmBShoqk69Q==} cpu: [arm64] os: [android] - '@rollup/rollup-darwin-arm64@4.46.2': - resolution: {integrity: sha512-HV7bW2Fb/F5KPdM/9bApunQh68YVDU8sO8BvcW9OngQVN3HHHkw99wFupuUJfGR9pYLLAjcAOA6iO+evsbBaPQ==} - cpu: [arm64] - os: [darwin] - - '@rollup/rollup-darwin-arm64@4.52.3': - resolution: {integrity: sha512-lj9ViATR1SsqycwFkJCtYfQTheBdvlWJqzqxwc9f2qrcVrQaF/gCuBRTiTolkRWS6KvNxSk4KHZWG7tDktLgjg==} + '@rollup/rollup-darwin-arm64@4.59.0': + resolution: {integrity: sha512-W2Psnbh1J8ZJw0xKAd8zdNgF9HRLkdWwwdWqubSVk0pUuQkoHnv7rx4GiF9rT4t5DIZGAsConRE3AxCdJ4m8rg==} cpu: [arm64] os: [darwin] - '@rollup/rollup-darwin-x64@4.46.2': - resolution: {integrity: sha512-SSj8TlYV5nJixSsm/y3QXfhspSiLYP11zpfwp6G/YDXctf3Xkdnk4woJIF5VQe0of2OjzTt8EsxnJDCdHd2xMA==} - cpu: [x64] - os: [darwin] - - '@rollup/rollup-darwin-x64@4.52.3': - resolution: {integrity: sha512-+Dyo7O1KUmIsbzx1l+4V4tvEVnVQqMOIYtrxK7ncLSknl1xnMHLgn7gddJVrYPNZfEB8CIi3hK8gq8bDhb3h5A==} + '@rollup/rollup-darwin-x64@4.59.0': + resolution: {integrity: sha512-ZW2KkwlS4lwTv7ZVsYDiARfFCnSGhzYPdiOU4IM2fDbL+QGlyAbjgSFuqNRbSthybLbIJ915UtZBtmuLrQAT/w==} cpu: [x64] os: [darwin] - '@rollup/rollup-freebsd-arm64@4.46.2': - resolution: {integrity: sha512-ZyrsG4TIT9xnOlLsSSi9w/X29tCbK1yegE49RYm3tu3wF1L/B6LVMqnEWyDB26d9Ecx9zrmXCiPmIabVuLmNSg==} + '@rollup/rollup-freebsd-arm64@4.59.0': + resolution: {integrity: sha512-EsKaJ5ytAu9jI3lonzn3BgG8iRBjV4LxZexygcQbpiU0wU0ATxhNVEpXKfUa0pS05gTcSDMKpn3Sx+QB9RlTTA==} cpu: [arm64] os: [freebsd] - '@rollup/rollup-freebsd-arm64@4.52.3': - resolution: {integrity: sha512-u9Xg2FavYbD30g3DSfNhxgNrxhi6xVG4Y6i9Ur1C7xUuGDW3banRbXj+qgnIrwRN4KeJ396jchwy9bCIzbyBEQ==} - cpu: [arm64] - os: [freebsd] - - '@rollup/rollup-freebsd-x64@4.46.2': - resolution: {integrity: sha512-pCgHFoOECwVCJ5GFq8+gR8SBKnMO+xe5UEqbemxBpCKYQddRQMgomv1104RnLSg7nNvgKy05sLsY51+OVRyiVw==} + '@rollup/rollup-freebsd-x64@4.59.0': + resolution: {integrity: sha512-d3DuZi2KzTMjImrxoHIAODUZYoUUMsuUiY4SRRcJy6NJoZ6iIqWnJu9IScV9jXysyGMVuW+KNzZvBLOcpdl3Vg==} cpu: [x64] os: [freebsd] - '@rollup/rollup-freebsd-x64@4.52.3': - resolution: {integrity: sha512-5M8kyi/OX96wtD5qJR89a/3x5x8x5inXBZO04JWhkQb2JWavOWfjgkdvUqibGJeNNaz1/Z1PPza5/tAPXICI6A==} - cpu: [x64] - os: [freebsd] - - '@rollup/rollup-linux-arm-gnueabihf@4.46.2': - resolution: {integrity: sha512-EtP8aquZ0xQg0ETFcxUbU71MZlHaw9MChwrQzatiE8U/bvi5uv/oChExXC4mWhjiqK7azGJBqU0tt5H123SzVA==} - cpu: [arm] - os: [linux] - libc: [glibc] - - '@rollup/rollup-linux-arm-gnueabihf@4.52.3': - resolution: {integrity: sha512-IoerZJ4l1wRMopEHRKOO16e04iXRDyZFZnNZKrWeNquh5d6bucjezgd+OxG03mOMTnS1x7hilzb3uURPkJ0OfA==} + '@rollup/rollup-linux-arm-gnueabihf@4.59.0': + resolution: {integrity: sha512-t4ONHboXi/3E0rT6OZl1pKbl2Vgxf9vJfWgmUoCEVQVxhW6Cw/c8I6hbbu7DAvgp82RKiH7TpLwxnJeKv2pbsw==} cpu: [arm] os: [linux] libc: [glibc] - '@rollup/rollup-linux-arm-musleabihf@4.46.2': - resolution: {integrity: sha512-qO7F7U3u1nfxYRPM8HqFtLd+raev2K137dsV08q/LRKRLEc7RsiDWihUnrINdsWQxPR9jqZ8DIIZ1zJJAm5PjQ==} + '@rollup/rollup-linux-arm-musleabihf@4.59.0': + resolution: {integrity: sha512-CikFT7aYPA2ufMD086cVORBYGHffBo4K8MQ4uPS/ZnY54GKj36i196u8U+aDVT2LX4eSMbyHtyOh7D7Zvk2VvA==} cpu: [arm] os: [linux] libc: [musl] - '@rollup/rollup-linux-arm-musleabihf@4.52.3': - resolution: {integrity: sha512-ZYdtqgHTDfvrJHSh3W22TvjWxwOgc3ThK/XjgcNGP2DIwFIPeAPNsQxrJO5XqleSlgDux2VAoWQ5iJrtaC1TbA==} - cpu: [arm] - os: [linux] - libc: [musl] - - '@rollup/rollup-linux-arm64-gnu@4.46.2': - resolution: {integrity: sha512-3dRaqLfcOXYsfvw5xMrxAk9Lb1f395gkoBYzSFcc/scgRFptRXL9DOaDpMiehf9CO8ZDRJW2z45b6fpU5nwjng==} + '@rollup/rollup-linux-arm64-gnu@4.59.0': + resolution: {integrity: sha512-jYgUGk5aLd1nUb1CtQ8E+t5JhLc9x5WdBKew9ZgAXg7DBk0ZHErLHdXM24rfX+bKrFe+Xp5YuJo54I5HFjGDAA==} cpu: [arm64] os: [linux] libc: [glibc] - '@rollup/rollup-linux-arm64-gnu@4.52.3': - resolution: {integrity: sha512-NcViG7A0YtuFDA6xWSgmFb6iPFzHlf5vcqb2p0lGEbT+gjrEEz8nC/EeDHvx6mnGXnGCC1SeVV+8u+smj0CeGQ==} - cpu: [arm64] - os: [linux] - libc: [glibc] - - '@rollup/rollup-linux-arm64-musl@4.46.2': - resolution: {integrity: sha512-fhHFTutA7SM+IrR6lIfiHskxmpmPTJUXpWIsBXpeEwNgZzZZSg/q4i6FU4J8qOGyJ0TR+wXBwx/L7Ho9z0+uDg==} - cpu: [arm64] - os: [linux] - libc: [musl] - - '@rollup/rollup-linux-arm64-musl@4.52.3': - resolution: {integrity: sha512-d3pY7LWno6SYNXRm6Ebsq0DJGoiLXTb83AIPCXl9fmtIQs/rXoS8SJxxUNtFbJ5MiOvs+7y34np77+9l4nfFMw==} + '@rollup/rollup-linux-arm64-musl@4.59.0': + resolution: {integrity: sha512-peZRVEdnFWZ5Bh2KeumKG9ty7aCXzzEsHShOZEFiCQlDEepP1dpUl/SrUNXNg13UmZl+gzVDPsiCwnV1uI0RUA==} cpu: [arm64] os: [linux] libc: [musl] - '@rollup/rollup-linux-loong64-gnu@4.52.3': - resolution: {integrity: sha512-3y5GA0JkBuirLqmjwAKwB0keDlI6JfGYduMlJD/Rl7fvb4Ni8iKdQs1eiunMZJhwDWdCvrcqXRY++VEBbvk6Eg==} + '@rollup/rollup-linux-loong64-gnu@4.59.0': + resolution: {integrity: sha512-gbUSW/97f7+r4gHy3Jlup8zDG190AuodsWnNiXErp9mT90iCy9NKKU0Xwx5k8VlRAIV2uU9CsMnEFg/xXaOfXg==} cpu: [loong64] os: [linux] libc: [glibc] - '@rollup/rollup-linux-loongarch64-gnu@4.46.2': - resolution: {integrity: sha512-i7wfGFXu8x4+FRqPymzjD+Hyav8l95UIZ773j7J7zRYc3Xsxy2wIn4x+llpunexXe6laaO72iEjeeGyUFmjKeA==} + '@rollup/rollup-linux-loong64-musl@4.59.0': + resolution: {integrity: sha512-yTRONe79E+o0FWFijasoTjtzG9EBedFXJMl888NBEDCDV9I2wGbFFfJQQe63OijbFCUZqxpHz1GzpbtSFikJ4Q==} cpu: [loong64] os: [linux] - libc: [glibc] + libc: [musl] - '@rollup/rollup-linux-ppc64-gnu@4.46.2': - resolution: {integrity: sha512-B/l0dFcHVUnqcGZWKcWBSV2PF01YUt0Rvlurci5P+neqY/yMKchGU8ullZvIv5e8Y1C6wOn+U03mrDylP5q9Yw==} + '@rollup/rollup-linux-ppc64-gnu@4.59.0': + resolution: {integrity: sha512-sw1o3tfyk12k3OEpRddF68a1unZ5VCN7zoTNtSn2KndUE+ea3m3ROOKRCZxEpmT9nsGnogpFP9x6mnLTCaoLkA==} cpu: [ppc64] os: [linux] libc: [glibc] - '@rollup/rollup-linux-ppc64-gnu@4.52.3': - resolution: {integrity: sha512-AUUH65a0p3Q0Yfm5oD2KVgzTKgwPyp9DSXc3UA7DtxhEb/WSPfbG4wqXeSN62OG5gSo18em4xv6dbfcUGXcagw==} + '@rollup/rollup-linux-ppc64-musl@4.59.0': + resolution: {integrity: sha512-+2kLtQ4xT3AiIxkzFVFXfsmlZiG5FXYW7ZyIIvGA7Bdeuh9Z0aN4hVyXS/G1E9bTP/vqszNIN/pUKCk/BTHsKA==} cpu: [ppc64] os: [linux] - libc: [glibc] - - '@rollup/rollup-linux-riscv64-gnu@4.46.2': - resolution: {integrity: sha512-32k4ENb5ygtkMwPMucAb8MtV8olkPT03oiTxJbgkJa7lJ7dZMr0GCFJlyvy+K8iq7F/iuOr41ZdUHaOiqyR3iQ==} - cpu: [riscv64] - os: [linux] - libc: [glibc] + libc: [musl] - '@rollup/rollup-linux-riscv64-gnu@4.52.3': - resolution: {integrity: sha512-1makPhFFVBqZE+XFg3Dkq+IkQ7JvmUrwwqaYBL2CE+ZpxPaqkGaiWFEWVGyvTwZace6WLJHwjVh/+CXbKDGPmg==} + '@rollup/rollup-linux-riscv64-gnu@4.59.0': + resolution: {integrity: sha512-NDYMpsXYJJaj+I7UdwIuHHNxXZ/b/N2hR15NyH3m2qAtb/hHPA4g4SuuvrdxetTdndfj9b1WOmy73kcPRoERUg==} cpu: [riscv64] os: [linux] libc: [glibc] - '@rollup/rollup-linux-riscv64-musl@4.46.2': - resolution: {integrity: sha512-t5B2loThlFEauloaQkZg9gxV05BYeITLvLkWOkRXogP4qHXLkWSbSHKM9S6H1schf/0YGP/qNKtiISlxvfmmZw==} - cpu: [riscv64] - os: [linux] - libc: [musl] - - '@rollup/rollup-linux-riscv64-musl@4.52.3': - resolution: {integrity: sha512-OOFJa28dxfl8kLOPMUOQBCO6z3X2SAfzIE276fwT52uXDWUS178KWq0pL7d6p1kz7pkzA0yQwtqL0dEPoVcRWg==} + '@rollup/rollup-linux-riscv64-musl@4.59.0': + resolution: {integrity: sha512-nLckB8WOqHIf1bhymk+oHxvM9D3tyPndZH8i8+35p/1YiVoVswPid2yLzgX7ZJP0KQvnkhM4H6QZ5m0LzbyIAg==} cpu: [riscv64] os: [linux] libc: [musl] - '@rollup/rollup-linux-s390x-gnu@4.46.2': - resolution: {integrity: sha512-YKjekwTEKgbB7n17gmODSmJVUIvj8CX7q5442/CK80L8nqOUbMtf8b01QkG3jOqyr1rotrAnW6B/qiHwfcuWQA==} + '@rollup/rollup-linux-s390x-gnu@4.59.0': + resolution: {integrity: sha512-oF87Ie3uAIvORFBpwnCvUzdeYUqi2wY6jRFWJAy1qus/udHFYIkplYRW+wo+GRUP4sKzYdmE1Y3+rY5Gc4ZO+w==} cpu: [s390x] os: [linux] libc: [glibc] - '@rollup/rollup-linux-s390x-gnu@4.52.3': - resolution: {integrity: sha512-jMdsML2VI5l+V7cKfZx3ak+SLlJ8fKvLJ0Eoa4b9/vCUrzXKgoKxvHqvJ/mkWhFiyp88nCkM5S2v6nIwRtPcgg==} - cpu: [s390x] - os: [linux] - libc: [glibc] - - '@rollup/rollup-linux-x64-gnu@4.46.2': - resolution: {integrity: sha512-Jj5a9RUoe5ra+MEyERkDKLwTXVu6s3aACP51nkfnK9wJTraCC8IMe3snOfALkrjTYd2G1ViE1hICj0fZ7ALBPA==} - cpu: [x64] - os: [linux] - libc: [glibc] - - '@rollup/rollup-linux-x64-gnu@4.52.3': - resolution: {integrity: sha512-tPgGd6bY2M2LJTA1uGq8fkSPK8ZLYjDjY+ZLK9WHncCnfIz29LIXIqUgzCR0hIefzy6Hpbe8Th5WOSwTM8E7LA==} + '@rollup/rollup-linux-x64-gnu@4.59.0': + resolution: {integrity: sha512-3AHmtQq/ppNuUspKAlvA8HtLybkDflkMuLK4DPo77DfthRb71V84/c4MlWJXixZz4uruIH4uaa07IqoAkG64fg==} cpu: [x64] os: [linux] libc: [glibc] - '@rollup/rollup-linux-x64-musl@4.46.2': - resolution: {integrity: sha512-7kX69DIrBeD7yNp4A5b81izs8BqoZkCIaxQaOpumcJ1S/kmqNFjPhDu1LHeVXv0SexfHQv5cqHsxLOjETuqDuA==} + '@rollup/rollup-linux-x64-musl@4.59.0': + resolution: {integrity: sha512-2UdiwS/9cTAx7qIUZB/fWtToJwvt0Vbo0zmnYt7ED35KPg13Q0ym1g442THLC7VyI6JfYTP4PiSOWyoMdV2/xg==} cpu: [x64] os: [linux] libc: [musl] - '@rollup/rollup-linux-x64-musl@4.52.3': - resolution: {integrity: sha512-BCFkJjgk+WFzP+tcSMXq77ymAPIxsX9lFJWs+2JzuZTLtksJ2o5hvgTdIcZ5+oKzUDMwI0PfWzRBYAydAHF2Mw==} + '@rollup/rollup-openbsd-x64@4.59.0': + resolution: {integrity: sha512-M3bLRAVk6GOwFlPTIxVBSYKUaqfLrn8l0psKinkCFxl4lQvOSz8ZrKDz2gxcBwHFpci0B6rttydI4IpS4IS/jQ==} cpu: [x64] - os: [linux] - libc: [musl] + os: [openbsd] - '@rollup/rollup-openharmony-arm64@4.52.3': - resolution: {integrity: sha512-KTD/EqjZF3yvRaWUJdD1cW+IQBk4fbQaHYJUmP8N4XoKFZilVL8cobFSTDnjTtxWJQ3JYaMgF4nObY/+nYkumA==} + '@rollup/rollup-openharmony-arm64@4.59.0': + resolution: {integrity: sha512-tt9KBJqaqp5i5HUZzoafHZX8b5Q2Fe7UjYERADll83O4fGqJ49O1FsL6LpdzVFQcpwvnyd0i+K/VSwu/o/nWlA==} cpu: [arm64] os: [openharmony] - '@rollup/rollup-win32-arm64-msvc@4.46.2': - resolution: {integrity: sha512-wiJWMIpeaak/jsbaq2HMh/rzZxHVW1rU6coyeNNpMwk5isiPjSTx0a4YLSlYDwBH/WBvLz+EtsNqQScZTLJy3g==} + '@rollup/rollup-win32-arm64-msvc@4.59.0': + resolution: {integrity: sha512-V5B6mG7OrGTwnxaNUzZTDTjDS7F75PO1ae6MJYdiMu60sq0CqN5CVeVsbhPxalupvTX8gXVSU9gq+Rx1/hvu6A==} cpu: [arm64] os: [win32] - '@rollup/rollup-win32-arm64-msvc@4.52.3': - resolution: {integrity: sha512-+zteHZdoUYLkyYKObGHieibUFLbttX2r+58l27XZauq0tcWYYuKUwY2wjeCN9oK1Um2YgH2ibd6cnX/wFD7DuA==} - cpu: [arm64] - os: [win32] - - '@rollup/rollup-win32-ia32-msvc@4.46.2': - resolution: {integrity: sha512-gBgaUDESVzMgWZhcyjfs9QFK16D8K6QZpwAaVNJxYDLHWayOta4ZMjGm/vsAEy3hvlS2GosVFlBlP9/Wb85DqQ==} + '@rollup/rollup-win32-ia32-msvc@4.59.0': + resolution: {integrity: sha512-UKFMHPuM9R0iBegwzKF4y0C4J9u8C6MEJgFuXTBerMk7EJ92GFVFYBfOZaSGLu6COf7FxpQNqhNS4c4icUPqxA==} cpu: [ia32] os: [win32] - '@rollup/rollup-win32-ia32-msvc@4.52.3': - resolution: {integrity: sha512-of1iHkTQSo3kr6dTIRX6t81uj/c/b15HXVsPcEElN5sS859qHrOepM5p9G41Hah+CTqSh2r8Bm56dL2z9UQQ7g==} - cpu: [ia32] - os: [win32] - - '@rollup/rollup-win32-x64-gnu@4.52.3': - resolution: {integrity: sha512-s0hybmlHb56mWVZQj8ra9048/WZTPLILKxcvcq+8awSZmyiSUZjjem1AhU3Tf4ZKpYhK4mg36HtHDOe8QJS5PQ==} - cpu: [x64] - os: [win32] - - '@rollup/rollup-win32-x64-msvc@4.46.2': - resolution: {integrity: sha512-CvUo2ixeIQGtF6WvuB87XWqPQkoFAFqW+HUo/WzHwuHDvIwZCtjdWXoYCcr06iKGydiqTclC4jU/TNObC/xKZg==} + '@rollup/rollup-win32-x64-gnu@4.59.0': + resolution: {integrity: sha512-laBkYlSS1n2L8fSo1thDNGrCTQMmxjYY5G0WFWjFFYZkKPjsMBsgJfGf4TLxXrF6RyhI60L8TMOjBMvXiTcxeA==} cpu: [x64] os: [win32] - '@rollup/rollup-win32-x64-msvc@4.52.3': - resolution: {integrity: sha512-zGIbEVVXVtauFgl3MRwGWEN36P5ZGenHRMgNw88X5wEhEBpq0XrMEZwOn07+ICrwM17XO5xfMZqh0OldCH5VTA==} + '@rollup/rollup-win32-x64-msvc@4.59.0': + resolution: {integrity: sha512-2HRCml6OztYXyJXAvdDXPKcawukWY2GpR5/nxKp4iBgiO3wcoEGkAaqctIbZcNB6KlUQBIqt8VYkNSj2397EfA==} cpu: [x64] os: [win32] @@ -7870,13 +7776,8 @@ packages: '@types/node': optional: true - rollup@4.46.2: - resolution: {integrity: sha512-WMmLFI+Boh6xbop+OAGo9cQ3OgX9MIg7xOQjn+pTCwOkk+FNDAeAemXkJ3HzDJrVXleLOFVa1ipuc1AmEx1Dwg==} - engines: {node: '>=18.0.0', npm: '>=8.0.0'} - hasBin: true - - rollup@4.52.3: - resolution: {integrity: sha512-RIDh866U8agLgiIcdpB+COKnlCreHJLfIhWC3LVflku5YHfpnsIKigRZeFfMfCc4dVcqNVfQQ5gO/afOck064A==} + rollup@4.59.0: + resolution: {integrity: sha512-2oMpl67a3zCH9H79LeMcbDhXW/UmWG/y2zuqnF2jQq5uq9TbM9TVyXvA4+t+ne2IIkBdrLpAaRQAvo7YI/Yyeg==} engines: {node: '>=18.0.0', npm: '>=8.0.0'} hasBin: true @@ -11645,13 +11546,13 @@ snapshots: - react-native-b4a - supports-color - '@rollup/plugin-alias@5.1.1(rollup@4.46.2)': + '@rollup/plugin-alias@5.1.1(rollup@4.59.0)': optionalDependencies: - rollup: 4.46.2 + rollup: 4.59.0 - '@rollup/plugin-commonjs@28.0.6(rollup@4.46.2)': + '@rollup/plugin-commonjs@28.0.6(rollup@4.59.0)': dependencies: - '@rollup/pluginutils': 5.3.0(rollup@4.46.2) + '@rollup/pluginutils': 5.3.0(rollup@4.59.0) commondir: 1.0.1 estree-walker: 2.0.2 fdir: 6.5.0(picomatch@4.0.3) @@ -11659,188 +11560,123 @@ snapshots: magic-string: 0.30.17 picomatch: 4.0.3 optionalDependencies: - rollup: 4.46.2 - - '@rollup/plugin-json@6.1.0(rollup@4.46.2)': - dependencies: - '@rollup/pluginutils': 5.3.0(rollup@4.46.2) - optionalDependencies: - rollup: 4.46.2 + rollup: 4.59.0 - '@rollup/plugin-json@6.1.0(rollup@4.52.3)': + '@rollup/plugin-json@6.1.0(rollup@4.59.0)': dependencies: - '@rollup/pluginutils': 5.3.0(rollup@4.52.3) + '@rollup/pluginutils': 5.3.0(rollup@4.59.0) optionalDependencies: - rollup: 4.52.3 + rollup: 4.59.0 - '@rollup/plugin-node-resolve@15.3.1(rollup@4.52.3)': + '@rollup/plugin-node-resolve@15.3.1(rollup@4.59.0)': dependencies: - '@rollup/pluginutils': 5.3.0(rollup@4.52.3) + '@rollup/pluginutils': 5.3.0(rollup@4.59.0) '@types/resolve': 1.20.2 deepmerge: 4.3.1 is-module: 1.0.0 resolve: 1.22.10 optionalDependencies: - rollup: 4.52.3 + rollup: 4.59.0 - '@rollup/plugin-node-resolve@16.0.1(rollup@4.46.2)': + '@rollup/plugin-node-resolve@16.0.1(rollup@4.59.0)': dependencies: - '@rollup/pluginutils': 5.3.0(rollup@4.46.2) + '@rollup/pluginutils': 5.3.0(rollup@4.59.0) '@types/resolve': 1.20.2 deepmerge: 4.3.1 is-module: 1.0.0 resolve: 1.22.10 optionalDependencies: - rollup: 4.46.2 - - '@rollup/pluginutils@5.2.0(rollup@4.46.2)': - dependencies: - '@types/estree': 1.0.8 - estree-walker: 2.0.2 - picomatch: 4.0.3 - optionalDependencies: - rollup: 4.46.2 + rollup: 4.59.0 - '@rollup/pluginutils@5.3.0(rollup@4.46.2)': + '@rollup/pluginutils@5.2.0(rollup@4.59.0)': dependencies: '@types/estree': 1.0.8 estree-walker: 2.0.2 picomatch: 4.0.3 optionalDependencies: - rollup: 4.46.2 + rollup: 4.59.0 - '@rollup/pluginutils@5.3.0(rollup@4.52.3)': + '@rollup/pluginutils@5.3.0(rollup@4.59.0)': dependencies: '@types/estree': 1.0.8 estree-walker: 2.0.2 picomatch: 4.0.3 optionalDependencies: - rollup: 4.52.3 + rollup: 4.59.0 - '@rollup/rollup-android-arm-eabi@4.46.2': + '@rollup/rollup-android-arm-eabi@4.59.0': optional: true - '@rollup/rollup-android-arm-eabi@4.52.3': + '@rollup/rollup-android-arm64@4.59.0': optional: true - '@rollup/rollup-android-arm64@4.46.2': + '@rollup/rollup-darwin-arm64@4.59.0': optional: true - '@rollup/rollup-android-arm64@4.52.3': + '@rollup/rollup-darwin-x64@4.59.0': optional: true - '@rollup/rollup-darwin-arm64@4.46.2': + '@rollup/rollup-freebsd-arm64@4.59.0': optional: true - '@rollup/rollup-darwin-arm64@4.52.3': + '@rollup/rollup-freebsd-x64@4.59.0': optional: true - '@rollup/rollup-darwin-x64@4.46.2': + '@rollup/rollup-linux-arm-gnueabihf@4.59.0': optional: true - '@rollup/rollup-darwin-x64@4.52.3': + '@rollup/rollup-linux-arm-musleabihf@4.59.0': optional: true - '@rollup/rollup-freebsd-arm64@4.46.2': + '@rollup/rollup-linux-arm64-gnu@4.59.0': optional: true - '@rollup/rollup-freebsd-arm64@4.52.3': + '@rollup/rollup-linux-arm64-musl@4.59.0': optional: true - '@rollup/rollup-freebsd-x64@4.46.2': + '@rollup/rollup-linux-loong64-gnu@4.59.0': optional: true - '@rollup/rollup-freebsd-x64@4.52.3': + '@rollup/rollup-linux-loong64-musl@4.59.0': optional: true - '@rollup/rollup-linux-arm-gnueabihf@4.46.2': + '@rollup/rollup-linux-ppc64-gnu@4.59.0': optional: true - '@rollup/rollup-linux-arm-gnueabihf@4.52.3': + '@rollup/rollup-linux-ppc64-musl@4.59.0': optional: true - '@rollup/rollup-linux-arm-musleabihf@4.46.2': + '@rollup/rollup-linux-riscv64-gnu@4.59.0': optional: true - '@rollup/rollup-linux-arm-musleabihf@4.52.3': + '@rollup/rollup-linux-riscv64-musl@4.59.0': optional: true - '@rollup/rollup-linux-arm64-gnu@4.46.2': + '@rollup/rollup-linux-s390x-gnu@4.59.0': optional: true - '@rollup/rollup-linux-arm64-gnu@4.52.3': + '@rollup/rollup-linux-x64-gnu@4.59.0': optional: true - '@rollup/rollup-linux-arm64-musl@4.46.2': + '@rollup/rollup-linux-x64-musl@4.59.0': optional: true - '@rollup/rollup-linux-arm64-musl@4.52.3': + '@rollup/rollup-openbsd-x64@4.59.0': optional: true - '@rollup/rollup-linux-loong64-gnu@4.52.3': + '@rollup/rollup-openharmony-arm64@4.59.0': optional: true - '@rollup/rollup-linux-loongarch64-gnu@4.46.2': + '@rollup/rollup-win32-arm64-msvc@4.59.0': optional: true - '@rollup/rollup-linux-ppc64-gnu@4.46.2': + '@rollup/rollup-win32-ia32-msvc@4.59.0': optional: true - '@rollup/rollup-linux-ppc64-gnu@4.52.3': + '@rollup/rollup-win32-x64-gnu@4.59.0': optional: true - '@rollup/rollup-linux-riscv64-gnu@4.46.2': - optional: true - - '@rollup/rollup-linux-riscv64-gnu@4.52.3': - optional: true - - '@rollup/rollup-linux-riscv64-musl@4.46.2': - optional: true - - '@rollup/rollup-linux-riscv64-musl@4.52.3': - optional: true - - '@rollup/rollup-linux-s390x-gnu@4.46.2': - optional: true - - '@rollup/rollup-linux-s390x-gnu@4.52.3': - optional: true - - '@rollup/rollup-linux-x64-gnu@4.46.2': - optional: true - - '@rollup/rollup-linux-x64-gnu@4.52.3': - optional: true - - '@rollup/rollup-linux-x64-musl@4.46.2': - optional: true - - '@rollup/rollup-linux-x64-musl@4.52.3': - optional: true - - '@rollup/rollup-openharmony-arm64@4.52.3': - optional: true - - '@rollup/rollup-win32-arm64-msvc@4.46.2': - optional: true - - '@rollup/rollup-win32-arm64-msvc@4.52.3': - optional: true - - '@rollup/rollup-win32-ia32-msvc@4.46.2': - optional: true - - '@rollup/rollup-win32-ia32-msvc@4.52.3': - optional: true - - '@rollup/rollup-win32-x64-gnu@4.52.3': - optional: true - - '@rollup/rollup-win32-x64-msvc@4.46.2': - optional: true - - '@rollup/rollup-win32-x64-msvc@4.52.3': + '@rollup/rollup-win32-x64-msvc@4.59.0': optional: true '@rollup/wasm-node@4.52.4': @@ -12613,11 +12449,11 @@ snapshots: '@web/dev-server-rollup@0.6.4(bufferutil@4.0.9)': dependencies: - '@rollup/plugin-node-resolve': 15.3.1(rollup@4.52.3) + '@rollup/plugin-node-resolve': 15.3.1(rollup@4.59.0) '@web/dev-server-core': 0.7.5(bufferutil@4.0.9) nanocolors: 0.2.13 parse5: 6.0.1 - rollup: 4.52.3 + rollup: 4.59.0 whatwg-url: 14.2.0 transitivePeerDependencies: - bufferutil @@ -16303,7 +16139,7 @@ snapshots: dependencies: '@ampproject/remapping': 2.3.0 '@angular/compiler-cli': 20.3.7(@angular/compiler@20.3.7)(typescript@5.9.2) - '@rollup/plugin-json': 6.1.0(rollup@4.52.3) + '@rollup/plugin-json': 6.1.0(rollup@4.59.0) '@rollup/wasm-node': 4.52.4 ajv: 8.17.1 ansi-colors: 4.1.3 @@ -16319,14 +16155,14 @@ snapshots: ora: 8.2.0 piscina: 5.1.3 postcss: 8.5.6 - rollup-plugin-dts: 6.2.1(rollup@4.52.3)(typescript@5.9.2) + rollup-plugin-dts: 6.2.1(rollup@4.59.0)(typescript@5.9.2) rxjs: 7.8.2 sass: 1.90.0 tinyglobby: 0.2.14 tslib: 2.8.1 typescript: 5.9.2 optionalDependencies: - rollup: 4.52.3 + rollup: 4.59.0 nock@14.0.10: dependencies: @@ -17257,81 +17093,50 @@ snapshots: node-fetch: 3.3.2 spdx-expression-validate: 2.0.0 - rollup-plugin-dts@6.2.1(rollup@4.46.2)(typescript@5.9.2): + rollup-plugin-dts@6.2.1(rollup@4.59.0)(typescript@5.9.2): dependencies: magic-string: 0.30.17 - rollup: 4.46.2 + rollup: 4.59.0 typescript: 5.9.2 optionalDependencies: '@babel/code-frame': 7.27.1 - rollup-plugin-dts@6.2.1(rollup@4.52.3)(typescript@5.9.2): + rollup-plugin-sourcemaps2@0.5.3(@types/node@22.18.10)(rollup@4.59.0): dependencies: - magic-string: 0.30.17 - rollup: 4.52.3 - typescript: 5.9.2 - optionalDependencies: - '@babel/code-frame': 7.27.1 - - rollup-plugin-sourcemaps2@0.5.3(@types/node@22.18.10)(rollup@4.46.2): - dependencies: - '@rollup/pluginutils': 5.2.0(rollup@4.46.2) - rollup: 4.46.2 + '@rollup/pluginutils': 5.2.0(rollup@4.59.0) + rollup: 4.59.0 optionalDependencies: '@types/node': 22.18.10 - rollup@4.46.2: - dependencies: - '@types/estree': 1.0.8 - optionalDependencies: - '@rollup/rollup-android-arm-eabi': 4.46.2 - '@rollup/rollup-android-arm64': 4.46.2 - '@rollup/rollup-darwin-arm64': 4.46.2 - '@rollup/rollup-darwin-x64': 4.46.2 - '@rollup/rollup-freebsd-arm64': 4.46.2 - '@rollup/rollup-freebsd-x64': 4.46.2 - '@rollup/rollup-linux-arm-gnueabihf': 4.46.2 - '@rollup/rollup-linux-arm-musleabihf': 4.46.2 - '@rollup/rollup-linux-arm64-gnu': 4.46.2 - '@rollup/rollup-linux-arm64-musl': 4.46.2 - '@rollup/rollup-linux-loongarch64-gnu': 4.46.2 - '@rollup/rollup-linux-ppc64-gnu': 4.46.2 - '@rollup/rollup-linux-riscv64-gnu': 4.46.2 - '@rollup/rollup-linux-riscv64-musl': 4.46.2 - '@rollup/rollup-linux-s390x-gnu': 4.46.2 - '@rollup/rollup-linux-x64-gnu': 4.46.2 - '@rollup/rollup-linux-x64-musl': 4.46.2 - '@rollup/rollup-win32-arm64-msvc': 4.46.2 - '@rollup/rollup-win32-ia32-msvc': 4.46.2 - '@rollup/rollup-win32-x64-msvc': 4.46.2 - fsevents: 2.3.3 - - rollup@4.52.3: + rollup@4.59.0: dependencies: '@types/estree': 1.0.8 optionalDependencies: - '@rollup/rollup-android-arm-eabi': 4.52.3 - '@rollup/rollup-android-arm64': 4.52.3 - '@rollup/rollup-darwin-arm64': 4.52.3 - '@rollup/rollup-darwin-x64': 4.52.3 - '@rollup/rollup-freebsd-arm64': 4.52.3 - '@rollup/rollup-freebsd-x64': 4.52.3 - '@rollup/rollup-linux-arm-gnueabihf': 4.52.3 - '@rollup/rollup-linux-arm-musleabihf': 4.52.3 - '@rollup/rollup-linux-arm64-gnu': 4.52.3 - '@rollup/rollup-linux-arm64-musl': 4.52.3 - '@rollup/rollup-linux-loong64-gnu': 4.52.3 - '@rollup/rollup-linux-ppc64-gnu': 4.52.3 - '@rollup/rollup-linux-riscv64-gnu': 4.52.3 - '@rollup/rollup-linux-riscv64-musl': 4.52.3 - '@rollup/rollup-linux-s390x-gnu': 4.52.3 - '@rollup/rollup-linux-x64-gnu': 4.52.3 - '@rollup/rollup-linux-x64-musl': 4.52.3 - '@rollup/rollup-openharmony-arm64': 4.52.3 - '@rollup/rollup-win32-arm64-msvc': 4.52.3 - '@rollup/rollup-win32-ia32-msvc': 4.52.3 - '@rollup/rollup-win32-x64-gnu': 4.52.3 - '@rollup/rollup-win32-x64-msvc': 4.52.3 + '@rollup/rollup-android-arm-eabi': 4.59.0 + '@rollup/rollup-android-arm64': 4.59.0 + '@rollup/rollup-darwin-arm64': 4.59.0 + '@rollup/rollup-darwin-x64': 4.59.0 + '@rollup/rollup-freebsd-arm64': 4.59.0 + '@rollup/rollup-freebsd-x64': 4.59.0 + '@rollup/rollup-linux-arm-gnueabihf': 4.59.0 + '@rollup/rollup-linux-arm-musleabihf': 4.59.0 + '@rollup/rollup-linux-arm64-gnu': 4.59.0 + '@rollup/rollup-linux-arm64-musl': 4.59.0 + '@rollup/rollup-linux-loong64-gnu': 4.59.0 + '@rollup/rollup-linux-loong64-musl': 4.59.0 + '@rollup/rollup-linux-ppc64-gnu': 4.59.0 + '@rollup/rollup-linux-ppc64-musl': 4.59.0 + '@rollup/rollup-linux-riscv64-gnu': 4.59.0 + '@rollup/rollup-linux-riscv64-musl': 4.59.0 + '@rollup/rollup-linux-s390x-gnu': 4.59.0 + '@rollup/rollup-linux-x64-gnu': 4.59.0 + '@rollup/rollup-linux-x64-musl': 4.59.0 + '@rollup/rollup-openbsd-x64': 4.59.0 + '@rollup/rollup-openharmony-arm64': 4.59.0 + '@rollup/rollup-win32-arm64-msvc': 4.59.0 + '@rollup/rollup-win32-ia32-msvc': 4.59.0 + '@rollup/rollup-win32-x64-gnu': 4.59.0 + '@rollup/rollup-win32-x64-msvc': 4.59.0 fsevents: 2.3.3 router@2.2.0: @@ -18470,7 +18275,7 @@ snapshots: fdir: 6.5.0(picomatch@4.0.3) picomatch: 4.0.3 postcss: 8.5.6 - rollup: 4.52.3 + rollup: 4.59.0 tinyglobby: 0.2.15 optionalDependencies: '@types/node': 24.9.1 @@ -18488,7 +18293,7 @@ snapshots: fdir: 6.5.0(picomatch@4.0.3) picomatch: 4.0.3 postcss: 8.5.6 - rollup: 4.52.3 + rollup: 4.59.0 tinyglobby: 0.2.15 optionalDependencies: '@types/node': 24.9.1 From 39596d529f831f72a2134bc3c9ac163867ff5702 Mon Sep 17 00:00:00 2001 From: Alan Agius <17563226+alan-agius4@users.noreply.github.com> Date: Thu, 26 Feb 2026 10:06:32 +0000 Subject: [PATCH 43/52] fix(@angular-devkit/core): update `ajv` to `8.18.0` This fixes GHSA-2g4f-4pwh-qvx6 Closes #32592 --- package.json | 2 +- packages/angular_devkit/core/package.json | 2 +- pnpm-lock.yaml | 34 ++++++++++++++++------- 3 files changed, 26 insertions(+), 12 deletions(-) diff --git a/package.json b/package.json index 05e6c9c80384..26f7b8512c1e 100644 --- a/package.json +++ b/package.json @@ -96,7 +96,7 @@ "@types/yarnpkg__lockfile": "^1.1.5", "@typescript-eslint/eslint-plugin": "8.39.1", "@typescript-eslint/parser": "8.39.1", - "ajv": "8.17.1", + "ajv": "8.18.0", "ansi-colors": "4.1.3", "beasties": "0.3.5", "buffer": "6.0.3", diff --git a/packages/angular_devkit/core/package.json b/packages/angular_devkit/core/package.json index 2fa6f3eb24a4..e2daae128bdc 100644 --- a/packages/angular_devkit/core/package.json +++ b/packages/angular_devkit/core/package.json @@ -25,7 +25,7 @@ "./*.js": "./*.js" }, "dependencies": { - "ajv": "8.17.1", + "ajv": "8.18.0", "ajv-formats": "3.0.1", "jsonc-parser": "3.3.1", "picomatch": "4.0.3", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index b9cf605c93f6..da74e29c83af 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -170,8 +170,8 @@ importers: specifier: 8.39.1 version: 8.39.1(eslint@9.33.0(jiti@1.21.7))(typescript@5.9.2) ajv: - specifier: 8.17.1 - version: 8.17.1 + specifier: 8.18.0 + version: 8.18.0 ansi-colors: specifier: 4.1.3 version: 4.1.3 @@ -795,11 +795,11 @@ importers: packages/angular_devkit/core: dependencies: ajv: - specifier: 8.17.1 - version: 8.17.1 + specifier: 8.18.0 + version: 8.18.0 ajv-formats: specifier: 3.0.1 - version: 3.0.1(ajv@8.17.1) + version: 3.0.1(ajv@8.18.0) jsonc-parser: specifier: 3.3.1 version: 3.3.1 @@ -3938,6 +3938,9 @@ packages: ajv@8.17.1: resolution: {integrity: sha512-B/gBuNg5SiMTrPkC+A2+cW0RszwxYmn6VYxB/inlBStS5nx6xHIt/ehKRhIMhqusl7a8LjQoZnjCs5vhwxOQ1g==} + ajv@8.18.0: + resolution: {integrity: sha512-PlXPeEWMXMZ7sPYOHqmDyCJzcfNrUr3fGNKtezX14ykXOEIvyK81d+qydx89KY5O71FKMPaQ2vBfBFI5NHR63A==} + algoliasearch@5.35.0: resolution: {integrity: sha512-Y+moNhsqgLmvJdgTsO4GZNgsaDWv8AOGAaPeIeHKlDn/XunoAqYbA+XNpBd1dW8GOXAUDyxC9Rxc7AV4kpFcIg==} engines: {node: '>= 14.0.0'} @@ -12728,15 +12731,19 @@ snapshots: ajv-formats@2.1.1: dependencies: - ajv: 8.17.1 + ajv: 8.18.0 ajv-formats@3.0.1(ajv@8.17.1): optionalDependencies: ajv: 8.17.1 - ajv-keywords@5.1.0(ajv@8.17.1): + ajv-formats@3.0.1(ajv@8.18.0): + optionalDependencies: + ajv: 8.18.0 + + ajv-keywords@5.1.0(ajv@8.18.0): dependencies: - ajv: 8.17.1 + ajv: 8.18.0 fast-deep-equal: 3.1.3 ajv@6.12.6: @@ -12753,6 +12760,13 @@ snapshots: json-schema-traverse: 1.0.0 require-from-string: 2.0.2 + ajv@8.18.0: + dependencies: + fast-deep-equal: 3.1.3 + fast-uri: 3.1.0 + json-schema-traverse: 1.0.0 + require-from-string: 2.0.2 + algoliasearch@5.35.0: dependencies: '@algolia/abtesting': 1.1.0 @@ -17220,9 +17234,9 @@ snapshots: schema-utils@4.3.3: dependencies: '@types/json-schema': 7.0.15 - ajv: 8.17.1 + ajv: 8.18.0 ajv-formats: 2.1.1 - ajv-keywords: 5.1.0(ajv@8.17.1) + ajv-keywords: 5.1.0(ajv@8.18.0) select-hose@2.0.0: {} From 05b35113e680341f9f9465b0f35d93fd663ba59f Mon Sep 17 00:00:00 2001 From: Doug Parker Date: Thu, 26 Feb 2026 12:47:06 -0800 Subject: [PATCH 44/52] release: cut the v20.3.18 release --- CHANGELOG.md | 18 ++++++++++++++++++ package.json | 2 +- 2 files changed, 19 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 7e76df245531..f8d22c867ae3 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,21 @@ + + +# 20.3.18 (2026-02-26) + +### @angular-devkit/core + +| Commit | Type | Description | +| --------------------------------------------------------------------------------------------------- | ---- | ------------------------ | +| [39596d529](https://github.com/angular/angular-cli/commit/39596d529f831f72a2134bc3c9ac163867ff5702) | fix | update `ajv` to `8.18.0` | + +### @angular/build + +| Commit | Type | Description | +| --------------------------------------------------------------------------------------------------- | ---- | ----------------------- | +| [f668e2778](https://github.com/angular/angular-cli/commit/f668e2778c4c4dbecc8a1c6831c092f5512d1ec1) | fix | update rollup to 4.59.0 | + + + # 20.3.17 (2026-02-23) diff --git a/package.json b/package.json index 26f7b8512c1e..d751378daead 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@angular/devkit-repo", - "version": "20.3.17", + "version": "20.3.18", "private": true, "description": "Software Development Kit for Angular", "keywords": [ From 0299b4d1aca13f11a06e2e92c593fe3e20906d23 Mon Sep 17 00:00:00 2001 From: Charles Lyding <19598772+clydin@users.noreply.github.com> Date: Tue, 3 Mar 2026 16:25:15 -0500 Subject: [PATCH 45/52] fix(@angular-devkit/build-angular): update copy-webpack-plugin to v14.0.0 --- .../angular_devkit/build_angular/package.json | 2 +- pnpm-lock.yaml | 20 ++++++++++++------- 2 files changed, 14 insertions(+), 8 deletions(-) diff --git a/packages/angular_devkit/build_angular/package.json b/packages/angular_devkit/build_angular/package.json index e4253b78d121..0c9a4f13980d 100644 --- a/packages/angular_devkit/build_angular/package.json +++ b/packages/angular_devkit/build_angular/package.json @@ -26,7 +26,7 @@ "autoprefixer": "10.4.21", "babel-loader": "10.0.0", "browserslist": "^4.21.5", - "copy-webpack-plugin": "13.0.1", + "copy-webpack-plugin": "14.0.0", "css-loader": "7.1.2", "esbuild-wasm": "0.25.9", "fast-glob": "3.3.3", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index da74e29c83af..7d23f2dbb743 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -648,8 +648,8 @@ importers: specifier: ^4.21.5 version: 4.26.3 copy-webpack-plugin: - specifier: 13.0.1 - version: 13.0.1(webpack@5.105.0(esbuild@0.25.9)) + specifier: 14.0.0 + version: 14.0.0(webpack@5.105.0(esbuild@0.25.9)) css-loader: specifier: 7.1.2 version: 7.1.2(webpack@5.105.0(esbuild@0.25.9)) @@ -4626,9 +4626,9 @@ packages: copy-anything@2.0.6: resolution: {integrity: sha512-1j20GZTsvKNkc4BY3NpMOM8tt///wY3FpIzozTOFO2ffuZcV61nojHXVKIy3WM+7ADCy5FVhdZYHYDdgTU0yJw==} - copy-webpack-plugin@13.0.1: - resolution: {integrity: sha512-J+YV3WfhY6W/Xf9h+J1znYuqTye2xkBUIGyTPWuBAT27qajBa5mR4f8WBmfDY3YjRftT2kqZZiLi1qf0H+UOFw==} - engines: {node: '>= 18.12.0'} + copy-webpack-plugin@14.0.0: + resolution: {integrity: sha512-3JLW90aBGeaTLpM7mYQKpnVdgsUZRExY55giiZgLuX/xTQRUs1dOCwbBnWnvY6Q6rfZoXMNwzOQJCSZPppfqXA==} + engines: {node: '>= 20.9.0'} peerDependencies: webpack: ^5.1.0 @@ -7913,6 +7913,10 @@ packages: serialize-javascript@6.0.2: resolution: {integrity: sha512-Saa1xPByTTq2gdeFZYLLo+RFE35NHZkAbqZeWNd3BpzppeVisAqpDjcp8dyf6uIvEqJRd46jemmyA4iFIeVk8g==} + serialize-javascript@7.0.3: + resolution: {integrity: sha512-h+cZ/XXarqDgCjo+YSyQU/ulDEESGGf8AMK9pPNmhNSl/FzPl6L8pMp1leca5z6NuG6tvV/auC8/43tmovowww==} + engines: {node: '>=20.0.0'} + serve-index@1.9.1: resolution: {integrity: sha512-pXHfKNP4qujrtteMrSBb0rc8HJ9Ms/GrXwcUtUtD5s4ewDJI8bT3Cz2zTVRMKtri49pLx2e0Ya8ziP5Ya2pZZw==} engines: {node: '>= 0.8.0'} @@ -13550,12 +13554,12 @@ snapshots: dependencies: is-what: 3.14.1 - copy-webpack-plugin@13.0.1(webpack@5.105.0(esbuild@0.25.9)): + copy-webpack-plugin@14.0.0(webpack@5.105.0(esbuild@0.25.9)): dependencies: glob-parent: 6.0.2 normalize-path: 3.0.0 schema-utils: 4.3.3 - serialize-javascript: 6.0.2 + serialize-javascript: 7.0.3 tinyglobby: 0.2.14 webpack: 5.105.0(esbuild@0.25.9) @@ -17316,6 +17320,8 @@ snapshots: dependencies: randombytes: 2.1.0 + serialize-javascript@7.0.3: {} + serve-index@1.9.1: dependencies: accepts: 1.3.8 From 93a6f3615f8e07fa7178ed1d6dc52eaa6b507ecd Mon Sep 17 00:00:00 2001 From: Charles Lyding <19598772+clydin@users.noreply.github.com> Date: Wed, 4 Mar 2026 10:40:48 -0500 Subject: [PATCH 46/52] release: cut the v20.3.19 release --- CHANGELOG.md | 12 ++++++++++++ package.json | 2 +- 2 files changed, 13 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index f8d22c867ae3..8fc145618dd9 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,15 @@ + + +# 20.3.19 (2026-03-04) + +### @angular-devkit/build-angular + +| Commit | Type | Description | +| --------------------------------------------------------------------------------------------------- | ---- | ------------------------------------- | +| [0299b4d1a](https://github.com/angular/angular-cli/commit/0299b4d1aca13f11a06e2e92c593fe3e20906d23) | fix | update copy-webpack-plugin to v14.0.0 | + + + # 20.3.18 (2026-02-26) diff --git a/package.json b/package.json index d751378daead..a0387019ed7e 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@angular/devkit-repo", - "version": "20.3.18", + "version": "20.3.19", "private": true, "description": "Software Development Kit for Angular", "keywords": [ From 0fd6823af0adec23f7c3f1d531f45f6432afe555 Mon Sep 17 00:00:00 2001 From: Alan Agius <17563226+alan-agius4@users.noreply.github.com> Date: Tue, 10 Mar 2026 12:23:22 +0000 Subject: [PATCH 47/52] fix(@angular/build): pass process environment variables to prerender workers Worker processes used for prerendering and route extraction now inherit `process.env`. This ensures that any custom environment variables required by the application are available during the server-side rendering process. Closes #32730 --- packages/angular/build/src/utils/server-rendering/prerender.ts | 2 ++ 1 file changed, 2 insertions(+) diff --git a/packages/angular/build/src/utils/server-rendering/prerender.ts b/packages/angular/build/src/utils/server-rendering/prerender.ts index 39d0f0934c92..52890cac22ac 100644 --- a/packages/angular/build/src/utils/server-rendering/prerender.ts +++ b/packages/angular/build/src/utils/server-rendering/prerender.ts @@ -226,6 +226,7 @@ async function renderPages( } as RenderWorkerData, execArgv: workerExecArgv, env: { + ...process.env, 'NG_ALLOWED_HOSTS': 'localhost', }, }); @@ -341,6 +342,7 @@ async function getAllRoutes( } as RoutesExtractorWorkerData, execArgv: workerExecArgv, env: { + ...process.env, 'NG_ALLOWED_HOSTS': 'localhost', }, }); From 1e7d877d0a1c9f03bda8d7ec5411b45fffee114c Mon Sep 17 00:00:00 2001 From: Alan Agius <17563226+alan-agius4@users.noreply.github.com> Date: Wed, 11 Mar 2026 12:56:04 +0000 Subject: [PATCH 48/52] release: cut the v20.3.20 release --- CHANGELOG.md | 12 ++++++++++++ package.json | 2 +- 2 files changed, 13 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 8fc145618dd9..dc083e4021f7 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,15 @@ + + +# 20.3.20 (2026-03-11) + +### @angular/build + +| Commit | Type | Description | +| --------------------------------------------------------------------------------------------------- | ---- | ------------------------------------------------------- | +| [0fd6823af](https://github.com/angular/angular-cli/commit/0fd6823af0adec23f7c3f1d531f45f6432afe555) | fix | pass process environment variables to prerender workers | + + + # 20.3.19 (2026-03-04) diff --git a/package.json b/package.json index a0387019ed7e..dbc82633fb35 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@angular/devkit-repo", - "version": "20.3.19", + "version": "20.3.20", "private": true, "description": "Software Development Kit for Angular", "keywords": [ From 1dc6992a5ae6c5a1f16f22f6c94690d5cf218c38 Mon Sep 17 00:00:00 2001 From: Alan Agius <17563226+alan-agius4@users.noreply.github.com> Date: Mon, 16 Mar 2026 09:23:43 +0000 Subject: [PATCH 49/52] fix(@angular/ssr): disallow x-forwarded-prefix starting with a backslash Updated the INVALID_PREFIX_REGEX to ensure that prefixes starting with a backslash are considered invalid. Previously, only multiple slashes or dot segments were explicitly disallowed at the start. Also updated the associated validation error message and unit tests to reflect this change. --- packages/angular/ssr/src/utils/validation.ts | 4 ++-- packages/angular/ssr/test/utils/validation_spec.ts | 8 ++++---- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/packages/angular/ssr/src/utils/validation.ts b/packages/angular/ssr/src/utils/validation.ts index c89cdd6a64ed..9e83e144b347 100644 --- a/packages/angular/ssr/src/utils/validation.ts +++ b/packages/angular/ssr/src/utils/validation.ts @@ -29,7 +29,7 @@ const VALID_HOST_REGEX = /^[a-z0-9.:-]+$/i; /** * Regular expression to validate that the prefix is valid. */ -const INVALID_PREFIX_REGEX = /^[/\\]{2}|(?:^|[/\\])\.\.?(?:[/\\]|$)/; +const INVALID_PREFIX_REGEX = /^(?:\\|\/[/\\])|(?:^|[/\\])\.\.?(?:[/\\]|$)/; /** * Extracts the first value from a multi-value header string. @@ -262,7 +262,7 @@ function validateHeaders(request: Request): void { const xForwardedPrefix = getFirstHeaderValue(headers.get('x-forwarded-prefix')); if (xForwardedPrefix && INVALID_PREFIX_REGEX.test(xForwardedPrefix)) { throw new Error( - 'Header "x-forwarded-prefix" must not start with multiple "/" or "\\" or contain ".", ".." path segments.', + 'Header "x-forwarded-prefix" must not start with "\\" or multiple "/" or contain ".", ".." path segments.', ); } } diff --git a/packages/angular/ssr/test/utils/validation_spec.ts b/packages/angular/ssr/test/utils/validation_spec.ts index 10ab896e36f1..acf1e4829e8e 100644 --- a/packages/angular/ssr/test/utils/validation_spec.ts +++ b/packages/angular/ssr/test/utils/validation_spec.ts @@ -125,8 +125,8 @@ describe('Validation Utils', () => { ); }); - it('should throw error if x-forwarded-prefix starts with multiple slashes or backslashes', () => { - const inputs = ['//evil', '\\\\evil', '/\\evil', '\\/evil']; + it('should throw error if x-forwarded-prefix starts with a backslash or multiple slashes', () => { + const inputs = ['//evil', '\\\\evil', '/\\evil', '\\/evil', '\\evil']; for (const prefix of inputs) { const request = new Request('https://example.com', { @@ -138,7 +138,7 @@ describe('Validation Utils', () => { expect(() => validateRequest(request, allowedHosts)) .withContext(`Prefix: "${prefix}"`) .toThrowError( - 'Header "x-forwarded-prefix" must not start with multiple "/" or "\\" or contain ".", ".." path segments.', + 'Header "x-forwarded-prefix" must not start with "\\" or multiple "/" or contain ".", ".." path segments.', ); } }); @@ -171,7 +171,7 @@ describe('Validation Utils', () => { expect(() => validateRequest(request, allowedHosts)) .withContext(`Prefix: "${prefix}"`) .toThrowError( - 'Header "x-forwarded-prefix" must not start with multiple "/" or "\\" or contain ".", ".." path segments.', + 'Header "x-forwarded-prefix" must not start with "\\" or multiple "/" or contain ".", ".." path segments.', ); } }); From cdbac82a85b35f24c70a062eeb8a13b521831019 Mon Sep 17 00:00:00 2001 From: Alan Agius <17563226+alan-agius4@users.noreply.github.com> Date: Tue, 17 Mar 2026 10:09:28 +0000 Subject: [PATCH 50/52] fix(@angular/ssr): support custom headers in redirect responses Updates createRedirectResponse to accept an optional Record of headers, allowing custom headers to be merged into the redirect response. The Location and Vary: X-Forwarded-Prefix headers are automatically set to ensure correct routing and proxy behavior. AngularServerApp now passes relevant headers from the matched route or response context when creating a redirect. --- packages/angular/ssr/src/app.ts | 23 ++----- packages/angular/ssr/src/utils/redirect.ts | 66 +++++++++++++++++++ .../angular/ssr/test/utils/redirect_spec.ts | 60 +++++++++++++++++ 3 files changed, 130 insertions(+), 19 deletions(-) create mode 100644 packages/angular/ssr/src/utils/redirect.ts create mode 100644 packages/angular/ssr/test/utils/redirect_spec.ts diff --git a/packages/angular/ssr/src/app.ts b/packages/angular/ssr/src/app.ts index 85227a9d8a33..d3e3b1dfa7bf 100644 --- a/packages/angular/ssr/src/app.ts +++ b/packages/angular/ssr/src/app.ts @@ -25,6 +25,7 @@ import { InlineCriticalCssProcessor } from './utils/inline-critical-css'; import { LRUCache } from './utils/lru-cache'; import { AngularBootstrap, renderAngular } from './utils/ng'; import { promiseWithAbort } from './utils/promise'; +import { createRedirectResponse } from './utils/redirect'; import { buildPathWithParams, joinUrlParts, stripLeadingSlash } from './utils/url'; /** @@ -174,7 +175,7 @@ export class AngularServerApp { return null; } - const { redirectTo, status, renderMode } = matchedRoute; + const { redirectTo, status, renderMode, headers } = matchedRoute; if (redirectTo !== undefined) { return createRedirectResponse( @@ -183,6 +184,7 @@ export class AngularServerApp { buildPathWithParams(redirectTo, url.pathname), ), status, + headers, ); } @@ -336,7 +338,7 @@ export class AngularServerApp { } if (result.redirectTo) { - return createRedirectResponse(result.redirectTo, status); + return createRedirectResponse(result.redirectTo, responseInit.status, headers); } if (renderMode === RenderMode.Prerender) { @@ -552,20 +554,3 @@ function appendPreloadHintsToHtml(html: string, preload: readonly string[]): str html.slice(bodyCloseIdx), ].join('\n'); } - -/** - * Creates an HTTP redirect response with a specified location and status code. - * - * @param location - The URL to which the response should redirect. - * @param status - The HTTP status code for the redirection. Defaults to 302 (Found). - * See: https://developer.mozilla.org/en-US/docs/Web/API/Response/redirect_static#status - * @returns A `Response` object representing the HTTP redirect. - */ -function createRedirectResponse(location: string, status = 302): Response { - return new Response(null, { - status, - headers: { - 'Location': location, - }, - }); -} diff --git a/packages/angular/ssr/src/utils/redirect.ts b/packages/angular/ssr/src/utils/redirect.ts new file mode 100644 index 000000000000..3da6a0232bd8 --- /dev/null +++ b/packages/angular/ssr/src/utils/redirect.ts @@ -0,0 +1,66 @@ +/** + * @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 + */ + +/** + * An set of HTTP status codes that are considered valid for redirect responses. + */ +export const VALID_REDIRECT_RESPONSE_CODES: Set = new Set([301, 302, 303, 307, 308]); + +/** + * Checks if the given HTTP status code is a valid redirect response code. + * + * @param code The HTTP status code to check. + * @returns `true` if the code is a valid redirect response code, `false` otherwise. + */ +export function isValidRedirectResponseCode(code: number): boolean { + return VALID_REDIRECT_RESPONSE_CODES.has(code); +} + +/** + * Creates an HTTP redirect response with a specified location and status code. + * + * @param location - The URL to which the response should redirect. + * @param status - The HTTP status code for the redirection. Defaults to 302 (Found). + * See: https://developer.mozilla.org/en-US/docs/Web/API/Response/redirect_static#status + * @param headers - Additional headers to include in the response. + * @returns A `Response` object representing the HTTP redirect. + */ +export function createRedirectResponse( + location: string, + status = 302, + headers?: Record, +): Response { + if (ngDevMode && !isValidRedirectResponseCode(status)) { + throw new Error( + `Invalid redirect status code: ${status}. ` + + `Please use one of the following redirect response codes: ${[...VALID_REDIRECT_RESPONSE_CODES.values()].join(', ')}.`, + ); + } + + const resHeaders = new Headers(headers); + if (ngDevMode && resHeaders.has('location')) { + // eslint-disable-next-line no-console + console.warn( + `Location header "${resHeaders.get('location')}" will ignored and set to "${location}".`, + ); + } + + let vary = resHeaders.get('Vary') ?? ''; + if (vary) { + vary += ', '; + } + vary += 'X-Forwarded-Prefix'; + + resHeaders.set('Vary', vary); + resHeaders.set('Location', location); + + return new Response(null, { + status, + headers: resHeaders, + }); +} diff --git a/packages/angular/ssr/test/utils/redirect_spec.ts b/packages/angular/ssr/test/utils/redirect_spec.ts new file mode 100644 index 000000000000..bddbb81e2723 --- /dev/null +++ b/packages/angular/ssr/test/utils/redirect_spec.ts @@ -0,0 +1,60 @@ +/** + * @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 { createRedirectResponse } from '../../src/utils/redirect'; + +describe('Redirect Utils', () => { + describe('createRedirectResponse', () => { + it('should create a redirect response with default status 302', () => { + const response = createRedirectResponse('/home'); + expect(response.status).toBe(302); + expect(response.headers.get('Location')).toBe('/home'); + expect(response.headers.get('Vary')).toBe('X-Forwarded-Prefix'); + }); + + it('should create a redirect response with a custom status', () => { + const response = createRedirectResponse('/home', 301); + expect(response.status).toBe(301); + expect(response.headers.get('Location')).toBe('/home'); + }); + + it('should allow providing additional headers', () => { + const response = createRedirectResponse('/home', 302, { 'X-Custom': 'value' }); + expect(response.headers.get('X-Custom')).toBe('value'); + expect(response.headers.get('Location')).toBe('/home'); + expect(response.headers.get('Vary')).toBe('X-Forwarded-Prefix'); + }); + + it('should append to Vary header instead of overriding it', () => { + const response = createRedirectResponse('/home', 302, { + 'Location': '/evil', + 'Vary': 'Host', + }); + expect(response.headers.get('Location')).toBe('/home'); + expect(response.headers.get('Vary')).toBe('Host, X-Forwarded-Prefix'); + }); + + it('should warn if Location header is provided in extra headers in dev mode', () => { + // @ts-expect-error accessing global + globalThis.ngDevMode = true; + const warnSpy = spyOn(console, 'warn'); + createRedirectResponse('/home', 302, { 'Location': '/evil' }); + expect(warnSpy).toHaveBeenCalledWith( + 'Location header "/evil" will ignored and set to "/home".', + ); + }); + + it('should throw error for invalid redirect status code in dev mode', () => { + // @ts-expect-error accessing global + globalThis.ngDevMode = true; + expect(() => createRedirectResponse('/home', 200)).toThrowError( + /Invalid redirect status code: 200/, + ); + }); + }); +}); From 0a2ff0b2b3aceb228c9447c19fb762df742d7265 Mon Sep 17 00:00:00 2001 From: Alan Agius <17563226+alan-agius4@users.noreply.github.com> Date: Tue, 17 Mar 2026 10:20:09 +0000 Subject: [PATCH 51/52] fix(@angular/ssr): ensure unique values in redirect response Vary header Refactors the `createRedirectResponse` function to use a `Set` for constructing the `Vary` header. This ensures that `X-Forwarded-Prefix` is always present exactly once, and that existing `Vary` values from provided headers are correctly parsed, deduplicated, and preserved. Updates the associated unit tests to reflect the new header order and verify the deduplication logic. --- packages/angular/ssr/src/utils/redirect.ts | 15 ++++++++++----- packages/angular/ssr/test/utils/redirect_spec.ts | 9 ++++++++- 2 files changed, 18 insertions(+), 6 deletions(-) diff --git a/packages/angular/ssr/src/utils/redirect.ts b/packages/angular/ssr/src/utils/redirect.ts index 3da6a0232bd8..79fb10f424dc 100644 --- a/packages/angular/ssr/src/utils/redirect.ts +++ b/packages/angular/ssr/src/utils/redirect.ts @@ -50,13 +50,18 @@ export function createRedirectResponse( ); } - let vary = resHeaders.get('Vary') ?? ''; - if (vary) { - vary += ', '; + // Ensure unique values for Vary header + const varyArray = resHeaders.get('Vary')?.split(',') ?? []; + const varySet = new Set(['X-Forwarded-Prefix']); + for (const vary of varyArray) { + const value = vary.trim(); + + if (value) { + varySet.add(value); + } } - vary += 'X-Forwarded-Prefix'; - resHeaders.set('Vary', vary); + resHeaders.set('Vary', [...varySet].join(', ')); resHeaders.set('Location', location); return new Response(null, { diff --git a/packages/angular/ssr/test/utils/redirect_spec.ts b/packages/angular/ssr/test/utils/redirect_spec.ts index bddbb81e2723..b26edd458ac3 100644 --- a/packages/angular/ssr/test/utils/redirect_spec.ts +++ b/packages/angular/ssr/test/utils/redirect_spec.ts @@ -36,7 +36,14 @@ describe('Redirect Utils', () => { 'Vary': 'Host', }); expect(response.headers.get('Location')).toBe('/home'); - expect(response.headers.get('Vary')).toBe('Host, X-Forwarded-Prefix'); + expect(response.headers.get('Vary')).toBe('X-Forwarded-Prefix, Host'); + }); + + it('should NOT add duplicate X-Forwarded-Prefix if already present in Vary header', () => { + const response = createRedirectResponse('/home', 302, { + 'Vary': 'X-Forwarded-Prefix, Host', + }); + expect(response.headers.get('Vary')).toBe('X-Forwarded-Prefix, Host'); }); it('should warn if Location header is provided in extra headers in dev mode', () => { From 34d524549b68912f8ebe4e656a342b797161d232 Mon Sep 17 00:00:00 2001 From: Alan Agius <17563226+alan-agius4@users.noreply.github.com> Date: Thu, 19 Mar 2026 13:30:42 +0000 Subject: [PATCH 52/52] release: cut the v20.3.21 release --- CHANGELOG.md | 14 ++++++++++++++ package.json | 2 +- 2 files changed, 15 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index dc083e4021f7..1bf6e50b2a2a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,17 @@ + + +# 20.3.21 (2026-03-19) + +### @angular/ssr + +| Commit | Type | Description | +| --------------------------------------------------------------------------------------------------- | ---- | ----------------------------------------------------- | +| [1dc6992a5](https://github.com/angular/angular-cli/commit/1dc6992a5ae6c5a1f16f22f6c94690d5cf218c38) | fix | disallow x-forwarded-prefix starting with a backslash | +| [0a2ff0b2b](https://github.com/angular/angular-cli/commit/0a2ff0b2b3aceb228c9447c19fb762df742d7265) | fix | ensure unique values in redirect response Vary header | +| [cdbac82a8](https://github.com/angular/angular-cli/commit/cdbac82a85b35f24c70a062eeb8a13b521831019) | fix | support custom headers in redirect responses | + + + # 20.3.20 (2026-03-11) diff --git a/package.json b/package.json index dbc82633fb35..496d9947a0f4 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@angular/devkit-repo", - "version": "20.3.20", + "version": "20.3.21", "private": true, "description": "Software Development Kit for Angular", "keywords": [