diff --git a/.github/dependabot.yml b/.github/dependabot.yml index b79f095..e126844 100644 --- a/.github/dependabot.yml +++ b/.github/dependabot.yml @@ -21,6 +21,24 @@ updates: - dependency-name: "@types/node" update-types: - version-update:semver-major + - package-ecosystem: npm + directory: /tools/npm-toolchain + versioning-strategy: lockfile-only + schedule: + interval: weekly + day: monday + time: "20:00" + timezone: Australia/Melbourne + open-pull-requests-limit: 2 + groups: + package-manager-runtime: + update-types: + - minor + - patch + ignore: + - dependency-name: "*" + update-types: + - version-update:semver-major - package-ecosystem: github-actions directory: / schedule: diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 78bb478..4ff3ada 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -26,7 +26,11 @@ jobs: uses: actions/setup-node@820762786026740c76f36085b0efc47a31fe5020 # v7.0.0 with: node-version-file: .nvmrc - cache: npm + package-manager-cache: false + + - name: Restore the reviewed package-manager toolchain + id: toolchain + run: node tools/bootstrap-npm.ts - name: Install locked dependencies run: npm ci @@ -73,7 +77,11 @@ jobs: uses: actions/setup-node@820762786026740c76f36085b0efc47a31fe5020 # v7.0.0 with: node-version-file: .nvmrc - cache: npm + package-manager-cache: false + + - name: Restore the reviewed package-manager toolchain + id: toolchain + run: node tools/bootstrap-npm.ts - name: Install locked dependencies run: npm ci diff --git a/.github/workflows/codeql.yml b/.github/workflows/codeql.yml index 7bb3d3c..5e74cb0 100644 --- a/.github/workflows/codeql.yml +++ b/.github/workflows/codeql.yml @@ -24,9 +24,9 @@ jobs: uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 - name: Initialise CodeQL - uses: github/codeql-action/init@e4fba868fa4b1b91e1fdab776edc8cfbe6e9fb81 # v4.37.3 + uses: github/codeql-action/init@2892aa5e19bbd11bc0cff5427e3b750a04d9e3c2 # v4.38.2 with: languages: javascript-typescript - name: Analyse source - uses: github/codeql-action/analyze@e4fba868fa4b1b91e1fdab776edc8cfbe6e9fb81 # v4.37.3 + uses: github/codeql-action/analyze@2892aa5e19bbd11bc0cff5427e3b750a04d9e3c2 # v4.38.2 diff --git a/.github/workflows/pages.yml b/.github/workflows/pages.yml index 98591bf..844dd12 100644 --- a/.github/workflows/pages.yml +++ b/.github/workflows/pages.yml @@ -19,35 +19,69 @@ concurrency: jobs: build: - if: github.event_name == 'workflow_dispatch' || (github.event.workflow_run.conclusion == 'success' && github.event.workflow_run.event == 'push' && github.event.workflow_run.head_branch == 'main') + if: (github.event_name == 'workflow_dispatch' && github.ref == 'refs/heads/main') || (github.event.workflow_run.conclusion == 'success' && github.event.workflow_run.event == 'push' && github.event.workflow_run.head_branch == 'main') runs-on: ubuntu-latest - timeout-minutes: 15 + timeout-minutes: 30 env: CONTROLCURRENT_DEPLOY_TARGET: github-pages permissions: contents: read pages: read + actions: read + outputs: + release_sha: ${{ steps.release.outputs.sha }} steps: - name: Check out repository uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 with: ref: ${{ github.event_name == 'workflow_run' && github.event.workflow_run.head_sha || github.sha }} + persist-credentials: false - name: Set up Node.js uses: actions/setup-node@820762786026740c76f36085b0efc47a31fe5020 # v7.0.0 with: node-version-file: .nvmrc - cache: npm + package-manager-cache: false + + - name: Require current verified release + id: release + env: + GH_TOKEN: ${{ github.token }} + RELEASE_SHA: ${{ github.event_name == 'workflow_run' && github.event.workflow_run.head_sha || github.sha }} + GATE_WAIT_SECONDS: "600" + run: node tools/publication-gate.ts - name: Configure Pages uses: actions/configure-pages@45bfe0192ca1faeb007ade9deae92b16b8254a0d # v6.0.0 + - name: Restore the reviewed package-manager toolchain + id: toolchain + run: node tools/bootstrap-npm.ts + - name: Install locked dependencies run: npm ci - name: Verify and build run: npm run verify + - name: Audit dependencies for manual publication + if: github.event_name == 'workflow_dispatch' + run: npm audit --audit-level=high + + - name: Install the locked Chromium browser for manual publication + if: github.event_name == 'workflow_dispatch' + run: npm run test:e2e:install:ci + + - name: Run browser and accessibility tests for manual publication + if: github.event_name == 'workflow_dispatch' + env: + CONTROLCURRENT_DEPLOY_TARGET: "" + run: npm run test:e2e + + - name: Restore and audit the publication build after browser fixtures + if: github.event_name == 'workflow_dispatch' + run: npm run build && npm run audit:public + - name: Upload Pages artifact uses: actions/upload-pages-artifact@fc324d3547104276b827a68afc52ff2a11cc49c9 # v5.0.0 with: @@ -61,9 +95,32 @@ jobs: runs-on: ubuntu-latest timeout-minutes: 10 permissions: + contents: read + actions: read pages: write id-token: write steps: + - name: Check out the release guard only + uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 + with: + ref: ${{ needs.build.outputs.release_sha }} + persist-credentials: false + sparse-checkout: tools/publication-gate.ts + sparse-checkout-cone-mode: false + + - name: Set up the guard runtime without dependency caching + uses: actions/setup-node@820762786026740c76f36085b0efc47a31fe5020 # v7.0.0 + with: + node-version: "24" + package-manager-cache: false + + - name: Recheck current release immediately before deployment + env: + GH_TOKEN: ${{ github.token }} + RELEASE_SHA: ${{ needs.build.outputs.release_sha }} + GATE_WAIT_SECONDS: "0" + run: node tools/publication-gate.ts + - name: Deploy Pages artifact id: deployment - uses: actions/deploy-pages@cd2ce8fcbc39b97be8ca5fce6e763baed58fa128 # v5.0.0 + uses: actions/deploy-pages@368f82528645a54fb793d4d04e342629a3f51346 # v5.0.1 diff --git a/.github/workflows/source-review.yml b/.github/workflows/source-review.yml index de2f192..6b29904 100644 --- a/.github/workflows/source-review.yml +++ b/.github/workflows/source-review.yml @@ -24,9 +24,13 @@ jobs: uses: actions/setup-node@820762786026740c76f36085b0efc47a31fe5020 # v7.0.0 with: node-version-file: .nvmrc - cache: npm + package-manager-cache: false registry-url: https://registry.npmjs.org + - name: Restore the reviewed package-manager toolchain + id: toolchain + run: node tools/bootstrap-npm.ts + - name: Install locked dependencies run: npm ci @@ -39,7 +43,7 @@ jobs: run: npm outdated @mdn/browser-compat-data web-features --json > source-review.json - name: Summarise source review - if: always() + if: always() && steps.toolchain.outcome == 'success' run: npm run source-review:summary -- source-review.json >> "$GITHUB_STEP_SUMMARY" - name: Require review when an update is available diff --git a/.github/workflows/update-dry-run.yml b/.github/workflows/update-dry-run.yml index dd03b95..560896d 100644 --- a/.github/workflows/update-dry-run.yml +++ b/.github/workflows/update-dry-run.yml @@ -22,9 +22,13 @@ jobs: uses: actions/setup-node@820762786026740c76f36085b0efc47a31fe5020 # v7.0.0 with: node-version-file: .nvmrc - cache: npm + package-manager-cache: false registry-url: https://registry.npmjs.org + - name: Restore the reviewed package-manager toolchain + id: toolchain + run: node tools/bootstrap-npm.ts + - name: Install locked dependencies run: npm ci diff --git a/README.md b/README.md index 3bd5b76..7035230 100644 --- a/README.md +++ b/README.md @@ -55,6 +55,8 @@ checker or certification service. - Save a browser plan locally or export it as JSON. - Opt in to remembering one result so a later data update can be compared. - Compare an exported result with a newer result from the same source version. +- Read exact source versions, package timestamps and local package age beside + both planning workflows. ### Record an engineering decision @@ -130,8 +132,8 @@ boundary. The current selected dataset is generated from: -- `@mdn/browser-compat-data` 8.0.8; -- `web-features` 3.34.2; and +- `@mdn/browser-compat-data` 8.1.4; +- `web-features` 3.40.1; and - exact Web Platform Tests suite paths pinned to revision `af38980d2fcd74af19a226f5f651051cc15940ed`. @@ -149,10 +151,12 @@ third-party notices for attribution and licence details. Requirements: - Node.js 24.15 or a compatible later supported release; -- npm 11.17–12; and +- the reviewed npm 12.2.0 runtime reconstructed from its separate lock; and - dependencies installed from the committed lockfile. ```bash +node tools/bootstrap-npm.ts +# Apply the PATH export printed after a successful bootstrap. npm ci npm run dev ``` @@ -164,6 +168,13 @@ npm run build npm run preview ``` +The bootstrap downloads only reviewed registry archives and checks integrity, +the toolchain audit and registry signatures before activation. It does not +modify global npm or execute the upstream bundled dependencies. Ordinary tests +remain fixture-only; bootstrap and signature checks require registry access. +See [dependency policy](docs/dependency-policy.md) for the separate runtime lock +and host trust assumptions. + ## Verification The main local verification command runs linting, formatting checks, strict @@ -209,7 +220,13 @@ edit the lockfile, selected data, source history, repository or deployment. The public site is suitable for static GitHub Pages hosting. It needs no runtime secret, server or database. Changes to `main` deploy only after the -complete CI workflow succeeds. +complete CI and CodeQL workflows succeed for the exact current `main` commit. +Both automatic and manual publication recheck that commit immediately before +deployment. The [dependency policy](docs/dependency-policy.md) records the +reviewed, separately locked package-manager reconstruction and its trust +assumptions. Complete checks on the corrected revision and eventual exact-main +release remain required; a clean application dependency audit or verified +signatures do not prove that build-tool code is benign or vulnerability-free. GitHub Pages does not apply the generated `_headers` file, so the current public site relies on its restrictive meta Content Security Policy and framing guard. @@ -218,6 +235,8 @@ with organisation-specific evidence. ## Documentation +- [PR32 optional follow-up and local validation](docs/pr32-optional-follow-up.md) + - [Architecture](docs/architecture.md) - [Data contract](docs/data-contract.md) - [Methodology](docs/methodology.md) diff --git a/data/change-events.json b/data/change-events.json index fc1f428..665af87 100644 --- a/data/change-events.json +++ b/data/change-events.json @@ -2538,5 +2538,622 @@ "sourceTimestamp": "2026-07-24T16:06:32.098Z", "summary": "Firefox 156 was added to the selected BCD release metadata.", "type": "browser_release_added" + }, + { + "after": { + "releaseDate": "2026-10-13", + "status": "planned", + "version": "158" + }, + "browser": "firefox_android", + "id": "037ccdbcfa90e75323c34ee2", + "observedInBcdVersion": "8.1.0", + "observedInWebFeaturesVersion": "3.37.0", + "schemaVersion": 1, + "sourceTimestamp": "2026-09-03T15:52:15.027Z", + "summary": "Firefox for Android 158 was added to the selected BCD release metadata.", + "type": "browser_release_added" + }, + { + "after": { + "version_added": "70" + }, + "before": { + "version_added": false + }, + "browser": "webview_android", + "id": "161d55e466686250bfc5ee8a", + "observedInBcdVersion": "8.1.0", + "observedInWebFeaturesVersion": "3.37.0", + "path": "api.PublicKeyCredential.isUserVerifyingPlatformAuthenticatorAvailable_static", + "schemaVersion": 1, + "sourceTimestamp": "2026-09-03T15:52:15.027Z", + "summary": "api.PublicKeyCredential.isUserVerifyingPlatformAuthenticatorAvailable_static changed for webview_android: {\"version_added\":false} to {\"version_added\":\"70\"}.", + "type": "support_version_added" + }, + { + "after": { + "releaseDate": "2026-09-22", + "status": "nightly", + "version": "154" + }, + "browser": "chrome", + "id": "1c33691d2753a1895f20e194", + "observedInBcdVersion": "8.1.0", + "observedInWebFeaturesVersion": "3.37.0", + "schemaVersion": 1, + "sourceTimestamp": "2026-09-03T15:52:15.027Z", + "summary": "Chrome 154 was added to the selected BCD release metadata.", + "type": "browser_release_added" + }, + { + "after": { + "status": "planned", + "version": "155" + }, + "browser": "chrome", + "id": "29479f8610b07f8ac005c5a7", + "observedInBcdVersion": "8.1.0", + "observedInWebFeaturesVersion": "3.37.0", + "schemaVersion": 1, + "sourceTimestamp": "2026-09-03T15:52:15.027Z", + "summary": "Chrome 155 was added to the selected BCD release metadata.", + "type": "browser_release_added" + }, + { + "after": { + "releaseDate": "2026-09-22", + "status": "nightly", + "version": "154" + }, + "browser": "webview_android", + "id": "2c1e428eb26b72cf1924226e", + "observedInBcdVersion": "8.1.0", + "observedInWebFeaturesVersion": "3.37.0", + "schemaVersion": 1, + "sourceTimestamp": "2026-09-03T15:52:15.027Z", + "summary": "WebView Android 154 was added to the selected BCD release metadata.", + "type": "browser_release_added" + }, + { + "after": { + "status": "planned", + "version": "155" + }, + "browser": "webview_android", + "id": "32853ba9f5c9c13ee1f810d6", + "observedInBcdVersion": "8.1.0", + "observedInWebFeaturesVersion": "3.37.0", + "schemaVersion": 1, + "sourceTimestamp": "2026-09-03T15:52:15.027Z", + "summary": "WebView Android 155 was added to the selected BCD release metadata.", + "type": "browser_release_added" + }, + { + "after": { + "version_added": "85" + }, + "before": { + "version_added": "88" + }, + "browser": "webview_android", + "id": "34a6fe099ee00b009434fb8b", + "observedInBcdVersion": "8.1.0", + "observedInWebFeaturesVersion": "3.37.0", + "path": "http.headers.Permissions-Policy", + "schemaVersion": 1, + "sourceTimestamp": "2026-09-03T15:52:15.027Z", + "summary": "http.headers.Permissions-Policy changed for webview_android: {\"version_added\":\"88\"} to {\"version_added\":\"85\"}.", + "type": "support_version_corrected" + }, + { + "after": { + "version_added": "85" + }, + "before": { + "version_added": "88" + }, + "browser": "chrome", + "id": "380bcc9d73d6deed5fe8546d", + "observedInBcdVersion": "8.1.0", + "observedInWebFeaturesVersion": "3.37.0", + "path": "http.headers.Permissions-Policy", + "schemaVersion": 1, + "sourceTimestamp": "2026-09-03T15:52:15.027Z", + "summary": "http.headers.Permissions-Policy changed for chrome: {\"version_added\":\"88\"} to {\"version_added\":\"85\"}.", + "type": "support_version_corrected" + }, + { + "after": { + "version_added": "85" + }, + "before": { + "version_added": "88" + }, + "browser": "chrome_android", + "id": "4bbf22407c2aec2056a2623a", + "observedInBcdVersion": "8.1.0", + "observedInWebFeaturesVersion": "3.37.0", + "path": "http.headers.Permissions-Policy", + "schemaVersion": 1, + "sourceTimestamp": "2026-09-03T15:52:15.027Z", + "summary": "http.headers.Permissions-Policy changed for chrome_android: {\"version_added\":\"88\"} to {\"version_added\":\"85\"}.", + "type": "support_version_corrected" + }, + { + "after": { + "status": "planned", + "version": "155" + }, + "browser": "chrome_android", + "id": "513f19b97ab02332edc800b9", + "observedInBcdVersion": "8.1.0", + "observedInWebFeaturesVersion": "3.37.0", + "schemaVersion": 1, + "sourceTimestamp": "2026-09-03T15:52:15.027Z", + "summary": "Chrome Android 155 was added to the selected BCD release metadata.", + "type": "browser_release_added" + }, + { + "after": { + "releaseDate": "2026-09-29", + "status": "nightly", + "version": "157" + }, + "browser": "firefox_android", + "id": "5e3f14d2d0526657c479e372", + "observedInBcdVersion": "8.1.0", + "observedInWebFeaturesVersion": "3.37.0", + "schemaVersion": 1, + "sourceTimestamp": "2026-09-03T15:52:15.027Z", + "summary": "Firefox for Android 157 was added to the selected BCD release metadata.", + "type": "browser_release_added" + }, + { + "after": { + "releaseDate": "2026-07-27", + "status": "current", + "version": "26.6" + }, + "browser": "safari", + "id": "7733146a9762d58aa9385380", + "observedInBcdVersion": "8.1.0", + "observedInWebFeaturesVersion": "3.37.0", + "schemaVersion": 1, + "sourceTimestamp": "2026-09-03T15:52:15.027Z", + "summary": "Safari 26.6 was added to the selected BCD release metadata.", + "type": "browser_release_added" + }, + { + "after": { + "notes": "Conditional mediation (autofill integration) is not supported; isConditionalMediationAvailable() always returns false.", + "partial_implementation": true, + "version_added": "131" + }, + "before": { + "version_added": false + }, + "browser": "webview_android", + "id": "7adb2f05248ebfd44b11c0a0", + "observedInBcdVersion": "8.1.0", + "observedInWebFeaturesVersion": "3.37.0", + "path": "api.PublicKeyCredential.isConditionalMediationAvailable_static", + "schemaVersion": 1, + "sourceTimestamp": "2026-09-03T15:52:15.027Z", + "summary": "api.PublicKeyCredential.isConditionalMediationAvailable_static changed for webview_android: {\"version_added\":false} to {\"version_added\":\"131\",\"partial_implementation\":true,\"notes\":\"Conditional mediation (autofill integration) is not sup….", + "type": "partial_support_added" + }, + { + "after": { + "version_added": "14.0" + }, + "before": { + "version_added": "15.0" + }, + "browser": "samsunginternet_android", + "id": "86c0464bb1e9261c3f6b1a4c", + "observedInBcdVersion": "8.1.0", + "observedInWebFeaturesVersion": "3.37.0", + "path": "http.headers.Permissions-Policy", + "schemaVersion": 1, + "sourceTimestamp": "2026-09-03T15:52:15.027Z", + "summary": "http.headers.Permissions-Policy changed for samsunginternet_android: {\"version_added\":\"15.0\"} to {\"version_added\":\"14.0\"}.", + "type": "support_version_corrected" + }, + { + "after": { + "releaseDate": "2026-09-22", + "status": "nightly", + "version": "154" + }, + "browser": "chrome_android", + "id": "877fca61a9626dfd88f2b969", + "observedInBcdVersion": "8.1.0", + "observedInWebFeaturesVersion": "3.37.0", + "schemaVersion": 1, + "sourceTimestamp": "2026-09-03T15:52:15.027Z", + "summary": "Chrome Android 154 was added to the selected BCD release metadata.", + "type": "browser_release_added" + }, + { + "after": { + "releaseDate": "2026-07-27", + "status": "current", + "version": "26.6" + }, + "browser": "safari_ios", + "id": "9ac921cc8bdd32cf90d48c84", + "observedInBcdVersion": "8.1.0", + "observedInWebFeaturesVersion": "3.37.0", + "schemaVersion": 1, + "sourceTimestamp": "2026-09-03T15:52:15.027Z", + "summary": "Safari on iOS 26.6 was added to the selected BCD release metadata.", + "type": "browser_release_added" + }, + { + "after": { + "releaseDate": "2026-10-08", + "status": "planned", + "version": "155" + }, + "browser": "edge", + "id": "b28d7c6a10e8b39513082cdc", + "observedInBcdVersion": "8.1.0", + "observedInWebFeaturesVersion": "3.37.0", + "schemaVersion": 1, + "sourceTimestamp": "2026-09-03T15:52:15.027Z", + "summary": "Edge 155 was added to the selected BCD release metadata.", + "type": "browser_release_added" + }, + { + "after": { + "releaseDate": "2026-10-13", + "status": "planned", + "version": "158" + }, + "browser": "firefox", + "id": "cb4899dcb14c351ac163d64d", + "observedInBcdVersion": "8.1.0", + "observedInWebFeaturesVersion": "3.37.0", + "schemaVersion": 1, + "sourceTimestamp": "2026-09-03T15:52:15.027Z", + "summary": "Firefox 158 was added to the selected BCD release metadata.", + "type": "browser_release_added" + }, + { + "after": { + "version_added": "85" + }, + "before": { + "version_added": "88" + }, + "browser": "edge", + "id": "cc535ec1126dd819d740c43b", + "observedInBcdVersion": "8.1.0", + "observedInWebFeaturesVersion": "3.37.0", + "path": "http.headers.Permissions-Policy", + "schemaVersion": 1, + "sourceTimestamp": "2026-09-03T15:52:15.027Z", + "summary": "http.headers.Permissions-Policy changed for edge: {\"version_added\":\"88\"} to {\"version_added\":\"85\"}.", + "type": "support_version_corrected" + }, + { + "after": { + "version_added": "149" + }, + "before": { + "impl_url": "https://bugzil.la/1958716", + "version_added": false + }, + "browser": "firefox_android", + "id": "cf410e6f346230a9f241b525", + "observedInBcdVersion": "8.1.0", + "observedInWebFeaturesVersion": "3.37.0", + "path": "api.CredentialsContainer.create.publicKey_option.extensions.prf", + "schemaVersion": 1, + "sourceTimestamp": "2026-09-03T15:52:15.027Z", + "summary": "api.CredentialsContainer.create.publicKey_option.extensions.prf changed for firefox_android: {\"version_added\":false,\"impl_url\":\"https://bugzil.la/1958716\"} to {\"version_added\":\"149\"}.", + "type": "support_version_added" + }, + { + "after": { + "releaseDate": "2026-09-29", + "status": "nightly", + "version": "157" + }, + "browser": "firefox", + "id": "d6bf5e422846117151686980", + "observedInBcdVersion": "8.1.0", + "observedInWebFeaturesVersion": "3.37.0", + "schemaVersion": 1, + "sourceTimestamp": "2026-09-03T15:52:15.027Z", + "summary": "Firefox 157 was added to the selected BCD release metadata.", + "type": "browser_release_added" + }, + { + "after": { + "releaseDate": "2026-09-24", + "status": "nightly", + "version": "154" + }, + "browser": "edge", + "id": "e5592f8181c5392d545dce2a", + "observedInBcdVersion": "8.1.0", + "observedInWebFeaturesVersion": "3.37.0", + "schemaVersion": 1, + "sourceTimestamp": "2026-09-03T15:52:15.027Z", + "summary": "Edge 154 was added to the selected BCD release metadata.", + "type": "browser_release_added" + }, + { + "after": { + "status": "beta", + "version": "27.2" + }, + "browser": "safari_ios", + "id": "2317e1d97beed2465d73b1c6", + "observedInBcdVersion": "8.1.4", + "observedInWebFeaturesVersion": "3.40.1", + "schemaVersion": 1, + "sourceTimestamp": "2026-10-01T10:12:15.059Z", + "summary": "Safari on iOS 27.2 was added to the selected BCD release metadata.", + "type": "browser_release_added" + }, + { + "after": { + "releaseDate": "2026-10-20", + "status": "nightly", + "version": "156" + }, + "browser": "chrome", + "id": "24841353064df9d363785d72", + "observedInBcdVersion": "8.1.4", + "observedInWebFeaturesVersion": "3.40.1", + "schemaVersion": 1, + "sourceTimestamp": "2026-10-01T10:12:15.059Z", + "summary": "Chrome 156 was added to the selected BCD release metadata.", + "type": "browser_release_added" + }, + { + "after": { + "releaseDate": "2026-10-22", + "status": "nightly", + "version": "156" + }, + "browser": "edge", + "id": "25982a665bb3c7756647b154", + "observedInBcdVersion": "8.1.4", + "observedInWebFeaturesVersion": "3.40.1", + "schemaVersion": 1, + "sourceTimestamp": "2026-10-01T10:12:15.059Z", + "summary": "Edge 156 was added to the selected BCD release metadata.", + "type": "browser_release_added" + }, + { + "after": { + "releaseDate": "2026-11-10", + "status": "planned", + "version": "160" + }, + "browser": "firefox_android", + "id": "259da8174f9fb1d31fb1bc1f", + "observedInBcdVersion": "8.1.4", + "observedInWebFeaturesVersion": "3.40.1", + "schemaVersion": 1, + "sourceTimestamp": "2026-10-01T10:12:15.059Z", + "summary": "Firefox for Android 160 was added to the selected BCD release metadata.", + "type": "browser_release_added" + }, + { + "after": { + "releaseDate": "2026-05-11", + "status": "current", + "version": "30.0" + }, + "browser": "samsunginternet_android", + "id": "284ee04f14965b191a18674c", + "observedInBcdVersion": "8.1.4", + "observedInWebFeaturesVersion": "3.40.1", + "schemaVersion": 1, + "sourceTimestamp": "2026-10-01T10:12:15.059Z", + "summary": "Samsung Browser 30.0 was added to the selected BCD release metadata.", + "type": "browser_release_added" + }, + { + "after": { + "releaseDate": "2026-10-27", + "status": "nightly", + "version": "159" + }, + "browser": "firefox_android", + "id": "56649cddeb047632af3409a6", + "observedInBcdVersion": "8.1.4", + "observedInWebFeaturesVersion": "3.40.1", + "schemaVersion": 1, + "sourceTimestamp": "2026-10-01T10:12:15.059Z", + "summary": "Firefox for Android 159 was added to the selected BCD release metadata.", + "type": "browser_release_added" + }, + { + "after": { + "releaseDate": "2026-10-27", + "status": "nightly", + "version": "159" + }, + "browser": "firefox", + "id": "72f4af1348e5d5d79dff181a", + "observedInBcdVersion": "8.1.4", + "observedInWebFeaturesVersion": "3.40.1", + "schemaVersion": 1, + "sourceTimestamp": "2026-10-01T10:12:15.059Z", + "summary": "Firefox 159 was added to the selected BCD release metadata.", + "type": "browser_release_added" + }, + { + "after": { + "status": "planned", + "version": "157" + }, + "browser": "chrome", + "id": "79122de93b6b6ebca0671bcc", + "observedInBcdVersion": "8.1.4", + "observedInWebFeaturesVersion": "3.40.1", + "schemaVersion": 1, + "sourceTimestamp": "2026-10-01T10:12:15.059Z", + "summary": "Chrome 157 was added to the selected BCD release metadata.", + "type": "browser_release_added" + }, + { + "after": { + "releaseDate": "2026-10-20", + "status": "nightly", + "version": "156" + }, + "browser": "chrome_android", + "id": "7cfca20381dcf2de017679b7", + "observedInBcdVersion": "8.1.4", + "observedInWebFeaturesVersion": "3.40.1", + "schemaVersion": 1, + "sourceTimestamp": "2026-10-01T10:12:15.059Z", + "summary": "Chrome Android 156 was added to the selected BCD release metadata.", + "type": "browser_release_added" + }, + { + "after": { + "releaseDate": "2026-11-10", + "status": "planned", + "version": "160" + }, + "browser": "firefox", + "id": "80c30d4cb1e47e1170f50616", + "observedInBcdVersion": "8.1.4", + "observedInWebFeaturesVersion": "3.40.1", + "schemaVersion": 1, + "sourceTimestamp": "2026-10-01T10:12:15.059Z", + "summary": "Firefox 160 was added to the selected BCD release metadata.", + "type": "browser_release_added" + }, + { + "after": { + "status": "planned", + "version": "157" + }, + "browser": "webview_android", + "id": "834eaed7d80c41b50ff7dc19", + "observedInBcdVersion": "8.1.4", + "observedInWebFeaturesVersion": "3.40.1", + "schemaVersion": 1, + "sourceTimestamp": "2026-10-01T10:12:15.059Z", + "summary": "WebView Android 157 was added to the selected BCD release metadata.", + "type": "browser_release_added" + }, + { + "after": { + "version_added": "30.0" + }, + "before": { + "version_added": false + }, + "browser": "samsunginternet_android", + "id": "856f584c27a60a56f7294a5f", + "observedInBcdVersion": "8.1.4", + "observedInWebFeaturesVersion": "3.40.1", + "path": "http.headers.Integrity-Policy", + "schemaVersion": 1, + "sourceTimestamp": "2026-10-01T10:12:15.059Z", + "summary": "http.headers.Integrity-Policy changed for samsunginternet_android: {\"version_added\":false} to {\"version_added\":\"30.0\"}.", + "type": "support_version_added" + }, + { + "after": { + "releaseDate": "2026-10-20", + "status": "nightly", + "version": "156" + }, + "browser": "webview_android", + "id": "bdbbc0de7057d2921a97d356", + "observedInBcdVersion": "8.1.4", + "observedInWebFeaturesVersion": "3.40.1", + "schemaVersion": 1, + "sourceTimestamp": "2026-10-01T10:12:15.059Z", + "summary": "WebView Android 156 was added to the selected BCD release metadata.", + "type": "browser_release_added" + }, + { + "after": { + "status": "beta", + "version": "27.2" + }, + "browser": "safari", + "id": "c7c2bda6ded4d9c86ef276f7", + "observedInBcdVersion": "8.1.4", + "observedInWebFeaturesVersion": "3.40.1", + "schemaVersion": 1, + "sourceTimestamp": "2026-10-01T10:12:15.059Z", + "summary": "Safari 27.2 was added to the selected BCD release metadata.", + "type": "browser_release_added" + }, + { + "after": { + "status": "planned", + "version": "157" + }, + "browser": "chrome_android", + "id": "c7c4d441e9916a04c41ad310", + "observedInBcdVersion": "8.1.4", + "observedInWebFeaturesVersion": "3.40.1", + "schemaVersion": 1, + "sourceTimestamp": "2026-10-01T10:12:15.059Z", + "summary": "Chrome Android 157 was added to the selected BCD release metadata.", + "type": "browser_release_added" + }, + { + "after": { + "version_added": "30.0" + }, + "before": { + "version_added": false + }, + "browser": "samsunginternet_android", + "id": "d5c5d41d5c6a5dd21e1f7c33", + "observedInBcdVersion": "8.1.4", + "observedInWebFeaturesVersion": "3.40.1", + "path": "http.headers.Set-Cookie.http_host-http_prefixes", + "schemaVersion": 1, + "sourceTimestamp": "2026-10-01T10:12:15.059Z", + "summary": "http.headers.Set-Cookie.http_host-http_prefixes changed for samsunginternet_android: {\"version_added\":false} to {\"version_added\":\"30.0\"}.", + "type": "support_version_added" + }, + { + "after": { + "version_added": "30.0" + }, + "before": { + "version_added": false + }, + "browser": "samsunginternet_android", + "id": "f4eed25a2003a719afa9775a", + "observedInBcdVersion": "8.1.4", + "observedInWebFeaturesVersion": "3.40.1", + "path": "http.headers.Integrity-Policy-Report-Only", + "schemaVersion": 1, + "sourceTimestamp": "2026-10-01T10:12:15.059Z", + "summary": "http.headers.Integrity-Policy-Report-Only changed for samsunginternet_android: {\"version_added\":false} to {\"version_added\":\"30.0\"}.", + "type": "support_version_added" + }, + { + "after": { + "releaseDate": "2026-11-05", + "status": "planned", + "version": "157" + }, + "browser": "edge", + "id": "fc51c60d71e976f89f9f784f", + "observedInBcdVersion": "8.1.4", + "observedInWebFeaturesVersion": "3.40.1", + "schemaVersion": 1, + "sourceTimestamp": "2026-10-01T10:12:15.059Z", + "summary": "Edge 157 was added to the selected BCD release metadata.", + "type": "browser_release_added" } ] diff --git a/data/selected-bcd.json b/data/selected-bcd.json index c138556..aca1676 100644 --- a/data/selected-bcd.json +++ b/data/selected-bcd.json @@ -1,6 +1,6 @@ { - "bcdTimestamp": "2026-07-24T16:06:32.098Z", - "bcdVersion": "8.0.8", + "bcdTimestamp": "2026-10-01T10:12:15.059Z", + "bcdVersion": "8.1.4", "browsers": { "chrome": { "id": "chrome", @@ -748,22 +748,42 @@ }, { "releaseDate": "2026-06-30", - "status": "current", + "status": "retired", "version": "150" }, { "releaseDate": "2026-07-28", - "status": "beta", + "status": "retired", "version": "151" }, { "releaseDate": "2026-08-25", - "status": "nightly", + "status": "retired", "version": "152" }, { - "status": "planned", + "releaseDate": "2026-09-08", + "status": "retired", "version": "153" + }, + { + "releaseDate": "2026-09-22", + "status": "current", + "version": "154" + }, + { + "releaseDate": "2026-10-06", + "status": "beta", + "version": "155" + }, + { + "releaseDate": "2026-10-20", + "status": "nightly", + "version": "156" + }, + { + "status": "planned", + "version": "157" } ] }, @@ -1398,22 +1418,42 @@ }, { "releaseDate": "2026-06-30", - "status": "current", + "status": "retired", "version": "150" }, { "releaseDate": "2026-07-28", - "status": "beta", + "status": "retired", "version": "151" }, { "releaseDate": "2026-08-25", - "status": "nightly", + "status": "retired", "version": "152" }, { - "status": "planned", + "releaseDate": "2026-09-08", + "status": "retired", "version": "153" + }, + { + "releaseDate": "2026-09-22", + "status": "current", + "version": "154" + }, + { + "releaseDate": "2026-10-06", + "status": "beta", + "version": "155" + }, + { + "releaseDate": "2026-10-20", + "status": "nightly", + "version": "156" + }, + { + "status": "planned", + "version": "157" } ], "upstream": "chrome" @@ -1809,23 +1849,43 @@ }, { "releaseDate": "2026-07-02", - "status": "current", + "status": "retired", "version": "150" }, { - "releaseDate": "2026-07-30", - "status": "beta", + "releaseDate": "2026-07-31", + "status": "retired", "version": "151" }, { - "releaseDate": "2026-08-27", - "status": "nightly", + "releaseDate": "2026-08-28", + "status": "retired", "version": "152" }, { - "releaseDate": "2026-09-10", - "status": "planned", + "releaseDate": "2026-09-11", + "status": "retired", "version": "153" + }, + { + "releaseDate": "2026-09-24", + "status": "current", + "version": "154" + }, + { + "releaseDate": "2026-10-08", + "status": "beta", + "version": "155" + }, + { + "releaseDate": "2026-10-22", + "status": "nightly", + "version": "156" + }, + { + "releaseDate": "2026-11-05", + "status": "planned", + "version": "157" } ], "upstream": "chrome" @@ -2611,23 +2671,43 @@ }, { "releaseDate": "2026-07-21", - "status": "current", + "status": "esr", "version": "153" }, { "releaseDate": "2026-08-18", - "status": "beta", + "status": "retired", "version": "154" }, { "releaseDate": "2026-09-01", - "status": "nightly", + "status": "retired", "version": "155" }, { "releaseDate": "2026-09-15", - "status": "planned", + "status": "retired", "version": "156" + }, + { + "releaseDate": "2026-09-29", + "status": "current", + "version": "157" + }, + { + "releaseDate": "2026-10-13", + "status": "beta", + "version": "158" + }, + { + "releaseDate": "2026-10-27", + "status": "nightly", + "version": "159" + }, + { + "releaseDate": "2026-11-10", + "status": "planned", + "version": "160" } ] }, @@ -3317,23 +3397,43 @@ }, { "releaseDate": "2026-07-21", - "status": "current", + "status": "esr", "version": "153" }, { "releaseDate": "2026-08-18", - "status": "beta", + "status": "retired", "version": "154" }, { "releaseDate": "2026-09-01", - "status": "nightly", + "status": "retired", "version": "155" }, { "releaseDate": "2026-09-15", - "status": "planned", + "status": "retired", "version": "156" + }, + { + "releaseDate": "2026-09-29", + "status": "current", + "version": "157" + }, + { + "releaseDate": "2026-10-13", + "status": "beta", + "version": "158" + }, + { + "releaseDate": "2026-10-27", + "status": "nightly", + "version": "159" + }, + { + "releaseDate": "2026-11-10", + "status": "planned", + "version": "160" } ], "upstream": "firefox" @@ -3634,12 +3734,22 @@ }, { "releaseDate": "2026-05-11", - "status": "current", + "status": "retired", "version": "26.5" }, { - "status": "beta", + "releaseDate": "2026-07-27", + "status": "retired", + "version": "26.6" + }, + { + "releaseDate": "2026-09-14", + "status": "current", "version": "27" + }, + { + "status": "beta", + "version": "27.2" } ] }, @@ -3924,19 +4034,29 @@ }, { "releaseDate": "2026-05-11", - "status": "current", + "status": "retired", "version": "26.5" }, { - "status": "beta", + "releaseDate": "2026-07-27", + "status": "retired", + "version": "26.6" + }, + { + "releaseDate": "2026-09-14", + "status": "current", "version": "27" + }, + { + "status": "beta", + "version": "27.2" } ], "upstream": "safari" }, "samsunginternet_android": { "id": "samsunginternet_android", - "name": "Samsung Internet", + "name": "Samsung Browser", "releases": [ { "releaseDate": "2013-04-27", @@ -4190,8 +4310,13 @@ }, { "releaseDate": "2025-10-25", - "status": "current", + "status": "retired", "version": "29.0" + }, + { + "releaseDate": "2026-05-11", + "status": "current", + "version": "30.0" } ], "upstream": "chrome_android" @@ -4802,22 +4927,42 @@ }, { "releaseDate": "2026-06-30", - "status": "current", + "status": "retired", "version": "150" }, { "releaseDate": "2026-07-28", - "status": "beta", + "status": "retired", "version": "151" }, { "releaseDate": "2026-08-25", - "status": "nightly", + "status": "retired", "version": "152" }, { - "status": "planned", + "releaseDate": "2026-09-08", + "status": "retired", "version": "153" + }, + { + "releaseDate": "2026-09-22", + "status": "current", + "version": "154" + }, + { + "releaseDate": "2026-10-06", + "status": "beta", + "version": "155" + }, + { + "releaseDate": "2026-10-20", + "status": "nightly", + "version": "156" + }, + { + "status": "planned", + "version": "157" } ], "upstream": "chrome_android" @@ -5062,8 +5207,7 @@ ], "firefox_android": [ { - "impl_url": "https://bugzil.la/1958716", - "version_added": false + "version_added": "149" } ], "safari": [ @@ -5222,7 +5366,9 @@ ], "webview_android": [ { - "version_added": false + "notes": "Conditional mediation (autofill integration) is not supported; isConditionalMediationAvailable() always returns false.", + "partial_implementation": true, + "version_added": "131" } ] } @@ -5300,7 +5446,7 @@ ], "webview_android": [ { - "version_added": false + "version_added": "70" } ] } @@ -6467,7 +6613,7 @@ ], "samsunginternet_android": [ { - "version_added": false + "version_added": "30.0" } ], "webview_android": [ @@ -6538,7 +6684,7 @@ ], "samsunginternet_android": [ { - "version_added": false + "version_added": "30.0" } ], "webview_android": [ @@ -6629,17 +6775,17 @@ "support": { "chrome": [ { - "version_added": "88" + "version_added": "85" } ], "chrome_android": [ { - "version_added": "88" + "version_added": "85" } ], "edge": [ { - "version_added": "88" + "version_added": "85" } ], "firefox": [ @@ -6666,12 +6812,12 @@ ], "samsunginternet_android": [ { - "version_added": "15.0" + "version_added": "14.0" } ], "webview_android": [ { - "version_added": "88" + "version_added": "85" } ] } @@ -7153,7 +7299,7 @@ ], "samsunginternet_android": [ { - "version_added": false + "version_added": "30.0" } ], "webview_android": [ @@ -7547,7 +7693,7 @@ } } }, - "schemaFingerprint": "ebad2f9787d9e115700d562ee122e62ba9116b04888263ebdaf922464b36b092", + "schemaFingerprint": "55e3832ebde9d4644e72e418bfda3bc9f2104f195a589da318a9fad1cde9a403", "schemaVersion": 2, - "webFeaturesVersion": "3.34.2" + "webFeaturesVersion": "3.40.1" } diff --git a/data/source-history.json b/data/source-history.json index b9f004c..50d0619 100644 --- a/data/source-history.json +++ b/data/source-history.json @@ -51,6 +51,32 @@ "pathCount": 36, "schemaFingerprint": "ebad2f9787d9e115700d562ee122e62ba9116b04888263ebdaf922464b36b092", "webFeaturesVersion": "3.34.2" + }, + { + "associatedEventCount": 22, + "baselineAssociationCount": 28, + "bcdTimestamp": "2026-09-03T15:52:15.027Z", + "bcdVersion": "8.1.0", + "browserCount": 9, + "catalogueVersion": "2.2.0", + "controlCount": 30, + "id": "884691434b0276dad168bd85", + "pathCount": 36, + "schemaFingerprint": "0faaff2d43d04fb6f962ed22348ce28b9aa8454ce01e70831e0f11cae29b06a9", + "webFeaturesVersion": "3.37.0" + }, + { + "associatedEventCount": 18, + "baselineAssociationCount": 28, + "bcdTimestamp": "2026-10-01T10:12:15.059Z", + "bcdVersion": "8.1.4", + "browserCount": 9, + "catalogueVersion": "2.2.0", + "controlCount": 30, + "id": "2e6b9c3b8aa64649847c2001", + "pathCount": 36, + "schemaFingerprint": "55e3832ebde9d4644e72e418bfda3bc9f2104f195a589da318a9fad1cde9a403", + "webFeaturesVersion": "3.40.1" } ], "schemaVersion": 1 diff --git a/docs/architecture.md b/docs/architecture.md index 990cf88..6ef51d6 100644 --- a/docs/architecture.md +++ b/docs/architecture.md @@ -54,6 +54,24 @@ static Astro build The browser receives only static HTML, CSS, JavaScript, and the selected data bundled by the build. There is no runtime source request. +## Browser controllers + +The planner, minimum planner and evidence-bundle components own their static +markup. Their scripts call explicit initialisers in `src/controllers/`, which +own DOM references, operation generations, session state, rendering and event +handlers. Required controls are checked by element type before handlers are +registered. Shared helpers handle asynchronous event feedback and bounded Blob +downloads with URL cleanup; model calculations and guarded storage remain in +independent modules. This extracts the complete controllers without introducing +a framework or changing opt-in persistence. + +The unit coverage denominator includes model modules, the publication gate, +collector transport, private-output handling and toolchain activation. DOM +controllers retain real-browser validation separately, as they did when embedded +in Astro. CLI dispatch and bootstrap reconstruction remain outside the measured +unit denominator; subprocess and archive tests are separate evidence for those +paths. Thresholds are unchanged. + ## Source selection The catalogue owns every requested BCD path. The generator: diff --git a/docs/attested-evidence.md b/docs/attested-evidence.md index d720ff4..9e54278 100644 --- a/docs/attested-evidence.md +++ b/docs/attested-evidence.md @@ -123,6 +123,18 @@ messages do not enter the reduced policy result. ## Security meaning +### Compose a verified result without changing its meaning + +`verify-evidence --json` produces an envelope with `attestation` and `evidence`. +For `build-packet`, extract its exact `evidence` member unchanged into a private +JSON file using a local JSON tool, then pass that file as the evidence input. +The nested evaluation already carries the verification outcome bound to the +report fingerprint; do not splice a verification result from another report or +invent a `verified` value. Retain the original envelope, report and signature +bundle privately for re-verification. Packet fingerprints prove content binding, +not independent cryptographic authenticity of a manually edited input. No new +wrapper or breaking artifact schema is introduced for this composition path. + A verified result establishes that: - the Sigstore bundle passed the configured cryptographic and transparency diff --git a/docs/authorised-collection.md b/docs/authorised-collection.md index e3de9b8..34e8a9d 100644 --- a/docs/authorised-collection.md +++ b/docs/authorised-collection.md @@ -13,7 +13,7 @@ Collection requires all of the following: - an explicit manifest file; - one fixed HTTPS origin; -- one to 32 exact same-origin paths without query strings or fragments; +- one to 16 exact same-origin paths without query strings or fragments; - `--confirm-authorised-target`; - an output path outside the repository or under ignored `private-data/` or `.private-data/`; @@ -31,7 +31,12 @@ The collector: - records a cross-origin redirect relationship but does not follow it; - performs bounded `GET` requests only; - caps each response body at 128 KiB; -- uses a ten-second request timeout; +- caps retained HTML at 512 KiB in total; +- reserves one response slot per remaining surface, limiting redirect expansion + to the 16-response bundle budget; an exhausted chain remains an explicit + redirect observation rather than a successful final response; +- uses one absolute ten-second deadline per surface, including DNS, headers, + response streaming and all redirect hops; trickled bytes do not restart it; - does not run JavaScript; - does not submit forms; - does not use cookies, credentials, browser profiles or authentication state; @@ -40,6 +45,14 @@ The collector: bundle; - discards non-HTML response bodies. +Repeated response-header values are limited to eight. Overflow produces an +explicit transport error, never a successful observation of a sliced subset. +Cookie reduction preserves the most-specific `__Host-Http-`, `__Http-`, +`__Host-` or `__Secure-` prefix class while removing the actual name and value. +Derived labels reserve suffix space within 80 characters; the complete opaque +surface ID remains the association key. Injected transports that exceed the +body or aggregate budgets fail instead of producing a complete bundle. + Loopback HTTP is available only for deliberate local fixture testing with `--allow-loopback`. It does not permit other private addresses. @@ -74,9 +87,28 @@ npm run cli -- collect-evidence private-data/collector/manifest.json \ --confirm-authorised-target ``` -The command refuses to overwrite an existing file. Output directories are -created with restrictive permissions where the platform supports them, the file -is written atomically with mode `0600`, and no output is committed or uploaded. +The repository boundary is the real directory containing this CLI's checkout, +even when the command is invoked from a different working directory. Relative +output arguments are still relative to that working directory. Before any target +request, the command refuses public repository destinations, existing output +files and symlink parents beneath the repository's private directories. External +destinations are resolved through their existing parent directory before new +children are created; an alias back into the publication tree is refused. + +Output directories are created with mode `0700` and temporary files with mode +`0600` where supported. Complete, flushed bytes are published with an atomic +same-directory hard link. An existing destination makes that operation fail; +competing writers cannot replace the winner. Temporary files are removed after +write or publication failures. A filesystem without hard-link support fails +closed; there is no overwrite-capable rename fallback. No output is committed +or uploaded. + +Use directories controlled by the operator. Parent validation prevents existing +aliases; it does not provide a sandbox against another local process that can +rename or replace those directories concurrently. Defending against a malicious +same-user directory swap would require a reviewed directory-handle strategy and +platform-specific support. Restrictive file modes alone do not make a public +publication directory safe. Inspect the resulting private bundle separately: diff --git a/docs/data-contract.md b/docs/data-contract.md index 913db7f..24cfb49 100644 --- a/docs/data-contract.md +++ b/docs/data-contract.md @@ -1,5 +1,32 @@ # Data contract +## Conservative comparison and policy changes + +Decision-packet evidence comparison counts the complete event set before its +512-event display limit. `totalEvents`, `emittedEvents` and `truncated` describe +that distinction; omitted events still affect regression gates. Reduced-report +comparisons preserve the underlying comparison totals when wrapped in packets. +The browser-policy comparison likewise counts before slicing its display list. +These additive optional summary fields retain the existing schema numbers; +consumers with strict older schemas must update their schema files. No browser +storage migration is needed. Evidence analysis is versioned at 5.1.0; comparisons +across analysis versions are inconclusive, and policies must deliberately review +their expected version rather than accepting it automatically. + +Evidence-policy drift uses `policy:` keys distinct from factual finding keys. +Removing surfaces or requirements, relaxing a fail rule, introducing/extending +exceptions, or replacing trust, identity, scope, freshness or expected-version +constraints requires regression review. Replacements are deliberately conservative: +even an intended strengthening of a trust boundary requires human review rather +than being interpreted as a factual fix. Strengthening a result rule and removing +an exception are resolutions. Adding requirements and role changes are changes. +An unchanged browser lane cannot conceal weakening in the evidence lane. + +Exceptions must name a declared surface and a required evidence/control/composite +target. Outcomes must be unique and scopes cannot overlap, regardless of expiry +or ordering. Disjoint outcomes remain permitted. Exceptions cannot target the +independent trust, identity, freshness or inventory guards and cannot create pass. + ## Selected snapshot `data/selected-bcd.json` is a versioned canonical projection, not a source @@ -90,10 +117,10 @@ normaliser also has explicit behaviour for historic or fixture `true` and | Reduced evidence export | 512 KiB | | Reduced comparison events emitted | 512 | | Collector manifest | 64 KiB | -| Collector surfaces | 32 | +| Collector surfaces | 16 | | Collector response body | 128 KiB | | Collector redirects | 5 | -| Collector request timeout | 10 seconds | +| Collector absolute surface deadline | 10 seconds | | Evidence-policy exceptions | 128 | | Evidence-policy findings | 4,096 | | Browser-policy exceptions | 64 | diff --git a/docs/dependency-policy.md b/docs/dependency-policy.md index f246813..c4ea44b 100644 --- a/docs/dependency-policy.md +++ b/docs/dependency-policy.md @@ -51,6 +51,65 @@ The repository uses npm's `allowScripts` field: Changes to lifecycle-script packages require explicit review. +The publication guard runs with native Node.js TypeScript support and no project +dependencies, including in the final deployment job. + +### Separately locked package-manager runtime + +The npm executable and its dependencies are outside the application lockfile's +audit. The official npm 12.2.0 archive still bundles reported vulnerable versions +of brace-expansion, http-cache-semantics, ip-address and undici. An ordinary +application audit or `npm audit fix` does not repair that bundle. + +`node tools/bootstrap-npm.ts` does not use runner npm for reconstruction, +installation, audit or signature verification. It uses the +supported native Node runtime and the host's `tar` executable to download the +fixed official CLI archive, check its pinned SHA-512 integrity, and restore only +CLI code, documentation and licence files. The upstream `node_modules` bundle +is excluded. Its runtime dependency declarations must exactly match the +reviewed manifest in `tools/npm-toolchain/package.json`. + +A separate `tools/npm-toolchain/package-lock.json` fixes every runtime package +to a registry URL and SHA-512 integrity. All packages remain within their owning +dependency ranges; there are no cross-major overrides. The refreshed graph uses +brace-expansion 5.0.12, http-cache-semantics 4.3.0, ip-address 10.7.3 and undici +8.11.2. It is materialised directly without lifecycle scripts, npm installation, +global changes, or copying bundled modules. The CLI's development, workspace and +bundle declarations are omitted from the reconstructed runtime manifest. + +The bootstrap refuses redirects, non-registry URLs, path traversal, links, +special archive entries, bundled modules and script-bearing runtime packages. +It caps archives, metadata, members, graph size, total downloads, concurrency +and duration. A fresh temporary directory is used for each invocation. The +reconstructed CLI audits that graph at every severity and verifies registry +signatures before its npm and npx executable links are created or added to +workflow PATH. Activation uses the reconstructed CLI's absolute path for the +version, advisory and signature checks. Any failed gate stops activation; the +entry point removes that invocation's temporary reconstruction. Offline process +fixtures exercise each failure and confirm that no executable links or PATH +entry become available. +This is a project-maintained runtime reconstruction, not an unmodified upstream +distribution or an assurance that unknown vulnerabilities cannot exist. + +Every dependency-installing workflow performs this bootstrap before project +installation or dependency audit. Pre-bootstrap package-manager caching is +disabled. A failure cannot fall back to the runner's npm. The deployment job +performs no project install or build. + +Pinned `setup-node` still invokes available node, npm and yarn with `--version` +before cache handling; disabling package-manager caching does not disable these probes. +The action and its environment probes remain inside the trusted runner and +provisioning boundary. No vulnerable execution path or compromise was established +by a version probe. The Node runtime, system extraction tool, runner and registry +signing roots remain trusted bootstrap components. Application lifecycle-script permissions are unchanged. +Executable selection is not enforced by `packageManager` alone. + +Review a CLI version change together with its archive integrity, original +runtime declarations and separate lock. Audit and verify both dependency graphs, +test a fresh reconstruction and application reinstall, and run ordinary unit, +build and browser checks. Dependabot may propose runtime graph updates, but +manifest, lock and compatibility tests must remain consistent. + ## Updates Dependabot may propose npm and Actions updates. A merge requires: @@ -63,3 +122,21 @@ Dependabot may propose npm and Actions updates. A merge requires: - unit, type, build, dependency, browser, accessibility, and public-tree checks. Automatic major-version merges are not configured. + +## Compatibility holds + +TypeScript remains on the supported 6.0 release line while the reviewed +`typescript-eslint` peer range requires a version below 6.1. A newer compiler +major must not be forced through that constraint. Keep the Node.js type +definitions on the 24.x line to match the documented runtime compatibility +floor, even when a newer runtime has its own type definitions. + +Nested dependencies follow their owning package's declared ranges. Refresh +compatible nested releases through the lockfile rather than adding blanket +overrides for unrelated newer majors. Review runtime floors, licences and +lifecycle-script changes before a locked reinstall. + +The reviewed formatting plugin's 1.x line uses the same compiler generation as +the static framework's 7.x line and supports the project runtime and formatter. +Its compiler rewrite requires a formatting pass and the normal build and browser +checks; formatting changes must not introduce unrelated behaviour changes. diff --git a/docs/deployment-security.md b/docs/deployment-security.md index 40e26a8..fef9e07 100644 --- a/docs/deployment-security.md +++ b/docs/deployment-security.md @@ -17,14 +17,17 @@ path is not an origin-isolation boundary. The Pages workflow runs after CI completes successfully for a push to `main` and may also be dispatched manually. Automatic publication is bound to the -exact commit SHA reported by the successful CI run. The workflow separates two -trust levels: +exact commit SHA reported by the successful CI run and additionally requires +successful analysis and current-main checks. The workflow separates two trust +levels: 1. the build job checks out source, installs locked dependencies, runs the full verification suite, and uploads the generated artifact with read-only - repository and Pages access; -2. the dependency-free deployment job receives only `pages: write` and - `id-token: write`, then deploys the already generated artifact. + repository, workflow-metadata and Pages access; +2. the dependency-free deployment job receives `pages: write` and + `id-token: write`, plus read-only source and workflow-metadata access for a + sparse release-guard checkout and final verification, then deploys the + already generated artifact. Every third-party action is pinned to an immutable commit SHA. The repository audit refuses mutable action references, `pull_request_target`, self-hosted @@ -43,6 +46,94 @@ does not alter the checked-out repository or trigger deployment. ## Browser boundary +### Manual-dispatch verification parity + +Both publication paths require the exact release commit to be current `main`, +with successful main-branch **push** runs of CI and CodeQL. The latest matching +run and its latest attempt must contain successful `verify`, `browser` and +`analyse` jobs; old successes, PR checks, skipped jobs and incomplete metadata +cannot authorise publication. A manual Pages dispatch on another branch is +refused. If required checks are pending, the build gate waits with a bounded +polling budget; failed, cancelled or unavailable results fail closed. +The build gate has a ten-minute absolute network/polling budget and the final +gate a ten-second budget. A later successful analysis does not itself dispatch +Pages: after a bounded wait expires, review both pipelines and explicitly rerun +the publication workflow rather than weakening the gate. + +The dependency-free native TypeScript guard uses only fixed-origin, read-only +API requests with redirect refusal, ten-second request limits, bounded response +bodies and complete result counts. It rechecks current `main` during each pass. +Before deploying, after any environment approval, a sparse checkout retrieves +only the same commit's guard. A second gate permits no pending-check wait and +revalidates the exact build SHA, current `main` and required checks. No package +installation or project build runs in the credential-bearing deployment job. +Checks are point-in-time observations, not an atomic lock on future branch +updates; branch protection and environment governance remain necessary. + +Manual Pages dispatch checks out its exact `github.sha` and runs `npm run verify`, +`npm audit --audit-level=high`, installs the locked Chromium build, and runs +`npm run test:e2e` before uploading. There is no emergency verification bypass: +a failed audit or browser check prevents artifact upload and deployment. The +build job has a bounded 30-minute timeout to accommodate both verification +stages. Automatic publication retains its successful exact-SHA CI prerequisite +and does not repeat the additional manual-only checks. + +Browser tests deliberately clear the deployment target for their loopback root +fixture. They rebuild `dist`, so the manual path then rebuilds and audits the +publication target with the Pages base path restored before upload. A local +fixture build can never be uploaded as the deployment artifact by this path. + +Workflow contract tests retain the event-SHA binding, ordered gates and +read-only build boundary. The manual path has verification-command parity with +the current CI workflow, not proof that hosted execution has succeeded. Local +workflow edits do not change the deployed workflow until reviewed publication; +no dispatch or deployment is required to test this contract locally. + +Node 24 remains the hosted compatibility line. Every dependency-installing job +first restores the reviewed CLI and separately locked runtime graph through +`node tools/bootstrap-npm.ts`, without using runner npm for reconstruction, +installation, audit or signature verification, or executing upstream bundled +modules. The pinned `setup-node` action still probes available node, npm and +yarn with `--version` inside the trusted action/runner boundary. +It audits and verifies that graph before activating PATH. Pre-bootstrap npm +caching is disabled and failed restoration cannot fall back to runner npm. +The guard-only deployment job needs Node but neither npm installation nor +dependency caching. See the dependency policy for bootstrap trust assumptions; +a clean application audit alone does not audit the toolchain. + +### Organisation-specific origin review + +Use a separate dedicated origin, not a shared project-site path, for sensitive +local assessment. A header-capable static host should serve the existing +reviewed `_headers` policy, including response CSP and frame restrictions that +cannot be supplied by a meta element. Review TLS, origin isolation, resource +integrity, zero telemetry and cross-origin request behaviour using synthetic +fixtures before approval. Keep actual evidence on the device and out of build +artifacts. A host/origin/DNS/account change and any evidence publication need +separate explicit approval; no such change is performed by local tests. + +The migration plan is: + +1. Choose an organisation-controlled dedicated hostname and a static host that + serves response headers. Do not select an account or domain implicitly. +2. Configure the canonical URL and root base path for that origin in a separate + reviewed change; the current production configuration remains the public + project site. Keep the existing public deployment available for public data. +3. Build the same locked static application with no private evidence, accounts, + telemetry or runtime collection. Translate `_headers` only if required by the + selected host; preserve every restriction and review host-added scripts. +4. Review host access, deployment permissions, logging and retention. Imported + evidence must never enter host logs, build artefacts or deployment storage; + ordinary navigation metadata may still be logged by the host. +5. Before sensitive use, verify actual response headers on document, asset and + error routes, TLS, canonical URLs, frame rejection and absence of external + requests with synthetic fixtures. The presence of `_headers` alone is not a + delivery check. Review browser storage origin separation and provide a clear + local-data clearing path. +6. Approve account, DNS and deployment changes explicitly, retain a rollback + route to the previous public site, and do not move organisation evidence into + either public repository or deployment artefact. Choose HSTS separately. + Every generated HTML page carries a restrictive meta Content Security Policy: - scripts, styles, images, and fonts are limited to the static site's needs; @@ -141,6 +232,8 @@ domain-level decision. Before a deployment commit: ```sh +node tools/bootstrap-npm.ts +# Apply the printed PATH export before the commands below. npm ci npm run verify npm audit --omit=dev --audit-level=low @@ -152,6 +245,52 @@ CONTROLCURRENT_DEPLOY_TARGET=github-pages npm run audit:public git diff --check ``` +Optional local cross-engine smoke checks use the locked browser package without +changing recurring hosted CI or uploading additional artefacts: + +```sh +npx playwright install chromium firefox webkit +CONTROLCURRENT_BROWSER_SMOKE=1 npx playwright test --grep @smoke +``` + +The smoke fixture uses HTTPS with a disposable, locally generated certificate +because WebKit upgrades loopback subresources under the site's existing CSP. +It requires local `openssl`; the certificate and key are deleted after reading +them into the loopback server. Certificate-error checks are disabled in the +smoke browser context and readiness probe, not pinned to a single certificate. +This is a local test-only limitation, not production TLS verification; the built +site's CSP is not weakened. + +The cross-engine smoke jobs run serially to avoid local browser resource +contention. Shared schema validation disables dynamic compilation, including +the schema library's caught capability probe, instead of allowing `unsafe-eval`. + +The smoke scenario checks keyboard use and enlarged text. The complete +Chromium suite remains the default; a smoke pass is not equivalent to complete +Firefox or WebKit coverage. + +The broader local workflow selection is separately opt-in: + +```sh +CONTROLCURRENT_DEPLOY_TARGET= CONTROLCURRENT_BROWSER_WORKFLOWS=1 \ + npm run test:e2e -- --grep '@smoke|@workflow' +``` + +It uses the same disposable HTTPS fixture and runs serially across Chromium, +Firefox and WebKit. It covers profile/policy imports, Blob downloads, denied +storage, evidence file drop, non-executing markup, pending-operation supersession, +bounded export failures, source context, restrictive CSP/framing behaviour, axe +checks and 320-pixel reflow. The original smoke flag still selects only the +keyboard/enlarged-text smoke for the optional engines. Neither flag changes +recurring hosted workflows or uploads artefacts. + +The reflow fixture uses a 320 CSS-pixel viewport and the keyboard fixture uses +200% root font size. Neither is native 400% browser zoom. A manual zoom check +should set a 1280-pixel browser window to 400% in the browser UI, then exercise +planner inputs, imports, result disclosure, evidence review and downloads while +checking focus visibility and horizontal scrolling. Record the browser/version +and actual zoom setting; do not substitute a CSS transform or device scale factor. + After deployment: 1. compare the deployed commit with the reviewed local commit; diff --git a/docs/engineering-case-study.md b/docs/engineering-case-study.md index df24f4f..9f2c51c 100644 --- a/docs/engineering-case-study.md +++ b/docs/engineering-case-study.md @@ -28,7 +28,7 @@ This creates a reviewable surface: ## Honest unsupported states -The desired catalogue included CSP nonce and hash sources. BCD 8.0.8 has no +The desired catalogue included CSP nonce and hash sources. BCD 8.1.4 has no standalone compatibility statement for either source expression. Mapping both to the broader `script-src` directive would overstate the evidence, so the catalogue exposes them with `unsupported_mapping`. diff --git a/docs/methodology.md b/docs/methodology.md index 146aa7d..b62ee96 100644 --- a/docs/methodology.md +++ b/docs/methodology.md @@ -32,10 +32,16 @@ control definition. Multi-path controls use: - `all` when every mapped feature is required; - `any` only when independent paths each establish the intended capability. -No current catalogue control uses `any`. +Integrity Policy uses `any` for its enforcement and report-only source paths; +the currently bundled paths carry identical support data. An `any` mapping +requires at least one path to cover the complete reviewed released population +from the chosen minimum onwards. Complementary intervals across different paths +do not establish one consistently available implementation. Synthetic tests +retain this deliberately stronger planning contract, including qualified support; +the evaluator does not assume an application switches implementations by release. Related data is not substituted for a missing feature. CSP nonce and hash -sources remain unsupported mappings in BCD 8.0.8 because the package does not +sources remain unsupported mappings in BCD 8.1.4 because the package does not publish standalone compatibility statements for those source expressions. ## Version comparison @@ -78,13 +84,20 @@ policy. The planner accepts explicit minimum versions. The reverse planner searches release entries marked `retired`, `current`, or `esr` that carry a release date in the selected snapshot. For every requested browser, it returns the earliest retained release at which all selected -controls have the required outcome. Source-qualified support is accepted only +controls have the required outcome throughout the later reviewed released +population. Source-qualified support is accepted only when the visitor selects that option. An unsupported mapping blocks the complete calculation rather than inheriting a related control. If no retained release satisfies every control, the result identifies the blockers at the most recent comparable release. +Both planning forms show the exact bundled package timestamp and source versions. +Package age is calculated against the device's clock, with an explicit unavailable +state for a future timestamp or invalid clock. It is the age of package metadata, +not a review date, freshness guarantee or runtime source check. The displayed +snapshot may omit later releases and corrections. + Profile comparison requires the same BCD and catalogue versions. It distinguishes: - support gained or lost; @@ -199,11 +212,31 @@ require that control. A control required nowhere is `not_applicable`; a required control with insufficient evidence remains missing, invalid, inconclusive, report-only, or not evaluated. -Project-authored strict CSP, cross-origin isolation, and cookie attribute +Project-authored script CSP declaration, cross-origin isolation, and cookie attribute composites are transparent candidate recipes rather than certification or policy scores. They are evaluated only for surfaces that explicitly require them. +The script CSP declaration candidate (stable ID `strict-csp-candidate`) is not +a claim about the whole policy being strong. Analysis version 5.1.0 requires +one enforced policy, `base-uri 'none'` or `base-uri 'self'`, and valid script +nonce/hash authorisation in both effective element and general script lists. +A style-only nonce cannot satisfy it. It checks declarations without needing +HTML; multiple policies remain review-only rather than being guessed equivalent. +The CSP3 ignored-token rules allow backwards-compatible `unsafe-inline`, host +and scheme tokens when nonce/hash and `strict-dynamic` make them ineffective. +Effective broad script allowances and evaluation sources prevent satisfaction. +Markup correlation and broader style warnings remain separate; unmatched inline +content or nonce reuse still requires review. Runtime execution and nonce +unpredictability are not established. See the [CSP3 processing rules](https://www.w3.org/TR/CSP3/#strict-dynamic-usage). + +Browser minimums describe the selected release and the later released versions +recorded in the reviewed source snapshot, not an unlimited future promise. +Every recorded point in that suffix must retain support. A removal followed by +reintroduction does not make the earlier minimum valid; unknown or qualified +points propagate conservatively. Point-release evaluation remains separate. +This handles the Safari Partitioned-cookie gap without changing source facts. + An optional scope inventory can be supplied before the surface manifest. It contains up to 256 opaque IDs from a declared list, framework manifest, authorised crawl, or test suite. Included IDs must match assessed surface IDs diff --git a/docs/policy-as-code.md b/docs/policy-as-code.md index 3f0b019..6f5dd83 100644 --- a/docs/policy-as-code.md +++ b/docs/policy-as-code.md @@ -85,6 +85,14 @@ Browser availability and supplied configuration evidence remain separate decision lanes. A packet does not prove independent collection, complete coverage, correct runtime enforcement, or production security. +Comparison decisions use complete event totals, not the bounded list displayed +in a report. Truncated lists expose emitted and total counts. JUnit output adds +an explicit omitted-events case when needed so an adverse event beyond the +display limit cannot disappear from the CI result. Evidence-policy requirement +removals and weakened rules are policy regressions, separate from factual +evidence changes. Changes to pinned trust, identity, scope or freshness contracts +also require review rather than implying that evidence improved. + The command line can build, validate and compare packets. Comparison keeps the browser-policy and evidence lanes separate, refuses invalid fingerprints, and classifies incomparable evidence rather than manufacturing a resolution. @@ -153,6 +161,47 @@ npm run cli -- compare-packets previous-packet.json decision-packet.json \ --format junit ``` +Compare reduced evidence reports with an optional incomparable-result gate: + +```sh +npm run cli -- compare-reports previous-report.json report.json \ + --fail-regression --fail-incomparable --format junit +``` + +`compare-reports` accepts `--format text|json|markdown|junit`; `--json` remains +a compatibility alias. Conflicting or missing format arguments return `2`. +Text, Markdown and JUnit disclose complete event totals, emitted events and +truncation separately; display limits do not reduce decision counts. + +`--fail-incomparable` returns exit code `1` for incompatible report context or +any finding-level incomparable result in the complete summary. Without that flag, the existing exit-code behaviour is +unchanged: incomparable results are reported but do not alone fail the command. +Invalid input still returns `2`. Flags govern the process exit consistently +across JSON, text, Markdown and JUnit output. Output documents still describe +all regressions and incomparable results even when an optional exit gate is +omitted; JUnit may therefore contain failure cases with a non-strict exit `0`. + +All JUnit renderers replace each character forbidden by XML 1.0 with one ASCII +space before escaping markup. This includes U+FFFE, U+FFFF and lone UTF-16 +surrogates. Legal Unicode, including supplementary characters, is preserved. +The replacement affects display text only; source reports, fingerprints, +comparison totals and exit decisions are unchanged. + +CI Markdown renderers escape supplied names, keys and summaries as CommonMark +text, including image/link delimiters, HTML, formatting, entities and table pipes. +Control characters become spaces. This prevents supplied Markdown syntax from +creating images or raw HTML; a viewer can still independently linkify plain URLs. +No renderer controls a viewer's network or extension policy. JSON and fingerprints +retain the original values. + +Decision-packet comparison keeps complete evidence totals up to 16,384 and combined +browser/evidence totals up to 20,480 while emitting at most 512 events per lane. +Two disjoint accepted 4,096-finding evidence-policy inputs can therefore report +all 8,192 changes without overflowing a category total. The stress fixture uses +schema-valid inputs and the normal packet builder; it does not claim the bundled +catalogue evaluator naturally produces that many findings. Input and byte limits +are unchanged. + ## JSON Schemas The static site publishes draft 2020-12 schemas for browser policy profiles and diff --git a/docs/pr32-follow-up.md b/docs/pr32-follow-up.md new file mode 100644 index 0000000..2a907e0 --- /dev/null +++ b/docs/pr32-follow-up.md @@ -0,0 +1,142 @@ +# PR32 XML output follow-up + +Later authorised optional work is recorded in +[the optional follow-up](pr32-optional-follow-up.md). This file retains the +validation evidence and deferred choices at the XML correction's revision. + +This local correction addresses FU01 from the supplied follow-up audit dated +7 October 2026. The implementation session began on 10 October with a clean +checkout at `7f16e8b25366a4ccd15ead7af152f92767c33877` on +`maintenance/security-repairs-and-deployment-hardening`. Existing commits, +dependency locks, source snapshots and workflow boundaries are preserved. + +## Confirmed correction + +Accepted bundle names containing U+FFFE or U+FFFF reached JUnit suite attributes +through `inspectEvidenceBundle`, report fingerprinting, report comparison and the +actual CLI. Both pre-fix process fixtures produced XML rejected by Chromium's +XML parser. This is an output interoperability defect; no target collection, +external request or security exploit is claimed. + +The shared XML escaping function now admits exactly the XML 1.0 character set: +U+0009, U+000A, U+000D, U+0020–U+D7FF, U+E000–U+FFFD and +U+10000–U+10FFFF. Each forbidden code point is replaced with one ASCII space +before markup escaping. Lone UTF-16 surrogates are covered at the renderer +boundary. Legal supplementary characters, including supplementary noncharacters +permitted by XML 1.0, are retained. Legal U+007F is also retained rather than +being removed by the previous broader control-character rule. + +This changes display text only. JSON reports keep their original names and +fingerprints, and comparison totals and exit decisions are unchanged. No schema +restriction, evaluator-version change, dependency addition or output limit change +is needed. + +## Regression evidence + +Twelve new unit cases cover forbidden controls, surrogate boundaries, U+FFFE, +U+FFFF and legal character-range boundaries. Existing markup escaping remains +covered. The Markdown test description was narrowed to what it actually tests; +Markdown literal escaping was not implemented. + +Five new default Chromium tests use `DOMParser` with `application/xml` on an +empty page. The oracle first rejects the original illegal literals and accepts +ordinary Unicode. The previously used `sax` strict parser accepts those literals, +so it is not used as the character-validity oracle. + +Normal bundle builders generate both report-name fixtures. The tests run the +actual CLI, decode stdout as strict UTF-8, parse the emitted XML, and compare its +names, full event totals, case/failure counts, process status and stderr with JSON +output. Unchanged and regressed reports are covered. Positive controls include +accented and combining text, Japanese, emoji, supplementary range boundaries, +quotes and markup characters. The other four shared JUnit renderers are also +parsed; descriptive renderer-contract fields exercise case/message escaping +without fabricating reduced-report fingerprints. + +The initial browser harness attempt failed on conflicting inherited colour +environment variables before reaching the XML assertion. The CLI subprocess now +uses an explicit, non-conflicting colour environment and still requires empty +stderr. The corrected pre-fix reproduction then failed twice on the intended XML +parse errors. Initial post-fix fixture assertions omitted an existing outcome +prefix and one preserved space; those expectations and nine new-fixture lint +errors were corrected. The production character-set correction was unchanged. + +## Retained closures and optional work + +PR32-1 through PR32-4 and H1 remain addressed in the retained source. H2's parent +symlink design and H3's concurrent no-overwrite design remain deferred. This +patch does not extend their filesystem scope. + +The fourteen historical closures and nine optional-item dispositions remain as +recorded in [the earlier local handoff](pr32-local-corrections.md#historical-and-optional-boundaries). +FU01 is additional output polish; it does not reopen those original defects. +Markdown literal escaping remains optional, as do broader browser workflows, +controller extraction, planner source-age display, deterministic export-error +coverage, bootstrap failure orchestration and maximum-input experiments. +The default Chromium project is retained; no Firefox/WebKit schedule or hosted +workflow is added. + +If reports from an earlier PR32 revision depended on malformed CSP hashes, +regenerate them from the original evidence with the corrected evaluator before +relying on their conclusions. Import and fingerprint validation check report +bytes and do not rerun the evaluator. This XML display correction does not itself +change the analyser model or require a migration. + +## Local validation on 10 October 2026 + +The following checks use Node 26.4.0 and the retained reviewed npm 12.2.0 +reconstruction. Package versions remain Astro 7.3.6, TypeScript 6.0.3, +Vitest 5.0.3, Playwright 1.63.0 and axe 4.13.0. BCD 8.1.4 and WebDX 3.40.1 +remain unchanged. No package-manager bootstrap change or new reconstruction +was required for this output-only correction. + +| Command | Exit | Observed result | +| ----------------------------------------------------------------------------------------------------------- | ---- | ------------------------------------------------------------------------------ | +| `npm ci` | 0 | 414 added, 415 audited; manifests, both locks and source data unchanged. | +| `npm run test -- --coverage.enabled=false tests/ci-output.test.ts` | 0 | 16 renderer tests passed. | +| `CONTROLCURRENT_DEPLOY_TARGET= CONTROLCURRENT_BROWSER_SMOKE=0 npm run test:e2e -- e2e/junit-output.spec.ts` | 0 | All 5 focused XML tests passed. | +| `CONTROLCURRENT_DEPLOY_TARGET=github-pages npm run verify` | 0 | Every verification stage passed; 366 unit tests in 41 files, none skipped. | +| `npm audit --audit-level=low --json` | 0 | Dedicated application audit: zero vulnerabilities. | +| `npm audit --audit-level=high` | 0 | Documented application audit gate: zero vulnerabilities. | +| `npm audit signatures` | 0 | 414 registry signatures and 149 attestations verified. | +| `npm audit --prefix --audit-level=low --json` | 0 | Separate npm runtime audit: zero vulnerabilities. | +| `npm audit signatures --prefix ` | 0 | 147 registry signatures and 72 attestations verified. | +| `CONTROLCURRENT_DEPLOY_TARGET= CONTROLCURRENT_BROWSER_SMOKE=0 npm run test:e2e` | 0 | 33 Chromium/accessibility tests passed; no failures, skips, flakes or retries. | +| `git diff --cached --check` and `git diff --quiet` | 0 | Staged diff clean and worktree matches the index before commit. | + +Coverage is 89.71% statements, 80.00% branches, 94.72% functions and 90.87% lines; +thresholds and the coverage denominator policy are unchanged. Astro checked +66 files with zero errors, warnings or hints. The repository audit checked +187 tracked/unignored paths, 16 bounded public JSON files and five workflows. +All six schemas and 36 selected paths/30 controls matched. The publication-target +build produced 45 pages; the public audit passed on 71 files (2,463,189 bytes). +The language audit passed on 164 authored files, including staged additions. + +The final verification is repeated after staging this record, retaining the +publication-target build. Browser tests use the default controlled loopback +fixture and an empty page for XML parsing. The test runner printed inherited +colour-environment warnings; CLI subprocess stderr remained empty. Runtime +prefixes, exact invocations, machine results and local logs are retained in the +temporary validation record. Earlier expected reproduction failures and corrected +fixture/harness failures are recorded above rather than reported as final passes. +Registry package provenance is separate from application evidence authenticity. + +## Evidence boundaries + +The supplied follow-up audit reports successful CI run `37619283178` and CodeQL +run `37619283088`, attempt 1, for synthetic merge +`842560428f6167b4cedbf7d3bb8c1a0055155922`. It reports 354 unit tests in 41 files, +28 Chromium tests, the dedicated application audit and CodeQL completion for +that earlier revision. These are attributed historical observations, not fresh +remote verification of this local correction. The original 7 October local +handoff remains a dated record and is not rewritten as current hosted evidence. + +The reviewed reconstructed npm 12.2.0 is reused with Node 26.4.0 for this session. +The separate runtime and application audits are run separately. The exact +commands, current counts and any failures or unexecuted checks are recorded in +the final local validation handoff. No claim is made about the exact Node 24 +floor, broader browser matrix, genuine signed evidence flow, current remote +checks, branch protection, environment approval or release readiness. + +This session is authorised for a local commit only. No push, merge, deployment, +release, hosted workflow dispatch, live target collection or evidence upload is +part of this correction. diff --git a/docs/pr32-local-corrections.md b/docs/pr32-local-corrections.md new file mode 100644 index 0000000..ffd2d4c --- /dev/null +++ b/docs/pr32-local-corrections.md @@ -0,0 +1,302 @@ +# PR32 local correction and maintenance record + +Later authorised optional work is recorded in +[the optional follow-up](pr32-optional-follow-up.md). This file retains the +dated maintenance evidence and choices for the original correction batch. + +This record accompanies the local correction of the four confirmed PR32 issues +on 7 October 2026 AEDT. The companion source audit dated 6 October was read as +evidence, not additional authority. This record does not establish release +readiness or authorise publication. + +## Preserved checkout + +The session began with a clean staged, unstaged and untracked inventory on +`maintenance/security-repairs-and-deployment-hardening` at +`ca5ca99198ed43e0df5961ba937c48364f0634d8`. The supplied reviewed head was +`0bd0e25b070e08826164da23d1d016fddecb803d`, and the comparison base was +`8e142af595dc21b77da1a87075def83f9842e1da`. The only subsequent committed change +was the language-audit correction and four regression tests. It was retained. +There was no uncommitted 18-file dependency-refresh batch to overwrite. Existing +maintenance commits, generated data and workflows were preserved. The user later +authorised compatible dependency/source refreshes and a local commit; the root +manifest and lock were updated within that scope. No branch switch, reset, stash, +clean or remote repository mutation was performed. The workspace alias is a symlink to this checkout; the configured +sandbox could not start, so local commands used approval-reviewed execution. + +## Correction dispositions + +- PR32-1 was already implemented: only the two reviewed generated lock paths are + exempted; nearby authored manifests and forbidden authored terms still fail. + The audit also covers unignored new files and NUL-delimited paths. +- PR32-2 now applies a full-token CSP hash grammar and checks decoded algorithm + lengths independently of SRI options. All three algorithms, malformed option + suffixes, broad allowances, absent/empty HTML, fallback and overrides, style-only + authorisation, multiple policies and evidence-policy mapping are covered. + Valid nonce/hash and CSP3 ignored-source controls remain accepted. The Script + CSP declaration candidate remains a declaration recipe with runtime caveats; + no object-src requirement or security score was introduced. +- PR32-3 gates the complete incomparable summary as well as incompatible report + context. The exact normal-builder reproduction produced compatible context, + zero regressions, two incomparable results and one surface change. CLI tests + cover default and independent strict flags, missing/not-evaluated findings, + model/application/environment differences and unchanged reports. +- PR32-4 implements report-specific JSON, Markdown and JUnit output with shared + format parsing, legacy --json compatibility, invalid/conflicting option errors + and explicit total/emitted/truncated disclosure. Process tests parse JSON and + XML and preserve status across formats, including bounded builder output. +- H1 documentation now distinguishes setup-node's node/npm/yarn version probes + from reconstruction, installation, audit and signature verification. The action + and runner remain trusted; deploy performs no project install or build. No + exploit is inferred from a version probe. Provisioning was not rewritten. +- H2 remains deferred: decide the trusted private root before any filesystem + redesign. Proposed synthetic tests cover an ordinary private destination and + a private-parent symlink into a publication tree. Parent validation alone is + not a defence against concurrent directory replacement; a race-resistant + directory-relative design is needed if that threat is selected. +- H3 remains deferred: select exclusive final creation with partial-write cleanup + or a genuine platform-supported no-replace primitive. Proposed competing-writer + tests must show the loser preserves the winner's bytes. A second destination + check does not close the race. Neither filesystem scenario was exercised. + +## Dated dependency evidence + +The application and separately reconstructed npm runtime both returned exit 0 +from fresh low-severity JSON audits, with zero vulnerabilities. Fresh registry +verification returned 414 application signatures and 149 attestations, and 147 +toolchain signatures and 72 attestations. These are registry-package provenance +checks, not tests of a genuine application evidence attestation or proof of benign +code. `npm ci` using reviewed npm 12.2.0 added 414 packages and audited 415; +its install-time result is separate from the dedicated final audit. + +A fresh package-lock-only audit of the exact comparison-base lock on 7 October +returned exit 1: 15 affected package entries (4 moderate, 10 high, 1 critical). +The historical audit JSON establishing the previously reported 13 vulnerabilities +is unavailable. The table below records this dated reconstruction, not an +individual reconciliation of that missing historical result. Repeated package +entries and multiple advisories are not interchangeable counts. The affected +ranges are registry advisory data; the current locked versions are outside those +reported ranges. That initial correction phase preserved the existing dependency graph. The later +explicitly approved compatible refresh is recorded below. + +| Exact baseline locked path | Prior version | Current locked version | Advisory identifiers | Reported affected range | +| ----------------------------------- | ------------- | ---------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------ | +| `node_modules/@vitest/coverage-v8` | 4.1.10 | 5.0.3 | Transitive advisory propagation | `See mocker advisory` | +| `node_modules/@vitest/mocker` | 4.1.10 | 5.0.3 | GHSA-82fw-gwwq-j7x9 | `>=2.1.0 <4.1.11` | +| `node_modules/astro` | 7.1.3 | 7.3.6 | GHSA-26w7-cxv4-gfx2; GHSA-376h-93r7-7g6f | `<7.2.8; <=7.2.3` | +| `node_modules/brace-expansion` | 5.0.8 | 5.0.12 | GHSA-rgw5-rvv9-x895; GHSA-q2hr-2g5m-vwhr; GHSA-qhr7-859c-m2p7; GHSA-6j4f-fj2g-mc7p | `>=4.0.0 <5.0.9; >=4.0.0 <5.0.12; >=4.0.0 <5.0.11; >=4.0.0 <5.0.10` | +| `node_modules/devalue` | 5.8.2 | 5.9.4 | GHSA-9rgm-9g3h-6x36; GHSA-j22f-vq7h-c4qm; GHSA-hx4r-w6wj-j8fg; GHSA-mcm9-63f2-9j32; GHSA-wf3x-273g-mvxv; GHSA-x5rw-q4pp-hg5g; GHSA-4q55-j62x-fr9h | `<5.9.1; >=5.1.0 <=5.9.2; <=5.9.2; >=1.0.0 <=5.9.2; >=5.8.0 <=5.9.2` | +| `node_modules/fast-uri` | 3.1.4 | 3.1.8 | GHSA-7p8r-x3mc-p8w7; GHSA-5jgf-p345-68v8; GHSA-f65p-4m7j-42xc; GHSA-fph4-wmhf-6fwf; GHSA-jqff-g426-hqxp; GHSA-qw65-cvwx-89v3; GHSA-hrr3-gc8f-f4qj | `>=3.0.0 <3.1.5; >=3.1.3 <3.1.6; >=3.0.0 <3.1.6; >=3.1.2 <3.1.6; >=3.0.0 <3.1.7; >=3.0.0 <3.1.8` | +| `node_modules/http-cache-semantics` | 4.2.0 | 4.3.0 | GHSA-ch52-4w7c-c8xp | `<=4.2.0` | +| `node_modules/js-yaml` | 4.3.0 | Removed | GHSA-5p4m-2wfm-xmqj; GHSA-2883-xcg3-v3hh | `>=4.0.0 <4.3.1; >=4.0.0 <4.3.2` | +| `node_modules/nanoid` | 3.3.16 | 3.3.20 | GHSA-2v37-7h3g-55p8 | `<3.3.18` | +| `node_modules/postcss` | 8.5.22 | 8.5.29 | GHSA-fxqj-rqcc-2cmp | `<=8.5.22` | +| `node_modules/sharp` | 0.35.3 | 0.35.5 | GHSA-rgj7-g3m4-5g8c; GHSA-wq5f-xc86-pv6w | `<0.35.4; <0.35.5` | +| `node_modules/smol-toml` | 1.7.0 | 1.9.0 | GHSA-7w5x-hrqm-74c2; GHSA-r4xh-jqrq-34v2 | `<=1.7.0; <=1.8.0` | +| `node_modules/source-map-js` | 1.2.1 | 1.2.2 | GHSA-68fv-2mgg-jv7q | `>=1.0.0 <1.2.2` | +| `node_modules/svgo` | 4.0.2 | 4.1.0 | GHSA-w27v-7q3p-w38r; GHSA-4vpr-x523-8j87 | `>=4.0.0 <4.1.0` | +| `node_modules/vitest` | 4.1.10 | 5.0.3 | GHSA-82fw-gwwq-j7x9 | `>=2.1.0 <4.1.11` | + +The corresponding original advisory records can be opened at +`https://github.com/advisories/`. The full dated audit JSON and lock +comparison were retained in the local temporary validation files. The absence +of the original historical audit remains an evidence gap. + +### Reachability and compatibility + +Vitest, mocker and coverage are development test paths. Astro, devalue, sharp, +SVGO, YAML/TOML helpers and cache semantics are static build/development paths. +The former js-yaml build dependency and its argparse child were removed by the +approved framework patch; the owning helpers now declare yaml instead. +PostCSS, nanoid and source-map-js participate in build CSS/source-map tooling; +fast-uri is reached through the YAML language server's Ajv dependency. These +package-presence facts do not establish execution of an advisory's specific +vulnerable operation. Static deployment has no Node server/image service. + +brace-expansion is also reachable in the declared CLI-only graph through +@sigstore/tuf, @tufjs/models and minimatch; lint tooling shares minimatch. The +verifier reads the pinned packaged trust root directly and does not start the +TUF client. No exploit reachability claim is made merely from that installed +chain. Sigstore remains excluded from the browser build. CLI, transport and +bootstrap are outside the coverage denominator; subprocess tests do not change it. + +The retained refresh includes deliberate Vitest/coverage 4-to-5 and formatter +plugin 0-to-1 upgrades, rather than only patch updates. TypeScript stays at 6.0.3; +the installed typescript-estree peer range is `>=4.8.4 <6.1.0`. Node type +packages remain on 24.x. This session ran Node 26.4.0, which the package engine +permits; the Node 24 floor was not independently rerun. No forced audit repair, +bulk override or unexplained lock replacement was used. + +Comparison of 286 changed lock entries, including the root entry, found no +licence changes at retained package paths; added package paths declare MIT. +The only install-script flag removals are two former nested fsevents paths. +Current script-bearing paths remain esbuild 0.28.2 and optional fsevents 2.3.3. +The inherited policy permits only the exact esbuild script and denies fsevents; +its esbuild pin changed from 0.28.1 in the base to 0.28.2 in the retained refresh. + +The upstream npm bundle's complete historical advisory inventory was not +independently reconstructed here. The separate current graph uses +brace-expansion 5.0.12, http-cache-semantics 4.3.0, ip-address 10.7.3 and undici +8.11.2 within owning dependency ranges. The maintained reconstruction is not an +unmodified upstream npm distribution. Hashes/signatures do not prove benign +code. Native Node, tar, actions, the runner and registry roots remain trusted. +The 128 MiB compressed-download bound is not an expanded-disk quota. + +### Approved compatible refresh on 7 October + +Registry inventory identified Astro 7.3.6 and typescript-eslint 8.71.1 as compatible +updates from 7.3.5 and 8.71.0. The owning lint packages advance together to 8.71.1. +Vite advances from 8.3.2 to 8.3.3 and tinybench from 6.2.0 to 6.2.1 within declared +ranges. The framework patch itself changes its declared helper versions: +internal-helpers 0.11.0 to 0.12.0, markdown-satteri 0.4.2 to 0.4.3, +am-i-vibing 0.4.0 to 0.5.0, verkit 0.4.1 to 0.5.0, and its exact get-tsconfig +prerelease from 5.0.0-beta.4 to 5.0.0-beta.6. It adds a nested es-module-lexer +3.0.3 while the other consumer retains its own version. These are changes in +upstream owning declarations, not root overrides or an added optional-peer graph. + +The refreshed lock changes 23 entries including the root, retains licences at +all retained paths, adds one MIT path, +and removes the former MIT js-yaml and Python-2.0 argparse paths. No lifecycle +script flag, allowScripts permission or retained package runtime floor changes. +TypeScript 6.0.3 and Node types 24.19.1 remain deliberate compatibility holds; +TypeScript 7 and Node types 26 were not installed. The separate reconstructed npm +12.2.0 graph has no installed compatible updates and its lock is unchanged. + +The registry still identifies BCD 8.1.4 and web-features 3.40.1 as latest. +The documented source-update preview against those installed exact packages +reports zero semantic events and no truncation. Regeneration therefore retains +the reviewed dataset and event history unchanged; no source update was invented. + +## Source review + +The retained dataset refresh is BCD 8.0.8 to 8.1.4 and WebDX web-features 3.34.2 +to 3.40.1. The semantic comparison produced 40 events without truncation: +29 browser-release additions, 5 support additions, 5 support-version corrections +and 1 partial-support addition. All 36 selected paths, the catalogue's 30 controls, +control mappings and retained WebDX Baseline fields remain unchanged. + +Support additions cover Firefox Android PRF, WebView Android platform-authenticator +availability, Samsung Integrity Policy/enforcement-report-only and Host-Http cookie +prefixes. Permissions Policy's Chrome, Chrome Android, Edge and WebView Android +start versions move from 88 to 85. Conditional-mediation support in WebView Android +is explicitly partial because autofill integration is unavailable. Release metadata +additions do not bypass released-population checks. Generation/schema verification +checks exact pinned inputs; no runtime source fetch was added. + +## Historical and optional boundaries + +The companion audit source-closed CC01 and CC03–CC14 for their identified defects. +This patch repairs CC02's residual malformed-hash authorisation. Existing +population/Safari-gap, repeated-header, prefix-redaction, budget/deadline, +count-before-truncation, policy-drift, state invalidation, import preflight, +generation, guarded-storage, exception-scope and cache-boundary work is retained. +Source presence alone is not execution of every historical acceptance permutation. + +| Finding | Disposition for the identified defect | +| ------- | ----------------------------------------------------------------------- | +| CC01 | Source-closed; released-population and Safari gap semantics retained. | +| CC02 | Residual CSP hash grammar correction completed here with focused tests. | +| CC03 | Source-closed; repeated-header fail-closed handling retained. | +| CC04 | Source-closed; prefix-class privacy reduction retained. | +| CC05 | Source-closed; surface, redirect, HTML and label budgets retained. | +| CC06 | Source-closed; total deadlines retained. | +| CC07 | Source-closed; counts before truncation and wrapped totals retained. | +| CC08 | Source-closed; independent policy-drift decisions retained. | +| CC09 | Source-closed; dirty-state and export invalidation retained. | +| CC10 | Source-closed; unavailable-version preflight retained. | +| CC11 | Source-closed; generation supersession retained. | +| CC12 | Source-closed; guarded storage retained. | +| CC13 | Source-closed; exception-scope rejection retained. | +| CC14 | Source-closed; cache boundaries retained. | + +The nine original optional choices remain separate: + +1. Strict incomparable report gate and documented formats are corrected here. +2. Broader browser/accessibility coverage remains partial: opt-in Firefox/WebKit + use one tagged keyboard/planner smoke at 200% root font and 640 px, not full + imports/downloads/storage/file-drop/CSP or 400% browser zoom coverage. +3. CLI process/diagnostic coverage is expanded for these corrections; broader + diagnostics and denominator expansion remain optional. +4. Shared generation/storage extraction is partial; a complete controller refactor + is deferred. +5. Source-age display beside planning remains deferred; Data/footer context remains. +6. The Pages origin limitation is retained; sensitive evidence stays outside it. +7. Manual deployment parity is addressed in source, with no deployment observed. +8. Portable verified output is documented by unchanged evidence-member extraction; + import does not perform fresh attestation verification. +9. Bounded export error feedback is addressed in source; a deterministic browser + error-path regression remains deferred. + +Complementary any-feature intervals, maximum disjoint accepted comparison inputs +and pending planner snapshot polish remain optional questions. No present bundled +support regression or ordinary-user maximum-input bug is asserted here. + +## Local validation record + +Commands used the reviewed reconstructed npm 12.2.0 on native Node 26.4.0. +The executable PATH was the fresh temporary reconstruction returned by +`node tools/bootstrap-npm.ts`, not runner npm. Final application versions are +Astro 7.3.6, typescript-eslint 8.71.1, TypeScript 6.0.3, Vitest 5.0.3, +Playwright 1.63.0 and axe 4.13.0. The installed Chromium is 153.0.8010.12, +revision 1243. BCD remains 8.1.4 and WebDX web-features remains 3.40.1. + +| Exact command | Exit | Observed result | +| ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | ---- | --------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| `node tools/bootstrap-npm.ts` | 0 | Fresh reviewed runtime; no fallback. | +| `npm install --save-dev --save-exact --package-lock-only --ignore-scripts astro@7.3.6 typescript-eslint@8.71.1` | 0 | Exact compatible root patches and owning declarations. | +| `npm update --package-lock-only --ignore-scripts vite tinybench` | 0 | Compatible installed transitive build/test patches. | +| `npm ci` | 0 | 414 packages added, 415 audited; exact script permissions retained. | +| `npm run source-update:preview -- --bcd-package node_modules/@mdn/browser-compat-data/package.json --web-features-package node_modules/web-features/package.json --bcd-data node_modules/@mdn/browser-compat-data/data.json --web-features-data node_modules/web-features/data.json` | 0 | Zero semantic events, no truncation. | +| `npm run generate` | 0 | 36 selected paths, zero new events; repository formatting restored identical source bytes. | +| `npm run test -- --coverage.enabled=false tests/language-audit.test.ts tests/csp-hash-grammar.test.ts tests/report-cli-process.test.ts tests/workflow-boundaries.test.ts` | 0 | 49 tests in 4 files passed. | +| `npm run verify` | 0 | Lint, formatting, tool types, Astro diagnostics, units/coverage, repository audit, generation/schema checks, build, public audit and language audit all passed. | +| `CONTROLCURRENT_DEPLOY_TARGET=github-pages npm run verify` | 0 | Complete final staged-tree verification, retaining the local publication-target build. | +| `npm audit --audit-level=low --json` | 0 | Dedicated application audit: zero vulnerabilities. | +| `npm audit --audit-level=high` | 0 | Separately documented application gate: zero vulnerabilities. | +| `npm audit signatures` | 0 | 414 signatures and 149 attestations verified. | +| `npm audit --prefix --audit-level=low --json` | 0 | Separate npm runtime audit: zero vulnerabilities. | +| `npm audit signatures --prefix ` | 0 | 147 signatures and 72 attestations verified. | +| `CONTROLCURRENT_DEPLOY_TARGET= CONTROLCURRENT_BROWSER_SMOKE=0 npm run test:e2e` | 0 | Default Chromium/axe: 28 passed, 0 failed/skipped/flaky/retried. | +| `CONTROLCURRENT_DEPLOY_TARGET=github-pages npm run build` | 0 | Local publication-target static build; 45 pages. | +| `CONTROLCURRENT_DEPLOY_TARGET=github-pages npm run audit:public` | 0 | Publication tree passed; no deployment. | +| `git diff --cached --check` and `git diff --quiet` | 0 | Staged diff clean; worktree matches index before commit. | +| `npm outdated --json` | 1 | Only deliberate TypeScript and Node-type compatibility holds remain. | + +Full verification passed 354 tests in 41 files with none skipped. Coverage is +89.71% statements, 79.89% branches, 94.72% functions and 90.87% lines; thresholds +are unchanged. Astro checked 66 files with zero errors, warnings or hints. +Repository audit checked 185 tracked/unignored paths, 16 bounded public JSON files +and 5 workflows; six public schemas and all 36 source paths/30 controls matched. +Language audit checked 162 authored files including the staged handoff record. +The ordinary build/public audit checked 45 pages and 71 files (2,446,959 bytes). +The separate publication-target audit checked 71 files (2,463,189 bytes). + +Exact temporary runtime paths, machine results, registry metadata, audit JSON, +lock review and logs are retained in the local temporary validation record. +Registry attestations do not constitute a genuine signed application evidence +end-to-end test. The closure matrix and optional status above are source-backed +boundaries; passing the complete suite does not prove every historical acceptance +permutation was executed. + +## Validation limits + +The final handoff records exact focused/full verification, dependency audits and +Chromium/axe results separately. The initial focused run had one invalid synthetic +fixture (32 responses against a limit of 16); it was corrected to accepted inputs. +No threshold, schema bound or publication gate was weakened. A preliminary lint +run found five issues in the new tests; those were corrected before final verify. An initial full verify passed 351 +tests and failed one stale assertion of the old H1 wording; the assertion now +checks the accurate probe/install boundary while retaining provisioning controls. +The first post-refresh verify stopped at formatting: generation expanded JSON +whitespace in two source files. Parsed equality was confirmed before applying +repository formatting, which restored both files byte-for-byte to their retained +versions. Type, unit, build and later audit stages of that attempt were not run. + +No hosted checks were dispatched, PR state fetched, CodeQL rerun, branch protections +or environment approvals verified, exact-current-main release demonstrated, real +Sigstore evidence attestation signed, live target collected, or artifact uploaded. +The supplied audit's reviewed-head synthetic-merge CI result is historical: unit +checks passed, language failed, and dedicated application audit/browser jobs were +skipped. It is not current hosted evidence for this local patch. Exact-main checks, +newest run/attempt and successful required jobs remain publication prerequisites, +with a current-main recheck and separately approved least-privilege deployment. diff --git a/docs/pr32-optional-follow-up.md b/docs/pr32-optional-follow-up.md new file mode 100644 index 0000000..b70bf92 --- /dev/null +++ b/docs/pr32-optional-follow-up.md @@ -0,0 +1,216 @@ +# PR32 optional local follow-up + +This session on 10 October 2026 implements the authorised optional and deferred +local work. It started with a clean tracked, staged and untracked inventory at +`eaf928facc64e565fe300712a91a518e2970c4df` on +`maintenance/security-repairs-and-deployment-hardening`. The earlier maintenance, +dependency/source refresh, four PR32 corrections and XML correction are retained. +No branch switch, reset, stash, clean, lock replacement or discarded edit occurred. +All changes in this session belong to this follow-up; no ownership conflict arose. + +## Dispositions + +| Item | Current disposition | +| ------ | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| PR32-1 | Retained exact generated-lock exclusions and authored-language regressions. | +| PR32-2 | Retained anchored CSP hash grammar, SRI options and effective-source tests. | +| PR32-3 | Retained the complete incomparable-summary gate and real-builder process fixture. | +| PR32-4 | Retained genuine text/JSON/Markdown/JUnit output and format-independent gates. | +| H1 | Retained accurate setup-node probe wording; provisioning and least privilege unchanged. | +| H2 | Implemented repository-root anchoring, private-parent link refusal, canonical external destinations and pre-collection preflight. Trusted-parent concurrency boundary documented. | +| H3 | Implemented atomic no-replace hard-link publication, private modes and temporary-file cleanup. Real competing writers and a deterministic post-preflight claimant are tested. | +| FU01 | Retained the exact XML 1.0 character boundary and browser XML parser regressions. | + +The private-output root follows the CLI's checkout, not the invoking process's +working directory. A synthetic process test starts elsewhere and verifies that a +public destination is refused before any loopback request. Existing aliases into +the publication tree are rejected. Output bytes are flushed and closed before a +same-directory hard link claims the final filename. Eight competing processes +produce exactly one winner; a forced claim after preflight cannot be replaced. +Serialisation and partial-write failures leave no partial final file or temporary +file. Unsupported hard-link filesystems fail closed. Windows and other filesystem +implementations were not executed in this session. The design assumes trusted +parents and does not claim resistance to malicious concurrent directory swaps. + +Markdown display fields now escape CommonMark punctuation, including supplied +image/link/HTML/formatting syntax. Offline parser fixtures preserve literal names +and refuse active supplied image/HTML/formatting nodes. CommonMark and GFM parsing +are distinguished: viewers can independently linkify plain URLs after parsing. +No URL in those fixtures was visited. JSON, fingerprints and classification remain +unchanged. + +The public packet builder accepts the synthetic maximum of 4,096 evidence-policy +findings per input within its byte bound. Disjoint sets reproduced a failure at +8,192 changes against the former 4,096 category cap. Category totals now share the +existing 16,384 whole-evidence bound; combined totals allow that evidence lane +plus at most 4,096 browser events. The 512-event display limit remains. These are +accepted builder-contract inputs, not findings naturally emitted by the current +catalogue evaluator. No ordinary-user failure is inferred from the stress case. + +The planner, minimum planner and evidence-bundle inspector now use complete +TypeScript controllers with explicit initialisers, typed required DOM controls, +guarded async listeners and shared bounded downloads. Existing generation/storage +boundaries remain. Replacement evidence disables review until loading finishes; +replacement comparisons remove old comparison data immediately. Source timestamps, +versions and device-clock package age appear beside both planning forms. Package +age is not a review date or a guarantee of current data. + +The alternative-feature test preserves the current stronger contract: one mapped +path must cover the entire reviewed release population. It covers complementary +support intervals and a qualified whole-population alternative. The current +Integrity Policy paths still share their bundled support data. The stale +methodology claim that no control uses `any` is corrected. + +Bootstrap activation is measured separately from reconstruction. Version, advisory +and registry-signature subprocesses must all succeed before executable links or a +workflow PATH entry are created. Offline failing subprocesses test each gate. The +real fresh reconstruction is also validated locally; it does not establish that +the reconstructed code is benign or that evidence collection is truthful. + +## Historical closure matrix + +These retain the identified closures, not a claim that every historical acceptance +permutation has been executed again. + +| Finding | Retained closure | +| ------- | ------------------------------------------------------------------------------- | +| CC01 | Released populations and Safari gaps. | +| CC02 | CSP hash grammar and effective declaration candidate; runtime caveats retained. | +| CC03 | Repeated-header fail-closed handling. | +| CC04 | Most-specific cookie-prefix redaction. | +| CC05 | Surface, redirect, HTML and label budgets. | +| CC06 | Absolute collection deadlines. | +| CC07 | Complete counts before truncation, including wrapped totals. | +| CC08 | Independent policy-drift decisions. | +| CC09 | Dirty-state/export invalidation; pending comparisons now clearer. | +| CC10 | Unavailable-version preflight. | +| CC11 | Generation supersession; retained across controller extraction. | +| CC12 | Guarded opt-in storage. | +| CC13 | Exception-scope rejection. | +| CC14 | Cache boundaries. | + +## Nine optional choices + +| Item | Current status | +| -------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | +| 1. Strict incomparable/formats | Completed previously; retained. | +| 2. Browser/accessibility breadth | Expanded local opt-in workflows across three engines; native 400% browser zoom and a complete cross-engine site suite remain unexecuted. No recurring hosted change. | +| 3. CLI diagnostics/coverage | Added actual collector process diagnostics. Measured unit coverage now includes transport, private output and activation. CLI dispatch and reconstruction remain outside that denominator. | +| 4. UI controllers | Complete planner, minimum-planner and evidence-bundle controllers extracted; shared DOM/event/download boundaries added. Other simple page scripts remain in their components. | +| 5. Source age | Implemented beside both planning forms with exact timestamp/version context and clock caveats. | +| 6. Hosting boundary | Retained. Sensitive organisational evidence still requires an appropriate dedicated origin; no account or hosting changes authorised. | +| 7. Manual deployment parity | Source controls retained. Deployment and eventual exact-main verification remain unobserved. | +| 8. Portable authenticated output | Existing unchanged evidence-member extraction remains documented; no new wrapper or fresh browser attestation claim. | +| 9. Export error feedback | Deterministic browser tests now exercise the byte-limit error, Blob failure, no-download outcome and successful retry. | + +## Validation record + +Commands use Node 26.4.0 and the fresh reviewed npm 12.2.0 reconstruction. +`RUNTIME` below denotes the fresh temporary directory printed by the bootstrap; +its `executables` directory is first on PATH for all subsequent npm commands. +The private command record retains that exact path and per-command exit codes. +Astro is 7.3.6, TypeScript 6.0.3, Vitest 5.0.3, Playwright 1.63.0 and axe 4.13.0. +The executed engines report Chromium 153.0.8010.12 (revision 1243), Firefox 155.0 +(1543) and WebKit 26.6 (2359). + +| Command | Exit | Observed result | +| -------------------------------------------------------------------------------------------------------------------------------------------------- | ---- | -------------------------------------------------------------------------------------------------------------------------------- | +| `env -u GITHUB_PATH -u GITHUB_ENV node tools/bootstrap-npm.ts` | 0 | Fresh reconstruction, version check, low-severity runtime audit and registry signature verification succeeded before activation. | +| `npm ci` | 0 | 414 added, 415 audited; zero reported vulnerabilities. Manifests and locks unchanged. | +| `npm run test -- --coverage.enabled=false tests/collector-cli-process.test.ts tests/private-output.test.ts` | 0 | 15 focused filesystem/process tests passed, including the deterministic late claimant. | +| `CONTROLCURRENT_DEPLOY_TARGET= CONTROLCURRENT_BROWSER_SMOKE=0 CONTROLCURRENT_BROWSER_WORKFLOWS=0 npm run test:e2e -- e2e/audit-boundaries.spec.ts` | 0 | 15 focused Chromium tests passed. | +| `CONTROLCURRENT_DEPLOY_TARGET= CONTROLCURRENT_BROWSER_SMOKE=0 CONTROLCURRENT_BROWSER_WORKFLOWS=1 npm run test:e2e -- --grep '@smoke\|@workflow'` | 0 | 60 passed: 20 each in Chromium, Firefox and WebKit; no failures, skips, flakes or retries. | +| `CONTROLCURRENT_DEPLOY_TARGET=github-pages npm run verify` | 0 | Every stage passed; 396 tests in 44 files, none skipped. Repeated on the final staged tree before commit. | +| `npm audit --audit-level=low --json` | 0 | Dedicated full application audit: zero vulnerabilities. | +| `npm audit --audit-level=high` | 0 | Documented application gate: zero vulnerabilities. | +| `npm audit --omit=dev --audit-level=low --json` | 0 | Production dependency advisory query: zero vulnerabilities. | +| `npm audit signatures` | 0 | 414 registry signatures and 149 attestations verified. | +| `npm audit --prefix "$RUNTIME" --audit-level=low --json` | 0 | Separate package-manager runtime audit: zero vulnerabilities. | +| `npm audit signatures --prefix "$RUNTIME"` | 0 | 147 registry signatures and 72 attestations verified. | +| `CONTROLCURRENT_DEPLOY_TARGET= CONTROLCURRENT_BROWSER_SMOKE=0 CONTROLCURRENT_BROWSER_WORKFLOWS=0 npm run test:e2e` | 0 | All 38 default Chromium/accessibility tests passed; no failures, skips, flakes or retries. | +| `git diff --cached --check` and `git diff --quiet` | 0 | Staged patch passes whitespace checks and matches the worktree before commit. | + +The complete verification runs lint, formatting, TypeScript, Astro, unit coverage, +repository audit, generated-data/schema checks, static build, public audit and +language audit. Astro checks 73 files with zero errors, warnings or hints. Unit +coverage is 88.82% statements, 79.32% branches, 94.21% functions and 90.48% lines; +the expanded denominator meets the unchanged thresholds. The repository audit +checks 200 tracked/unignored paths, 16 bounded public JSON files (480,213 bytes) +and five workflows. All six schemas and 36 selected paths/30 controls match. +The publication-target build has 45 pages and 73 public files (2,463,447 bytes). +The language audit covers 177 authored paths, including the staged additions. + +The install count is not substituted for either dedicated audit. Application +advisory metadata covers 516 lock-graph entries including optional platform +packages; registry signatures cover the 414 installed packages. The separate +runtime graph has 147 packages. No dependency or browser download was added by +the optional engine checks; those engines were already installed locally. + +Intermediate failures are retained as development evidence. The first focused +run had 68 passes and one obsolete Markdown expectation. The next had 35 passes +and seven failures: the intended maximum-input reproduction, four parser-extension +expectations, one legacy escaped-text expectation and one incorrect expected +support state. The next had 95 passes and one incorrect JUnit-property expectation. +Those fixtures now check the actual retained contracts. The extracted scripts +initially exposed 377 strict-lint errors, predominantly inherited non-null +assertions; typed element guards and async handlers resolved them without rule +suppression. One remaining generic-helper error and the moved base-URL typing were +also corrected. The new collector process fixture initially had a missing brace +(11 other tests passed); all 15 then passed after repair. The first complete verify +stopped at its new environment-variable type annotation, leaving subsequent stages +unexecuted in that attempt. The corrected complete run and final staged run pass. +Browser logs contain inherited colour-environment warnings; the tested CLI +subprocesses have empty stderr on successful commands. + +## Changed files + +The local commit contains 37 files: + +- UI/model: `src/ci-output.ts`, `src/contracts.ts`, `src/source-age.ts`, + `src/components/Planner.astro`, `src/components/MinimumPlanner.astro`, + `src/components/EvidenceBundleInspector.astro`, `src/components/SourceContext.astro`, + `src/controllers/planner.ts`, `src/controllers/minimum-planner.ts`, + `src/controllers/evidence-bundle.ts`, `src/controllers/dom.ts`, + `src/controllers/download.ts`. +- Local tooling: `tools/cli.ts`, `tools/private-output.ts`, `tools/bootstrap-npm.ts`, + `tools/toolchain-activation.ts`. +- Verification: `tests/ci-output.test.ts`, `tests/decision-packet.test.ts`, + `tests/evaluate.test.ts`, `tests/npm-toolchain.test.ts`, `tests/private-output.test.ts`, + `tests/collector-cli-process.test.ts`, `tests/source-age.test.ts`, + `e2e/audit-boundaries.spec.ts`, `e2e/site.spec.ts`, `playwright.config.ts`, + `vitest.config.ts`. +- Documentation: `README.md`, `docs/architecture.md`, `docs/authorised-collection.md`, + `docs/dependency-policy.md`, `docs/deployment-security.md`, `docs/methodology.md`, + `docs/policy-as-code.md`, `docs/pr32-follow-up.md`, `docs/pr32-local-corrections.md`, + `docs/pr32-optional-follow-up.md`. + +## Maintenance and provenance limits + +The current batch changes no package manifest, either lockfile, selected browser +dataset, source history, WPT revision, workflow, install-script policy or licence +inventory. The prior dated advisory and source-change evidence remains in +[the maintenance handoff](pr32-local-corrections.md) and +[the XML follow-up](pr32-follow-up.md). The original thirteen historical advisory +items are not newly claimed to have been individually reconciled. Current audit +results are separate from historical advisory reachability. + +BCD 8.1.4, WebDX 3.40.1, TypeScript 6.0.3 and Node types 24.19.1 are retained. +This session uses Node 26.4.0 and the reviewed reconstructed npm 12.2.0; the Node 24 +floor is not independently exercised. The reconstruction remains a maintained +distribution, not the unmodified upstream bundle. Hashes, registry signatures and +attestations do not prove benign code. Compressed download bounds are not expanded +disk quotas. Registry provenance is separate from authentic application evidence. + +The optional browsers use a disposable loopback HTTPS certificate with the +documented context-wide test-only certificate bypass. This is not production TLS +verification. No real signed evidence ceremony, native 400% zoom, hostile-directory +race defence, current hosted run, branch protection, human environment approval or +exact-main release check is claimed. Full bootstrap reconstruction is outside unit +coverage even though archive tests and a successful fresh run provide other evidence. + +No push, merge, deployment, release, hosted workflow dispatch, live target +collection, evidence upload, signing ceremony, external message or account change +is part of this session. The only remote validation is the previously approved +registry reconstruction, advisory queries and registry signature verification. +Further publication or hosted runs need separate approval; merge and deployment +retain their own renewed approval boundary. diff --git a/e2e/audit-boundaries.spec.ts b/e2e/audit-boundaries.spec.ts new file mode 100644 index 0000000..7fb39d3 --- /dev/null +++ b/e2e/audit-boundaries.spec.ts @@ -0,0 +1,580 @@ +import { expect, test, type Page } from "@playwright/test"; +import { readFileSync } from "node:fs"; +import { readFile } from "node:fs/promises"; +import { inspectEvidenceBundle } from "../src/evidence-bundle"; +import { evaluateProfile } from "../src/evaluate"; +import { selectedSnapshotSchema } from "../src/contracts"; +import { evidenceIdentity, evidenceSourceContext } from "../tests/helpers"; + +const selectedSnapshot = selectedSnapshotSchema.parse( + JSON.parse(readFileSync(new URL("../data/selected-bcd.json", import.meta.url), "utf8")) as unknown +); + +async function reportFixture() { + return inspectEvidenceBundle( + { + schemaVersion: 4, + name: "Synthetic deferred fixture", + identity: evidenceIdentity, + surfaces: [ + { + id: "document", + role: "document", + requiredEvidence: ["response"], + requiredControls: ["content-security-policy"], + requiredComposites: [] + } + ], + responses: [ + { + schemaVersion: 1, + name: "Fixture", + surfaceId: "document", + headers: { "Content-Security-Policy": "default-src 'none'" } + } + ] + }, + evidenceSourceContext + ); +} + +async function deferredInputs(page: Page) { + await page.addInitScript(() => { + const gates: { kind: "file" | "hash"; release: () => Promise; reject: () => void }[] = []; + let activeHandlers = 0; + const nativeAdd: unknown = Object.getOwnPropertyDescriptor( + EventTarget.prototype, + "addEventListener" + )?.value; + if (typeof nativeAdd !== "function") throw new Error("Missing native event registration"); + const originalAdd = ( + target: EventTarget, + type: string, + listener: EventListenerOrEventListenerObject | null, + options?: boolean | AddEventListenerOptions + ) => { + Reflect.apply(nativeAdd, target, [type, listener, options]); + }; + EventTarget.prototype.addEventListener = function (type, listener, options) { + if (typeof listener !== "function") { + originalAdd(this, type, listener, options); + return; + } + const wrapped: EventListener = function (this: EventTarget, event) { + const result: unknown = listener.call(this, event); + if (result instanceof Promise) { + activeHandlers++; + void result.then( + () => { + activeHandlers--; + }, + () => { + activeHandlers--; + } + ); + } + }; + originalAdd(this, type, wrapped, options); + }; + const originalText = (file: File) => Blob.prototype.text.call(file); + const originalDigest = crypto.subtle.digest.bind(crypto.subtle); + let holdHash = false; + Object.defineProperty(window, "auditDeferred", { + value: { + pending: () => gates.map((gate) => gate.kind), + activeHandlers: () => activeHandlers, + holdHash: (value: boolean) => { + holdHash = value; + }, + release: async (index: number, fail = false) => { + const gate = gates[index]; + if (gate) { + if (fail) gate.reject(); + else await gate.release(); + } + } + } + }); + File.prototype.text = function () { + return new Promise((resolve, reject) => + gates.push({ + kind: "file", + release: () => originalText(this).then(resolve, reject), + reject: () => reject(new Error("Stale synthetic file error")) + }) + ); + }; + crypto.subtle.digest = function (algorithm, data) { + if (!holdHash) return originalDigest(algorithm, data); + return new Promise((resolve, reject) => + gates.push({ + kind: "hash", + release: () => originalDigest(algorithm, data).then(resolve, reject), + reject: () => reject(new Error("Stale synthetic hash error")) + }) + ); + }; + }); +} +async function gate( + page: Page, + action: "release" | "holdHash", + value: number | boolean, + fail = false +) { + await page.evaluate( + async ({ action, value, fail }) => { + const api = ( + window as unknown as { + auditDeferred: { + release(index: number, fail: boolean): Promise; + holdHash(value: boolean): void; + }; + } + ).auditDeferred; + if (action === "release") await api.release(value as number, fail); + else api.holdHash(value as boolean); + }, + { action, value, fail } + ); +} +async function pending(page: Page) { + return page.evaluate(() => + (window as unknown as { auditDeferred: { pending(): string[] } }).auditDeferred.pending() + ); +} + +async function settled(page: Page) { + // Observe completion of the enclosing async event handlers, not just their + // File.text or digest dependency. No arbitrary race delay is involved. + await expect + .poll(() => + page.evaluate(() => + ( + window as unknown as { auditDeferred: { activeHandlers(): number } } + ).auditDeferred.activeHandlers() + ) + ) + .toBe(0); +} + +test("profile edits invalidate every derived export, including an empty browser selection @workflow", async ({ + page +}) => { + await page.goto("/planner/"); + await page.getByRole("button", { name: "Load example" }).click(); + await page.getByRole("button", { name: "Check support" }).click(); + await expect(page.locator("#export-profile")).toBeEnabled(); + await page.getByLabel("Profile name").fill("Edited plan"); + await expect(page.locator("#export-profile")).toBeDisabled(); + await expect(page.locator("#profile-results")).toBeHidden(); + await page.getByRole("button", { name: "Check support" }).click(); + await expect(page.locator("#export-profile")).toBeEnabled(); + for (const checkbox of await page.locator('input[name^="include-"]').all()) + await checkbox.uncheck(); + await expect(page.locator("#export-profile")).toBeDisabled(); + await page.getByRole("button", { name: "Check support" }).click(); + await expect(page.locator("#profile-results")).toBeHidden(); +}); + +test("rejects an unavailable imported release without substituting the old select value @workflow", async ({ + page +}) => { + await page.goto("/planner/"); + const prior = await page.locator('select[name="version-chrome"]').inputValue(); + await page.locator("#import-profile").setInputFiles({ + name: "invalid-version.json", + mimeType: "application/json", + buffer: Buffer.from( + JSON.stringify({ + schemaVersion: 1, + name: "Unavailable plan", + baselines: [{ browser: "chrome", minimumVersion: "999" }] + }) + ) + }); + await expect(page.locator("#profile-message")).toContainText("cannot evaluate"); + await expect(page.locator('select[name="version-chrome"]')).toHaveValue(prior); + await expect(page.getByLabel("Profile name")).not.toHaveValue("Unavailable plan"); +}); + +test("supports session-only evaluation with a throwing storage getter @workflow", async ({ + page +}) => { + await page.addInitScript(() => + Object.defineProperty(window, "localStorage", { + get() { + throw new Error("Synthetic storage denial"); + } + }) + ); + await page.goto("/planner/"); + await expect(page.locator("#profile-message")).toContainText("unavailable"); + await page.getByRole("button", { name: "Load example" }).click(); + await page.getByRole("button", { name: "Check support" }).click(); + await expect(page.locator("#export-profile")).toBeEnabled(); + await page.getByRole("button", { name: "Save locally" }).click(); + await expect(page.locator("#profile-message")).toContainText("not saved"); +}); + +test("clear and replacement supersede deferred evidence-file successes and errors @workflow", async ({ + page +}) => { + await deferredInputs(page); + await page.goto("/assess/"); + await page.locator(".advanced-assessment > summary").click(); + await page.locator("#bundle-file").setInputFiles({ + name: "first.json", + mimeType: "application/json", + buffer: Buffer.from("first") + }); + await expect.poll(() => pending(page)).toEqual(["file"]); + await page.getByRole("button", { name: "Clear" }).last().click(); + await gate(page, "release", 0); + await settled(page); + await expect(page.locator("#bundle-block")).toHaveValue(""); + await page + .locator("#bundle-file") + .setInputFiles({ name: "old.json", mimeType: "application/json", buffer: Buffer.from("old") }); + await page + .locator("#bundle-file") + .setInputFiles({ name: "new.json", mimeType: "application/json", buffer: Buffer.from("new") }); + await expect.poll(() => pending(page)).toEqual(["file", "file", "file"]); + await gate(page, "release", 2); + await expect(page.locator("#bundle-block")).toHaveValue("new"); + await gate(page, "release", 1, true); + await settled(page); + await expect(page.locator("#bundle-block")).toHaveValue("new"); + await expect(page.locator("#bundle-message")).not.toContainText("Stale synthetic"); +}); + +test("clear during deferred hashing cannot restore the report or its export @workflow", async ({ + page +}) => { + await deferredInputs(page); + await page.goto("/assess/"); + await page.locator(".advanced-assessment > summary").click(); + await page.getByRole("button", { name: "Load redacted example" }).last().click(); + await gate(page, "holdHash", true); + await page.getByRole("button", { name: "Review evidence file" }).click(); + await expect.poll(() => pending(page).then((items) => items.length)).toBeGreaterThan(0); + await page.getByRole("button", { name: "Clear" }).last().click(); + await gate(page, "holdHash", false); + for (let i = 0; i < (await pending(page)).length; i++) await gate(page, "release", i); + await settled(page); + await expect(page.locator("#bundle-results")).toBeHidden(); + await expect(page.locator("#export-bundle")).toBeDisabled(); + await expect(page.locator("#bundle-form")).toHaveAttribute("aria-busy", "false"); +}); + +test("a profile edit cancels a deferred import before any form mutation @workflow", async ({ + page +}) => { + await deferredInputs(page); + await page.goto("/planner/"); + await page.locator("#import-profile").setInputFiles({ + name: "old.json", + mimeType: "application/json", + buffer: Buffer.from( + JSON.stringify({ + schemaVersion: 1, + name: "Stale import", + baselines: [{ browser: "chrome", minimumVersion: "120" }] + }) + ) + }); + await expect.poll(() => pending(page)).toEqual(["file"]); + await page.getByLabel("Profile name").fill("Current plan"); + await gate(page, "release", 0); + await settled(page); + await expect(page.getByLabel("Profile name")).toHaveValue("Current plan"); + await expect(page.locator("#export-profile")).toBeDisabled(); +}); + +test("preserves import-before-evaluation comparison input but clears it on a genuine edit @workflow", async ({ + page +}) => { + await page.goto("/planner/"); + await page.getByRole("button", { name: "Load example" }).click(); + const earlier = evaluateProfile(selectedSnapshot, { + schemaVersion: 1, + name: "Example browser baseline", + baselines: [ + { browser: "chrome", minimumVersion: "120" }, + { browser: "firefox", minimumVersion: "115" }, + { browser: "safari", minimumVersion: "17" } + ] + }); + await page.locator("#compare-profile").setInputFiles({ + name: "earlier.json", + mimeType: "application/json", + buffer: Buffer.from(JSON.stringify(earlier)) + }); + await expect(page.locator("#profile-message")).toContainText("Earlier evaluation loaded"); + await page.getByRole("button", { name: "Check support" }).click(); + await expect( + page.getByRole("heading", { name: "What changed since the earlier result" }) + ).toBeVisible(); + await page.getByLabel("Profile name").fill("New plan"); + await page.getByRole("button", { name: "Check support" }).click(); + await expect( + page.getByRole("heading", { name: "What changed since the earlier result" }) + ).toBeHidden(); +}); + +test("clear during deferred comparison hashing cannot restore comparison exports @workflow", async ({ + page +}) => { + await deferredInputs(page); + await page.goto("/assess/"); + await page.locator(".advanced-assessment > summary").click(); + await page.getByRole("button", { name: "Load redacted example" }).last().click(); + await page.getByRole("button", { name: "Review evidence file" }).click(); + await expect(page.locator("#bundle-results")).toBeVisible(); + await page.getByText("Compare with an earlier report", { exact: true }).click(); + await page.locator("#previous-report").fill(JSON.stringify(await reportFixture())); + await gate(page, "holdHash", true); + await page.locator("#compare-report").click(); + await expect.poll(() => pending(page).then((items) => items.length)).toBeGreaterThan(0); + await page.getByRole("button", { name: "Clear" }).last().click(); + await gate(page, "holdHash", false); + for (let i = 0; i < (await pending(page)).length; i++) await gate(page, "release", i); + await settled(page); + await expect(page.locator("#export-comparison")).toBeDisabled(); + await expect(page.locator("#bundle-results")).toBeHidden(); +}); + +test("profile edits supersede deferred attachment validation and packet export @workflow", async ({ + page +}) => { + await deferredInputs(page); + await page.goto("/planner/"); + await page.getByRole("button", { name: "Load example" }).click(); + await page.getByRole("button", { name: "Check support" }).click(); + await page + .getByText("Turn this result into a reviewable browser policy", { exact: true }) + .click(); + await page.getByRole("button", { name: "Check policy" }).click(); + const report = await reportFixture(); + await page.getByLabel("Evidence result JSON").setInputFiles({ + name: "evidence.json", + mimeType: "application/json", + buffer: Buffer.from(JSON.stringify(report)) + }); + await expect.poll(() => pending(page)).toEqual(["file"]); + await page.getByLabel("Profile name").fill("Replacement"); + await gate(page, "release", 0); + await settled(page); + await expect(page.locator("#export-decision-packet")).toBeDisabled(); + await page.getByRole("button", { name: "Check support" }).click(); + await page.getByRole("button", { name: "Check policy" }).click(); + await page.getByLabel("Evidence result JSON").setInputFiles({ + name: "evidence2.json", + mimeType: "application/json", + buffer: Buffer.from(JSON.stringify(report)) + }); + await gate(page, "release", 1); + await expect(page.locator("#export-decision-packet")).toBeEnabled(); + const downloads: string[] = []; + page.on("download", (download) => downloads.push(download.suggestedFilename())); + await gate(page, "holdHash", true); + await page.locator("#export-decision-packet").click(); + await expect.poll(() => pending(page).then((items) => items.length)).toBeGreaterThan(2); + await page.getByLabel("Profile name").fill("Cancelled export"); + await gate(page, "holdHash", false); + for (let i = 2; i < (await pending(page)).length; i++) await gate(page, "release", i); + await settled(page); + await expect(page.locator("#export-decision-packet")).toBeDisabled(); + expect(downloads).toEqual([]); +}); + +test("planner remains keyboard-operable at enlarged text @smoke", async ({ page }) => { + const errors: string[] = []; + page.on("pageerror", (error) => errors.push(error.message)); + page.on("console", (message) => { + if (/JavaScript eval|unsafe-eval/u.test(message.text())) errors.push(message.text()); + }); + await page.goto("/planner/"); + await page.evaluate(() => { + document.documentElement.style.fontSize = "200%"; + }); + await page.getByRole("button", { name: "Load example" }).focus(); + await expect(page.getByRole("button", { name: "Load example" })).toBeFocused(); + // Exercise native non-submit and submit keyboard actions, without click helpers. + await page.keyboard.press("Space"); + await expect(page.locator('input[name="include-chrome"]')).toBeChecked(); + await page.getByRole("button", { name: "Check support" }).focus(); + await page.keyboard.press("Enter"); + await expect(page.locator("#profile-results")).toBeVisible(); + await page.setViewportSize({ width: 640, height: 900 }); + expect( + await page.evaluate( + () => document.documentElement.scrollWidth <= document.documentElement.clientWidth + ) + ).toBe(true); + expect(errors).toEqual([]); +}); + +test("a pending replacement disables evidence review until its bytes arrive @workflow", async ({ + page +}) => { + await deferredInputs(page); + await page.goto("/assess/"); + await page.locator(".advanced-assessment > summary").click(); + await page.getByRole("button", { name: "Load redacted example" }).last().click(); + const old = await page.locator("#bundle-block").inputValue(); + const replacement = old.replace('"Release candidate"', '"Replacement evidence"'); + await page.locator("#bundle-file").setInputFiles({ + name: "replacement.json", + mimeType: "application/json", + buffer: Buffer.from(replacement) + }); + await expect.poll(() => pending(page)).toEqual(["file"]); + await expect(page.getByRole("button", { name: "Review evidence file" })).toBeDisabled(); + await expect(page.locator("#bundle-form")).toHaveAttribute("aria-busy", "true"); + await expect(page.locator("#bundle-message")).toContainText("Reading evidence"); + // Exercise the handler guard as well as the native disabled button. + await page.locator("#bundle-form").dispatchEvent("submit"); + await expect(page.locator("#bundle-results")).toBeHidden(); + await gate(page, "release", 0); + await settled(page); + await expect(page.locator("#bundle-block")).toHaveValue(replacement); + await expect(page.getByRole("button", { name: "Review evidence file" })).toBeEnabled(); + await page.getByRole("button", { name: "Review evidence file" }).click(); + await expect(page.locator("#bundle-source")).toContainText("Replacement evidence"); +}); + +test("a pending comparison hides its predecessor from the visible result and exported report @workflow", async ({ + page +}) => { + await page.goto("/planner/"); + await page.getByRole("button", { name: "Load example" }).click(); + await page.getByRole("button", { name: "Check support" }).click(); + const earlier = evaluateProfile(selectedSnapshot, { + schemaVersion: 1, + name: "Earlier snapshot", + baselines: [{ browser: "chrome", minimumVersion: "120" }] + }); + await page.locator("#compare-profile").setInputFiles({ + name: "earlier.json", + mimeType: "application/json", + buffer: Buffer.from(JSON.stringify(earlier)) + }); + await expect(page.locator("#profile-comparison")).toBeVisible(); + // Delay the next read without navigating away from the retained result. + await page.evaluate(() => { + File.prototype.text = () => + new Promise(() => { + /* Deliberately pending fixture. */ + }); + }); + await page.locator("#compare-profile").setInputFiles({ + name: "replacement.json", + mimeType: "application/json", + buffer: Buffer.from(JSON.stringify(earlier)) + }); + await expect(page.locator("#profile-message")).toContainText("Reading the earlier evaluation"); + await expect(page.locator("#profile-comparison")).toBeHidden(); + const downloading = page.waitForEvent("download"); + await page.locator("#export-engineering-report").click(); + const path = await (await downloading).path(); + if (!path) throw new Error("Missing local report download"); + expect(await readFile(path, "utf8")).not.toContain("Earlier snapshot"); +}); + +test("bounded export and Blob failures reach the live status and recover without a download @workflow", async ({ + page +}) => { + await page.goto("/planner/"); + await page.getByRole("button", { name: "Load example" }).click(); + await page.getByRole("button", { name: "Check support" }).click(); + const downloads: string[] = []; + page.on("download", (download) => downloads.push(download.suggestedFilename())); + await page.evaluate(() => { + const descriptor = Object.getOwnPropertyDescriptor(TextEncoder.prototype, "encode"); + if (!descriptor) throw new Error("Missing native encoder"); + TextEncoder.prototype.encode = function () { + Object.defineProperty(TextEncoder.prototype, "encode", descriptor); + return new Uint8Array(512 * 1024 + 1); + }; + }); + await page.locator("#export-profile").click(); + await expect(page.locator("#profile-message")).toHaveAttribute("role", "status"); + await expect(page.locator("#profile-message")).toContainText("exceeds the 524288-byte limit"); + expect(downloads).toEqual([]); + await page.evaluate(() => { + const create = URL.createObjectURL.bind(URL); + URL.createObjectURL = () => { + URL.createObjectURL = create; + throw new Error("Synthetic Blob creation failure"); + }; + }); + await page.locator("#export-profile").click(); + await expect(page.locator("#profile-message")).toContainText("Synthetic Blob creation failure"); + expect(downloads).toEqual([]); + const downloading = page.waitForEvent("download"); + await page.locator("#export-profile").click(); + expect((await downloading).suggestedFilename()).toBe("controlcurrent-profile.json"); + await expect(page.locator("#profile-message")).toContainText("generated locally"); +}); + +test("file-drop input stays local and never executes supplied markup @workflow", async ({ + page +}) => { + const external: string[] = []; + await page.route("**/*", async (route) => { + if (new URL(route.request().url()).hostname !== "127.0.0.1") { + external.push(route.request().url()); + await route.abort(); + } else await route.continue(); + }); + await page.goto("/assess/"); + await page.locator(".advanced-assessment > summary").click(); + await page.getByRole("button", { name: "Load redacted example" }).last().click(); + const example: unknown = JSON.parse(await page.locator("#bundle-block").inputValue()); + if (!example || typeof example !== "object") throw new Error("Missing fixture"); + const fixture = { + ...example, + htmlDocuments: [ + { + schemaVersion: 1, + name: "Synthetic markup", + surfaceId: "sign-in", + html: '' + } + ] + }; + const text = JSON.stringify(fixture); + await page.getByRole("button", { name: "Clear" }).last().click(); + await page.locator("#bundle-drop").evaluate((element, value) => { + const transfer = new DataTransfer(); + transfer.items.add(new File([value], "dropped.json", { type: "application/json" })); + element.dispatchEvent( + new DragEvent("drop", { bubbles: true, cancelable: true, dataTransfer: transfer }) + ); + }, text); + await expect(page.locator("#bundle-message")).toContainText("Evidence file loaded"); + await page.getByRole("button", { name: "Review evidence file" }).click(); + await expect(page.locator("#bundle-results")).toBeVisible(); + expect(await page.evaluate(() => "fixtureExecuted" in window)).toBe(false); + expect(external).toEqual([]); +}); + +test("planning shows exact bundled timestamps and local source age beside both forms @workflow", async ({ + page +}) => { + await page.clock.setFixedTime(new Date("2026-10-10T12:00:00.000Z")); + await page.goto("/planner/"); + const contexts = page.locator(".source-context"); + await expect(contexts).toHaveCount(2); + for (const context of await contexts.all()) { + await expect(context.locator("time")).toHaveAttribute( + "datetime", + selectedSnapshot.bcdTimestamp + ); + await expect(context).toContainText(`BCD ${selectedSnapshot.bcdVersion}`); + await expect(context).toContainText(`Web feature data ${selectedSnapshot.webFeaturesVersion}`); + await expect(context).toContainText("Package age on this device:"); + await expect(context).toContainText("may omit later releases or corrections"); + } +}); diff --git a/e2e/junit-output.spec.ts b/e2e/junit-output.spec.ts new file mode 100644 index 0000000..80afd6d --- /dev/null +++ b/e2e/junit-output.spec.ts @@ -0,0 +1,222 @@ +import { expect, test, type Page } from "@playwright/test"; +import { spawnSync } from "node:child_process"; +import { readFileSync } from "node:fs"; +import { mkdtemp, rm, writeFile } from "node:fs/promises"; +import { tmpdir } from "node:os"; +import { join } from "node:path"; +import { + renderDecisionPacketComparisonJunit, + renderEvidenceEvaluationJunit, + renderPolicyDriftJunit, + renderPolicyEvaluationJunit +} from "../src/ci-output"; +import { + evidencePolicyProfileSchema, + evidenceReportComparisonSchema, + selectedSnapshotSchema +} from "../src/contracts"; +import { buildDecisionPacket, compareDecisionPackets } from "../src/decision-packet"; +import { inspectEvidenceBundle } from "../src/evidence-bundle"; +import { evaluateEvidencePolicy } from "../src/evidence-policy"; +import { evaluatePolicyProfile } from "../src/policy"; +import { comparePolicyEvaluations } from "../src/policy-comparison"; +import { evidenceIdentity, evidenceSourceContext } from "../tests/helpers"; + +const asOf = "2026-07-24"; +const selectedSnapshot = selectedSnapshotSchema.parse( + JSON.parse(readFileSync(new URL("../data/selected-bcd.json", import.meta.url), "utf8")) as unknown +); + +async function report(name: string, csp = "default-src 'none'") { + return inspectEvidenceBundle( + { + schemaVersion: 4, + name, + identity: evidenceIdentity, + surfaces: [ + { + id: "document", + role: "document", + requiredEvidence: ["response"], + requiredControls: ["content-security-policy"], + requiredComposites: [] + } + ], + responses: [ + { + schemaVersion: 1, + name: "Response", + surfaceId: "document", + headers: csp ? { "Content-Security-Policy": csp } : {} + } + ] + }, + evidenceSourceContext + ); +} + +function cli(args: string[], status: number): string { + const environment: NodeJS.ProcessEnv = { ...process.env, NO_COLOR: "1" }; + delete environment.FORCE_COLOR; + const result = spawnSync(process.execPath, ["--import", "tsx", "tools/cli.ts", ...args], { + cwd: process.cwd(), + env: environment, + timeout: 10_000, + maxBuffer: 2 * 1024 * 1024 + }); + expect(result.error).toBeUndefined(); + expect(result.signal).toBeNull(); + expect(result.stderr.toString("utf8")).toBe(""); + expect(result.status).toBe(status); + // Validate the emitted bytes before passing the decoded document to the XML parser. + return new TextDecoder("utf-8", { fatal: true }).decode(result.stdout); +} + +async function parseXml(page: Page, xml: string) { + return page.evaluate((text) => { + const document = new DOMParser().parseFromString(text, "application/xml"); + return { + error: document.querySelector("parsererror")?.textContent ?? null, + name: document.documentElement.getAttribute("name"), + tests: Number(document.documentElement.getAttribute("tests")), + failures: Number(document.documentElement.getAttribute("failures")), + cases: document.querySelectorAll("testcase").length, + failureElements: document.querySelectorAll("failure").length, + properties: Object.fromEntries( + Array.from( + document.querySelectorAll("property"), + (item) => [item.getAttribute("name") ?? "", item.getAttribute("value")] as const + ) + ), + values: Array.from(document.querySelectorAll("*"), (element) => + Array.from(element.attributes, (attribute) => attribute.value) + ).flat() + }; + }, xml); +} + +test("XML oracle rejects the original illegal characters and accepts legal Unicode", async ({ + page +}) => { + // sax's strict mode accepts these literals; it is not an oracle for XML 1.0 characters. + for (const character of ["\uFFFE", "\uFFFF"]) { + const parsed = await parseXml(page, ``); + expect(parsed.error).not.toBeNull(); + } + expect((await parseXml(page, '')).error).toBeNull(); +}); + +for (const [label, input, expected] of [ + ["U+FFFE", "\uFFFE", " "], + ["U+FFFF", "\uFFFF", " "], + [ + "legal Unicode", + "café 日本語 e\u0301 😀 \u{10000} \u{1FFFE} \u{10FFFF}", + "café 日本語 e\u0301 😀 \u{10000} \u{1FFFE} \u{10FFFF}" + ] +] as const) { + test(`exports ${label} in genuine report CLI JUnit without changing gates or totals`, async ({ + page + }) => { + const name = `Fixture${input} <&> "' suffix`; + const expectedName = `Fixture${expected} <&> "' suffix`; + const before = await report(name); + expect(before.name).toBe(name); + const root = await mkdtemp(join(tmpdir(), "controlcurrent-junit-")); + try { + const beforePath = join(root, "before.json"); + const afterPath = join(root, "after.json"); + await writeFile(beforePath, JSON.stringify(before)); + for (const changed of [false, true]) { + await writeFile(afterPath, JSON.stringify(changed ? await report(name, "") : before)); + const args = [ + "compare-reports", + beforePath, + afterPath, + "--fail-regression", + "--fail-incomparable" + ]; + const status = changed ? 1 : 0; + const comparison = evidenceReportComparisonSchema.parse( + JSON.parse(cli([...args, "--format", "json"], status)) as unknown + ); + expect(comparison.beforeName).toBe(name); + expect(comparison.afterName).toBe(name); + const xml = cli([...args, "--format", "junit"], status); + const parsed = await parseXml(page, xml); + expect(parsed.error).toBeNull(); + expect(parsed.name).toBe(`${expectedName} to ${expectedName}`); + expect(parsed.tests).toBe(parsed.cases); + expect(parsed.failures).toBe(parsed.failureElements); + expect(parsed.failures).toBe(comparison.summary.regressions); + expect(parsed.properties["total-events"]).toBe(String(comparison.summary.totalEvents)); + expect(parsed.properties["emitted-events"]).toBe(String(comparison.summary.emittedEvents)); + expect(parsed.properties["total-regressions"]).toBe(String(comparison.summary.regressions)); + expect(parsed.properties["total-incomparable"]).toBe( + String(comparison.summary.incomparable) + ); + expect(parsed.properties.truncated).toBe(String(comparison.summary.truncated)); + } + } finally { + await rm(root, { recursive: true, force: true }); + } + }); +} + +test("shared JUnit consumers encode names, case attributes and explanations as valid XML", async ({ + page +}) => { + const name = "Fixture\uFFFE\uFFFF café 😀 <&> \"' suffix"; + const expectedName = "Fixture café 😀 <&> \"' suffix"; + const policy = (controls: string[]) => + evaluatePolicyProfile( + selectedSnapshot, + { + schemaVersion: 1, + name, + baselines: [{ browser: "chrome", minimumVersion: "120" }], + requiredControls: controls, + rules: { qualifications: "review", unknown: "fail", unsupported: "fail" }, + exceptions: [] + }, + asOf + ); + const before = policy(["content-security-policy"]); + const after = policy(["content-security-policy", "csp-nonces"]); + const evidence = await report(name); + const evidenceProfile = evidencePolicyProfileSchema.parse( + JSON.parse( + readFileSync(new URL("../examples/evidence-policy.json", import.meta.url), "utf8") + ) as unknown + ); + const evaluation = await evaluateEvidencePolicy(evidence, { ...evidenceProfile, name }, asOf); + const packets = await compareDecisionPackets( + await buildDecisionPacket(before, evidence, asOf), + await buildDecisionPacket(after, evidence, asOf), + asOf + ); + expect(packets.browserPolicy.events.length).toBeGreaterThan(0); + // Exercise accepted descriptive renderer fields; no reduced report fingerprint is fabricated. + const outputs = [ + renderPolicyEvaluationJunit({ + ...after, + findings: after.findings.map((finding) => ({ ...finding, explanation: name })) + }), + renderEvidenceEvaluationJunit(evaluation), + renderPolicyDriftJunit(comparePolicyEvaluations(before, after, asOf)), + renderDecisionPacketComparisonJunit({ + ...packets, + browserPolicy: { + ...packets.browserPolicy, + events: packets.browserPolicy.events.map((item) => ({ ...item, summary: name })) + } + }) + ]; + for (const xml of outputs) { + const parsed = await parseXml(page, xml); + expect(parsed.error).toBeNull(); + expect(parsed.values.some((value) => value.includes(expectedName))).toBe(true); + expect(parsed.tests).toBe(parsed.cases); + expect(parsed.failures).toBe(parsed.failureElements); + } +}); diff --git a/e2e/site.spec.ts b/e2e/site.spec.ts index e52f760..f722efa 100644 --- a/e2e/site.spec.ts +++ b/e2e/site.spec.ts @@ -19,8 +19,8 @@ test("renders real source provenance and makes no external request", async ({ pa ).toBeVisible(); await expect( page.getByText("MDN browser data", { exact: true }).first().locator("..") - ).toContainText("8.0.8"); - await expect(page.getByText("Web feature data").locator("..")).toContainText("3.34.2"); + ).toContainText("8.1.4"); + await expect(page.getByText("Web feature data").locator("..")).toContainText("3.40.1"); await expect(page.getByText("Server connection").locator("..")).toContainText("none"); expect(externalRequests).toEqual([]); @@ -28,7 +28,7 @@ test("renders real source provenance and makes no external request", async ({ pa expect(violations.violations).toEqual([]); }); -test("evaluates, stores, clears, and exports a profile locally", async ({ page }) => { +test("evaluates, stores, clears, and exports a profile locally @workflow", async ({ page }) => { await page.goto("/planner/"); await page.getByRole("button", { name: "Load example" }).click(); await page.getByRole("button", { name: "Check support" }).click(); @@ -122,7 +122,9 @@ test("evaluates, stores, clears, and exports a profile locally", async ({ page } expect(violations.violations).toEqual([]); }); -test("imports explicit browser minimums and builds a local policy report", async ({ page }) => { +test("imports explicit browser minimums and builds a local policy report @workflow", async ({ + page +}) => { await page.goto("/planner/"); await page.locator("#import-browser-config").setInputFiles({ name: "package.json", @@ -309,7 +311,7 @@ test("wraps long browser-data labels without clipping", async ({ page }) => { await expectLabelsInsideBounds(); }); -test("keeps dense views inside the viewport at 320 pixels", async ({ page }) => { +test("keeps dense views inside the viewport at 320 pixels @workflow", async ({ page }) => { await page.setViewportSize({ width: 320, height: 800 }); for (const path of [ "/", @@ -451,7 +453,9 @@ test("assesses and clears a redacted header snapshot without a network request", expect(await page.evaluate(() => localStorage.length)).toBe(0); }); -test("reduces a multi-surface evidence bundle without exposing raw inputs", async ({ page }) => { +test("reduces a multi-surface evidence bundle without exposing raw inputs @workflow", async ({ + page +}) => { const externalRequests: string[] = []; page.on("request", (request) => { const url = new URL(request.url()); @@ -476,7 +480,7 @@ test("reduces a multi-surface evidence bundle without exposing raw inputs", asyn page.getByRole("heading", { name: "Privacy-reduced evidence report" }) ).toBeVisible(); await expect( - results.getByRole("heading", { name: "Strong Content Security Policy" }) + results.getByRole("heading", { name: "Script CSP declaration candidate" }) ).toBeVisible(); await expect( results.getByRole("heading", { name: "Cross-origin isolation headers" }) @@ -488,7 +492,7 @@ test("reduces a multi-surface evidence bundle without exposing raw inputs", asyn results.getByRole("heading", { name: "Requirements for page · sign-in" }) ).toBeVisible(); await expect( - results.getByText("19 of 19 required features found · 3 of 3 combined checks met") + results.getByText("18 of 19 required features found · 3 of 3 combined checks met") ).toBeVisible(); await expect( results.getByText("No declared surface requires this control.").first() @@ -500,7 +504,7 @@ test("reduces a multi-surface evidence bundle without exposing raw inputs", asyn "captured 2026-07-20T09:05:00.000Z by example-ci (application_ci)" ); await expect(results.locator("#bundle-source")).toContainText( - "analyser 5.0.0 · catalogue 2.2.0 · BCD 8.0.8" + "analyser 5.1.0 · catalogue 2.2.0 · BCD 8.1.4" ); await expect( results.getByText("Supplied page list · Reviewed application route manifest") @@ -673,7 +677,9 @@ test("does not detect the actual browser or expose a runtime connection surface" expect(source).not.toContain("userAgentData"); }); -test("publishes a restrictive meta policy and refuses embedded interaction", async ({ page }) => { +test("publishes a restrictive meta policy and refuses embedded interaction @workflow", async ({ + page +}) => { await page.goto("/assess/"); const policy = await page .locator('meta[http-equiv="Content-Security-Policy"]') @@ -685,13 +691,14 @@ test("publishes a restrictive meta policy and refuses embedded interaction", asy expect(policy).toContain("worker-src 'none'"); expect(policy).not.toContain("frame-ancestors"); - await page.route("http://127.0.0.1:4389/__frame-test.html", async (route) => { + const fixtureUrl = new URL("/__frame-test.html", page.url()).href; + await page.route(fixtureUrl, async (route) => { await route.fulfill({ body: '', contentType: "text/html" }); }); - await page.goto("http://127.0.0.1:4389/__frame-test.html"); + await page.goto(fixtureUrl); const embedded = page.frameLocator('iframe[title="Embedded ControlCurrent"]'); await expect(embedded.getByRole("alert")).toContainText("Open ControlCurrent directly"); await expect(embedded.getByLabel("HTTP response headers")).toBeHidden(); diff --git a/eslint.config.js b/eslint.config.js index a544cbf..3823dc1 100644 --- a/eslint.config.js +++ b/eslint.config.js @@ -8,6 +8,7 @@ export default tseslint.config( "coverage/**", "dist/**", "node_modules/**", + "tools/npm-toolchain/node_modules/**", "playwright-report/**", "test-results/**" ] diff --git a/examples/evidence-policy.json b/examples/evidence-policy.json index 69fc3f6..5089ca6 100644 --- a/examples/evidence-policy.json +++ b/examples/evidence-policy.json @@ -1,9 +1,9 @@ { "schemaVersion": 4, "name": "Release evidence baseline", - "expectedAnalyserVersion": "5.0.0", + "expectedAnalyserVersion": "5.1.0", "expectedCatalogueVersion": "2.2.0", - "expectedBcdVersion": "8.0.8", + "expectedBcdVersion": "8.1.4", "attestation": { "required": false, "certificateIssuer": "https://token.actions.githubusercontent.com/", diff --git a/package-lock.json b/package-lock.json index a1c40d1..b2eeddf 100644 --- a/package-lock.json +++ b/package-lock.json @@ -9,48 +9,62 @@ "version": "0.1.0", "license": "MIT", "dependencies": { - "@mdn/browser-compat-data": "8.0.8", + "@mdn/browser-compat-data": "8.1.4", "@sigstore/bundle": "5.0.0", - "@sigstore/protobuf-specs": "0.5.1", + "@sigstore/protobuf-specs": "0.5.2", "@sigstore/tuf": "5.0.0", - "@sigstore/verify": "4.1.0", + "@sigstore/verify": "4.1.2", "parse5": "8.0.1", - "web-features": "3.34.2", - "zod": "4.4.3" + "web-features": "3.40.1", + "zod": "4.6.5" }, "devDependencies": { - "@astrojs/check": "0.9.9", - "@astrojs/sitemap": "3.7.3", - "@axe-core/playwright": "4.12.1", + "@astrojs/check": "0.9.10", + "@astrojs/sitemap": "3.7.4", + "@axe-core/playwright": "4.13.0", "@eslint/js": "10.0.1", - "@playwright/test": "1.62.0", - "@types/node": "24.13.3", - "@vitest/coverage-v8": "4.1.10", - "astro": "7.1.3", - "eslint": "10.8.0", - "prettier": "3.9.6", - "prettier-plugin-astro": "0.14.1", - "tsx": "4.23.1", + "@playwright/test": "1.63.0", + "@types/node": "24.19.1", + "@vitest/coverage-v8": "5.0.3", + "astro": "7.3.6", + "eslint": "10.12.0", + "prettier": "3.9.9", + "prettier-plugin-astro": "1.1.0", + "tsx": "4.23.15", "typescript": "6.0.3", - "typescript-eslint": "8.65.0", - "vitest": "4.1.10" + "typescript-eslint": "8.71.1", + "vitest": "5.0.3" }, "engines": { "node": "^24.15.0 || >=26.0.0", - "npm": ">=11.17.0 <13" + "npm": "12.2.0" + } + }, + "node_modules/@astrojs/astro2tsx": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/@astrojs/astro2tsx/-/astro2tsx-0.1.2.tgz", + "integrity": "sha512-Uj/M9zbrhu5cIZEvWAGTbQJRKSxXWJ/E59BZwt7F+chrKhbfttW+9rkS/l+1QxoJP1KU3UnpM62M7yszfAI0WA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@emnapi/core": "1.11.3", + "@napi-rs/wasm-runtime": "1.2.4" + }, + "engines": { + "node": "^20.19.0 || >=22.12.0" } }, "node_modules/@astrojs/check": { - "version": "0.9.9", - "resolved": "https://registry.npmjs.org/@astrojs/check/-/check-0.9.9.tgz", - "integrity": "sha512-A5UW8uIuErLWEoRQvzgXpO1gTjUFtK8r7nU2Z7GewAMxUb7bPvpk11qaKKgxqXlHJWlAvaaxy+Xg28A6bmQ1Tg==", + "version": "0.9.10", + "resolved": "https://registry.npmjs.org/@astrojs/check/-/check-0.9.10.tgz", + "integrity": "sha512-zgx/UQMozdjOa3bOxjgeCFdtpE3c9rRX6xHwa+2QXvy8z8Akifu2AtubHyv/zzC2znO8dl8fFWL4K+Ba9kS8HQ==", "dev": true, "license": "MIT", "dependencies": { "@astrojs/language-server": "^2.16.7", "chokidar": "^4.0.3", "kleur": "^4.1.5", - "yargs": "^17.7.2" + "yargs": "^18.0.0" }, "bin": { "astro-check": "bin/astro-check.js" @@ -59,38 +73,49 @@ "typescript": "^5.0.0 || ^6.0.0" } }, - "node_modules/@astrojs/compiler": { - "version": "2.13.1", - "resolved": "https://registry.npmjs.org/@astrojs/compiler/-/compiler-2.13.1.tgz", - "integrity": "sha512-f3FN83d2G/v32ipNClRKgYv30onQlMZX1vCeZMjPsMMPl1mDpmbl0+N5BYo4S/ofzqJyS5hvwacEo0CCVDn/Qg==", - "dev": true, - "license": "MIT" - }, "node_modules/@astrojs/compiler-binding": { - "version": "0.3.1", - "resolved": "https://registry.npmjs.org/@astrojs/compiler-binding/-/compiler-binding-0.3.1.tgz", - "integrity": "sha512-DaAUj29AIBU2XdJ8uwcab8lW5O2pk9pY8AXkcMw0sw77nVa3oeTYRcO+Dvbbpoexf6ThMc0FMWYCQ/wN1/T7oQ==", + "version": "0.5.1", + "resolved": "https://registry.npmjs.org/@astrojs/compiler-binding/-/compiler-binding-0.5.1.tgz", + "integrity": "sha512-oczyolLUl9mNrtuBuNjuvn5thpHrFLXAHAWGTRg0JDHQ8cGVsVeFekOu2uSoQGgainJIi+A3/9m0DyYwz3Nlnw==", "dev": true, "license": "MIT", "engines": { "node": "^20.19.0 || >=22.12.0" }, "optionalDependencies": { - "@astrojs/compiler-binding-darwin-arm64": "0.3.1", - "@astrojs/compiler-binding-darwin-x64": "0.3.1", - "@astrojs/compiler-binding-linux-arm64-gnu": "0.3.1", - "@astrojs/compiler-binding-linux-arm64-musl": "0.3.1", - "@astrojs/compiler-binding-linux-x64-gnu": "0.3.1", - "@astrojs/compiler-binding-linux-x64-musl": "0.3.1", - "@astrojs/compiler-binding-wasm32-wasi": "0.3.1", - "@astrojs/compiler-binding-win32-arm64-msvc": "0.3.1", - "@astrojs/compiler-binding-win32-x64-msvc": "0.3.1" + "@astrojs/compiler-binding-android-arm64": "0.5.1", + "@astrojs/compiler-binding-darwin-arm64": "0.5.1", + "@astrojs/compiler-binding-darwin-x64": "0.5.1", + "@astrojs/compiler-binding-linux-arm64-gnu": "0.5.1", + "@astrojs/compiler-binding-linux-arm64-musl": "0.5.1", + "@astrojs/compiler-binding-linux-x64-gnu": "0.5.1", + "@astrojs/compiler-binding-linux-x64-musl": "0.5.1", + "@astrojs/compiler-binding-wasm32-wasi": "0.5.1", + "@astrojs/compiler-binding-win32-arm64-msvc": "0.5.1", + "@astrojs/compiler-binding-win32-x64-msvc": "0.5.1" + } + }, + "node_modules/@astrojs/compiler-binding-android-arm64": { + "version": "0.5.1", + "resolved": "https://registry.npmjs.org/@astrojs/compiler-binding-android-arm64/-/compiler-binding-android-arm64-0.5.1.tgz", + "integrity": "sha512-nMb2nMIJtcWLNH+fV75Enmi+jp4tIOYOfsv4XtpgdOWkqc9P4uSSdK5u1xb340AzrXo5V18SxLl/nc3vcqtamQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" } }, "node_modules/@astrojs/compiler-binding-darwin-arm64": { - "version": "0.3.1", - "resolved": "https://registry.npmjs.org/@astrojs/compiler-binding-darwin-arm64/-/compiler-binding-darwin-arm64-0.3.1.tgz", - "integrity": "sha512-IEmEF2fUIlTHtpeE/isyEGVOB14cEyh/LZOFYt6wn3jNyVpdC8aR5OZ+RzFUR/f+8ZDM1LaMwZKvoA7eMyJeFw==", + "version": "0.5.1", + "resolved": "https://registry.npmjs.org/@astrojs/compiler-binding-darwin-arm64/-/compiler-binding-darwin-arm64-0.5.1.tgz", + "integrity": "sha512-5k4+nZ/WRt+dcVow4z7rBuI7iv9A58h/uQ91YJe1PrTivbcCkq3u2Ynx/AZJwII4CsZawBCeGpojkFjutZBhBQ==", "cpu": [ "arm64" ], @@ -105,9 +130,9 @@ } }, "node_modules/@astrojs/compiler-binding-darwin-x64": { - "version": "0.3.1", - "resolved": "https://registry.npmjs.org/@astrojs/compiler-binding-darwin-x64/-/compiler-binding-darwin-x64-0.3.1.tgz", - "integrity": "sha512-GF2kIxjpPDLsn94zbZNMsxEmkU828QqnmM7kiQJnaooS3jmI+I7kk6+oI6EpwOsK3femCMdcm+wmOsEqtGrmjQ==", + "version": "0.5.1", + "resolved": "https://registry.npmjs.org/@astrojs/compiler-binding-darwin-x64/-/compiler-binding-darwin-x64-0.5.1.tgz", + "integrity": "sha512-0Buw+YST9Ff2EqQyhRMQujuFq/dijLw3zXWhsvI0dJ2pGrT38iVoxTEca2eBX/PfhlwkVWSRJEKO5gMqKHyeHg==", "cpu": [ "x64" ], @@ -122,9 +147,9 @@ } }, "node_modules/@astrojs/compiler-binding-linux-arm64-gnu": { - "version": "0.3.1", - "resolved": "https://registry.npmjs.org/@astrojs/compiler-binding-linux-arm64-gnu/-/compiler-binding-linux-arm64-gnu-0.3.1.tgz", - "integrity": "sha512-XJL3SDmOtVrqFhCirNcHwE91+IesJqlgNo23I4qW9QUYfwzm/TBZuH61fgqsb1ttgR1mMYz6ooPWs0JDhwMqpQ==", + "version": "0.5.1", + "resolved": "https://registry.npmjs.org/@astrojs/compiler-binding-linux-arm64-gnu/-/compiler-binding-linux-arm64-gnu-0.5.1.tgz", + "integrity": "sha512-x5LRpyCoMKuu3INr18cn42YhwSOaRpp9b5Ny3eJJ/sWVeejC16Zeshu1JlvlSmEZACLeWxU5JM0RX6T6nI+YyA==", "cpu": [ "arm64" ], @@ -142,9 +167,9 @@ } }, "node_modules/@astrojs/compiler-binding-linux-arm64-musl": { - "version": "0.3.1", - "resolved": "https://registry.npmjs.org/@astrojs/compiler-binding-linux-arm64-musl/-/compiler-binding-linux-arm64-musl-0.3.1.tgz", - "integrity": "sha512-xqE8BVbDoBueK/B47w30PtkVofUWJKGkwoMVE+EOMLf11rnoANxIAdA9FPqY+rng4oNI5ndHGsri1yPj2k8vZQ==", + "version": "0.5.1", + "resolved": "https://registry.npmjs.org/@astrojs/compiler-binding-linux-arm64-musl/-/compiler-binding-linux-arm64-musl-0.5.1.tgz", + "integrity": "sha512-mL7tQEuDk3rGfaKmrO63nw6WBy1TPVioQGmVyjcAr+C+a/k3SVMYBytNSMqH9mZPT/Swj30JaZ2N842Z1NnOEQ==", "cpu": [ "arm64" ], @@ -162,9 +187,9 @@ } }, "node_modules/@astrojs/compiler-binding-linux-x64-gnu": { - "version": "0.3.1", - "resolved": "https://registry.npmjs.org/@astrojs/compiler-binding-linux-x64-gnu/-/compiler-binding-linux-x64-gnu-0.3.1.tgz", - "integrity": "sha512-1y0StU1qiCuDFH3rmbRJXcxdfHxFPrES1Rd+RLffosvUR7I2cH5SF5SFnBN9vXpzpkmyElZm3Yr47iJBPN7vVA==", + "version": "0.5.1", + "resolved": "https://registry.npmjs.org/@astrojs/compiler-binding-linux-x64-gnu/-/compiler-binding-linux-x64-gnu-0.5.1.tgz", + "integrity": "sha512-uLGc9jtxwiDe4cQyhNPQim4ECiB/YzbWlXssfLAv8r374kArfTwBHjwR2+j+XVyF71yCx5mF9YNRclRqdNBgeg==", "cpu": [ "x64" ], @@ -182,9 +207,9 @@ } }, "node_modules/@astrojs/compiler-binding-linux-x64-musl": { - "version": "0.3.1", - "resolved": "https://registry.npmjs.org/@astrojs/compiler-binding-linux-x64-musl/-/compiler-binding-linux-x64-musl-0.3.1.tgz", - "integrity": "sha512-16q0fYf7kpbmdObZEeZJEup8hQv/whgNwVjrSvT8umrKwLDSnNIWiQpm09lQQu6bweZB0XyIvHwlPitvJhC+hg==", + "version": "0.5.1", + "resolved": "https://registry.npmjs.org/@astrojs/compiler-binding-linux-x64-musl/-/compiler-binding-linux-x64-musl-0.5.1.tgz", + "integrity": "sha512-G0cywinaQUc8v1MrytvYKUX7svTDMmYtOCZfxjwKPbJi59zIqM+Ll0rWgO0GQWLZH3XoPYo19ZwlP3Xt9ep9YA==", "cpu": [ "x64" ], @@ -202,9 +227,9 @@ } }, "node_modules/@astrojs/compiler-binding-wasm32-wasi": { - "version": "0.3.1", - "resolved": "https://registry.npmjs.org/@astrojs/compiler-binding-wasm32-wasi/-/compiler-binding-wasm32-wasi-0.3.1.tgz", - "integrity": "sha512-cB456shIwDv/PrVT+2QG7LFndpHkVge5HjqADKZgGaAc9JHVktCtjSrcdkRQ+3tbkPazNKaTLRjXLIiz2NIx9g==", + "version": "0.5.1", + "resolved": "https://registry.npmjs.org/@astrojs/compiler-binding-wasm32-wasi/-/compiler-binding-wasm32-wasi-0.5.1.tgz", + "integrity": "sha512-yMhLL8asmLydoAdnEZxAw6eLfNDs3YJl6jqn0pjPt6zrb2U5qIDLnii4/twThpIFODKkQ6YDpBRTOz/vSfZCxw==", "cpu": [ "wasm32" ], @@ -212,16 +237,18 @@ "license": "MIT", "optional": true, "dependencies": { - "@napi-rs/wasm-runtime": "^1.1.6" + "@emnapi/core": "1.11.3", + "@emnapi/runtime": "1.11.3", + "@napi-rs/wasm-runtime": "^1.2.4" }, "engines": { - "node": ">=14.0.0" + "node": "^20.19.0 || >=22.12.0" } }, "node_modules/@astrojs/compiler-binding-win32-arm64-msvc": { - "version": "0.3.1", - "resolved": "https://registry.npmjs.org/@astrojs/compiler-binding-win32-arm64-msvc/-/compiler-binding-win32-arm64-msvc-0.3.1.tgz", - "integrity": "sha512-ur/9+If/yTE69mmeX5MqSZndL0HOyx67GeNZUy3N7wVdWpLz9UTJXwyWS4UR2PUQHitghjsM5xoX0Ge56WRVQQ==", + "version": "0.5.1", + "resolved": "https://registry.npmjs.org/@astrojs/compiler-binding-win32-arm64-msvc/-/compiler-binding-win32-arm64-msvc-0.5.1.tgz", + "integrity": "sha512-aClIG6poFt3Wf/bZykrEAX2nAnKvBHW6RXiKUa69QjBtWH0/FOlOAjnFcxRNlhej2AMWNYFx0o+LGjwMcH8P7Q==", "cpu": [ "arm64" ], @@ -236,9 +263,9 @@ } }, "node_modules/@astrojs/compiler-binding-win32-x64-msvc": { - "version": "0.3.1", - "resolved": "https://registry.npmjs.org/@astrojs/compiler-binding-win32-x64-msvc/-/compiler-binding-win32-x64-msvc-0.3.1.tgz", - "integrity": "sha512-k0W+kDBzDkNZOqu4kElDvCOIbKw5Ut9S1WZ1Krj3KTgNuBERNKXsMMsRLLcbgfdMdbe7bTekQLshZrrvmYpmwA==", + "version": "0.5.1", + "resolved": "https://registry.npmjs.org/@astrojs/compiler-binding-win32-x64-msvc/-/compiler-binding-win32-x64-msvc-0.5.1.tgz", + "integrity": "sha512-/E6uBCagY70YpWqssBC+/FuniNSloeQPRgj7l3LDWiqjxIyTLnIgX1sTt18FU7jrigetpSnC9cHAM6b6IxSgPw==", "cpu": [ "x64" ], @@ -253,51 +280,50 @@ } }, "node_modules/@astrojs/compiler-rs": { - "version": "0.3.1", - "resolved": "https://registry.npmjs.org/@astrojs/compiler-rs/-/compiler-rs-0.3.1.tgz", - "integrity": "sha512-aT7xkgsbNoS6nriY5qKpbihK43slFHO41iqgHCTdOvn1ifaQxLCc5yXy+6GzAtiafoaC1zA7OwVXCXMsvUZOkg==", + "version": "0.5.1", + "resolved": "https://registry.npmjs.org/@astrojs/compiler-rs/-/compiler-rs-0.5.1.tgz", + "integrity": "sha512-1k1acnX7DepIiea9U9/Y+d1hdAFfylu1ZQQkkYgRSwBOBAsXInolyZuh/2tax+83vu/A+hOYP6P3+265RvMTvw==", "dev": true, "license": "MIT", "dependencies": { - "@astrojs/compiler-binding": "0.3.1" + "@astrojs/compiler-binding": "0.5.1" }, "engines": { "node": ">=22.12.0" } }, "node_modules/@astrojs/internal-helpers": { - "version": "0.10.1", - "resolved": "https://registry.npmjs.org/@astrojs/internal-helpers/-/internal-helpers-0.10.1.tgz", - "integrity": "sha512-5phcroT/vmOOrYuuAxtkbPixy5hePtlz9i8K4OeDv3dNK6/UQRuXPOSRTxIOBbUY5Sonw2UaxjbuVc43Mcir6Q==", + "version": "0.12.0", + "resolved": "https://registry.npmjs.org/@astrojs/internal-helpers/-/internal-helpers-0.12.0.tgz", + "integrity": "sha512-pKPuwCDtO0L7zgmt1JGd9X4Aes1+0SX3IEBSqBNPHsScYdPMlfmed3Y7DTbXyF7E+8ylnb563o/0OzGQPOFehw==", "dev": true, "license": "MIT", "dependencies": { "@types/hast": "^3.0.4", "@types/mdast": "^4.0.4", - "js-yaml": "^4.1.1", "picomatch": "^4.0.4", "retext-smartypants": "^6.2.0", "shiki": "^4.0.2", - "smol-toml": "^1.6.0", - "unified": "^11.0.5" + "smol-toml": "^1.8.0", + "unified": "^11.0.5", + "yaml": "^2.9.1" } }, "node_modules/@astrojs/language-server": { - "version": "2.16.13", - "resolved": "https://registry.npmjs.org/@astrojs/language-server/-/language-server-2.16.13.tgz", - "integrity": "sha512-ekOa+CYprEq5n4EJC1qTIAhLk49HZIUQuFwrEuF+3JK/pdMaYnWoREFUI2A0KEPOJiFA2kamBzKzbYljDvUxLg==", + "version": "2.17.1", + "resolved": "https://registry.npmjs.org/@astrojs/language-server/-/language-server-2.17.1.tgz", + "integrity": "sha512-gG7bvMVNIXgoSe1pM9dI1HsSDLU1EIc/dSAYQ0DuReLyLkOBjsiqvaRYgQltWaldLxh0bNEqjgreLfjd9OnUxQ==", "dev": true, "license": "MIT", "dependencies": { - "@astrojs/compiler": "^2.13.1", + "@astrojs/astro2tsx": "^0.1.0", "@astrojs/yaml2ts": "^0.2.4", - "@jridgewell/sourcemap-codec": "^1.5.5", "@volar/kit": "~2.4.28", "@volar/language-core": "~2.4.28", "@volar/language-server": "~2.4.28", "@volar/language-service": "~2.4.28", "muggle-string": "^0.4.1", - "tinyglobby": "^0.2.16", + "tinyglobby": "^0.2.17", "volar-service-css": "0.0.71", "volar-service-emmet": "0.0.71", "volar-service-html": "0.0.71", @@ -306,7 +332,7 @@ "volar-service-typescript-twoslash-queries": "0.0.71", "volar-service-yaml": "0.0.71", "vscode-html-languageservice": "^5.6.2", - "vscode-uri": "^3.1.0" + "vscode-uri": "^3.2.0" }, "bin": { "astro-ls": "bin/nodeServer.js" @@ -325,17 +351,16 @@ } }, "node_modules/@astrojs/markdown-satteri": { - "version": "0.3.4", - "resolved": "https://registry.npmjs.org/@astrojs/markdown-satteri/-/markdown-satteri-0.3.4.tgz", - "integrity": "sha512-6Lvt/bQZEBW+zzdhPblvfZEy5PGEYJaUsUqaCgwHeRPxZJL1gc9I+DRLKWJjjYTWDzVUTzXlMq4WwSK+X34CVw==", + "version": "0.4.3", + "resolved": "https://registry.npmjs.org/@astrojs/markdown-satteri/-/markdown-satteri-0.4.3.tgz", + "integrity": "sha512-PFbEHPnwUlLvpXd7RXrrKM+j12akF4bG+DSuNuoN+3eiwjOwp4HaPi+QQdbkBV7QEYXmzyKca50OJsmGxhNIUA==", "dev": true, "license": "MIT", "dependencies": { - "@astrojs/internal-helpers": "0.10.1", + "@astrojs/internal-helpers": "0.12.0", "@astrojs/prism": "4.0.2", "github-slugger": "^2.0.0", - "hast-util-from-html": "^2.0.3", - "satteri": "^0.9.1" + "satteri": "^0.10.3" } }, "node_modules/@astrojs/prism": { @@ -352,14 +377,13 @@ } }, "node_modules/@astrojs/sitemap": { - "version": "3.7.3", - "resolved": "https://registry.npmjs.org/@astrojs/sitemap/-/sitemap-3.7.3.tgz", - "integrity": "sha512-f8euLVsyeAmAkSm/1M2Kb8sL8byQmfgbvBNaHFItCheTj/IpiJYSEWVcqDHZ/yEHxiS7+w87mQkzwZaPHmk5GA==", + "version": "3.7.4", + "resolved": "https://registry.npmjs.org/@astrojs/sitemap/-/sitemap-3.7.4.tgz", + "integrity": "sha512-LbKNC24bdUWcQf/pThB6qLlSqHojxGjZDURIzFocY8rlWnAn2t74nnhnK6S5x0NHriHoAduLEpVjRykmeGiVvA==", "dev": true, "license": "MIT", "dependencies": { "sitemap": "^9.0.0", - "stream-replace-string": "^2.0.0", "zod": "^4.3.6" } }, @@ -390,13 +414,13 @@ } }, "node_modules/@axe-core/playwright": { - "version": "4.12.1", - "resolved": "https://registry.npmjs.org/@axe-core/playwright/-/playwright-4.12.1.tgz", - "integrity": "sha512-rMd7xriptqKpP+w5265i4Hdkv2X5kbu6uiBi/B2I7uf3hieRBM3qDCfaKPtxfiYb2mKXfF+yLODJwIx+Jv1GDw==", + "version": "4.13.0", + "resolved": "https://registry.npmjs.org/@axe-core/playwright/-/playwright-4.13.0.tgz", + "integrity": "sha512-6YLx+kxXu5GJceG4ozFg+33a2EMTdjYwWGloJ3sb9Kta5pp+ZNS53uxGVog5JetIY8s++P5UrtX+cri+u0VAVg==", "dev": true, "license": "MPL-2.0", "dependencies": { - "axe-core": "~4.12.1" + "axe-core": "~4.13.0" }, "peerDependencies": { "playwright-core": ">= 1.0.0" @@ -423,13 +447,13 @@ } }, "node_modules/@babel/parser": { - "version": "7.29.7", - "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.29.7.tgz", - "integrity": "sha512-hnORnjP/1P/zFEndoeX+n+t1RwWRJiJpM/jO7FW32Kn9r5+sJB2JWOdYo4L6k78j15eCwY3Gm/7364B1EMwtNg==", + "version": "7.29.9", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.29.9.tgz", + "integrity": "sha512-CjXrNHTnvqBVqHgdBysY3vk2T8tpJHb5/RMeHJBTyVa9xgugCB0CJTx/3oO8RV2QRQP391RWpB7D6hLjm8V9uA==", "dev": true, "license": "MIT", "dependencies": { - "@babel/types": "^7.29.7" + "@babel/types": "^7.29.8" }, "bin": { "parser": "bin/babel-parser.js" @@ -439,9 +463,9 @@ } }, "node_modules/@babel/types": { - "version": "7.29.7", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.29.7.tgz", - "integrity": "sha512-4zBIxpPzowiZpusoFkyGVwakdRJUyuH5PxQ/PrqghfdFWWasvnCdPfQXHrenDai+gyLARulZjZowCOj6fjT4pA==", + "version": "7.29.8", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.29.8.tgz", + "integrity": "sha512-Vj1jF3cPfxg7OAfoI7QnVKLoILlm2JF9pnVHrX8qx7AHMiYWT+NDAA7jChlNgRS4WTLc/fD1lXLmPixluj+3Gg==", "dev": true, "license": "MIT", "dependencies": { @@ -463,9 +487,9 @@ } }, "node_modules/@bruits/satteri-darwin-arm64": { - "version": "0.9.5", - "resolved": "https://registry.npmjs.org/@bruits/satteri-darwin-arm64/-/satteri-darwin-arm64-0.9.5.tgz", - "integrity": "sha512-iw4nZgx9v30lWo/MTngQqi1pI78KI0DnkSm+lVJGYdmPLgAyDNJigVhpG42/Iq55A6c1Ll8q66ljyyRiQUxwow==", + "version": "0.10.5", + "resolved": "https://registry.npmjs.org/@bruits/satteri-darwin-arm64/-/satteri-darwin-arm64-0.10.5.tgz", + "integrity": "sha512-27KTVl4TJkVahMy/ohyA7qd4938G5UNneFUz/PsScYfpIhj0IVAS23mpcJXdPF44sa6nva198lmV/cKIb2YPyA==", "cpu": [ "arm64" ], @@ -477,9 +501,9 @@ ] }, "node_modules/@bruits/satteri-darwin-x64": { - "version": "0.9.5", - "resolved": "https://registry.npmjs.org/@bruits/satteri-darwin-x64/-/satteri-darwin-x64-0.9.5.tgz", - "integrity": "sha512-6T26Z5Kf3cFW2PSlk9p7zT7yVxvuBSiJvYyz9u8KjYwMTqZyIDOj2wDyNpxKV4+6yUVG7rddq2QwvG/8LJA2+Q==", + "version": "0.10.5", + "resolved": "https://registry.npmjs.org/@bruits/satteri-darwin-x64/-/satteri-darwin-x64-0.10.5.tgz", + "integrity": "sha512-IjnLe3nKspq6qaeqGgjT7MT8VrTV74yWRlaag7ZdNsI8TDAYZ0iPxMCo+9KQZHUk5EyVB+reBI/PFWL5KuFw9Q==", "cpu": [ "x64" ], @@ -491,9 +515,9 @@ ] }, "node_modules/@bruits/satteri-linux-arm64-gnu": { - "version": "0.9.5", - "resolved": "https://registry.npmjs.org/@bruits/satteri-linux-arm64-gnu/-/satteri-linux-arm64-gnu-0.9.5.tgz", - "integrity": "sha512-u51id17uJwNEMK9nBlICsq6U31c+XVqQueVBkwRIzZG+gMpS8TOJctt5h5Wz33Z8xnMdTd+adtACVz0yHgGuOA==", + "version": "0.10.5", + "resolved": "https://registry.npmjs.org/@bruits/satteri-linux-arm64-gnu/-/satteri-linux-arm64-gnu-0.10.5.tgz", + "integrity": "sha512-glkYXZCJywjP13v67eAyAMSJdF+ncvEbYvgi/wOtffL9tQ27lr/zsyzUfgs+ovjJ9d8JNQKiXeiArJcX8PJL9w==", "cpu": [ "arm64" ], @@ -508,9 +532,9 @@ ] }, "node_modules/@bruits/satteri-linux-arm64-musl": { - "version": "0.9.5", - "resolved": "https://registry.npmjs.org/@bruits/satteri-linux-arm64-musl/-/satteri-linux-arm64-musl-0.9.5.tgz", - "integrity": "sha512-v39HxiwGC5Rqm01HksP6+5Y+xKLPlsuVFgIgpEAo+SiQ22c+mJVhS3u7Z6ePAKdhL5NJoK1xq70kLz3L13AhpQ==", + "version": "0.10.5", + "resolved": "https://registry.npmjs.org/@bruits/satteri-linux-arm64-musl/-/satteri-linux-arm64-musl-0.10.5.tgz", + "integrity": "sha512-yWdgG1g17Nh2QyGVlFUxGRa3FEFwiMcpZEyMNWkbM3deC94cmVc+/i9OuyFpdKuWo3GkgoCtYVOoxk1uCnCZIA==", "cpu": [ "arm64" ], @@ -525,9 +549,9 @@ ] }, "node_modules/@bruits/satteri-linux-x64-gnu": { - "version": "0.9.5", - "resolved": "https://registry.npmjs.org/@bruits/satteri-linux-x64-gnu/-/satteri-linux-x64-gnu-0.9.5.tgz", - "integrity": "sha512-F3uO8uFp3pAP5ZGXttwvh57GS7s0lL953tnNdyI2gRyP4kOOkp6pyGojNJzCjkDvWI2Cvb9iNrKok3aqQPauAw==", + "version": "0.10.5", + "resolved": "https://registry.npmjs.org/@bruits/satteri-linux-x64-gnu/-/satteri-linux-x64-gnu-0.10.5.tgz", + "integrity": "sha512-FVaLoPT1fBgGl0J+AYebyyXJYBachGl8Oyyrf1lye4RTqCB4S0Gwkj1uM9RJyThUOvx5VUmAT1CnNh1SFHA+kw==", "cpu": [ "x64" ], @@ -542,9 +566,9 @@ ] }, "node_modules/@bruits/satteri-linux-x64-musl": { - "version": "0.9.5", - "resolved": "https://registry.npmjs.org/@bruits/satteri-linux-x64-musl/-/satteri-linux-x64-musl-0.9.5.tgz", - "integrity": "sha512-bicEqglLlz++mWyADaZoP0JY20s4vDfLjaPYgQqC+NI4zZLTOOg1T4GB8aqtc822Pqji8SQBmSrTb7CrP8i08Q==", + "version": "0.10.5", + "resolved": "https://registry.npmjs.org/@bruits/satteri-linux-x64-musl/-/satteri-linux-x64-musl-0.10.5.tgz", + "integrity": "sha512-EHpVAx2bqW3GINHTKkljtxVfQmVDGWIuwOYOP5YghTj+0PkBa2o8oKPRtQ9Kbsr1Fye8jtUcDjhwj2jMNugZKg==", "cpu": [ "x64" ], @@ -559,9 +583,9 @@ ] }, "node_modules/@bruits/satteri-wasm32-wasi": { - "version": "0.9.5", - "resolved": "https://registry.npmjs.org/@bruits/satteri-wasm32-wasi/-/satteri-wasm32-wasi-0.9.5.tgz", - "integrity": "sha512-zauAuMwfPnKPUkd4AFixRFpXdgKwP2mKgxrIIo2gJzW0/ZneF9dbHnLkojSpaBnCCp7VUL1hIi5WWZvB1CqmAQ==", + "version": "0.10.5", + "resolved": "https://registry.npmjs.org/@bruits/satteri-wasm32-wasi/-/satteri-wasm32-wasi-0.10.5.tgz", + "integrity": "sha512-ypz8c/Zmipxp4IoeDa228Gstv6TLzVmNs3yC6wKCoNSOjx1iwpgzu87Y3hTkXFdwChVGU85qeUDuOIarGUZQLw==", "cpu": [ "wasm32" ], @@ -571,7 +595,7 @@ "dependencies": { "@emnapi/core": "1.11.1", "@emnapi/runtime": "1.11.1", - "@napi-rs/wasm-runtime": "^1.1.6" + "@napi-rs/wasm-runtime": "^1.2.3" }, "engines": { "node": ">=14.0.0" @@ -600,10 +624,21 @@ "tslib": "^2.4.0" } }, + "node_modules/@bruits/satteri-wasm32-wasi/node_modules/@emnapi/wasi-threads": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/@emnapi/wasi-threads/-/wasi-threads-1.2.2.tgz", + "integrity": "sha512-c95qOXkHdydNKhscBTebqEC1CVAZpyqOfVfBzQ1qgzyl3gfeldUjIggDbIZgDKsHLgnsM+igH7TJ/eAasaVuMA==", + "dev": true, + "license": "MIT", + "optional": true, + "dependencies": { + "tslib": "^2.4.0" + } + }, "node_modules/@bruits/satteri-win32-arm64-msvc": { - "version": "0.9.5", - "resolved": "https://registry.npmjs.org/@bruits/satteri-win32-arm64-msvc/-/satteri-win32-arm64-msvc-0.9.5.tgz", - "integrity": "sha512-SrfE7NEsgZjBvU3c+RR6oQRu0ToXY5uVJEbieXEF0YTctIV2zAVlbaMjWLts074QCgh3a+XHWkR/lWh2VH2LUg==", + "version": "0.10.5", + "resolved": "https://registry.npmjs.org/@bruits/satteri-win32-arm64-msvc/-/satteri-win32-arm64-msvc-0.10.5.tgz", + "integrity": "sha512-siTV88nb0LRqNpkL2gXboqCwVdq95sLtzMHS1/3eONV2gLbB3NAK46wmSMvCO/yquBvI2lvaFIfd8P12ecsxBw==", "cpu": [ "arm64" ], @@ -615,9 +650,9 @@ ] }, "node_modules/@bruits/satteri-win32-x64-msvc": { - "version": "0.9.5", - "resolved": "https://registry.npmjs.org/@bruits/satteri-win32-x64-msvc/-/satteri-win32-x64-msvc-0.9.5.tgz", - "integrity": "sha512-5Kw9ZAtTGS8WHizyn+CJhjjfIQrw+7jcZodpmpXJjefnO15M8UexIi6JR2E5thyvsmHyhL6ZDDMUNR4bKJPd4g==", + "version": "0.10.5", + "resolved": "https://registry.npmjs.org/@bruits/satteri-win32-x64-msvc/-/satteri-win32-x64-msvc-0.10.5.tgz", + "integrity": "sha512-C3IfPvfvMXmlzBxaMPKFS1XiuV9pu2mC7YqkPk7PSvTgPZ8gbdASIpHpztDLvTTQjqZ0z1Ol8tK5X+V6XXC0wQ==", "cpu": [ "x64" ], @@ -628,6 +663,30 @@ "win32" ] }, + "node_modules/@cacheable/memory": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/@cacheable/memory/-/memory-2.2.0.tgz", + "integrity": "sha512-CTLKqLItRCEixEAewD3/j9DB3/o96gpTPD4eJ1v+DGOlxZRZncRQkGYqqnAGCscYd6RNeXfGeiuCphsPtqyIfQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@cacheable/utils": "^2.5.0", + "@keyv/bigmap": "^1.3.1", + "hookified": "^1.15.1", + "keyv": "^5.6.0" + } + }, + "node_modules/@cacheable/utils": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/@cacheable/utils/-/utils-2.5.0.tgz", + "integrity": "sha512-buipgOVDkkPXNR5+xBpDw7Zk2n1EvU7qBJCNUcL7rhQ//kfpOXPAvQ511Os0vpLYJ1pZnvudNytkQt2hst3wqA==", + "dev": true, + "license": "MIT", + "dependencies": { + "hashery": "^1.5.1", + "keyv": "^5.6.0" + } + }, "node_modules/@capsizecss/unpack": { "version": "4.0.1", "resolved": "https://registry.npmjs.org/@capsizecss/unpack/-/unpack-4.0.1.tgz", @@ -642,9 +701,9 @@ } }, "node_modules/@clack/core": { - "version": "1.4.3", - "resolved": "https://registry.npmjs.org/@clack/core/-/core-1.4.3.tgz", - "integrity": "sha512-/kr3UWNtdJfxZtPgDqUOmG2pvwlmcLGheex5yiZKdwbzZJxhV+HMNR9QNmyY5cGwTNV6LrR7Jtp+KjhUAP1qBQ==", + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/@clack/core/-/core-1.5.1.tgz", + "integrity": "sha512-iHTrHA8MtVuLl2TfZySmcKv1qO2PoyC9Z7pfSDozEuV5vtY3/wcOPKJXlqJ5Oq2Cx5DDGQGAMVx6HZfRRoVEbQ==", "dev": true, "license": "MIT", "dependencies": { @@ -656,13 +715,13 @@ } }, "node_modules/@clack/prompts": { - "version": "1.7.0", - "resolved": "https://registry.npmjs.org/@clack/prompts/-/prompts-1.7.0.tgz", - "integrity": "sha512-y7/yvZ2TPAnR9+jnc00klvNNLkJiXFFrQA/hlLCcxA9a2A4zQIOimyFQ9XfwYKiGD1fb5GY8vbKIIgO8d5Tb2A==", + "version": "1.8.1", + "resolved": "https://registry.npmjs.org/@clack/prompts/-/prompts-1.8.1.tgz", + "integrity": "sha512-dlT1m5e/0yUL0kRNcQn7yGLVThkgbB0Ga/1AmfDDC/8ik6AIiSf2QLQO2zPYvefsHP0aFgxO93cVLCCfDp7kzQ==", "dev": true, "license": "MIT", "dependencies": { - "@clack/core": "1.4.3", + "@clack/core": "1.5.1", "fast-string-width": "^3.0.2", "fast-wrap-ansi": "^0.2.0", "sisteransi": "^1.0.5" @@ -734,44 +793,40 @@ "license": "MIT" }, "node_modules/@emnapi/core": { - "version": "1.11.2", - "resolved": "https://registry.npmjs.org/@emnapi/core/-/core-1.11.2.tgz", - "integrity": "sha512-TC8MkTuZUtcTSiFeuC0ksCh9QIJ5+F21MvZ4Wn4ORfYaFJ/0dsiudv5tVkejgwZlwQ39jL9WWDe2lz8x0WglOA==", + "version": "1.11.3", + "resolved": "https://registry.npmjs.org/@emnapi/core/-/core-1.11.3.tgz", + "integrity": "sha512-zLpS5asjEb7lq8jYLq37N6XKaE41DIexlY1rF/z4/tIl3wo13Sqm28fRyfIsKZD+NZ8mM5RoKkpW/rBcuoSZSg==", "dev": true, "license": "MIT", - "optional": true, - "peer": true, "dependencies": { - "@emnapi/wasi-threads": "1.2.2", + "@emnapi/wasi-threads": "1.2.3", "tslib": "^2.4.0" } }, "node_modules/@emnapi/runtime": { - "version": "1.11.2", - "resolved": "https://registry.npmjs.org/@emnapi/runtime/-/runtime-1.11.2.tgz", - "integrity": "sha512-kyOl3X0DuTiT1h2ft8r2fYO8JYtU9a9Xis/zBSiGArNaagCOWx90N1k2wxp18czFDH+OgcWGb5ZP/XMt3dcyPA==", + "version": "1.11.3", + "resolved": "https://registry.npmjs.org/@emnapi/runtime/-/runtime-1.11.3.tgz", + "integrity": "sha512-Xz4Tpyki7XyrpbUK1jR1AhdAdaXyhhY4lZ3neLodmhpuWfy2PAQN5B46sAiU4liOXGLkHypn/qU+jvfWSCYYLA==", "dev": true, "license": "MIT", - "optional": true, "dependencies": { "tslib": "^2.4.0" } }, "node_modules/@emnapi/wasi-threads": { - "version": "1.2.2", - "resolved": "https://registry.npmjs.org/@emnapi/wasi-threads/-/wasi-threads-1.2.2.tgz", - "integrity": "sha512-c95qOXkHdydNKhscBTebqEC1CVAZpyqOfVfBzQ1qgzyl3gfeldUjIggDbIZgDKsHLgnsM+igH7TJ/eAasaVuMA==", + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/@emnapi/wasi-threads/-/wasi-threads-1.2.3.tgz", + "integrity": "sha512-ELEBe8PsLvvJ6QMr0zLt8ffvOHW/dc1m3CEzNMg7aJUv3bMaoDtw2TXyDAwkYBuroxxuHEwhRTLJSe5sya547g==", "dev": true, "license": "MIT", - "optional": true, "dependencies": { "tslib": "^2.4.0" } }, "node_modules/@esbuild/aix-ppc64": { - "version": "0.28.1", - "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.28.1.tgz", - "integrity": "sha512-Svl7tq8k/08+p6CXPpRjQ1fKX+1odH/BQbb48fV6fj3CWHhsoIOoY87w1oHXm0qEpkIK3ZfVgp0hed3XBXzXMQ==", + "version": "0.28.2", + "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.28.2.tgz", + "integrity": "sha512-XExcO+dvLKvVtNTibSTBej1NCAbaGhWn9Ww1ZPx80qsahhPFe/8jgWP0IchNe0F3HwkU7n8ejhH8bjonqht8mQ==", "cpu": [ "ppc64" ], @@ -786,9 +841,9 @@ } }, "node_modules/@esbuild/android-arm": { - "version": "0.28.1", - "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.28.1.tgz", - "integrity": "sha512-0k2F129Xdio1TdJfzJ8sy1Q47vUD2NnwdhiAf7drUN1EBTfPf4hsFCtmMgu/6m8JSzsBrlmVjudMBQqOfG8usQ==", + "version": "0.28.2", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.28.2.tgz", + "integrity": "sha512-kXXoiPVVGQcnIYGOeaovwOURpniDBpSq4A03qkQ+BMQqtGG6HYap3xne9C1O1yo4TR3qxlCX5IqqmX6fFo2Lqg==", "cpu": [ "arm" ], @@ -803,9 +858,9 @@ } }, "node_modules/@esbuild/android-arm64": { - "version": "0.28.1", - "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.28.1.tgz", - "integrity": "sha512-34EGEbCIAgosYz6goLcopX6Mo7NyGv9tfwEM2/7Ce2VcVRk568iSvniGWcUXIy7wEDR1wzolcxcriFVrWYcwBg==", + "version": "0.28.2", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.28.2.tgz", + "integrity": "sha512-5YfKeeI8qWfBZIX+u2xZC3Zlb3Os/gLS2sbEKM+I4ZOcsWmHS2WLysCcQZDAFRslDUU5Oiq44gf6PYN1vGwG5A==", "cpu": [ "arm64" ], @@ -820,9 +875,9 @@ } }, "node_modules/@esbuild/android-x64": { - "version": "0.28.1", - "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.28.1.tgz", - "integrity": "sha512-dbwY7ltSMDWsRatcRpCnES4F+im88OCUgGZjy52shC7GqHRE/cYlxNbB4Z4UpJswpcc4Qxd2oE/ufM0p61IKng==", + "version": "0.28.2", + "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.28.2.tgz", + "integrity": "sha512-O387ite7SzUyCcy3JQX4P4bLtEA7bLLkx+esve5JHnyYfNTxcVpXZo9jhdB0lTKN44gztELTdU7nS8Nr16Fs1Q==", "cpu": [ "x64" ], @@ -837,9 +892,9 @@ } }, "node_modules/@esbuild/darwin-arm64": { - "version": "0.28.1", - "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.28.1.tgz", - "integrity": "sha512-TZbWkQY7kvTAXbXUT7uVACR5cMHsDiSz9z7ZKAX/RTq/WJEk3QyRr0wZpNhBDX+/0CtdqUIJlOiodQcta6tY3Q==", + "version": "0.28.2", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.28.2.tgz", + "integrity": "sha512-n4KqkOQrraxHJcgjM1RvwbigfQKIKJVpM7xp+KsxiyUSrRdIXnt73VhrPAx0fV44hgfmIVKjxMN9J1t5jySVkw==", "cpu": [ "arm64" ], @@ -854,9 +909,9 @@ } }, "node_modules/@esbuild/darwin-x64": { - "version": "0.28.1", - "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.28.1.tgz", - "integrity": "sha512-zfdzgK9ACBNZLI/CyHTOx81SyNbM6YXn7rxSgX97VjyiPl9W1i4Ka4fgKECEoFCKGpvBj5qArWIGgQjOwkgskQ==", + "version": "0.28.2", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.28.2.tgz", + "integrity": "sha512-uq6suIWYP37qzGddBKPw5QEQPi6HiLGsO7UmkpfyaYNQ3D+rN6w6WfwH+nuqcGXWvawGwxOEroO4YGnFh95azw==", "cpu": [ "x64" ], @@ -871,9 +926,9 @@ } }, "node_modules/@esbuild/freebsd-arm64": { - "version": "0.28.1", - "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.28.1.tgz", - "integrity": "sha512-wG2EA8ENdEI0qhkSZMjfqrdY+ziCYCPMmtZjjIwOmXFjmyzEHn+UUxk5of+SYsjtfs3VpnlC7QLzSI5hY/rOAw==", + "version": "0.28.2", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.28.2.tgz", + "integrity": "sha512-n+I0BTSRIoy+d6RPKnEVwql5UwBJolytvY4mAOIEJorKlqgPII8ix6slVVrfZ5Tnj7glIZvloylbB/EJPMWEXw==", "cpu": [ "arm64" ], @@ -888,9 +943,9 @@ } }, "node_modules/@esbuild/freebsd-x64": { - "version": "0.28.1", - "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.28.1.tgz", - "integrity": "sha512-i7dZ9vQgnvSCzi/rYCXNgtF/U+eKZNJBzu3eTQbRgHnM7tNSizLOkRFAl3qzVc/Op/u5YkHHa4pf/3DOYHthLQ==", + "version": "0.28.2", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.28.2.tgz", + "integrity": "sha512-78XJTJkvPs0kz2w61301PJjXl4g7q3JqiYMZ/M/yVI73EHBrCRTgkhu9oqG7vPqq+a/yadEW8aD+agKlk5xrmg==", "cpu": [ "x64" ], @@ -905,9 +960,9 @@ } }, "node_modules/@esbuild/linux-arm": { - "version": "0.28.1", - "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.28.1.tgz", - "integrity": "sha512-qVXBOHQS+d5Y722GwJzJUtOLlX7km3CraOaGormF1pDtPd2C/l1SHRPgjLunLGe51Sh5YYWKMFDyV4SxgMQYTQ==", + "version": "0.28.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.28.2.tgz", + "integrity": "sha512-XlDnu2q5yoqems+xay6wSAcg9DDD7K9RLKZEBOMZm3ckNpJBvOX20tSfby8KfrrhINDyv9V2YVZKY/SpoGJI8w==", "cpu": [ "arm" ], @@ -922,9 +977,9 @@ } }, "node_modules/@esbuild/linux-arm64": { - "version": "0.28.1", - "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.28.1.tgz", - "integrity": "sha512-yHs+0uc8+nvEAfAfxrWQKK5peSNzBc4PegcMO0EJ2hT71uA7vB8Ihg2e77R2P7SG5uYjPbHlLLmve4LLLRCf0g==", + "version": "0.28.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.28.2.tgz", + "integrity": "sha512-pW4AC0P3it8c7do9MVM4p51FzHzdM/TZrerurgRcHJ2WTa1VQ1CIq18xncfpBJw4ojkiZZrKW2yIBWBP92j6Ug==", "cpu": [ "arm64" ], @@ -939,9 +994,9 @@ } }, "node_modules/@esbuild/linux-ia32": { - "version": "0.28.1", - "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.28.1.tgz", - "integrity": "sha512-d1z4ZuP0ajrfz/FhGT4vv278rX8KnPPJx8i5+AtK7TYbx9Le9F1hyzurZpkEyjkGa9dUGhQow4C1NmeGvqxN2w==", + "version": "0.28.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.28.2.tgz", + "integrity": "sha512-CYbnj78HsIeA+DhgUKgFCfvNsTHFhMMrinUrMZpDXJXKN8T3XViTZ/+wtHeVxEWY8ewSzTFN+nRmSwO2tZaLUQ==", "cpu": [ "ia32" ], @@ -956,9 +1011,9 @@ } }, "node_modules/@esbuild/linux-loong64": { - "version": "0.28.1", - "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.28.1.tgz", - "integrity": "sha512-M5sRjUVZrkm1OAPR3dlOYzNmN+loZKGVi1VUQGrwuqLcbR6qeAz+famMhjASeH3YVKvZz+zT1jlh/keC3Rj/lg==", + "version": "0.28.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.28.2.tgz", + "integrity": "sha512-buwkd8nsph4R+ajRvw0qM5Hja/TXQow3ptzWO2EbG/cqcIkHloRrdlBtQlshyYGTNFvfkfJ5tpPLVkY4DtsPfQ==", "cpu": [ "loong64" ], @@ -973,9 +1028,9 @@ } }, "node_modules/@esbuild/linux-mips64el": { - "version": "0.28.1", - "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.28.1.tgz", - "integrity": "sha512-mRObBZeHh2OxcBFPWE/FjylkRgZdYuiTR3vaTozquCGOH14iP9oN4x4Ge81CoIDYQrXmIxpFumJBu5MtZpnQJQ==", + "version": "0.28.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.28.2.tgz", + "integrity": "sha512-ZVykbDyk7519VwiNb9Lcj9m8XM6v5V9uKPvrEMkkEedVewf+0itkhahp4HDpgERXhwLRpWFypsGbG/J8s0QjJA==", "cpu": [ "mips64el" ], @@ -990,9 +1045,9 @@ } }, "node_modules/@esbuild/linux-ppc64": { - "version": "0.28.1", - "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.28.1.tgz", - "integrity": "sha512-slScBsMAb3GFDcdrCgLwZtPYRoH2H/youv10QiZyRjmsP48fznoveWytSgCI/R0ZcUgpc0ZhIUEx6LHts8yrfQ==", + "version": "0.28.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.28.2.tgz", + "integrity": "sha512-CAXl+Dtd9UUuJd8pKKdwh6MLm3MUMiqMPmhZ3tTSXPqfyQ3vDl6R5hZdZ/kYojK4ofXtdfSv1tFq8XzWx3heNQ==", "cpu": [ "ppc64" ], @@ -1007,9 +1062,9 @@ } }, "node_modules/@esbuild/linux-riscv64": { - "version": "0.28.1", - "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.28.1.tgz", - "integrity": "sha512-kw0owk1o0GFETUJyW0jc0G4Yzs0BHZn0JDZ8JRT088vjJYX777BAs1fDGxAC+q831qOs2DTC96mNsG2opdfyyQ==", + "version": "0.28.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.28.2.tgz", + "integrity": "sha512-GeXCej4IQtU1B+QlDV8W/RRvbzI3O/Stss+/bCXv4lZls5WGRtu2a+3JkA3i4qIUlMXpcHebWpF8AkJhATowuA==", "cpu": [ "riscv64" ], @@ -1024,9 +1079,9 @@ } }, "node_modules/@esbuild/linux-s390x": { - "version": "0.28.1", - "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.28.1.tgz", - "integrity": "sha512-/lAIjX8aYFRByhh6L5rYtPEDRqa9de/4V/juOXcta5frjvzXO4/sqEtyytse0g3zZFuWu5cDN0MkLz2qRDD2Ag==", + "version": "0.28.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.28.2.tgz", + "integrity": "sha512-3H1weTYZPxt/WOhByszQZybS9w5lKzUn1FDMsgEChbHWQwHYQQRfBxgCcZvPhjHfKyJjIievvMmEUawJrdY9Dg==", "cpu": [ "s390x" ], @@ -1041,9 +1096,9 @@ } }, "node_modules/@esbuild/linux-x64": { - "version": "0.28.1", - "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.28.1.tgz", - "integrity": "sha512-u/anNYF2mmVOEDwLtnQ1wOr3EZ9sTNGLWrsYGYwHWzGA3Si84IOkHXlbWTD1NB+9/1lcnweYKO54uhxZydNzfA==", + "version": "0.28.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.28.2.tgz", + "integrity": "sha512-4xTZr1FUmSoQW4XIWmit3tzQrUTZM+N3P0XV8xROKYF50XfI7xeO90+1bZvNwxIufQ9hDQVRJH5YhgPVF8A/HQ==", "cpu": [ "x64" ], @@ -1058,9 +1113,9 @@ } }, "node_modules/@esbuild/netbsd-arm64": { - "version": "0.28.1", - "resolved": "https://registry.npmjs.org/@esbuild/netbsd-arm64/-/netbsd-arm64-0.28.1.tgz", - "integrity": "sha512-oks0DYbLwWMmaakTsCb+zL4E+aHRVLom9IJZOAthMQEPiQmydXHkziYEsGYRx0uNV/IjEKGAV941JzH02pflqw==", + "version": "0.28.2", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-arm64/-/netbsd-arm64-0.28.2.tgz", + "integrity": "sha512-sSATRjPeDBg3pdgHoQfoYBob11Kk1FGa9lui5RIHZCoCkJa9QKlvl3/vKz2usCmYYjs7ymJR/2Nnsqe+Hjt5nw==", "cpu": [ "arm64" ], @@ -1075,9 +1130,9 @@ } }, "node_modules/@esbuild/netbsd-x64": { - "version": "0.28.1", - "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.28.1.tgz", - "integrity": "sha512-aeL6lAnN89Hz43Mlh1G8ARasbuoYvSITDEx0tHh5b7jJnHcssqgjy9Yx430GDpmCa6OyrKoS0aNRjKundRizGg==", + "version": "0.28.2", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.28.2.tgz", + "integrity": "sha512-lqnzCV+mM0gIADaKihiCg6ifgfU2L3h5E33rNQBN1Y4MaVGnzryzmvvf7UHxprpQdE8hpqLolJ9Rl+SkIRDpyw==", "cpu": [ "x64" ], @@ -1092,9 +1147,9 @@ } }, "node_modules/@esbuild/openbsd-arm64": { - "version": "0.28.1", - "resolved": "https://registry.npmjs.org/@esbuild/openbsd-arm64/-/openbsd-arm64-0.28.1.tgz", - "integrity": "sha512-MEFJe5C3R8pwXdZ5Y21oo6m7ePiS0d9pWucn99O/wvyJZChoIQKrQDxKrGeW8F5+T0okTHesAmDeiHDTIq0V/Q==", + "version": "0.28.2", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-arm64/-/openbsd-arm64-0.28.2.tgz", + "integrity": "sha512-AL2qJILH7lNjrDmCQDvdxMfAUIv8KMNZOvrwAQ8i8//ntL9FflhOyMJ8OZSMBb8/AWXe3/5v5S20y3zCoZWKoQ==", "cpu": [ "arm64" ], @@ -1109,9 +1164,9 @@ } }, "node_modules/@esbuild/openbsd-x64": { - "version": "0.28.1", - "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.28.1.tgz", - "integrity": "sha512-i/ZLIOafE0Z8cI/XANJAixoJL/uRAoS2xOA3rb0xN+KK0K177cMAsQYkzHtBrtMXAKuAc7HGgcWiZ/sRC1Nxgw==", + "version": "0.28.2", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.28.2.tgz", + "integrity": "sha512-QtiuPytchRyC4rwUKhexJdQKvDuZ6hWloi3igqPQNUJCS1/v9EiO3UTOXR6A3FoMo4fnAKbWJdqaIwhOzh8qEw==", "cpu": [ "x64" ], @@ -1126,9 +1181,9 @@ } }, "node_modules/@esbuild/openharmony-arm64": { - "version": "0.28.1", - "resolved": "https://registry.npmjs.org/@esbuild/openharmony-arm64/-/openharmony-arm64-0.28.1.tgz", - "integrity": "sha512-ge+Z7EXFNt2BO1oAMsVpiQ8EwndV9i1xXerAeTIK7AtPs3bKFXQM7nlRxDSIUIMeueR1CNXxqztLzdNeReKBJg==", + "version": "0.28.2", + "resolved": "https://registry.npmjs.org/@esbuild/openharmony-arm64/-/openharmony-arm64-0.28.2.tgz", + "integrity": "sha512-WkhYDmpTjLvGlScA1rwjRUmhl4k8oXR3cIbtqWmELgU/dFeHHlEllxDvdWcNJV9rbzCexB5vz8gtNewWLgCT7Q==", "cpu": [ "arm64" ], @@ -1143,9 +1198,9 @@ } }, "node_modules/@esbuild/sunos-x64": { - "version": "0.28.1", - "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.28.1.tgz", - "integrity": "sha512-BEjgtECkL3vY+SaSQ6nzVfiALUeFxpawyp8Jmf5PtYhf1Ug40N1h/hxlhts+f1FvSvarEigdxS3BlSMI2PJLcQ==", + "version": "0.28.2", + "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.28.2.tgz", + "integrity": "sha512-GPMSkTOtMnv2U2F8gxe4Io6qmVs+YKyp832Etqqxr0hFngmXQ3rzwytelm3GIn7T4VviRUlf3sOgBOiTdvaf7g==", "cpu": [ "x64" ], @@ -1160,9 +1215,9 @@ } }, "node_modules/@esbuild/win32-arm64": { - "version": "0.28.1", - "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.28.1.tgz", - "integrity": "sha512-lCv9eK/H6ZJWbE7bh2nw54CZ9M2nupBxJcTsdk/QQnWkdSjKGuxmmH8/GWrlT1eMmZfn4dGcCjRte397WqfQXA==", + "version": "0.28.2", + "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.28.2.tgz", + "integrity": "sha512-PIhhEkE9uPBleRBrQEJpUn7MBnibZzbGzYWPmY3x+YoVg/95zbjB4CxPPOQ8l5tYYM4mMaCthF8/1DIfBQQyWQ==", "cpu": [ "arm64" ], @@ -1177,9 +1232,9 @@ } }, "node_modules/@esbuild/win32-ia32": { - "version": "0.28.1", - "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.28.1.tgz", - "integrity": "sha512-zvb/mB2bSCoJOpoCBgYKKpX6YM6mJBlBUVUtVj41DlZJVEB6/0CKlRYxP5wWl1C1ILiCoAU5wZZ4q1P3qeS6Eg==", + "version": "0.28.2", + "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.28.2.tgz", + "integrity": "sha512-YmJbfTlvU7Sdn9BB+4PRES4oB6pxgS37MAONj+hBr/cpXS1aBPKXxNnDbu+QCWPj0o9dgyxeq79g6c5P8KeuYA==", "cpu": [ "ia32" ], @@ -1194,9 +1249,9 @@ } }, "node_modules/@esbuild/win32-x64": { - "version": "0.28.1", - "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.28.1.tgz", - "integrity": "sha512-bm4Mowrv+GXMlpWX++EcXw/iLyd1o3+bJkC2DkWXYVvgZCqD/bSj9ctZeAMC3cIxgjRVR2Dufaiu4YPxr5gW1A==", + "version": "0.28.2", + "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.28.2.tgz", + "integrity": "sha512-5ebpxr3nWMzrL/rnUI755Jkuee0bHL/Gq0WTF9lvcpv73wAp5eu8MfBUgWK9bhWvZjj7yX8etf/8tI8Ney695g==", "cpu": [ "x64" ], @@ -1325,9 +1380,9 @@ } }, "node_modules/@eslint/plugin-kit": { - "version": "0.7.2", - "resolved": "https://registry.npmjs.org/@eslint/plugin-kit/-/plugin-kit-0.7.2.tgz", - "integrity": "sha512-+CNAzxglkrpNf/kKywqQfk74QjtceuOE7Qm+AF8miRvPF/wmmK5+OJOgVh3AVTT3RP2mH3+FOaxlE5v72owk0A==", + "version": "0.7.3", + "resolved": "https://registry.npmjs.org/@eslint/plugin-kit/-/plugin-kit-0.7.3.tgz", + "integrity": "sha512-IkO+/KEUvwbVpiURZg+P7zF74z5Jxe0UgJxVni+RtoHQ6IZieXaO02kmadomap/q+l6bc/jdPGGqTjhuZnuz1Q==", "dev": true, "license": "Apache-2.0", "dependencies": { @@ -1425,9 +1480,9 @@ } }, "node_modules/@img/sharp-darwin-arm64": { - "version": "0.35.3", - "resolved": "https://registry.npmjs.org/@img/sharp-darwin-arm64/-/sharp-darwin-arm64-0.35.3.tgz", - "integrity": "sha512-RMnFX7YQsMoh7lWfcM4NEHHymBX/rLuKNPVM84XE9ONPcaSCDgE7CHIHpSgPcO2xcRthgBy1HfNO319mwhIAkg==", + "version": "0.35.5", + "resolved": "https://registry.npmjs.org/@img/sharp-darwin-arm64/-/sharp-darwin-arm64-0.35.5.tgz", + "integrity": "sha512-QRUlFQ0WxvdWyqqG/WtI3iupfD5rBzmCHXSdPsY91sAtVtTo7Q4cb6zOccZ3gqEqkr0f1As1ehLqmEpDsRf+lg==", "cpu": [ "arm64" ], @@ -1444,13 +1499,13 @@ "url": "https://opencollective.com/libvips" }, "optionalDependencies": { - "@img/sharp-libvips-darwin-arm64": "1.3.2" + "@img/sharp-libvips-darwin-arm64": "1.3.4" } }, "node_modules/@img/sharp-darwin-x64": { - "version": "0.35.3", - "resolved": "https://registry.npmjs.org/@img/sharp-darwin-x64/-/sharp-darwin-x64-0.35.3.tgz", - "integrity": "sha512-Xo+5uFBtLN0BKqieTxiFzFPQAUlBbbH5iBKyRX/z1JrbnYsHTfKJnUfL8+p2TPXr1pXqao4eeL4Rl144uDpK9w==", + "version": "0.35.5", + "resolved": "https://registry.npmjs.org/@img/sharp-darwin-x64/-/sharp-darwin-x64-0.35.5.tgz", + "integrity": "sha512-+BR255RhDlpygUpOc/Jdt1nT6DQ3XG/ERo5wbcdOf5Q320dKtPCKPLR1LJs9VGXRaMa8l1uUa0tkCNOXiAxZUw==", "cpu": [ "x64" ], @@ -1467,13 +1522,13 @@ "url": "https://opencollective.com/libvips" }, "optionalDependencies": { - "@img/sharp-libvips-darwin-x64": "1.3.2" + "@img/sharp-libvips-darwin-x64": "1.3.4" } }, "node_modules/@img/sharp-freebsd-wasm32": { - "version": "0.35.3", - "resolved": "https://registry.npmjs.org/@img/sharp-freebsd-wasm32/-/sharp-freebsd-wasm32-0.35.3.tgz", - "integrity": "sha512-lUxcqWIj2wMQ9BrwNjngcr1gWUr5xgaGThBRqPPalIC2n67Cqj1uPh8NnA/ZhAg8hUbKl+kVHKwgUIwe6ZYPrg==", + "version": "0.35.5", + "resolved": "https://registry.npmjs.org/@img/sharp-freebsd-wasm32/-/sharp-freebsd-wasm32-0.35.5.tgz", + "integrity": "sha512-Y/z91nEZ4uIBX5X3nfTovjU9lHNKFYbL2lpHCLVNmXQK03VIZvXBBt0KxbPGp2SdGSF+2mQU4e+hQaWOt86iAw==", "dev": true, "license": "Apache-2.0", "optional": true, @@ -1481,7 +1536,7 @@ "freebsd" ], "dependencies": { - "@img/sharp-wasm32": "0.35.3" + "@img/sharp-wasm32": "0.35.5" }, "engines": { "node": ">=20.9.0" @@ -1491,9 +1546,9 @@ } }, "node_modules/@img/sharp-libvips-darwin-arm64": { - "version": "1.3.2", - "resolved": "https://registry.npmjs.org/@img/sharp-libvips-darwin-arm64/-/sharp-libvips-darwin-arm64-1.3.2.tgz", - "integrity": "sha512-9J6ypZFpQBj4YnePGoq/S38w6nz+vqg5WZLrLGY4YuSemdMq47GMLBPO42MzwdGwpg/agZ7xzZcFHa48xlywfg==", + "version": "1.3.4", + "resolved": "https://registry.npmjs.org/@img/sharp-libvips-darwin-arm64/-/sharp-libvips-darwin-arm64-1.3.4.tgz", + "integrity": "sha512-5R89nBYiRdUlSWJxPhO+GVtaXzXSxKnRu/xqMn3KTA3L9EB9Oy/P+Nn2f2vlhPuUdy/Zusb2DarbyTpGCfEDuw==", "cpu": [ "arm64" ], @@ -1508,9 +1563,9 @@ } }, "node_modules/@img/sharp-libvips-darwin-x64": { - "version": "1.3.2", - "resolved": "https://registry.npmjs.org/@img/sharp-libvips-darwin-x64/-/sharp-libvips-darwin-x64-1.3.2.tgz", - "integrity": "sha512-m2pW1n6cns9VaubNwsZ+c3CRYjxNQWgJ5gPlnL1nbBcpkBvFm6SCFN5o0psFHI8w9n11NKhFkeEDns98tiqbEw==", + "version": "1.3.4", + "resolved": "https://registry.npmjs.org/@img/sharp-libvips-darwin-x64/-/sharp-libvips-darwin-x64-1.3.4.tgz", + "integrity": "sha512-iR2OKH80yi0U+dUplyh3/xdpFvps6YkCwsXenIJxqxR1v9o+xtKTGbS9H7cps+2Vxjc8B1j96p75NmTGjIhtpQ==", "cpu": [ "x64" ], @@ -1525,9 +1580,9 @@ } }, "node_modules/@img/sharp-libvips-linux-arm": { - "version": "1.3.2", - "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-arm/-/sharp-libvips-linux-arm-1.3.2.tgz", - "integrity": "sha512-1eMLzy92I4J6rmi4mAT8yC3HxOtniyGELlzGbNMLLeqe052ahFQ0h6LFq+lh5DsDIdYViIDst08abvSbcEdLXQ==", + "version": "1.3.4", + "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-arm/-/sharp-libvips-linux-arm-1.3.4.tgz", + "integrity": "sha512-LmRtTsOHuvM2+wlO2Db37dx5MiZhB0FvSunciw48YjdOkZz9KAiRbm8ujeMOA1INqmei5NapFxYEK1D1ZSidmw==", "cpu": [ "arm" ], @@ -1545,9 +1600,9 @@ } }, "node_modules/@img/sharp-libvips-linux-arm64": { - "version": "1.3.2", - "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-arm64/-/sharp-libvips-linux-arm64-1.3.2.tgz", - "integrity": "sha512-dqVSFynCox4C/J8kT16V7SIFAns0IjgLwkvYT7p8LQVmJ5OS5b6tI9IGflxTeuBS//zXeFIUbwt5dwxyZ17cnA==", + "version": "1.3.4", + "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-arm64/-/sharp-libvips-linux-arm64-1.3.4.tgz", + "integrity": "sha512-Y3dgX/6lE2QhQb+Gxy0WZxfg9MEm/JBjamZpS2IklP7xIQoKN4hzAm7KcMVGtaVDt3neE9OKBC7vAfonA/Lr1A==", "cpu": [ "arm64" ], @@ -1565,9 +1620,9 @@ } }, "node_modules/@img/sharp-libvips-linux-ppc64": { - "version": "1.3.2", - "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-ppc64/-/sharp-libvips-linux-ppc64-1.3.2.tgz", - "integrity": "sha512-3z0NHDxD6n5I9gc05U1eW1AyRm+Gznzq3naMrthPNqE6oYykcogW0l/jfpJdjYnuNl8R7yI9pNbE1XiUeyq0Aw==", + "version": "1.3.4", + "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-ppc64/-/sharp-libvips-linux-ppc64-1.3.4.tgz", + "integrity": "sha512-Le6boB8Tai0Nis+gIxIpKx68UDVVIqdR8Tin5Yf1z2LJJQLDJvCDRqRu+jC2qCoD+eIomonmOwB4smBRxfVpYQ==", "cpu": [ "ppc64" ], @@ -1585,9 +1640,9 @@ } }, "node_modules/@img/sharp-libvips-linux-riscv64": { - "version": "1.3.2", - "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-riscv64/-/sharp-libvips-linux-riscv64-1.3.2.tgz", - "integrity": "sha512-bsb4rI+NldGOsXuej2r8OdSS8+zXDVaCWxyWrcv6kneTOlgAHtZABRzBBCwdsPiD90J4myNJuHpg6kA20ImW/w==", + "version": "1.3.4", + "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-riscv64/-/sharp-libvips-linux-riscv64-1.3.4.tgz", + "integrity": "sha512-aHkkIEHPRdQEegJN20MLmGtxYD9R2wQr3Cwpddnu5+YKMt6Uzax7S9h5gpZTo8wyrGuZSlfQ63OevL5mTyOC7Q==", "cpu": [ "riscv64" ], @@ -1605,9 +1660,9 @@ } }, "node_modules/@img/sharp-libvips-linux-s390x": { - "version": "1.3.2", - "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-s390x/-/sharp-libvips-linux-s390x-1.3.2.tgz", - "integrity": "sha512-/ABshyj8gCpyIrNXnHn4LorDJ0HHm1VhXPBlxZ8zAtfVPAaSafXPGn+sUSIRiwaSBy0mmFjSjiXI5mkcwdChKQ==", + "version": "1.3.4", + "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-s390x/-/sharp-libvips-linux-s390x-1.3.4.tgz", + "integrity": "sha512-ra/mB6MikESDUO7Yg+Mi95bFBb9GsObURuhnOv3OqknjGe9sZrG8tCe9q0xSIGrtLgvgw0gKnFWcK4blSgQOuQ==", "cpu": [ "s390x" ], @@ -1625,9 +1680,9 @@ } }, "node_modules/@img/sharp-libvips-linux-x64": { - "version": "1.3.2", - "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-x64/-/sharp-libvips-linux-x64-1.3.2.tgz", - "integrity": "sha512-ITPEtgffGJ0S6G9dRyw/366tJQqFRcHWPHhC+Stpg3Z8AEMrDrTr2lhdz4f/Y/HMbRh//7Z5mBzEpVdi62Oc3w==", + "version": "1.3.4", + "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-x64/-/sharp-libvips-linux-x64-1.3.4.tgz", + "integrity": "sha512-GJ//SSXbnwSDes02umB3nDJLFcQzw8a18V8fyhqr6tV515tOEMdImjjxj1AoafMRz56F3PHgftnj1QEKSU1zkw==", "cpu": [ "x64" ], @@ -1645,9 +1700,9 @@ } }, "node_modules/@img/sharp-libvips-linuxmusl-arm64": { - "version": "1.3.2", - "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linuxmusl-arm64/-/sharp-libvips-linuxmusl-arm64-1.3.2.tgz", - "integrity": "sha512-zE9EdiUzUmg5mDT5a1rk5fYJ6GWPloTwWBYDS14naqHsL+EaMpDj1AWnpLgh3u0YCORv2Tt50wrcrpYqkP97Kw==", + "version": "1.3.4", + "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linuxmusl-arm64/-/sharp-libvips-linuxmusl-arm64-1.3.4.tgz", + "integrity": "sha512-hvulFwtjUcagsis6BBxHwGFwWoNZjgYmULGVrZcyfNbjA8hKILbRxGg15/7w5HDyXHXUos/j6baAWqnCyQ2DWA==", "cpu": [ "arm64" ], @@ -1665,9 +1720,9 @@ } }, "node_modules/@img/sharp-libvips-linuxmusl-x64": { - "version": "1.3.2", - "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linuxmusl-x64/-/sharp-libvips-linuxmusl-x64-1.3.2.tgz", - "integrity": "sha512-m0lrLiUt+lBYnCFr8qV/65yMR4E/c7/wf78I5eKTdkEakFAlZ9QlzEM3QIhhAwVeUhLAHLcCq7a7Vszq/oFNZQ==", + "version": "1.3.4", + "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linuxmusl-x64/-/sharp-libvips-linuxmusl-x64-1.3.4.tgz", + "integrity": "sha512-6zXKeE/p39I1AmA3cJG35eyBGNqNddLnUXjhwBnsGjFPWqf5VKkDBEqaEkPDoTEtkxwi2vv8Tcr2mDyP4So7Fg==", "cpu": [ "x64" ], @@ -1685,9 +1740,9 @@ } }, "node_modules/@img/sharp-linux-arm": { - "version": "0.35.3", - "resolved": "https://registry.npmjs.org/@img/sharp-linux-arm/-/sharp-linux-arm-0.35.3.tgz", - "integrity": "sha512-affVWCTLooy8TSxbDx2qkzuDeaWLNVBA+P//FNBirHsXpP2fuBhk5AuboYUnrDnzoXes8GFjpTx0SBFOCRg+FA==", + "version": "0.35.5", + "resolved": "https://registry.npmjs.org/@img/sharp-linux-arm/-/sharp-linux-arm-0.35.5.tgz", + "integrity": "sha512-LEaXK2WdXVK5ykcw0buWyPMsmLLL2vpHLD6yrNSW+JGEL3BZPA4tpKN6iaMc4AxTTAoaX/sU1rOL51lcIz48ZQ==", "cpu": [ "arm" ], @@ -1707,13 +1762,13 @@ "url": "https://opencollective.com/libvips" }, "optionalDependencies": { - "@img/sharp-libvips-linux-arm": "1.3.2" + "@img/sharp-libvips-linux-arm": "1.3.4" } }, "node_modules/@img/sharp-linux-arm64": { - "version": "0.35.3", - "resolved": "https://registry.npmjs.org/@img/sharp-linux-arm64/-/sharp-linux-arm64-0.35.3.tgz", - "integrity": "sha512-QgKDspHPnrU+GQ55XPhGwyhC8acLVOOSyAvo1oVfFmrIXLkDNmGWzAfDZ4xK8oSA1qBQrALcHX0G5UZni/SuFQ==", + "version": "0.35.5", + "resolved": "https://registry.npmjs.org/@img/sharp-linux-arm64/-/sharp-linux-arm64-0.35.5.tgz", + "integrity": "sha512-LYVx5JTsOM2CBzmxreh+nl64/3H6Xb09iSLknqH47z2T2DFFxDeFLP5y4dJwe6H7uGQlHPyEEtIqyo3DYsRwdQ==", "cpu": [ "arm64" ], @@ -1733,13 +1788,13 @@ "url": "https://opencollective.com/libvips" }, "optionalDependencies": { - "@img/sharp-libvips-linux-arm64": "1.3.2" + "@img/sharp-libvips-linux-arm64": "1.3.4" } }, "node_modules/@img/sharp-linux-ppc64": { - "version": "0.35.3", - "resolved": "https://registry.npmjs.org/@img/sharp-linux-ppc64/-/sharp-linux-ppc64-0.35.3.tgz", - "integrity": "sha512-sMd8rDxmpLOwv/7N44klFjOD5DUO7FLdjiXDI0hoxYaf7Ar262dQIEkosE98bps+5HPLtp/EvNqeqQtOycP/IA==", + "version": "0.35.5", + "resolved": "https://registry.npmjs.org/@img/sharp-linux-ppc64/-/sharp-linux-ppc64-0.35.5.tgz", + "integrity": "sha512-QVxAAq8evVRI9ia2vqgwrmWucn5Dfv+JdWzj75pD8omHLPSP7f8p20O8jxzjCcuCEQEOtYOZUmX1hkiZ0kdevA==", "cpu": [ "ppc64" ], @@ -1759,13 +1814,13 @@ "url": "https://opencollective.com/libvips" }, "optionalDependencies": { - "@img/sharp-libvips-linux-ppc64": "1.3.2" + "@img/sharp-libvips-linux-ppc64": "1.3.4" } }, "node_modules/@img/sharp-linux-riscv64": { - "version": "0.35.3", - "resolved": "https://registry.npmjs.org/@img/sharp-linux-riscv64/-/sharp-linux-riscv64-0.35.3.tgz", - "integrity": "sha512-0Eob78yjlYPfL5vMNWAW55l3R9Y6BQS/gOfe0ZcP9mEz9ohhKSt4im1hayiknXgf8AWrFqMvJcKIdmLmEe7yeQ==", + "version": "0.35.5", + "resolved": "https://registry.npmjs.org/@img/sharp-linux-riscv64/-/sharp-linux-riscv64-0.35.5.tgz", + "integrity": "sha512-LtdreXguaavKODPIfzJ4kffx7UNt1omwtK0rch4EBbbSTXPnxWmYSayXdLJw0fJzQ97kHt1gL/yh4tvU+nCyRQ==", "cpu": [ "riscv64" ], @@ -1785,13 +1840,13 @@ "url": "https://opencollective.com/libvips" }, "optionalDependencies": { - "@img/sharp-libvips-linux-riscv64": "1.3.2" + "@img/sharp-libvips-linux-riscv64": "1.3.4" } }, "node_modules/@img/sharp-linux-s390x": { - "version": "0.35.3", - "resolved": "https://registry.npmjs.org/@img/sharp-linux-s390x/-/sharp-linux-s390x-0.35.3.tgz", - "integrity": "sha512-KgAxQ0DxpNOq1rG2t5cgTgShJFGSuU7XO45cqC+1NVOuZnP6tlgZRuSYOfNupGkHID0o3cJOsw4DVeJpMovcGw==", + "version": "0.35.5", + "resolved": "https://registry.npmjs.org/@img/sharp-linux-s390x/-/sharp-linux-s390x-0.35.5.tgz", + "integrity": "sha512-UZasTOFiYzotTsGOCu42BfUzP6Tu6Do/947iRm1RsLKvlllxwGcn4RN27LibGWceix4Y+Pmw3jsnTcCQIgWjqA==", "cpu": [ "s390x" ], @@ -1811,13 +1866,13 @@ "url": "https://opencollective.com/libvips" }, "optionalDependencies": { - "@img/sharp-libvips-linux-s390x": "1.3.2" + "@img/sharp-libvips-linux-s390x": "1.3.4" } }, "node_modules/@img/sharp-linux-x64": { - "version": "0.35.3", - "resolved": "https://registry.npmjs.org/@img/sharp-linux-x64/-/sharp-linux-x64-0.35.3.tgz", - "integrity": "sha512-8pqvxubL2PGdhlPy6GLqzDYMUjyRmKAwKHYKixpdJYBUK7PJ0C029XdsnpFIdgRZG68fZiGdHVWcKPvtiPB4cA==", + "version": "0.35.5", + "resolved": "https://registry.npmjs.org/@img/sharp-linux-x64/-/sharp-linux-x64-0.35.5.tgz", + "integrity": "sha512-SxFtLTeJInhAA9Q836kux2vZNeOBQEx658qvbboZScr0wIARym3IcGmW7KpVD5sbVg0Ojy+udFQdayYIZyoNog==", "cpu": [ "x64" ], @@ -1837,13 +1892,13 @@ "url": "https://opencollective.com/libvips" }, "optionalDependencies": { - "@img/sharp-libvips-linux-x64": "1.3.2" + "@img/sharp-libvips-linux-x64": "1.3.4" } }, "node_modules/@img/sharp-linuxmusl-arm64": { - "version": "0.35.3", - "resolved": "https://registry.npmjs.org/@img/sharp-linuxmusl-arm64/-/sharp-linuxmusl-arm64-0.35.3.tgz", - "integrity": "sha512-Vz0iQjzzcSX3HCbfwFfCSG/9SCIqyO0mH2sXyiHaAYfBk0cRsCWXRyQYX0ovCK/PAQBbTzQ0dsPQHh5MAFL59w==", + "version": "0.35.5", + "resolved": "https://registry.npmjs.org/@img/sharp-linuxmusl-arm64/-/sharp-linuxmusl-arm64-0.35.5.tgz", + "integrity": "sha512-9HbMclmI1zlNkFRs3z9/eBtDjfD0sGlrX1z6b1qwmiFY5ElDLh4BC0LPBdVp7z1DXFiKlIcznf+ZlsuZzLxQqg==", "cpu": [ "arm64" ], @@ -1863,13 +1918,13 @@ "url": "https://opencollective.com/libvips" }, "optionalDependencies": { - "@img/sharp-libvips-linuxmusl-arm64": "1.3.2" + "@img/sharp-libvips-linuxmusl-arm64": "1.3.4" } }, "node_modules/@img/sharp-linuxmusl-x64": { - "version": "0.35.3", - "resolved": "https://registry.npmjs.org/@img/sharp-linuxmusl-x64/-/sharp-linuxmusl-x64-0.35.3.tgz", - "integrity": "sha512-6O1NPKcDVj9QEdg7Hx549EX8U0rp6yXQERqru6yRN7fGBn32UvIRJUlWnk+8xDCiG76hXVBbX82NZ/ZKr0euIg==", + "version": "0.35.5", + "resolved": "https://registry.npmjs.org/@img/sharp-linuxmusl-x64/-/sharp-linuxmusl-x64-0.35.5.tgz", + "integrity": "sha512-4KOphqB035HrVdqLZfCgMzzERrQkkzOwRhl4OAkRO1YCldbaFjySXMaK534Mo0V+LndnlJk+sbUyLeU0ULyD1A==", "cpu": [ "x64" ], @@ -1889,18 +1944,18 @@ "url": "https://opencollective.com/libvips" }, "optionalDependencies": { - "@img/sharp-libvips-linuxmusl-x64": "1.3.2" + "@img/sharp-libvips-linuxmusl-x64": "1.3.4" } }, "node_modules/@img/sharp-wasm32": { - "version": "0.35.3", - "resolved": "https://registry.npmjs.org/@img/sharp-wasm32/-/sharp-wasm32-0.35.3.tgz", - "integrity": "sha512-cZ0XkcYGpHZkqW6iCkqTcmUC0CD9DhD5d/qeZlZkfRBn6GnHniZXLUo5+9xw8Iv76YE6LQFN9YNBlKREcCG76w==", + "version": "0.35.5", + "resolved": "https://registry.npmjs.org/@img/sharp-wasm32/-/sharp-wasm32-0.35.5.tgz", + "integrity": "sha512-Ptsga1su4tQx+LLF1ECS9U6nz5kmrXKo6XVbtR48Ke3ZRxxgaWBu7IDtEe1quo8hiupwm6WFqxVlXaSf7IINGQ==", "dev": true, "license": "Apache-2.0 AND LGPL-3.0-or-later AND MIT", "optional": true, "dependencies": { - "@emnapi/runtime": "^1.11.1" + "@emnapi/runtime": "^1.11.3" }, "engines": { "node": ">=20.9.0" @@ -1910,9 +1965,9 @@ } }, "node_modules/@img/sharp-webcontainers-wasm32": { - "version": "0.35.3", - "resolved": "https://registry.npmjs.org/@img/sharp-webcontainers-wasm32/-/sharp-webcontainers-wasm32-0.35.3.tgz", - "integrity": "sha512-2rnq7bX3NzeR2T4YWgz8qiG4h3TSdMe+vN1iQXpJleSJ3SM5zQ8Fy2SyyXAWlbxpEZ2Y+Z4u1BePgJEYbSy80Q==", + "version": "0.35.5", + "resolved": "https://registry.npmjs.org/@img/sharp-webcontainers-wasm32/-/sharp-webcontainers-wasm32-0.35.5.tgz", + "integrity": "sha512-hfhF/FmoQyTUkA0bIKFOtw536BQSeBMe6BF6QyWlrPxT754+TFLaZ7sKKTfvvM0yJgKgaYTwnFCIZ/GuDw5SUA==", "cpu": [ "wasm32" ], @@ -1920,7 +1975,7 @@ "license": "Apache-2.0", "optional": true, "dependencies": { - "@img/sharp-wasm32": "0.35.3" + "@img/sharp-wasm32": "0.35.5" }, "engines": { "node": ">=20.9.0" @@ -1930,9 +1985,9 @@ } }, "node_modules/@img/sharp-win32-arm64": { - "version": "0.35.3", - "resolved": "https://registry.npmjs.org/@img/sharp-win32-arm64/-/sharp-win32-arm64-0.35.3.tgz", - "integrity": "sha512-4bPwFdMbeC4JQ8L8LOyWp6nsHcboP5fxkp6iPOXz2Vg49R42TuMs2whkJ5OAP4/Ul035qOzy0AecOF9VOscn4w==", + "version": "0.35.5", + "resolved": "https://registry.npmjs.org/@img/sharp-win32-arm64/-/sharp-win32-arm64-0.35.5.tgz", + "integrity": "sha512-X4t7g+7ZA5DKblCBEXGjUqqemj4vczING/5viFwAL8h4N3qYeyjwdCvRLHi4EdOUI+2Z7UFlp1VM+p/AuEtm6Q==", "cpu": [ "arm64" ], @@ -1950,9 +2005,9 @@ } }, "node_modules/@img/sharp-win32-ia32": { - "version": "0.35.3", - "resolved": "https://registry.npmjs.org/@img/sharp-win32-ia32/-/sharp-win32-ia32-0.35.3.tgz", - "integrity": "sha512-r53mXsBN6lFUDiST764SvgwUdHAqM4rPAiDzAmf4fLoB6X/rkfyTrLCg6+g17wJJiCmB3JYgHuUldCWUIRFSXw==", + "version": "0.35.5", + "resolved": "https://registry.npmjs.org/@img/sharp-win32-ia32/-/sharp-win32-ia32-0.35.5.tgz", + "integrity": "sha512-5Zm82LoBc43nhwNybZlG7Y1KO//Zhsn306fQl29ZOuStHLGTo3BWL83q3cznX0poxSAMuYL1On/BHBxkBeKr6A==", "cpu": [ "ia32" ], @@ -1970,9 +2025,9 @@ } }, "node_modules/@img/sharp-win32-x64": { - "version": "0.35.3", - "resolved": "https://registry.npmjs.org/@img/sharp-win32-x64/-/sharp-win32-x64-0.35.3.tgz", - "integrity": "sha512-D4y1vNeZrIIJCN+uHaWVtH86B+aCrdMYYjicy9pXHvbGZeGYLLSd3wdVuC37FxVXlU1ARsk84eKWfWMXGYEqvA==", + "version": "0.35.5", + "resolved": "https://registry.npmjs.org/@img/sharp-win32-x64/-/sharp-win32-x64-0.35.5.tgz", + "integrity": "sha512-x76eH0vEiHlcMQu8Y8IenntaACtddpT6W0wmXtWrnKcnKI7ME5DdgqhAD6SEWOEl1v2zDvkZDhFA9KnURwpfqg==", "cpu": [ "x64" ], @@ -2000,9 +2055,9 @@ } }, "node_modules/@jridgewell/sourcemap-codec": { - "version": "1.5.5", - "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.5.tgz", - "integrity": "sha512-cYQ9310grqxueWbl+WuIUIaiUaDcj7WOq5fVhEljNVgRfOUhY9fy2zTvfoqWsnebh8Sl70VScFbICvJnLKB0Og==", + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.6.0.tgz", + "integrity": "sha512-T7jf+5zgsZHwNJ4lvQ7/aezbyk0nNX+zJVWpmHA7VYsEx7a7qr5Rg5IbtJFqkgze5Y2sruq1RUY8Q837Od7iFw==", "dev": true, "license": "MIT" }, @@ -2017,29 +2072,55 @@ "@jridgewell/sourcemap-codec": "^1.4.14" } }, + "node_modules/@keyv/bigmap": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/@keyv/bigmap/-/bigmap-1.3.1.tgz", + "integrity": "sha512-WbzE9sdmQtKy8vrNPa9BRnwZh5UF4s1KTmSK0KUVLo3eff5BlQNNWDnFOouNpKfPKDnms9xynJjsMYjMaT/aFQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "hashery": "^1.4.0", + "hookified": "^1.15.0" + }, + "engines": { + "node": ">= 18" + }, + "peerDependencies": { + "keyv": "^5.6.0" + } + }, + "node_modules/@keyv/serialize": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@keyv/serialize/-/serialize-1.1.1.tgz", + "integrity": "sha512-dXn3FZhPv0US+7dtJsIi2R+c7qWYiReoEh5zUntWCf4oSpMNib8FDhSoed6m3QyZdx5hK7iLFkYk3rNxwt8vTA==", + "dev": true, + "license": "MIT" + }, "node_modules/@mdn/browser-compat-data": { - "version": "8.0.8", - "resolved": "https://registry.npmjs.org/@mdn/browser-compat-data/-/browser-compat-data-8.0.8.tgz", - "integrity": "sha512-Rutrrc3FYOc+um4/QC4WFETNk2fV8NKWoqQl3tQfcVTQ1WFaoJRbsJBasSF34ltitmnYYD6ZsKW1cOQtSj1jbQ==", + "version": "8.1.4", + "resolved": "https://registry.npmjs.org/@mdn/browser-compat-data/-/browser-compat-data-8.1.4.tgz", + "integrity": "sha512-Cgp3OP3u9x57kT1sZPI115SP5H1IyaBhdDPnvnHRYZ1988kW83wuqcIdcMinLJXlMKOL5Y2cufWHzngh5cVtow==", "license": "CC0-1.0" }, "node_modules/@napi-rs/wasm-runtime": { - "version": "1.1.6", - "resolved": "https://registry.npmjs.org/@napi-rs/wasm-runtime/-/wasm-runtime-1.1.6.tgz", - "integrity": "sha512-ZLv/JdUfkvOy9eCnnBaGfiO+XimbjebAeO+MRQqD/B+FR1tnRN0tpKSJHRbE8sFfS6aqsXZ67TQjfwfsxULVbg==", + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/@napi-rs/wasm-runtime/-/wasm-runtime-1.2.4.tgz", + "integrity": "sha512-AJxoUD2/15ESHbvpcyjU274nsAPLuOtPHCk0vKJM5pj//Fg/B1FXNWjPnXTT9PymCYYiHo4zPj0ZomXBKhoy7g==", "dev": true, "license": "MIT", - "optional": true, "dependencies": { "@tybys/wasm-util": "^0.10.3" }, + "engines": { + "node": "^20.19.0 || ^22.13.0 || >=23.5.0" + }, "funding": { "type": "github", "url": "https://github.com/sponsors/Brooooooklyn" }, "peerDependencies": { - "@emnapi/core": "^1.7.1", - "@emnapi/runtime": "^1.7.1" + "@emnapi/core": "^1.7.1 || ^2.0.0-alpha.4", + "@emnapi/runtime": "^1.7.1 || ^2.0.0-alpha.4" } }, "node_modules/@oslojs/encoding": { @@ -2050,23 +2131,23 @@ "license": "MIT" }, "node_modules/@oxc-project/types": { - "version": "0.139.0", - "resolved": "https://registry.npmjs.org/@oxc-project/types/-/types-0.139.0.tgz", - "integrity": "sha512-r9gHphtCs+1M7J0pw6Sn/hh/Wpa/iQrOOkrNAlVLF/gHq+/CJmHIWKKUUhdWjcD6CIa8idarspCsASiXCXvFUw==", + "version": "0.152.0", + "resolved": "https://registry.npmjs.org/@oxc-project/types/-/types-0.152.0.tgz", + "integrity": "sha512-oM/5rLBm2tPkg0iBgkH/FOeR3PCDpY19GTgAZjMFM8h9WI9VW7cLgzp6nwtarYKmovavIQZ+Fe/RKX/8C8O/Rw==", "dev": true, "license": "MIT", "funding": { - "url": "https://github.com/sponsors/Boshen" + "url": "https://github.com/sponsors/oxc-project" } }, "node_modules/@playwright/test": { - "version": "1.62.0", - "resolved": "https://registry.npmjs.org/@playwright/test/-/test-1.62.0.tgz", - "integrity": "sha512-9zOJ6ZQRAena31MpOH9VSzIz8Ou3YJ/wtY/eQm5T2uhfhG7/U3COrMS8xOtUrZrp9OgdmzEnIYODye3nY1VqzA==", + "version": "1.63.0", + "resolved": "https://registry.npmjs.org/@playwright/test/-/test-1.63.0.tgz", + "integrity": "sha512-oxMK4vllB9RK5NQ2l1pq1IfOf2AvnEuj/vYGDj0H2nMtmtZpKtCwt/l00GEO6xjGfpBNAvjovvYdCm50dRQkpQ==", "dev": true, "license": "Apache-2.0", "dependencies": { - "playwright": "1.62.0" + "playwright": "1.63.0" }, "bin": { "playwright": "cli.js" @@ -2075,10 +2156,34 @@ "node": ">=20" } }, + "node_modules/@prettier/parse-srcset": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/@prettier/parse-srcset/-/parse-srcset-3.1.0.tgz", + "integrity": "sha512-FIRv2rZotO9NP/r66taYqD1zICpPiBbrECqjKV/xqNotqDxF7fLzzUeK+1RSRx9Tenk0DajR/GcRmTJ2qtHaKQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/@rolldown/binding-android-arm-eabi": { + "version": "1.2.12", + "resolved": "https://registry.npmjs.org/@rolldown/binding-android-arm-eabi/-/binding-android-arm-eabi-1.2.12.tgz", + "integrity": "sha512-dB/a1214qKfHMXCpgqR4OZT+jS4kTyEXbQGJPqzobt5EwH5rX080pxE37alt3RzvR1bf1Yz/yGqRfrYAxuPw0A==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, "node_modules/@rolldown/binding-android-arm64": { - "version": "1.1.5", - "resolved": "https://registry.npmjs.org/@rolldown/binding-android-arm64/-/binding-android-arm64-1.1.5.tgz", - "integrity": "sha512-lZg8fqIv2v7FF237bwMgzGZEJvGL79/s5knJ/i6FmsGF4XXlzccZ4jb+TrFIxtSSxFtIpdsgrPZeMk1I9AFcyQ==", + "version": "1.2.12", + "resolved": "https://registry.npmjs.org/@rolldown/binding-android-arm64/-/binding-android-arm64-1.2.12.tgz", + "integrity": "sha512-7KHFgQ5VJxIHcLlrwrc3Xbds7oTNQT7Pgi9gQCJKrd2VGab/UksIOYp6VD8MzCstGxOKMgNamPwUCfxPdP1OHg==", "cpu": [ "arm64" ], @@ -2093,9 +2198,9 @@ } }, "node_modules/@rolldown/binding-darwin-arm64": { - "version": "1.1.5", - "resolved": "https://registry.npmjs.org/@rolldown/binding-darwin-arm64/-/binding-darwin-arm64-1.1.5.tgz", - "integrity": "sha512-51Bnx9pNiMRKSUNtBfySkNJ9vMU9Hh3I1ozDd6gyPPYzaXCfnptUcEZxXGYFn+ul2dtcMUiqGR1Yai2K10uoTw==", + "version": "1.2.12", + "resolved": "https://registry.npmjs.org/@rolldown/binding-darwin-arm64/-/binding-darwin-arm64-1.2.12.tgz", + "integrity": "sha512-3YIhqHD96nA5SaYNRBR16HnGv4oavZvXfD/ayHM+oYZ0WD/8lBAtf6zQua4kEyAvpqrluKXl0lnOBoiNby7x9w==", "cpu": [ "arm64" ], @@ -2110,9 +2215,9 @@ } }, "node_modules/@rolldown/binding-darwin-x64": { - "version": "1.1.5", - "resolved": "https://registry.npmjs.org/@rolldown/binding-darwin-x64/-/binding-darwin-x64-1.1.5.tgz", - "integrity": "sha512-Tm+gbfC0aHu1tBA/JvKQh32S0K6YgCHkiAF4/W6xX0K0RmNuc94VeK419dJoE65R5aRxmo+noZQSWrAMF6yb6g==", + "version": "1.2.12", + "resolved": "https://registry.npmjs.org/@rolldown/binding-darwin-x64/-/binding-darwin-x64-1.2.12.tgz", + "integrity": "sha512-UuuJ35MFw4gmFOrE9pEqIV+K3syIKveph+Qc1/ljHZVdoDW4pz/JHR/eMVom+TZGl/5OOvGJOWaOCVt3ZfqhxA==", "cpu": [ "x64" ], @@ -2127,9 +2232,9 @@ } }, "node_modules/@rolldown/binding-freebsd-x64": { - "version": "1.1.5", - "resolved": "https://registry.npmjs.org/@rolldown/binding-freebsd-x64/-/binding-freebsd-x64-1.1.5.tgz", - "integrity": "sha512-JMzDKCCXq93YccG5gz3hvOs1oXRKAf0XYpfOS88e+wZrC8Iugj6j68867vrYZkvpDDpKn/KoKORThmchMpF6TA==", + "version": "1.2.12", + "resolved": "https://registry.npmjs.org/@rolldown/binding-freebsd-x64/-/binding-freebsd-x64-1.2.12.tgz", + "integrity": "sha512-uMvssit0a4W+/7D8CbHUvG719mH3R2jwXAlh/XcPvuHTE0g++LymF88DCGNX0HM2rBOn0xrzgXktIB6fLSJBTQ==", "cpu": [ "x64" ], @@ -2144,9 +2249,9 @@ } }, "node_modules/@rolldown/binding-linux-arm-gnueabihf": { - "version": "1.1.5", - "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-arm-gnueabihf/-/binding-linux-arm-gnueabihf-1.1.5.tgz", - "integrity": "sha512-uML21j2K5TfPGutKxub+M+nLjZIrWjXQ5Grx4lCe/nimTj9B4L63zHpjXLl4y0L3mcm2htEQIb06oCG/szerNw==", + "version": "1.2.12", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-arm-gnueabihf/-/binding-linux-arm-gnueabihf-1.2.12.tgz", + "integrity": "sha512-XcFu0R0xWnwzSf4IQgFH1rJIckPN1pLy2R+4r9IDB7Yfu/ys9cVqfa4pBrMHj7a3gl8mIR4nRNPg0e5IvEVs6g==", "cpu": [ "arm" ], @@ -2161,9 +2266,9 @@ } }, "node_modules/@rolldown/binding-linux-arm64-gnu": { - "version": "1.1.5", - "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-arm64-gnu/-/binding-linux-arm64-gnu-1.1.5.tgz", - "integrity": "sha512-navSiuTMogvnQoZoM/v+l3ZWo50/NTwSHSzheABx/RCnmUPaKwq9qSo4Br2OYRs21+Fz8uFqITZM3H4opOB0/Q==", + "version": "1.2.12", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-arm64-gnu/-/binding-linux-arm64-gnu-1.2.12.tgz", + "integrity": "sha512-260UrKgn8tz39ak+SMDOirKzr7V04M9dWPw5llW00SwBivCZoWcRBKV1d8cXnRkUmSZA3BdiUmBHWk7734Ulpw==", "cpu": [ "arm64" ], @@ -2181,9 +2286,9 @@ } }, "node_modules/@rolldown/binding-linux-arm64-musl": { - "version": "1.1.5", - "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-arm64-musl/-/binding-linux-arm64-musl-1.1.5.tgz", - "integrity": "sha512-lAryqH7IteztmCXQXk0etKj4wBQ7Gx5S6LjKhsgp9zb8I5bsuvU/2llH1hDQcjsFeqIsovMVN339/8pUDDBXxA==", + "version": "1.2.12", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-arm64-musl/-/binding-linux-arm64-musl-1.2.12.tgz", + "integrity": "sha512-5YK1I9SqDkbPgc1IA8BgDl34suqUS2q0KWnBrirm0E51YjOs6eo6dV6jbQfNE/argHRSvd0QUGgtpIoYx+WWpw==", "cpu": [ "arm64" ], @@ -2201,9 +2306,9 @@ } }, "node_modules/@rolldown/binding-linux-ppc64-gnu": { - "version": "1.1.5", - "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-ppc64-gnu/-/binding-linux-ppc64-gnu-1.1.5.tgz", - "integrity": "sha512-fsK/sNBnxzBlL4O1JNrZakVQxPspqpED5dLtNsZS9oOKmtSpdNIzxH2kkol5HYTWJN47sE20ztMJPxfZ89qGOg==", + "version": "1.2.12", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-ppc64-gnu/-/binding-linux-ppc64-gnu-1.2.12.tgz", + "integrity": "sha512-Rkcrmp7eFRg74yL5fXEU91JEWbdEPLevWwGtXpmhbjlD1StScbWTmO94Bhly+Mo+ketKYkdmM1vNUKeWSlx8cQ==", "cpu": [ "ppc64" ], @@ -2221,9 +2326,9 @@ } }, "node_modules/@rolldown/binding-linux-s390x-gnu": { - "version": "1.1.5", - "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-s390x-gnu/-/binding-linux-s390x-gnu-1.1.5.tgz", - "integrity": "sha512-gLYb4BIadlfTOYT5gO503n8zQjXflgzpD0FcyKh0Mzx3rqCZKnHoJWV9xe1KXUJ5lx2JfcSHr/mhzS0PC/McAA==", + "version": "1.2.12", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-s390x-gnu/-/binding-linux-s390x-gnu-1.2.12.tgz", + "integrity": "sha512-qvK4DuAsQc2BSjlx+Xr+IzOIvvxbGZqxFwdWfG6F518Erj0GGISyQbJ6pIappnOxlNPzNHvo/L0BwB30GZ+zVw==", "cpu": [ "s390x" ], @@ -2241,9 +2346,9 @@ } }, "node_modules/@rolldown/binding-linux-x64-gnu": { - "version": "1.1.5", - "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-x64-gnu/-/binding-linux-x64-gnu-1.1.5.tgz", - "integrity": "sha512-FjcpEKUyJygHgs1o50VYNvkt5+7Le/VEdYt0AkRpkL33MnyQfwr8l5mXwMmfmTbyMPr5vJLC+8/Gd9gXnwU1QQ==", + "version": "1.2.12", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-x64-gnu/-/binding-linux-x64-gnu-1.2.12.tgz", + "integrity": "sha512-Q9uLBO53Xd4QIq1WOycVQyPP1O4HhraEV2qqb3uTrnVw6QZih9duY4vNXOivL1xoUS1/z+W8eF4NMfl2a8Sdjw==", "cpu": [ "x64" ], @@ -2261,9 +2366,9 @@ } }, "node_modules/@rolldown/binding-linux-x64-musl": { - "version": "1.1.5", - "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-x64-musl/-/binding-linux-x64-musl-1.1.5.tgz", - "integrity": "sha512-Me+PfPI2TMeOQk0gYWfLQZtTktrmzbr8cDboqX83XKc7UrgAi55gF+2dUkWdxd19n55Essp2yeca+O9N5rBxHg==", + "version": "1.2.12", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-x64-musl/-/binding-linux-x64-musl-1.2.12.tgz", + "integrity": "sha512-3IBxWFMjbOZskDPKv8Lf9BCnahlKuHthWkYnyIxOH/QcJrFcS4EmcenthApkwr/5+nEqZlLzeYbxeMaX7A5u4g==", "cpu": [ "x64" ], @@ -2281,9 +2386,9 @@ } }, "node_modules/@rolldown/binding-openharmony-arm64": { - "version": "1.1.5", - "resolved": "https://registry.npmjs.org/@rolldown/binding-openharmony-arm64/-/binding-openharmony-arm64-1.1.5.tgz", - "integrity": "sha512-yc5WrLzXks6zCQfn9Oxr8pORKyl/pF+QjHmW/Qx3qu0oyrrNC+y2JLTU1E2rcWYAmzlnqngWXHQjy51VzW70Vw==", + "version": "1.2.12", + "resolved": "https://registry.npmjs.org/@rolldown/binding-openharmony-arm64/-/binding-openharmony-arm64-1.2.12.tgz", + "integrity": "sha512-xtX61xg4LKPkPWilZU1ynKClz5Gj4bf74LML4r3eVLWumKnGjoEr1OSHQhMdbBDoYTi+yjrujvpZe2pUnqCrrA==", "cpu": [ "arm64" ], @@ -2297,52 +2402,10 @@ "node": "^20.19.0 || >=22.12.0" } }, - "node_modules/@rolldown/binding-wasm32-wasi": { - "version": "1.1.5", - "resolved": "https://registry.npmjs.org/@rolldown/binding-wasm32-wasi/-/binding-wasm32-wasi-1.1.5.tgz", - "integrity": "sha512-VbQGPX2b4r48TAMIM2cjgluIM1HYutm4pcTEJsle7iEP7sB1dFqtPLBVbdLAZCxy1txCcPxf4QFf4v8uvltPqA==", - "cpu": [ - "wasm32" - ], - "dev": true, - "license": "MIT", - "optional": true, - "dependencies": { - "@emnapi/core": "1.11.1", - "@emnapi/runtime": "1.11.1", - "@napi-rs/wasm-runtime": "^1.1.6" - }, - "engines": { - "node": "^20.19.0 || >=22.12.0" - } - }, - "node_modules/@rolldown/binding-wasm32-wasi/node_modules/@emnapi/core": { - "version": "1.11.1", - "resolved": "https://registry.npmjs.org/@emnapi/core/-/core-1.11.1.tgz", - "integrity": "sha512-RSvbQmHzdKzNsLYa/wHrbc3KN4sYLKAdPZxqiM2HATqv/SBk2/ENSHpvXGaLOMcsAyz0poEGqkmmKYG3OWiJEQ==", - "dev": true, - "license": "MIT", - "optional": true, - "dependencies": { - "@emnapi/wasi-threads": "1.2.2", - "tslib": "^2.4.0" - } - }, - "node_modules/@rolldown/binding-wasm32-wasi/node_modules/@emnapi/runtime": { - "version": "1.11.1", - "resolved": "https://registry.npmjs.org/@emnapi/runtime/-/runtime-1.11.1.tgz", - "integrity": "sha512-vgj7R3y3Wgx24IQaGPA/R6YFXLHVMOZ0uVEyIQPaWs+rd1AzfEMXlAC22FYwO1XkKR6NPsq7mUandH8oIRdZFw==", - "dev": true, - "license": "MIT", - "optional": true, - "dependencies": { - "tslib": "^2.4.0" - } - }, "node_modules/@rolldown/binding-win32-arm64-msvc": { - "version": "1.1.5", - "resolved": "https://registry.npmjs.org/@rolldown/binding-win32-arm64-msvc/-/binding-win32-arm64-msvc-1.1.5.tgz", - "integrity": "sha512-gHv82k63z4qpV5+Q1y/12KrK0ltWBukVDI8nZcbT7Tt/ZlOIVwppazneq0F93oDxTo3IgAMEDIoQh3E2n6mVsw==", + "version": "1.2.12", + "resolved": "https://registry.npmjs.org/@rolldown/binding-win32-arm64-msvc/-/binding-win32-arm64-msvc-1.2.12.tgz", + "integrity": "sha512-At7fPB6PCaIjzgIhEZFxuT+BBFqiQibJDT4d3PhiR3f4E7bbMZF4aKblbFfEM3sETRDd1YiQx/+U/g/B/ou5Ew==", "cpu": [ "arm64" ], @@ -2357,9 +2420,9 @@ } }, "node_modules/@rolldown/binding-win32-x64-msvc": { - "version": "1.1.5", - "resolved": "https://registry.npmjs.org/@rolldown/binding-win32-x64-msvc/-/binding-win32-x64-msvc-1.1.5.tgz", - "integrity": "sha512-tTZuDBPw85tEN5PQi1pnEBzDy0Z49HtScLAbD5t6hyeU92A95pRWaSMw1GZZi/RwgSgUIl0xrSlXIT/9QzvYSA==", + "version": "1.2.12", + "resolved": "https://registry.npmjs.org/@rolldown/binding-win32-x64-msvc/-/binding-win32-x64-msvc-1.2.12.tgz", + "integrity": "sha512-WIw2haVKwjuYdXkHaoC0mF8Le71TuCBxjrdKqLbJGctbBABj+ClfmNvtbOnzpq3RokNo5+V1qhtSzJyXorsklQ==", "cpu": [ "x64" ], @@ -2380,47 +2443,17 @@ "dev": true, "license": "MIT" }, - "node_modules/@rollup/pluginutils": { - "version": "5.4.0", - "resolved": "https://registry.npmjs.org/@rollup/pluginutils/-/pluginutils-5.4.0.tgz", - "integrity": "sha512-MfPp06CjRLfXQ3wY0R8vJDYBy/MvVcc9OulEfR0B8Iv9ko+GCNaRZ+EpJYFl27LhKsZK0o420sYCRHCjfCgeUg==", - "dev": true, - "license": "MIT", - "dependencies": { - "@types/estree": "^1.0.0", - "estree-walker": "^2.0.2", - "picomatch": "^4.0.2" - }, - "engines": { - "node": ">=14.0.0" - }, - "peerDependencies": { - "rollup": "^1.20.0||^2.0.0||^3.0.0||^4.0.0" - }, - "peerDependenciesMeta": { - "rollup": { - "optional": true - } - } - }, - "node_modules/@rollup/pluginutils/node_modules/estree-walker": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-2.0.2.tgz", - "integrity": "sha512-Rfkk/Mp/DL7JVje3u18FxFujQlTNR2q6QfMSMB7AvCBx91NGj/ba3kCfza0f6dVDbw7YlRf/nDrn7pQrCCyQ/w==", - "dev": true, - "license": "MIT" - }, "node_modules/@shikijs/core": { - "version": "4.3.1", - "resolved": "https://registry.npmjs.org/@shikijs/core/-/core-4.3.1.tgz", - "integrity": "sha512-ANMDxuaPsNMdDC1m4vfvhlDmJweMwkE5XitTwrq2rWHx5jM+dlm4MmHt2PP6t0uejfR77SuhrhJ0zEijIF/uhA==", + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/@shikijs/core/-/core-4.5.0.tgz", + "integrity": "sha512-6CIgwq+bt2JZ3OSjb/nBkkwEf/CfpHcbam+Mg5Pllco7HAGRQ2/EFhZrrJtbyNTgKwknfVS+llsXGygiDGwJWw==", "dev": true, "license": "MIT", "dependencies": { - "@shikijs/primitive": "4.3.1", - "@shikijs/types": "4.3.1", + "@shikijs/primitive": "4.5.0", + "@shikijs/types": "4.5.0", "@shikijs/vscode-textmate": "^10.0.2", - "@types/hast": "^3.0.4", + "@types/hast": "^3.0.5", "hast-util-to-html": "^9.0.5" }, "engines": { @@ -2428,13 +2461,13 @@ } }, "node_modules/@shikijs/engine-javascript": { - "version": "4.3.1", - "resolved": "https://registry.npmjs.org/@shikijs/engine-javascript/-/engine-javascript-4.3.1.tgz", - "integrity": "sha512-JBItcnPuYq7jVJdZo/vMj94r+szT7XEjHFX+mvFDGSEIbVAXAGyHAHzhbWzpGOwYidCZrErJLLgn2PVeiokHnQ==", + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/@shikijs/engine-javascript/-/engine-javascript-4.5.0.tgz", + "integrity": "sha512-Ed6UdEj84LyYkwnxM5CvSMWAD+id9ExTYri0/+x41U9zrgNifPSS9lZm0JqBP0VfYI8yr8tY5nbNq9+p9R0kFA==", "dev": true, "license": "MIT", "dependencies": { - "@shikijs/types": "4.3.1", + "@shikijs/types": "4.5.0", "@shikijs/vscode-textmate": "^10.0.2", "oniguruma-to-es": "^4.3.6" }, @@ -2443,13 +2476,13 @@ } }, "node_modules/@shikijs/engine-oniguruma": { - "version": "4.3.1", - "resolved": "https://registry.npmjs.org/@shikijs/engine-oniguruma/-/engine-oniguruma-4.3.1.tgz", - "integrity": "sha512-OXyNMzg0pews+msMj4cHeqT4xiYKKvbnn6VbdAXxfoFl3SSx4fJTc8FadECuc5/H9p3BzhNAoAUXKwAu9rWYhg==", + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/@shikijs/engine-oniguruma/-/engine-oniguruma-4.5.0.tgz", + "integrity": "sha512-dKVmbJecVdB9recl8a/CU4jdpNXyjJQrIcesIkpS70s5HS02ohpnCSpMUbotPnEUzbAcLQ+S4hwZYbkBBiTcJw==", "dev": true, "license": "MIT", "dependencies": { - "@shikijs/types": "4.3.1", + "@shikijs/types": "4.5.0", "@shikijs/vscode-textmate": "^10.0.2" }, "engines": { @@ -2457,55 +2490,55 @@ } }, "node_modules/@shikijs/langs": { - "version": "4.3.1", - "resolved": "https://registry.npmjs.org/@shikijs/langs/-/langs-4.3.1.tgz", - "integrity": "sha512-m0l9nsDqgBHvbZbk7A0/kXz/impK3uB/c6rAn6Gpg/uPtdZRQ+alsN/17MU5thb68XTj/4DxkZAotrM0GGSpDQ==", + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/@shikijs/langs/-/langs-4.5.0.tgz", + "integrity": "sha512-wwBTqwduXSz0X4v9Qa2EWeFaYJEw1clCncWjoRNQRbVDu3SPRTRWucnouYapKj3b8Q+sk/41Vbc4B5c8nuYzLA==", "dev": true, "license": "MIT", "dependencies": { - "@shikijs/types": "4.3.1" + "@shikijs/types": "4.5.0" }, "engines": { "node": ">=20" } }, "node_modules/@shikijs/primitive": { - "version": "4.3.1", - "resolved": "https://registry.npmjs.org/@shikijs/primitive/-/primitive-4.3.1.tgz", - "integrity": "sha512-CXQRQOYy1leqQ8ceTeJdmXv/bsUY++6QyLpXJ94LZAAYj5X2SKRdc5ipguv4NPyGVKItB2PPwUpRNe0Sjh5S1A==", + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/@shikijs/primitive/-/primitive-4.5.0.tgz", + "integrity": "sha512-UM7ShlA8oz0OWxLLO8BmO9Ip6fVqdkt8yF0EH7nOCqHfrx1eEAzF0ZUVK7L+I8NEgeu1PEWSRlxaiPPeCb4iDg==", "dev": true, "license": "MIT", "dependencies": { - "@shikijs/types": "4.3.1", + "@shikijs/types": "4.5.0", "@shikijs/vscode-textmate": "^10.0.2", - "@types/hast": "^3.0.4" + "@types/hast": "^3.0.5" }, "engines": { "node": ">=20" } }, "node_modules/@shikijs/themes": { - "version": "4.3.1", - "resolved": "https://registry.npmjs.org/@shikijs/themes/-/themes-4.3.1.tgz", - "integrity": "sha512-dgpoJ4WqNi2yTmizQHBJ5zcX6j2lE6icN/0yt4l1kkf16jrY/pwPLoTb1ETsWMz0OBLf9ZNvwmxft+cH+N9qSA==", + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/@shikijs/themes/-/themes-4.5.0.tgz", + "integrity": "sha512-zGb87H3UBbpuI4yoh5UguB1XbU+2BDU3kflM7UfZ+Cy2hWo9lBtqjSVK20gmLY6ukYl040hAypGXMgud9vul8Q==", "dev": true, "license": "MIT", "dependencies": { - "@shikijs/types": "4.3.1" + "@shikijs/types": "4.5.0" }, "engines": { "node": ">=20" } }, "node_modules/@shikijs/types": { - "version": "4.3.1", - "resolved": "https://registry.npmjs.org/@shikijs/types/-/types-4.3.1.tgz", - "integrity": "sha512-CHFxE0jztBIZRHH6gxXE7DXUCFXjReEGxZ/j0rfSLGKZuwp2xBYycEP14875DSa9KLL/6700oxIq6oO6ef9K2g==", + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/@shikijs/types/-/types-4.5.0.tgz", + "integrity": "sha512-drtPrtD8N0DENyD2cyt6Ajy+IWsiCLgMxODwLTpvH1UsN6a9jf90tNTPjqwHvA+0Lzu9e0txk8DjfqH1p9UJRw==", "dev": true, "license": "MIT", "dependencies": { "@shikijs/vscode-textmate": "^10.0.2", - "@types/hast": "^3.0.4" + "@types/hast": "^3.0.5" }, "engines": { "node": ">=20" @@ -2540,9 +2573,9 @@ } }, "node_modules/@sigstore/protobuf-specs": { - "version": "0.5.1", - "resolved": "https://registry.npmjs.org/@sigstore/protobuf-specs/-/protobuf-specs-0.5.1.tgz", - "integrity": "sha512-/ScWUhhoFasJsSRGTVBwId1loQjjnjAfE4djL6ZhrXRpNCmPTnUKF5Jokd58ILseOMjzET3UrMOtJPS9sYeI0g==", + "version": "0.5.2", + "resolved": "https://registry.npmjs.org/@sigstore/protobuf-specs/-/protobuf-specs-0.5.2.tgz", + "integrity": "sha512-SQqvFMt4V78fdjcDdYX6HbiVSOR4QK3ZgwCa2KOsopAgPIHy1rU5UDUmzLl02r5oyyaYcYHR1hpwDRk/yUe+Mw==", "license": "Apache-2.0", "engines": { "node": "^18.17.0 || >=20.5.0" @@ -2562,9 +2595,9 @@ } }, "node_modules/@sigstore/verify": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/@sigstore/verify/-/verify-4.1.0.tgz", - "integrity": "sha512-p/s720RiWxLG8XtmfdPfEJOlATA6H/2knFqmtQbFkHKN3IrhWGUwPfpQAf1UnQIEES9IaH6zzhfjkrhTfeSdZw==", + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/@sigstore/verify/-/verify-4.1.2.tgz", + "integrity": "sha512-BfD9eLrz3A/DG58aSgfgZYmIR6V9Yw96QVN/frtu2bEH7ctSTk2TDvHU12un3JsDPBTqTNkqkIkucjxljpOFqQ==", "license": "Apache-2.0", "dependencies": { "@sigstore/bundle": "^5.0.0", @@ -2575,13 +2608,6 @@ "node": "^22.22.2 || ^24.15.0 || >=26.0.0" } }, - "node_modules/@standard-schema/spec": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/@standard-schema/spec/-/spec-1.1.0.tgz", - "integrity": "sha512-l2aFy5jALhniG5HgqrD6jXLi/rUWrKvqN/qJx6yoJsgKhblVd+iqqU4RCXavm/jPityDo5TCvKMnpjKnOriy0w==", - "dev": true, - "license": "MIT" - }, "node_modules/@tufjs/canonical-json": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/@tufjs/canonical-json/-/canonical-json-2.0.0.tgz", @@ -2605,12 +2631,11 @@ } }, "node_modules/@tybys/wasm-util": { - "version": "0.10.3", - "resolved": "https://registry.npmjs.org/@tybys/wasm-util/-/wasm-util-0.10.3.tgz", - "integrity": "sha512-F3fo1MYrRJYL3zER0OUOmkutjr1Vp23m7OsSgp7nq4SP6OqX6C/56XFIPAl5bt3zaBRjmW7SGz3u/6LwFpYcOg==", + "version": "0.10.4", + "resolved": "https://registry.npmjs.org/@tybys/wasm-util/-/wasm-util-0.10.4.tgz", + "integrity": "sha512-W3c4gRigFS0T/Ma4qIYF3GDAc5AQdHb1yL5znJT1Zv1YaD9Kitx656wBjvr19qbiosmZT8lWDM5BEMynUqX65A==", "dev": true, "license": "MIT", - "optional": true, "dependencies": { "tslib": "^2.4.0" } @@ -2695,13 +2720,13 @@ } }, "node_modules/@types/node": { - "version": "24.13.3", - "resolved": "https://registry.npmjs.org/@types/node/-/node-24.13.3.tgz", - "integrity": "sha512-Dh8vAsV36ig5wa9OX4pXvMc9D3Veibfw2wix0CUwYODLD8nkj9UsLjASr49nPg+2eKzxhBV+v7L8pXvT4e639Q==", + "version": "24.19.1", + "resolved": "https://registry.npmjs.org/@types/node/-/node-24.19.1.tgz", + "integrity": "sha512-aS3/DG0oM05K0RIXXP+hKjinGG5IgSSVGzswZxW3O0sS3pH4/fycXundUC9XsszgKCk4gHXylTEK6hyFxVxnoQ==", "dev": true, "license": "MIT", "dependencies": { - "undici-types": "~7.18.0" + "undici-types": ">=7.24.0 <7.24.7" } }, "node_modules/@types/sax": { @@ -2722,17 +2747,17 @@ "license": "MIT" }, "node_modules/@typescript-eslint/eslint-plugin": { - "version": "8.65.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-8.65.0.tgz", - "integrity": "sha512-IEgob78X12rHpUmtcwFsXhZdVGJtwTVP8FiCLZkR6GlYVrl2PcuB+KhCE5BlVC/eQpQnu8WXRtkHZuPar+gCRA==", + "version": "8.71.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-8.71.1.tgz", + "integrity": "sha512-nNlBf6HuotqMgZvSkWD5hNdemiBIxQ2NmrlgfcUIeZRs+BbakjscCQRq/Hb74EFVnFiSWWdL12JruqwBy3ERDw==", "dev": true, "license": "MIT", "dependencies": { "@eslint-community/regexpp": "^4.12.2", - "@typescript-eslint/scope-manager": "8.65.0", - "@typescript-eslint/type-utils": "8.65.0", - "@typescript-eslint/utils": "8.65.0", - "@typescript-eslint/visitor-keys": "8.65.0", + "@typescript-eslint/scope-manager": "8.71.1", + "@typescript-eslint/type-utils": "8.71.1", + "@typescript-eslint/utils": "8.71.1", + "@typescript-eslint/visitor-keys": "8.71.1", "ignore": "^7.0.5", "natural-compare": "^1.4.0", "ts-api-utils": "^2.5.0" @@ -2745,15 +2770,15 @@ "url": "https://opencollective.com/typescript-eslint" }, "peerDependencies": { - "@typescript-eslint/parser": "^8.65.0", + "@typescript-eslint/parser": "^8.71.1", "eslint": "^8.57.0 || ^9.0.0 || ^10.0.0", "typescript": ">=4.8.4 <6.1.0" } }, "node_modules/@typescript-eslint/eslint-plugin/node_modules/ignore": { - "version": "7.0.6", - "resolved": "https://registry.npmjs.org/ignore/-/ignore-7.0.6.tgz", - "integrity": "sha512-BAg6QkE8W+TuQLrrw0Ugr7HegXduRuuj8/ti2kSOc+jz1dmx8/WNcjr6XGnq5YpDWxFwwaavqD0+jIUOKelTsw==", + "version": "7.0.12", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-7.0.12.tgz", + "integrity": "sha512-/8UvqAPU9DGTI9k4mxtf49U37Isfwr8Uts96+SBHIkFxPJnHS0Ew4f00sM4Scd8V8EjM0jUNtVDdv1kPdt35lg==", "dev": true, "license": "MIT", "engines": { @@ -2761,16 +2786,16 @@ } }, "node_modules/@typescript-eslint/parser": { - "version": "8.65.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-8.65.0.tgz", - "integrity": "sha512-CZ4nMxWwgu1HEEFNkeaCptra9QCtkmKdgf3sWh1rl1trIhmxLilgTV4cwcbQ4wemnT4sWQN8CaKOmdYx+g2gMA==", + "version": "8.71.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-8.71.1.tgz", + "integrity": "sha512-oM/5sAqz/l1v/zYK1qTOPrn2+JIrBGC1V6uNYucRO5gh6eT9vWJ/RhPbGE59byvZEUQ4VP6XkLBaS5Jti5jpvw==", "dev": true, "license": "MIT", "dependencies": { - "@typescript-eslint/scope-manager": "8.65.0", - "@typescript-eslint/types": "8.65.0", - "@typescript-eslint/typescript-estree": "8.65.0", - "@typescript-eslint/visitor-keys": "8.65.0", + "@typescript-eslint/scope-manager": "8.71.1", + "@typescript-eslint/types": "8.71.1", + "@typescript-eslint/typescript-estree": "8.71.1", + "@typescript-eslint/visitor-keys": "8.71.1", "debug": "^4.4.3" }, "engines": { @@ -2786,14 +2811,14 @@ } }, "node_modules/@typescript-eslint/project-service": { - "version": "8.65.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/project-service/-/project-service-8.65.0.tgz", - "integrity": "sha512-SxnPhbTsGahizDgbu7oqFH/xVtzIqMd/s+WtnSxNxJZJpLbdT5IPdzg8EZxO3+PoKahXmwJLeNQOpKJb3/bi7Q==", + "version": "8.71.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/project-service/-/project-service-8.71.1.tgz", + "integrity": "sha512-Oijc9RUsohHjncg6iGi7gCtjnEjYt9FWv9u6ygK8uKcHK5eLjLAkqERQ9BaytbpceOFdk6kifPCS/zAZE+A99g==", "dev": true, "license": "MIT", "dependencies": { - "@typescript-eslint/tsconfig-utils": "^8.65.0", - "@typescript-eslint/types": "^8.65.0", + "@typescript-eslint/tsconfig-utils": "^8.71.1", + "@typescript-eslint/types": "^8.71.1", "debug": "^4.4.3" }, "engines": { @@ -2808,14 +2833,14 @@ } }, "node_modules/@typescript-eslint/scope-manager": { - "version": "8.65.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-8.65.0.tgz", - "integrity": "sha512-Esbl8OSYiVxBokYgWPf7VVWg/BE798wXhimnn9ML9Pt5qoDf8bfQlgjlKXR/k98+AcNzlLKYrpCcrcuZ9DZLgg==", + "version": "8.71.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-8.71.1.tgz", + "integrity": "sha512-1YUDZXdTnXLlob03SFHBipdyMBsDVm7zoSz0ytTJ39dk5J1TgsTK03VlR/dLXG/RLLUrPcYbD4rp23BmHxHP0w==", "dev": true, "license": "MIT", "dependencies": { - "@typescript-eslint/types": "8.65.0", - "@typescript-eslint/visitor-keys": "8.65.0" + "@typescript-eslint/types": "8.71.1", + "@typescript-eslint/visitor-keys": "8.71.1" }, "engines": { "node": "^18.18.0 || ^20.9.0 || >=21.1.0" @@ -2826,9 +2851,9 @@ } }, "node_modules/@typescript-eslint/tsconfig-utils": { - "version": "8.65.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/tsconfig-utils/-/tsconfig-utils-8.65.0.tgz", - "integrity": "sha512-j6GzGqCiRdA7Qhur2VVmKZAkBLfnHFQfx4TaJGL9RMveZqCo48jSHHO0DTgizEnGhtWnqmbtCUSrqSkdiY/0Hg==", + "version": "8.71.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/tsconfig-utils/-/tsconfig-utils-8.71.1.tgz", + "integrity": "sha512-oTvkml5SxXhgg+WWKhod5qWQICDXtOB+/Hi9VdPKFAANJ2b7YOgMffgvzXuqog7R6A/JtrzRf128dsxummyWhg==", "dev": true, "license": "MIT", "engines": { @@ -2843,15 +2868,15 @@ } }, "node_modules/@typescript-eslint/type-utils": { - "version": "8.65.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-8.65.0.tgz", - "integrity": "sha512-YjaZ7PRI5qY7ax2L3PbvX0rRyGtipAReCWs0mhhDBHjH/vl0g0BonaGXrKdKpMbIIsMIwDgbk/xzkBTyAltS5g==", + "version": "8.71.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-8.71.1.tgz", + "integrity": "sha512-kH3t3jZCYv2PZSBEWPKTariLrCaoF1CLoPitYFBJOhAGEwWnSRAtGEifrfrpBa4K9JlwWNZotgA5w3/wLSk/FQ==", "dev": true, "license": "MIT", "dependencies": { - "@typescript-eslint/types": "8.65.0", - "@typescript-eslint/typescript-estree": "8.65.0", - "@typescript-eslint/utils": "8.65.0", + "@typescript-eslint/types": "8.71.1", + "@typescript-eslint/typescript-estree": "8.71.1", + "@typescript-eslint/utils": "8.71.1", "debug": "^4.4.3", "ts-api-utils": "^2.5.0" }, @@ -2868,9 +2893,9 @@ } }, "node_modules/@typescript-eslint/types": { - "version": "8.65.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-8.65.0.tgz", - "integrity": "sha512-JSSwWNy+H0E/01jJEM+hrX6N0OFDzFzeIhHFSAS01tlVaevpG8cFyYRPhS5yjGOvBUx3sqQHVMjCL1CAZZMxBg==", + "version": "8.71.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-8.71.1.tgz", + "integrity": "sha512-ybYnPTUwg3VQQOFEiBPLs8Jxl1ry2vXdn1kVKguomBbvxpetdu3MKTNDqFNUrlG8ylP9MpZosmXMFYlGQHk1oQ==", "dev": true, "license": "MIT", "engines": { @@ -2882,16 +2907,16 @@ } }, "node_modules/@typescript-eslint/typescript-estree": { - "version": "8.65.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-8.65.0.tgz", - "integrity": "sha512-JboAE2swaYt4tb1fHhHTABE2K+OLy09XfcTbhnk4Pw96f9dd2e9iYsJ28gBggHlo5z5x1rkyWvcPoTuNTd4oGg==", + "version": "8.71.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-8.71.1.tgz", + "integrity": "sha512-pSKSEK1JJpHs6KiKVtABCE4iJK5d7FLFzDXQNBQ2oRY7LEd3UwOt3TZemTgu9syTIf56dJWlTn/pdmrO9oKUXQ==", "dev": true, "license": "MIT", "dependencies": { - "@typescript-eslint/project-service": "8.65.0", - "@typescript-eslint/tsconfig-utils": "8.65.0", - "@typescript-eslint/types": "8.65.0", - "@typescript-eslint/visitor-keys": "8.65.0", + "@typescript-eslint/project-service": "8.71.1", + "@typescript-eslint/tsconfig-utils": "8.71.1", + "@typescript-eslint/types": "8.71.1", + "@typescript-eslint/visitor-keys": "8.71.1", "debug": "^4.4.3", "minimatch": "^10.2.2", "semver": "^7.7.3", @@ -2910,16 +2935,16 @@ } }, "node_modules/@typescript-eslint/utils": { - "version": "8.65.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-8.65.0.tgz", - "integrity": "sha512-gXiwIHsYreboxeJucHKPvgwl7dXt50mF8s1/c00cP/WoVTyWKFdtfhRWwZiXYFU5H2O8vVoSLNrexFZjYS/SGA==", + "version": "8.71.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-8.71.1.tgz", + "integrity": "sha512-CBjT6gfAz3DW2j9Q4moFnqt208Aq+506sVGXfpRcyAeqn0EpayL0mjdWoCO2t3RC7GewNrFxdeehuEaPg6DMzQ==", "dev": true, "license": "MIT", "dependencies": { "@eslint-community/eslint-utils": "^4.9.1", - "@typescript-eslint/scope-manager": "8.65.0", - "@typescript-eslint/types": "8.65.0", - "@typescript-eslint/typescript-estree": "8.65.0" + "@typescript-eslint/scope-manager": "8.71.1", + "@typescript-eslint/types": "8.71.1", + "@typescript-eslint/typescript-estree": "8.71.1" }, "engines": { "node": "^18.18.0 || ^20.9.0 || >=21.1.0" @@ -2934,13 +2959,13 @@ } }, "node_modules/@typescript-eslint/visitor-keys": { - "version": "8.65.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-8.65.0.tgz", - "integrity": "sha512-8C71BQkGjiMmXtop7pHVJu1l2NNShFdkCyD6a2ezzs5vU/L3LRtb69EtcteFwz0mYMPzIgOw0n6OV4VBUWZd7A==", + "version": "8.71.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-8.71.1.tgz", + "integrity": "sha512-0GxiUGqMU0qXJt58cBsiG3DP8lUmBaFo2vChtUX+CT7PnR3v/VGLLrzVP4K9r1lNiZXjHYefMBbPunplr09v6w==", "dev": true, "license": "MIT", "dependencies": { - "@typescript-eslint/types": "8.65.0", + "@typescript-eslint/types": "8.71.1", "eslint-visitor-keys": "^5.0.0" }, "engines": { @@ -2952,36 +2977,34 @@ } }, "node_modules/@ungap/structured-clone": { - "version": "1.3.3", - "resolved": "https://registry.npmjs.org/@ungap/structured-clone/-/structured-clone-1.3.3.tgz", - "integrity": "sha512-60YRaenCQcVjYEKOcG824+DRGGIQ3VKErcBoAEDJZz5bKIs2ZG+X/H9Nk+Q6EVkwJk5QNApxbrc5QtBSwtrXAg==", + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/@ungap/structured-clone/-/structured-clone-1.4.0.tgz", + "integrity": "sha512-1mEZtMKPM09vDmQt5y7YvmN2+DFTP7Tg0EWXdic8/C6VRnpb33e4ghisCIE3WZjsE2N8mf+QV1Zqh7ZFYLWInQ==", "dev": true, "license": "ISC" }, "node_modules/@vitest/coverage-v8": { - "version": "4.1.10", - "resolved": "https://registry.npmjs.org/@vitest/coverage-v8/-/coverage-v8-4.1.10.tgz", - "integrity": "sha512-IM49HmthevbgAO4anp1hwtoT9wYe59w0LR00gr+eagHE+ZJ5lK4sLPeO0ubgoJcwLk6dehU3R24N+FbEEKDc8g==", + "version": "5.0.3", + "resolved": "https://registry.npmjs.org/@vitest/coverage-v8/-/coverage-v8-5.0.3.tgz", + "integrity": "sha512-+klsyz7BvT1vCU28Zkfzms1Ia78XD0V41U3FUtRaa3S+vOr/EXvK1O6BvVD7l1RzEjm6SONR2aybOvDDf9u0mQ==", "dev": true, "license": "MIT", "dependencies": { "@bcoe/v8-coverage": "^1.0.2", - "@vitest/utils": "4.1.10", - "ast-v8-to-istanbul": "^1.0.0", - "istanbul-lib-coverage": "^3.2.2", - "istanbul-lib-report": "^3.0.1", - "istanbul-reports": "^3.2.0", - "magicast": "^0.5.2", - "obug": "^2.1.1", - "std-env": "^4.0.0-rc.1", - "tinyrainbow": "^3.1.0" + "@vitest/istanbul-lib-coverage": "^1.0.0", + "@vitest/istanbul-lib-report": "^1.0.0", + "ast-v8-to-istanbul": "^1.0.5", + "magicast": "^0.5.4", + "obug": "^2.1.4", + "std-env": "^4.2.0", + "tinyrainbow": "^3.1.1" }, "funding": { "url": "https://opencollective.com/vitest" }, "peerDependencies": { - "@vitest/browser": "4.1.10", - "vitest": "4.1.10" + "@vitest/browser": "5.0.3", + "vitest": "5.0.3" }, "peerDependenciesMeta": { "@vitest/browser": { @@ -2989,34 +3012,40 @@ } } }, - "node_modules/@vitest/expect": { - "version": "4.1.10", - "resolved": "https://registry.npmjs.org/@vitest/expect/-/expect-4.1.10.tgz", - "integrity": "sha512-YsCn+qAk1GWjQOWFEsEcL2gNQ0zmVmQu3T03qP6UyjhtmdtwtbuI+DASn/7iQB3HGTXkdBwGddzxPlmiql5vlA==", + "node_modules/@vitest/istanbul-lib-coverage": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/@vitest/istanbul-lib-coverage/-/istanbul-lib-coverage-1.0.2.tgz", + "integrity": "sha512-9J/JMwOf9AoJhAywhrn7ScKTL38hsWQP/qPG60OtaAFcQ5OXPwKsxZFlbnuCKmZ61m8/lGgHYnFpdyQZUvG/iA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=22" + } + }, + "node_modules/@vitest/istanbul-lib-report": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/@vitest/istanbul-lib-report/-/istanbul-lib-report-1.0.2.tgz", + "integrity": "sha512-gUsfXZJbzPamoIY5TvHFiMMoXESBrUMo+xqaj+rYrWI69+EnvRlYBlP96ZnHPY4vX8kyUpgAnFUCg5wZG/HkDQ==", "dev": true, "license": "MIT", "dependencies": { - "@standard-schema/spec": "^1.1.0", - "@types/chai": "^5.2.2", - "@vitest/spy": "4.1.10", - "@vitest/utils": "4.1.10", - "chai": "^6.2.2", - "tinyrainbow": "^3.1.0" + "@vitest/istanbul-lib-coverage": "1.0.2" }, - "funding": { - "url": "https://opencollective.com/vitest" + "engines": { + "node": ">=22" } }, "node_modules/@vitest/mocker": { - "version": "4.1.10", - "resolved": "https://registry.npmjs.org/@vitest/mocker/-/mocker-4.1.10.tgz", - "integrity": "sha512-v0xaezt+DKEmKfaxg133ldzADrwLGd7Ze1MfQQTYfvs8OqZIwbxyxaYURivwV7sWy5fqn3rH5uOrSp07bp44Ow==", + "version": "5.0.3", + "resolved": "https://registry.npmjs.org/@vitest/mocker/-/mocker-5.0.3.tgz", + "integrity": "sha512-T8sWAIbkSyAjkwTcaEc3Iu0o9A27X1/kdXrizhZkGuSKScRQtRzclfAMpOTcGdXCsqxeWlpGy3XjqaW8CpLORg==", "dev": true, "license": "MIT", "dependencies": { - "@vitest/spy": "4.1.10", + "@jridgewell/trace-mapping": "0.3.31", + "@vitest/spy": "5.0.3", "estree-walker": "^3.0.3", - "magic-string": "^0.30.21" + "magic-string": "^1.2.3" }, "funding": { "url": "https://opencollective.com/vitest" @@ -3034,70 +3063,12 @@ } } }, - "node_modules/@vitest/pretty-format": { - "version": "4.1.10", - "resolved": "https://registry.npmjs.org/@vitest/pretty-format/-/pretty-format-4.1.10.tgz", - "integrity": "sha512-W1HsjSH4MXQ9YfmmhLAoIYf1HRfekQCGngeIgcei6MP5QQGWUe0gkopdZQaVCFO+JDJMrAJGwa5pRpNpvy4P8Q==", - "dev": true, - "license": "MIT", - "dependencies": { - "tinyrainbow": "^3.1.0" - }, - "funding": { - "url": "https://opencollective.com/vitest" - } - }, - "node_modules/@vitest/runner": { - "version": "4.1.10", - "resolved": "https://registry.npmjs.org/@vitest/runner/-/runner-4.1.10.tgz", - "integrity": "sha512-IKI6kpIH+LmpROplyLwBBaCfMgOZOMsygVa6BARD6ahA04VRuJSa6OaVG7kRvSEMD870Vd91rSSw0eegtWyLGg==", - "dev": true, - "license": "MIT", - "dependencies": { - "@vitest/utils": "4.1.10", - "pathe": "^2.0.3" - }, - "funding": { - "url": "https://opencollective.com/vitest" - } - }, - "node_modules/@vitest/snapshot": { - "version": "4.1.10", - "resolved": "https://registry.npmjs.org/@vitest/snapshot/-/snapshot-4.1.10.tgz", - "integrity": "sha512-xRkfOT1qpTAi/Ti4Y1LtfRc3kEuqxGw59eN2jN9pRWMtS/XDevekhcFSqvQqjUNGksfjMJu3Y+oJ+4Ypn2OaJw==", - "dev": true, - "license": "MIT", - "dependencies": { - "@vitest/pretty-format": "4.1.10", - "@vitest/utils": "4.1.10", - "magic-string": "^0.30.21", - "pathe": "^2.0.3" - }, - "funding": { - "url": "https://opencollective.com/vitest" - } - }, "node_modules/@vitest/spy": { - "version": "4.1.10", - "resolved": "https://registry.npmjs.org/@vitest/spy/-/spy-4.1.10.tgz", - "integrity": "sha512-PLf/Ugvoq5wO/b4rwYCR1h2PSIdXz7wnkQFMiUpLdtM7l6pqVFcQIBEHyT1+l+cj7mNwAfZHzqXqDyjvOuwbDw==", - "dev": true, - "license": "MIT", - "funding": { - "url": "https://opencollective.com/vitest" - } - }, - "node_modules/@vitest/utils": { - "version": "4.1.10", - "resolved": "https://registry.npmjs.org/@vitest/utils/-/utils-4.1.10.tgz", - "integrity": "sha512-fy9am/HWxbaGt/Sawrp90vt6Y6jQwf1RX77cz3uwoJwJVMli/e1IEwRPnMNJ7vKfPTwo0diXifkpPvwH9v7nGA==", + "version": "5.0.3", + "resolved": "https://registry.npmjs.org/@vitest/spy/-/spy-5.0.3.tgz", + "integrity": "sha512-XhFysQTB8AZ+P4gMi+Lpo99vg2AZi0qKpaB9yXQl37+CaMEAPO3iH/wGVnSyL5MPERiLezpqTVtrR6UZH5GCXg==", "dev": true, "license": "MIT", - "dependencies": { - "@vitest/pretty-format": "4.1.10", - "convert-source-map": "^2.0.0", - "tinyrainbow": "^3.1.0" - }, "funding": { "url": "https://opencollective.com/vitest" } @@ -3208,9 +3179,9 @@ "license": "MIT" }, "node_modules/acorn": { - "version": "8.17.0", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.17.0.tgz", - "integrity": "sha512-xRQbDb9BnwDafYNn6Vwl839DYVjqXYb1XVGtWAZ1kcDc6iwAL4hg3B1dZlRiuENFeO2H53gFG3in621AdERVAg==", + "version": "8.19.0", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.19.0.tgz", + "integrity": "sha512-oJlA3XiRm7Cyk6qFD2Jn8ak9B7jSy0qy00ADO3+8dpT0LSjFihQYv4C02LFCSYJV3Q37xYwwRy5m+IpIiUzqWw==", "dev": true, "license": "MIT", "bin": { @@ -3248,9 +3219,9 @@ } }, "node_modules/am-i-vibing": { - "version": "0.4.0", - "resolved": "https://registry.npmjs.org/am-i-vibing/-/am-i-vibing-0.4.0.tgz", - "integrity": "sha512-MxT4XZL7pzLHpuvhDKdMaQHMGGkJDLluKBLsbstn+8wv9sWcFT6h+0ve9qkml95amVTZtZV83gQe2hY+ojgHLg==", + "version": "0.5.0", + "resolved": "https://registry.npmjs.org/am-i-vibing/-/am-i-vibing-0.5.0.tgz", + "integrity": "sha512-KLcsDhqf1XRrJmJr+9I/C0EX2K+sGrAGZFgkmd84c8TJO9zJBu+/kFInjazu1KfJWFhWDKdRWkpBzEs7s35DVA==", "dev": true, "license": "MIT", "dependencies": { @@ -3261,26 +3232,26 @@ } }, "node_modules/ansi-regex": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", - "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "version": "6.4.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.4.0.tgz", + "integrity": "sha512-KzTVk2tCWAHtYrvvvaP8bJKJq2pVinhLcGEQdtLIYPbmNGNyYe8QwNaTUYQp2J7/vIsUKt5QCqAfUkYyG9DkOw==", "dev": true, "license": "MIT", "engines": { - "node": ">=8" + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/ansi-regex?sponsor=1" } }, "node_modules/ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "version": "6.2.3", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-6.2.3.tgz", + "integrity": "sha512-4Dj6M28JB+oAH8kFkTLUo+a2jwOFkuqb3yucU0CANcRRUbxS0cP0nZYCGjcc3BNXwRIsUVmDGgzawme7zvJHvg==", "dev": true, "license": "MIT", - "dependencies": { - "color-convert": "^2.0.1" - }, "engines": { - "node": ">=8" + "node": ">=12" }, "funding": { "url": "https://github.com/chalk/ansi-styles?sponsor=1" @@ -3320,13 +3291,6 @@ "dev": true, "license": "MIT" }, - "node_modules/argparse": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", - "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", - "dev": true, - "license": "Python-2.0" - }, "node_modules/aria-query": { "version": "5.3.2", "resolved": "https://registry.npmjs.org/aria-query/-/aria-query-5.3.2.tgz", @@ -3348,9 +3312,9 @@ } }, "node_modules/ast-v8-to-istanbul": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/ast-v8-to-istanbul/-/ast-v8-to-istanbul-1.0.5.tgz", - "integrity": "sha512-UPAgKJFSEGMWSDr3LX4tqnAb4f7KGT8O40Tyx8wbYmmZ/yn58lNCm8h3svs3eXgiGd5AXxz8NDOvXWvicq+rJA==", + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/ast-v8-to-istanbul/-/ast-v8-to-istanbul-1.0.7.tgz", + "integrity": "sha512-kFL68AG6ajd8fg248zwM9GQrUWEp79gsmjum34OEXjs4yHuUMZfYKwOLW9GMmB4oNvVrj+EAGxsP7ye2UR9UlA==", "dev": true, "license": "MIT", "dependencies": { @@ -3360,65 +3324,65 @@ } }, "node_modules/astro": { - "version": "7.1.3", - "resolved": "https://registry.npmjs.org/astro/-/astro-7.1.3.tgz", - "integrity": "sha512-4dhPyAAXthf3xLEYnG8SeL7yr/nTPPABfY7e9YF0yuO+vK9Xp+8Q5j4xzsmL3GueukQv4oNwGNTBepLOiDGeJA==", + "version": "7.3.6", + "resolved": "https://registry.npmjs.org/astro/-/astro-7.3.6.tgz", + "integrity": "sha512-3q0MKxfE4cpr5IoQ9EWrN0gwxeT5tkCaSVe3SrGlLR5fnTIywHqjVqFokQkQiZexfwpNtB9dtBdUcXV9FuD+4w==", "dev": true, "license": "MIT", "dependencies": { - "@astrojs/compiler-rs": "^0.3.1", - "@astrojs/internal-helpers": "0.10.1", - "@astrojs/markdown-satteri": "0.3.4", + "@astrojs/compiler-rs": "^0.5.1", + "@astrojs/internal-helpers": "0.12.0", + "@astrojs/markdown-satteri": "0.4.3", "@astrojs/telemetry": "3.3.3", - "@capsizecss/unpack": "^4.0.0", - "@clack/prompts": "^1.1.0", + "@capsizecss/unpack": "^4.0.1", + "@clack/prompts": "^1.8.1", "@oslojs/encoding": "^1.1.0", - "@rollup/pluginutils": "^5.3.0", - "am-i-vibing": "^0.4.0", + "am-i-vibing": "^0.5.0", "aria-query": "^5.3.2", "axobject-query": "^4.1.0", "ci-info": "^4.4.0", "clsx": "^2.1.1", "common-ancestor-path": "^2.0.0", "cookie": "^2.0.1", - "devalue": "^5.8.1", - "diff": "^8.0.3", + "devalue": "^5.9.4", + "diff": "^9.0.0", "dset": "^3.1.4", - "es-module-lexer": "^2.0.0", + "es-module-lexer": "^3.0.2", "esbuild": "^0.28.0", + "find-proc": "0.2.0", "flattie": "^1.1.1", "fontace": "~0.4.1", - "get-tsconfig": "5.0.0-beta.4", + "get-tsconfig": "5.0.0-beta.6", "github-slugger": "^2.0.0", "html-escaper": "3.0.3", "http-cache-semantics": "^4.2.0", - "js-yaml": "^4.1.1", "jsonc-parser": "^3.3.1", - "magic-string": "^0.30.21", - "magicast": "^0.5.2", + "magic-string": "^1.4.2", + "magicast": "^0.5.5", "mrmime": "^2.0.1", "neotraverse": "^1.0.1", - "obug": "^2.1.1", - "p-limit": "^7.3.0", - "p-queue": "^9.1.0", - "package-manager-detector": "^1.6.0", + "obug": "^3.0.0", + "p-limit": "^7.3.3", + "p-queue": "^9.3.3", + "package-manager-detector": "^1.8.0", "piccolore": "^0.1.3", - "picomatch": "^4.0.4", - "semver": "^7.7.4", - "shiki": "^4.0.2", - "smol-toml": "^1.6.0", - "svgo": "^4.0.1", - "tinyclip": "^0.1.12", - "tinyexec": "^1.0.4", - "tinyglobby": "^0.2.15", - "ultrahtml": "^1.6.0", - "unifont": "~0.7.4", + "picomatch": "^4.0.7", + "rolldown": "^1.2.11", + "shiki": "^4.4.3", + "smol-toml": "^1.9.0", + "svgo": "^4.1.0", + "tinyclip": "^1.0.3", + "tinyexec": "^1.3.1", + "tinyglobby": "^0.2.17", + "ultrahtml": "^1.7.0", + "unifont": "~0.7.5", "unstorage": "^1.17.5", - "vite": "^8.0.13", - "vitefu": "^1.1.2", + "verkit": "^0.5.0", + "vite": "^8.3.1", + "vitefu": "^1.1.3", "xxhash-wasm": "^1.1.0", "yargs-parser": "^22.0.0", - "zod": "^4.3.6" + "zod": "^4.6.5" }, "bin": { "astro": "bin/astro.mjs" @@ -3433,10 +3397,10 @@ "url": "https://opencollective.com/astrodotbuild" }, "optionalDependencies": { - "sharp": "^0.34.0 || ^0.35.0" + "sharp": "^0.35.4" }, "peerDependencies": { - "@astrojs/markdown-remark": "7.2.1" + "@astrojs/markdown-remark": "^7.3.0" }, "peerDependenciesMeta": { "@astrojs/markdown-remark": { @@ -3444,10 +3408,31 @@ } } }, + "node_modules/astro/node_modules/es-module-lexer": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/es-module-lexer/-/es-module-lexer-3.0.3.tgz", + "integrity": "sha512-yWGe1O/j+almnV4hOYrmZo8u58JdnmXEMneRQAYkWtqSiT86yoMIEKF4rpqEDj52tbYl3xceBD3DQIBwcsC9Pw==", + "dev": true, + "license": "MIT" + }, + "node_modules/astro/node_modules/obug": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/obug/-/obug-3.0.0.tgz", + "integrity": "sha512-5vvB5+W7ePv+p3uqxi+RcW1XAzLW0/hxt3/4X4Lc4qHudzOhmBiBwOY6DRob4WnanAEGvNcLjF+KNOufrUoEQw==", + "dev": true, + "funding": [ + "https://github.com/sponsors/sxzz", + "https://opencollective.com/debug" + ], + "license": "MIT", + "engines": { + "node": ">=12.20.0" + } + }, "node_modules/axe-core": { - "version": "4.12.1", - "resolved": "https://registry.npmjs.org/axe-core/-/axe-core-4.12.1.tgz", - "integrity": "sha512-s7iGf5GaVMxEG0ENN9x+xTr7GFZCb1ZP/1uATUpCEK2X78nDB3RwbtFCo9pGAf9ru+VwoQ464DkaLEeRM08wJA==", + "version": "4.13.0", + "resolved": "https://registry.npmjs.org/axe-core/-/axe-core-4.13.0.tgz", + "integrity": "sha512-UzGt8zg7Ny8djbYMhxl2zuEevVa7r2gJjYY5Lwr1xM7+XU2nd6CkIWFTVcCIbAP63vSz71NaVyyuSk9lHKcy0A==", "dev": true, "license": "MPL-2.0", "engines": { @@ -3492,9 +3477,9 @@ "license": "ISC" }, "node_modules/brace-expansion": { - "version": "5.0.8", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-5.0.8.tgz", - "integrity": "sha512-JZyDyq3D4AUifKTPOB7DELf6XsB3WdPuNxCtob1vFXPsSXhdAiHBWJ/tJ8HAc9aH84BK+5JFZLNkJKx3G9kzQg==", + "version": "5.0.12", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-5.0.12.tgz", + "integrity": "sha512-YovQ3rzhaLMIrDjNDMkNS01tea93qhEhG5xy8f6+R0l+dw3Ki+5sCoIoI942iuLZTHWogWktgwVDhU09iNEimQ==", "license": "MIT", "dependencies": { "balanced-match": "^4.0.2" @@ -3503,6 +3488,20 @@ "node": "20 || >=22" } }, + "node_modules/cacheable": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/cacheable/-/cacheable-2.5.0.tgz", + "integrity": "sha512-60cyAOytib/OzBw1JNSoSV/boK1AtHryDIjvVBk7XbN4ugfkM3+Sry7fEjNgPMGgOjuaZPAp8ruZ0Cxafwyq9g==", + "dev": true, + "license": "MIT", + "dependencies": { + "@cacheable/memory": "^2.2.0", + "@cacheable/utils": "^2.5.0", + "hookified": "^1.15.0", + "keyv": "^5.6.0", + "qified": "^0.10.1" + } + }, "node_modules/ccount": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/ccount/-/ccount-2.0.1.tgz", @@ -3515,9 +3514,9 @@ } }, "node_modules/chai": { - "version": "6.2.2", - "resolved": "https://registry.npmjs.org/chai/-/chai-6.2.2.tgz", - "integrity": "sha512-NUPRluOfOiTKBKvWPtSD4PhFvWCqOi0BGStNWs57X9js7XGTprSmFoz5F0tWhR4WPjNeR9jXqdC7/UpSJTnlRg==", + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/chai/-/chai-6.3.0.tgz", + "integrity": "sha512-XWAtwJ6OHO+tj0EKCs0Y2UamnyOxseZWltU4x2U2wh8g4AigdjwvtUjvLP2tqkA/avxHEtzxNaqGq/YGNwckKg==", "dev": true, "license": "MIT", "engines": { @@ -3579,50 +3578,48 @@ } }, "node_modules/cliui": { - "version": "8.0.1", - "resolved": "https://registry.npmjs.org/cliui/-/cliui-8.0.1.tgz", - "integrity": "sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ==", + "version": "9.0.1", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-9.0.1.tgz", + "integrity": "sha512-k7ndgKhwoQveBL+/1tqGJYNz097I7WOvwbmmU2AR5+magtbjPWQTS1C5vzGkBC8Ym8UWRzfKUzUUqFLypY4Q+w==", "dev": true, "license": "ISC", "dependencies": { - "string-width": "^4.2.0", - "strip-ansi": "^6.0.1", - "wrap-ansi": "^7.0.0" + "string-width": "^7.2.0", + "strip-ansi": "^7.1.0", + "wrap-ansi": "^9.0.0" }, "engines": { - "node": ">=12" + "node": ">=20" } }, - "node_modules/clsx": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/clsx/-/clsx-2.1.1.tgz", - "integrity": "sha512-eYm0QWBtUrBWZWG0d386OGAw16Z995PiOVo2B7bjWSbHedGl5e0ZWaq65kOGgUSNesEIDkB9ISbTg/JK9dhCZA==", + "node_modules/cliui/node_modules/string-width": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-7.2.0.tgz", + "integrity": "sha512-tsaTIkKW9b4N+AEj+SVA+WhJzV7/zMhcSu78mLKWSk7cXMOSHsBKFWUs0fWwq8QyK3MgJBQRX6Gbi4kYbdvGkQ==", "dev": true, "license": "MIT", + "dependencies": { + "emoji-regex": "^10.3.0", + "get-east-asian-width": "^1.0.0", + "strip-ansi": "^7.1.0" + }, "engines": { - "node": ">=6" + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "node_modules/clsx": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/clsx/-/clsx-2.1.1.tgz", + "integrity": "sha512-eYm0QWBtUrBWZWG0d386OGAw16Z995PiOVo2B7bjWSbHedGl5e0ZWaq65kOGgUSNesEIDkB9ISbTg/JK9dhCZA==", "dev": true, "license": "MIT", - "dependencies": { - "color-name": "~1.1.4" - }, "engines": { - "node": ">=7.0.0" + "node": ">=6" } }, - "node_modules/color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true, - "license": "MIT" - }, "node_modules/comma-separated-tokens": { "version": "2.0.3", "resolved": "https://registry.npmjs.org/comma-separated-tokens/-/comma-separated-tokens-2.0.3.tgz", @@ -3654,13 +3651,6 @@ "node": ">= 18" } }, - "node_modules/convert-source-map": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-2.0.0.tgz", - "integrity": "sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==", - "dev": true, - "license": "MIT" - }, "node_modules/cookie": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/cookie/-/cookie-2.0.1.tgz", @@ -3708,17 +3698,17 @@ } }, "node_modules/css-select": { - "version": "5.2.2", - "resolved": "https://registry.npmjs.org/css-select/-/css-select-5.2.2.tgz", - "integrity": "sha512-TizTzUddG/xYLA3NXodFM0fSbNizXjOKhqiQQwvhlspadZokn1KDy0NZFS0wuEubIYAV5/c1/lAr0TaaFXEXzw==", + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/css-select/-/css-select-6.0.0.tgz", + "integrity": "sha512-rZZVSLle8v0+EY8QAkDWrKhpgt6SA5OtHsgBnsj6ZaLb5dmDVOWUDtQitd9ydxxvEjhewNudS6eTVU7uOyzvXw==", "dev": true, "license": "BSD-2-Clause", "dependencies": { "boolbase": "^1.0.0", - "css-what": "^6.1.0", - "domhandler": "^5.0.2", - "domutils": "^3.0.1", - "nth-check": "^2.0.1" + "css-what": "^7.0.0", + "domhandler": "^5.0.3", + "domutils": "^3.2.2", + "nth-check": "^2.1.1" }, "funding": { "url": "https://github.com/sponsors/fb55" @@ -3739,9 +3729,9 @@ } }, "node_modules/css-what": { - "version": "6.2.2", - "resolved": "https://registry.npmjs.org/css-what/-/css-what-6.2.2.tgz", - "integrity": "sha512-u/O3vwbptzhMs3L1fQE82ZSLHQQfto5gyZzwteVIEyeaY5Fc7R4dapF/BvRoSYFeqfBk4m0V1Vafq5Pjv25wvA==", + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/css-what/-/css-what-7.0.0.tgz", + "integrity": "sha512-wD5oz5xibMOPHzy13CyGmogB3phdvcDaB5t0W/Nr5Z2O/agcB8YwOz6e2Lsp10pNDzBoDO9nVa3RGs/2BttpHQ==", "dev": true, "license": "BSD-2-Clause", "engines": { @@ -3846,9 +3836,9 @@ } }, "node_modules/devalue": { - "version": "5.8.2", - "resolved": "https://registry.npmjs.org/devalue/-/devalue-5.8.2.tgz", - "integrity": "sha512-DObPPAfdtFbXjxLqK8s2Xk9ZuWz5+ZoFEhC7J76es4GU/rEiXwHTmbImoCdyoCOcBH1UF3+Cz6Z2sYD4hyl5TA==", + "version": "5.9.4", + "resolved": "https://registry.npmjs.org/devalue/-/devalue-5.9.4.tgz", + "integrity": "sha512-sPAT4pztbu6586/hrhOnMKS17IJrvg12mXiSPSS3W5qDeN2RGgvZ0diZCm31dBbnevfVmujNO3IM2wrS4Y2Rhg==", "dev": true, "license": "MIT" }, @@ -3867,9 +3857,9 @@ } }, "node_modules/diff": { - "version": "8.0.4", - "resolved": "https://registry.npmjs.org/diff/-/diff-8.0.4.tgz", - "integrity": "sha512-DPi0FmjiSU5EvQV0++GFDOJ9ASQUVFh5kD+OzOnYdi7n3Wpm9hWWGfB/O2blfHcMVTL5WkQXSnRiK9makhrcnw==", + "version": "9.0.0", + "resolved": "https://registry.npmjs.org/diff/-/diff-9.0.0.tgz", + "integrity": "sha512-svtcdpS8CgJyqAjEQIXdb3OjhFVVYjzGAPO8WGCmRbrml64SPw/jJD4GoE98aR7r25A0XcgrK3F02yw9R/vhQw==", "dev": true, "license": "BSD-3-Clause", "engines": { @@ -3976,16 +3966,16 @@ } }, "node_modules/emoji-regex": { - "version": "8.0.0", - "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", - "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", + "version": "10.6.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-10.6.0.tgz", + "integrity": "sha512-toUI84YS5YmxW219erniWD0CIVOo46xGKColeNQRgOzDorgBi1v4D71/OFzgD9GO2UGKIv1C3Sp8DAn0+j5w7A==", "dev": true, "license": "MIT" }, "node_modules/entities": { - "version": "8.0.0", - "resolved": "https://registry.npmjs.org/entities/-/entities-8.0.0.tgz", - "integrity": "sha512-zwfzJecQ/Uej6tusMqwAqU/6KL2XaB2VZ2Jg54Je6ahNBGNH6Ek6g3jjNCF0fG9EWQKGZNddNjU5F1ZQn/sBnA==", + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/entities/-/entities-8.1.0.tgz", + "integrity": "sha512-kxL7msIffSuh9aaFAMD7rxAIuTRMAHMeBtgHW2yUdWw732ZNh4MehkF2gdjvtdmikkaIP9bFDDJOPlsvm7avrA==", "license": "BSD-2-Clause", "engines": { "node": ">=20.19.0" @@ -3995,16 +3985,16 @@ } }, "node_modules/es-module-lexer": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/es-module-lexer/-/es-module-lexer-2.3.1.tgz", - "integrity": "sha512-shc1dbU90Yl/xq1QrC7QRtfcwURZuVRfPhZbDoldJ1cn1gzDvBaBWlv0eFolj5+0znnPJz5TXLxsN77X/12KTA==", + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/es-module-lexer/-/es-module-lexer-2.3.2.tgz", + "integrity": "sha512-poHGpORABojJJucnV9KbOavETW8lBVnphkW77ER5/BQ5Fz7oXSoCNek7IH3vR5nRjdsEz926ibFYX8KtLQmdyw==", "dev": true, "license": "MIT" }, "node_modules/esbuild": { - "version": "0.28.1", - "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.28.1.tgz", - "integrity": "sha512-HrJrvZv5ayxBzPfwphOoNzkzOIIlifzk0KJrGK2c8R4+LKpMtpYLQeUdjnwjWv/LZlkH2laZk+4w78pi99D4Vw==", + "version": "0.28.2", + "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.28.2.tgz", + "integrity": "sha512-HKVLS8dvII+xoKW9kmqxbRKrnWEXfJJr/FZhhJmiqIB0e053QNYFqOBouTMO/k5sID4MvCiUCvv8b9M4h32wIA==", "dev": true, "hasInstallScript": true, "license": "MIT", @@ -4015,32 +4005,32 @@ "node": ">=18" }, "optionalDependencies": { - "@esbuild/aix-ppc64": "0.28.1", - "@esbuild/android-arm": "0.28.1", - "@esbuild/android-arm64": "0.28.1", - "@esbuild/android-x64": "0.28.1", - "@esbuild/darwin-arm64": "0.28.1", - "@esbuild/darwin-x64": "0.28.1", - "@esbuild/freebsd-arm64": "0.28.1", - "@esbuild/freebsd-x64": "0.28.1", - "@esbuild/linux-arm": "0.28.1", - "@esbuild/linux-arm64": "0.28.1", - "@esbuild/linux-ia32": "0.28.1", - "@esbuild/linux-loong64": "0.28.1", - "@esbuild/linux-mips64el": "0.28.1", - "@esbuild/linux-ppc64": "0.28.1", - "@esbuild/linux-riscv64": "0.28.1", - "@esbuild/linux-s390x": "0.28.1", - "@esbuild/linux-x64": "0.28.1", - "@esbuild/netbsd-arm64": "0.28.1", - "@esbuild/netbsd-x64": "0.28.1", - "@esbuild/openbsd-arm64": "0.28.1", - "@esbuild/openbsd-x64": "0.28.1", - "@esbuild/openharmony-arm64": "0.28.1", - "@esbuild/sunos-x64": "0.28.1", - "@esbuild/win32-arm64": "0.28.1", - "@esbuild/win32-ia32": "0.28.1", - "@esbuild/win32-x64": "0.28.1" + "@esbuild/aix-ppc64": "0.28.2", + "@esbuild/android-arm": "0.28.2", + "@esbuild/android-arm64": "0.28.2", + "@esbuild/android-x64": "0.28.2", + "@esbuild/darwin-arm64": "0.28.2", + "@esbuild/darwin-x64": "0.28.2", + "@esbuild/freebsd-arm64": "0.28.2", + "@esbuild/freebsd-x64": "0.28.2", + "@esbuild/linux-arm": "0.28.2", + "@esbuild/linux-arm64": "0.28.2", + "@esbuild/linux-ia32": "0.28.2", + "@esbuild/linux-loong64": "0.28.2", + "@esbuild/linux-mips64el": "0.28.2", + "@esbuild/linux-ppc64": "0.28.2", + "@esbuild/linux-riscv64": "0.28.2", + "@esbuild/linux-s390x": "0.28.2", + "@esbuild/linux-x64": "0.28.2", + "@esbuild/netbsd-arm64": "0.28.2", + "@esbuild/netbsd-x64": "0.28.2", + "@esbuild/openbsd-arm64": "0.28.2", + "@esbuild/openbsd-x64": "0.28.2", + "@esbuild/openharmony-arm64": "0.28.2", + "@esbuild/sunos-x64": "0.28.2", + "@esbuild/win32-arm64": "0.28.2", + "@esbuild/win32-ia32": "0.28.2", + "@esbuild/win32-x64": "0.28.2" } }, "node_modules/escalade": { @@ -4067,9 +4057,9 @@ } }, "node_modules/eslint": { - "version": "10.8.0", - "resolved": "https://registry.npmjs.org/eslint/-/eslint-10.8.0.tgz", - "integrity": "sha512-nuKKvN+oIBO0koN7Tm7dlkmnkc21mtt0QJLwAKzjLq14y6lRTdVG36MZHJ8eQHwdJMwZbQNMlPOYedMq/oVJvQ==", + "version": "10.12.0", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-10.12.0.tgz", + "integrity": "sha512-npHjrHb2o4ehH3mE+YuxABR+0gyb0aVWCIolgJDArwCiHEIsonBm3ZKjel5b0U5+a+MbEvIyRCGCzD3eKKK2NA==", "dev": true, "license": "MIT", "workspaces": [ @@ -4081,7 +4071,7 @@ "@eslint/config-array": "^0.23.5", "@eslint/config-helpers": "^0.7.0", "@eslint/core": "^1.2.1", - "@eslint/plugin-kit": "^0.7.2", + "@eslint/plugin-kit": "^0.7.3", "@humanfs/node": "^0.16.6", "@humanwhocodes/module-importer": "^1.0.1", "@humanwhocodes/retry": "^0.4.2", @@ -4096,7 +4086,7 @@ "esquery": "^1.7.0", "esutils": "^2.0.2", "fast-deep-equal": "^3.1.3", - "file-entry-cache": "^8.0.0", + "file-entry-cache": "11.1.5 || >11.1.6 <12", "find-up": "^5.0.0", "glob-parent": "^6.0.2", "ignore": "^5.2.0", @@ -4294,9 +4284,9 @@ } }, "node_modules/fast-uri": { - "version": "3.1.4", - "resolved": "https://registry.npmjs.org/fast-uri/-/fast-uri-3.1.4.tgz", - "integrity": "sha512-8JnbkQ4juDyvYs4mgFGQqg4yCYtFDtUtmp2QIQq11ZZe5CFQ5wcqm1rqDgAh/QdMySuBnPzMUiJUNZG5N/AiQw==", + "version": "3.1.8", + "resolved": "https://registry.npmjs.org/fast-uri/-/fast-uri-3.1.8.tgz", + "integrity": "sha512-GZMtZUTNRpOVIECoXwLNZS5xUGE+mVNbTB8h/7Rwh2TFWcBQiPzTgyZi05BF9UMZKkLJv8XBRJTlU7zg8+ZfMg==", "dev": true, "funding": [ { @@ -4339,16 +4329,23 @@ } }, "node_modules/file-entry-cache": { - "version": "8.0.0", - "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-8.0.0.tgz", - "integrity": "sha512-XXTUwCvisa5oacNGRP9SfNtYBNAMi+RPwBFmblZEF7N7swHYQS6/Zfk7SRwx4D5j3CH211YNRco1DEMNVfZCnQ==", + "version": "11.1.5", + "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-11.1.5.tgz", + "integrity": "sha512-+PFTHITI08JIGhnNpGNI8T8inUpgZfk3GNEqfT9R2zZV2iFXg3CvqzSl/uEhs7TSGujYRELEANyDvS8Fj7+S7Q==", "dev": true, "license": "MIT", "dependencies": { - "flat-cache": "^4.0.0" - }, + "flat-cache": "^6.1.23" + } + }, + "node_modules/find-proc": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/find-proc/-/find-proc-0.2.0.tgz", + "integrity": "sha512-a6h2nTrgB3g5Wrn4au9Ux4kMk7IJtyF6oA8uGn+mk3weLZssUtc1cp6meHIzzuW2o1srrBAxzkmXLbqjRkgB6w==", + "dev": true, + "license": "MIT", "engines": { - "node": ">=16.0.0" + "node": "^20.19.0 || >=22.12.0" } }, "node_modules/find-up": { @@ -4369,23 +4366,21 @@ } }, "node_modules/flat-cache": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-4.0.1.tgz", - "integrity": "sha512-f7ccFPK3SXFHpx15UIGyRJ/FJQctuKZ0zVuN3frBo4HnK3cay9VEW0R6yPYFHC0AgqhukPzKjq22t5DmAyqGyw==", + "version": "6.1.23", + "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-6.1.23.tgz", + "integrity": "sha512-f++BY9pTk+983xK1FLzlLpmM0i0z+jHmx3QESGkURMXujQZz1k5wzwX6hjnQ8goaD0B+sYnDK1yZ6MTyZfUaqA==", "dev": true, "license": "MIT", "dependencies": { - "flatted": "^3.2.9", - "keyv": "^4.5.4" - }, - "engines": { - "node": ">=16" + "cacheable": "^2.5.0", + "flatted": "^3.4.2", + "hookified": "^1.15.0" } }, "node_modules/flatted": { - "version": "3.4.3", - "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.4.3.tgz", - "integrity": "sha512-/zipXxyO6rGvuNGDiULY9MvEGSkb2gaG4GGH4ygMi0ZZzyMHdUZBmntJmx5x1G2VuPytCwGN4xsJP6cw+sK+vQ==", + "version": "3.4.4", + "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.4.4.tgz", + "integrity": "sha512-5+ybhBZANEJxaH3X5evAFatUxLfEHSr7n6kYJ+1Qd0mUqr4eu9gIf6GDbWHf8RJijHrjjO8G+la14SlL2SeS1Q==", "dev": true, "license": "ISC" }, @@ -4423,9 +4418,9 @@ } }, "node_modules/fsevents": { - "version": "2.3.2", - "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.2.tgz", - "integrity": "sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==", + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", + "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==", "dev": true, "hasInstallScript": true, "license": "MIT", @@ -4447,10 +4442,23 @@ "node": "6.* || 8.* || >= 10.*" } }, + "node_modules/get-east-asian-width": { + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/get-east-asian-width/-/get-east-asian-width-1.7.0.tgz", + "integrity": "sha512-XjH1AECxf0giL2V1aU8vKyRR2ppRUb5c0EvT7zuJTokQ74bNo52zOtghqdWIqrhUD79fo3x0WfKZdOqxF6LG1Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/get-tsconfig": { - "version": "5.0.0-beta.4", - "resolved": "https://registry.npmjs.org/get-tsconfig/-/get-tsconfig-5.0.0-beta.4.tgz", - "integrity": "sha512-7nF7C9fIPFEMHgEMEfgIlO9wDdZ8CyHw27rWciFZfHvHDReIiPhsYuzPRXsfvBCqFy1l8RRyyWV7QLM+ZhUJsQ==", + "version": "5.0.0-beta.6", + "resolved": "https://registry.npmjs.org/get-tsconfig/-/get-tsconfig-5.0.0-beta.6.tgz", + "integrity": "sha512-X6fBC0pmImC70gvX2zm56go9hx0MyoGVdG0tUCkg/D+Xnh5TJsOZ7iDbOdI3PvmtrDxnu1YdDufpK2QJX1Meqw==", "dev": true, "license": "MIT", "dependencies": { @@ -4501,94 +4509,17 @@ "uncrypto": "^0.1.3" } }, - "node_modules/has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=8" - } - }, - "node_modules/hast-util-from-html": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/hast-util-from-html/-/hast-util-from-html-2.0.3.tgz", - "integrity": "sha512-CUSRHXyKjzHov8yKsQjGOElXy/3EKpyX56ELnkHH34vDVw1N1XSQ1ZcAvTyAPtGqLTuKP/uxM+aLkSPqF/EtMw==", + "node_modules/hashery": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/hashery/-/hashery-1.5.1.tgz", + "integrity": "sha512-iZyKG96/JwPz1N55vj2Ie2vXbhu440zfUfJvSwEqEbeLluk7NnapfGqa7LH0mOsnDxTF85Mx8/dyR6HfqcbmbQ==", "dev": true, "license": "MIT", "dependencies": { - "@types/hast": "^3.0.0", - "devlop": "^1.1.0", - "hast-util-from-parse5": "^8.0.0", - "parse5": "^7.0.0", - "vfile": "^6.0.0", - "vfile-message": "^4.0.0" + "hookified": "^1.15.0" }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/unified" - } - }, - "node_modules/hast-util-from-html/node_modules/entities": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/entities/-/entities-6.0.1.tgz", - "integrity": "sha512-aN97NXWF6AWBTahfVOIrB/NShkzi5H7F9r1s9mD3cDj4Ko5f2qhhVoYMibXF7GlLveb/D2ioWay8lxI97Ven3g==", - "dev": true, - "license": "BSD-2-Clause", "engines": { - "node": ">=0.12" - }, - "funding": { - "url": "https://github.com/fb55/entities?sponsor=1" - } - }, - "node_modules/hast-util-from-html/node_modules/parse5": { - "version": "7.3.0", - "resolved": "https://registry.npmjs.org/parse5/-/parse5-7.3.0.tgz", - "integrity": "sha512-IInvU7fabl34qmi9gY8XOVxhYyMyuH2xUNpb2q8/Y+7552KlejkRvqvD19nMoUW/uQGGbqNpA6Tufu5FL5BZgw==", - "dev": true, - "license": "MIT", - "dependencies": { - "entities": "^6.0.0" - }, - "funding": { - "url": "https://github.com/inikulin/parse5?sponsor=1" - } - }, - "node_modules/hast-util-from-parse5": { - "version": "8.0.3", - "resolved": "https://registry.npmjs.org/hast-util-from-parse5/-/hast-util-from-parse5-8.0.3.tgz", - "integrity": "sha512-3kxEVkEKt0zvcZ3hCRYI8rqrgwtlIOFMWkbclACvjlDw8Li9S2hk/d51OI0nr/gIpdMHNepwgOKqZ/sy0Clpyg==", - "dev": true, - "license": "MIT", - "dependencies": { - "@types/hast": "^3.0.0", - "@types/unist": "^3.0.0", - "devlop": "^1.0.0", - "hastscript": "^9.0.0", - "property-information": "^7.0.0", - "vfile": "^6.0.0", - "vfile-location": "^5.0.0", - "web-namespaces": "^2.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/unified" - } - }, - "node_modules/hast-util-parse-selector": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/hast-util-parse-selector/-/hast-util-parse-selector-4.0.0.tgz", - "integrity": "sha512-wkQCkSYoOGCRKERFWcxMVMOcYE2K1AaNLU8DXS9arxnLOUEWbOXKXiJUNzEpqZ3JOKpnha3jkFrumEjVliDe7A==", - "dev": true, - "license": "MIT", - "dependencies": { - "@types/hast": "^3.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/unified" + "node": ">=20" } }, "node_modules/hast-util-to-html": { @@ -4629,23 +4560,12 @@ "url": "https://opencollective.com/unified" } }, - "node_modules/hastscript": { - "version": "9.0.1", - "resolved": "https://registry.npmjs.org/hastscript/-/hastscript-9.0.1.tgz", - "integrity": "sha512-g7df9rMFX/SPi34tyGCyUBREQoKkapwdY/T04Qn9TDWfHhAYt4/I0gMVirzK5wEzeUqIjEB+LXC/ypb7Aqno5w==", + "node_modules/hookified": { + "version": "1.15.1", + "resolved": "https://registry.npmjs.org/hookified/-/hookified-1.15.1.tgz", + "integrity": "sha512-MvG/clsADq1GPM2KGo2nyfaWVyn9naPiXrqIe4jYjXNZQt238kWyOGrsyc/DmRAQ+Re6yeo6yX/yoNCG5KAEVg==", "dev": true, - "license": "MIT", - "dependencies": { - "@types/hast": "^3.0.0", - "comma-separated-tokens": "^2.0.0", - "hast-util-parse-selector": "^4.0.0", - "property-information": "^7.0.0", - "space-separated-tokens": "^2.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/unified" - } + "license": "MIT" }, "node_modules/html-escaper": { "version": "3.0.3", @@ -4666,9 +4586,9 @@ } }, "node_modules/http-cache-semantics": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/http-cache-semantics/-/http-cache-semantics-4.2.0.tgz", - "integrity": "sha512-dTxcvPXqPvXBQpq5dUr6mEMJX4oIEFv6bwom3FDwKRDsuIjjJGANqhBuoAn9c1RQJIdAKav33ED65E2ys+87QQ==", + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/http-cache-semantics/-/http-cache-semantics-4.3.0.tgz", + "integrity": "sha512-M5t5LlJpS1UHMjvwRQVdFHvPISGeLAxNcrWuJkeGh0KxsqCHZ1O3NXZU/8x7cD0BDcGW8kapxMKTvwlqrNkHkA==", "dev": true, "license": "BSD-2-Clause" }, @@ -4728,16 +4648,6 @@ "node": ">=0.10.0" } }, - "node_modules/is-fullwidth-code-point": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", - "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=8" - } - }, "node_modules/is-glob": { "version": "4.0.3", "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", @@ -4771,52 +4681,6 @@ "dev": true, "license": "ISC" }, - "node_modules/istanbul-lib-coverage": { - "version": "3.2.2", - "resolved": "https://registry.npmjs.org/istanbul-lib-coverage/-/istanbul-lib-coverage-3.2.2.tgz", - "integrity": "sha512-O8dpsF+r0WV/8MNRKfnmrtCWhuKjxrq2w+jpzBL5UZKTi2LeVWnWOmWRxFlesJONmc+wLAGvKQZEOanko0LFTg==", - "dev": true, - "license": "BSD-3-Clause", - "engines": { - "node": ">=8" - } - }, - "node_modules/istanbul-lib-report": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/istanbul-lib-report/-/istanbul-lib-report-3.0.1.tgz", - "integrity": "sha512-GCfE1mtsHGOELCU8e/Z7YWzpmybrx/+dSTfLrvY8qRmaY6zXTKWn6WQIjaAFw069icm6GVMNkgu0NzI4iPZUNw==", - "dev": true, - "license": "BSD-3-Clause", - "dependencies": { - "istanbul-lib-coverage": "^3.0.0", - "make-dir": "^4.0.0", - "supports-color": "^7.1.0" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/istanbul-reports": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/istanbul-reports/-/istanbul-reports-3.2.0.tgz", - "integrity": "sha512-HGYWWS/ehqTV3xN10i23tkPkpH46MLCIMFNCaaKNavAXTF1RkqxawEPtnjnGZ6XKSInBKkiOA5BKS+aZiY3AvA==", - "dev": true, - "license": "BSD-3-Clause", - "dependencies": { - "html-escaper": "^2.0.0", - "istanbul-lib-report": "^3.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/istanbul-reports/node_modules/html-escaper": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/html-escaper/-/html-escaper-2.0.2.tgz", - "integrity": "sha512-H2iMtd0I4Mt5eYiapRdIDjp+XzelXQ0tFE4JS7YFwFevXXMmOp9myNrUvCg0D6ws8iqkRPBfKHgbwig1SmlLfg==", - "dev": true, - "license": "MIT" - }, "node_modules/js-tokens": { "version": "10.0.0", "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-10.0.0.tgz", @@ -4824,36 +4688,6 @@ "dev": true, "license": "MIT" }, - "node_modules/js-yaml": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.3.0.tgz", - "integrity": "sha512-1td788aAnnZ5qs7V2QIRl1owjtYpbKt749Y3xauqQgwIIGF/xXWz1wMTEBx5O3LK3lXLVuqXPdPxj2BoFHaW9Q==", - "dev": true, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/puzrin" - }, - { - "type": "github", - "url": "https://github.com/sponsors/nodeca" - } - ], - "license": "MIT", - "dependencies": { - "argparse": "^2.0.1" - }, - "bin": { - "js-yaml": "bin/js-yaml.js" - } - }, - "node_modules/json-buffer": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/json-buffer/-/json-buffer-3.0.1.tgz", - "integrity": "sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ==", - "dev": true, - "license": "MIT" - }, "node_modules/json-schema-traverse": { "version": "0.4.1", "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", @@ -4876,13 +4710,13 @@ "license": "MIT" }, "node_modules/keyv": { - "version": "4.5.4", - "resolved": "https://registry.npmjs.org/keyv/-/keyv-4.5.4.tgz", - "integrity": "sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw==", + "version": "5.6.0", + "resolved": "https://registry.npmjs.org/keyv/-/keyv-5.6.0.tgz", + "integrity": "sha512-CYDD3SOtsHtyXeEORYRx2qBtpDJFjRTGXUtmNEMGyzYOKj1TE3tycdlho7kA1Ufx9OYWZzg52QFBGALTirzDSw==", "dev": true, "license": "MIT", "dependencies": { - "json-buffer": "3.0.1" + "@keyv/serialize": "^1.1.1" } }, "node_modules/kleur": { @@ -5199,9 +5033,9 @@ } }, "node_modules/lru-cache": { - "version": "11.5.2", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-11.5.2.tgz", - "integrity": "sha512-4pfM1Ff0x50o0tQwb5ucw/RzNyD0/YJME6IVcStalZuMWxdt3sR3huStTtxz4PUmvZfRguvDejasvQ2kifR11g==", + "version": "11.5.3", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-11.5.3.tgz", + "integrity": "sha512-U4N8FgzmWxc8k1VH8Kr6lQg18U7Fjvby6wXHVRX/ZZ7IwWbRMgrRbP0Wrb5q5NVinryp4SQampHKdvtecItxUg==", "dev": true, "license": "BlueOak-1.0.0", "engines": { @@ -5209,43 +5043,27 @@ } }, "node_modules/magic-string": { - "version": "0.30.21", - "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.21.tgz", - "integrity": "sha512-vd2F4YUyEXKGcLHoq+TEyCjxueSeHnFxyyjNp80yg0XV4vUhnDer/lvvlqM/arB5bXQN5K2/3oinyCRyx8T2CQ==", + "version": "1.4.3", + "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-1.4.3.tgz", + "integrity": "sha512-z12OxmaPGE0F4xlpGdjuAUckipLpQlTAuAmyGhNoD7ODpYUzvDfvtxUbjM/jwznyP178oju/KDdyi220wNJ0RQ==", "dev": true, "license": "MIT", "dependencies": { - "@jridgewell/sourcemap-codec": "^1.5.5" + "@jridgewell/sourcemap-codec": "^1.6.0" } }, "node_modules/magicast": { - "version": "0.5.3", - "resolved": "https://registry.npmjs.org/magicast/-/magicast-0.5.3.tgz", - "integrity": "sha512-pVKE4UdSQ7DvHzivsCIFx2BJn1mHG6KsyrFcaxFx6tONdneEuThrDx0Cj3AMg58KyN4pzYT+LHOotxDQDjNvkw==", + "version": "0.5.5", + "resolved": "https://registry.npmjs.org/magicast/-/magicast-0.5.5.tgz", + "integrity": "sha512-UicdXN8zQ3JHlxVq+28afMXPr1z7WNY6+7EJnzTdQWkTAlMLF5fNCCKxJHBQwGaNGR11581EiQmQzx73+MvszA==", "dev": true, "license": "MIT", "dependencies": { - "@babel/parser": "^7.29.3", - "@babel/types": "^7.29.0", + "@babel/parser": "^7.29.7", + "@babel/types": "^7.29.7", "source-map-js": "^1.2.1" } }, - "node_modules/make-dir": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-4.0.0.tgz", - "integrity": "sha512-hXdUTZYIVOt1Ex//jAQi+wTZZpUpwBj/0QsOzqegb3rGMMeJiSEu5xLHnYfBrRV4RH2+OCSOO95Is/7x1WJ4bw==", - "dev": true, - "license": "MIT", - "dependencies": { - "semver": "^7.5.3" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, "node_modules/mdast-util-to-hast": { "version": "13.2.1", "resolved": "https://registry.npmjs.org/mdast-util-to-hast/-/mdast-util-to-hast-13.2.1.tgz", @@ -5353,9 +5171,9 @@ "license": "MIT" }, "node_modules/micromark-util-types": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/micromark-util-types/-/micromark-util-types-2.0.2.tgz", - "integrity": "sha512-Yw0ECSpJoViF1qTU4DC6NwtC4aWGt1EkzaQB8KPPyCRR8z9TWeV0HbEFGTO+ZY1wB22zmxnJqhPyTpOVCpeHTA==", + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/micromark-util-types/-/micromark-util-types-2.0.3.tgz", + "integrity": "sha512-oxB2Ik03hI0gv+VNn9tnh1t1YEe9MDPptViAEgfdf3YQHsn0pzGTgCdlSCJXcwhqm8phaEuM7zeEu3QQzVBrPg==", "dev": true, "funding": [ { @@ -5370,12 +5188,12 @@ "license": "MIT" }, "node_modules/minimatch": { - "version": "10.2.5", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-10.2.5.tgz", - "integrity": "sha512-MULkVLfKGYDFYejP07QOurDLLQpcjk7Fw+7jXS2R2czRQzR56yHRveU5NDJEOviH+hETZKSkIk5c+T23GjFUMg==", + "version": "10.2.6", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-10.2.6.tgz", + "integrity": "sha512-vpLQEs+VLCr1nU0BXS07maYoFwlDAH0gngQuuttxIwutDFEMHq2blX+8vpgxDdK3J1PwjCJiep77OitTZ4Ll1A==", "license": "BlueOak-1.0.0", "dependencies": { - "brace-expansion": "^5.0.5" + "brace-expansion": "^5.0.8" }, "engines": { "node": "18 || 20 || >=22" @@ -5408,9 +5226,9 @@ "license": "MIT" }, "node_modules/nanoid": { - "version": "3.3.16", - "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.16.tgz", - "integrity": "sha512-bzlKTyNJ7+LdGIIwy8ijFpIqEQIvafahV7eYykJ8Cvh42EdJeODoJ6gUJXpQJvej1BddH8OqTXZNE/KfbWAu8Q==", + "version": "3.3.20", + "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.20.tgz", + "integrity": "sha512-uKdg2G3GNCKQn9byYOpxbGqrT2fGO5KRt5J/8b3pok8rT6qxGWF6hxMyJiEYtAf+FVyYuD9hRaDqX5uPFYJ4ZQ==", "dev": true, "funding": [ { @@ -5465,9 +5283,9 @@ "license": "MIT" }, "node_modules/node-mock-http": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/node-mock-http/-/node-mock-http-1.0.4.tgz", - "integrity": "sha512-8DY+kFsDkNXy1sJglUfuODx1/opAGJGyrTuFqEoN90oRc2Vk0ZbD4K2qmKXBBEhZQzdKHIVfEJpDU8Ak2NJEvQ==", + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/node-mock-http/-/node-mock-http-1.0.5.tgz", + "integrity": "sha512-KQyt/wLjG3TAc7DOUhpqWzgd4ERxR80JOlTK5VE5R1S12IaPVN5qkj4klBce9HPG1Njuup4Sb5bljaT34lIyjw==", "dev": true, "license": "MIT" }, @@ -5495,9 +5313,9 @@ } }, "node_modules/obug": { - "version": "2.1.4", - "resolved": "https://registry.npmjs.org/obug/-/obug-2.1.4.tgz", - "integrity": "sha512-4a+OsYv9UktOJKE+l1A4OufDgdRF9PifWj+tJnHURo/P+WOxpG4GzUFL9qCalmWauao6ogiG+QvnCovwPoyAWA==", + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/obug/-/obug-2.2.1.tgz", + "integrity": "sha512-XrsrhT5sybtKI6wakr2SPOlGZWWYbUXZ7a0jT8/QOeAPau+1X/bSegNe5YR75oJmEZQbKningirmGOEJCIk61Q==", "dev": true, "funding": [ "https://github.com/sponsors/sxzz", @@ -5521,9 +5339,9 @@ } }, "node_modules/ohash": { - "version": "2.0.11", - "resolved": "https://registry.npmjs.org/ohash/-/ohash-2.0.11.tgz", - "integrity": "sha512-RdR9FQrFwNBNXAr4GixM8YaRZRJ5PUWbKYbE5eOsrwAjJW0q2REGcf79oYPsLyskQCZG1PLN+S/K1V00joZAoQ==", + "version": "2.0.12", + "resolved": "https://registry.npmjs.org/ohash/-/ohash-2.0.12.tgz", + "integrity": "sha512-65S/5gk9YSsaRjcyf7Nfa6h/d3E8/1gslpXfI4W7Dxn/oap8IKRuNT5VXkLQ1YFKIEg4apRY4Pj6aiwFzrDdmw==", "dev": true, "license": "MIT" }, @@ -5565,9 +5383,9 @@ } }, "node_modules/p-limit": { - "version": "7.3.1", - "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-7.3.1.tgz", - "integrity": "sha512-0trZaiG7Y7kN/Egy9a8j47t9osC0Tch4PaIWd9yGF6bvmlk7muExRvGNYb8sXBwEKMoNKsbNN9P8EefuQekE4Q==", + "version": "7.3.3", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-7.3.3.tgz", + "integrity": "sha512-SKgVvDU5TNIxQ4r30U75BNLC6a+6GOEjngrk/ysM5+Zu3oJuk1SC5ApzIzY/7PjCEjoVPMWJ0zho/4QUiEB7TQ==", "dev": true, "license": "MIT", "dependencies": { @@ -5643,9 +5461,9 @@ } }, "node_modules/p-timeout": { - "version": "7.0.1", - "resolved": "https://registry.npmjs.org/p-timeout/-/p-timeout-7.0.1.tgz", - "integrity": "sha512-AxTM2wDGORHGEkPCt8yqxOTMgpfbEHqF51f/5fJCmwFC3C/zNcGT63SymH2ttOAaiIws2zVg4+izQCjrakcwHg==", + "version": "7.0.2", + "resolved": "https://registry.npmjs.org/p-timeout/-/p-timeout-7.0.2.tgz", + "integrity": "sha512-prbX4Z3YszrFNgH+MW5Zoeq3baXrMtP/MQnFeET90UB/GtGcGDQ5Usg9OCy6ETjTTntOw1SL2z9fMPUppN3Guw==", "dev": true, "license": "MIT", "engines": { @@ -5656,9 +5474,9 @@ } }, "node_modules/package-manager-detector": { - "version": "1.8.0", - "resolved": "https://registry.npmjs.org/package-manager-detector/-/package-manager-detector-1.8.0.tgz", - "integrity": "sha512-yQA4H19AmPEoMUeavPMDIe1higySl/gH/yaQrkT/s07Qp+7pp2hYz30N3z2l5BkjVkF9Ow6o0wjJamm2y7Sn0A==", + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/package-manager-detector/-/package-manager-detector-1.9.0.tgz", + "integrity": "sha512-zAMfbta9nPA8AKkA4WdmNAT8R8s6Dk0/xwPsqNnRidMFcLo1YkLuPDTgs2f64XdzS8vbLNnoJ+uUIkgbz7oRHA==", "dev": true, "license": "MIT" }, @@ -5701,13 +5519,6 @@ "node": ">=8" } }, - "node_modules/pathe": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/pathe/-/pathe-2.0.3.tgz", - "integrity": "sha512-WUjGcAqP1gQacoQe+OBJsFA7Ld4DyXuUIjZ5cc75cLHvJ7dtNsTugphxIADwspS+AraAUePCKrSVtPLFj/F88w==", - "dev": true, - "license": "MIT" - }, "node_modules/piccolore": { "version": "0.1.3", "resolved": "https://registry.npmjs.org/piccolore/-/piccolore-0.1.3.tgz", @@ -5723,9 +5534,9 @@ "license": "ISC" }, "node_modules/picomatch": { - "version": "4.0.5", - "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.5.tgz", - "integrity": "sha512-RvwwcruNjI1ncT5xRakeyS9Lf8lcItv34KD+aif+VH9kduAyfYBipGh12274xtenIPZ119/R9BdTBa8gAwSh0A==", + "version": "4.0.7", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.7.tgz", + "integrity": "sha512-qcJu88Q2IWqJsDD529JKMdwGm/dvInW4HvQnRwiH9JtihJvzGOscDtHE3x1pBKeUOTysQ8kVmLnJ2kJu7yhcGA==", "dev": true, "license": "MIT", "engines": { @@ -5736,28 +5547,25 @@ } }, "node_modules/playwright": { - "version": "1.62.0", - "resolved": "https://registry.npmjs.org/playwright/-/playwright-1.62.0.tgz", - "integrity": "sha512-Z14dG305dgaLu6foB1TXQagFiW8JfSUIUaUuPaKQ6NtBPKF1P/qXcqfh6c6K/icPqdy37JmjbiBXf6JNg6Sylw==", + "version": "1.63.0", + "resolved": "https://registry.npmjs.org/playwright/-/playwright-1.63.0.tgz", + "integrity": "sha512-+7ziBLidS4NaNCdt57SUDT+wYmmd5fmiQejUic/kb+YsYSCPyOOE9sebzMjNmQrsnNpDJqd4WHvV/8lfKfUDUg==", "dev": true, "license": "Apache-2.0", "dependencies": { - "playwright-core": "1.62.0" + "playwright-core": "1.63.0" }, "bin": { "playwright": "cli.js" }, "engines": { "node": ">=20" - }, - "optionalDependencies": { - "fsevents": "2.3.2" } }, "node_modules/playwright-core": { - "version": "1.62.0", - "resolved": "https://registry.npmjs.org/playwright-core/-/playwright-core-1.62.0.tgz", - "integrity": "sha512-nsNRyq0r2zsG8AcRHWknc9QRA5XCueC7gWMrs+Gx2tlZn9hcl8zudfh00lhJPY1DE7NmZ6bDsT9g2yey8mXljA==", + "version": "1.63.0", + "resolved": "https://registry.npmjs.org/playwright-core/-/playwright-core-1.63.0.tgz", + "integrity": "sha512-rYCsBF/M5HjUch52bbtVONEFjv6Xu8sm8h72dNlR5bzIE1fvC/bxgspzkjSfU+MweEMmPM8KJebG6nnyxo5mCg==", "dev": true, "license": "Apache-2.0", "bin": { @@ -5768,9 +5576,9 @@ } }, "node_modules/postcss": { - "version": "8.5.22", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.22.tgz", - "integrity": "sha512-KBDEIpLrvpv16pp3K0Fw+UCoZfopFjjgeB+0tA/aaThfEE74kKDLrgg603YvOWJyg3+WYtyq3xYsQWsIyZlPqQ==", + "version": "8.5.29", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.29.tgz", + "integrity": "sha512-49cGhUbXj8Qenv0iTMxA1cFBzxXoctpC9Ujd77t1WcbJIr6nF/eI7g/8MgxrYldFRuAXvja7xQRwavoW7kgrxQ==", "dev": true, "funding": [ { @@ -5788,9 +5596,9 @@ ], "license": "MIT", "dependencies": { - "nanoid": "^3.3.16", + "nanoid": "^3.3.19", "picocolors": "^1.1.1", - "source-map-js": "^1.2.1" + "source-map-js": "^1.2.2" }, "engines": { "node": "^10 || ^12 || >=14" @@ -5807,9 +5615,9 @@ } }, "node_modules/prettier": { - "version": "3.9.6", - "resolved": "https://registry.npmjs.org/prettier/-/prettier-3.9.6.tgz", - "integrity": "sha512-OpN0zzVdiaiAhxpuuj5efpIS4sY9j7bY6uR5mnj5yPzGkdkjNKSJeUThPb60Jw29QuAZgA4o+/iB49kFiaBX6g==", + "version": "3.9.9", + "resolved": "https://registry.npmjs.org/prettier/-/prettier-3.9.9.tgz", + "integrity": "sha512-Z/CJHIkdujO/OtN7nXUii0Rf3VT5SRuhjBA82Xvu2XhBUgX3nhP67T0LHceBdQLex7OOFGTox+Q5Yg8Jk2Qivg==", "dev": true, "license": "MIT", "bin": { @@ -5823,38 +5631,258 @@ } }, "node_modules/prettier-plugin-astro": { - "version": "0.14.1", - "resolved": "https://registry.npmjs.org/prettier-plugin-astro/-/prettier-plugin-astro-0.14.1.tgz", - "integrity": "sha512-RiBETaaP9veVstE4vUwSIcdATj6dKmXljouXc/DDNwBSPTp8FRkLGDSGFClKsAFeeg+13SB0Z1JZvbD76bigJw==", + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/prettier-plugin-astro/-/prettier-plugin-astro-1.1.0.tgz", + "integrity": "sha512-ujJ1VX+iin4eYJPHVCEbmXHzrEVsi1SaVehHtbAteTZv8VTrZyBiZPmYc6Ud6+fkr/UBMXuEu3N3+d49h7YfKw==", "dev": true, "license": "MIT", "dependencies": { - "@astrojs/compiler": "^2.9.1", - "prettier": "^3.0.0", - "sass-formatter": "^0.7.6" + "@astrojs/compiler-rs": "^0.4.0", + "@prettier/parse-srcset": "^3.1.0", + "sass-formatter": "^0.8.0" }, "engines": { - "node": "^14.15.0 || >=16.0.0" - } - }, - "node_modules/prismjs": { - "version": "1.30.0", - "resolved": "https://registry.npmjs.org/prismjs/-/prismjs-1.30.0.tgz", - "integrity": "sha512-DEvV2ZF2r2/63V+tK8hQvrR2ZGn10srHbXviTlcv7Kpzw8jWiNTqbVgjO3IY8RxrrOUF8VPMQQFysYYYv0YZxw==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=6" + "node": ">=22.12.0" + }, + "peerDependencies": { + "prettier": "^3.5.3" } }, - "node_modules/process-ancestry": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/process-ancestry/-/process-ancestry-0.1.0.tgz", - "integrity": "sha512-tGqJW/UnclpYASFcM6Xh8D8l/BMtaQ9+CSG0vlJSJTcdMM4lDRv4c6H0Pdcsfted+bVczdYSfk2fdukg2gQkZg==", + "node_modules/prettier-plugin-astro/node_modules/@astrojs/compiler-binding": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/@astrojs/compiler-binding/-/compiler-binding-0.4.1.tgz", + "integrity": "sha512-ZYVDW1P58OXyxqZbOMp+/2U9KA7y2esIx9r4pWdpZ/l6fCZhaw4ul+D7EgpRVxYLkyTWqzANbTTUFGPFP8zDHA==", "dev": true, "license": "MIT", "engines": { - "node": ">=18.0.0" + "node": "^20.19.0 || >=22.12.0" + }, + "optionalDependencies": { + "@astrojs/compiler-binding-android-arm64": "0.4.1", + "@astrojs/compiler-binding-darwin-arm64": "0.4.1", + "@astrojs/compiler-binding-darwin-x64": "0.4.1", + "@astrojs/compiler-binding-linux-arm64-gnu": "0.4.1", + "@astrojs/compiler-binding-linux-arm64-musl": "0.4.1", + "@astrojs/compiler-binding-linux-x64-gnu": "0.4.1", + "@astrojs/compiler-binding-linux-x64-musl": "0.4.1", + "@astrojs/compiler-binding-wasm32-wasi": "0.4.1", + "@astrojs/compiler-binding-win32-arm64-msvc": "0.4.1", + "@astrojs/compiler-binding-win32-x64-msvc": "0.4.1" + } + }, + "node_modules/prettier-plugin-astro/node_modules/@astrojs/compiler-binding-android-arm64": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/@astrojs/compiler-binding-android-arm64/-/compiler-binding-android-arm64-0.4.1.tgz", + "integrity": "sha512-Wtx2DZORuNTLASLLZ8hlrjFaJe1LUloatcCn9EPq7knBhRpjMGXeJANIJMeBZG4igvz7x+3nyAJM2iwCSW9xog==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/prettier-plugin-astro/node_modules/@astrojs/compiler-binding-darwin-arm64": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/@astrojs/compiler-binding-darwin-arm64/-/compiler-binding-darwin-arm64-0.4.1.tgz", + "integrity": "sha512-7iwXcU+hB60Y1SvOfnWHNioT72gDsDQKaDipXh2Onwp/TvQMozhbvhy13wJR8Af940a0h6PbddCeJFpj791UDA==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/prettier-plugin-astro/node_modules/@astrojs/compiler-binding-darwin-x64": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/@astrojs/compiler-binding-darwin-x64/-/compiler-binding-darwin-x64-0.4.1.tgz", + "integrity": "sha512-pifjICos49RXhSVKSDu5gDB0/8j0O7DmxSp1DaWW2PyLG5ekwSkcrfOZto5JqhdI7QYMZB3XOiXpsdOXpS4npA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/prettier-plugin-astro/node_modules/@astrojs/compiler-binding-linux-arm64-gnu": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/@astrojs/compiler-binding-linux-arm64-gnu/-/compiler-binding-linux-arm64-gnu-0.4.1.tgz", + "integrity": "sha512-hsZMlNWc6LqWHh9LlSwTq1/XCY7pxA5rkkKIdZRV8mgbOz9OwLvjEoe5Jry13eIZjMUQO8XnQyzk8o/Pjw2YFA==", + "cpu": [ + "arm64" + ], + "dev": true, + "libc": [ + "glibc" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/prettier-plugin-astro/node_modules/@astrojs/compiler-binding-linux-arm64-musl": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/@astrojs/compiler-binding-linux-arm64-musl/-/compiler-binding-linux-arm64-musl-0.4.1.tgz", + "integrity": "sha512-a3EW27f+Z9uf57vYmpLgUriA1y9wDhKz57PT8D8XlFZt2HZEWhUxKuxI1jvKVI9p8okYee11WXEm/FHY1G9yoQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "libc": [ + "musl" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/prettier-plugin-astro/node_modules/@astrojs/compiler-binding-linux-x64-gnu": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/@astrojs/compiler-binding-linux-x64-gnu/-/compiler-binding-linux-x64-gnu-0.4.1.tgz", + "integrity": "sha512-XruPTKB/SS4DFzeAjQ1ZyM0ieHDjapHkOSnnzRApZ4FXY2YAI7UY3mETjfJiIS/acyZyrnPH5jObv1gATTdUJQ==", + "cpu": [ + "x64" + ], + "dev": true, + "libc": [ + "glibc" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/prettier-plugin-astro/node_modules/@astrojs/compiler-binding-linux-x64-musl": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/@astrojs/compiler-binding-linux-x64-musl/-/compiler-binding-linux-x64-musl-0.4.1.tgz", + "integrity": "sha512-E8j7lGanqNpudtkUbsFaOLJhmwFe4Ecqux7K9hkj4wULIPNZRM2bYZNcMSj8r1oWvaUiwZl8LaaNwv3+14jqhw==", + "cpu": [ + "x64" + ], + "dev": true, + "libc": [ + "musl" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/prettier-plugin-astro/node_modules/@astrojs/compiler-binding-wasm32-wasi": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/@astrojs/compiler-binding-wasm32-wasi/-/compiler-binding-wasm32-wasi-0.4.1.tgz", + "integrity": "sha512-vNLxIv41ZE+nmPFtw24cRW5ZXG+ZPcAGtgigtjCP8lvcxKI7u2GrXoMsCgEH5fMw8WCEJpwLvsVBg15rJKAkyA==", + "cpu": [ + "wasm32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "dependencies": { + "@napi-rs/wasm-runtime": "^1.2.4" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/prettier-plugin-astro/node_modules/@astrojs/compiler-binding-win32-arm64-msvc": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/@astrojs/compiler-binding-win32-arm64-msvc/-/compiler-binding-win32-arm64-msvc-0.4.1.tgz", + "integrity": "sha512-/xTDgRsFDoTh0/+KFXJ74DY4Jqn8CoSHwa8UP5RAblHfnRHkenwfSl4zYDET61O9vXKLk09UzHjjq09yP20/AQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/prettier-plugin-astro/node_modules/@astrojs/compiler-binding-win32-x64-msvc": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/@astrojs/compiler-binding-win32-x64-msvc/-/compiler-binding-win32-x64-msvc-0.4.1.tgz", + "integrity": "sha512-0x5J6iHZO0Fjo/CVzoIbXKzWnGESftDbEUQ/oXQ61HhUAFoR7+T1jfToZSNAS+gYyBXHSTpMWYC7lzarbhClcg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/prettier-plugin-astro/node_modules/@astrojs/compiler-rs": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/@astrojs/compiler-rs/-/compiler-rs-0.4.1.tgz", + "integrity": "sha512-//NmAuRhy7eU9iP0ceI5Pymy55M+nUZ//kS6XeOyhBWdDib2KbJOyFaVJ52k7sDkJwTKVox7oPu3SpYiVnGm5A==", + "dev": true, + "license": "MIT", + "dependencies": { + "@astrojs/compiler-binding": "0.4.1" + }, + "engines": { + "node": ">=22.12.0" + } + }, + "node_modules/prismjs": { + "version": "1.30.0", + "resolved": "https://registry.npmjs.org/prismjs/-/prismjs-1.30.0.tgz", + "integrity": "sha512-DEvV2ZF2r2/63V+tK8hQvrR2ZGn10srHbXviTlcv7Kpzw8jWiNTqbVgjO3IY8RxrrOUF8VPMQQFysYYYv0YZxw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/process-ancestry": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/process-ancestry/-/process-ancestry-0.1.0.tgz", + "integrity": "sha512-tGqJW/UnclpYASFcM6Xh8D8l/BMtaQ9+CSG0vlJSJTcdMM4lDRv4c6H0Pdcsfted+bVczdYSfk2fdukg2gQkZg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18.0.0" } }, "node_modules/property-information": { @@ -5878,6 +5906,26 @@ "node": ">=6" } }, + "node_modules/qified": { + "version": "0.10.1", + "resolved": "https://registry.npmjs.org/qified/-/qified-0.10.1.tgz", + "integrity": "sha512-+Owyggi9IxT1ePKGafcI87ubSmxol6smwJ+RAHDQlx9+9cPwFWDiKFFCPuWhr9ignlGpZ9vDQLw67N4dcTVFEA==", + "dev": true, + "license": "MIT", + "dependencies": { + "hookified": "^2.1.1" + }, + "engines": { + "node": ">=20" + } + }, + "node_modules/qified/node_modules/hookified": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/hookified/-/hookified-2.2.0.tgz", + "integrity": "sha512-p/LgFzRN5FeoD3DLS6bkUapeye6E4SI6yJs6KetENd18S+FBthqYq2amJUWpt5z0EQwwHemidjY5OqJGEKm5uA==", + "dev": true, + "license": "MIT" + }, "node_modules/radix3": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/radix3/-/radix3-1.1.2.tgz", @@ -5933,16 +5981,6 @@ "dev": true, "license": "MIT" }, - "node_modules/require-directory": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", - "integrity": "sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/require-from-string": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/require-from-string/-/require-from-string-2.0.2.tgz", @@ -5980,13 +6018,13 @@ } }, "node_modules/rolldown": { - "version": "1.1.5", - "resolved": "https://registry.npmjs.org/rolldown/-/rolldown-1.1.5.tgz", - "integrity": "sha512-t9z29cJjXf/vxQ8dyhCSpt6H6aSwHTk8cT5I3iy6SMXuFpk5mB6PL6XfC8PCwrPTx93udwKUm9HRteAlTGBLiA==", + "version": "1.2.12", + "resolved": "https://registry.npmjs.org/rolldown/-/rolldown-1.2.12.tgz", + "integrity": "sha512-8wafseiaG80xmXSfqidUNqZcylTlhmPZZt+za2m+js2sFZ8dTNlhIOV2WcbIPx2hgwPBJpEUGFAMZ9bgBBLTSQ==", "dev": true, "license": "MIT", "dependencies": { - "@oxc-project/types": "=0.139.0", + "@oxc-project/types": "=0.152.0", "@rolldown/pluginutils": "^1.0.0" }, "bin": { @@ -5996,21 +6034,21 @@ "node": "^20.19.0 || >=22.12.0" }, "optionalDependencies": { - "@rolldown/binding-android-arm64": "1.1.5", - "@rolldown/binding-darwin-arm64": "1.1.5", - "@rolldown/binding-darwin-x64": "1.1.5", - "@rolldown/binding-freebsd-x64": "1.1.5", - "@rolldown/binding-linux-arm-gnueabihf": "1.1.5", - "@rolldown/binding-linux-arm64-gnu": "1.1.5", - "@rolldown/binding-linux-arm64-musl": "1.1.5", - "@rolldown/binding-linux-ppc64-gnu": "1.1.5", - "@rolldown/binding-linux-s390x-gnu": "1.1.5", - "@rolldown/binding-linux-x64-gnu": "1.1.5", - "@rolldown/binding-linux-x64-musl": "1.1.5", - "@rolldown/binding-openharmony-arm64": "1.1.5", - "@rolldown/binding-wasm32-wasi": "1.1.5", - "@rolldown/binding-win32-arm64-msvc": "1.1.5", - "@rolldown/binding-win32-x64-msvc": "1.1.5" + "@rolldown/binding-android-arm-eabi": "1.2.12", + "@rolldown/binding-android-arm64": "1.2.12", + "@rolldown/binding-darwin-arm64": "1.2.12", + "@rolldown/binding-darwin-x64": "1.2.12", + "@rolldown/binding-freebsd-x64": "1.2.12", + "@rolldown/binding-linux-arm-gnueabihf": "1.2.12", + "@rolldown/binding-linux-arm64-gnu": "1.2.12", + "@rolldown/binding-linux-arm64-musl": "1.2.12", + "@rolldown/binding-linux-ppc64-gnu": "1.2.12", + "@rolldown/binding-linux-s390x-gnu": "1.2.12", + "@rolldown/binding-linux-x64-gnu": "1.2.12", + "@rolldown/binding-linux-x64-musl": "1.2.12", + "@rolldown/binding-openharmony-arm64": "1.2.12", + "@rolldown/binding-win32-arm64-msvc": "1.2.12", + "@rolldown/binding-win32-x64-msvc": "1.2.12" } }, "node_modules/s.color": { @@ -6021,43 +6059,46 @@ "license": "MIT" }, "node_modules/sass-formatter": { - "version": "0.7.9", - "resolved": "https://registry.npmjs.org/sass-formatter/-/sass-formatter-0.7.9.tgz", - "integrity": "sha512-CWZ8XiSim+fJVG0cFLStwDvft1VI7uvXdCNJYXhDvowiv+DsbD1nXLiQ4zrE5UBvj5DWZJ93cwN0NX5PMsr1Pw==", + "version": "0.8.0", + "resolved": "https://registry.npmjs.org/sass-formatter/-/sass-formatter-0.8.0.tgz", + "integrity": "sha512-Nf4eMGE2O5vnJG7KPCRyksWS9gVKSYoUWtPeMXRRxwZSPVQhSGtL602xVYS65LvMkHmkvKa7xpauF0+/5pPwrg==", "dev": true, "license": "MIT", "dependencies": { "suf-log": "^2.5.3" + }, + "bin": { + "sass-formatter": "dist/cli.js" } }, "node_modules/satteri": { - "version": "0.9.5", - "resolved": "https://registry.npmjs.org/satteri/-/satteri-0.9.5.tgz", - "integrity": "sha512-ZuWVl+vnM64y+/TtX8Kosv2c00W+hLQiiwnEL6H0UKVVrxFqMw4D2CJHHQaouVd89OAhtBBfjWLqhKi3TVUV4w==", + "version": "0.10.5", + "resolved": "https://registry.npmjs.org/satteri/-/satteri-0.10.5.tgz", + "integrity": "sha512-Ao1LKpAEa9Wdg0otgbVKViZHEq9ebdXe4DMrp3s9vQAU0HNIuHnFEuMuOcm0ZIXyV0Yzxj91NvhLpvXZJO/5ZQ==", "dev": true, "license": "MIT", "dependencies": { "@types/estree-jsx": "^1.0.5", - "@types/hast": "^3.0.4", + "@types/hast": "^3.0.5", "@types/mdast": "^4.0.4", "@types/unist": "^3.0.3" }, "optionalDependencies": { - "@bruits/satteri-darwin-arm64": "0.9.5", - "@bruits/satteri-darwin-x64": "0.9.5", - "@bruits/satteri-linux-arm64-gnu": "0.9.5", - "@bruits/satteri-linux-arm64-musl": "0.9.5", - "@bruits/satteri-linux-x64-gnu": "0.9.5", - "@bruits/satteri-linux-x64-musl": "0.9.5", - "@bruits/satteri-wasm32-wasi": "0.9.5", - "@bruits/satteri-win32-arm64-msvc": "0.9.5", - "@bruits/satteri-win32-x64-msvc": "0.9.5" + "@bruits/satteri-darwin-arm64": "0.10.5", + "@bruits/satteri-darwin-x64": "0.10.5", + "@bruits/satteri-linux-arm64-gnu": "0.10.5", + "@bruits/satteri-linux-arm64-musl": "0.10.5", + "@bruits/satteri-linux-x64-gnu": "0.10.5", + "@bruits/satteri-linux-x64-musl": "0.10.5", + "@bruits/satteri-wasm32-wasi": "0.10.5", + "@bruits/satteri-win32-arm64-msvc": "0.10.5", + "@bruits/satteri-win32-x64-msvc": "0.10.5" } }, "node_modules/sax": { - "version": "1.6.0", - "resolved": "https://registry.npmjs.org/sax/-/sax-1.6.0.tgz", - "integrity": "sha512-6R3J5M4AcbtLUdZmRv2SygeVaM7IhrLXu9BmnOGmmACak8fiUtOsYNWUS4uK7upbmHIBbLBeFeI//477BKLBzA==", + "version": "1.6.1", + "resolved": "https://registry.npmjs.org/sax/-/sax-1.6.1.tgz", + "integrity": "sha512-42tBVwLWnaQvW5zc4HbZrTuWccECCZfBi92FDuwtqxasH+JbPB3/FOKb1m222K42R4WxuxzzMsTswfzgtSu64Q==", "dev": true, "license": "BlueOak-1.0.0", "engines": { @@ -6078,9 +6119,9 @@ } }, "node_modules/sharp": { - "version": "0.35.3", - "resolved": "https://registry.npmjs.org/sharp/-/sharp-0.35.3.tgz", - "integrity": "sha512-ej0zVHuZGHCiABXcNxeYhpRnPNPAcvbG8RMdBAhDAxLKkCRVSpK3Iyu7qbqw3JMzoj0REeM6f3tJLtVwl0023Q==", + "version": "0.35.5", + "resolved": "https://registry.npmjs.org/sharp/-/sharp-0.35.5.tgz", + "integrity": "sha512-Ywn4OnzGukp7CDMrp08RQ50YKmuwG47brZgIVPTvBaaAfQlRlygrRqSrxdCiL9M+LlzLBiJ68IR1QqvzHyjC7g==", "dev": true, "license": "Apache-2.0", "optional": true, @@ -6096,31 +6137,31 @@ "url": "https://opencollective.com/libvips" }, "optionalDependencies": { - "@img/sharp-darwin-arm64": "0.35.3", - "@img/sharp-darwin-x64": "0.35.3", - "@img/sharp-freebsd-wasm32": "0.35.3", - "@img/sharp-libvips-darwin-arm64": "1.3.2", - "@img/sharp-libvips-darwin-x64": "1.3.2", - "@img/sharp-libvips-linux-arm": "1.3.2", - "@img/sharp-libvips-linux-arm64": "1.3.2", - "@img/sharp-libvips-linux-ppc64": "1.3.2", - "@img/sharp-libvips-linux-riscv64": "1.3.2", - "@img/sharp-libvips-linux-s390x": "1.3.2", - "@img/sharp-libvips-linux-x64": "1.3.2", - "@img/sharp-libvips-linuxmusl-arm64": "1.3.2", - "@img/sharp-libvips-linuxmusl-x64": "1.3.2", - "@img/sharp-linux-arm": "0.35.3", - "@img/sharp-linux-arm64": "0.35.3", - "@img/sharp-linux-ppc64": "0.35.3", - "@img/sharp-linux-riscv64": "0.35.3", - "@img/sharp-linux-s390x": "0.35.3", - "@img/sharp-linux-x64": "0.35.3", - "@img/sharp-linuxmusl-arm64": "0.35.3", - "@img/sharp-linuxmusl-x64": "0.35.3", - "@img/sharp-webcontainers-wasm32": "0.35.3", - "@img/sharp-win32-arm64": "0.35.3", - "@img/sharp-win32-ia32": "0.35.3", - "@img/sharp-win32-x64": "0.35.3" + "@img/sharp-darwin-arm64": "0.35.5", + "@img/sharp-darwin-x64": "0.35.5", + "@img/sharp-freebsd-wasm32": "0.35.5", + "@img/sharp-libvips-darwin-arm64": "1.3.4", + "@img/sharp-libvips-darwin-x64": "1.3.4", + "@img/sharp-libvips-linux-arm": "1.3.4", + "@img/sharp-libvips-linux-arm64": "1.3.4", + "@img/sharp-libvips-linux-ppc64": "1.3.4", + "@img/sharp-libvips-linux-riscv64": "1.3.4", + "@img/sharp-libvips-linux-s390x": "1.3.4", + "@img/sharp-libvips-linux-x64": "1.3.4", + "@img/sharp-libvips-linuxmusl-arm64": "1.3.4", + "@img/sharp-libvips-linuxmusl-x64": "1.3.4", + "@img/sharp-linux-arm": "0.35.5", + "@img/sharp-linux-arm64": "0.35.5", + "@img/sharp-linux-ppc64": "0.35.5", + "@img/sharp-linux-riscv64": "0.35.5", + "@img/sharp-linux-s390x": "0.35.5", + "@img/sharp-linux-x64": "0.35.5", + "@img/sharp-linuxmusl-arm64": "0.35.5", + "@img/sharp-linuxmusl-x64": "0.35.5", + "@img/sharp-webcontainers-wasm32": "0.35.5", + "@img/sharp-win32-arm64": "0.35.5", + "@img/sharp-win32-ia32": "0.35.5", + "@img/sharp-win32-x64": "0.35.5" }, "peerDependenciesMeta": { "@types/node": { @@ -6152,32 +6193,25 @@ } }, "node_modules/shiki": { - "version": "4.3.1", - "resolved": "https://registry.npmjs.org/shiki/-/shiki-4.3.1.tgz", - "integrity": "sha512-oR+qDVi2OjX1tmDpyv+3KviX01KzO6Af+0NNnKnsp9491UEGz2YpxTuJboS/6VhYpTdqzmuJBuiTlrAWWJAssw==", + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/shiki/-/shiki-4.5.0.tgz", + "integrity": "sha512-OcRW72ngQvc+MSVWBRIovC/BTW589iUE/Vxav7VeM4RcY9MUjqB+IR6ILG1k9nuW6LiG/nct9uma4/MBtnZbmQ==", "dev": true, "license": "MIT", "dependencies": { - "@shikijs/core": "4.3.1", - "@shikijs/engine-javascript": "4.3.1", - "@shikijs/engine-oniguruma": "4.3.1", - "@shikijs/langs": "4.3.1", - "@shikijs/themes": "4.3.1", - "@shikijs/types": "4.3.1", + "@shikijs/core": "4.5.0", + "@shikijs/engine-javascript": "4.5.0", + "@shikijs/engine-oniguruma": "4.5.0", + "@shikijs/langs": "4.5.0", + "@shikijs/themes": "4.5.0", + "@shikijs/types": "4.5.0", "@shikijs/vscode-textmate": "^10.0.2", - "@types/hast": "^3.0.4" + "@types/hast": "^3.0.5" }, "engines": { "node": ">=20" } }, - "node_modules/siginfo": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/siginfo/-/siginfo-2.0.0.tgz", - "integrity": "sha512-ybx0WO1/8bSBLEWXZvEd7gMW3Sn3JFlW3TvX1nREbDLRNQNaeNN8WK0meBwPdAaOI7TtRRRJn/Es1zhrrCHu7g==", - "dev": true, - "license": "ISC" - }, "node_modules/sisteransi": { "version": "1.0.5", "resolved": "https://registry.npmjs.org/sisteransi/-/sisteransi-1.0.5.tgz", @@ -6206,9 +6240,9 @@ } }, "node_modules/smol-toml": { - "version": "1.7.0", - "resolved": "https://registry.npmjs.org/smol-toml/-/smol-toml-1.7.0.tgz", - "integrity": "sha512-aqVvWoyO21L23mb+drl4RmMXbf6N7FdHjAhTRA9ZBL7apWBgfWC16KjrASI+1p9GAroljyMHj6fK67i0UiTNvQ==", + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/smol-toml/-/smol-toml-1.9.0.tgz", + "integrity": "sha512-hpd+HLON7HdZXqYchMM/+LaTTbdK0AU3NngIJ4KVyWbY9bfQqdL9cD+4yf6dUoU2Ap4VsU0JkQi6FxAI1B2mXQ==", "dev": true, "license": "BSD-3-Clause", "engines": { @@ -6219,9 +6253,9 @@ } }, "node_modules/source-map-js": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.1.tgz", - "integrity": "sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==", + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.2.tgz", + "integrity": "sha512-KGj/8Y43x35aZVDtt+J4mK1hoLGHULMYfSkODJNQjNDC3oW1PqPoxMwo0pLUsWM/UEGzON/NxeHywEfNXNP3Vw==", "dev": true, "license": "BSD-3-Clause", "engines": { @@ -6239,40 +6273,28 @@ "url": "https://github.com/sponsors/wooorm" } }, - "node_modules/stackback": { - "version": "0.0.2", - "resolved": "https://registry.npmjs.org/stackback/-/stackback-0.0.2.tgz", - "integrity": "sha512-1XMJE5fQo1jGH6Y/7ebnwPOBEkIEnT4QF32d5R1+VXdXveM0IBMJt8zfaxX1P3QhVwrYe+576+jkANtSS2mBbw==", - "dev": true, - "license": "MIT" - }, "node_modules/std-env": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/std-env/-/std-env-4.2.0.tgz", - "integrity": "sha512-oCUKSupKTHX53EyjDtuZQ64pjLJ6yYCtpmEw0goYxtjG9KpbRe8KAsl2tBUGU9DyMcJ0RwJ8GqJAFzMXcXW1Rw==", - "dev": true, - "license": "MIT" - }, - "node_modules/stream-replace-string": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/stream-replace-string/-/stream-replace-string-2.0.0.tgz", - "integrity": "sha512-TlnjJ1C0QrmxRNrON00JvaFFlNh5TTG00APw23j74ET7gkQpTASi6/L2fuiav8pzK715HXtUeClpBTw2NPSn6w==", + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/std-env/-/std-env-4.3.0.tgz", + "integrity": "sha512-OtU/EgQ1kIm5KwqQpBC6ZEMXrZRui11w8zgfTWp8cdO9B8OaPsbA8bTHO2P+HNo1VlUTGMVBwPhydu6poeXiag==", "dev": true, "license": "MIT" }, "node_modules/string-width": { - "version": "4.2.3", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", - "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "version": "8.3.0", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-8.3.0.tgz", + "integrity": "sha512-ZbmZM0JCihQN91dWnxoipT2KOEyHqEyfRXUyjuRhW8b/xnqPDoq4gWEVApTVa9db2wN8mmoikgFBbjh71+cGeQ==", "dev": true, "license": "MIT", "dependencies": { - "emoji-regex": "^8.0.0", - "is-fullwidth-code-point": "^3.0.0", - "strip-ansi": "^6.0.1" + "get-east-asian-width": "^1.5.0", + "strip-ansi": "^7.1.2" }, "engines": { - "node": ">=8" + "node": ">=20" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, "node_modules/stringify-entities": { @@ -6291,16 +6313,19 @@ } }, "node_modules/strip-ansi": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", - "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.2.0.tgz", + "integrity": "sha512-yDPMNjp4WyfYBkHnjIRLfca1i6KMyGCtsVgoKe/z1+6vukgaENdgGBZt+ZmKPc4gavvEZ5OgHfHdrazhgNyG7w==", "dev": true, "license": "MIT", "dependencies": { - "ansi-regex": "^5.0.1" + "ansi-regex": "^6.2.2" }, "engines": { - "node": ">=8" + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/strip-ansi?sponsor=1" } }, "node_modules/suf-log": { @@ -6313,33 +6338,20 @@ "s.color": "0.0.15" } }, - "node_modules/supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", - "dev": true, - "license": "MIT", - "dependencies": { - "has-flag": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, "node_modules/svgo": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/svgo/-/svgo-4.0.2.tgz", - "integrity": "sha512-ekx94z1rRc5LDi6oSUaeRnYhd0UOJxdtQCL2rF8xpWxD3TPAsISWOrxezqGovqS38GRZOdpDfvQe3ts6F7nsng==", + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/svgo/-/svgo-4.1.0.tgz", + "integrity": "sha512-bkxnTg1kSU0guhIBmibA6UUhrQmPVA1XsQLN+ylCd+UWzbnLkySOcXpyk1mrl05f+pcaCx2eHb+sp6BgMZWX+Q==", "dev": true, "license": "MIT", "dependencies": { "commander": "^11.1.0", - "css-select": "^5.1.0", + "css-select": "^6.0.0", "css-tree": "^3.0.1", - "css-what": "^6.1.0", + "css-what": "^7.0.0", "csso": "^5.0.5", "picocolors": "^1.1.1", - "sax": "^1.5.0" + "sax": "1.6.1" }, "bin": { "svgo": "bin/svgo.js" @@ -6360,16 +6372,19 @@ "license": "MIT" }, "node_modules/tinybench": { - "version": "2.9.0", - "resolved": "https://registry.npmjs.org/tinybench/-/tinybench-2.9.0.tgz", - "integrity": "sha512-0+DUvqWMValLmha6lr4kD8iAMK1HzV0/aKnCtWb9v9641TnP/MFb7Pc2bxoxQjTXAErryXVgUOfv2YqNllqGeg==", + "version": "6.2.1", + "resolved": "https://registry.npmjs.org/tinybench/-/tinybench-6.2.1.tgz", + "integrity": "sha512-IAbQaPJIIdhVxi0mqy9lez1wEwje0UQf9F1vwtbelEG5Nbgn0nPOxCvU+mNeNS9gyJTAhrHp74CbUaSynQpZcQ==", "dev": true, - "license": "MIT" + "license": "MIT", + "engines": { + "node": ">=20.0.0" + } }, "node_modules/tinyclip": { - "version": "0.1.15", - "resolved": "https://registry.npmjs.org/tinyclip/-/tinyclip-0.1.15.tgz", - "integrity": "sha512-uo33abH+Ays0xYaDysoBt494Hb3hsEczMpcC0MwFl773pazORx4fmvKhclhR1wonUbB6vvpRsvVMwnhfqeMc+A==", + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/tinyclip/-/tinyclip-1.0.3.tgz", + "integrity": "sha512-nTv2raKFMzGG6JJp0lpNDsRPdfFE6UHlu2rVEjXo8vkx1ZS3LW2CVXqIaLu8xZlu+6tbFs9V58Qc/Jmk/Ii7wA==", "dev": true, "license": "MIT", "engines": { @@ -6377,9 +6392,9 @@ } }, "node_modules/tinyexec": { - "version": "1.2.4", - "resolved": "https://registry.npmjs.org/tinyexec/-/tinyexec-1.2.4.tgz", - "integrity": "sha512-SHf/r48b7vOrjve9PxJo3MN5v5yuyjHvdUcrQffT3WXMUfnGmHDVbC4k3sHJaJTgZCwpUplIaAo5ANtMyp3YHg==", + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/tinyexec/-/tinyexec-1.3.1.tgz", + "integrity": "sha512-GCvB3aoys96IuDFBMcTB46JOR6mdMtAToqwiW8JlWhsoh1mhHi/xn9ss/Dg7N555GiJyEt2qzoG/NHCwM6h1EA==", "dev": true, "license": "MIT", "engines": { @@ -6404,9 +6419,9 @@ } }, "node_modules/tinyrainbow": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/tinyrainbow/-/tinyrainbow-3.1.0.tgz", - "integrity": "sha512-Bf+ILmBgretUrdJxzXM0SgXLZ3XfiaUuOj/IKQHuTXip+05Xn+uyEYdVg0kYDipTBcLrCVyUzAPz7QmArb0mmw==", + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/tinyrainbow/-/tinyrainbow-3.2.0.tgz", + "integrity": "sha512-LgO3D9yZJjApUiuUfl9iFAwrtaX4+lok3wJIqttGoKCHlWUqHqbQpnxCf82L8FjgKsh4iGo78hqJwgL8F6To2A==", "dev": true, "license": "MIT", "engines": { @@ -6453,13 +6468,12 @@ "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz", "integrity": "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==", "dev": true, - "license": "0BSD", - "optional": true + "license": "0BSD" }, "node_modules/tsx": { - "version": "4.23.1", - "resolved": "https://registry.npmjs.org/tsx/-/tsx-4.23.1.tgz", - "integrity": "sha512-GQHnkIfxyx1wYCOS/wonik5MVRZU9hi1TEZmzGZSCJB1y9YgoZ8H6itNE/u4suE+yLmOzuE4E5S4TZ/ZX2wcWQ==", + "version": "4.23.15", + "resolved": "https://registry.npmjs.org/tsx/-/tsx-4.23.15.tgz", + "integrity": "sha512-Yiex1Ovn8z2xPpOWckIiysV1SSyRMY9BkLF++q0yKiDxCqRhosKfMg3janKkiLBwZ5c/YryloKwGZcrEmtwxKw==", "dev": true, "license": "MIT", "dependencies": { @@ -6475,21 +6489,6 @@ "fsevents": "~2.3.3" } }, - "node_modules/tsx/node_modules/fsevents": { - "version": "2.3.3", - "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", - "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==", - "dev": true, - "hasInstallScript": true, - "license": "MIT", - "optional": true, - "os": [ - "darwin" - ], - "engines": { - "node": "^8.16.0 || ^10.6.0 || >=11.0.0" - } - }, "node_modules/tuf-js": { "version": "6.0.0", "resolved": "https://registry.npmjs.org/tuf-js/-/tuf-js-6.0.0.tgz", @@ -6549,16 +6548,16 @@ } }, "node_modules/typescript-eslint": { - "version": "8.65.0", - "resolved": "https://registry.npmjs.org/typescript-eslint/-/typescript-eslint-8.65.0.tgz", - "integrity": "sha512-/ggrHAwyjENDusvyxbuqxAC2dTnZg/Z8F+fgQtYIz+L6n/9HfSlEZcFGV/NsMNa6CkGk0xUjUAFwC0vHOflvIA==", + "version": "8.71.1", + "resolved": "https://registry.npmjs.org/typescript-eslint/-/typescript-eslint-8.71.1.tgz", + "integrity": "sha512-oiNVPC3/NbV1FpaHU07l8O6ynqG9v4PAiW2WvTrAmZdR0f2HI/gE668ElMLCK7Xbsu5k2fK5C4fXNiq05j7/nQ==", "dev": true, "license": "MIT", "dependencies": { - "@typescript-eslint/eslint-plugin": "8.65.0", - "@typescript-eslint/parser": "8.65.0", - "@typescript-eslint/typescript-estree": "8.65.0", - "@typescript-eslint/utils": "8.65.0" + "@typescript-eslint/eslint-plugin": "8.71.1", + "@typescript-eslint/parser": "8.71.1", + "@typescript-eslint/typescript-estree": "8.71.1", + "@typescript-eslint/utils": "8.71.1" }, "engines": { "node": "^18.18.0 || ^20.9.0 || >=21.1.0" @@ -6593,10 +6592,20 @@ "dev": true, "license": "MIT" }, + "node_modules/undici": { + "version": "8.11.2", + "resolved": "https://registry.npmjs.org/undici/-/undici-8.11.2.tgz", + "integrity": "sha512-u4UB2/IrKdU6lFxumHmmo1a3fCQO5tzQllRorfoRS63txhrB7xTpSn1PftwC4qEHkOaqP95fCWW4lJzwErwzhQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=22.19.0" + } + }, "node_modules/undici-types": { - "version": "7.18.2", - "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-7.18.2.tgz", - "integrity": "sha512-AsuCzffGHJybSaRrmr5eHr81mwJU3kjw6M+uprWvCXiNeN9SOGwQ3Jn8jb8m3Z6izVgknn1R0FTCEAP2QrLY/w==", + "version": "7.24.6", + "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-7.24.6.tgz", + "integrity": "sha512-WRNW+sJgj5OBN4/0JpHFqtqzhpbnV0GuB+OozA9gCL7a993SmU+1JBZCzLNxYsbMfIeDL+lTsphD5jN5N+n0zg==", "dev": true, "license": "MIT" }, @@ -6621,15 +6630,15 @@ } }, "node_modules/unifont": { - "version": "0.7.4", - "resolved": "https://registry.npmjs.org/unifont/-/unifont-0.7.4.tgz", - "integrity": "sha512-oHeis4/xl42HUIeHuNZRGEvxj5AaIKR+bHPNegRq5LV1gdc3jundpONbjglKpihmJf+dswygdMJn3eftGIMemg==", + "version": "0.7.5", + "resolved": "https://registry.npmjs.org/unifont/-/unifont-0.7.5.tgz", + "integrity": "sha512-ULe/Cs+ZIsq+dcFofNkhqielCrUJnb5mr+Yc4EBM2VlL+6OZR6+cjtI2mT1bJvRBrVncqHAbLURxmPLcCXzWMg==", "dev": true, "license": "MIT", "dependencies": { "css-tree": "^3.1.0", - "ofetch": "^1.5.1", - "ohash": "^2.0.11" + "ohash": "^2.0.11", + "undici": "^8.0.0" } }, "node_modules/unist-util-is": { @@ -6819,9 +6828,9 @@ } }, "node_modules/unstorage/node_modules/readdirp": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-5.0.0.tgz", - "integrity": "sha512-9u/XQ1pvrQtYyMpZe7DXKv2p5CNvyVwzUB6uhLAnQwHMSgKMBR62lc7AHljaeteeHXn11XTAaLLUVZYVZyuRBQ==", + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-5.1.1.tgz", + "integrity": "sha512-Kko+Y5XQ6fM+Ce3dq3m9YGxnacYZYl9cA1wZjaF3Vbry2L3i1qVg8+CAgNPsXRArPMUMCaOR7oa9Nqntc43JKA==", "dev": true, "license": "MIT", "engines": { @@ -6842,30 +6851,28 @@ "punycode": "^2.1.0" } }, - "node_modules/vfile": { - "version": "6.0.3", - "resolved": "https://registry.npmjs.org/vfile/-/vfile-6.0.3.tgz", - "integrity": "sha512-KzIbH/9tXat2u30jf+smMwFCsno4wHVdNmzFyL+T/L3UGqqk6JKfVqOFOZEpZSHADH1k40ab6NUIXZq422ov3Q==", + "node_modules/verkit": { + "version": "0.5.0", + "resolved": "https://registry.npmjs.org/verkit/-/verkit-0.5.0.tgz", + "integrity": "sha512-u4J1hr6Y+C/hit34GwL3eIcUf3wngT8TlYUjK7tk0jxydKLAq3sYvifjdTDA6U3KCKRcQCQDGf/srjxfZF3l7g==", "dev": true, "license": "MIT", - "dependencies": { - "@types/unist": "^3.0.0", - "vfile-message": "^4.0.0" + "engines": { + "node": ">=18.12.0" }, "funding": { - "type": "opencollective", - "url": "https://opencollective.com/unified" + "url": "https://github.com/sponsors/sxzz" } }, - "node_modules/vfile-location": { - "version": "5.0.3", - "resolved": "https://registry.npmjs.org/vfile-location/-/vfile-location-5.0.3.tgz", - "integrity": "sha512-5yXvWDEgqeiYiBe1lbxYF7UMAIm/IcopxMHrMQDq3nvKcjPKIhZklUKL+AE7J7uApI4kwe2snsK+eI6UTj9EHg==", + "node_modules/vfile": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/vfile/-/vfile-6.0.3.tgz", + "integrity": "sha512-KzIbH/9tXat2u30jf+smMwFCsno4wHVdNmzFyL+T/L3UGqqk6JKfVqOFOZEpZSHADH1k40ab6NUIXZq422ov3Q==", "dev": true, "license": "MIT", "dependencies": { "@types/unist": "^3.0.0", - "vfile": "^6.0.0" + "vfile-message": "^4.0.0" }, "funding": { "type": "opencollective", @@ -6888,16 +6895,16 @@ } }, "node_modules/vite": { - "version": "8.1.5", - "resolved": "https://registry.npmjs.org/vite/-/vite-8.1.5.tgz", - "integrity": "sha512-7ULLwsCdYx/nRyrpiEwvqb5TFHrMVZyBt+rg/OAXT7rgj/z+DtTDyKFeLAdDkubDVDKD8jOsndmy7m55XcfUsw==", + "version": "8.3.3", + "resolved": "https://registry.npmjs.org/vite/-/vite-8.3.3.tgz", + "integrity": "sha512-cTAldKPImjg6c+gk48U19POPn3GCBzZwpdsN8ZMEEcbpes+6/wvfqUd0C2y3qYY4wsj8PwgFwrZ/1jBPVttMSg==", "dev": true, "license": "MIT", "dependencies": { - "lightningcss": "^1.32.0", - "picomatch": "^4.0.5", - "postcss": "^8.5.17", - "rolldown": "~1.1.5", + "lightningcss": "^1.33.0", + "picomatch": "^4.0.7", + "postcss": "^8.5.28", + "rolldown": "~1.2.11", "tinyglobby": "^0.2.17" }, "bin": { @@ -6914,7 +6921,7 @@ }, "peerDependencies": { "@types/node": "^20.19.0 || >=22.12.0", - "@vitejs/devtools": "^0.3.0", + "@vitejs/devtools": "^0.7.1", "esbuild": "^0.27.0 || ^0.28.0", "jiti": ">=1.21.0", "less": "^4.0.0", @@ -6965,21 +6972,6 @@ } } }, - "node_modules/vite/node_modules/fsevents": { - "version": "2.3.3", - "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", - "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==", - "dev": true, - "hasInstallScript": true, - "license": "MIT", - "optional": true, - "os": [ - "darwin" - ], - "engines": { - "node": "^8.16.0 || ^10.6.0 || >=11.0.0" - } - }, "node_modules/vitefu": { "version": "1.1.3", "resolved": "https://registry.npmjs.org/vitefu/-/vitefu-1.1.3.tgz", @@ -7001,38 +6993,31 @@ } }, "node_modules/vitest": { - "version": "4.1.10", - "resolved": "https://registry.npmjs.org/vitest/-/vitest-4.1.10.tgz", - "integrity": "sha512-R9jUTe5S4Qb0HCd4TNqpC7oGcrMssMRGXLW80ubjWsW9VH5GF8y1Y0SFLY9AbqSk6nt0PnOx4H4WNJYZ13GUPw==", - "dev": true, - "license": "MIT", - "dependencies": { - "@vitest/expect": "4.1.10", - "@vitest/mocker": "4.1.10", - "@vitest/pretty-format": "4.1.10", - "@vitest/runner": "4.1.10", - "@vitest/snapshot": "4.1.10", - "@vitest/spy": "4.1.10", - "@vitest/utils": "4.1.10", - "es-module-lexer": "^2.0.0", - "expect-type": "^1.3.0", - "magic-string": "^0.30.21", - "obug": "^2.1.1", - "pathe": "^2.0.3", - "picomatch": "^4.0.3", - "std-env": "^4.0.0-rc.1", - "tinybench": "^2.9.0", - "tinyexec": "^1.0.2", - "tinyglobby": "^0.2.15", - "tinyrainbow": "^3.1.0", - "vite": "^6.0.0 || ^7.0.0 || ^8.0.0", - "why-is-node-running": "^2.3.0" + "version": "5.0.3", + "resolved": "https://registry.npmjs.org/vitest/-/vitest-5.0.3.tgz", + "integrity": "sha512-xMw97S3rjdtj5dkVat7jCsqWBpvchs3RlpQctUqwJD0KkERk40vz2fJ77lDwW/Vzh/pk18eItYAzkodhSes3jQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/chai": "^5.2.2", + "@vitest/mocker": "5.0.3", + "chai": "^6.2.2", + "es-module-lexer": "^2.3.2", + "expect-type": "^1.4.0", + "magic-string": "^1.2.3", + "obug": "^2.1.4", + "picomatch": "^4.0.7", + "std-env": "^4.2.0", + "tinybench": "^6.1.4", + "tinyexec": "^1.3.0", + "tinyglobby": "^0.2.17", + "why-is-node-running": "3.2.1" }, "bin": { "vitest": "vitest.mjs" }, "engines": { - "node": "^20.0.0 || ^22.0.0 || >=24.0.0" + "node": "^22.12.0 || ^24.0.0 || >=26.0.0" }, "funding": { "url": "https://opencollective.com/vitest" @@ -7040,16 +7025,16 @@ "peerDependencies": { "@edge-runtime/vm": "*", "@opentelemetry/api": "^1.9.0", - "@types/node": "^20.0.0 || ^22.0.0 || >=24.0.0", - "@vitest/browser-playwright": "4.1.10", - "@vitest/browser-preview": "4.1.10", - "@vitest/browser-webdriverio": "4.1.10", - "@vitest/coverage-istanbul": "4.1.10", - "@vitest/coverage-v8": "4.1.10", - "@vitest/ui": "4.1.10", + "@types/node": "^22.0.0 || >=24.0.0", + "@vitest/browser-playwright": "5.0.3", + "@vitest/browser-preview": "5.0.3", + "@vitest/browser-webdriverio": "^5.0.0-beta.5 || >=5.0.0", + "@vitest/coverage-istanbul": "5.0.3", + "@vitest/coverage-v8": "5.0.3", + "@vitest/ui": "5.0.3", "happy-dom": "*", "jsdom": "*", - "vite": "^6.0.0 || ^7.0.0 || ^8.0.0" + "vite": "^6.4.0 || ^7.0.0 || ^8.0.0" }, "peerDependenciesMeta": { "@edge-runtime/vm": { @@ -7284,9 +7269,9 @@ } }, "node_modules/vscode-jsonrpc": { - "version": "9.0.1", - "resolved": "https://registry.npmjs.org/vscode-jsonrpc/-/vscode-jsonrpc-9.0.1.tgz", - "integrity": "sha512-rfuA6T75H6m5EkbhtEPzre9pT0HPcDI2MMy4+nPFIBks5J8JBAUHD4tRYSgaBOijIEC7SRkC1kKyXTLqbmh9jw==", + "version": "9.0.3", + "resolved": "https://registry.npmjs.org/vscode-jsonrpc/-/vscode-jsonrpc-9.0.3.tgz", + "integrity": "sha512-qETYf9PCl1lVfwR+oBmMfc4vP2nqLNA35ABxorw3j06+xlKRgDVxbLgKm4Y/xPL0YWdeDjLoI4ImICIT3nB0zQ==", "dev": true, "license": "MIT", "engines": { @@ -7307,27 +7292,27 @@ } }, "node_modules/vscode-languageserver-protocol": { - "version": "3.18.2", - "resolved": "https://registry.npmjs.org/vscode-languageserver-protocol/-/vscode-languageserver-protocol-3.18.2.tgz", - "integrity": "sha512-XRyDbT0Pp3sSNti3JmxVEUMySWCSi1hhM+/KUlCy1hV1zmrqpM1OwO12EAki8blhmLuIMpaJrYbo0OzGVfK2Qg==", + "version": "3.18.4", + "resolved": "https://registry.npmjs.org/vscode-languageserver-protocol/-/vscode-languageserver-protocol-3.18.4.tgz", + "integrity": "sha512-CCXbyr99dafRJzJH/0Ryk7ly5T8XPmSR0//OuF2w4m+9JiOin7zcAT5iET8GRE7Z9taFBejb3GbM0a0mbjdbrg==", "dev": true, "license": "MIT", "dependencies": { - "vscode-jsonrpc": "9.0.1", - "vscode-languageserver-types": "3.18.0" + "vscode-jsonrpc": "9.0.3", + "vscode-languageserver-types": "3.18.4" } }, "node_modules/vscode-languageserver-textdocument": { - "version": "1.0.12", - "resolved": "https://registry.npmjs.org/vscode-languageserver-textdocument/-/vscode-languageserver-textdocument-1.0.12.tgz", - "integrity": "sha512-cxWNPesCnQCcMPeenjKKsOCKQZ/L6Tv19DTRIGuLWe32lyzWhihGVJ/rcckZXJxfdKCFvRLS3fpBIsV/ZGX4zA==", + "version": "1.0.15", + "resolved": "https://registry.npmjs.org/vscode-languageserver-textdocument/-/vscode-languageserver-textdocument-1.0.15.tgz", + "integrity": "sha512-Gsfr9S8LU3S6885cS+NaleasJ0n3V5y/SOTqHCifQiXWFw3G9w9/YItDfwHrlCz+dSZWWZ8ilYVMcJe7Sz7Sxw==", "dev": true, "license": "MIT" }, "node_modules/vscode-languageserver-types": { - "version": "3.18.0", - "resolved": "https://registry.npmjs.org/vscode-languageserver-types/-/vscode-languageserver-types-3.18.0.tgz", - "integrity": "sha512-8TsGPNMIMiiBdkORgRSvLjuiEIiAFtO+KssmYWxQ+uSVvlf7RjK8YKCOjPzZ+YA04jXEV7+7LvkSmHkhpNS99g==", + "version": "3.18.4", + "resolved": "https://registry.npmjs.org/vscode-languageserver-types/-/vscode-languageserver-types-3.18.4.tgz", + "integrity": "sha512-nQsacoiijvl0fRf2q28uFDrAVwRhdCa3QveiF7/CX0r18mLR5FU/1WskSsCKOjmEbtteKUnY8x8Yzxop+k0zwg==", "dev": true, "license": "MIT" }, @@ -7367,29 +7352,18 @@ "license": "MIT" }, "node_modules/vscode-uri": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/vscode-uri/-/vscode-uri-3.1.0.tgz", - "integrity": "sha512-/BpdSx+yCQGnCvecbyXdxHDkuk55/G3xwnC0GqY4gmQ3j+A+g8kzzgB4Nk/SINjqn6+waqw3EgbVF2QKExkRxQ==", + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/vscode-uri/-/vscode-uri-3.2.0.tgz", + "integrity": "sha512-m2gXo3bn0G1kT9InzMf07fTbqMbGtyckj3bH5ktLO+1Ssv+yiATZ4dhwaQv9UZWxJh6E9IFGnQyjgWVDWVBDrg==", "dev": true, "license": "MIT" }, "node_modules/web-features": { - "version": "3.34.2", - "resolved": "https://registry.npmjs.org/web-features/-/web-features-3.34.2.tgz", - "integrity": "sha512-1/prthzNwl/ITxBgFuKUCJ1ezWxZDM8rhz/VIBCD6zMEv5STMDQxgf05IfYxmJvFBTTLONaTDUk7umPkhUHmpw==", + "version": "3.40.1", + "resolved": "https://registry.npmjs.org/web-features/-/web-features-3.40.1.tgz", + "integrity": "sha512-HRdUYqZRNawtIEI39iKjk6E6g1yO/bct/8bFcD/O+bNGYsbG475PV80+HTrpkYOiZnoEaVSMu5Q/LTVwnBH5ag==", "license": "Apache-2.0" }, - "node_modules/web-namespaces": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/web-namespaces/-/web-namespaces-2.0.1.tgz", - "integrity": "sha512-bKr1DkiNa2krS7qxNtdrtHAmzuYGFQLiQ13TsorsdT6ULTkPLKuu5+GsFpDlg6JFjUTwX2DyhMPG2be8uPrqsQ==", - "dev": true, - "license": "MIT", - "funding": { - "type": "github", - "url": "https://github.com/sponsors/wooorm" - } - }, "node_modules/which": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", @@ -7407,20 +7381,16 @@ } }, "node_modules/why-is-node-running": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/why-is-node-running/-/why-is-node-running-2.3.0.tgz", - "integrity": "sha512-hUrmaWBdVDcxvYqnyh09zunKzROWjbZTiNy8dBEjkS7ehEDQibXJ7XvlmtbwuTclUiIyN+CyXQD4Vmko8fNm8w==", + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/why-is-node-running/-/why-is-node-running-3.2.1.tgz", + "integrity": "sha512-Tb2FUhB4vUsGQlfSquQLYkApkuPAFQXGFzxWKHHumVz2dK+X1RUm/HnID4+TfIGYJ1kTcwOaCk/buYCEJr6YjQ==", "dev": true, "license": "MIT", - "dependencies": { - "siginfo": "^2.0.0", - "stackback": "0.0.2" - }, "bin": { "why-is-node-running": "cli.js" }, "engines": { - "node": ">=8" + "node": ">=20.11" } }, "node_modules/word-wrap": { @@ -7434,23 +7404,41 @@ } }, "node_modules/wrap-ansi": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", - "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", + "version": "9.0.2", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-9.0.2.tgz", + "integrity": "sha512-42AtmgqjV+X1VpdOfyTGOYRi0/zsoLqtXQckTmqTeybT+BDIbM/Guxo7x3pE2vtpr1ok6xRqM9OpBe+Jyoqyww==", "dev": true, "license": "MIT", "dependencies": { - "ansi-styles": "^4.0.0", - "string-width": "^4.1.0", - "strip-ansi": "^6.0.0" + "ansi-styles": "^6.2.1", + "string-width": "^7.0.0", + "strip-ansi": "^7.1.0" }, "engines": { - "node": ">=10" + "node": ">=18" }, "funding": { "url": "https://github.com/chalk/wrap-ansi?sponsor=1" } }, + "node_modules/wrap-ansi/node_modules/string-width": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-7.2.0.tgz", + "integrity": "sha512-tsaTIkKW9b4N+AEj+SVA+WhJzV7/zMhcSu78mLKWSk7cXMOSHsBKFWUs0fWwq8QyK3MgJBQRX6Gbi4kYbdvGkQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "emoji-regex": "^10.3.0", + "get-east-asian-width": "^1.0.0", + "strip-ansi": "^7.1.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/xxhash-wasm": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/xxhash-wasm/-/xxhash-wasm-1.1.0.tgz", @@ -7469,9 +7457,9 @@ } }, "node_modules/yaml": { - "version": "2.9.0", - "resolved": "https://registry.npmjs.org/yaml/-/yaml-2.9.0.tgz", - "integrity": "sha512-2AvhNX3mb8zd6Zy7INTtSpl1F15HW6Wnqj0srWlkKLcpYl/gMIMJiyuGq2KeI2YFxUPjdlB+3Lc10seMLtL4cA==", + "version": "2.9.1", + "resolved": "https://registry.npmjs.org/yaml/-/yaml-2.9.1.tgz", + "integrity": "sha512-3NxN8+78OdzbT7C/WjGsyfPAtJaN3FNDsWxv7Y7mcDsT/oOmgW8BpyQQFFBnvZE3j9Y2Sdz1ULFLezL7Eb2yFw==", "dev": true, "license": "ISC", "bin": { @@ -7581,22 +7569,21 @@ } }, "node_modules/yargs": { - "version": "17.7.3", - "resolved": "https://registry.npmjs.org/yargs/-/yargs-17.7.3.tgz", - "integrity": "sha512-GZtjxm/J/4TSxuL3FNYjCmLktBTnIw/rVmKSIyKeYAZpmJB2ig9VauCC5xsa82GNKVKDAqpOn3KVzNt0zmrU0g==", + "version": "18.2.0", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-18.2.0.tgz", + "integrity": "sha512-9OpKOLeaoNFecEp7P6iYbzze/5CqWoH7N3SMs/6y1XF4nMvFMspEGZzJ6uFi9MmQwXhyzqYoSEKO3tvA3Z/o2w==", "dev": true, "license": "MIT", "dependencies": { - "cliui": "^8.0.1", + "cliui": "^9.0.1", "escalade": "^3.1.1", "get-caller-file": "^2.0.5", - "require-directory": "^2.1.1", - "string-width": "^4.2.3", + "string-width": "^8.2.1", "y18n": "^5.0.5", - "yargs-parser": "^21.1.1" + "yargs-parser": "^22.0.0" }, "engines": { - "node": ">=12" + "node": "^20.19.0 || ^22.12.0 || >=23" } }, "node_modules/yargs-parser": { @@ -7609,16 +7596,6 @@ "node": "^20.19.0 || ^22.12.0 || >=23" } }, - "node_modules/yargs/node_modules/yargs-parser": { - "version": "21.1.1", - "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-21.1.1.tgz", - "integrity": "sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==", - "dev": true, - "license": "ISC", - "engines": { - "node": ">=12" - } - }, "node_modules/yocto-queue": { "version": "1.2.2", "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-1.2.2.tgz", @@ -7633,9 +7610,9 @@ } }, "node_modules/zod": { - "version": "4.4.3", - "resolved": "https://registry.npmjs.org/zod/-/zod-4.4.3.tgz", - "integrity": "sha512-ytENFjIJFl2UwYglde2jchW2Hwm4GJFLDiSXWdTrJQBIN9Fcyp7n4DhxJEiWNAJMV1/BqWfW/kkg71UDcHJyTQ==", + "version": "4.6.5", + "resolved": "https://registry.npmjs.org/zod/-/zod-4.6.5.tgz", + "integrity": "sha512-v5l/aFXZQeai4awLbOpSoHecE9UiMrnfx75tEXLjNonXVARxQ5mOeipTjROUchszUNCqnE+hqAMujRsRHsut2Q==", "license": "MIT", "funding": { "url": "https://github.com/sponsors/colinhacks" diff --git a/package.json b/package.json index 54a9d75..3c44340 100644 --- a/package.json +++ b/package.json @@ -6,10 +6,10 @@ "description": "Security-control compatibility planning from attributed browser support data", "license": "MIT", "author": "slicedearth", - "packageManager": "npm@12.0.1", + "packageManager": "npm@12.2.0", "engines": { "node": "^24.15.0 || >=26.0.0", - "npm": ">=11.17.0 <13" + "npm": "12.2.0" }, "scripts": { "dev": "astro dev", @@ -37,34 +37,34 @@ "verify": "npm run lint && npm run format:check && npm run typecheck && npm run check && npm test && npm run audit:repository && npm run build && npm run audit:public && npm run audit:language" }, "dependencies": { - "@mdn/browser-compat-data": "8.0.8", + "@mdn/browser-compat-data": "8.1.4", "@sigstore/bundle": "5.0.0", - "@sigstore/protobuf-specs": "0.5.1", + "@sigstore/protobuf-specs": "0.5.2", "@sigstore/tuf": "5.0.0", - "@sigstore/verify": "4.1.0", + "@sigstore/verify": "4.1.2", "parse5": "8.0.1", - "web-features": "3.34.2", - "zod": "4.4.3" + "web-features": "3.40.1", + "zod": "4.6.5" }, "devDependencies": { - "@astrojs/check": "0.9.9", - "@astrojs/sitemap": "3.7.3", - "@axe-core/playwright": "4.12.1", + "@astrojs/check": "0.9.10", + "@astrojs/sitemap": "3.7.4", + "@axe-core/playwright": "4.13.0", "@eslint/js": "10.0.1", - "@playwright/test": "1.62.0", - "@types/node": "24.13.3", - "@vitest/coverage-v8": "4.1.10", - "astro": "7.1.3", - "eslint": "10.8.0", - "prettier": "3.9.6", - "prettier-plugin-astro": "0.14.1", - "tsx": "4.23.1", + "@playwright/test": "1.63.0", + "@types/node": "24.19.1", + "@vitest/coverage-v8": "5.0.3", + "astro": "7.3.6", + "eslint": "10.12.0", + "prettier": "3.9.9", + "prettier-plugin-astro": "1.1.0", + "tsx": "4.23.15", "typescript": "6.0.3", - "typescript-eslint": "8.65.0", - "vitest": "4.1.10" + "typescript-eslint": "8.71.1", + "vitest": "5.0.3" }, "allowScripts": { - "esbuild@0.28.1": true, + "esbuild@0.28.2": true, "fsevents@2.3.2": false, "fsevents@2.3.3": false } diff --git a/playwright.config.ts b/playwright.config.ts index cb4b2fd..76e1df9 100644 --- a/playwright.config.ts +++ b/playwright.config.ts @@ -1,14 +1,23 @@ import { defineConfig, devices } from "@playwright/test"; +const crossEngineSmoke = process.env.CONTROLCURRENT_BROWSER_SMOKE === "1"; +const crossEngineWorkflows = process.env.CONTROLCURRENT_BROWSER_WORKFLOWS === "1"; +const crossEngine = crossEngineSmoke || crossEngineWorkflows; +const optionalTests = crossEngineWorkflows ? /@(?:smoke|workflow)/u : /@smoke/u; +const fixtureOrigin = `${crossEngine ? "https" : "http"}://127.0.0.1:4389`; + export default defineConfig({ testDir: "e2e", fullyParallel: false, forbidOnly: Boolean(process.env.CI), retries: process.env.CI ? 1 : 0, - ...(process.env.CI ? { workers: 1 } : {}), + ...(process.env.CI || crossEngine ? { workers: 1 } : {}), reporter: [["line"]], use: { - baseURL: "http://127.0.0.1:4389", + baseURL: fixtureOrigin, + // Context-wide test-only bypass for the disposable loopback certificate; + // this does not verify production TLS or pin a particular certificate. + ignoreHTTPSErrors: crossEngine, trace: "retain-on-failure", screenshot: "only-on-failure" }, @@ -16,11 +25,18 @@ export default defineConfig({ { name: "chromium", use: { ...devices["Desktop Chrome"] } - } + }, + ...(crossEngine + ? [ + { name: "firefox", use: { ...devices["Desktop Firefox"] }, grep: optionalTests }, + { name: "webkit", use: { ...devices["Desktop Safari"] }, grep: optionalTests } + ] + : []) ], webServer: { - command: "npm run build && tsx tools/serve-dist.ts", - url: "http://127.0.0.1:4389", + command: `npm run build && tsx tools/serve-dist.ts${crossEngine ? " --https-fixture" : ""}`, + url: fixtureOrigin, + ignoreHTTPSErrors: crossEngine, reuseExistingServer: false, timeout: 60_000 } diff --git a/public/schemas/browser-policy-evaluation.schema.json b/public/schemas/browser-policy-evaluation.schema.json index 0396220..aa8048e 100644 --- a/public/schemas/browser-policy-evaluation.schema.json +++ b/public/schemas/browser-policy-evaluation.schema.json @@ -6,7 +6,7 @@ "properties": { "bcdTimestamp": { "format": "date-time", - "pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z))$", + "pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d:[0-5]\\d(?:\\.\\d+)?(?:Z))$", "type": "string" }, "bcdVersion": { diff --git a/public/schemas/decision-packet.schema.json b/public/schemas/decision-packet.schema.json index 778db4f..8397a06 100644 --- a/public/schemas/decision-packet.schema.json +++ b/public/schemas/decision-packet.schema.json @@ -12,7 +12,7 @@ "properties": { "bcdTimestamp": { "format": "date-time", - "pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z))$", + "pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d:[0-5]\\d(?:\\.\\d+)?(?:Z))$", "type": "string" }, "bcdVersion": { @@ -757,7 +757,7 @@ "properties": { "completedAt": { "format": "date-time", - "pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z))$", + "pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d:[0-5]\\d(?:\\.\\d+)?(?:Z))$", "type": "string" }, "producer": { @@ -783,7 +783,7 @@ }, "startedAt": { "format": "date-time", - "pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z))$", + "pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d:[0-5]\\d(?:\\.\\d+)?(?:Z))$", "type": "string" } }, @@ -835,7 +835,7 @@ }, "bcdTimestamp": { "format": "date-time", - "pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z))$", + "pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d:[0-5]\\d(?:\\.\\d+)?(?:Z))$", "type": "string" }, "bcdVersion": { @@ -1304,7 +1304,7 @@ }, "generatedAt": { "format": "date-time", - "pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z))$", + "pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d:[0-5]\\d(?:\\.\\d+)?(?:Z))$", "type": "string" }, "includedEntries": { @@ -2358,7 +2358,7 @@ "properties": { "completedAt": { "format": "date-time", - "pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z))$", + "pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d:[0-5]\\d(?:\\.\\d+)?(?:Z))$", "type": "string" }, "producer": { @@ -2384,7 +2384,7 @@ }, "startedAt": { "format": "date-time", - "pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z))$", + "pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d:[0-5]\\d(?:\\.\\d+)?(?:Z))$", "type": "string" } }, @@ -2431,7 +2431,7 @@ }, "bcdTimestamp": { "format": "date-time", - "pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z))$", + "pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d:[0-5]\\d(?:\\.\\d+)?(?:Z))$", "type": "string" }, "bcdVersion": { @@ -2499,7 +2499,7 @@ }, "generatedAt": { "format": "date-time", - "pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z))$", + "pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d:[0-5]\\d(?:\\.\\d+)?(?:Z))$", "type": "string" }, "includedEntries": { diff --git a/public/schemas/evidence-policy-evaluation.schema.json b/public/schemas/evidence-policy-evaluation.schema.json index c374026..f5c8538 100644 --- a/public/schemas/evidence-policy-evaluation.schema.json +++ b/public/schemas/evidence-policy-evaluation.schema.json @@ -488,7 +488,7 @@ "properties": { "completedAt": { "format": "date-time", - "pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z))$", + "pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d:[0-5]\\d(?:\\.\\d+)?(?:Z))$", "type": "string" }, "producer": { @@ -514,7 +514,7 @@ }, "startedAt": { "format": "date-time", - "pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z))$", + "pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d:[0-5]\\d(?:\\.\\d+)?(?:Z))$", "type": "string" } }, @@ -561,7 +561,7 @@ }, "bcdTimestamp": { "format": "date-time", - "pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z))$", + "pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d:[0-5]\\d(?:\\.\\d+)?(?:Z))$", "type": "string" }, "bcdVersion": { @@ -629,7 +629,7 @@ }, "generatedAt": { "format": "date-time", - "pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z))$", + "pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d:[0-5]\\d(?:\\.\\d+)?(?:Z))$", "type": "string" }, "includedEntries": { diff --git a/public/schemas/reduced-evidence-report.schema.json b/public/schemas/reduced-evidence-report.schema.json index 7e04f37..45965f1 100644 --- a/public/schemas/reduced-evidence-report.schema.json +++ b/public/schemas/reduced-evidence-report.schema.json @@ -446,7 +446,7 @@ "properties": { "completedAt": { "format": "date-time", - "pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z))$", + "pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d:[0-5]\\d(?:\\.\\d+)?(?:Z))$", "type": "string" }, "producer": { @@ -472,7 +472,7 @@ }, "startedAt": { "format": "date-time", - "pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z))$", + "pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d:[0-5]\\d(?:\\.\\d+)?(?:Z))$", "type": "string" } }, @@ -524,7 +524,7 @@ }, "bcdTimestamp": { "format": "date-time", - "pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z))$", + "pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d:[0-5]\\d(?:\\.\\d+)?(?:Z))$", "type": "string" }, "bcdVersion": { @@ -993,7 +993,7 @@ }, "generatedAt": { "format": "date-time", - "pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z))$", + "pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d:[0-5]\\d(?:\\.\\d+)?(?:Z))$", "type": "string" }, "includedEntries": { diff --git a/src/assurance.ts b/src/assurance.ts index 3a006d8..f74e19c 100644 --- a/src/assurance.ts +++ b/src/assurance.ts @@ -216,7 +216,12 @@ function cspDirectiveFinding( ); } const present = - enforced.state === "present" && enforced.policies.some((policy) => policy.has(directive)); + enforced.state === "present" && + enforced.policies.some((policy) => + directive === "base-uri" + ? ["'none'", "'self'"].includes((policy.get(directive) ?? []).join(" ")) + : policy.has(directive) + ); const reported = reportOnly.state === "present" && reportOnly.policies.some((policy) => policy.has(directive)); return finding( @@ -264,6 +269,60 @@ export function cspElementTokens(policy: CspPolicy, kind: "script" | "style"): s return directive ? (policy.get(directive) ?? []) : []; } +/** Count effective broad allowances, respecting CSP3 ignored source expressions. */ +export function effectiveCspBroadSourceCount( + tokens: readonly string[], + kind: "script" | "style" +): number { + const authorisation = tokens.some( + (token) => + parseCspNonceSource(token).state === "valid" || parseCspHashSource(token).metadata.length > 0 + ); + const dynamic = kind === "script" && authorisation && tokens.includes("'strict-dynamic'"); + return tokens.filter((token) => { + const lower = token.toLowerCase(); + if (["'unsafe-eval'", "'wasm-unsafe-eval'"].includes(lower)) return true; + if (lower === "'unsafe-inline'") return !authorisation; + const location = lower === "*" || lower === "'self'" || !lower.startsWith("'"); + return location && !dynamic; + }).length; +} + +export function scriptCspCandidate(snapshotInput: unknown): "satisfied" | "gap" | "review" { + const { enforced } = extractCspEvidence(snapshotInput); + if (enforced.state === "invalid") return "review"; + if (enforced.state !== "present") return "gap"; + if (enforced.policies.length !== 1) return "review"; + const policy = enforced.policies[0]; + if (!policy || !["'none'", "'self'"].includes((policy.get("base-uri") ?? []).join(" "))) + return "gap"; + // Both the element override and the general script list must meet this declaration recipe. + const lists = effectiveDirectiveTokens(policy, SCRIPT_SOURCE_CHAINS); + if (lists.length !== SCRIPT_SOURCE_CHAINS.length) return "gap"; + for (const tokens of lists) { + if ( + !tokens.some( + (token) => + parseCspNonceSource(token).state === "valid" || + parseCspHashSource(token).metadata.length > 0 + ) + ) + return "gap"; + if ( + tokens.some( + (token) => + ["invalid", "short"].includes(parseCspNonceSource(token).state) || + parseCspHashSource(token).invalidSupportedTokenCount > 0 + ) + ) + return "review"; + if (effectiveCspBroadSourceCount(tokens, "script") > 0) return "gap"; + } + const attributes = policy.get("script-src-attr"); + if (attributes && effectiveCspBroadSourceCount(attributes, "script") > 0) return "gap"; + return "satisfied"; +} + function cspHasToken( result: CspParseResult, chains: readonly (readonly string[])[], diff --git a/src/catalogue.ts b/src/catalogue.ts index 027d052..9714a3d 100644 --- a/src/catalogue.ts +++ b/src/catalogue.ts @@ -64,7 +64,7 @@ export const SECURITY_CONTROLS = [ "Use a carefully scoped CSP and avoid inline script where a nonce deployment cannot be validated.", mappingState: "unsupported", mappingNote: - "BCD 8.0.8 does not publish a standalone compatibility statement for CSP nonce source expressions.", + "BCD 8.1.4 does not publish a standalone compatibility statement for CSP nonce source expressions.", combination: "all", bcdPaths: [], specificationUrls: ["https://w3c.github.io/webappsec-csp/#grammardef-nonce-source"] @@ -87,7 +87,7 @@ export const SECURITY_CONTROLS = [ "Use nonces or external resources under a restrictive CSP when hash maintenance is unsuitable.", mappingState: "unsupported", mappingNote: - "BCD 8.0.8 does not publish a standalone compatibility statement for CSP hash source expressions.", + "BCD 8.1.4 does not publish a standalone compatibility statement for CSP hash source expressions.", combination: "all", bcdPaths: [], specificationUrls: ["https://w3c.github.io/webappsec-csp/#grammardef-hash-source"] diff --git a/src/ci-output.ts b/src/ci-output.ts index 233ba09..8dfbd5b 100644 --- a/src/ci-output.ts +++ b/src/ci-output.ts @@ -1,6 +1,7 @@ import { decisionPacketComparisonSchema, evidencePolicyEvaluationSchema, + evidenceReportComparisonSchema, policyDriftComparisonSchema, policyEvaluationSchema } from "./contracts"; @@ -8,25 +9,33 @@ import { export type CliOutputFormat = "text" | "json" | "markdown" | "junit"; function markdown(value: string): string { - return Array.from(value) - .map((character) => { - const codePoint = character.codePointAt(0); - return codePoint !== undefined && (codePoint < 32 || codePoint === 127) ? " " : character; - }) - .join("") - .replaceAll("\\", "\\\\") - .replaceAll("|", "\\|") - .trim(); + return ( + Array.from(value) + .map((character) => { + const codePoint = character.codePointAt(0); + return codePoint !== undefined && (codePoint < 32 || codePoint === 127) ? " " : character; + }) + .join("") + // Escape all CommonMark punctuation in supplied text, including entities, + // HTML, autolinks, images and formatting. Renderer-owned syntax stays intact. + .replace(/[!"#$%&'()*+,\-./:;<=>?@[\\\]^_`{|}~]/gu, "\\$&") + .trim() + ); } function xml(value: string): string { return Array.from(value) .map((character) => { const codePoint = character.codePointAt(0); - return codePoint !== undefined && - ((codePoint < 32 && ![9, 10, 13].includes(codePoint)) || codePoint === 127) - ? " " - : character; + // XML 1.0 Char: replace each forbidden code point (including lone surrogates) + // with one space, while preserving legal BMP and supplementary characters. + const legal = + codePoint !== undefined && + ([9, 10, 13].includes(codePoint) || + (codePoint >= 0x20 && codePoint <= 0xd7ff) || + (codePoint >= 0xe000 && codePoint <= 0xfffd) || + (codePoint >= 0x10000 && codePoint <= 0x10ffff)); + return legal ? character : " "; }) .join("") .replaceAll("&", "&") @@ -53,11 +62,13 @@ function junitSuite( name: string, cases: readonly string[], failures: number, - skipped: number + skipped: number, + properties = "" ): string { return [ '', ``, + ...(properties ? [properties] : []), ...cases, "", "" @@ -172,6 +183,11 @@ export function renderPolicyDriftMarkdown(input: unknown): string { `- Review: ${String(comparison.summary.review)}`, `- Information: ${String(comparison.summary.information)}`, `- Expiring exceptions: ${String(comparison.summary.expiringExceptions)}`, + ...(comparison.summary.truncated + ? [ + `- Displayed events: ${String(comparison.summary.emittedEvents)} of ${String(comparison.summary.totalEvents)}; full totals determine the gate.` + ] + : []), "", ...(rows.length ? ["| Classification | Change | Summary |", "| --- | --- | --- |", ...rows] @@ -190,11 +206,26 @@ export function renderPolicyDriftJunit(input: unknown): string { item.summary ) ); + const visibleFailures = comparison.events.filter((item) => item.severity === "regression").length; + const visibleReview = comparison.events.filter((item) => item.severity === "review").length; + const hiddenFailures = comparison.summary.regressions - visibleFailures; + const hiddenReview = comparison.summary.review - visibleReview; + const omitted = comparison.summary.truncated === true; + if (omitted) + cases.push( + junitCase( + "Omitted bounded events", + "browser policy", + hiddenFailures > 0 ? "fail" : hiddenReview > 0 ? "review" : "pass", + `${String(hiddenFailures)} adverse and ${String(hiddenReview)} review events were omitted; full totals still determine the gate.` + ) + ); return junitSuite( `${comparison.beforeProfileName} to ${comparison.afterProfileName}`, cases, - comparison.summary.regressions, - comparison.summary.review + visibleFailures + (omitted && hiddenFailures > 0 ? 1 : 0), + visibleReview + (omitted && hiddenFailures <= 0 && hiddenReview > 0 ? 1 : 0), + `` ); } @@ -217,6 +248,12 @@ export function renderDecisionPacketComparisonMarkdown(input: unknown): string { "", "## Evidence", "", + ...(comparison.evidence.summary.truncated + ? [ + `Showing ${String(comparison.evidence.summary.emittedEvents)} of ${String(comparison.evidence.summary.totalEvents)} evidence events; the totals and gate include omitted events.`, + "" + ] + : []), ...(comparison.evidence.events.length ? comparison.evidence.events.map( (item) => `- **${markdown(item.type)}** ${markdown(item.summary)}` @@ -250,10 +287,116 @@ export function renderDecisionPacketComparisonJunit(input: unknown): string { item.summary ) ); + const visibleFailures = + comparison.browserPolicy.events.filter((item) => item.severity === "regression").length + + comparison.evidence.events.filter((item) => ["regression", "incomparable"].includes(item.type)) + .length; + const visibleReview = + comparison.browserPolicy.events.filter((item) => item.severity === "review").length + + comparison.evidence.events.filter((item) => item.type === "changed").length; + const hiddenFailures = + comparison.summary.regressions + comparison.summary.incomparable - visibleFailures; + const hiddenReview = + comparison.summary.review + comparison.evidence.summary.changed - visibleReview; + const omitted = + comparison.evidence.summary.truncated === true || + comparison.browserPolicy.summary.truncated === true; + const summaryCases = omitted + ? [ + junitCase( + "Omitted bounded events", + "decision packet", + hiddenFailures > 0 ? "fail" : hiddenReview > 0 ? "review" : "pass", + `${String(hiddenFailures)} adverse and ${String(hiddenReview)} review events were omitted from the display. Full totals still determine the gate.` + ) + ] + : []; + const properties = ``; return junitSuite( "decision packet comparison", - [...policyCases, ...evidenceCases], - comparison.summary.regressions + comparison.summary.incomparable, - comparison.summary.review + comparison.summary.changed + [...policyCases, ...evidenceCases, ...summaryCases], + visibleFailures + (omitted && hiddenFailures > 0 ? 1 : 0), + visibleReview + (omitted && hiddenFailures <= 0 && hiddenReview > 0 ? 1 : 0), + properties + ); +} + +const REPORT_REGRESSIONS = new Set([ + "finding_regressed", + "composite_regressed", + "surface_gap_added" +]); + +export function renderEvidenceReportComparisonMarkdown(input: unknown): string { + const comparison = evidenceReportComparisonSchema.parse(input); + return [ + `# Evidence report comparison: ${markdown(comparison.beforeName)} to ${markdown(comparison.afterName)}`, + "", + `- Regressions: ${String(comparison.summary.regressions)}`, + `- Resolutions: ${String(comparison.summary.resolutions)}`, + `- Other changes: ${String(comparison.summary.changed)}`, + `- Incomparable: ${String(comparison.summary.incomparable)}`, + `- Events: ${String(comparison.summary.totalEvents)} total, ${String(comparison.summary.emittedEvents)} emitted, truncated: ${String(comparison.summary.truncated)}`, + `- Report context compatible: ${String(comparison.compatible)}`, + ...comparison.compatibilityReasons.map((reason) => `- ${markdown(reason)}`), + "", + ...(comparison.events.length + ? [ + "| Change | Key | Summary |", + "| --- | --- | --- |", + ...comparison.events.map( + (item) => + `| ${markdown(item.type)} | ${markdown(item.key)} | ${markdown(item.summary)} |` + ) + ] + : ["No evidence changes were detected."]), + "", + "Complete totals determine exit gates. Supplied evidence does not prove runtime enforcement or collection authenticity.", + "" + ].join("\n"); +} + +export function renderEvidenceReportComparisonJunit(input: unknown): string { + const comparison = evidenceReportComparisonSchema.parse(input); + const adverse = (type: string) => + REPORT_REGRESSIONS.has(type) || type === "evidence_became_incomparable"; + const cases = comparison.events.map((item) => + junitCase( + `${item.type} / ${item.key}`, + "evidence report comparison", + adverse(item.type) ? "fail" : "pass", + item.summary + ) + ); + const visibleFailures = comparison.events.filter((item) => adverse(item.type)).length; + const hiddenFailures = + comparison.summary.regressions + comparison.summary.incomparable - visibleFailures; + if (comparison.summary.truncated) + cases.push( + junitCase( + "Omitted bounded events", + "evidence report comparison", + hiddenFailures > 0 ? "fail" : "pass", + `${String(comparison.summary.totalEvents - comparison.summary.emittedEvents)} events omitted, including ${String(hiddenFailures)} regressions or incomparable results; complete totals determine exit gates.` + ) + ); + const properties = { + "total-regressions": comparison.summary.regressions, + "total-resolutions": comparison.summary.resolutions, + "total-changed": comparison.summary.changed, + "total-incomparable": comparison.summary.incomparable, + "total-events": comparison.summary.totalEvents, + "emitted-events": comparison.summary.emittedEvents, + truncated: comparison.summary.truncated, + "context-compatible": comparison.compatible + }; + return junitSuite( + `${comparison.beforeName} to ${comparison.afterName}`, + cases, + visibleFailures + (comparison.summary.truncated && hiddenFailures > 0 ? 1 : 0), + 0, + `${Object.entries(properties) + .map(([name, value]) => ``) + .join("")}` ); } diff --git a/src/collector.ts b/src/collector.ts index ac44bb6..d67b463 100644 --- a/src/collector.ts +++ b/src/collector.ts @@ -10,6 +10,12 @@ export const MAX_COLLECTOR_MANIFEST_BYTES = 64 * 1_024; export const MAX_COLLECTOR_BODY_BYTES = 128 * 1_024; export const MAX_COLLECTOR_REDIRECTS = 5; export const COLLECTOR_TIMEOUT_MS = 10_000; +export const MAX_COLLECTOR_RESPONSES = 16; +export const MAX_COLLECTOR_TOTAL_HTML_BYTES = 512 * 1_024; + +function labelledId(id: string, suffix: string): string { + return `${id.slice(0, 80 - suffix.length)}${suffix}`; +} const opaqueIdSchema = z.string().regex(/^[a-z0-9][a-z0-9._-]{0,79}$/u); const pathSchema = z @@ -100,7 +106,7 @@ export const collectorManifestSchema = z .optional(), producerId: opaqueIdSchema, completeness: z.enum(["complete", "unknown"]), - surfaces: z.array(collectorSurfaceSchema).min(1).max(32) + surfaces: z.array(collectorSurfaceSchema).min(1).max(MAX_COLLECTOR_RESPONSES) }) .strict() .superRefine((manifest, context) => { @@ -154,29 +160,35 @@ export async function collectEvidenceBundle( const startedAt = clock().toISOString(); const responses: EvidenceBundleInput["responses"] = []; const htmlDocuments: EvidenceBundleInput["htmlDocuments"] = []; + let htmlBytes = 0; - for (const surface of manifest.surfaces) { + for (const [index, surface] of manifest.surfaces.entries()) { + // Reserve a response slot for each remaining surface before permitting redirects. + const slots = + MAX_COLLECTOR_RESPONSES - responses.length - (manifest.surfaces.length - index - 1); const hops = await transport.collect({ baseOrigin: manifest.baseOrigin, path: surface.path, - maximumBodyBytes: MAX_COLLECTOR_BODY_BYTES, - maximumRedirects: MAX_COLLECTOR_REDIRECTS, + maximumBodyBytes: surface.requiredEvidence.includes("html") + ? Math.min(MAX_COLLECTOR_BODY_BYTES, MAX_COLLECTOR_TOTAL_HTML_BYTES - htmlBytes) + : MAX_COLLECTOR_BODY_BYTES, + maximumRedirects: Math.min(MAX_COLLECTOR_REDIRECTS, slots - 1), timeoutMs: COLLECTOR_TIMEOUT_MS }); - if (hops.length === 0 || hops.length > MAX_COLLECTOR_REDIRECTS + 1) { + if (hops.length === 0 || hops.length > Math.min(MAX_COLLECTOR_REDIRECTS + 1, slots)) { throw new Error(`Collector returned an invalid hop count for ${surface.id}.`); } const redirectChainId = hops.some((hop) => hop.outcome === "redirect") - ? `${surface.id}-redirect` + ? labelledId(surface.id, "-redirect") : undefined; for (const [sequence, hop] of hops.entries()) { responses.push({ schemaVersion: 2, - name: `${surface.id} response ${String(sequence + 1)}`, + name: labelledId(surface.id, ` response ${String(sequence + 1)}`), surfaceId: surface.id, context: { schemaVersion: 1, - variantId: `${surface.id}-${surface.authentication}`, + variantId: labelledId(surface.id, `-${surface.authentication}`), sequence, outcome: hop.outcome, status: hop.status, @@ -195,9 +207,16 @@ export async function collectEvidenceBundle( hop.body !== undefined && surface.requiredEvidence.includes("html") ) { + htmlBytes += new TextEncoder().encode(hop.body).byteLength; + if ( + htmlBytes > MAX_COLLECTOR_TOTAL_HTML_BYTES || + new TextEncoder().encode(hop.body).byteLength > MAX_COLLECTOR_BODY_BYTES + ) { + throw new Error("Collector HTML budget exhausted; no complete bundle was produced."); + } htmlDocuments.push({ schemaVersion: 1, - name: `${surface.id} document`, + name: labelledId(surface.id, " document"), surfaceId: surface.id, html: hop.body }); @@ -228,7 +247,7 @@ export async function collectEvidenceBundle( }, scopeInventory: { schemaVersion: 1, - name: `${manifest.name} collector scope`, + name: labelledId(manifest.name, " collector scope"), kind: "authorised_crawl", generatedAt: startedAt, completeness: manifest.completeness, diff --git a/src/components/ControlCard.astro b/src/components/ControlCard.astro index 52578b5..0561ae1 100644 --- a/src/components/ControlCard.astro +++ b/src/components/ControlCard.astro @@ -42,11 +42,9 @@ const searchText = [
{control.category} - { - control.mappingState === "active" - ? `${control.bcdPaths.length} browser data record${control.bcdPaths.length === 1 ? "" : "s"}` - : "Browser data unavailable" - } + {control.mappingState === "active" + ? `${control.bcdPaths.length} browser data record${control.bcdPaths.length === 1 ? "" : "s"}` + : "Browser data unavailable"}

@@ -57,13 +55,11 @@ const searchText = [

{control.summary}

- { - evaluations.map((evaluation) => ( - - {browserNames[evaluation.browser]} - - - )) - } + {evaluations.map((evaluation) => ( + + {browserNames[evaluation.browser]} + + + ))}
diff --git a/src/components/EvidenceBundleInspector.astro b/src/components/EvidenceBundleInspector.astro index 4a0cdcd..ecdf5a5 100644 --- a/src/components/EvidenceBundleInspector.astro +++ b/src/components/EvidenceBundleInspector.astro @@ -47,12 +47,18 @@ import { selectedSnapshot } from "../data"; the file.

- - + + - +

@@ -88,7 +94,9 @@ import { selectedSnapshot } from "../data";
- + @@ -103,648 +111,6 @@ import { selectedSnapshot } from "../data"; diff --git a/src/components/HeaderInspector.astro b/src/components/HeaderInspector.astro index 2d56910..aa5bfcf 100644 --- a/src/components/HeaderInspector.astro +++ b/src/components/HeaderInspector.astro @@ -5,8 +5,8 @@

Response headers are instructions a website sends to the browser. Paste a set below and ControlCurrent will look for recognised security settings. It does not visit the URL, save the - text, or send it anywhere. Replace cookie values and other secrets with{" "} - REDACTED first. + text, or send it anywhere. Replace cookie values and other secrets with REDACTED{" "} + first.

@@ -28,9 +28,15 @@ X-Content-Type-Options: nosniff" If redirects produced several blocks, only the final response is checked.

- - - + + +

diff --git a/src/components/Layout.astro b/src/components/Layout.astro index f42ecc8..e3b98d3 100644 --- a/src/components/Layout.astro +++ b/src/components/Layout.astro @@ -72,7 +72,9 @@ const pathWithBase = (path: string) => `${base}${path}`; its own browser tab before entering any redacted evidence.

- +