From 4294ddc6c549ba805032e6d828ffbb2ddb9b43a2 Mon Sep 17 00:00:00 2001 From: Seongho Bae Date: Fri, 7 Aug 2026 16:26:08 +0900 Subject: [PATCH 01/92] test(supply-chain): require deterministic npm lock generator --- .../tests/test_npm_toolchain_contract.py | 61 +++++++++++++++++++ 1 file changed, 61 insertions(+) create mode 100644 services/analysis-engine/tests/test_npm_toolchain_contract.py diff --git a/services/analysis-engine/tests/test_npm_toolchain_contract.py b/services/analysis-engine/tests/test_npm_toolchain_contract.py new file mode 100644 index 000000000..89301fd9e --- /dev/null +++ b/services/analysis-engine/tests/test_npm_toolchain_contract.py @@ -0,0 +1,61 @@ +"""Contracts for deterministic npm lockfile generation and CI provenance.""" + +from __future__ import annotations + +import json +from pathlib import Path + + +_REPOSITORY_ROOT = Path(__file__).resolve().parents[3] +_EXPECTED_NPM_VERSION = "10.9.8" +_EXPECTED_NODE_VERSION = "22.22.3" + + +def _root_manifest() -> dict[str, object]: + """Return the checked-in root package manifest as a JSON object.""" + manifest = json.loads( + (_REPOSITORY_ROOT / "package.json").read_text(encoding="utf-8") + ) + assert isinstance(manifest, dict) + return manifest + + +def test_root_manifest_pins_the_lockfile_generator_and_fails_on_drift() -> None: + """Require npm and source-tree commands to reject a different generator.""" + manifest = _root_manifest() + + assert manifest["packageManager"] == f"npm@{_EXPECTED_NPM_VERSION}" + assert manifest["engines"]["npm"] == _EXPECTED_NPM_VERSION # type: ignore[index] + assert manifest["devEngines"] == { + "packageManager": { + "name": "npm", + "version": _EXPECTED_NPM_VERSION, + "onFail": "error", + } + } + + +def test_primary_ci_proves_exact_npm_before_install_and_lock_reproduction() -> None: + """Keep the clean installer and lock reproduction on one explicit toolchain.""" + workflow = (_REPOSITORY_ROOT / ".github" / "workflows" / "ci.yml").read_text( + encoding="utf-8" + ) + + assert f'node-version: "{_EXPECTED_NODE_VERSION}"' in workflow + assert f'EXPECTED_NPM_VERSION: "{_EXPECTED_NPM_VERSION}"' in workflow + assert 'test "$(npm --version)" = "$EXPECTED_NPM_VERSION"' in workflow + assert "npm install --package-lock-only" in workflow + assert "--ignore-scripts" in workflow + assert "--no-audit" in workflow + assert "--no-fund" in workflow + assert "git diff --exit-code -- package-lock.json" in workflow + + +def test_root_lock_uses_the_supported_location_keyed_format() -> None: + """Require the npm-v9-and-newer lock format used by the pinned generator.""" + lock_document = json.loads( + (_REPOSITORY_ROOT / "package-lock.json").read_text(encoding="utf-8") + ) + + assert lock_document["lockfileVersion"] == 3 + assert isinstance(lock_document["packages"], dict) From afb20beded7118dc9072fc3ae13d42af5d0b50c8 Mon Sep 17 00:00:00 2001 From: Seongho Bae Date: Fri, 7 Aug 2026 16:27:40 +0900 Subject: [PATCH 02/92] fix(supply-chain): pin npm lock generator metadata --- package.json | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/package.json b/package.json index a71236ed0..276804de1 100644 --- a/package.json +++ b/package.json @@ -3,8 +3,17 @@ "private": true, "version": "0.1.3", "type": "module", + "packageManager": "npm@10.9.8", "engines": { - "node": ">=22.13 <23" + "node": ">=22.13 <23", + "npm": "10.9.8" + }, + "devEngines": { + "packageManager": { + "name": "npm", + "version": "10.9.8", + "onFail": "error" + } }, "workspaces": [ "apps/*", From e64c229c527785278229f9401602e659e8f3d0b6 Mon Sep 17 00:00:00 2001 From: Seongho Bae Date: Fri, 7 Aug 2026 16:28:01 +0900 Subject: [PATCH 03/92] ci(supply-chain): prove npm version and lock reproduction --- .github/workflows/ci.yml | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 5f99a9c17..2750c5e01 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -17,6 +17,7 @@ env: GIT_CONFIG_COUNT: "1" GIT_CONFIG_KEY_0: init.defaultBranch GIT_CONFIG_VALUE_0: develop + EXPECTED_NPM_VERSION: "10.9.8" jobs: verify: @@ -26,14 +27,20 @@ jobs: - uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0 - uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6.4.0 with: - node-version: 22.22.3 + node-version: "22.22.3" cache: npm + - name: Verify exact npm lockfile generator + run: test "$(npm --version)" = "$EXPECTED_NPM_VERSION" - uses: astral-sh/setup-uv@11f9893b081a58869d3b5fccaea48c9e9e46f990 # v8.3.2 with: version: "0.8.6" enable-cache: false - name: Install node dependencies run: npm ci + - name: Prove package lock reproduces with the pinned npm + run: | + npm install --package-lock-only --ignore-scripts --no-audit --no-fund + git diff --exit-code -- package-lock.json - name: Sync Python dependencies run: uv sync --project services/analysis-engine --group dev --frozen - name: Install stable Rust toolchain @@ -56,8 +63,10 @@ jobs: - uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0 - uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6.4.0 with: - node-version: 22.22.3 + node-version: "22.22.3" cache: npm + - name: Verify exact npm lockfile generator + run: test "$(npm --version)" = "$EXPECTED_NPM_VERSION" - name: Install stable Rust toolchain run: rustup toolchain install stable --profile minimal - name: Install node dependencies From ebbde9baf051cd2944d14b141d791ce1777340cb Mon Sep 17 00:00:00 2001 From: Seongho Bae Date: Fri, 7 Aug 2026 16:28:31 +0900 Subject: [PATCH 04/92] docs(supply-chain): record npm generator provenance --- .../npm-lockfile-generator-provenance.md | 76 +++++++++++++++++++ 1 file changed, 76 insertions(+) create mode 100644 docs/doctoring/npm-lockfile-generator-provenance.md diff --git a/docs/doctoring/npm-lockfile-generator-provenance.md b/docs/doctoring/npm-lockfile-generator-provenance.md new file mode 100644 index 000000000..83bf73562 --- /dev/null +++ b/docs/doctoring/npm-lockfile-generator-provenance.md @@ -0,0 +1,76 @@ +# npm lockfile generator provenance + +## Decision + +BandScope generates and verifies its root npm workspace lock with exactly npm `10.9.8`. The root manifest records that decision through: + +- `packageManager: npm@10.9.8` as package-manager selection metadata; +- `engines.npm: 10.9.8` as the published source-tree compatibility declaration; and +- `devEngines.packageManager` with `onFail: error` as npm's source-tree command gate. + +The primary GitHub Actions workflow uses Node `22.22.3`, verifies the bundled npm version before any installation, runs `npm ci`, then runs a package-lock-only regeneration with scripts, audit, and funding output disabled. Any `package-lock.json` diff fails the exact head. + +The Node runtime support decision remains separate. This change does not raise the public `>=22.13 <23` Node range; a coordinated Node-floor migration is tracked independently. + +## Why the generator is part of the lock identity + +npm documents `package-lock.json` as the location-keyed description of the exact dependency tree. Lockfile version 3 is intended for npm 9 and newer. npm also notes that different package-manager versions may use different installation algorithms and metadata representations. A committed lockfile therefore is not fully reproducible unless the generator version and install-shaping flags are versioned with it. + +`npm ci` is the immutable consumption path: it requires a lockfile, rejects manifest/lock dependency disagreement, removes an existing `node_modules`, and does not write the manifest or lock. It does not prove that a future dependency update will regenerate byte-identical metadata. The additional package-lock-only replay closes that gap. + +```mermaid +flowchart LR + M[package.json ranges and workspaces] --> G[npm 10.9.8] + C[project npm configuration] --> G + G --> L[package-lock.json v3] + L --> I[npm ci clean install] + I --> R[npm 10.9.8 package-lock-only replay] + R --> D{lock diff?} + D -->|no| A[reproducible exact-head evidence] + D -->|yes| F[fail closed] +``` + +## Security and operational boundary + +- Dependency PRs may change only manifest ranges and the lock records produced by npm `10.9.8`. +- Reviewers must reject unrelated lock metadata that cannot be reproduced by the pinned generator. +- No lock record may be added or removed by hand to satisfy a validator. +- Install-shaping flags that change the tree, such as `legacy-peer-deps` or `install-links`, must be committed in project configuration and used identically by `npm ci` and regeneration. +- Dependency lifecycle scripts remain disabled for the reproduction pass. The normal clean install retains the repository's reviewed execution behavior. +- The exact npm version check occurs before `npm ci`; a different bundled or globally installed npm cannot generate acceptance evidence. +- The lockfile remains the sole npm workspace lock. Nested workspace locks are prohibited. + +`packageManager` alone is not the enforcement boundary for npm because Corepack's npm shim is not enabled by default in Node distributions. Enforcement is provided by npm `devEngines`, the explicit CI version assertion, and the lock replay. + +## Verification + +`services/analysis-engine/tests/test_npm_toolchain_contract.py` verifies the manifest metadata, exact CI Node/npm identity, replay command and flags, clean lock diff, and lockfile version 3. Repository CI then executes the replay using the hosted toolchain. + +A dependency update is mergeable only after: + +1. npm `10.9.8` produces the checked-in lock from the updated manifest; +2. a second package-lock-only replay is byte-clean; +3. `npm ci`, lint, strict typecheck, measured tests, production build, Rust/Tauri checks, and security/supply-chain gates succeed on the same head; and +4. current-head review, unresolved-thread, independent-approval, and branch-protection requirements succeed without bypass. + +## Incident response and rollback + +When replay changes the lock unexpectedly: + +1. preserve the exact head SHA, npm and Node versions, command flags, original lock blob SHA, regenerated lock, and CI run ID; +2. determine whether the manifest changed, npm changed, project configuration changed, or the protected lock was generated by a different toolchain; +3. never accept a partial or hand-edited lock; +4. regenerate from a clean checkout using the reviewed npm version and run the replay twice; +5. if rollback is necessary, restore the prior manifest and complete lock together, then rerun the entire exact-head gate. + +## References + +npm, Inc. (2026). *npm ci*. npm Docs. https://docs.npmjs.com/cli/v11/commands/npm-ci/ + +npm, Inc. (2026). *npm install*. npm Docs. https://docs.npmjs.com/cli/v10/commands/npm-install/ + +npm, Inc. (2026). *package-lock.json*. npm Docs. https://docs.npmjs.com/cli/v11/configuring-npm/package-lock-json/ + +npm, Inc. (2026). *package.json*. npm Docs. https://docs.npmjs.com/cli/configuring-npm/package-json/ + +Node.js contributors. (2026). *Corepack* [Software documentation]. GitHub. https://github.com/nodejs/corepack From 694ca83b4dfd31ef12be464d832b6bb84fb07362 Mon Sep 17 00:00:00 2001 From: Seongho Bae Date: Fri, 7 Aug 2026 16:29:00 +0900 Subject: [PATCH 05/92] docs(changelog): record npm generator contract --- CHANGELOG.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index eea696893..05f555100 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,10 @@ - Display the analyzed song tempo (BPM) as a badge in the rehearsal workspace. - 각 합주 역할(Role)별 개인 연습 진행도를 0~100% 범위로 기록 및 시각화할 수 있는 연습 진척도(`practiceProgress`) 트래커 기능 추가. UI 컨트롤(슬라이더 및 +/- 버튼)과 한/영 다국어 지원 포함. +### Changed + +- Pinned npm `10.9.8` as the lockfile generator and made primary CI reject a different npm version or any package-lock-only replay diff. + ## [0.1.3] - 2026-04-29 ### Fixed From 90dc2a0248bd5259a24040303368acf7b909f376 Mon Sep 17 00:00:00 2001 From: Seongho Bae Date: Fri, 7 Aug 2026 16:58:59 +0900 Subject: [PATCH 06/92] fix(supply-chain): avoid serializing npm into runtime engines --- package.json | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/package.json b/package.json index 276804de1..779899ede 100644 --- a/package.json +++ b/package.json @@ -5,8 +5,7 @@ "type": "module", "packageManager": "npm@10.9.8", "engines": { - "node": ">=22.13 <23", - "npm": "10.9.8" + "node": ">=22.13 <23" }, "devEngines": { "packageManager": { From fecc36b309f92afcf497a431edef4911dc6104f4 Mon Sep 17 00:00:00 2001 From: Seongho Bae Date: Fri, 7 Aug 2026 16:59:31 +0900 Subject: [PATCH 07/92] test(supply-chain): keep npm enforcement out of runtime engines --- services/analysis-engine/tests/test_npm_toolchain_contract.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/services/analysis-engine/tests/test_npm_toolchain_contract.py b/services/analysis-engine/tests/test_npm_toolchain_contract.py index 89301fd9e..b4a0ae46d 100644 --- a/services/analysis-engine/tests/test_npm_toolchain_contract.py +++ b/services/analysis-engine/tests/test_npm_toolchain_contract.py @@ -25,7 +25,7 @@ def test_root_manifest_pins_the_lockfile_generator_and_fails_on_drift() -> None: manifest = _root_manifest() assert manifest["packageManager"] == f"npm@{_EXPECTED_NPM_VERSION}" - assert manifest["engines"]["npm"] == _EXPECTED_NPM_VERSION # type: ignore[index] + assert manifest["engines"] == {"node": ">=22.13 <23"} assert manifest["devEngines"] == { "packageManager": { "name": "npm", From 9eb83c39c9978ad730824d6e93218565b5b7d577 Mon Sep 17 00:00:00 2001 From: Seongho Bae Date: Fri, 7 Aug 2026 17:00:13 +0900 Subject: [PATCH 08/92] docs(supply-chain): separate npm generator from runtime engines --- docs/doctoring/npm-lockfile-generator-provenance.md | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/docs/doctoring/npm-lockfile-generator-provenance.md b/docs/doctoring/npm-lockfile-generator-provenance.md index 83bf73562..1d50f2a5d 100644 --- a/docs/doctoring/npm-lockfile-generator-provenance.md +++ b/docs/doctoring/npm-lockfile-generator-provenance.md @@ -4,10 +4,11 @@ BandScope generates and verifies its root npm workspace lock with exactly npm `10.9.8`. The root manifest records that decision through: -- `packageManager: npm@10.9.8` as package-manager selection metadata; -- `engines.npm: 10.9.8` as the published source-tree compatibility declaration; and +- `packageManager: npm@10.9.8` as package-manager selection metadata; and - `devEngines.packageManager` with `onFail: error` as npm's source-tree command gate. +The npm version is intentionally not repeated under `engines`. npm serializes `engines` into the root lock package, so adding an npm-only source-tool constraint there creates lock metadata churn unrelated to dependency resolution. `devEngines`, the explicit CI assertion, and the replay gate enforce the generator while the published `engines.node` range remains the runtime compatibility contract. + The primary GitHub Actions workflow uses Node `22.22.3`, verifies the bundled npm version before any installation, runs `npm ci`, then runs a package-lock-only regeneration with scripts, audit, and funding output disabled. Any `package-lock.json` diff fails the exact head. The Node runtime support decision remains separate. This change does not raise the public `>=22.13 <23` Node range; a coordinated Node-floor migration is tracked independently. @@ -44,7 +45,7 @@ flowchart LR ## Verification -`services/analysis-engine/tests/test_npm_toolchain_contract.py` verifies the manifest metadata, exact CI Node/npm identity, replay command and flags, clean lock diff, and lockfile version 3. Repository CI then executes the replay using the hosted toolchain. +`services/analysis-engine/tests/test_npm_toolchain_contract.py` verifies the manifest metadata, separation of runtime and generator constraints, exact CI Node/npm identity, replay command and flags, clean lock diff, and lockfile version 3. Repository CI then executes the replay using the hosted toolchain. A dependency update is mergeable only after: From 5609b8828c7cd5e0bec0d0eed0a56d58197b8e86 Mon Sep 17 00:00:00 2001 From: Seongho Bae Date: Fri, 7 Aug 2026 17:04:24 +0900 Subject: [PATCH 09/92] ci(supply-chain): publish deterministic lock reproduction evidence --- .github/workflows/ci.yml | 30 ++++++++++++++++++++++++++---- 1 file changed, 26 insertions(+), 4 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 2750c5e01..8311a1dae 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -20,8 +20,33 @@ env: EXPECTED_NPM_VERSION: "10.9.8" jobs: + lock-reproduction: + name: gate / ci / npm-lock-reproduction + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0 + - uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6.4.0 + with: + node-version: "22.22.3" + cache: npm + - name: Verify exact npm lockfile generator + run: test "$(npm --version)" = "$EXPECTED_NPM_VERSION" + - name: Reproduce package lock without lifecycle execution + run: npm install --package-lock-only --ignore-scripts --no-audit --no-fund + - name: Preserve the exact generated lock as review evidence + if: always() + uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1 + with: + name: npm-lock-reproduction-${{ github.event.pull_request.head.sha || github.sha }} + path: package-lock.json + if-no-files-found: error + retention-days: 3 + - name: Reject lockfile drift + run: git diff --exit-code -- package-lock.json + verify: name: ci / build-and-test + needs: lock-reproduction runs-on: ubuntu-latest steps: - uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0 @@ -37,10 +62,6 @@ jobs: enable-cache: false - name: Install node dependencies run: npm ci - - name: Prove package lock reproduces with the pinned npm - run: | - npm install --package-lock-only --ignore-scripts --no-audit --no-fund - git diff --exit-code -- package-lock.json - name: Sync Python dependencies run: uv sync --project services/analysis-engine --group dev --frozen - name: Install stable Rust toolchain @@ -58,6 +79,7 @@ jobs: rust-check: name: gate / ci / rust-check + needs: lock-reproduction runs-on: macos-15 steps: - uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0 From 032314d724e0ddc5ce16c7958ee364dd40264699 Mon Sep 17 00:00:00 2001 From: Seongho Bae Date: Fri, 7 Aug 2026 17:04:59 +0900 Subject: [PATCH 10/92] test(supply-chain): require preserved lock reproduction evidence --- .../analysis-engine/tests/test_npm_toolchain_contract.py | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/services/analysis-engine/tests/test_npm_toolchain_contract.py b/services/analysis-engine/tests/test_npm_toolchain_contract.py index b4a0ae46d..30e00cbdd 100644 --- a/services/analysis-engine/tests/test_npm_toolchain_contract.py +++ b/services/analysis-engine/tests/test_npm_toolchain_contract.py @@ -44,10 +44,15 @@ def test_primary_ci_proves_exact_npm_before_install_and_lock_reproduction() -> N assert f'node-version: "{_EXPECTED_NODE_VERSION}"' in workflow assert f'EXPECTED_NPM_VERSION: "{_EXPECTED_NPM_VERSION}"' in workflow assert 'test "$(npm --version)" = "$EXPECTED_NPM_VERSION"' in workflow + assert "lock-reproduction:" in workflow + assert "needs: lock-reproduction" in workflow assert "npm install --package-lock-only" in workflow assert "--ignore-scripts" in workflow assert "--no-audit" in workflow assert "--no-fund" in workflow + assert "actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a" in workflow + assert "npm-lock-reproduction-${{ github.event.pull_request.head.sha || github.sha }}" in workflow + assert "if-no-files-found: error" in workflow assert "git diff --exit-code -- package-lock.json" in workflow From 0263ad427aa543e42ad9f01be1858074cf43ac52 Mon Sep 17 00:00:00 2001 From: Seongho Bae Date: Fri, 7 Aug 2026 17:08:32 +0900 Subject: [PATCH 11/92] test(security): require coordinated PDF.js and Undici baseline --- .../test_high_security_dependency_baseline.py | 79 +++++++++++++++++++ 1 file changed, 79 insertions(+) create mode 100644 services/analysis-engine/tests/test_high_security_dependency_baseline.py diff --git a/services/analysis-engine/tests/test_high_security_dependency_baseline.py b/services/analysis-engine/tests/test_high_security_dependency_baseline.py new file mode 100644 index 000000000..01dba0ab8 --- /dev/null +++ b/services/analysis-engine/tests/test_high_security_dependency_baseline.py @@ -0,0 +1,79 @@ +"""Contracts for the coordinated PDF.js and Undici security baseline.""" + +from __future__ import annotations + +import json +from pathlib import Path + + +_REPOSITORY_ROOT = Path(__file__).resolve().parents[3] +_PDFJS_VERSION = "6.2.108" +_UNDICI_VERSION = "7.29.0" +_PDFJS_INTEGRITY = ( + "sha512-YxFb+SQcodN2rnX9Tn3dHYlqfb7NjlzzfONPpJd+AKoKtUjEdevTfbC07d5Tcczz" + "OK6261auRkP/M8OBHs9vFQ==" +) +_UNDICI_INTEGRITY = ( + "sha512-IDxfleLmmbSskfWSUATiN1nfn2rDuvnMOqb5CWR92iIfojA0Ud+ulOAAEQ57LPr9" + "rWmsreUyf5lwyao+7GNNVw==" +) + + +def _read_json(relative_path: str) -> dict[str, object]: + """Return one repository JSON document as a mapping.""" + document = json.loads( + (_REPOSITORY_ROOT / relative_path).read_text(encoding="utf-8") + ) + assert isinstance(document, dict) + return document + + +def test_manifests_pin_the_security_floors_without_semver_drift() -> None: + """Keep the vulnerable transitive client and PDF parser on exact versions.""" + root_manifest = _read_json("package.json") + desktop_manifest = _read_json("apps/desktop/package.json") + + assert root_manifest["overrides"]["undici"] == _UNDICI_VERSION # type: ignore[index] + assert desktop_manifest["dependencies"]["pdfjs-dist"] == _PDFJS_VERSION # type: ignore[index] + + +def test_lock_records_match_exact_registry_artifacts_and_preserve_peer_metadata() -> None: + """Require the pinned generator's exact graph without unrelated esbuild churn.""" + lock_document = _read_json("package-lock.json") + packages = lock_document["packages"] + assert isinstance(packages, dict) + + desktop = packages["apps/desktop"] + assert isinstance(desktop, dict) + assert desktop["dependencies"]["pdfjs-dist"] == _PDFJS_VERSION # type: ignore[index] + + pdfjs = packages["node_modules/pdfjs-dist"] + assert pdfjs == { + "version": _PDFJS_VERSION, + "resolved": ( + "https://registry.npmjs.org/pdfjs-dist/-/" + f"pdfjs-dist-{_PDFJS_VERSION}.tgz" + ), + "integrity": _PDFJS_INTEGRITY, + "license": "Apache-2.0", + "engines": {"node": ">=22.13.0 || >=24"}, + } + + undici = packages["node_modules/undici"] + assert isinstance(undici, dict) + assert undici["version"] == _UNDICI_VERSION + assert undici["resolved"] == ( + "https://registry.npmjs.org/undici/-/undici-7.29.0.tgz" + ) + assert undici["integrity"] == _UNDICI_INTEGRITY + + esbuild_locations = { + path: metadata + for path, metadata in packages.items() + if isinstance(path, str) and path.startswith("node_modules/@esbuild/") + } + assert esbuild_locations + assert all( + isinstance(metadata, dict) and metadata.get("peer") is True + for metadata in esbuild_locations.values() + ) From 2cbf767f6fb42f7c8034c116c9b038350532b2b9 Mon Sep 17 00:00:00 2001 From: Seongho Bae Date: Fri, 7 Aug 2026 17:08:52 +0900 Subject: [PATCH 12/92] test(security): disable PDF expression evaluation --- apps/desktop/src/features/score/pdfjs.test.ts | 42 +++++++++++++++++++ 1 file changed, 42 insertions(+) create mode 100644 apps/desktop/src/features/score/pdfjs.test.ts diff --git a/apps/desktop/src/features/score/pdfjs.test.ts b/apps/desktop/src/features/score/pdfjs.test.ts new file mode 100644 index 000000000..49392ed66 --- /dev/null +++ b/apps/desktop/src/features/score/pdfjs.test.ts @@ -0,0 +1,42 @@ +import { beforeEach, describe, expect, it, vi } from "vitest"; +import { getDocument, GlobalWorkerOptions } from "pdfjs-dist"; +import { configureScorePdfWorker, loadScorePdf } from "./pdfjs"; + +vi.mock("pdfjs-dist", () => ({ + getDocument: vi.fn(() => ({ promise: Promise.resolve(), destroy: vi.fn() })), + GlobalWorkerOptions: { workerSrc: "" } +})); + +vi.mock("pdfjs-dist/build/pdf.worker.min.mjs?url", () => ({ + default: "/assets/pdf.worker.min.mjs" +})); + +describe("score PDF.js boundary", () => { + beforeEach(() => { + vi.mocked(getDocument).mockClear(); + GlobalWorkerOptions.workerSrc = ""; + }); + + it("uses the locally bundled worker asset", () => { + configureScorePdfWorker(); + + expect(GlobalWorkerOptions.workerSrc).toBe("/assets/pdf.worker.min.mjs"); + + configureScorePdfWorker(); + expect(GlobalWorkerOptions.workerSrc).toBe("/assets/pdf.worker.min.mjs"); + }); + + it("copies validated bytes and disables PDF expression evaluation", () => { + const source = new Uint8Array([0x25, 0x50, 0x44, 0x46]); + + loadScorePdf(source); + + expect(getDocument).toHaveBeenCalledTimes(1); + const parameters = vi.mocked(getDocument).mock.calls[0]?.[0]; + expect(parameters).toMatchObject({ isEvalSupported: false }); + expect(parameters).toHaveProperty("data"); + const copiedBytes = (parameters as { data: Uint8Array }).data; + expect(copiedBytes).toEqual(source); + expect(copiedBytes).not.toBe(source); + }); +}); From 475de96fc523bfab739817bb665493b11d0dd8bc Mon Sep 17 00:00:00 2001 From: Seongho Bae Date: Fri, 7 Aug 2026 17:10:02 +0900 Subject: [PATCH 13/92] fix(security): pin the patched Undici transitive version --- package.json | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/package.json b/package.json index 779899ede..1ad0f15ec 100644 --- a/package.json +++ b/package.json @@ -45,6 +45,7 @@ }, "overrides": { "brace-expansion": "5.0.9", - "postcss": "8.5.25" + "postcss": "8.5.25", + "undici": "7.29.0" } } From deb74acd7da82fe0696d5d876072455c7bebbec2 Mon Sep 17 00:00:00 2001 From: Seongho Bae Date: Fri, 7 Aug 2026 17:10:43 +0900 Subject: [PATCH 14/92] fix(security): pin the patched PDF.js release --- apps/desktop/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/desktop/package.json b/apps/desktop/package.json index e7685d6f0..e09719b22 100644 --- a/apps/desktop/package.json +++ b/apps/desktop/package.json @@ -20,7 +20,7 @@ "class-variance-authority": "^0.7.1", "clsx": "^2.1.1", "lucide-react": "^1.24.0", - "pdfjs-dist": "6.1.200", + "pdfjs-dist": "6.2.108", "react": "^19.2.4", "react-dom": "^19.2.7", "sonner": "^2.0.7", From dc90d5b0d8bb516df28467d09332256d141de836 Mon Sep 17 00:00:00 2001 From: Seongho Bae Date: Fri, 7 Aug 2026 17:11:01 +0900 Subject: [PATCH 15/92] fix(security): disable PDF expression evaluation --- apps/desktop/src/features/score/pdfjs.ts | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/apps/desktop/src/features/score/pdfjs.ts b/apps/desktop/src/features/score/pdfjs.ts index b62526c89..007cd5727 100644 --- a/apps/desktop/src/features/score/pdfjs.ts +++ b/apps/desktop/src/features/score/pdfjs.ts @@ -22,8 +22,13 @@ export function configureScorePdfWorker(): void { * this helper never fetches arbitrary URLs. The bytes are copied before they * are handed to pdf.js because pdf.js transfers the underlying buffer to its * worker, which would otherwise detach the caller's copy and break retries. + * PDF expression evaluation remains disabled as defense in depth even when + * the installed pdf.js release includes the corresponding security patch. */ export function loadScorePdf(data: Uint8Array): PDFDocumentLoadingTask { configureScorePdfWorker(); - return getDocument({ data: new Uint8Array(data) }); + return getDocument({ + data: new Uint8Array(data), + isEvalSupported: false + }); } From b23b957c2bcca70abcc5bd36d5ae05e343fa0054 Mon Sep 17 00:00:00 2001 From: Seongho Bae Date: Fri, 7 Aug 2026 17:12:13 +0900 Subject: [PATCH 16/92] docs(security): record coordinated PDF and HTTP remediation --- .../high-security-pdf-http-baseline.md | 78 +++++++++++++++++++ 1 file changed, 78 insertions(+) create mode 100644 docs/doctoring/high-security-pdf-http-baseline.md diff --git a/docs/doctoring/high-security-pdf-http-baseline.md b/docs/doctoring/high-security-pdf-http-baseline.md new file mode 100644 index 000000000..d7b4d4014 --- /dev/null +++ b/docs/doctoring/high-security-pdf-http-baseline.md @@ -0,0 +1,78 @@ +# High-security PDF and HTTP dependency baseline + +## Decision + +BandScope treats the PDF parser and its transitive HTTP client as one security-release boundary: + +- `pdfjs-dist` is pinned exactly to `6.2.108`; +- `undici` is pinned exactly to `7.29.0` through the root npm override; and +- the complete npm workspace lock is generated only by the repository-pinned npm `10.9.8` workflow and imported unchanged from the workflow artifact. + +The desktop PDF loader additionally passes `isEvalSupported: false` to `getDocument`. The dependency patch is the primary remediation; disabling expression evaluation is defense in depth and prevents a future regression or alternate vulnerable execution path from re-enabling dynamic PDF expression compilation. + +```mermaid +flowchart LR + A[Validated local PDF bytes] --> B[Copied Uint8Array] + B --> C[pdfjs-dist 6.2.108] + P[isEvalSupported false] --> C + C --> W[Same-origin bundled worker] + W --> R[Canvas render] + J[jsdom development path] --> U[undici 7.29.0 override] + N[npm 10.9.8] --> L[Exact package-lock artifact] + L --> C + L --> U +``` + +## Threat boundary + +The score viewer accepts only bytes already copied into the app-owned workspace through the native PDF intake boundary. It does not accept a URL and never uses a remote worker. This prevents a PDF from selecting an attacker-controlled fetch origin or script asset. + +PDF bytes remain untrusted after the native magic-byte, size, and path checks. Parser vulnerabilities, malformed object graphs, embedded actions, and expression compilation can still occur inside a syntactically valid PDF. The patched parser and explicit `isEvalSupported: false` therefore remain mandatory even for locally selected files. + +Undici is currently a development dependency reached through jsdom, but development and CI parsers process attacker-controlled fixtures, generated HTML, and network-like request bodies. A dev-only label does not make header injection, shared-cache disclosure, retry desynchronization, or cookie-attribute injection acceptable in the trusted build boundary. + +## Lockfile provenance + +The security manifests are changed before the lock. The exact branch workflow then: + +1. verifies Node `22.22.3` and npm `10.9.8`; +2. runs `npm install --package-lock-only --ignore-scripts --no-audit --no-fund`; +3. uploads the generated `package-lock.json` under a head-SHA-bound artifact name; and +4. fails while the generated lock differs from the branch. + +The maintainer imports that generated artifact byte-for-byte and reruns the workflow. The second run must produce a clean diff. No tarball URL, SRI, dependency range, `peer` classification, or workspace record is edited by hand. + +The lock contract requires the exact public-registry tarball and SHA-512 SRI for both patched packages and requires every existing `node_modules/@esbuild/*` location to retain npm 10.9.8's `peer: true` classification. This distinguishes the intended security graph from unrelated Dependabot generator churn. + +## Verification + +The merge gate includes: + +- exact manifest and lock artifact tests; +- a direct PDF.js wrapper test for copied bytes, the locally bundled worker, and `isEvalSupported: false`; +- valid and malformed local score-PDF component tests; +- desktop lint, strict typecheck, complete measured tests, and production build; +- Tauri/Rust checks and native PDF intake regressions; +- `npm audit --workspaces --audit-level=high` with no high finding; +- repository SAST, CodeQL, security scan, secret scan, SBOM, and dependency evidence; +- current-head central coverage and automated review; +- zero unresolved actionable threads and a qualifying independent non-author approval; and +- normal branch protection without administrative bypass. + +## Failure, rollback, and incident evidence + +On a failed lock replay or parser regression, preserve the exact head SHA, Node/npm versions, generated-lock artifact ID and digest, original and generated lock blob SHA, test output, audit report, and workflow run ID. Do not merge a partially updated graph. + +Rollback restores the previous desktop manifest, root override, complete lock, PDF loader, tests, and CHANGELOG entry together. Because the previous graph contains known high findings, rollback is an emergency availability action only and requires an explicit security exception, compensating controls, owner, expiration, and immediate replacement plan. + +## References + +GitHub. (2026). *PDF.js vulnerable to arbitrary JavaScript execution upon opening a malicious PDF* (GHSA-hq66-cqwq-w95j) [Security advisory]. https://github.com/advisories/GHSA-hq66-cqwq-w95j + +Mozilla. (2026). *PDF.js 6.2.108* [Software release]. https://github.com/mozilla/pdf.js/releases/tag/v6.2.108 + +Node.js contributors. (2026). *Undici 7.29.0* [Software release]. https://github.com/nodejs/undici/releases/tag/v7.29.0 + +npm, Inc. (2026). *npm ci*. npm Docs. https://docs.npmjs.com/cli/v11/commands/npm-ci/ + +npm, Inc. (2026). *package-lock.json*. npm Docs. https://docs.npmjs.com/cli/v11/configuring-npm/package-lock-json/ From 2e99f72d2859250a460bcadd6248b0ea93a0a8d0 Mon Sep 17 00:00:00 2001 From: Seongho Bae Date: Fri, 7 Aug 2026 17:12:46 +0900 Subject: [PATCH 17/92] docs(changelog): record coordinated security remediation --- CHANGELOG.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 05f555100..1d9910145 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -11,6 +11,10 @@ - Pinned npm `10.9.8` as the lockfile generator and made primary CI reject a different npm version or any package-lock-only replay diff. +### Fixed + +- Upgraded the local score PDF parser to `pdfjs-dist` 6.2.108, pinned Undici 7.29.0 across the workspace, and disabled PDF expression evaluation while preserving same-origin worker execution and npm-generated lock provenance. + ## [0.1.3] - 2026-04-29 ### Fixed From 8f50fe4ce8bf2440de6fbf55d48bc918bd311ffc Mon Sep 17 00:00:00 2001 From: Seongho Bae Date: Fri, 7 Aug 2026 17:20:04 +0900 Subject: [PATCH 18/92] fix(security): anchor the Undici override to an exact root floor --- package.json | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/package.json b/package.json index 1ad0f15ec..2c3a4e945 100644 --- a/package.json +++ b/package.json @@ -41,11 +41,12 @@ "@eslint/js": "^10.0.1", "eslint-plugin-jsdoc": "^63.0.13", "react": "^19.2.4", - "react-dom": "^19.2.7" + "react-dom": "^19.2.7", + "undici": "7.29.0" }, "overrides": { "brace-expansion": "5.0.9", "postcss": "8.5.25", - "undici": "7.29.0" + "undici": "$undici" } } From e2c0c2dfee35c19d1e9156ad0a7d9324fdefd1fb Mon Sep 17 00:00:00 2001 From: Seongho Bae Date: Fri, 7 Aug 2026 17:20:46 +0900 Subject: [PATCH 19/92] test(security): bind exact root floor and npm package locations --- .../test_high_security_dependency_baseline.py | 28 +++++++++++-------- 1 file changed, 16 insertions(+), 12 deletions(-) diff --git a/services/analysis-engine/tests/test_high_security_dependency_baseline.py b/services/analysis-engine/tests/test_high_security_dependency_baseline.py index 01dba0ab8..0a9e81ab1 100644 --- a/services/analysis-engine/tests/test_high_security_dependency_baseline.py +++ b/services/analysis-engine/tests/test_high_security_dependency_baseline.py @@ -33,7 +33,8 @@ def test_manifests_pin_the_security_floors_without_semver_drift() -> None: root_manifest = _read_json("package.json") desktop_manifest = _read_json("apps/desktop/package.json") - assert root_manifest["overrides"]["undici"] == _UNDICI_VERSION # type: ignore[index] + assert root_manifest["devDependencies"]["undici"] == _UNDICI_VERSION # type: ignore[index] + assert root_manifest["overrides"]["undici"] == "$undici" # type: ignore[index] assert desktop_manifest["dependencies"]["pdfjs-dist"] == _PDFJS_VERSION # type: ignore[index] @@ -43,21 +44,24 @@ def test_lock_records_match_exact_registry_artifacts_and_preserve_peer_metadata( packages = lock_document["packages"] assert isinstance(packages, dict) + root_package = packages[""] + assert isinstance(root_package, dict) + assert root_package["devDependencies"]["undici"] == _UNDICI_VERSION # type: ignore[index] + desktop = packages["apps/desktop"] assert isinstance(desktop, dict) assert desktop["dependencies"]["pdfjs-dist"] == _PDFJS_VERSION # type: ignore[index] - pdfjs = packages["node_modules/pdfjs-dist"] - assert pdfjs == { - "version": _PDFJS_VERSION, - "resolved": ( - "https://registry.npmjs.org/pdfjs-dist/-/" - f"pdfjs-dist-{_PDFJS_VERSION}.tgz" - ), - "integrity": _PDFJS_INTEGRITY, - "license": "Apache-2.0", - "engines": {"node": ">=22.13.0 || >=24"}, - } + pdfjs = packages["apps/desktop/node_modules/pdfjs-dist"] + assert isinstance(pdfjs, dict) + assert pdfjs["version"] == _PDFJS_VERSION + assert pdfjs["resolved"] == ( + "https://registry.npmjs.org/pdfjs-dist/-/" + f"pdfjs-dist-{_PDFJS_VERSION}.tgz" + ) + assert pdfjs["integrity"] == _PDFJS_INTEGRITY + assert pdfjs["license"] == "Apache-2.0" + assert pdfjs["engines"] == {"node": ">=22.13.0 || >=24"} undici = packages["node_modules/undici"] assert isinstance(undici, dict) From dd93f962d367e3a5b56ee171708bf4877a054541 Mon Sep 17 00:00:00 2001 From: Seongho Bae Date: Fri, 7 Aug 2026 18:59:55 +0900 Subject: [PATCH 20/92] ci(pr783): import exact npm 10.9.8 lock artifact --- .../workflows/import-pr783-generated-lock.yml | 125 ++++++++++++++++++ 1 file changed, 125 insertions(+) create mode 100644 .github/workflows/import-pr783-generated-lock.yml diff --git a/.github/workflows/import-pr783-generated-lock.yml b/.github/workflows/import-pr783-generated-lock.yml new file mode 100644 index 000000000..c2ce31af9 --- /dev/null +++ b/.github/workflows/import-pr783-generated-lock.yml @@ -0,0 +1,125 @@ +name: Import PR 783 generated npm lock + +on: + push: + branches: + - fix/high-security-dependency-baseline + paths: + - .github/workflows/import-pr783-generated-lock.yml + +permissions: + contents: read + actions: read + +concurrency: + group: import-pr783-generated-lock + cancel-in-progress: false + +env: + GIT_CONFIG_COUNT: "1" + GIT_CONFIG_KEY_0: init.defaultBranch + GIT_CONFIG_VALUE_0: develop + EXPECTED_SOURCE_HEAD: e2c0c2dfee35c19d1e9156ad0a7d9324fdefd1fb + EXPECTED_NPM_VERSION: "10.9.8" + ARTIFACT_ID: "8989562185" + ARTIFACT_RUN_ID: "31161313485" + ARTIFACT_NAME: npm-lock-reproduction-e2c0c2dfee35c19d1e9156ad0a7d9324fdefd1fb + EXPECTED_LOCK_SHA256: 31dd2661eca864e3da46f86629a2535dc181d01449bd3a50fa3cdbd6c58e7971 + +jobs: + import-and-verify: + if: >- + github.repository == 'ContextualWisdomLab/bandscope' && + github.ref == 'refs/heads/fix/high-security-dependency-baseline' + permissions: + contents: write + actions: read + runs-on: ubuntu-24.04 + timeout-minutes: 45 + steps: + - name: Harden runner + uses: step-security/harden-runner@bf7454d06d71f1098171f2acdf0cd4708d7b5920 # v2.20.0 + with: + egress-policy: audit + + - name: Checkout exact trigger without persisted credentials + uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0 + with: + ref: ${{ github.sha }} + fetch-depth: 2 + persist-credentials: false + + - name: Verify bounded trigger lineage + shell: bash --noprofile --norc -e -o pipefail {0} + run: | + test "$(git rev-parse HEAD)" = "$GITHUB_SHA" + test "$(git rev-parse HEAD^)" = "$EXPECTED_SOURCE_HEAD" + mapfile -t trigger_delta < <(git diff --name-only "$EXPECTED_SOURCE_HEAD" HEAD) + test "${#trigger_delta[@]}" -eq 1 + test "${trigger_delta[0]}" = ".github/workflows/import-pr783-generated-lock.yml" + + - name: Set up exact Node and npm generator + uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6.4.0 + with: + node-version: "22.22.3" + cache: npm + + - name: Download exact head-bound lock artifact + env: + GH_TOKEN: ${{ github.token }} + shell: bash --noprofile --norc -e -o pipefail {0} + run: | + test "$(npm --version)" = "$EXPECTED_NPM_VERSION" + mkdir -p "${RUNNER_TEMP}/pr783-lock" + curl --fail --silent --show-error --location \ + --retry 0 \ + --header "Accept: application/vnd.github+json" \ + --header "Authorization: Bearer ${GH_TOKEN}" \ + --header "X-GitHub-Api-Version: 2022-11-28" \ + "https://api.github.com/repos/${GITHUB_REPOSITORY}/actions/artifacts/${ARTIFACT_ID}/zip" \ + --output "${RUNNER_TEMP}/pr783-lock/artifact.zip" + mapfile -t archive_entries < <(zipinfo -1 "${RUNNER_TEMP}/pr783-lock/artifact.zip") + test "${#archive_entries[@]}" -eq 1 + test "${archive_entries[0]}" = "package-lock.json" + unzip -p "${RUNNER_TEMP}/pr783-lock/artifact.zip" package-lock.json \ + > "${RUNNER_TEMP}/pr783-lock/package-lock.json" + test "$(sha256sum "${RUNNER_TEMP}/pr783-lock/package-lock.json" | cut -d' ' -f1)" = "$EXPECTED_LOCK_SHA256" + mv "${RUNNER_TEMP}/pr783-lock/package-lock.json" package-lock.json + + - name: Verify exact generated lock and security baseline + shell: bash --noprofile --norc -e -o pipefail {0} + run: | + test "$(sha256sum package-lock.json | cut -d' ' -f1)" = "$EXPECTED_LOCK_SHA256" + npm install --package-lock-only --ignore-scripts --no-audit --no-fund + test "$(sha256sum package-lock.json | cut -d' ' -f1)" = "$EXPECTED_LOCK_SHA256" + npm ci --ignore-scripts --no-audit --no-fund + npm audit --workspaces --audit-level=high + npm run typecheck --workspace @bandscope/desktop + npm run lint --workspace @bandscope/desktop + npm exec --workspace @bandscope/desktop vitest run \ + src/features/score/pdfjs.test.ts \ + --coverage=false + git diff --check + + - name: Remove one-shot importer and publish verified lock + env: + EXPECTED_HEAD: ${{ github.sha }} + SOURCE_BRANCH: fix/high-security-dependency-baseline + PUSH_TOKEN: ${{ github.token }} + shell: bash --noprofile --norc -e -o pipefail {0} + run: | + rm .github/workflows/import-pr783-generated-lock.yml + test "$(git diff --name-only "$EXPECTED_SOURCE_HEAD" -- | sort)" = "package-lock.json" + test "$(sha256sum package-lock.json | cut -d' ' -f1)" = "$EXPECTED_LOCK_SHA256" + remote_head="$(git ls-remote origin "refs/heads/${SOURCE_BRANCH}" | cut -f1)" + test "$remote_head" = "$EXPECTED_HEAD" + git config user.name "github-actions[bot]" + git config user.email "41898282+github-actions[bot]@users.noreply.github.com" + git add package-lock.json .github/workflows/import-pr783-generated-lock.yml + git diff --cached --check + git commit -m "fix(security): import verified npm 10.9.8 lock" + auth_header="$(printf 'x-access-token:%s' "$PUSH_TOKEN" | base64 | tr -d '\n')" + echo "::add-mask::$auth_header" + git -c http.extraheader="AUTHORIZATION: basic ${auth_header}" \ + push --force-with-lease="refs/heads/${SOURCE_BRANCH}:${EXPECTED_HEAD}" \ + origin "HEAD:refs/heads/${SOURCE_BRANCH}" From dd8d1acda0a32ba02809b6a27cd9933815de03d6 Mon Sep 17 00:00:00 2001 From: Seongho Bae Date: Fri, 7 Aug 2026 19:07:00 +0900 Subject: [PATCH 21/92] fix(score): align PDF.js boundary with 6.2.108 API --- apps/desktop/src/features/score/pdfjs.ts | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/apps/desktop/src/features/score/pdfjs.ts b/apps/desktop/src/features/score/pdfjs.ts index 007cd5727..e0ce7692d 100644 --- a/apps/desktop/src/features/score/pdfjs.ts +++ b/apps/desktop/src/features/score/pdfjs.ts @@ -22,13 +22,13 @@ export function configureScorePdfWorker(): void { * this helper never fetches arbitrary URLs. The bytes are copied before they * are handed to pdf.js because pdf.js transfers the underlying buffer to its * worker, which would otherwise detach the caller's copy and break retries. - * PDF expression evaluation remains disabled as defense in depth even when - * the installed pdf.js release includes the corresponding security patch. + * + * PDF.js 6.2.108 no longer exposes the legacy `isEvalSupported` initialization + * option. Security therefore relies on the patched parser release plus this + * narrow data-only, same-origin-worker boundary rather than an ignored and + * falsely reassuring unknown option. */ export function loadScorePdf(data: Uint8Array): PDFDocumentLoadingTask { configureScorePdfWorker(); - return getDocument({ - data: new Uint8Array(data), - isEvalSupported: false - }); + return getDocument({ data: new Uint8Array(data) }); } From 988dc1d30878994042cd72b9f7d5b6c38c059f3c Mon Sep 17 00:00:00 2001 From: Seongho Bae Date: Fri, 7 Aug 2026 19:08:02 +0900 Subject: [PATCH 22/92] test(score): prove the supported data-only PDF.js boundary --- apps/desktop/src/features/score/pdfjs.test.ts | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/apps/desktop/src/features/score/pdfjs.test.ts b/apps/desktop/src/features/score/pdfjs.test.ts index 49392ed66..b225830e5 100644 --- a/apps/desktop/src/features/score/pdfjs.test.ts +++ b/apps/desktop/src/features/score/pdfjs.test.ts @@ -26,15 +26,15 @@ describe("score PDF.js boundary", () => { expect(GlobalWorkerOptions.workerSrc).toBe("/assets/pdf.worker.min.mjs"); }); - it("copies validated bytes and disables PDF expression evaluation", () => { + it("copies validated bytes through the supported data-only API", () => { const source = new Uint8Array([0x25, 0x50, 0x44, 0x46]); loadScorePdf(source); expect(getDocument).toHaveBeenCalledTimes(1); const parameters = vi.mocked(getDocument).mock.calls[0]?.[0]; - expect(parameters).toMatchObject({ isEvalSupported: false }); - expect(parameters).toHaveProperty("data"); + expect(parameters).toBeTypeOf("object"); + expect(Object.keys(parameters as object)).toEqual(["data"]); const copiedBytes = (parameters as { data: Uint8Array }).data; expect(copiedBytes).toEqual(source); expect(copiedBytes).not.toBe(source); From a39e37f3eca2a185feddc142d5ea648c943ce9a5 Mon Sep 17 00:00:00 2001 From: Seongho Bae Date: Fri, 7 Aug 2026 19:09:48 +0900 Subject: [PATCH 23/92] docs(security): record the supported PDF.js 6.2.108 boundary --- docs/doctoring/high-security-pdf-http-baseline.md | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/docs/doctoring/high-security-pdf-http-baseline.md b/docs/doctoring/high-security-pdf-http-baseline.md index d7b4d4014..d83a63eb7 100644 --- a/docs/doctoring/high-security-pdf-http-baseline.md +++ b/docs/doctoring/high-security-pdf-http-baseline.md @@ -8,13 +8,13 @@ BandScope treats the PDF parser and its transitive HTTP client as one security-r - `undici` is pinned exactly to `7.29.0` through the root npm override; and - the complete npm workspace lock is generated only by the repository-pinned npm `10.9.8` workflow and imported unchanged from the workflow artifact. -The desktop PDF loader additionally passes `isEvalSupported: false` to `getDocument`. The dependency patch is the primary remediation; disabling expression evaluation is defense in depth and prevents a future regression or alternate vulnerable execution path from re-enabling dynamic PDF expression compilation. +PDF.js `6.2.108` no longer exposes the legacy `isEvalSupported` member in its public `DocumentInitParameters` contract, and `getDocument` no longer reads that member. BandScope therefore does not cast or pass an unknown option that would be ignored while creating false assurance. The primary remediation is the patched parser release, reinforced by a narrow data-only call, copied caller-owned bytes, and a same-origin bundled worker. ```mermaid flowchart LR A[Validated local PDF bytes] --> B[Copied Uint8Array] - B --> C[pdfjs-dist 6.2.108] - P[isEvalSupported false] --> C + B --> D[Data-only DocumentInitParameters] + D --> C[pdfjs-dist 6.2.108] C --> W[Same-origin bundled worker] W --> R[Canvas render] J[jsdom development path] --> U[undici 7.29.0 override] @@ -25,9 +25,9 @@ flowchart LR ## Threat boundary -The score viewer accepts only bytes already copied into the app-owned workspace through the native PDF intake boundary. It does not accept a URL and never uses a remote worker. This prevents a PDF from selecting an attacker-controlled fetch origin or script asset. +The score viewer accepts only bytes already copied into the app-owned workspace through the native PDF intake boundary. It does not accept a URL, credentials, custom request headers, or a remote worker. This prevents a PDF from selecting an attacker-controlled fetch origin or script asset. -PDF bytes remain untrusted after the native magic-byte, size, and path checks. Parser vulnerabilities, malformed object graphs, embedded actions, and expression compilation can still occur inside a syntactically valid PDF. The patched parser and explicit `isEvalSupported: false` therefore remain mandatory even for locally selected files. +PDF bytes remain untrusted after the native magic-byte, size, and path checks. Parser vulnerabilities, malformed object graphs, embedded actions, and resource-exhaustion paths can still occur inside a syntactically valid PDF. The patched parser, exact dependency lock, copied data-only input, same-origin worker, and existing native intake limits therefore remain mandatory for locally selected files. Undici is currently a development dependency reached through jsdom, but development and CI parsers process attacker-controlled fixtures, generated HTML, and network-like request bodies. A dev-only label does not make header injection, shared-cache disclosure, retry desynchronization, or cookie-attribute injection acceptable in the trusted build boundary. @@ -49,7 +49,8 @@ The lock contract requires the exact public-registry tarball and SHA-512 SRI for The merge gate includes: - exact manifest and lock artifact tests; -- a direct PDF.js wrapper test for copied bytes, the locally bundled worker, and `isEvalSupported: false`; +- a direct PDF.js wrapper test proving copied bytes, the locally bundled worker, and an exact data-only initialization object; +- TypeScript compilation against the installed PDF.js `DocumentInitParameters` rather than an unsafe cast; - valid and malformed local score-PDF component tests; - desktop lint, strict typecheck, complete measured tests, and production build; - Tauri/Rust checks and native PDF intake regressions; @@ -69,6 +70,8 @@ Rollback restores the previous desktop manifest, root override, complete lock, P GitHub. (2026). *PDF.js vulnerable to arbitrary JavaScript execution upon opening a malicious PDF* (GHSA-hq66-cqwq-w95j) [Security advisory]. https://github.com/advisories/GHSA-hq66-cqwq-w95j +Mozilla. (2026). *Document initialization parameters in PDF.js 6.2.108* [Source code]. GitHub. https://github.com/mozilla/pdf.js/blob/v6.2.108/src/display/api.js + Mozilla. (2026). *PDF.js 6.2.108* [Software release]. https://github.com/mozilla/pdf.js/releases/tag/v6.2.108 Node.js contributors. (2026). *Undici 7.29.0* [Software release]. https://github.com/nodejs/undici/releases/tag/v7.29.0 From 6b753e6b0bacbe250885c20a53728966b81e0009 Mon Sep 17 00:00:00 2001 From: Seongho Bae Date: Fri, 7 Aug 2026 19:11:29 +0900 Subject: [PATCH 24/92] docs(changelog): describe the supported patched PDF boundary --- CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 1d9910145..c746043fc 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -13,7 +13,7 @@ ### Fixed -- Upgraded the local score PDF parser to `pdfjs-dist` 6.2.108, pinned Undici 7.29.0 across the workspace, and disabled PDF expression evaluation while preserving same-origin worker execution and npm-generated lock provenance. +- Upgraded the local score PDF parser to `pdfjs-dist` 6.2.108, pinned Undici 7.29.0 across the workspace, and constrained PDF loading to copied in-memory bytes with a same-origin bundled worker and npm-generated lock provenance. ## [0.1.3] - 2026-04-29 From b773653f76fae5cfbda4a24548bffd4fedfe06ef Mon Sep 17 00:00:00 2001 From: Seongho Bae Date: Fri, 7 Aug 2026 19:14:08 +0900 Subject: [PATCH 25/92] ci(pr783): rerun lock import after supported API repair --- .github/workflows/import-pr783-generated-lock.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/import-pr783-generated-lock.yml b/.github/workflows/import-pr783-generated-lock.yml index c2ce31af9..c9616f453 100644 --- a/.github/workflows/import-pr783-generated-lock.yml +++ b/.github/workflows/import-pr783-generated-lock.yml @@ -19,7 +19,7 @@ env: GIT_CONFIG_COUNT: "1" GIT_CONFIG_KEY_0: init.defaultBranch GIT_CONFIG_VALUE_0: develop - EXPECTED_SOURCE_HEAD: e2c0c2dfee35c19d1e9156ad0a7d9324fdefd1fb + EXPECTED_SOURCE_HEAD: 6b753e6b0bacbe250885c20a53728966b81e0009 EXPECTED_NPM_VERSION: "10.9.8" ARTIFACT_ID: "8989562185" ARTIFACT_RUN_ID: "31161313485" From 01cb39e9c9f7513fc3410f86b2f1e1332a969da4 Mon Sep 17 00:00:00 2001 From: Seongho Bae Date: Fri, 7 Aug 2026 19:19:01 +0900 Subject: [PATCH 26/92] ci(pr783): publish the verified lock from the bounded importer --- .github/workflows/import-pr783-generated-lock.yml | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/.github/workflows/import-pr783-generated-lock.yml b/.github/workflows/import-pr783-generated-lock.yml index c9616f453..f29616e91 100644 --- a/.github/workflows/import-pr783-generated-lock.yml +++ b/.github/workflows/import-pr783-generated-lock.yml @@ -20,6 +20,7 @@ env: GIT_CONFIG_KEY_0: init.defaultBranch GIT_CONFIG_VALUE_0: develop EXPECTED_SOURCE_HEAD: 6b753e6b0bacbe250885c20a53728966b81e0009 + EXPECTED_TRIGGER_PARENT: b773653f76fae5cfbda4a24548bffd4fedfe06ef EXPECTED_NPM_VERSION: "10.9.8" ARTIFACT_ID: "8989562185" ARTIFACT_RUN_ID: "31161313485" @@ -53,8 +54,8 @@ jobs: shell: bash --noprofile --norc -e -o pipefail {0} run: | test "$(git rev-parse HEAD)" = "$GITHUB_SHA" - test "$(git rev-parse HEAD^)" = "$EXPECTED_SOURCE_HEAD" - mapfile -t trigger_delta < <(git diff --name-only "$EXPECTED_SOURCE_HEAD" HEAD) + test "$(git rev-parse HEAD^)" = "$EXPECTED_TRIGGER_PARENT" + mapfile -t trigger_delta < <(git diff --name-only "$EXPECTED_TRIGGER_PARENT" HEAD) test "${#trigger_delta[@]}" -eq 1 test "${trigger_delta[0]}" = ".github/workflows/import-pr783-generated-lock.yml" @@ -109,7 +110,9 @@ jobs: shell: bash --noprofile --norc -e -o pipefail {0} run: | rm .github/workflows/import-pr783-generated-lock.yml - test "$(git diff --name-only "$EXPECTED_SOURCE_HEAD" -- | sort)" = "package-lock.json" + actual_delta="$(git diff --name-only "$EXPECTED_SOURCE_HEAD" -- | sort)" + expected_delta="$(printf '%s\n' .github/workflows/import-pr783-generated-lock.yml package-lock.json | sort)" + test "$actual_delta" = "$expected_delta" test "$(sha256sum package-lock.json | cut -d' ' -f1)" = "$EXPECTED_LOCK_SHA256" remote_head="$(git ls-remote origin "refs/heads/${SOURCE_BRANCH}" | cut -f1)" test "$remote_head" = "$EXPECTED_HEAD" From ad558ace02522f15c27705fff97c87c6661f0695 Mon Sep 17 00:00:00 2001 From: Seongho Bae Date: Fri, 7 Aug 2026 19:24:21 +0900 Subject: [PATCH 27/92] ci(pr783): fetch complete lineage for verified lock publication --- .github/workflows/import-pr783-generated-lock.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/import-pr783-generated-lock.yml b/.github/workflows/import-pr783-generated-lock.yml index f29616e91..762bb7cd9 100644 --- a/.github/workflows/import-pr783-generated-lock.yml +++ b/.github/workflows/import-pr783-generated-lock.yml @@ -20,7 +20,7 @@ env: GIT_CONFIG_KEY_0: init.defaultBranch GIT_CONFIG_VALUE_0: develop EXPECTED_SOURCE_HEAD: 6b753e6b0bacbe250885c20a53728966b81e0009 - EXPECTED_TRIGGER_PARENT: b773653f76fae5cfbda4a24548bffd4fedfe06ef + EXPECTED_TRIGGER_PARENT: 01cb39e9c9f7513fc3410f86b2f1e1332a969da4 EXPECTED_NPM_VERSION: "10.9.8" ARTIFACT_ID: "8989562185" ARTIFACT_RUN_ID: "31161313485" @@ -47,7 +47,7 @@ jobs: uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0 with: ref: ${{ github.sha }} - fetch-depth: 2 + fetch-depth: 0 persist-credentials: false - name: Verify bounded trigger lineage From 83865dce76bf158ae444a23a85f7036ccfc9663b Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Fri, 7 Aug 2026 10:25:15 +0000 Subject: [PATCH 28/92] fix(security): import verified npm 10.9.8 lock --- .../workflows/import-pr783-generated-lock.yml | 128 ------------------ package-lock.json | 35 ++--- 2 files changed, 18 insertions(+), 145 deletions(-) delete mode 100644 .github/workflows/import-pr783-generated-lock.yml diff --git a/.github/workflows/import-pr783-generated-lock.yml b/.github/workflows/import-pr783-generated-lock.yml deleted file mode 100644 index 762bb7cd9..000000000 --- a/.github/workflows/import-pr783-generated-lock.yml +++ /dev/null @@ -1,128 +0,0 @@ -name: Import PR 783 generated npm lock - -on: - push: - branches: - - fix/high-security-dependency-baseline - paths: - - .github/workflows/import-pr783-generated-lock.yml - -permissions: - contents: read - actions: read - -concurrency: - group: import-pr783-generated-lock - cancel-in-progress: false - -env: - GIT_CONFIG_COUNT: "1" - GIT_CONFIG_KEY_0: init.defaultBranch - GIT_CONFIG_VALUE_0: develop - EXPECTED_SOURCE_HEAD: 6b753e6b0bacbe250885c20a53728966b81e0009 - EXPECTED_TRIGGER_PARENT: 01cb39e9c9f7513fc3410f86b2f1e1332a969da4 - EXPECTED_NPM_VERSION: "10.9.8" - ARTIFACT_ID: "8989562185" - ARTIFACT_RUN_ID: "31161313485" - ARTIFACT_NAME: npm-lock-reproduction-e2c0c2dfee35c19d1e9156ad0a7d9324fdefd1fb - EXPECTED_LOCK_SHA256: 31dd2661eca864e3da46f86629a2535dc181d01449bd3a50fa3cdbd6c58e7971 - -jobs: - import-and-verify: - if: >- - github.repository == 'ContextualWisdomLab/bandscope' && - github.ref == 'refs/heads/fix/high-security-dependency-baseline' - permissions: - contents: write - actions: read - runs-on: ubuntu-24.04 - timeout-minutes: 45 - steps: - - name: Harden runner - uses: step-security/harden-runner@bf7454d06d71f1098171f2acdf0cd4708d7b5920 # v2.20.0 - with: - egress-policy: audit - - - name: Checkout exact trigger without persisted credentials - uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0 - with: - ref: ${{ github.sha }} - fetch-depth: 0 - persist-credentials: false - - - name: Verify bounded trigger lineage - shell: bash --noprofile --norc -e -o pipefail {0} - run: | - test "$(git rev-parse HEAD)" = "$GITHUB_SHA" - test "$(git rev-parse HEAD^)" = "$EXPECTED_TRIGGER_PARENT" - mapfile -t trigger_delta < <(git diff --name-only "$EXPECTED_TRIGGER_PARENT" HEAD) - test "${#trigger_delta[@]}" -eq 1 - test "${trigger_delta[0]}" = ".github/workflows/import-pr783-generated-lock.yml" - - - name: Set up exact Node and npm generator - uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6.4.0 - with: - node-version: "22.22.3" - cache: npm - - - name: Download exact head-bound lock artifact - env: - GH_TOKEN: ${{ github.token }} - shell: bash --noprofile --norc -e -o pipefail {0} - run: | - test "$(npm --version)" = "$EXPECTED_NPM_VERSION" - mkdir -p "${RUNNER_TEMP}/pr783-lock" - curl --fail --silent --show-error --location \ - --retry 0 \ - --header "Accept: application/vnd.github+json" \ - --header "Authorization: Bearer ${GH_TOKEN}" \ - --header "X-GitHub-Api-Version: 2022-11-28" \ - "https://api.github.com/repos/${GITHUB_REPOSITORY}/actions/artifacts/${ARTIFACT_ID}/zip" \ - --output "${RUNNER_TEMP}/pr783-lock/artifact.zip" - mapfile -t archive_entries < <(zipinfo -1 "${RUNNER_TEMP}/pr783-lock/artifact.zip") - test "${#archive_entries[@]}" -eq 1 - test "${archive_entries[0]}" = "package-lock.json" - unzip -p "${RUNNER_TEMP}/pr783-lock/artifact.zip" package-lock.json \ - > "${RUNNER_TEMP}/pr783-lock/package-lock.json" - test "$(sha256sum "${RUNNER_TEMP}/pr783-lock/package-lock.json" | cut -d' ' -f1)" = "$EXPECTED_LOCK_SHA256" - mv "${RUNNER_TEMP}/pr783-lock/package-lock.json" package-lock.json - - - name: Verify exact generated lock and security baseline - shell: bash --noprofile --norc -e -o pipefail {0} - run: | - test "$(sha256sum package-lock.json | cut -d' ' -f1)" = "$EXPECTED_LOCK_SHA256" - npm install --package-lock-only --ignore-scripts --no-audit --no-fund - test "$(sha256sum package-lock.json | cut -d' ' -f1)" = "$EXPECTED_LOCK_SHA256" - npm ci --ignore-scripts --no-audit --no-fund - npm audit --workspaces --audit-level=high - npm run typecheck --workspace @bandscope/desktop - npm run lint --workspace @bandscope/desktop - npm exec --workspace @bandscope/desktop vitest run \ - src/features/score/pdfjs.test.ts \ - --coverage=false - git diff --check - - - name: Remove one-shot importer and publish verified lock - env: - EXPECTED_HEAD: ${{ github.sha }} - SOURCE_BRANCH: fix/high-security-dependency-baseline - PUSH_TOKEN: ${{ github.token }} - shell: bash --noprofile --norc -e -o pipefail {0} - run: | - rm .github/workflows/import-pr783-generated-lock.yml - actual_delta="$(git diff --name-only "$EXPECTED_SOURCE_HEAD" -- | sort)" - expected_delta="$(printf '%s\n' .github/workflows/import-pr783-generated-lock.yml package-lock.json | sort)" - test "$actual_delta" = "$expected_delta" - test "$(sha256sum package-lock.json | cut -d' ' -f1)" = "$EXPECTED_LOCK_SHA256" - remote_head="$(git ls-remote origin "refs/heads/${SOURCE_BRANCH}" | cut -f1)" - test "$remote_head" = "$EXPECTED_HEAD" - git config user.name "github-actions[bot]" - git config user.email "41898282+github-actions[bot]@users.noreply.github.com" - git add package-lock.json .github/workflows/import-pr783-generated-lock.yml - git diff --cached --check - git commit -m "fix(security): import verified npm 10.9.8 lock" - auth_header="$(printf 'x-access-token:%s' "$PUSH_TOKEN" | base64 | tr -d '\n')" - echo "::add-mask::$auth_header" - git -c http.extraheader="AUTHORIZATION: basic ${auth_header}" \ - push --force-with-lease="refs/heads/${SOURCE_BRANCH}:${EXPECTED_HEAD}" \ - origin "HEAD:refs/heads/${SOURCE_BRANCH}" diff --git a/package-lock.json b/package-lock.json index cf1c991c1..792ca5179 100644 --- a/package-lock.json +++ b/package-lock.json @@ -15,7 +15,8 @@ "@eslint/js": "^10.0.1", "eslint-plugin-jsdoc": "^63.0.13", "react": "^19.2.4", - "react-dom": "^19.2.7" + "react-dom": "^19.2.7", + "undici": "7.29.0" }, "engines": { "node": ">=22.13 <23" @@ -32,7 +33,7 @@ "class-variance-authority": "^0.7.1", "clsx": "^2.1.1", "lucide-react": "^1.24.0", - "pdfjs-dist": "6.1.200", + "pdfjs-dist": "6.2.108", "react": "^19.2.4", "react-dom": "^19.2.7", "sonner": "^2.0.7", @@ -212,6 +213,18 @@ "url": "https://opencollective.com/vitest" } }, + "apps/desktop/node_modules/pdfjs-dist": { + "version": "6.2.108", + "resolved": "https://registry.npmjs.org/pdfjs-dist/-/pdfjs-dist-6.2.108.tgz", + "integrity": "sha512-YxFb+SQcodN2rnX9Tn3dHYlqfb7NjlzzfONPpJd+AKoKtUjEdevTfbC07d5TcczzOK6261auRkP/M8OBHs9vFQ==", + "license": "Apache-2.0", + "engines": { + "node": ">=22.13.0 || >=24" + }, + "optionalDependencies": { + "@napi-rs/canvas": "^1.0.0" + } + }, "apps/desktop/node_modules/vitest": { "version": "4.1.10", "resolved": "https://registry.npmjs.org/vitest/-/vitest-4.1.10.tgz", @@ -6367,18 +6380,6 @@ "node": ">= 14.16" } }, - "node_modules/pdfjs-dist": { - "version": "6.1.200", - "resolved": "https://registry.npmjs.org/pdfjs-dist/-/pdfjs-dist-6.1.200.tgz", - "integrity": "sha512-o8MolyzirkkLrcdsae/HEOiIcXWI7DS5zGpvqW8xTC2YUsW30rltFw2bDGvw/fskUdEMrQm2br68jzDS5BH2vw==", - "license": "Apache-2.0", - "engines": { - "node": ">=22.13.0 || >=24" - }, - "optionalDependencies": { - "@napi-rs/canvas": "^1.0.0" - } - }, "node_modules/picocolors": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz", @@ -7179,9 +7180,9 @@ } }, "node_modules/undici": { - "version": "7.28.0", - "resolved": "https://registry.npmjs.org/undici/-/undici-7.28.0.tgz", - "integrity": "sha512-cRZYrTDwWznlnRiPjggAGxZXanty6M8RV1ff8Wm4LWXBp7/IG8v5DnOm74DtUBp9OONpK75YlPnIjQqX0dBDtA==", + "version": "7.29.0", + "resolved": "https://registry.npmjs.org/undici/-/undici-7.29.0.tgz", + "integrity": "sha512-IDxfleLmmbSskfWSUATiN1nfn2rDuvnMOqb5CWR92iIfojA0Ud+ulOAAEQ57LPr9rWmsreUyf5lwyao+7GNNVw==", "dev": true, "license": "MIT", "engines": { From e6b48ca58e5c481e4b0bef8961338b5a3967e6c6 Mon Sep 17 00:00:00 2001 From: Seongho Bae Date: Fri, 7 Aug 2026 19:29:20 +0900 Subject: [PATCH 29/92] test(ci): preserve canonical npm provenance formatting --- .../analysis-engine/tests/test_npm_toolchain_contract.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/services/analysis-engine/tests/test_npm_toolchain_contract.py b/services/analysis-engine/tests/test_npm_toolchain_contract.py index 30e00cbdd..bdfc1e45f 100644 --- a/services/analysis-engine/tests/test_npm_toolchain_contract.py +++ b/services/analysis-engine/tests/test_npm_toolchain_contract.py @@ -51,7 +51,10 @@ def test_primary_ci_proves_exact_npm_before_install_and_lock_reproduction() -> N assert "--no-audit" in workflow assert "--no-fund" in workflow assert "actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a" in workflow - assert "npm-lock-reproduction-${{ github.event.pull_request.head.sha || github.sha }}" in workflow + assert ( + "npm-lock-reproduction-${{ github.event.pull_request.head.sha || github.sha }}" + in workflow + ) assert "if-no-files-found: error" in workflow assert "git diff --exit-code -- package-lock.json" in workflow From 3edf17356cea74b8fceac50fed8fb3b958dfc1ac Mon Sep 17 00:00:00 2001 From: Seongho Bae Date: Fri, 7 Aug 2026 19:48:49 +0900 Subject: [PATCH 30/92] ci(pr783): diagnose Ruff import ordering --- .../workflows/diagnose-pr783-ruff-imports.yml | 64 +++++++++++++++++++ 1 file changed, 64 insertions(+) create mode 100644 .github/workflows/diagnose-pr783-ruff-imports.yml diff --git a/.github/workflows/diagnose-pr783-ruff-imports.yml b/.github/workflows/diagnose-pr783-ruff-imports.yml new file mode 100644 index 000000000..f800fdaae --- /dev/null +++ b/.github/workflows/diagnose-pr783-ruff-imports.yml @@ -0,0 +1,64 @@ +name: Diagnose PR 783 Ruff import ordering + +on: + push: + branches: + - fix/high-security-dependency-baseline + paths: + - .github/workflows/diagnose-pr783-ruff-imports.yml + +permissions: + contents: read + +concurrency: + group: diagnose-pr783-ruff-imports + cancel-in-progress: false + +env: + GIT_CONFIG_COUNT: "1" + GIT_CONFIG_KEY_0: init.defaultBranch + GIT_CONFIG_VALUE_0: develop + +jobs: + diagnose: + if: >- + github.repository == 'ContextualWisdomLab/bandscope' && + github.ref == 'refs/heads/fix/high-security-dependency-baseline' + runs-on: ubuntu-24.04 + timeout-minutes: 15 + steps: + - name: Harden runner + uses: step-security/harden-runner@bf7454d06d71f1098171f2acdf0cd4708d7b5920 # v2.20.0 + with: + egress-policy: audit + + - name: Checkout exact trigger + uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0 + with: + ref: ${{ github.sha }} + persist-credentials: false + + - name: Set up Python + uses: actions/setup-python@a309ff8b426b58ec0e2a45f0f869d46889d02405 # v6.0.0 + with: + python-version: "3.12" + + - name: Set up uv + uses: astral-sh/setup-uv@11f9893b081a58869d3b5fccaea48c9e9e46f990 # v8.3.2 + with: + version: "0.8.6" + enable-cache: false + + - name: Print Ruff's exact import repair + shell: bash --noprofile --norc -e -o pipefail {0} + run: | + uv sync --project services/analysis-engine --group dev --frozen + cd services/analysis-engine + uv run ruff check \ + tests/test_high_security_dependency_baseline.py \ + tests/test_npm_toolchain_contract.py \ + --fix-only + git diff -- \ + tests/test_high_security_dependency_baseline.py \ + tests/test_npm_toolchain_contract.py + test -n "$(git diff --name-only -- tests/test_high_security_dependency_baseline.py tests/test_npm_toolchain_contract.py)" From 234521906a99fb786847cfacd0425f9527bd455b Mon Sep 17 00:00:00 2001 From: Seongho Bae Date: Fri, 7 Aug 2026 19:53:39 +0900 Subject: [PATCH 31/92] style(ci): normalize security test imports --- .../tests/test_high_security_dependency_baseline.py | 1 - 1 file changed, 1 deletion(-) diff --git a/services/analysis-engine/tests/test_high_security_dependency_baseline.py b/services/analysis-engine/tests/test_high_security_dependency_baseline.py index 0a9e81ab1..1df9d6ab2 100644 --- a/services/analysis-engine/tests/test_high_security_dependency_baseline.py +++ b/services/analysis-engine/tests/test_high_security_dependency_baseline.py @@ -5,7 +5,6 @@ import json from pathlib import Path - _REPOSITORY_ROOT = Path(__file__).resolve().parents[3] _PDFJS_VERSION = "6.2.108" _UNDICI_VERSION = "7.29.0" From dc7e8b4aa4b18e3a20db3eab9b65fbd71503417d Mon Sep 17 00:00:00 2001 From: Seongho Bae Date: Fri, 7 Aug 2026 19:54:37 +0900 Subject: [PATCH 32/92] style(ci): normalize npm provenance test imports --- services/analysis-engine/tests/test_npm_toolchain_contract.py | 1 - 1 file changed, 1 deletion(-) diff --git a/services/analysis-engine/tests/test_npm_toolchain_contract.py b/services/analysis-engine/tests/test_npm_toolchain_contract.py index bdfc1e45f..72a34305a 100644 --- a/services/analysis-engine/tests/test_npm_toolchain_contract.py +++ b/services/analysis-engine/tests/test_npm_toolchain_contract.py @@ -5,7 +5,6 @@ import json from pathlib import Path - _REPOSITORY_ROOT = Path(__file__).resolve().parents[3] _EXPECTED_NPM_VERSION = "10.9.8" _EXPECTED_NODE_VERSION = "22.22.3" From c5ee630fd73decab457450d629d11aecb756637a Mon Sep 17 00:00:00 2001 From: Seongho Bae Date: Fri, 7 Aug 2026 19:55:01 +0900 Subject: [PATCH 33/92] chore(ci): remove completed Ruff diagnostic --- .../workflows/diagnose-pr783-ruff-imports.yml | 64 ------------------- 1 file changed, 64 deletions(-) delete mode 100644 .github/workflows/diagnose-pr783-ruff-imports.yml diff --git a/.github/workflows/diagnose-pr783-ruff-imports.yml b/.github/workflows/diagnose-pr783-ruff-imports.yml deleted file mode 100644 index f800fdaae..000000000 --- a/.github/workflows/diagnose-pr783-ruff-imports.yml +++ /dev/null @@ -1,64 +0,0 @@ -name: Diagnose PR 783 Ruff import ordering - -on: - push: - branches: - - fix/high-security-dependency-baseline - paths: - - .github/workflows/diagnose-pr783-ruff-imports.yml - -permissions: - contents: read - -concurrency: - group: diagnose-pr783-ruff-imports - cancel-in-progress: false - -env: - GIT_CONFIG_COUNT: "1" - GIT_CONFIG_KEY_0: init.defaultBranch - GIT_CONFIG_VALUE_0: develop - -jobs: - diagnose: - if: >- - github.repository == 'ContextualWisdomLab/bandscope' && - github.ref == 'refs/heads/fix/high-security-dependency-baseline' - runs-on: ubuntu-24.04 - timeout-minutes: 15 - steps: - - name: Harden runner - uses: step-security/harden-runner@bf7454d06d71f1098171f2acdf0cd4708d7b5920 # v2.20.0 - with: - egress-policy: audit - - - name: Checkout exact trigger - uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0 - with: - ref: ${{ github.sha }} - persist-credentials: false - - - name: Set up Python - uses: actions/setup-python@a309ff8b426b58ec0e2a45f0f869d46889d02405 # v6.0.0 - with: - python-version: "3.12" - - - name: Set up uv - uses: astral-sh/setup-uv@11f9893b081a58869d3b5fccaea48c9e9e46f990 # v8.3.2 - with: - version: "0.8.6" - enable-cache: false - - - name: Print Ruff's exact import repair - shell: bash --noprofile --norc -e -o pipefail {0} - run: | - uv sync --project services/analysis-engine --group dev --frozen - cd services/analysis-engine - uv run ruff check \ - tests/test_high_security_dependency_baseline.py \ - tests/test_npm_toolchain_contract.py \ - --fix-only - git diff -- \ - tests/test_high_security_dependency_baseline.py \ - tests/test_npm_toolchain_contract.py - test -n "$(git diff --name-only -- tests/test_high_security_dependency_baseline.py tests/test_npm_toolchain_contract.py)" From f0c9ad11566b5b57f09eac56289647a4560d4b73 Mon Sep 17 00:00:00 2001 From: Seongho Bae Date: Fri, 7 Aug 2026 20:13:19 +0900 Subject: [PATCH 34/92] ci(pr783): finalize exact Ruff formatting --- .../finalize-pr783-python-format.yml | 130 ++++++++++++++++++ 1 file changed, 130 insertions(+) create mode 100644 .github/workflows/finalize-pr783-python-format.yml diff --git a/.github/workflows/finalize-pr783-python-format.yml b/.github/workflows/finalize-pr783-python-format.yml new file mode 100644 index 000000000..14f869cb4 --- /dev/null +++ b/.github/workflows/finalize-pr783-python-format.yml @@ -0,0 +1,130 @@ +name: Finalize PR 783 Python formatting + +on: + push: + branches: + - fix/high-security-dependency-baseline + paths: + - .github/workflows/finalize-pr783-python-format.yml + +permissions: + contents: read + +concurrency: + group: finalize-pr783-python-format + cancel-in-progress: false + +env: + GIT_CONFIG_COUNT: "1" + GIT_CONFIG_KEY_0: init.defaultBranch + GIT_CONFIG_VALUE_0: develop + EXPECTED_SOURCE_HEAD: c5ee630fd73decab457450d629d11aecb756637a + +jobs: + format-verify-publish: + if: >- + github.repository == 'ContextualWisdomLab/bandscope' && + github.ref == 'refs/heads/fix/high-security-dependency-baseline' + permissions: + contents: write + runs-on: ubuntu-24.04 + timeout-minutes: 45 + steps: + - name: Harden runner + uses: step-security/harden-runner@bf7454d06d71f1098171f2acdf0cd4708d7b5920 # v2.20.0 + with: + egress-policy: audit + + - name: Checkout exact trigger without persisted credentials + uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0 + with: + ref: ${{ github.sha }} + fetch-depth: 0 + persist-credentials: false + + - name: Verify bounded trigger lineage + shell: bash --noprofile --norc -e -o pipefail {0} + run: | + test "$(git rev-parse HEAD)" = "$GITHUB_SHA" + test "$(git rev-parse HEAD^)" = "$EXPECTED_SOURCE_HEAD" + mapfile -t trigger_delta < <(git diff --name-only "$EXPECTED_SOURCE_HEAD" HEAD) + test "${#trigger_delta[@]}" -eq 1 + test "${trigger_delta[0]}" = ".github/workflows/finalize-pr783-python-format.yml" + + - name: Set up Node and npm + uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6.4.0 + with: + node-version: "22.22.3" + cache: npm + + - name: Set up Python + uses: actions/setup-python@a309ff8b426b58ec0e2a45f0f869d46889d02405 # v6.0.0 + with: + python-version: "3.12" + + - name: Set up uv + uses: astral-sh/setup-uv@11f9893b081a58869d3b5fccaea48c9e9e46f990 # v8.3.2 + with: + version: "0.8.6" + enable-cache: false + + - name: Install Rust stable + shell: bash --noprofile --norc -e -o pipefail {0} + run: rustup toolchain install stable --profile minimal + + - name: Install exact dependencies + shell: bash --noprofile --norc -e -o pipefail {0} + run: | + test "$(npm --version)" = "10.9.8" + npm ci + uv sync --project services/analysis-engine --group dev --frozen + + - name: Apply Ruff's exact formatter result + shell: bash --noprofile --norc -e -o pipefail {0} + run: | + cd services/analysis-engine + uv run ruff format \ + tests/test_high_security_dependency_baseline.py \ + tests/test_npm_toolchain_contract.py + uv run ruff format --check \ + tests/test_high_security_dependency_baseline.py \ + tests/test_npm_toolchain_contract.py + uv run ruff check \ + tests/test_high_security_dependency_baseline.py \ + tests/test_npm_toolchain_contract.py + cd ../.. + actual_delta="$(git diff --name-only -- | sort)" + expected_delta="$(printf '%s\n' services/analysis-engine/tests/test_high_security_dependency_baseline.py services/analysis-engine/tests/test_npm_toolchain_contract.py | sort)" + test "$actual_delta" = "$expected_delta" + git diff --check + + - name: Run the complete release harness + shell: bash --noprofile --norc -e -o pipefail {0} + run: ./scripts/harness/quickcheck.sh + + - name: Remove one-shot formatter and publish verified source + env: + EXPECTED_HEAD: ${{ github.sha }} + SOURCE_BRANCH: fix/high-security-dependency-baseline + PUSH_TOKEN: ${{ github.token }} + shell: bash --noprofile --norc -e -o pipefail {0} + run: | + rm .github/workflows/finalize-pr783-python-format.yml + actual_delta="$(git diff --name-only "$EXPECTED_SOURCE_HEAD" -- | sort)" + expected_delta="$(printf '%s\n' \ + .github/workflows/finalize-pr783-python-format.yml \ + services/analysis-engine/tests/test_high_security_dependency_baseline.py \ + services/analysis-engine/tests/test_npm_toolchain_contract.py | sort)" + test "$actual_delta" = "$expected_delta" + remote_head="$(git ls-remote origin "refs/heads/${SOURCE_BRANCH}" | cut -f1)" + test "$remote_head" = "$EXPECTED_HEAD" + git config user.name "github-actions[bot]" + git config user.email "41898282+github-actions[bot]@users.noreply.github.com" + git add -A + git diff --cached --check + git commit -m "style(ci): apply canonical Ruff formatting" + auth_header="$(printf 'x-access-token:%s' "$PUSH_TOKEN" | base64 | tr -d '\n')" + echo "::add-mask::$auth_header" + git -c http.extraheader="AUTHORIZATION: basic ${auth_header}" \ + push --force-with-lease="refs/heads/${SOURCE_BRANCH}:${EXPECTED_HEAD}" \ + origin "HEAD:refs/heads/${SOURCE_BRANCH}" From 102a89f91d8e4418a4af489b82bd19d4fe1bd77f Mon Sep 17 00:00:00 2001 From: Seongho Bae Date: Fri, 7 Aug 2026 20:16:52 +0900 Subject: [PATCH 35/92] chore(ci): remove temporary branch writer --- .../finalize-pr783-python-format.yml | 130 ------------------ 1 file changed, 130 deletions(-) delete mode 100644 .github/workflows/finalize-pr783-python-format.yml diff --git a/.github/workflows/finalize-pr783-python-format.yml b/.github/workflows/finalize-pr783-python-format.yml deleted file mode 100644 index 14f869cb4..000000000 --- a/.github/workflows/finalize-pr783-python-format.yml +++ /dev/null @@ -1,130 +0,0 @@ -name: Finalize PR 783 Python formatting - -on: - push: - branches: - - fix/high-security-dependency-baseline - paths: - - .github/workflows/finalize-pr783-python-format.yml - -permissions: - contents: read - -concurrency: - group: finalize-pr783-python-format - cancel-in-progress: false - -env: - GIT_CONFIG_COUNT: "1" - GIT_CONFIG_KEY_0: init.defaultBranch - GIT_CONFIG_VALUE_0: develop - EXPECTED_SOURCE_HEAD: c5ee630fd73decab457450d629d11aecb756637a - -jobs: - format-verify-publish: - if: >- - github.repository == 'ContextualWisdomLab/bandscope' && - github.ref == 'refs/heads/fix/high-security-dependency-baseline' - permissions: - contents: write - runs-on: ubuntu-24.04 - timeout-minutes: 45 - steps: - - name: Harden runner - uses: step-security/harden-runner@bf7454d06d71f1098171f2acdf0cd4708d7b5920 # v2.20.0 - with: - egress-policy: audit - - - name: Checkout exact trigger without persisted credentials - uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0 - with: - ref: ${{ github.sha }} - fetch-depth: 0 - persist-credentials: false - - - name: Verify bounded trigger lineage - shell: bash --noprofile --norc -e -o pipefail {0} - run: | - test "$(git rev-parse HEAD)" = "$GITHUB_SHA" - test "$(git rev-parse HEAD^)" = "$EXPECTED_SOURCE_HEAD" - mapfile -t trigger_delta < <(git diff --name-only "$EXPECTED_SOURCE_HEAD" HEAD) - test "${#trigger_delta[@]}" -eq 1 - test "${trigger_delta[0]}" = ".github/workflows/finalize-pr783-python-format.yml" - - - name: Set up Node and npm - uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6.4.0 - with: - node-version: "22.22.3" - cache: npm - - - name: Set up Python - uses: actions/setup-python@a309ff8b426b58ec0e2a45f0f869d46889d02405 # v6.0.0 - with: - python-version: "3.12" - - - name: Set up uv - uses: astral-sh/setup-uv@11f9893b081a58869d3b5fccaea48c9e9e46f990 # v8.3.2 - with: - version: "0.8.6" - enable-cache: false - - - name: Install Rust stable - shell: bash --noprofile --norc -e -o pipefail {0} - run: rustup toolchain install stable --profile minimal - - - name: Install exact dependencies - shell: bash --noprofile --norc -e -o pipefail {0} - run: | - test "$(npm --version)" = "10.9.8" - npm ci - uv sync --project services/analysis-engine --group dev --frozen - - - name: Apply Ruff's exact formatter result - shell: bash --noprofile --norc -e -o pipefail {0} - run: | - cd services/analysis-engine - uv run ruff format \ - tests/test_high_security_dependency_baseline.py \ - tests/test_npm_toolchain_contract.py - uv run ruff format --check \ - tests/test_high_security_dependency_baseline.py \ - tests/test_npm_toolchain_contract.py - uv run ruff check \ - tests/test_high_security_dependency_baseline.py \ - tests/test_npm_toolchain_contract.py - cd ../.. - actual_delta="$(git diff --name-only -- | sort)" - expected_delta="$(printf '%s\n' services/analysis-engine/tests/test_high_security_dependency_baseline.py services/analysis-engine/tests/test_npm_toolchain_contract.py | sort)" - test "$actual_delta" = "$expected_delta" - git diff --check - - - name: Run the complete release harness - shell: bash --noprofile --norc -e -o pipefail {0} - run: ./scripts/harness/quickcheck.sh - - - name: Remove one-shot formatter and publish verified source - env: - EXPECTED_HEAD: ${{ github.sha }} - SOURCE_BRANCH: fix/high-security-dependency-baseline - PUSH_TOKEN: ${{ github.token }} - shell: bash --noprofile --norc -e -o pipefail {0} - run: | - rm .github/workflows/finalize-pr783-python-format.yml - actual_delta="$(git diff --name-only "$EXPECTED_SOURCE_HEAD" -- | sort)" - expected_delta="$(printf '%s\n' \ - .github/workflows/finalize-pr783-python-format.yml \ - services/analysis-engine/tests/test_high_security_dependency_baseline.py \ - services/analysis-engine/tests/test_npm_toolchain_contract.py | sort)" - test "$actual_delta" = "$expected_delta" - remote_head="$(git ls-remote origin "refs/heads/${SOURCE_BRANCH}" | cut -f1)" - test "$remote_head" = "$EXPECTED_HEAD" - git config user.name "github-actions[bot]" - git config user.email "41898282+github-actions[bot]@users.noreply.github.com" - git add -A - git diff --cached --check - git commit -m "style(ci): apply canonical Ruff formatting" - auth_header="$(printf 'x-access-token:%s' "$PUSH_TOKEN" | base64 | tr -d '\n')" - echo "::add-mask::$auth_header" - git -c http.extraheader="AUTHORIZATION: basic ${auth_header}" \ - push --force-with-lease="refs/heads/${SOURCE_BRANCH}:${EXPECTED_HEAD}" \ - origin "HEAD:refs/heads/${SOURCE_BRANCH}" From d4887ec31bd6f48475ef5ac7832946649721db74 Mon Sep 17 00:00:00 2001 From: Seongho Bae Date: Fri, 7 Aug 2026 20:29:43 +0900 Subject: [PATCH 36/92] style(test): apply Ruff formatting to security contracts --- .../tests/test_high_security_dependency_baseline.py | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/services/analysis-engine/tests/test_high_security_dependency_baseline.py b/services/analysis-engine/tests/test_high_security_dependency_baseline.py index 1df9d6ab2..7be5df944 100644 --- a/services/analysis-engine/tests/test_high_security_dependency_baseline.py +++ b/services/analysis-engine/tests/test_high_security_dependency_baseline.py @@ -20,9 +20,7 @@ def _read_json(relative_path: str) -> dict[str, object]: """Return one repository JSON document as a mapping.""" - document = json.loads( - (_REPOSITORY_ROOT / relative_path).read_text(encoding="utf-8") - ) + document = json.loads((_REPOSITORY_ROOT / relative_path).read_text(encoding="utf-8")) assert isinstance(document, dict) return document @@ -65,9 +63,7 @@ def test_lock_records_match_exact_registry_artifacts_and_preserve_peer_metadata( undici = packages["node_modules/undici"] assert isinstance(undici, dict) assert undici["version"] == _UNDICI_VERSION - assert undici["resolved"] == ( - "https://registry.npmjs.org/undici/-/undici-7.29.0.tgz" - ) + assert undici["resolved"] == "https://registry.npmjs.org/undici/-/undici-7.29.0.tgz" assert undici["integrity"] == _UNDICI_INTEGRITY esbuild_locations = { From 459abdd9b30ee32adb60ecb66f0efae8ac25219b Mon Sep 17 00:00:00 2001 From: Seongho Bae Date: Fri, 7 Aug 2026 20:30:19 +0900 Subject: [PATCH 37/92] style(test): finish Ruff formatting for npm provenance --- .../tests/test_npm_toolchain_contract.py | 12 +++--------- 1 file changed, 3 insertions(+), 9 deletions(-) diff --git a/services/analysis-engine/tests/test_npm_toolchain_contract.py b/services/analysis-engine/tests/test_npm_toolchain_contract.py index 72a34305a..5e9a65dbc 100644 --- a/services/analysis-engine/tests/test_npm_toolchain_contract.py +++ b/services/analysis-engine/tests/test_npm_toolchain_contract.py @@ -12,9 +12,7 @@ def _root_manifest() -> dict[str, object]: """Return the checked-in root package manifest as a JSON object.""" - manifest = json.loads( - (_REPOSITORY_ROOT / "package.json").read_text(encoding="utf-8") - ) + manifest = json.loads((_REPOSITORY_ROOT / "package.json").read_text(encoding="utf-8")) assert isinstance(manifest, dict) return manifest @@ -36,9 +34,7 @@ def test_root_manifest_pins_the_lockfile_generator_and_fails_on_drift() -> None: def test_primary_ci_proves_exact_npm_before_install_and_lock_reproduction() -> None: """Keep the clean installer and lock reproduction on one explicit toolchain.""" - workflow = (_REPOSITORY_ROOT / ".github" / "workflows" / "ci.yml").read_text( - encoding="utf-8" - ) + workflow = (_REPOSITORY_ROOT / ".github" / "workflows" / "ci.yml").read_text(encoding="utf-8") assert f'node-version: "{_EXPECTED_NODE_VERSION}"' in workflow assert f'EXPECTED_NPM_VERSION: "{_EXPECTED_NPM_VERSION}"' in workflow @@ -60,9 +56,7 @@ def test_primary_ci_proves_exact_npm_before_install_and_lock_reproduction() -> N def test_root_lock_uses_the_supported_location_keyed_format() -> None: """Require the npm-v9-and-newer lock format used by the pinned generator.""" - lock_document = json.loads( - (_REPOSITORY_ROOT / "package-lock.json").read_text(encoding="utf-8") - ) + lock_document = json.loads((_REPOSITORY_ROOT / "package-lock.json").read_text(encoding="utf-8")) assert lock_document["lockfileVersion"] == 3 assert isinstance(lock_document["packages"], dict) From ace4257be06754d78b6f6eca2207d7cdd1bf52e5 Mon Sep 17 00:00:00 2001 From: Seongho Bae Date: Wed, 12 Aug 2026 03:07:40 +0900 Subject: [PATCH 38/92] fix(security): refresh vulnerable npm transitive pins --- package-lock.json | 3062 +++++++++++++++++++++++---------------------- 1 file changed, 1573 insertions(+), 1489 deletions(-) diff --git a/package-lock.json b/package-lock.json index 792ca5179..973344f3b 100644 --- a/package-lock.json +++ b/package-lock.json @@ -11,12 +11,16 @@ "apps/*", "packages/*" ], + "dependencies": { + "nanoid": "^3.3.18", + "pdfjs-dist": "^6.2.108", + "undici": "^7.29.0" + }, "devDependencies": { "@eslint/js": "^10.0.1", "eslint-plugin-jsdoc": "^63.0.13", "react": "^19.2.4", - "react-dom": "^19.2.7", - "undici": "7.29.0" + "react-dom": "^19.2.7" }, "engines": { "node": ">=22.13 <23" @@ -61,264 +65,10 @@ "vitest": "^4.1.10" } }, - "apps/desktop/node_modules/@types/react-dom": { - "version": "19.2.3", - "dev": true, - "license": "MIT", - "peerDependencies": { - "@types/react": "^19.2.0" - } - }, - "apps/desktop/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==", - "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" - }, - "funding": { - "url": "https://opencollective.com/vitest" - }, - "peerDependencies": { - "@vitest/browser": "4.1.10", - "vitest": "4.1.10" - }, - "peerDependenciesMeta": { - "@vitest/browser": { - "optional": true - } - } - }, - "apps/desktop/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==", - "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" - }, - "funding": { - "url": "https://opencollective.com/vitest" - } - }, - "apps/desktop/node_modules/@vitest/mocker": { - "version": "4.1.10", - "resolved": "https://registry.npmjs.org/@vitest/mocker/-/mocker-4.1.10.tgz", - "integrity": "sha512-v0xaezt+DKEmKfaxg133ldzADrwLGd7Ze1MfQQTYfvs8OqZIwbxyxaYURivwV7sWy5fqn3rH5uOrSp07bp44Ow==", - "dev": true, - "license": "MIT", - "dependencies": { - "@vitest/spy": "4.1.10", - "estree-walker": "^3.0.3", - "magic-string": "^0.30.21" - }, - "funding": { - "url": "https://opencollective.com/vitest" - }, - "peerDependencies": { - "msw": "^2.4.9", - "vite": "^6.0.0 || ^7.0.0 || ^8.0.0" - }, - "peerDependenciesMeta": { - "msw": { - "optional": true - }, - "vite": { - "optional": true - } - } - }, - "apps/desktop/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" - } - }, - "apps/desktop/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" - } - }, - "apps/desktop/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" - } - }, - "apps/desktop/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" - } - }, - "apps/desktop/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==", - "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" - } - }, - "apps/desktop/node_modules/pdfjs-dist": { - "version": "6.2.108", - "resolved": "https://registry.npmjs.org/pdfjs-dist/-/pdfjs-dist-6.2.108.tgz", - "integrity": "sha512-YxFb+SQcodN2rnX9Tn3dHYlqfb7NjlzzfONPpJd+AKoKtUjEdevTfbC07d5TcczzOK6261auRkP/M8OBHs9vFQ==", - "license": "Apache-2.0", - "engines": { - "node": ">=22.13.0 || >=24" - }, - "optionalDependencies": { - "@napi-rs/canvas": "^1.0.0" - } - }, - "apps/desktop/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" - }, - "bin": { - "vitest": "vitest.mjs" - }, - "engines": { - "node": "^20.0.0 || ^22.0.0 || >=24.0.0" - }, - "funding": { - "url": "https://opencollective.com/vitest" - }, - "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", - "happy-dom": "*", - "jsdom": "*", - "vite": "^6.0.0 || ^7.0.0 || ^8.0.0" - }, - "peerDependenciesMeta": { - "@edge-runtime/vm": { - "optional": true - }, - "@opentelemetry/api": { - "optional": true - }, - "@types/node": { - "optional": true - }, - "@vitest/browser-playwright": { - "optional": true - }, - "@vitest/browser-preview": { - "optional": true - }, - "@vitest/browser-webdriverio": { - "optional": true - }, - "@vitest/coverage-istanbul": { - "optional": true - }, - "@vitest/coverage-v8": { - "optional": true - }, - "@vitest/ui": { - "optional": true - }, - "happy-dom": { - "optional": true - }, - "jsdom": { - "optional": true - }, - "vite": { - "optional": false - } - } - }, "node_modules/@adobe/css-tools": { - "version": "4.4.4", - "resolved": "https://registry.npmjs.org/@adobe/css-tools/-/css-tools-4.4.4.tgz", - "integrity": "sha512-Elp+iwUx5rN5+Y8xLt5/GRoG20WGoDCQ/1Fb+1LiGtvwbDavuSk0jhD/eZdckHAuzcDzccnkv+rEjyWfRx18gg==", + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/@adobe/css-tools/-/css-tools-4.5.0.tgz", + "integrity": "sha512-6OzddxPio9UiWTCemp4N8cYLV2ZN1ncRnV1cVGtve7dhPOtRkleRyx32GQCYSwDYgaHU3USMm84tNsvKzRCa1Q==", "dev": true, "license": "MIT" }, @@ -440,14 +190,14 @@ } }, "node_modules/@babel/generator": { - "version": "7.29.7", - "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.29.7.tgz", - "integrity": "sha512-DkXD5OJQaAQIdZ1bt3UZdEnHAn9Imd3IVBdX03UFe+ony9Ojw5pzr9YVKGDY1jt+Gcn/FnGkNf8r+Vj5NOJWtQ==", + "version": "7.29.8", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.29.8.tgz", + "integrity": "sha512-gZbepsdh3WDtgZKWL+vTPh71LSBrm/Y4/QDZBVCcYfmeTEEuoOYwlSy+G1StfJg+/Zy550u/3TATbm7qDbbMtg==", "dev": true, "license": "MIT", "dependencies": { - "@babel/parser": "^7.29.7", - "@babel/types": "^7.29.7", + "@babel/parser": "^7.29.8", + "@babel/types": "^7.29.8", "@jridgewell/gen-mapping": "^0.3.12", "@jridgewell/trace-mapping": "^0.3.28", "jsesc": "^3.0.2" @@ -580,13 +330,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.8", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.29.8.tgz", + "integrity": "sha512-E8lTAYNB1KW+FH+VGJuZM1ioAx2E6oVlvQFRrf5P8ZZmsiJXYAD9vTFV7yyEURNzgh1dFqMZuO6tUwcARbqFCA==", "dev": true, "license": "MIT", "dependencies": { - "@babel/types": "^7.29.7" + "@babel/types": "^7.29.8" }, "bin": { "parser": "bin/babel-parser.js" @@ -596,9 +346,9 @@ } }, "node_modules/@babel/runtime": { - "version": "7.29.2", - "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.29.2.tgz", - "integrity": "sha512-JiDShH45zKHWyGe4ZNVRrCjBz8Nh9TMmZG1kh4QTK8hCBTWBi8Da+i7s1fJw7/lYpM4ccepSNfqzZ/QvABBi5g==", + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.29.7.tgz", + "integrity": "sha512-Nq8OhGWiZIZGV6hLHoyAKLLcJihP/xFeBMGJoUrxTX2psI8dCifzLhZISFb+VWS3wFMRDmCGw5R+dOySCqPLhw==", "license": "MIT", "engines": { "node": ">=6.9.0" @@ -620,18 +370,18 @@ } }, "node_modules/@babel/traverse": { - "version": "7.29.7", - "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.29.7.tgz", - "integrity": "sha512-EhlfNQtZ+NK22w5BM61ciuiq1m58ed33Wr1Xan//ZRTy6hgjnwyCffRYwzsGXdASJSUJ1guZILsErh1eQcl+zw==", + "version": "7.29.8", + "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.29.8.tgz", + "integrity": "sha512-I5z7H3bf/41ktsNVLtpN0wAa336HkqIHQ5BuPLEhTkt1jVSyZpeNKIzTgEWmlxjdg81R0IgUCcaE+Ok3NvrfZg==", "dev": true, "license": "MIT", "dependencies": { "@babel/code-frame": "^7.29.7", - "@babel/generator": "^7.29.7", + "@babel/generator": "^7.29.8", "@babel/helper-globals": "^7.29.7", - "@babel/parser": "^7.29.7", + "@babel/parser": "^7.29.8", "@babel/template": "^7.29.7", - "@babel/types": "^7.29.7", + "@babel/types": "^7.29.8", "debug": "^4.3.1" }, "engines": { @@ -639,9 +389,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": { @@ -661,15 +411,15 @@ "link": true }, "node_modules/@base-ui/react": { - "version": "1.5.0", - "resolved": "https://registry.npmjs.org/@base-ui/react/-/react-1.5.0.tgz", - "integrity": "sha512-z1gSAlced1yY+iM+mHDEtIkD8UI3Ebs52MuBPxvV6f5hRutk+xvCH/wuB7hDqDzK9JG5FoMz5nhrqtSs1wjt1A==", + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/@base-ui/react/-/react-1.7.0.tgz", + "integrity": "sha512-j+8QjX44C32jrXD/qyEAGpFr70FRpGL2CY61mQd9nBPWN737CK0xxD1ceJ055rW4RtdvFDT1e7otzdlfxvsYug==", "license": "MIT", "dependencies": { "@babel/runtime": "^7.29.2", - "@base-ui/utils": "0.2.9", - "@floating-ui/react-dom": "^2.1.8", - "@floating-ui/utils": "^0.2.11", + "@base-ui/utils": "0.3.2", + "@floating-ui/react-dom": "^2.1.9", + "@floating-ui/utils": "^0.2.12", "use-sync-external-store": "^1.6.0" }, "engines": { @@ -699,14 +449,14 @@ } }, "node_modules/@base-ui/utils": { - "version": "0.2.9", - "resolved": "https://registry.npmjs.org/@base-ui/utils/-/utils-0.2.9.tgz", - "integrity": "sha512-x/PDDCYzoqPpjrdyb3VcyylTI2IjUXEtYDGi5foh7KsnmNJIIaVwA2GLgDH1dps1GgXiJbA60hM+AyuTfQzIvw==", + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/@base-ui/utils/-/utils-0.3.2.tgz", + "integrity": "sha512-oWy1aq/I2GmYjpl4PhEAhzflF8VPGKgZeq0xAWTbfD5KBWyxcN0ZP2+WHSUm/5Z6lVMBDLReLcoXwSYoRc/zNQ==", "license": "MIT", "dependencies": { "@babel/runtime": "^7.29.2", - "@floating-ui/utils": "^0.2.11", - "reselect": "^5.1.1", + "@floating-ui/utils": "^0.2.12", + "reselect": "^5.2.0", "use-sync-external-store": "^1.6.0" }, "peerDependencies": { @@ -744,9 +494,9 @@ } }, "node_modules/@csstools/color-helpers": { - "version": "6.0.2", - "resolved": "https://registry.npmjs.org/@csstools/color-helpers/-/color-helpers-6.0.2.tgz", - "integrity": "sha512-LMGQLS9EuADloEFkcTBR3BwV/CGHV7zyDxVRtVDTwdI2Ca4it0CCVTT9wCkxSgokjE5Ho41hEPgb8OEUwoXr6Q==", + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/@csstools/color-helpers/-/color-helpers-6.1.0.tgz", + "integrity": "sha512-064IFJdjTfUqnjpCVpMOdbr8FLQBhinbZj6yRv2An2E41O/pLEXqfFRWqGq/SxlE5PEUYTlvWsG2r8MswAVvkg==", "dev": true, "funding": [ { @@ -764,9 +514,9 @@ } }, "node_modules/@csstools/css-calc": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/@csstools/css-calc/-/css-calc-3.2.1.tgz", - "integrity": "sha512-DtdHlgXh5ZkA43cwBcAm+huzgJiwx3ZTWVjBs94kwz2xKqSimDA3lBgCjphYgwgVUMWatSM0pDd8TILB1yrVVg==", + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/@csstools/css-calc/-/css-calc-3.3.0.tgz", + "integrity": "sha512-c5ihYsPkdG6JCkU2zTMm4+k6r7RXuGxtWYhu5DHMIiF1FHzrfmHL5so11AoFpUv/tu61xfcmT4AmKoFfMPoqdQ==", "dev": true, "funding": [ { @@ -788,9 +538,9 @@ } }, "node_modules/@csstools/css-color-parser": { - "version": "4.1.3", - "resolved": "https://registry.npmjs.org/@csstools/css-color-parser/-/css-color-parser-4.1.3.tgz", - "integrity": "sha512-DOgvIPkikIOixQRlD4YF31VN6fLLUTdrzhfRbis8vm0kMTgIbEPX0Ip/YX9fOeV9iywAS4sUUbTclpan7yYP8Q==", + "version": "4.1.10", + "resolved": "https://registry.npmjs.org/@csstools/css-color-parser/-/css-color-parser-4.1.10.tgz", + "integrity": "sha512-UZhQLIUyJaaMepqehrCODwCg2KW25vFvLWBmqYFaPclYvvxzj/sG8LBOhBFCp11i9uE7t1EyS+RAoV9tztPFyw==", "dev": true, "funding": [ { @@ -804,8 +554,8 @@ ], "license": "MIT", "dependencies": { - "@csstools/color-helpers": "^6.0.2", - "@csstools/css-calc": "^3.2.1" + "@csstools/color-helpers": "^6.1.0", + "@csstools/css-calc": "^3.3.0" }, "engines": { "node": ">=20.19.0" @@ -839,9 +589,9 @@ } }, "node_modules/@csstools/css-syntax-patches-for-csstree": { - "version": "1.1.5", - "resolved": "https://registry.npmjs.org/@csstools/css-syntax-patches-for-csstree/-/css-syntax-patches-for-csstree-1.1.5.tgz", - "integrity": "sha512-oNjBvzLq2GPZtJphCjLqXow/cHySHSgtxvKZb7OqSZ/xHgw6NWNhfad+6AB9cLeVm6eA9d/qMll3JdEHjy6M+A==", + "version": "1.1.7", + "resolved": "https://registry.npmjs.org/@csstools/css-syntax-patches-for-csstree/-/css-syntax-patches-for-csstree-1.1.7.tgz", + "integrity": "sha512-fQ+05118eQS1cofO3aJpB5efgpBZMvIzwr/sbC8kDLVA5XLG8q1kJV5yzrUAI1f7lvhPnm8fgIjzFB8/O/5Dig==", "dev": true, "funding": [ { @@ -884,32 +634,21 @@ } }, "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/@emnapi/core/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.9.2", + "resolved": "https://registry.npmjs.org/@emnapi/core/-/core-1.9.2.tgz", + "integrity": "sha512-UC+ZhH3XtczQYfOlu3lNEkdW/p4dsJ1r/bP7H8+rhao3TTTMO1ATq/4DdIi23XuGoFY+Cz0JmCbdVl0hz9jZcA==", "dev": true, "license": "MIT", "optional": true, "dependencies": { + "@emnapi/wasi-threads": "1.2.1", "tslib": "^2.4.0" } }, "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==", + "version": "1.9.2", + "resolved": "https://registry.npmjs.org/@emnapi/runtime/-/runtime-1.9.2.tgz", + "integrity": "sha512-3U4+MIWHImeyu1wnmVygh5WlgfYDtyf0k8AbLhMFxOipihf6nrWC4syIm/SwEeec0mNSafiiNnMJwbza/Is6Lw==", "dev": true, "license": "MIT", "optional": true, @@ -929,17 +668,17 @@ } }, "node_modules/@es-joy/jsdoccomment": { - "version": "0.88.0", - "resolved": "https://registry.npmjs.org/@es-joy/jsdoccomment/-/jsdoccomment-0.88.0.tgz", - "integrity": "sha512-GK/HL/claLLNo5KG705auIlZMwEtmn88ofSGuLsmVZwKBqMPJhW9DiznYNq07QEqz9BPtA3LBfYImtZmhVvRAw==", + "version": "0.91.0", + "resolved": "https://registry.npmjs.org/@es-joy/jsdoccomment/-/jsdoccomment-0.91.0.tgz", + "integrity": "sha512-vgqlMGNNhZxwDYbUNIHj3Hskb4R28iqdXx90ufHyt/NeuTQkeqjTDslAs9I0/GCAfbxP5BpH5WsL1R1fht5Lxg==", "dev": true, "license": "MIT", "dependencies": { "@types/estree": "^1.0.9", - "@typescript-eslint/types": "^8.59.4", + "@typescript-eslint/types": "^8.65.0", "comment-parser": "1.4.7", "esquery": "^1.7.0", - "jsdoc-type-pratt-parser": "~7.2.0" + "jsdoc-type-pratt-parser": "~8.0.0" }, "engines": { "node": "^20.19.0 || ^22.13.0 || >=24" @@ -956,9 +695,9 @@ } }, "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" ], @@ -968,15 +707,14 @@ "os": [ "aix" ], - "peer": true, "engines": { "node": ">=18" } }, "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" ], @@ -986,15 +724,14 @@ "os": [ "android" ], - "peer": true, "engines": { "node": ">=18" } }, "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" ], @@ -1004,15 +741,14 @@ "os": [ "android" ], - "peer": true, "engines": { "node": ">=18" } }, "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" ], @@ -1022,15 +758,14 @@ "os": [ "android" ], - "peer": true, "engines": { "node": ">=18" } }, "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" ], @@ -1040,15 +775,14 @@ "os": [ "darwin" ], - "peer": true, "engines": { "node": ">=18" } }, "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" ], @@ -1058,15 +792,14 @@ "os": [ "darwin" ], - "peer": true, "engines": { "node": ">=18" } }, "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" ], @@ -1076,15 +809,14 @@ "os": [ "freebsd" ], - "peer": true, "engines": { "node": ">=18" } }, "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" ], @@ -1094,15 +826,14 @@ "os": [ "freebsd" ], - "peer": true, "engines": { "node": ">=18" } }, "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" ], @@ -1112,15 +843,14 @@ "os": [ "linux" ], - "peer": true, "engines": { "node": ">=18" } }, "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" ], @@ -1130,15 +860,14 @@ "os": [ "linux" ], - "peer": true, "engines": { "node": ">=18" } }, "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" ], @@ -1148,15 +877,14 @@ "os": [ "linux" ], - "peer": true, "engines": { "node": ">=18" } }, "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" ], @@ -1166,15 +894,14 @@ "os": [ "linux" ], - "peer": true, "engines": { "node": ">=18" } }, "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" ], @@ -1184,15 +911,14 @@ "os": [ "linux" ], - "peer": true, "engines": { "node": ">=18" } }, "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" ], @@ -1202,15 +928,14 @@ "os": [ "linux" ], - "peer": true, "engines": { "node": ">=18" } }, "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" ], @@ -1220,15 +945,14 @@ "os": [ "linux" ], - "peer": true, "engines": { "node": ">=18" } }, "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" ], @@ -1238,15 +962,14 @@ "os": [ "linux" ], - "peer": true, "engines": { "node": ">=18" } }, "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" ], @@ -1256,15 +979,14 @@ "os": [ "linux" ], - "peer": true, "engines": { "node": ">=18" } }, "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" ], @@ -1274,15 +996,14 @@ "os": [ "netbsd" ], - "peer": true, "engines": { "node": ">=18" } }, "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" ], @@ -1292,15 +1013,14 @@ "os": [ "netbsd" ], - "peer": true, "engines": { "node": ">=18" } }, "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" ], @@ -1310,15 +1030,14 @@ "os": [ "openbsd" ], - "peer": true, "engines": { "node": ">=18" } }, "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" ], @@ -1328,15 +1047,14 @@ "os": [ "openbsd" ], - "peer": true, "engines": { "node": ">=18" } }, "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" ], @@ -1346,15 +1064,14 @@ "os": [ "openharmony" ], - "peer": true, "engines": { "node": ">=18" } }, "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" ], @@ -1364,15 +1081,14 @@ "os": [ "sunos" ], - "peer": true, "engines": { "node": ">=18" } }, "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" ], @@ -1382,15 +1098,14 @@ "os": [ "win32" ], - "peer": true, "engines": { "node": ">=18" } }, "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" ], @@ -1400,15 +1115,14 @@ "os": [ "win32" ], - "peer": true, "engines": { "node": ">=18" } }, "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" ], @@ -1418,15 +1132,14 @@ "os": [ "win32" ], - "peer": true, "engines": { "node": ">=18" } }, "node_modules/@eslint-community/eslint-utils": { - "version": "4.9.1", - "resolved": "https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.9.1.tgz", - "integrity": "sha512-phrYmNiYppR7znFEdqgfWHXR6NCkZEK7hwWDHZUjit/2/U0r6XvkDl0SYnoM51Hq7FhCGdLDT6zxCCOY1hexsQ==", + "version": "4.10.1", + "resolved": "https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.10.1.tgz", + "integrity": "sha512-cuadcxVFE8sDK6iWJbs8Sn0av2Nrh2QSGQhVlBW9AaAHqHwjWsZHT8LJ4hFGPh7ASBV2deFdM7H/DPjulmh8rg==", "dev": true, "license": "MIT", "dependencies": { @@ -1481,9 +1194,9 @@ } }, "node_modules/@eslint/config-helpers": { - "version": "0.6.0", - "resolved": "https://registry.npmjs.org/@eslint/config-helpers/-/config-helpers-0.6.0.tgz", - "integrity": "sha512-ii6Bw9jJ2zi2cWA2Z+9/QZ/+3DX6kwaV5Q986D/CdP3Lap3w/pgQZ373FV7byY/i7L4IRH/G43I5dz1ClsCbpA==", + "version": "0.7.0", + "resolved": "https://registry.npmjs.org/@eslint/config-helpers/-/config-helpers-0.7.0.tgz", + "integrity": "sha512-DObd/KKUsU+FaFv4PLxSRenpXfQWmPXXP3pPZ6/K1PCrMu2vQpMDMuQe/BqYeoLcz8ro0bVDF1RxOJgfVEdhUw==", "dev": true, "license": "Apache-2.0", "dependencies": { @@ -1552,9 +1265,9 @@ } }, "node_modules/@exodus/bytes": { - "version": "1.15.0", - "resolved": "https://registry.npmjs.org/@exodus/bytes/-/bytes-1.15.0.tgz", - "integrity": "sha512-UY0nlA+feH81UGSHv92sLEPLCeZFjXOuHhrIo0HQydScuQc8s0A7kL/UdgwgDq8g8ilksmuoF35YVTNphV2aBQ==", + "version": "1.15.1", + "resolved": "https://registry.npmjs.org/@exodus/bytes/-/bytes-1.15.1.tgz", + "integrity": "sha512-S6mL0yNB/Abt9Ei4tq8gDhcczc4S3+vQ4ra7vxnAf+YHC02srtqxKKZghx2Dq6p0e66THKwR6r8N6P95wEty7Q==", "dev": true, "license": "MIT", "engines": { @@ -1570,31 +1283,31 @@ } }, "node_modules/@floating-ui/core": { - "version": "1.7.5", - "resolved": "https://registry.npmjs.org/@floating-ui/core/-/core-1.7.5.tgz", - "integrity": "sha512-1Ih4WTWyw0+lKyFMcBHGbb5U5FtuHJuujoyyr5zTaWS5EYMeT6Jb2AuDeftsCsEuchO+mM2ij5+q9crhydzLhQ==", + "version": "1.8.0", + "resolved": "https://registry.npmjs.org/@floating-ui/core/-/core-1.8.0.tgz", + "integrity": "sha512-0CIZ5itps/8x7BG8dEIhs53BvCUH2PCoogtakwRTut+Arm58sJooJ0AuZhLw2HJYIR5cMLNPBSS728sPho2khQ==", "license": "MIT", "dependencies": { - "@floating-ui/utils": "^0.2.11" + "@floating-ui/utils": "^0.2.12" } }, "node_modules/@floating-ui/dom": { - "version": "1.7.6", - "resolved": "https://registry.npmjs.org/@floating-ui/dom/-/dom-1.7.6.tgz", - "integrity": "sha512-9gZSAI5XM36880PPMm//9dfiEngYoC6Am2izES1FF406YFsjvyBMmeJ2g4SAju3xWwtuynNRFL2s9hgxpLI5SQ==", + "version": "1.8.0", + "resolved": "https://registry.npmjs.org/@floating-ui/dom/-/dom-1.8.0.tgz", + "integrity": "sha512-yXSrzeHZBTZadLOlfyhCkJHNeLJnHRnRInwdZ40L7ZiaAtrBwoYlsDrX3v5zB1Utk7CLfzcOVnVVWoXEky7Ceg==", "license": "MIT", "dependencies": { - "@floating-ui/core": "^1.7.5", - "@floating-ui/utils": "^0.2.11" + "@floating-ui/core": "^1.8.0", + "@floating-ui/utils": "^0.2.12" } }, "node_modules/@floating-ui/react-dom": { - "version": "2.1.8", - "resolved": "https://registry.npmjs.org/@floating-ui/react-dom/-/react-dom-2.1.8.tgz", - "integrity": "sha512-cC52bHwM/n/CxS87FH0yWdngEZrjdtLW/qVruo68qg+prK7ZQ4YGdut2GyDVpoGeAYe/h899rVeOVm6Oi40k2A==", + "version": "2.1.9", + "resolved": "https://registry.npmjs.org/@floating-ui/react-dom/-/react-dom-2.1.9.tgz", + "integrity": "sha512-JDjEFGCpImxDCA7JJKviA0M9+RtmJdj0m/NVU5IMgBK+AmZouAQQ7/+2GLH0GXXY0YMw9oXPB8hKdbPYg5QLYg==", "license": "MIT", "dependencies": { - "@floating-ui/dom": "^1.7.6" + "@floating-ui/dom": "^1.8.0" }, "peerDependencies": { "react": ">=16.8.0", @@ -1602,44 +1315,58 @@ } }, "node_modules/@floating-ui/utils": { - "version": "0.2.11", - "resolved": "https://registry.npmjs.org/@floating-ui/utils/-/utils-0.2.11.tgz", - "integrity": "sha512-RiB/yIh78pcIxl6lLMG0CgBXAZ2Y0eVHqMPYugu+9U0AeT6YBeiJpf7lbdJNIugFP5SIjwNRgo4DhR1Qxi26Gg==", + "version": "0.2.12", + "resolved": "https://registry.npmjs.org/@floating-ui/utils/-/utils-0.2.12.tgz", + "integrity": "sha512-HpCo8tmWzLVad5s2d19EhAz5zqrrQ6s69qd6moPMQvkOuSwDT1YgRfWSVuc4ennqrgv3OHppiOGMQ7oC13yIww==", "license": "MIT" }, "node_modules/@fontsource-variable/geist": { - "version": "5.2.9", - "resolved": "https://registry.npmjs.org/@fontsource-variable/geist/-/geist-5.2.9.tgz", - "integrity": "sha512-TP+QSBG3wxKGPE33CbMy/L0Nu3qvJ6Fy81Yc4LnQ95xH+i+cfEp8fyU8/kfV14YwszxIFPhnoMTbjL71waVpyQ==", + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/@fontsource-variable/geist/-/geist-5.3.0.tgz", + "integrity": "sha512-j0m+vLQuG5XAYoHtGCVu0spvlGreR3EzpECUVzkFmI1mTVnAO38l/NEPDCFgZ177JxzYJCLSmTQibIiYPilGrA==", "license": "OFL-1.1", "funding": { "url": "https://github.com/sponsors/ayuhito" } }, "node_modules/@humanfs/core": { - "version": "0.19.1", - "resolved": "https://registry.npmjs.org/@humanfs/core/-/core-0.19.1.tgz", - "integrity": "sha512-5DyQ4+1JEUzejeK1JGICcideyfUbGixgS9jNgex5nqkW+cY7WZhxBigmieN5Qnw9ZosSNVC9KQKyb+GUaGyKUA==", + "version": "0.19.2", + "resolved": "https://registry.npmjs.org/@humanfs/core/-/core-0.19.2.tgz", + "integrity": "sha512-UhXNm+CFMWcbChXywFwkmhqjs3PRCmcSa/hfBgLIb7oQ5HNb1wS0icWsGtSAUNgefHeI+eBrA8I1fxmbHsGdvA==", "dev": true, "license": "Apache-2.0", + "dependencies": { + "@humanfs/types": "^0.15.0" + }, "engines": { "node": ">=18.18.0" } }, "node_modules/@humanfs/node": { - "version": "0.16.7", - "resolved": "https://registry.npmjs.org/@humanfs/node/-/node-0.16.7.tgz", - "integrity": "sha512-/zUx+yOsIrG4Y43Eh2peDeKCxlRt/gET6aHfaKpuq267qXdYDFViVHfMaLyygZOnl0kGWxFIgsBy8QFuTLUXEQ==", + "version": "0.16.8", + "resolved": "https://registry.npmjs.org/@humanfs/node/-/node-0.16.8.tgz", + "integrity": "sha512-gE1eQNZ3R++kTzFUpdGlpmy8kDZD/MLyHqDwqjkVQI0JMdI1D51sy1H958PNXYkM2rAac7e5/CnIKZrHtPh3BQ==", "dev": true, "license": "Apache-2.0", "dependencies": { - "@humanfs/core": "^0.19.1", + "@humanfs/core": "^0.19.2", + "@humanfs/types": "^0.15.0", "@humanwhocodes/retry": "^0.4.0" }, "engines": { "node": ">=18.18.0" } }, + "node_modules/@humanfs/types": { + "version": "0.15.0", + "resolved": "https://registry.npmjs.org/@humanfs/types/-/types-0.15.0.tgz", + "integrity": "sha512-ZZ1w0aoQkwuUuC7Yf+7sdeaNfqQiiLcSRbfI08oAxqLtpXQr9AIVX7Ay7HLDuiLYAaFPu8oBYNq/QIi9URHJ3Q==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": ">=18.18.0" + } + }, "node_modules/@humanwhocodes/module-importer": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/@humanwhocodes/module-importer/-/module-importer-1.0.1.tgz", @@ -1739,9 +1466,9 @@ } }, "node_modules/@napi-rs/canvas": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/@napi-rs/canvas/-/canvas-1.0.2.tgz", - "integrity": "sha512-EYEqlMYaCbpZDz+IgDH5xp9MTd3ui4dmGqbQYryhMLnSRxrhHKq5KQWHHKxFUcEP4Hp8/BWgvqXocX4j7iSbOQ==", + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/@napi-rs/canvas/-/canvas-1.0.5.tgz", + "integrity": "sha512-GaPlicMtnvgPr5SowFRprkEJicDSrV3qCq17U4jiF5u0kNORZo3IbdN2Bk4SfcZJAMYFHbMVJ81O3w21CYxazg==", "license": "MIT", "optional": true, "workspaces": [ @@ -1755,23 +1482,23 @@ "url": "https://github.com/sponsors/Brooooooklyn" }, "optionalDependencies": { - "@napi-rs/canvas-android-arm64": "1.0.2", - "@napi-rs/canvas-darwin-arm64": "1.0.2", - "@napi-rs/canvas-darwin-x64": "1.0.2", - "@napi-rs/canvas-linux-arm-gnueabihf": "1.0.2", - "@napi-rs/canvas-linux-arm64-gnu": "1.0.2", - "@napi-rs/canvas-linux-arm64-musl": "1.0.2", - "@napi-rs/canvas-linux-riscv64-gnu": "1.0.2", - "@napi-rs/canvas-linux-x64-gnu": "1.0.2", - "@napi-rs/canvas-linux-x64-musl": "1.0.2", - "@napi-rs/canvas-win32-arm64-msvc": "1.0.2", - "@napi-rs/canvas-win32-x64-msvc": "1.0.2" + "@napi-rs/canvas-android-arm64": "1.0.5", + "@napi-rs/canvas-darwin-arm64": "1.0.5", + "@napi-rs/canvas-darwin-x64": "1.0.5", + "@napi-rs/canvas-linux-arm-gnueabihf": "1.0.5", + "@napi-rs/canvas-linux-arm64-gnu": "1.0.5", + "@napi-rs/canvas-linux-arm64-musl": "1.0.5", + "@napi-rs/canvas-linux-riscv64-gnu": "1.0.5", + "@napi-rs/canvas-linux-x64-gnu": "1.0.5", + "@napi-rs/canvas-linux-x64-musl": "1.0.5", + "@napi-rs/canvas-win32-arm64-msvc": "1.0.5", + "@napi-rs/canvas-win32-x64-msvc": "1.0.5" } }, "node_modules/@napi-rs/canvas-android-arm64": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/@napi-rs/canvas-android-arm64/-/canvas-android-arm64-1.0.2.tgz", - "integrity": "sha512-IMXKVQod0ol4vt3gmClUfXz4JAgHYESGPCUqmH3lQxBoL0K/2greJaQE1HVBVxWWFKfLc4OLZVdxg7kXVyXv+g==", + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/@napi-rs/canvas-android-arm64/-/canvas-android-arm64-1.0.5.tgz", + "integrity": "sha512-ZzDlpKQocwFfCwhMh17UWre6Qt5yZN3kNIJoUpGfRZqwDDZ164IKOsPOHsRd3d8Tuj5KM6bDjGuPmZxuPuG3NQ==", "cpu": [ "arm64" ], @@ -1789,9 +1516,9 @@ } }, "node_modules/@napi-rs/canvas-darwin-arm64": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/@napi-rs/canvas-darwin-arm64/-/canvas-darwin-arm64-1.0.2.tgz", - "integrity": "sha512-Sc8tPi6cF+5lqOzCCKFALJHhDiRwyMzTPYm3bbhdXsOunU0lQO5f05ucyOzN2r55I23Hg5bsjH63uSCvWp3EgQ==", + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/@napi-rs/canvas-darwin-arm64/-/canvas-darwin-arm64-1.0.5.tgz", + "integrity": "sha512-Hr8v6CA/TBe+OJOePdV3sXWxzQHQKfQsTKPbc8wG7iPqVeAx6MMdzKGXlYID6SVvpfwV/zqkvGcdImYWSlhrZg==", "cpu": [ "arm64" ], @@ -1809,9 +1536,9 @@ } }, "node_modules/@napi-rs/canvas-darwin-x64": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/@napi-rs/canvas-darwin-x64/-/canvas-darwin-x64-1.0.2.tgz", - "integrity": "sha512-niDXZ9LhKB1zLrUdYB64RHQFDGz9rr0eGx061qtJJU3U20EMMIx28ADF5fVYbhtOgkWQrBjFicfaye1yM0U62A==", + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/@napi-rs/canvas-darwin-x64/-/canvas-darwin-x64-1.0.5.tgz", + "integrity": "sha512-9BXlLHBXpYnK4jSae1MdFdyPq09Xi1I3PeCNpvRzqgmUUBhgJS7aC1z7SZEP8JUXDHtbfIrolCS3sFuT9IGP2A==", "cpu": [ "x64" ], @@ -1829,9 +1556,9 @@ } }, "node_modules/@napi-rs/canvas-linux-arm-gnueabihf": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/@napi-rs/canvas-linux-arm-gnueabihf/-/canvas-linux-arm-gnueabihf-1.0.2.tgz", - "integrity": "sha512-sgatQL9JxGRH/Amzcvu0P3t8Am3duou74CisfuJ41Dwt8cWy723z/9KZ8LlgmxfypEwEZxSTNFJtU8d281lmhQ==", + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/@napi-rs/canvas-linux-arm-gnueabihf/-/canvas-linux-arm-gnueabihf-1.0.5.tgz", + "integrity": "sha512-zEW4fgvtYsOJ/N56Us4TQPfaFrUf0shGr9CgGSj3GACc+NHfUM3ci0YF9xFTjwJWGDmaEhYPL6KqCfFCxwm/qg==", "cpu": [ "arm" ], @@ -1849,12 +1576,15 @@ } }, "node_modules/@napi-rs/canvas-linux-arm64-gnu": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/@napi-rs/canvas-linux-arm64-gnu/-/canvas-linux-arm64-gnu-1.0.2.tgz", - "integrity": "sha512-dgKuX0peF3xwY6ZF5QxGS4wbfDqpoFAJYXiLSp+guZKARQUKMkRqZSDrXKj7nfrec3UCMzC0PFCPte0ES98AiA==", + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/@napi-rs/canvas-linux-arm64-gnu/-/canvas-linux-arm64-gnu-1.0.5.tgz", + "integrity": "sha512-HFprwLspelJxCEtZvdMcz95Mwvfs63GzFVedLFmC/wslHnaOXhjXxgYxPCM/VdM4Jhx3CV4Lk0vVmh6hJv2etQ==", "cpu": [ "arm64" ], + "libc": [ + "glibc" + ], "license": "MIT", "optional": true, "os": [ @@ -1869,12 +1599,15 @@ } }, "node_modules/@napi-rs/canvas-linux-arm64-musl": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/@napi-rs/canvas-linux-arm64-musl/-/canvas-linux-arm64-musl-1.0.2.tgz", - "integrity": "sha512-qwROoDIC9upfvDoRLuPn2aNg9CGW1x0Ygr4k2Or+8paA9d0qBLwk87U+g8KQpoOviKoPoiwl97kvBYuYD7qZoA==", + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/@napi-rs/canvas-linux-arm64-musl/-/canvas-linux-arm64-musl-1.0.5.tgz", + "integrity": "sha512-FNMGFAx8DvtDwlLfWyBJ+oQjgPXoIAqCnNTJYqtJCFRwwzK3AyAe5B1Ll3NZ6hcOzqw7HylZsq4nQxVyPCQX1Q==", "cpu": [ "arm64" ], + "libc": [ + "musl" + ], "license": "MIT", "optional": true, "os": [ @@ -1889,12 +1622,15 @@ } }, "node_modules/@napi-rs/canvas-linux-riscv64-gnu": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/@napi-rs/canvas-linux-riscv64-gnu/-/canvas-linux-riscv64-gnu-1.0.2.tgz", - "integrity": "sha512-fXRjnPihdnbO6qy1QQOgxAonb68A0TCEG7rj1x7v7rxNElsE8EVIKIEUTvyDtU+sthYSbX+8e7g3oZiLGnOmxw==", + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/@napi-rs/canvas-linux-riscv64-gnu/-/canvas-linux-riscv64-gnu-1.0.5.tgz", + "integrity": "sha512-2vd5v8Lui+37Hh/spITKIvTT384ip4dnUc5XBn0E+sMNS4b7au7IswyT5YDG2udPTjSh/eLUs3sGuB5YHooFOA==", "cpu": [ "riscv64" ], + "libc": [ + "glibc" + ], "license": "MIT", "optional": true, "os": [ @@ -1909,12 +1645,15 @@ } }, "node_modules/@napi-rs/canvas-linux-x64-gnu": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/@napi-rs/canvas-linux-x64-gnu/-/canvas-linux-x64-gnu-1.0.2.tgz", - "integrity": "sha512-nPR97DXhbWIAy7yazF3jc06kEPMqYMLmPzFOVNlwKPfIoSChnI+x7dc0hTLaihz3jxrjL6j4BbA7earxfx4X3g==", + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/@napi-rs/canvas-linux-x64-gnu/-/canvas-linux-x64-gnu-1.0.5.tgz", + "integrity": "sha512-iQIPy+Uey0expZTOszLri5n8rY7x4WUpMaY82mcXNIgbil30iHvc01OsiizhZC1KQHTK90RFMFWSpwFU+ON3aA==", "cpu": [ "x64" ], + "libc": [ + "glibc" + ], "license": "MIT", "optional": true, "os": [ @@ -1929,12 +1668,15 @@ } }, "node_modules/@napi-rs/canvas-linux-x64-musl": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/@napi-rs/canvas-linux-x64-musl/-/canvas-linux-x64-musl-1.0.2.tgz", - "integrity": "sha512-l7zZY5+jL5qnBZtDz7CoBtY6p7EkHu422g/0zWwrOrzIwWyWxZFRfZZORY1UG7YApymPLx+UbOkN206xXn/c1Q==", + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/@napi-rs/canvas-linux-x64-musl/-/canvas-linux-x64-musl-1.0.5.tgz", + "integrity": "sha512-Npthji25t7FUqIAKsoEkFS0qY5CYVkHjvI3tuZjDTG92wX8g4dst+Lfb4hhubdqPazlDcIwalPzInsFCtf3FFg==", "cpu": [ "x64" ], + "libc": [ + "musl" + ], "license": "MIT", "optional": true, "os": [ @@ -1949,9 +1691,9 @@ } }, "node_modules/@napi-rs/canvas-win32-arm64-msvc": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/@napi-rs/canvas-win32-arm64-msvc/-/canvas-win32-arm64-msvc-1.0.2.tgz", - "integrity": "sha512-yE0koHCFF4PIbMc2o2SEALhnipz7WBISh5glLvQiomtIoCcW0np3H4Lw93ceJAfJttTTeIIWFbwH84F7EVzjMQ==", + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/@napi-rs/canvas-win32-arm64-msvc/-/canvas-win32-arm64-msvc-1.0.5.tgz", + "integrity": "sha512-bi+JsdCdbfVJDoAQybTYmkLKwh1xpYpptg5j/BNr2BB56u4/R26jrVvtjqff+CxYMXV6Kz1/jeDVhZCuj6bDng==", "cpu": [ "arm64" ], @@ -1969,9 +1711,9 @@ } }, "node_modules/@napi-rs/canvas-win32-x64-msvc": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/@napi-rs/canvas-win32-x64-msvc/-/canvas-win32-x64-msvc-1.0.2.tgz", - "integrity": "sha512-okU8/t2foV6C31n0GtvEMbfD5rOFc70+/6xUNME9Guld29sgSOIGUEDScAWFlcP3k5TYQRl9TNkwJEEjh15w8A==", + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/@napi-rs/canvas-win32-x64-msvc/-/canvas-win32-x64-msvc-1.0.5.tgz", + "integrity": "sha512-KQQwG9/sBmcGxqaLFIQf+k2OefREGoyEaIBmRuTM8bUuFKOEE9Xk5pel90hE6pmBwk/vo4RB0OdX+FxobJGMFw==", "cpu": [ "x64" ], @@ -1989,22 +1731,25 @@ } }, "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.2", + "resolved": "https://registry.npmjs.org/@napi-rs/wasm-runtime/-/wasm-runtime-1.2.2.tgz", + "integrity": "sha512-JfB4kuJQjaoHuCTseIINHtHWeJnvgEcxjwA5t/Y00ZgaOO1Crz3fjT/p8kT28zA/Caz7oiUMn3d6H2yOVCVwuw==", "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.3", + "@emnapi/runtime": "^1.7.1 || ^2.0.0-alpha.3" } }, "node_modules/@oxc-parser/binding-android-arm-eabi": { @@ -2134,6 +1879,9 @@ "arm64" ], "dev": true, + "libc": [ + "glibc" + ], "license": "MIT", "optional": true, "os": [ @@ -2151,6 +1899,9 @@ "arm64" ], "dev": true, + "libc": [ + "musl" + ], "license": "MIT", "optional": true, "os": [ @@ -2168,6 +1919,9 @@ "ppc64" ], "dev": true, + "libc": [ + "glibc" + ], "license": "MIT", "optional": true, "os": [ @@ -2185,6 +1939,9 @@ "riscv64" ], "dev": true, + "libc": [ + "glibc" + ], "license": "MIT", "optional": true, "os": [ @@ -2202,6 +1959,9 @@ "riscv64" ], "dev": true, + "libc": [ + "musl" + ], "license": "MIT", "optional": true, "os": [ @@ -2219,6 +1979,9 @@ "s390x" ], "dev": true, + "libc": [ + "glibc" + ], "license": "MIT", "optional": true, "os": [ @@ -2236,6 +1999,9 @@ "x64" ], "dev": true, + "libc": [ + "glibc" + ], "license": "MIT", "optional": true, "os": [ @@ -2253,6 +2019,9 @@ "x64" ], "dev": true, + "libc": [ + "musl" + ], "license": "MIT", "optional": true, "os": [ @@ -2298,29 +2067,6 @@ "node": "^20.19.0 || >=22.12.0" } }, - "node_modules/@oxc-parser/binding-wasm32-wasi/node_modules/@emnapi/core": { - "version": "1.9.2", - "resolved": "https://registry.npmjs.org/@emnapi/core/-/core-1.9.2.tgz", - "integrity": "sha512-UC+ZhH3XtczQYfOlu3lNEkdW/p4dsJ1r/bP7H8+rhao3TTTMO1ATq/4DdIi23XuGoFY+Cz0JmCbdVl0hz9jZcA==", - "dev": true, - "license": "MIT", - "optional": true, - "dependencies": { - "@emnapi/wasi-threads": "1.2.1", - "tslib": "^2.4.0" - } - }, - "node_modules/@oxc-parser/binding-wasm32-wasi/node_modules/@emnapi/runtime": { - "version": "1.9.2", - "resolved": "https://registry.npmjs.org/@emnapi/runtime/-/runtime-1.9.2.tgz", - "integrity": "sha512-3U4+MIWHImeyu1wnmVygh5WlgfYDtyf0k8AbLhMFxOipihf6nrWC4syIm/SwEeec0mNSafiiNnMJwbza/Is6Lw==", - "dev": true, - "license": "MIT", - "optional": true, - "dependencies": { - "tslib": "^2.4.0" - } - }, "node_modules/@oxc-parser/binding-win32-arm64-msvc": { "version": "0.127.0", "resolved": "https://registry.npmjs.org/@oxc-parser/binding-win32-arm64-msvc/-/binding-win32-arm64-msvc-0.127.0.tgz", @@ -2373,9 +2119,9 @@ } }, "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.127.0", + "resolved": "https://registry.npmjs.org/@oxc-project/types/-/types-0.127.0.tgz", + "integrity": "sha512-aIYXQBo4lCbO4z0R3FHeucQHpF46l2LbMdxRvqvuRuW2OxdnSkcng5B8+K12spgLDj93rtN3+J2Vac/TIO+ciQ==", "dev": true, "license": "MIT", "funding": { @@ -2383,9 +2129,9 @@ } }, "node_modules/@oxc-resolver/binding-android-arm-eabi": { - "version": "11.23.0", - "resolved": "https://registry.npmjs.org/@oxc-resolver/binding-android-arm-eabi/-/binding-android-arm-eabi-11.23.0.tgz", - "integrity": "sha512-8IJyWRLVAyhTfe9/TIEbQqSQnl5rUqYJrUOS6Dkr+Mq9FGHMxDGeiEmwkBqCvDP5KckpPh/GYSgbag66O6JsCw==", + "version": "11.24.2", + "resolved": "https://registry.npmjs.org/@oxc-resolver/binding-android-arm-eabi/-/binding-android-arm-eabi-11.24.2.tgz", + "integrity": "sha512-y09e0L0SRI2OA2tUIrjBgoV3eH5hvUKXNkJqXmNo5V2WxIjyC7I7aJfRLMEVpA8yi95f90gFDvO0VMgrDw+vwA==", "cpu": [ "arm" ], @@ -2397,9 +2143,9 @@ ] }, "node_modules/@oxc-resolver/binding-android-arm64": { - "version": "11.23.0", - "resolved": "https://registry.npmjs.org/@oxc-resolver/binding-android-arm64/-/binding-android-arm64-11.23.0.tgz", - "integrity": "sha512-pprVojnNhHxupwTT2gdeUlkxll6XEvWWBk3oVicOSNVWQC99OBnDhMQDoirqnzrE1bScQSMS2JgPpqdlrhz/Fg==", + "version": "11.24.2", + "resolved": "https://registry.npmjs.org/@oxc-resolver/binding-android-arm64/-/binding-android-arm64-11.24.2.tgz", + "integrity": "sha512-cl4icWaZFnLdg8m6qtnh5rBMuGbxc/ptStFHLeCNwr+2cZjkjNwQu/jYRS0CHlnPecOJMpuS5M6/BH+0J/YkEg==", "cpu": [ "arm64" ], @@ -2411,9 +2157,9 @@ ] }, "node_modules/@oxc-resolver/binding-darwin-arm64": { - "version": "11.23.0", - "resolved": "https://registry.npmjs.org/@oxc-resolver/binding-darwin-arm64/-/binding-darwin-arm64-11.23.0.tgz", - "integrity": "sha512-mbIrWIMAJeytyee36OyUP5XH92TP7FaKaQ2m5AjokKy7STgjrhRt7SMXqpqLjhGm6Xn721Xmsg6H3Rtd9YQETw==", + "version": "11.24.2", + "resolved": "https://registry.npmjs.org/@oxc-resolver/binding-darwin-arm64/-/binding-darwin-arm64-11.24.2.tgz", + "integrity": "sha512-At29QEMF6HajbQvgY8K6OXnHD1x9rad74xBEfmCB6ZqCGsdq75aK7tOYcTbOanMy8qdIBrfL3SMr3p/lfSlb9w==", "cpu": [ "arm64" ], @@ -2425,9 +2171,9 @@ ] }, "node_modules/@oxc-resolver/binding-darwin-x64": { - "version": "11.23.0", - "resolved": "https://registry.npmjs.org/@oxc-resolver/binding-darwin-x64/-/binding-darwin-x64-11.23.0.tgz", - "integrity": "sha512-UnIphmZ1LazUCr9DXWaKYWtKDefPMbgLsywaoYxRqVCNHhq4MM6d2q1Nz1i9Vzxt5i+cE2nRUYpAUHr/lijNYA==", + "version": "11.24.2", + "resolved": "https://registry.npmjs.org/@oxc-resolver/binding-darwin-x64/-/binding-darwin-x64-11.24.2.tgz", + "integrity": "sha512-A5Kqr1EUj4oIL5CF4WRssq/o5P0Y11cwoFouMRmQ7YnC/A8V93nv1nb7aSU8HwcgmXropjLNkVTl4MN87cu28Q==", "cpu": [ "x64" ], @@ -2439,9 +2185,9 @@ ] }, "node_modules/@oxc-resolver/binding-freebsd-x64": { - "version": "11.23.0", - "resolved": "https://registry.npmjs.org/@oxc-resolver/binding-freebsd-x64/-/binding-freebsd-x64-11.23.0.tgz", - "integrity": "sha512-aaZ/cSEYFkSxgS2hOrobT6RQcsWNviOX8dW6CEkVx2/UYkAf9MeHbjl3W0usWV53rVV//ndBdn2nb1y7jsu4lw==", + "version": "11.24.2", + "resolved": "https://registry.npmjs.org/@oxc-resolver/binding-freebsd-x64/-/binding-freebsd-x64-11.24.2.tgz", + "integrity": "sha512-R5xkRBRRz7ceH/P5Jrc6G7FmdUdgpLYyESFAUDVTNQ9K0sGPxcp4ljiwEwEqsvNcQ4sYbMRrWcHHBCu7ksAJVw==", "cpu": [ "x64" ], @@ -2453,9 +2199,9 @@ ] }, "node_modules/@oxc-resolver/binding-linux-arm-gnueabihf": { - "version": "11.23.0", - "resolved": "https://registry.npmjs.org/@oxc-resolver/binding-linux-arm-gnueabihf/-/binding-linux-arm-gnueabihf-11.23.0.tgz", - "integrity": "sha512-IoJLvO5SjLSVMaq83BNTrPCb1FppvoJc1IhZ5CoUVl3PykUBku7D+LK1j0GSurhJcIc6zfjghsvaZNpq5ev6Mg==", + "version": "11.24.2", + "resolved": "https://registry.npmjs.org/@oxc-resolver/binding-linux-arm-gnueabihf/-/binding-linux-arm-gnueabihf-11.24.2.tgz", + "integrity": "sha512-k/RuYL4L/R58IBn3wT5ma3Wh4k62bp1eYCFRWCmMsasUOqL+H6sW0VGFadEzKWXFFlz+2uIMoeMk9ySSZJHgbg==", "cpu": [ "arm" ], @@ -2467,9 +2213,9 @@ ] }, "node_modules/@oxc-resolver/binding-linux-arm-musleabihf": { - "version": "11.23.0", - "resolved": "https://registry.npmjs.org/@oxc-resolver/binding-linux-arm-musleabihf/-/binding-linux-arm-musleabihf-11.23.0.tgz", - "integrity": "sha512-vskFpwg44T/LFsfjSCnVZ5ygcuqzPC1yUzVEiKa8BgHAQz0+QLQQW3EGWLPVi8EXFghzjR4EtgPBtOhCjU4jdw==", + "version": "11.24.2", + "resolved": "https://registry.npmjs.org/@oxc-resolver/binding-linux-arm-musleabihf/-/binding-linux-arm-musleabihf-11.24.2.tgz", + "integrity": "sha512-bnHAak3ujYfH5pKk4NieFNbvYvernfoQDgwLddbZ3OtMYrem87/qjlA+u+aKG0oZcqSLGCful/6/CEA+aeAgaA==", "cpu": [ "arm" ], @@ -2481,13 +2227,16 @@ ] }, "node_modules/@oxc-resolver/binding-linux-arm64-gnu": { - "version": "11.23.0", - "resolved": "https://registry.npmjs.org/@oxc-resolver/binding-linux-arm64-gnu/-/binding-linux-arm64-gnu-11.23.0.tgz", - "integrity": "sha512-//TcHVhrChyw5RYtgts6WO7KcWq9387c1Z5Zvhqpk/ktAbyaRYgBZrpSY1GDCFq50ASt6B6jhh+JxB1rB45IAg==", + "version": "11.24.2", + "resolved": "https://registry.npmjs.org/@oxc-resolver/binding-linux-arm64-gnu/-/binding-linux-arm64-gnu-11.24.2.tgz", + "integrity": "sha512-vDT3KHgzYp47gmtNOqL2VNhCyl5Zv643eyxm//A68J8DeUGXrvD1pZFiaT4jSfe+RInfnn1R2yVHye4enx6RnA==", "cpu": [ "arm64" ], "dev": true, + "libc": [ + "glibc" + ], "license": "MIT", "optional": true, "os": [ @@ -2495,13 +2244,16 @@ ] }, "node_modules/@oxc-resolver/binding-linux-arm64-musl": { - "version": "11.23.0", - "resolved": "https://registry.npmjs.org/@oxc-resolver/binding-linux-arm64-musl/-/binding-linux-arm64-musl-11.23.0.tgz", - "integrity": "sha512-ZFqlwiTf7CXLLSGyAR9tYiO33LiaeIEXW+xm42d8mnUGpDgPltyrCGYtQezyMMEXvjhOgCz1X+i7sbDTJEx+bg==", + "version": "11.24.2", + "resolved": "https://registry.npmjs.org/@oxc-resolver/binding-linux-arm64-musl/-/binding-linux-arm64-musl-11.24.2.tgz", + "integrity": "sha512-+kMlQvbzfyEYtu5FcjE4p+ttBLpKW4d/AsAsuE69BxV6V4twZJeIQZFfD8gh/wqglY0MkPSezWXQH0jBV13MUw==", "cpu": [ "arm64" ], "dev": true, + "libc": [ + "musl" + ], "license": "MIT", "optional": true, "os": [ @@ -2509,13 +2261,16 @@ ] }, "node_modules/@oxc-resolver/binding-linux-ppc64-gnu": { - "version": "11.23.0", - "resolved": "https://registry.npmjs.org/@oxc-resolver/binding-linux-ppc64-gnu/-/binding-linux-ppc64-gnu-11.23.0.tgz", - "integrity": "sha512-oZ5LeN5+H1R19dRjTAxKrxQguH+AsemHcnthEfFxf4OjmBSty2doHLeSmMunKy3zpTHJQ3lh3Af+dNS+W6dYeA==", + "version": "11.24.2", + "resolved": "https://registry.npmjs.org/@oxc-resolver/binding-linux-ppc64-gnu/-/binding-linux-ppc64-gnu-11.24.2.tgz", + "integrity": "sha512-shjfMhmZ3gq9fv/w7bi3PnZlgOPG+2QAOFf0BJF0EgBSIGZ6PMLN2zbGEblTUYB/NKVDRyYhE2ff3dJ1QqNPkA==", "cpu": [ "ppc64" ], "dev": true, + "libc": [ + "glibc" + ], "license": "MIT", "optional": true, "os": [ @@ -2523,13 +2278,16 @@ ] }, "node_modules/@oxc-resolver/binding-linux-riscv64-gnu": { - "version": "11.23.0", - "resolved": "https://registry.npmjs.org/@oxc-resolver/binding-linux-riscv64-gnu/-/binding-linux-riscv64-gnu-11.23.0.tgz", - "integrity": "sha512-O4ciFDyX5ebQd0qkb1bjAIg8IEfiLT03GbSeylwlwlUMK9KwBWaALwrxSbc0Msaz4U6iPj+T9eRXpD5mxBfmvA==", + "version": "11.24.2", + "resolved": "https://registry.npmjs.org/@oxc-resolver/binding-linux-riscv64-gnu/-/binding-linux-riscv64-gnu-11.24.2.tgz", + "integrity": "sha512-zGelwFR5oRo+b69k8Lrzun86DyUHzfKN6cnjbR9l7Z7NIRznOE/2ZvPa1IUKqAL2PzAXOdwkfVqNvO1H2RlpAw==", "cpu": [ "riscv64" ], "dev": true, + "libc": [ + "glibc" + ], "license": "MIT", "optional": true, "os": [ @@ -2537,13 +2295,16 @@ ] }, "node_modules/@oxc-resolver/binding-linux-riscv64-musl": { - "version": "11.23.0", - "resolved": "https://registry.npmjs.org/@oxc-resolver/binding-linux-riscv64-musl/-/binding-linux-riscv64-musl-11.23.0.tgz", - "integrity": "sha512-P3o8Y9kISYjcxadmbO+94ThRwLhwGuDAbA7dcdd4+YLpfeF+mmobz8fXf4NmSdfSqjyRSkceJDBRZha9NVYkiQ==", + "version": "11.24.2", + "resolved": "https://registry.npmjs.org/@oxc-resolver/binding-linux-riscv64-musl/-/binding-linux-riscv64-musl-11.24.2.tgz", + "integrity": "sha512-qxZ1SWCXJY0eyhAlP6Lmo9F2Nrtx7EkYj9oCgL8apDPCwXwCEDA2U697bbT81JIc2IrVjxO4KX6WU2N+oN9Z4w==", "cpu": [ "riscv64" ], "dev": true, + "libc": [ + "musl" + ], "license": "MIT", "optional": true, "os": [ @@ -2551,13 +2312,16 @@ ] }, "node_modules/@oxc-resolver/binding-linux-s390x-gnu": { - "version": "11.23.0", - "resolved": "https://registry.npmjs.org/@oxc-resolver/binding-linux-s390x-gnu/-/binding-linux-s390x-gnu-11.23.0.tgz", - "integrity": "sha512-oj03m1E3RmTFczKhcKJDzHaEDKJnPIsDcQFVxBJsSdXGSuIPdt5TvcM332FfMQgzI6yDJqyl4InrnFfXrmUTKQ==", + "version": "11.24.2", + "resolved": "https://registry.npmjs.org/@oxc-resolver/binding-linux-s390x-gnu/-/binding-linux-s390x-gnu-11.24.2.tgz", + "integrity": "sha512-sGCecF3cx2DFlH4t/z7ApnOnXqN48p5p5mlHDEnHTAukQa2P+qMVE4CwyWE9W+q/m3QJ7kKfGrIjax31f44oFQ==", "cpu": [ "s390x" ], "dev": true, + "libc": [ + "glibc" + ], "license": "MIT", "optional": true, "os": [ @@ -2565,13 +2329,16 @@ ] }, "node_modules/@oxc-resolver/binding-linux-x64-gnu": { - "version": "11.23.0", - "resolved": "https://registry.npmjs.org/@oxc-resolver/binding-linux-x64-gnu/-/binding-linux-x64-gnu-11.23.0.tgz", - "integrity": "sha512-BqJxbSC8FdP7mSuSpRePTGHm0hXWV+dfz//f7SjsteZncLaBgWTBmi/OZNv7sX6CyG/Pt/eJkPorP+DkMOhMwQ==", + "version": "11.24.2", + "resolved": "https://registry.npmjs.org/@oxc-resolver/binding-linux-x64-gnu/-/binding-linux-x64-gnu-11.24.2.tgz", + "integrity": "sha512-k/VlMMcSzMlahb3/fENM4rTlsJ0s3fFROA0KXPBmKggqmTSaE383sl8F3KCOXPLmVsYfW6hCitMhXCEtNeZxxg==", "cpu": [ "x64" ], "dev": true, + "libc": [ + "glibc" + ], "license": "MIT", "optional": true, "os": [ @@ -2579,13 +2346,16 @@ ] }, "node_modules/@oxc-resolver/binding-linux-x64-musl": { - "version": "11.23.0", - "resolved": "https://registry.npmjs.org/@oxc-resolver/binding-linux-x64-musl/-/binding-linux-x64-musl-11.23.0.tgz", - "integrity": "sha512-utmw+VmUrW4K8LI5/6jhg4aGYKJHOIjQ9syYOOA6pF3w7haKu4r4enTe2U0C04/HbUvkq/Zif43xFsKW1Pnq9w==", + "version": "11.24.2", + "resolved": "https://registry.npmjs.org/@oxc-resolver/binding-linux-x64-musl/-/binding-linux-x64-musl-11.24.2.tgz", + "integrity": "sha512-8hbnZyNi97b/8wapYaIF9+t9GmZKBW2vunaOc3h9HGJptH7b7XpvZqOTBSm/MpTjr7H497BlgOaSfLUdhmy2bw==", "cpu": [ "x64" ], "dev": true, + "libc": [ + "musl" + ], "license": "MIT", "optional": true, "os": [ @@ -2593,9 +2363,9 @@ ] }, "node_modules/@oxc-resolver/binding-openharmony-arm64": { - "version": "11.23.0", - "resolved": "https://registry.npmjs.org/@oxc-resolver/binding-openharmony-arm64/-/binding-openharmony-arm64-11.23.0.tgz", - "integrity": "sha512-V6lbRrthHa4TbvsLjPtg+EkXT1tRY+s4I8rYLXUfiHlZzGx3sLv1EH9CEOOevjvUYHLsbe/gqCIc73XnQfPb9A==", + "version": "11.24.2", + "resolved": "https://registry.npmjs.org/@oxc-resolver/binding-openharmony-arm64/-/binding-openharmony-arm64-11.24.2.tgz", + "integrity": "sha512-MvyGik3a6pVgZ0t/kWlbmFxFLmXQJwgLsY2eYFHLpy0wGwRbfzeIGgDwQ3kXqE30z+kSXennRkCrT7TUvkptNg==", "cpu": [ "arm64" ], @@ -2607,9 +2377,9 @@ ] }, "node_modules/@oxc-resolver/binding-wasm32-wasi": { - "version": "11.23.0", - "resolved": "https://registry.npmjs.org/@oxc-resolver/binding-wasm32-wasi/-/binding-wasm32-wasi-11.23.0.tgz", - "integrity": "sha512-gRoOxQPdnAmIAjxcuQNBxfihvx+wjTaQM/9/eP12xwnGNawOG/+Zz9RHN4WNSxT45b5CrscK4NB8aPh+oZQXAQ==", + "version": "11.24.2", + "resolved": "https://registry.npmjs.org/@oxc-resolver/binding-wasm32-wasi/-/binding-wasm32-wasi-11.24.2.tgz", + "integrity": "sha512-vHcssMPwO08RTvj/c0iOBz90attxyG3wQJ0dTcyEQK43LRpcdLWZlV5feBhv6Isn6ahbQIzHbCgfa81+RiML0Q==", "cpu": [ "wasm32" ], @@ -2617,18 +2387,52 @@ "license": "MIT", "optional": true, "dependencies": { - "@emnapi/core": "1.11.1", - "@emnapi/runtime": "1.11.1", + "@emnapi/core": "1.11.2", + "@emnapi/runtime": "1.11.2", "@napi-rs/wasm-runtime": "^1.1.6" }, "engines": { "node": ">=14.0.0" } }, + "node_modules/@oxc-resolver/binding-wasm32-wasi/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==", + "dev": true, + "license": "MIT", + "optional": true, + "dependencies": { + "@emnapi/wasi-threads": "1.2.2", + "tslib": "^2.4.0" + } + }, + "node_modules/@oxc-resolver/binding-wasm32-wasi/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==", + "dev": true, + "license": "MIT", + "optional": true, + "dependencies": { + "tslib": "^2.4.0" + } + }, + "node_modules/@oxc-resolver/binding-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/@oxc-resolver/binding-win32-arm64-msvc": { - "version": "11.23.0", - "resolved": "https://registry.npmjs.org/@oxc-resolver/binding-win32-arm64-msvc/-/binding-win32-arm64-msvc-11.23.0.tgz", - "integrity": "sha512-CgTGMYsJVe1eUiCdJTpGw21svXw79ITsemN1h0hcNkiswasDbN5MoibSLY+gRMWP5syfEz5iffrjZnwEP8xeUA==", + "version": "11.24.2", + "resolved": "https://registry.npmjs.org/@oxc-resolver/binding-win32-arm64-msvc/-/binding-win32-arm64-msvc-11.24.2.tgz", + "integrity": "sha512-uokJqro2iBqkFvJdKQLP7d8/BUmFwESQFVmIJUQKj1Xn1a/LysJoe1vmeECLF5b3jsV8CAL5sEMJXX6SdK9Nhg==", "cpu": [ "arm64" ], @@ -2640,9 +2444,9 @@ ] }, "node_modules/@oxc-resolver/binding-win32-x64-msvc": { - "version": "11.23.0", - "resolved": "https://registry.npmjs.org/@oxc-resolver/binding-win32-x64-msvc/-/binding-win32-x64-msvc-11.23.0.tgz", - "integrity": "sha512-gUGJpr+Rn6zMxm5juApV0K3U845i8t47o8k+rbO0BHbi4PoJIfSPeQmrE2dgohQm2g5k6iviNFyXCGqvmaYUpw==", + "version": "11.24.2", + "resolved": "https://registry.npmjs.org/@oxc-resolver/binding-win32-x64-msvc/-/binding-win32-x64-msvc-11.24.2.tgz", + "integrity": "sha512-UqGPmo56KDfLlfXFAFIrNflHT8tFxWGEivWg3Zeyp4Uy2NlKN1FGPr6/BxcLGG3+kZ6Wp14g5Uj+n71boqZfiw==", "cpu": [ "x64" ], @@ -2654,9 +2458,9 @@ ] }, "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.3", + "resolved": "https://registry.npmjs.org/@rolldown/binding-android-arm64/-/binding-android-arm64-1.2.3.tgz", + "integrity": "sha512-zrJtHDcaZJ1Fp7xf4hNl+7seH9Cn/N5TwLYkhgXREtBwAd/jaqW3uqeHxpDugJLVICWg4eW44kOQEGJ1r6jCGw==", "cpu": [ "arm64" ], @@ -2671,9 +2475,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.3", + "resolved": "https://registry.npmjs.org/@rolldown/binding-darwin-arm64/-/binding-darwin-arm64-1.2.3.tgz", + "integrity": "sha512-ieIiibVCp0tX7TLu2cafoNPv8wJyYi01ekXpbf8q2j7F4rGAhhXb/eQh7ge9DRBY78GwmRQtvjZDux7EDbA8kA==", "cpu": [ "arm64" ], @@ -2688,9 +2492,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.3", + "resolved": "https://registry.npmjs.org/@rolldown/binding-darwin-x64/-/binding-darwin-x64-1.2.3.tgz", + "integrity": "sha512-Zh9tCon19eDXJoihx0rqKhMUlMYqzwj3aPsSuHmI4RWZh62dWUL+DJN4C5YQya5TcQBJU/Fe8+rY0jhXTQITqA==", "cpu": [ "x64" ], @@ -2705,9 +2509,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.3", + "resolved": "https://registry.npmjs.org/@rolldown/binding-freebsd-x64/-/binding-freebsd-x64-1.2.3.tgz", + "integrity": "sha512-nGbJWewA1wrXXZiQhjAT5rhibGfns5ZNkDVqxsO6zJ3f3YvpoDNNmGMSbbhLuXKjNScaBJVOAboztAWVespQMg==", "cpu": [ "x64" ], @@ -2722,9 +2526,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.3", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-arm-gnueabihf/-/binding-linux-arm-gnueabihf-1.2.3.tgz", + "integrity": "sha512-QNniJr5Kml0kDEB98jiDOJjXNroxIIi0IXIbdYzY26Xt1pVbeP62+KnoIZLwirOymX/0jDk/2gI/bNUv7A7OIw==", "cpu": [ "arm" ], @@ -2739,13 +2543,16 @@ } }, "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.3", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-arm64-gnu/-/binding-linux-arm64-gnu-1.2.3.tgz", + "integrity": "sha512-TkqEAcmmvH3I/q4114NB4RVt6241Dao48pF45uLcFGrwAaIn0iITgTAKP/dLjbN0R4buJjGb91+UHSoFmpgIWw==", "cpu": [ "arm64" ], "dev": true, + "libc": [ + "glibc" + ], "license": "MIT", "optional": true, "os": [ @@ -2756,13 +2563,16 @@ } }, "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.3", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-arm64-musl/-/binding-linux-arm64-musl-1.2.3.tgz", + "integrity": "sha512-NHqjnxpsndf4MPymxteFAWHHfkTL8HjWh1KB7z23ofZ6QO2euONuxDXjat69dKZRALnGypg8k8SsK8vZJoXv1Q==", "cpu": [ "arm64" ], "dev": true, + "libc": [ + "musl" + ], "license": "MIT", "optional": true, "os": [ @@ -2773,13 +2583,16 @@ } }, "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.3", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-ppc64-gnu/-/binding-linux-ppc64-gnu-1.2.3.tgz", + "integrity": "sha512-6tbrbwfz5GB9DQ4Jwo6hy9v+vR31xZlvzZ6n5Xut6Hhx5PvrA9q/HsK8KMaYQp063iqZGXwNvZtYNLD7EM/x0w==", "cpu": [ "ppc64" ], "dev": true, + "libc": [ + "glibc" + ], "license": "MIT", "optional": true, "os": [ @@ -2790,13 +2603,16 @@ } }, "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.3", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-s390x-gnu/-/binding-linux-s390x-gnu-1.2.3.tgz", + "integrity": "sha512-oyuXxXmoZHjXC917IAPFAAv4wWAa0cM9afk8nx1+9/jNNOX1uPf8yDA6p7G0RypOfw/X0PQt5IfoquY1um+zSg==", "cpu": [ "s390x" ], "dev": true, + "libc": [ + "glibc" + ], "license": "MIT", "optional": true, "os": [ @@ -2807,13 +2623,16 @@ } }, "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.3", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-x64-gnu/-/binding-linux-x64-gnu-1.2.3.tgz", + "integrity": "sha512-TytMwF2KVGqP2tgd0I1OY0PAv78dZRAYcF5ssDzjM34SUXCED3uXvSd5+lHoC0bTD6eEdFz7LdQNCO1y0oVk9w==", "cpu": [ "x64" ], "dev": true, + "libc": [ + "glibc" + ], "license": "MIT", "optional": true, "os": [ @@ -2824,13 +2643,16 @@ } }, "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.3", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-x64-musl/-/binding-linux-x64-musl-1.2.3.tgz", + "integrity": "sha512-/E9m3qstrJFVPoULV25mVQblSNExY2+kBsYe4sy0Tn0yOOgJ8wZbZt3KnRbF/XeU2Gl1STKUQnDNTqhIE5MD4A==", "cpu": [ "x64" ], "dev": true, + "libc": [ + "musl" + ], "license": "MIT", "optional": true, "os": [ @@ -2841,9 +2663,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.3", + "resolved": "https://registry.npmjs.org/@rolldown/binding-openharmony-arm64/-/binding-openharmony-arm64-1.2.3.tgz", + "integrity": "sha512-Kr0OcsoQI816i6HOl3vFHpd1K0eZyh76zgfj4c1nTyaTsd5r2Mj1lwM4R90y/qaCfmTn9eHy0SKwi98eitRxug==", "cpu": [ "arm64" ], @@ -2857,29 +2679,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-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.3", + "resolved": "https://registry.npmjs.org/@rolldown/binding-win32-arm64-msvc/-/binding-win32-arm64-msvc-1.2.3.tgz", + "integrity": "sha512-hOtMwTqnME+/gJcH/PCZ0wn0zPUjiWOgkHpxbSJpfGKMezHltx1S7/k1SitzVa7Ww2cqrDDaFbZEhcJZO8o+Jw==", "cpu": [ "arm64" ], @@ -2894,9 +2697,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.3", + "resolved": "https://registry.npmjs.org/@rolldown/binding-win32-x64-msvc/-/binding-win32-x64-msvc-1.2.3.tgz", + "integrity": "sha512-ekcqMMkI2PlhYnfzQnB/cEdYUVVJViWvoUyLrbzgDoi3Snfc1mVBwdnc306ufA5ejy8JSPjT2RlW1nQSjW7efg==", "cpu": [ "x64" ], @@ -2940,13 +2743,6 @@ } } }, - "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/@sindresorhus/base62": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/@sindresorhus/base62/-/base62-1.0.0.tgz", @@ -2968,13 +2764,13 @@ "license": "MIT" }, "node_modules/@storybook/builder-vite": { - "version": "10.4.6", - "resolved": "https://registry.npmjs.org/@storybook/builder-vite/-/builder-vite-10.4.6.tgz", - "integrity": "sha512-BHBtD81HiXUiDQz/CaFynLtWmm7AFUQn8VnXuHipZ8KlnUANopa4yqdVuy/Gwz8ub254uFI5NMZsW/KlgWNgNg==", + "version": "10.5.7", + "resolved": "https://registry.npmjs.org/@storybook/builder-vite/-/builder-vite-10.5.7.tgz", + "integrity": "sha512-fShF/aQaITqcJuMCLr42BGNUAbhDi4IboqvlbZqXAwgrrTslnZEUnY8GcEcvpZmjl11VwlmazhMJdH50fIgBPg==", "dev": true, "license": "MIT", "dependencies": { - "@storybook/csf-plugin": "10.4.6", + "@storybook/csf-plugin": "10.5.7", "ts-dedent": "^2.0.0" }, "funding": { @@ -2982,14 +2778,14 @@ "url": "https://opencollective.com/storybook" }, "peerDependencies": { - "storybook": "^10.4.6", + "storybook": "^10.5.7", "vite": "^5.0.0 || ^6.0.0 || ^7.0.0 || ^8.0.0" } }, "node_modules/@storybook/csf-plugin": { - "version": "10.4.6", - "resolved": "https://registry.npmjs.org/@storybook/csf-plugin/-/csf-plugin-10.4.6.tgz", - "integrity": "sha512-NILLxDqpA/JR/AazGWpsz+4fadJwRU4uhHephGtYpVOWnQA/DkJfKT6zpcJVq8+QA8A2zKMLX3GVKsXIrxjuDA==", + "version": "10.5.7", + "resolved": "https://registry.npmjs.org/@storybook/csf-plugin/-/csf-plugin-10.5.7.tgz", + "integrity": "sha512-IaX8FlM0H36HNFhJ2+4L9bCldqfvHGqcLg841SJNyK/DhfMlM7JsvY/GDH2ZFuWrUf8FSOx96GRRnHq6XfRKag==", "dev": true, "license": "MIT", "dependencies": { @@ -3002,7 +2798,7 @@ "peerDependencies": { "esbuild": "*", "rollup": "*", - "storybook": "^10.4.6", + "storybook": "^10.5.7", "vite": "*", "webpack": "*" }, @@ -3039,14 +2835,14 @@ } }, "node_modules/@storybook/react": { - "version": "10.4.6", - "resolved": "https://registry.npmjs.org/@storybook/react/-/react-10.4.6.tgz", - "integrity": "sha512-9Y7YecrVFe1/01KYjfOLxVqTg2Aq+IO6TEv6sC2U0PfD0AWCSCmQ91QqgBpN/XW4aFFWoiZNinyXMUlU8zxy2w==", + "version": "10.5.7", + "resolved": "https://registry.npmjs.org/@storybook/react/-/react-10.5.7.tgz", + "integrity": "sha512-uFvty2MMdFXzW5PcQe1JqDAZkz6cQq7q/9G/cbGVnBEvP6zsOVeL+bmrQ0/WBlFQN0Ko9+ZoCTvaQ9s65zBa5g==", "dev": true, "license": "MIT", "dependencies": { "@storybook/global": "^5.0.0", - "@storybook/react-dom-shim": "10.4.6", + "@storybook/react-dom-shim": "10.5.7", "react-docgen": "^8.0.2", "react-docgen-typescript": "^2.2.2" }, @@ -3059,7 +2855,7 @@ "@types/react-dom": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0", "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0", "react-dom": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0", - "storybook": "^10.4.6", + "storybook": "^10.5.7", "typescript": ">= 4.9.x" }, "peerDependenciesMeta": { @@ -3075,9 +2871,9 @@ } }, "node_modules/@storybook/react-dom-shim": { - "version": "10.4.6", - "resolved": "https://registry.npmjs.org/@storybook/react-dom-shim/-/react-dom-shim-10.4.6.tgz", - "integrity": "sha512-iGNmKzrq9vgl2PDrYAnZKI+yvac3Ym+lJXXuQaqlFRS23zA5MNm4EBX+rAG7WulqchoK6NaZ0KQOs2mAgEpTMg==", + "version": "10.5.7", + "resolved": "https://registry.npmjs.org/@storybook/react-dom-shim/-/react-dom-shim-10.5.7.tgz", + "integrity": "sha512-lxOkyh+wu/MiBXvYQHjZfD+DRKOa4bHBzbuGuiHXnHXmdOcTRdcrQTsoeN2FPtfugmmOG66cZUEgDwNX+k5eRA==", "dev": true, "license": "MIT", "funding": { @@ -3089,7 +2885,7 @@ "@types/react-dom": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0", "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0", "react-dom": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0", - "storybook": "^10.4.6" + "storybook": "^10.5.7" }, "peerDependenciesMeta": { "@types/react": { @@ -3101,19 +2897,19 @@ } }, "node_modules/@storybook/react-vite": { - "version": "10.4.6", - "resolved": "https://registry.npmjs.org/@storybook/react-vite/-/react-vite-10.4.6.tgz", - "integrity": "sha512-0arEQtybqGYXHbXpTot+Wv9YtG+V5Vp43QayXavPKQ20M8mpEzhyCPKd0EhqMGSC1Z1UEt0hm365WUBhI9LfKA==", + "version": "10.5.7", + "resolved": "https://registry.npmjs.org/@storybook/react-vite/-/react-vite-10.5.7.tgz", + "integrity": "sha512-eEo3eVa2pvqrzQukKxAzx7YvswDAA1s6k/y+tdMxmRvWyHX6QEOsb9Tda6wcVaa7c8BeJM7Ggq+289cRMTH6Iw==", "dev": true, "license": "MIT", "dependencies": { "@joshwooding/vite-plugin-react-docgen-typescript": "^0.7.0", "@rollup/pluginutils": "^5.0.2", - "@storybook/builder-vite": "10.4.6", - "@storybook/react": "10.4.6", + "@storybook/builder-vite": "10.5.7", + "@storybook/react": "10.5.7", "empathic": "^2.0.0", "magic-string": "^0.30.0", - "react-docgen": "^8.0.0", + "react-docgen": "^8.0.2", "resolve": "^1.22.8", "tsconfig-paths": "^4.2.0" }, @@ -3124,54 +2920,60 @@ "peerDependencies": { "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0", "react-dom": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0", - "storybook": "^10.4.6", + "storybook": "^10.5.7", + "typescript": ">= 4.9.x", "vite": "^5.0.0 || ^6.0.0 || ^7.0.0 || ^8.0.0" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } } }, "node_modules/@tailwindcss/node": { - "version": "4.3.2", - "resolved": "https://registry.npmjs.org/@tailwindcss/node/-/node-4.3.2.tgz", - "integrity": "sha512-yWP/sqEcBLaD8JuA6zNwxoYKr75qxTioYwlRwekj5Jr/I5GXnoJfjetH/psLUIv74cYTH2lBUEzBkinthoYcBg==", + "version": "4.3.3", + "resolved": "https://registry.npmjs.org/@tailwindcss/node/-/node-4.3.3.tgz", + "integrity": "sha512-/T8IKEsf9VTU6tLjgC7+sv2mOPtQxzE2jMw7u4Tt40Tx+QSZxpzh95/H6cMKoja9XuW7iMdLJYBB0o9G1CaAgg==", "dev": true, "license": "MIT", "dependencies": { "@jridgewell/remapping": "^2.3.5", - "enhanced-resolve": "5.21.6", + "enhanced-resolve": "^5.24.1", "jiti": "^2.7.0", "lightningcss": "1.32.0", "magic-string": "^0.30.21", "source-map-js": "^1.2.1", - "tailwindcss": "4.3.2" + "tailwindcss": "4.3.3" } }, "node_modules/@tailwindcss/oxide": { - "version": "4.3.2", - "resolved": "https://registry.npmjs.org/@tailwindcss/oxide/-/oxide-4.3.2.tgz", - "integrity": "sha512-z8ZgnzX8gdNoWLBLqBPoh/sjnxkwvf9ZuWjnO0l0yIzbLa5/9S+eC5QxGZKRobVHIC3/1BoMWjHblqWjcgFgag==", + "version": "4.3.3", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide/-/oxide-4.3.3.tgz", + "integrity": "sha512-krXjAikiaFSPaK/FkAQT5UTx3VormQaiZ5hBFlJZ9UFQGB/rwg1MZIhHAG9smMQRTdyJxP6Qt5MwMtdyU5FWrA==", "dev": true, "license": "MIT", "engines": { "node": ">= 20" }, "optionalDependencies": { - "@tailwindcss/oxide-android-arm64": "4.3.2", - "@tailwindcss/oxide-darwin-arm64": "4.3.2", - "@tailwindcss/oxide-darwin-x64": "4.3.2", - "@tailwindcss/oxide-freebsd-x64": "4.3.2", - "@tailwindcss/oxide-linux-arm-gnueabihf": "4.3.2", - "@tailwindcss/oxide-linux-arm64-gnu": "4.3.2", - "@tailwindcss/oxide-linux-arm64-musl": "4.3.2", - "@tailwindcss/oxide-linux-x64-gnu": "4.3.2", - "@tailwindcss/oxide-linux-x64-musl": "4.3.2", - "@tailwindcss/oxide-wasm32-wasi": "4.3.2", - "@tailwindcss/oxide-win32-arm64-msvc": "4.3.2", - "@tailwindcss/oxide-win32-x64-msvc": "4.3.2" + "@tailwindcss/oxide-android-arm64": "4.3.3", + "@tailwindcss/oxide-darwin-arm64": "4.3.3", + "@tailwindcss/oxide-darwin-x64": "4.3.3", + "@tailwindcss/oxide-freebsd-x64": "4.3.3", + "@tailwindcss/oxide-linux-arm-gnueabihf": "4.3.3", + "@tailwindcss/oxide-linux-arm64-gnu": "4.3.3", + "@tailwindcss/oxide-linux-arm64-musl": "4.3.3", + "@tailwindcss/oxide-linux-x64-gnu": "4.3.3", + "@tailwindcss/oxide-linux-x64-musl": "4.3.3", + "@tailwindcss/oxide-wasm32-wasi": "4.3.3", + "@tailwindcss/oxide-win32-arm64-msvc": "4.3.3", + "@tailwindcss/oxide-win32-x64-msvc": "4.3.3" } }, "node_modules/@tailwindcss/oxide-android-arm64": { - "version": "4.3.2", - "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-android-arm64/-/oxide-android-arm64-4.3.2.tgz", - "integrity": "sha512-WHxqIuHpvZ5VtdX6GTl1Ik/Vp2YuN42Et+0CdeaVd/frQ9jAvGmvR8vLT+jk3e8/Q3x8kECB9+R17pgpp2BulA==", + "version": "4.3.3", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-android-arm64/-/oxide-android-arm64-4.3.3.tgz", + "integrity": "sha512-Y85A2gmPSkl5Ve5qR86GL4HT509cFqQh1aes9p3sSkyTPwt0Pppf3GkwGe4JPACcRYjgJIEhQgM6dBClnr0NYw==", "cpu": [ "arm64" ], @@ -3186,9 +2988,9 @@ } }, "node_modules/@tailwindcss/oxide-darwin-arm64": { - "version": "4.3.2", - "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-darwin-arm64/-/oxide-darwin-arm64-4.3.2.tgz", - "integrity": "sha512-GZypeUY/IDJW3877KeM+O67vbXr3MBnbtEL4aYhNErv/JWZhye2vGSWWG9tB6iiqR2MqRNkY8IOUy4NdSZV26w==", + "version": "4.3.3", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-darwin-arm64/-/oxide-darwin-arm64-4.3.3.tgz", + "integrity": "sha512-BiaWatpBcERQFDlOjRDpIVXuFK5PJez5SA4JMg6VYZdBYU+qKfV/vqjcIs+IYmtitf1xYQZTwXvU/8y4lfZUGw==", "cpu": [ "arm64" ], @@ -3203,9 +3005,9 @@ } }, "node_modules/@tailwindcss/oxide-darwin-x64": { - "version": "4.3.2", - "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-darwin-x64/-/oxide-darwin-x64-4.3.2.tgz", - "integrity": "sha512-UIIzmefR6KO1sDU7MzRqAxC8iBpft/VhkGjTjnhoS6k7Z3rQ9wEgA1ODSiyH/tcSYssulNm4Ci3hOeK1jH7ccQ==", + "version": "4.3.3", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-darwin-x64/-/oxide-darwin-x64-4.3.3.tgz", + "integrity": "sha512-fAeUqfV5ndhxRwai8cXGzdLvul9utWOmeTkv69unv4ZXixjn61Z+p9lCWdwOwA3TYboG3BwdVuN/RDjhBRl0mw==", "cpu": [ "x64" ], @@ -3220,9 +3022,9 @@ } }, "node_modules/@tailwindcss/oxide-freebsd-x64": { - "version": "4.3.2", - "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-freebsd-x64/-/oxide-freebsd-x64-4.3.2.tgz", - "integrity": "sha512-GN+uAmcI6DNspnCDwtOAZrTz6oukJnp337qZvxqCGLd3BHBzJpO0ZbTLRvJNdztOeAmTzewewGIMPb0tk2R4WA==", + "version": "4.3.3", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-freebsd-x64/-/oxide-freebsd-x64-4.3.3.tgz", + "integrity": "sha512-iyf5bV6+wnAlflVeEy7R25dupxTNECZN5QMI0qNT6eT+EgaGdZcKhGkr5SdoaWiLJ3spLqIY9VCeSGrwmtg4kw==", "cpu": [ "x64" ], @@ -3237,9 +3039,9 @@ } }, "node_modules/@tailwindcss/oxide-linux-arm-gnueabihf": { - "version": "4.3.2", - "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-arm-gnueabihf/-/oxide-linux-arm-gnueabihf-4.3.2.tgz", - "integrity": "sha512-4ABn7qSbdHRwTiDiuWNegCyb5+2FJ4vKIKc3DmKrvAFw7MU1Lm11dIkTPwUaFdTzc7IsOpDbqBrlh0x6y36U/w==", + "version": "4.3.3", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-arm-gnueabihf/-/oxide-linux-arm-gnueabihf-4.3.3.tgz", + "integrity": "sha512-aAYUprJAJQWWbRrPvtjdroZ56Md+JM8pMiopS6xGEwDfLhqj+2ver2p4nU4Mb3CRqcMmNBjo8KkUgcxhkzVQGQ==", "cpu": [ "arm" ], @@ -3254,13 +3056,16 @@ } }, "node_modules/@tailwindcss/oxide-linux-arm64-gnu": { - "version": "4.3.2", - "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-arm64-gnu/-/oxide-linux-arm64-gnu-4.3.2.tgz", - "integrity": "sha512-wDgEIGwoM8w8pufh9LVt1PahDgNdKXrLC2qfAnV3vAmococ9RWbxeAw4pxPttd/TsJfwjyLf90Dg1y9y8I6Emw==", + "version": "4.3.3", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-arm64-gnu/-/oxide-linux-arm64-gnu-4.3.3.tgz", + "integrity": "sha512-nDxldcEENOxZRzC2uu9jrutZdAAQtb+8WWDCSnWL1zvBk1+FN+x6MtDViPB5AJMfttVCUhehGWus3XBPgatM/w==", "cpu": [ "arm64" ], "dev": true, + "libc": [ + "glibc" + ], "license": "MIT", "optional": true, "os": [ @@ -3271,13 +3076,16 @@ } }, "node_modules/@tailwindcss/oxide-linux-arm64-musl": { - "version": "4.3.2", - "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-arm64-musl/-/oxide-linux-arm64-musl-4.3.2.tgz", - "integrity": "sha512-J5Nuk0uZQIiMTJj3LEx4sAA9tMFUoXQZFv1J6An+QGYe53HKRJuFDi0rpq/tuouCZeAbOBY3kQ6g8qeD4TUjtA==", + "version": "4.3.3", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-arm64-musl/-/oxide-linux-arm64-musl-4.3.3.tgz", + "integrity": "sha512-Md44bD6veX/PC5iyF8cDVnw4HBIANZepRZZ7a8DQOvkfo5WUBwcp6iAuCUz23u+4SUkhJlD3eL7hNdW8ezd/kA==", "cpu": [ "arm64" ], "dev": true, + "libc": [ + "musl" + ], "license": "MIT", "optional": true, "os": [ @@ -3288,13 +3096,16 @@ } }, "node_modules/@tailwindcss/oxide-linux-x64-gnu": { - "version": "4.3.2", - "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-x64-gnu/-/oxide-linux-x64-gnu-4.3.2.tgz", - "integrity": "sha512-kqCZpSKOBEJO4mz7OqWoofBZeXTAwaVGPj0ErAj7CojmhKpWVWVOnrt9dE8odoIraZq4oj3ausM37kXi+Tow8w==", + "version": "4.3.3", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-x64-gnu/-/oxide-linux-x64-gnu-4.3.3.tgz", + "integrity": "sha512-tx7us1muwOKAKWao2v/GaafFeQboE6aj88vC6ziN2NCGcRm8gWUhwjzg+YdVB1e4boAtdtma4L43onunI6NS4w==", "cpu": [ "x64" ], "dev": true, + "libc": [ + "glibc" + ], "license": "MIT", "optional": true, "os": [ @@ -3305,13 +3116,16 @@ } }, "node_modules/@tailwindcss/oxide-linux-x64-musl": { - "version": "4.3.2", - "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-x64-musl/-/oxide-linux-x64-musl-4.3.2.tgz", - "integrity": "sha512-cixpqbh2toJDmkuCRI68nXA8ZxNmdK9Y+9v5h3MC3ZQKy/0BO8AWzlkWyRM7JAFSGBlfig4YVTPsK6MVgqz1uw==", + "version": "4.3.3", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-x64-musl/-/oxide-linux-x64-musl-4.3.3.tgz", + "integrity": "sha512-SJxX60smvHgasZoBy11dX6YRjXJFovwWBoedhbQPOBzgFWBHGB+TVPWB9BxzR7TTxU8FQZAI2AyiNCMzFm8Img==", "cpu": [ "x64" ], "dev": true, + "libc": [ + "musl" + ], "license": "MIT", "optional": true, "os": [ @@ -3322,9 +3136,9 @@ } }, "node_modules/@tailwindcss/oxide-wasm32-wasi": { - "version": "4.3.2", - "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-wasm32-wasi/-/oxide-wasm32-wasi-4.3.2.tgz", - "integrity": "sha512-4ec2Z/LOmRsAgU23CS4xeJfcJlmRg94A/XrbGRCF1gyU/zdDfRLYDVsS+ynSZCmGNxQ1jQriQOKMQeQxBA3Isw==", + "version": "4.3.3", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-wasm32-wasi/-/oxide-wasm32-wasi-4.3.3.tgz", + "integrity": "sha512-jx1+rPhY/5Ympkktd656HBWEBLxP7dH06losBLjjf5vgCODXvi9KhtftWcMIwTFIDqBr7cRnQkdLnAG+IOlGvQ==", "bundleDependencies": [ "@napi-rs/wasm-runtime", "@emnapi/core", @@ -3351,76 +3165,10 @@ "node": ">=14.0.0" } }, - "node_modules/@tailwindcss/oxide-wasm32-wasi/node_modules/@emnapi/core": { - "version": "1.11.1", - "dev": true, - "inBundle": true, - "license": "MIT", - "optional": true, - "dependencies": { - "@emnapi/wasi-threads": "1.2.2", - "tslib": "^2.4.0" - } - }, - "node_modules/@tailwindcss/oxide-wasm32-wasi/node_modules/@emnapi/runtime": { - "version": "1.11.1", - "dev": true, - "inBundle": true, - "license": "MIT", - "optional": true, - "dependencies": { - "tslib": "^2.4.0" - } - }, - "node_modules/@tailwindcss/oxide-wasm32-wasi/node_modules/@emnapi/wasi-threads": { - "version": "1.2.2", - "dev": true, - "inBundle": true, - "license": "MIT", - "optional": true, - "dependencies": { - "tslib": "^2.4.0" - } - }, - "node_modules/@tailwindcss/oxide-wasm32-wasi/node_modules/@napi-rs/wasm-runtime": { - "version": "1.1.4", - "dev": true, - "inBundle": true, - "license": "MIT", - "optional": true, - "dependencies": { - "@tybys/wasm-util": "^0.10.1" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/Brooooooklyn" - }, - "peerDependencies": { - "@emnapi/core": "^1.7.1", - "@emnapi/runtime": "^1.7.1" - } - }, - "node_modules/@tailwindcss/oxide-wasm32-wasi/node_modules/@tybys/wasm-util": { - "version": "0.10.2", - "dev": true, - "inBundle": true, - "license": "MIT", - "optional": true, - "dependencies": { - "tslib": "^2.4.0" - } - }, - "node_modules/@tailwindcss/oxide-wasm32-wasi/node_modules/tslib": { - "version": "2.8.1", - "dev": true, - "inBundle": true, - "license": "0BSD", - "optional": true - }, "node_modules/@tailwindcss/oxide-win32-arm64-msvc": { - "version": "4.3.2", - "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-win32-arm64-msvc/-/oxide-win32-arm64-msvc-4.3.2.tgz", - "integrity": "sha512-Zyr/M0+XcYZu3bZrUytc7TXvrk0ftWfl8gN2MwekNDzhqhKRUucMPSeOzM0o0wH5AWOU49BsKRrfKxI2atCPMQ==", + "version": "4.3.3", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-win32-arm64-msvc/-/oxide-win32-arm64-msvc-4.3.3.tgz", + "integrity": "sha512-3rc292Ca2ceK6Ulcc/bAVnTs/3nDtoPhyEKlgPv+yQJQi/JS/AMJlqzxvlDacL1nekbrcf6bTqp/jV4qgnPxNQ==", "cpu": [ "arm64" ], @@ -3435,9 +3183,9 @@ } }, "node_modules/@tailwindcss/oxide-win32-x64-msvc": { - "version": "4.3.2", - "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-win32-x64-msvc/-/oxide-win32-x64-msvc-4.3.2.tgz", - "integrity": "sha512-QI9BO7KlNZsp2GuO0jwAAj5jCDABOKXRkCk2XuKTSaNEFSdfzqswYVTtCHBNKHLsqyjFyFkqlDiwkNbTYSssMQ==", + "version": "4.3.3", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-win32-x64-msvc/-/oxide-win32-x64-msvc-4.3.3.tgz", + "integrity": "sha512-yJ0pwIVc/nYeGoV02WtsN8KYyLQv7kyI2wDnkezyJlGGjkd4QLwDGAwl47YpPJeuI0M0ObaXGSPjvWDPeTPggw==", "cpu": [ "x64" ], @@ -3452,24 +3200,24 @@ } }, "node_modules/@tailwindcss/vite": { - "version": "4.3.2", - "resolved": "https://registry.npmjs.org/@tailwindcss/vite/-/vite-4.3.2.tgz", - "integrity": "sha512-eHpMeX4JXfVNJDEcsouTeCBubJBTcTLigeaw/NTUW6PB5ATKKXdyonnXgTBX2VuRbjz1hjfz6C5XAhr52ImQXA==", + "version": "4.3.3", + "resolved": "https://registry.npmjs.org/@tailwindcss/vite/-/vite-4.3.3.tgz", + "integrity": "sha512-yYU8cogLeSh/ms2jh8Fj7jaba/EWa7Ja6GoUqYZaraEuCI5YS6ms6ObZgjjedm+jm6XZjdNRWBpPP6Z86oOxcw==", "dev": true, "license": "MIT", "dependencies": { - "@tailwindcss/node": "4.3.2", - "@tailwindcss/oxide": "4.3.2", - "tailwindcss": "4.3.2" + "@tailwindcss/node": "4.3.3", + "@tailwindcss/oxide": "4.3.3", + "tailwindcss": "4.3.3" }, "peerDependencies": { "vite": "^5.2.0 || ^6 || ^7 || ^8" } }, "node_modules/@tauri-apps/api": { - "version": "2.11.0", - "resolved": "https://registry.npmjs.org/@tauri-apps/api/-/api-2.11.0.tgz", - "integrity": "sha512-7CinYODhky9lmO23xHnUFv0Xt43fbtWMyxZcLcRBlFkcgXKuEirBvHpmtJ89YMhyeGcq20Wuc47Fa4XjyniywA==", + "version": "2.11.1", + "resolved": "https://registry.npmjs.org/@tauri-apps/api/-/api-2.11.1.tgz", + "integrity": "sha512-M2FPuYND2m+wh5hfW9ZpSdxMPdEJovPBWwoHJmwUpysTYNHaOkVFN419m/K0LIgjb/7KU2vBgsUepJWugQCvAA==", "license": "Apache-2.0 OR MIT", "funding": { "type": "opencollective", @@ -3565,6 +3313,9 @@ "arm64" ], "dev": true, + "libc": [ + "glibc" + ], "license": "Apache-2.0 OR MIT", "optional": true, "os": [ @@ -3582,6 +3333,9 @@ "arm64" ], "dev": true, + "libc": [ + "musl" + ], "license": "Apache-2.0 OR MIT", "optional": true, "os": [ @@ -3599,6 +3353,9 @@ "riscv64" ], "dev": true, + "libc": [ + "glibc" + ], "license": "Apache-2.0 OR MIT", "optional": true, "os": [ @@ -3616,6 +3373,9 @@ "x64" ], "dev": true, + "libc": [ + "glibc" + ], "license": "Apache-2.0 OR MIT", "optional": true, "os": [ @@ -3633,6 +3393,9 @@ "x64" ], "dev": true, + "libc": [ + "musl" + ], "license": "Apache-2.0 OR MIT", "optional": true, "os": [ @@ -3699,7 +3462,6 @@ "integrity": "sha512-o4PXJQidqJl82ckFaXUeoAW+XysPLauYI43Abki5hABd853iMhitooc6znOnczgbTYmEP6U6/y1ZyKAIsvMKGg==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "@babel/code-frame": "^7.10.4", "@babel/runtime": "^7.12.5", @@ -3770,9 +3532,9 @@ } }, "node_modules/@testing-library/user-event": { - "version": "14.6.1", - "resolved": "https://registry.npmjs.org/@testing-library/user-event/-/user-event-14.6.1.tgz", - "integrity": "sha512-vq7fv0rnt+QTXgPxr5Hjc210p6YKq2kmdziLgnsZGgLJ9e6VAShx1pACLuRjd/AS/sr7phAR58OIIpf0LlmQNw==", + "version": "14.6.3", + "resolved": "https://registry.npmjs.org/@testing-library/user-event/-/user-event-14.6.3.tgz", + "integrity": "sha512-6dBq67jT8lE+JTE8Exm02Kt6ze43hz1jdiSpSJwtTZiT1xQQ6b7nZYTTQ9njdArdU8XklOwaDp/AbT/eYSKF4g==", "dev": true, "license": "MIT", "engines": { @@ -3799,8 +3561,7 @@ "resolved": "https://registry.npmjs.org/@types/aria-query/-/aria-query-5.0.4.tgz", "integrity": "sha512-rfT93uj5s0PRL7EzccGMs3brplhcrghnDoV26NqKhCAS1hVo+WdNsPvE/yb6ilfr5hi2MEk6d5EWJTKdxg8jVw==", "dev": true, - "license": "MIT", - "peer": true + "license": "MIT" }, "node_modules/@types/babel__core": { "version": "7.20.5", @@ -3894,9 +3655,9 @@ "license": "MIT" }, "node_modules/@types/node": { - "version": "26.1.1", - "resolved": "https://registry.npmjs.org/@types/node/-/node-26.1.1.tgz", - "integrity": "sha512-nxAkRSVkN1Y0JC1W8ky/fTfkGsMmcrRsbx+3XoZE+rMOX71kLYTV7fLXpqud1GpbpP5TuffXFqfX7fH2GgZREw==", + "version": "26.2.0", + "resolved": "https://registry.npmjs.org/@types/node/-/node-26.2.0.tgz", + "integrity": "sha512-5IviulTZeRNp2vAJ514cc/HUlY5nZ9fCbq9DMyC52BrhFZACo3nI0R7qBxhQmo/d27NFe96ur/b7Wwxklda+kg==", "dev": true, "license": "MIT", "dependencies": { @@ -3904,15 +3665,25 @@ } }, "node_modules/@types/react": { - "version": "19.2.17", - "resolved": "https://registry.npmjs.org/@types/react/-/react-19.2.17.tgz", - "integrity": "sha512-MXfmqaVPEVgkBT/aY0aGCkRWWtByiYQXo3xdQ8r5RzuFrPiRn8Gar2tQdXSUQ2GKV3bkXckek89V8wQBY2Q/Aw==", + "version": "19.2.18", + "resolved": "https://registry.npmjs.org/@types/react/-/react-19.2.18.tgz", + "integrity": "sha512-AnzbBERsrLKtk2XSfTbYRLjQPdy116Sty4q+T+Bp3IC4l6jNBvreVPAHmpq9qhXQM7CXZPjLVmGMw9sy+hxQ3w==", "devOptional": true, "license": "MIT", "dependencies": { "csstype": "^3.2.2" } }, + "node_modules/@types/react-dom": { + "version": "19.2.4", + "resolved": "https://registry.npmjs.org/@types/react-dom/-/react-dom-19.2.4.tgz", + "integrity": "sha512-Bsc+QHgp+P/F02XDzNCY9jnZNCUuLki36KT7VKrTXXLdHf+vHMNZnW1rVu5DNW/rCK+fya3DATySbLM4yhtKUw==", + "dev": true, + "license": "MIT", + "peerDependencies": { + "@types/react": "^19.2.0" + } + }, "node_modules/@types/resolve": { "version": "1.20.6", "resolved": "https://registry.npmjs.org/@types/resolve/-/resolve-1.20.6.tgz", @@ -3921,17 +3692,17 @@ "license": "MIT" }, "node_modules/@typescript-eslint/eslint-plugin": { - "version": "8.63.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-8.63.0.tgz", - "integrity": "sha512-rvwSgqT+DHpWdzfSzPatRLm02a0GlESt++9iy3hLCDY4BgkaLcl8LBi9Yh7XGFBpwcBE/K3024QuXWTpbz4FfQ==", + "version": "8.66.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-8.66.0.tgz", + "integrity": "sha512-p088eaGrzYz1s+7cov0aMOCkNGTJlVxF4jgubf28c8L0Cv9Rloj8YBHnv4hXLq6IIEE1AsjNWavO+k+8kP2Y0A==", "dev": true, "license": "MIT", "dependencies": { "@eslint-community/regexpp": "^4.12.2", - "@typescript-eslint/scope-manager": "8.63.0", - "@typescript-eslint/type-utils": "8.63.0", - "@typescript-eslint/utils": "8.63.0", - "@typescript-eslint/visitor-keys": "8.63.0", + "@typescript-eslint/scope-manager": "8.66.0", + "@typescript-eslint/type-utils": "8.66.0", + "@typescript-eslint/utils": "8.66.0", + "@typescript-eslint/visitor-keys": "8.66.0", "ignore": "^7.0.5", "natural-compare": "^1.4.0", "ts-api-utils": "^2.5.0" @@ -3944,7 +3715,7 @@ "url": "https://opencollective.com/typescript-eslint" }, "peerDependencies": { - "@typescript-eslint/parser": "^8.63.0", + "@typescript-eslint/parser": "^8.66.0", "eslint": "^8.57.0 || ^9.0.0 || ^10.0.0", "typescript": ">=4.8.4 <6.1.0" } @@ -3960,16 +3731,16 @@ } }, "node_modules/@typescript-eslint/parser": { - "version": "8.63.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-8.63.0.tgz", - "integrity": "sha512-gwh4gvvlaVDKKxyfxMG+Gnu1u9X0OQBwyGLkbwB65dIzBKnxeRiJlNFqlI3zwVhNXJIs6qV7mlFCn/BIajlVig==", + "version": "8.66.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-8.66.0.tgz", + "integrity": "sha512-X6ypGChaWYk6PBtUg2BwuTZEFFcHJAtGTVJ9/lCTOufhZ4i9fNolQNnktq+kkMCwMj7V8Svsq7+TxSDslmhE0g==", "dev": true, "license": "MIT", "dependencies": { - "@typescript-eslint/scope-manager": "8.63.0", - "@typescript-eslint/types": "8.63.0", - "@typescript-eslint/typescript-estree": "8.63.0", - "@typescript-eslint/visitor-keys": "8.63.0", + "@typescript-eslint/scope-manager": "8.66.0", + "@typescript-eslint/types": "8.66.0", + "@typescript-eslint/typescript-estree": "8.66.0", + "@typescript-eslint/visitor-keys": "8.66.0", "debug": "^4.4.3" }, "engines": { @@ -3985,14 +3756,14 @@ } }, "node_modules/@typescript-eslint/project-service": { - "version": "8.63.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/project-service/-/project-service-8.63.0.tgz", - "integrity": "sha512-e5dh0/UI0ok53AlZ5wRkXCB32z/f2jUZqPR/ygAw5WYaSw8j9EoJWlS7wQjr/dmOaqWjnPIn2m+HhVPCMWGZVQ==", + "version": "8.66.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/project-service/-/project-service-8.66.0.tgz", + "integrity": "sha512-7MthGPTt4BP69lSryqpqq8HQqxuzynssckL/jyDyk3+TNMQ3y2jFWkptCrktWvBrP+EH787Nl5N5Qpw7WZg+5g==", "dev": true, "license": "MIT", "dependencies": { - "@typescript-eslint/tsconfig-utils": "^8.63.0", - "@typescript-eslint/types": "^8.63.0", + "@typescript-eslint/tsconfig-utils": "^8.66.0", + "@typescript-eslint/types": "^8.66.0", "debug": "^4.4.3" }, "engines": { @@ -4007,14 +3778,14 @@ } }, "node_modules/@typescript-eslint/scope-manager": { - "version": "8.63.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-8.63.0.tgz", - "integrity": "sha512-uUyfMWCnDSN8bCpcrY8nGP2BLkQ9Xn0GsipcONcpIDWhwhO4ZSyHvyS14U3X75mzxWxL3I2UZIrenTzdzcJO8A==", + "version": "8.66.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-8.66.0.tgz", + "integrity": "sha512-8TGcH25j9zqJ/IULB/ppyhRvxA8QYfFEZ7nfbg6/BN9spDgb8fPWQXlE5l8TWBL50EtUx007uZ1o9VOwrq2/9g==", "dev": true, "license": "MIT", "dependencies": { - "@typescript-eslint/types": "8.63.0", - "@typescript-eslint/visitor-keys": "8.63.0" + "@typescript-eslint/types": "8.66.0", + "@typescript-eslint/visitor-keys": "8.66.0" }, "engines": { "node": "^18.18.0 || ^20.9.0 || >=21.1.0" @@ -4025,9 +3796,9 @@ } }, "node_modules/@typescript-eslint/tsconfig-utils": { - "version": "8.63.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/tsconfig-utils/-/tsconfig-utils-8.63.0.tgz", - "integrity": "sha512-sUAbkulqBAsncKnbRP3+7CtQFRKicexnj7ZwNC6ddCR7EmrXvjvdCYMJbUIqMd6lwoEriZjwLo08aS5tSjVMHg==", + "version": "8.66.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/tsconfig-utils/-/tsconfig-utils-8.66.0.tgz", + "integrity": "sha512-9D5gLYZG4rOjcoag8MQ/fWI8WqA9wcPDyOGyWtWFhvM1lHRbliqUSPIY5J3zqCU1tvSwzXxnnjhQhz5Ne7mJ4g==", "dev": true, "license": "MIT", "engines": { @@ -4042,15 +3813,15 @@ } }, "node_modules/@typescript-eslint/type-utils": { - "version": "8.63.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-8.63.0.tgz", - "integrity": "sha512-Nzzh/OGxVCOjObjaj1CQF2RUasyYy2Jfuh+zZ3PjLzG2fYRriAiZLib9UKtO+CpQAS3YHiAS+ckZDclwqI1TPA==", + "version": "8.66.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-8.66.0.tgz", + "integrity": "sha512-LG2dWfjZQQp0ADtAu/EWJVayefGL2UEZ3CDeI44D9v3rXB/WYUqE/jpO28KrEKul5AySrmI+Zh1v6v+xW2U9+g==", "dev": true, "license": "MIT", "dependencies": { - "@typescript-eslint/types": "8.63.0", - "@typescript-eslint/typescript-estree": "8.63.0", - "@typescript-eslint/utils": "8.63.0", + "@typescript-eslint/types": "8.66.0", + "@typescript-eslint/typescript-estree": "8.66.0", + "@typescript-eslint/utils": "8.66.0", "debug": "^4.4.3", "ts-api-utils": "^2.5.0" }, @@ -4067,9 +3838,9 @@ } }, "node_modules/@typescript-eslint/types": { - "version": "8.63.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-8.63.0.tgz", - "integrity": "sha512-xyLtl9DUBBFrcJS4x2pIqGLH68/tC2uOa4Z7pUteW09D3bXnnXUom4dyPikzWgB7llmIc1zoeI3aoUdC4rPK/Q==", + "version": "8.66.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-8.66.0.tgz", + "integrity": "sha512-H6gcYaSDOyvL3AD/jHUtUFo2jqGgn/F6nuyuZSu0QTesxL+cP4dQoIMrODRofuJC09g64+WgZ6tE19Y1N2YIFQ==", "dev": true, "license": "MIT", "engines": { @@ -4081,16 +3852,16 @@ } }, "node_modules/@typescript-eslint/typescript-estree": { - "version": "8.63.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-8.63.0.tgz", - "integrity": "sha512-ygBkU+B7ex5UI/gKhaqexWev79uISfIv7XQCRNYO/jmD8rGLPyWLAb3KMRT6nd8Gt9bmUBi9+iX6tBdYfOY81Q==", + "version": "8.66.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-8.66.0.tgz", + "integrity": "sha512-8/x4INiiQb10jGgXYD7116/zQ+OL84ZIFn0za68wwFHCanT/VLbBEroWht8RV8fn0/ZCAoazHLQgwUC0UQcDfg==", "dev": true, "license": "MIT", "dependencies": { - "@typescript-eslint/project-service": "8.63.0", - "@typescript-eslint/tsconfig-utils": "8.63.0", - "@typescript-eslint/types": "8.63.0", - "@typescript-eslint/visitor-keys": "8.63.0", + "@typescript-eslint/project-service": "8.66.0", + "@typescript-eslint/tsconfig-utils": "8.66.0", + "@typescript-eslint/types": "8.66.0", + "@typescript-eslint/visitor-keys": "8.66.0", "debug": "^4.4.3", "minimatch": "^10.2.2", "semver": "^7.7.3", @@ -4109,16 +3880,16 @@ } }, "node_modules/@typescript-eslint/utils": { - "version": "8.63.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-8.63.0.tgz", - "integrity": "sha512-fUKaeAvrTuQg/Tgt3nliAUSZHJM6DlCcfyEmxCvlX8kieWSStBX+5O5Fnidtc3i2JrH+9c/GL4RY2iasd/GPTA==", + "version": "8.66.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-8.66.0.tgz", + "integrity": "sha512-jasearZPolBw5NJNYGMwxzHMF83niVWmMU1VdHzG1CyfI2VS7f7nZltnKtHcg20hW+7Uo5GfK4MeDPoU3qI8EA==", "dev": true, "license": "MIT", "dependencies": { "@eslint-community/eslint-utils": "^4.9.1", - "@typescript-eslint/scope-manager": "8.63.0", - "@typescript-eslint/types": "8.63.0", - "@typescript-eslint/typescript-estree": "8.63.0" + "@typescript-eslint/scope-manager": "8.66.0", + "@typescript-eslint/types": "8.66.0", + "@typescript-eslint/typescript-estree": "8.66.0" }, "engines": { "node": "^18.18.0 || ^20.9.0 || >=21.1.0" @@ -4133,13 +3904,13 @@ } }, "node_modules/@typescript-eslint/visitor-keys": { - "version": "8.63.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-8.63.0.tgz", - "integrity": "sha512-UexrHGnGTpbuQHct2ExOc2ZcFbGUS9FOesCxxqdBGcpI1BxYu/LZ6U8Aq6/72XtF/qRBk9nhuGHFJIXXMhPMdw==", + "version": "8.66.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-8.66.0.tgz", + "integrity": "sha512-dkKR8q+lKciskj1Y3vthHktl+3cMLWGyVUP23bRiPZ5O9BRT++4EqDDV+TVeIKBL1VXVEqrJlz8MYbcnvJcAlg==", "dev": true, "license": "MIT", "dependencies": { - "@typescript-eslint/types": "8.63.0", + "@typescript-eslint/types": "8.66.0", "eslint-visitor-keys": "^5.0.0" }, "engines": { @@ -4151,13 +3922,13 @@ } }, "node_modules/@vitejs/plugin-react": { - "version": "6.0.2", - "resolved": "https://registry.npmjs.org/@vitejs/plugin-react/-/plugin-react-6.0.2.tgz", - "integrity": "sha512-DlSMqo4WhThw4vB8Mpn0Woe9J+Jfq1geJ61AKW0QEgLzGMNwtIMdxbDUzLxcun8W7NbJO0e2Jg/Nxm3cCSVzzg==", + "version": "6.0.5", + "resolved": "https://registry.npmjs.org/@vitejs/plugin-react/-/plugin-react-6.0.5.tgz", + "integrity": "sha512-BOVzne/NL162sMdResB25mUv+vWMF5NoAjNf09TeGlE7ZpszZWSD3winycicLJw72yeVsoCn/2kOhEuCvEShMA==", "dev": true, "license": "MIT", "dependencies": { - "@rolldown/pluginutils": "^1.0.0" + "@rolldown/pluginutils": "^1.0.1" }, "engines": { "node": "^20.19.0 || >=22.12.0" @@ -4176,64 +3947,83 @@ } } }, - "node_modules/@vitest/expect": { - "version": "3.2.4", - "resolved": "https://registry.npmjs.org/@vitest/expect/-/expect-3.2.4.tgz", - "integrity": "sha512-Io0yyORnB6sikFlt8QW5K7slY4OjqNX9jmJQ02QDda8lyM6B5oNgVWoSoKPac8/kgnCUzuHQKrSLtu/uOqqrig==", + "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==", "dev": true, "license": "MIT", "dependencies": { - "@types/chai": "^5.2.2", - "@vitest/spy": "3.2.4", - "@vitest/utils": "3.2.4", - "chai": "^5.2.0", - "tinyrainbow": "^2.0.0" + "@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" }, "funding": { "url": "https://opencollective.com/vitest" - } - }, - "node_modules/@vitest/expect/node_modules/chai": { - "version": "5.3.3", - "resolved": "https://registry.npmjs.org/chai/-/chai-5.3.3.tgz", - "integrity": "sha512-4zNhdJD/iOjSH0A05ea+Ke6MU5mmpQcbQsSOkgdaUMJ9zTlDTD/GYlwohmIE2u0gaxHYiVHEn1Fw9mZ/ktJWgw==", + }, + "peerDependencies": { + "@vitest/browser": "4.1.10", + "vitest": "4.1.10" + }, + "peerDependenciesMeta": { + "@vitest/browser": { + "optional": true + } + } + }, + "node_modules/@vitest/expect": { + "version": "3.2.4", + "resolved": "https://registry.npmjs.org/@vitest/expect/-/expect-3.2.4.tgz", + "integrity": "sha512-Io0yyORnB6sikFlt8QW5K7slY4OjqNX9jmJQ02QDda8lyM6B5oNgVWoSoKPac8/kgnCUzuHQKrSLtu/uOqqrig==", "dev": true, "license": "MIT", "dependencies": { - "assertion-error": "^2.0.1", - "check-error": "^2.1.1", - "deep-eql": "^5.0.1", - "loupe": "^3.1.0", - "pathval": "^2.0.0" + "@types/chai": "^5.2.2", + "@vitest/spy": "3.2.4", + "@vitest/utils": "3.2.4", + "chai": "^5.2.0", + "tinyrainbow": "^2.0.0" }, - "engines": { - "node": ">=18" + "funding": { + "url": "https://opencollective.com/vitest" } }, - "node_modules/@vitest/expect/node_modules/tinyrainbow": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/tinyrainbow/-/tinyrainbow-2.0.0.tgz", - "integrity": "sha512-op4nsTR47R6p0vMUUoYl/a+ljLFVtlfaXkLQmqfLR1qHma1h/ysYk4hEXZ880bf2CYgTskvTa/e196Vd5dDQXw==", + "node_modules/@vitest/expect/node_modules/@vitest/pretty-format": { + "version": "3.2.4", + "resolved": "https://registry.npmjs.org/@vitest/pretty-format/-/pretty-format-3.2.4.tgz", + "integrity": "sha512-IVNZik8IVRJRTr9fxlitMKeJeXFFFN0JaB9PHPGQ8NKQbGpfjlTx9zO4RefN8gp7eqjNy8nyK3NZmBzOPeIxtA==", "dev": true, "license": "MIT", - "engines": { - "node": ">=14.0.0" + "dependencies": { + "tinyrainbow": "^2.0.0" + }, + "funding": { + "url": "https://opencollective.com/vitest" } }, - "node_modules/@vitest/pretty-format": { + "node_modules/@vitest/expect/node_modules/@vitest/utils": { "version": "3.2.4", - "resolved": "https://registry.npmjs.org/@vitest/pretty-format/-/pretty-format-3.2.4.tgz", - "integrity": "sha512-IVNZik8IVRJRTr9fxlitMKeJeXFFFN0JaB9PHPGQ8NKQbGpfjlTx9zO4RefN8gp7eqjNy8nyK3NZmBzOPeIxtA==", + "resolved": "https://registry.npmjs.org/@vitest/utils/-/utils-3.2.4.tgz", + "integrity": "sha512-fB2V0JFrQSMsCo9HiSq3Ezpdv4iYaXRG1Sx8edX3MwxfyNn83mKiGzOcH+Fkxt4MHxr3y42fQi1oeAInqgX2QA==", "dev": true, "license": "MIT", "dependencies": { + "@vitest/pretty-format": "3.2.4", + "loupe": "^3.1.4", "tinyrainbow": "^2.0.0" }, "funding": { "url": "https://opencollective.com/vitest" } }, - "node_modules/@vitest/pretty-format/node_modules/tinyrainbow": { + "node_modules/@vitest/expect/node_modules/tinyrainbow": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/tinyrainbow/-/tinyrainbow-2.0.0.tgz", "integrity": "sha512-op4nsTR47R6p0vMUUoYl/a+ljLFVtlfaXkLQmqfLR1qHma1h/ysYk4hEXZ880bf2CYgTskvTa/e196Vd5dDQXw==", @@ -4243,6 +4033,96 @@ "node": ">=14.0.0" } }, + "node_modules/@vitest/mocker": { + "version": "4.1.10", + "resolved": "https://registry.npmjs.org/@vitest/mocker/-/mocker-4.1.10.tgz", + "integrity": "sha512-v0xaezt+DKEmKfaxg133ldzADrwLGd7Ze1MfQQTYfvs8OqZIwbxyxaYURivwV7sWy5fqn3rH5uOrSp07bp44Ow==", + "dev": true, + "license": "MIT", + "dependencies": { + "@vitest/spy": "4.1.10", + "estree-walker": "^3.0.3", + "magic-string": "^0.30.21" + }, + "funding": { + "url": "https://opencollective.com/vitest" + }, + "peerDependencies": { + "msw": "^2.4.9", + "vite": "^6.0.0 || ^7.0.0 || ^8.0.0" + }, + "peerDependenciesMeta": { + "msw": { + "optional": true + }, + "vite": { + "optional": true + } + } + }, + "node_modules/@vitest/mocker/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/mocker/node_modules/estree-walker": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-3.0.3.tgz", + "integrity": "sha512-7RUKfXgSMMkzt6ZuXmqapOurLGPPfgj6l9uRZ7lRGolvk0y2yocc35LdcxKC5PQZdn2DMqioAQ2NoWcrTKmm6g==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/estree": "^1.0.0" + } + }, + "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": "3.2.4", "resolved": "https://registry.npmjs.org/@vitest/spy/-/spy-3.2.4.tgz", @@ -4257,30 +4137,20 @@ } }, "node_modules/@vitest/utils": { - "version": "3.2.4", - "resolved": "https://registry.npmjs.org/@vitest/utils/-/utils-3.2.4.tgz", - "integrity": "sha512-fB2V0JFrQSMsCo9HiSq3Ezpdv4iYaXRG1Sx8edX3MwxfyNn83mKiGzOcH+Fkxt4MHxr3y42fQi1oeAInqgX2QA==", + "version": "4.1.10", + "resolved": "https://registry.npmjs.org/@vitest/utils/-/utils-4.1.10.tgz", + "integrity": "sha512-fy9am/HWxbaGt/Sawrp90vt6Y6jQwf1RX77cz3uwoJwJVMli/e1IEwRPnMNJ7vKfPTwo0diXifkpPvwH9v7nGA==", "dev": true, "license": "MIT", "dependencies": { - "@vitest/pretty-format": "3.2.4", - "loupe": "^3.1.4", - "tinyrainbow": "^2.0.0" + "@vitest/pretty-format": "4.1.10", + "convert-source-map": "^2.0.0", + "tinyrainbow": "^3.1.0" }, "funding": { "url": "https://opencollective.com/vitest" } }, - "node_modules/@vitest/utils/node_modules/tinyrainbow": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/tinyrainbow/-/tinyrainbow-2.0.0.tgz", - "integrity": "sha512-op4nsTR47R6p0vMUUoYl/a+ljLFVtlfaXkLQmqfLR1qHma1h/ysYk4hEXZ880bf2CYgTskvTa/e196Vd5dDQXw==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=14.0.0" - } - }, "node_modules/@webcontainer/env": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/@webcontainer/env/-/env-1.1.1.tgz", @@ -4289,9 +4159,9 @@ "license": "MIT" }, "node_modules/acorn": { - "version": "8.16.0", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.16.0.tgz", - "integrity": "sha512-UVJyE9MttOsBQIDKw1skb9nAwQuR5wuGD3+82K6JgJlm/Y+KI92oNsMNGZCYdDsVtRHSak0pcV5Dno5+4jh9sw==", + "version": "8.18.0", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.18.0.tgz", + "integrity": "sha512-lGq+9yr1/GuAWaVYIHRjvvySG5/4VfKIvC8EWxStPdcDh/Ka7FG3twP6v4d5BkravUilhIAsG4Qj83t02LWUPQ==", "dev": true, "license": "MIT", "bin": { @@ -4312,9 +4182,9 @@ } }, "node_modules/ajv": { - "version": "6.14.0", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.14.0.tgz", - "integrity": "sha512-IWrosm/yrn43eiKqkfkHis7QioDleaXQHdDVPKg0FSwwd/DuvyX79TZnFOnYpB7dcsFAMmtFztZuXPDvSePkFw==", + "version": "6.15.0", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.15.0.tgz", + "integrity": "sha512-fgFx7Hfoq60ytK2c7DhnF8jIvzYgOMxfugjLOSMHjLIPgenqa7S7oaagATUq99mV6IYvN2tRmC0wnTYX6iPbMw==", "dev": true, "license": "MIT", "dependencies": { @@ -4334,7 +4204,6 @@ "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", "dev": true, "license": "MIT", - "peer": true, "engines": { "node": ">=8" } @@ -4345,7 +4214,6 @@ "integrity": "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==", "dev": true, "license": "MIT", - "peer": true, "engines": { "node": ">=10" }, @@ -4397,9 +4265,9 @@ } }, "node_modules/ast-v8-to-istanbul": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/ast-v8-to-istanbul/-/ast-v8-to-istanbul-1.0.0.tgz", - "integrity": "sha512-1fSfIwuDICFA4LKkCzRPO7F0hzFf0B7+Xqrl27ynQaa+Rh0e1Es0v6kWHPott3lU10AyAr7oKHa65OppjLn3Rg==", + "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==", "dev": true, "license": "MIT", "dependencies": { @@ -4408,6 +4276,16 @@ "js-tokens": "^10.0.0" } }, + "node_modules/ast-v8-to-istanbul/node_modules/estree-walker": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-3.0.3.tgz", + "integrity": "sha512-7RUKfXgSMMkzt6ZuXmqapOurLGPPfgj6l9uRZ7lRGolvk0y2yocc35LdcxKC5PQZdn2DMqioAQ2NoWcrTKmm6g==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/estree": "^1.0.0" + } + }, "node_modules/ast-v8-to-istanbul/node_modules/js-tokens": { "version": "10.0.0", "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-10.0.0.tgz", @@ -4426,9 +4304,9 @@ } }, "node_modules/baseline-browser-mapping": { - "version": "2.10.42", - "resolved": "https://registry.npmjs.org/baseline-browser-mapping/-/baseline-browser-mapping-2.10.42.tgz", - "integrity": "sha512-c/jurFrDLyui7o1J86yLkRu4LMsTYcBohveus7/I2Hzdn9KIP2bdJPTue/lR1KH46enoPbD77GKeSYNdyPoD3Q==", + "version": "2.11.13", + "resolved": "https://registry.npmjs.org/baseline-browser-mapping/-/baseline-browser-mapping-2.11.13.tgz", + "integrity": "sha512-k9HNuUVMlqVjQ9UHzfPjIqiDbWw7WqT1AoT7GL8VwvF3r0ZfArtgiSPAlmupyNquNgOJHTuH4CKYf8ttMTWBTQ==", "dev": true, "license": "Apache-2.0", "bin": { @@ -4462,9 +4340,9 @@ } }, "node_modules/browserslist": { - "version": "4.28.4", - "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.28.4.tgz", - "integrity": "sha512-MTc8i/x9jBQd1iMw2CFGS+rwMa07eYjLR0CCTLDACl9xhxy+nIs3KeML/biicXtk9JrZ6dnnTatmc7ErPXIxqw==", + "version": "4.28.8", + "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.28.8.tgz", + "integrity": "sha512-V2NpofLblG64mfOtSgDhOJESZEGogzDMBv/q+W6oc4LXWP/q75eOXoOaaOu1EOadB9U4Bwx/e0yzbvwKH8zalA==", "dev": true, "funding": [ { @@ -4482,11 +4360,11 @@ ], "license": "MIT", "dependencies": { - "baseline-browser-mapping": "^2.10.38", - "caniuse-lite": "^1.0.30001799", - "electron-to-chromium": "^1.5.376", - "node-releases": "^2.0.48", - "update-browserslist-db": "^1.2.3" + "baseline-browser-mapping": "^2.11.12", + "caniuse-lite": "^1.0.30001809", + "electron-to-chromium": "^1.5.402", + "node-releases": "^2.0.53", + "update-browserslist-db": "^1.3.0" }, "bin": { "browserslist": "cli.js" @@ -4512,9 +4390,9 @@ } }, "node_modules/caniuse-lite": { - "version": "1.0.30001800", - "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001800.tgz", - "integrity": "sha512-MMHtuAz9Ys840zAY5F4k6fV5GaivZ9sPk+nz0mY+GYVzRBnYkN0mpqkSR92oWRQ19yQWo4HvBV/FnC16AJX8MA==", + "version": "1.0.30001809", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001809.tgz", + "integrity": "sha512-xxWVywk6a6Arlk+hymeycyn/VgqEfLDxupvhH/xiY5SJ/18kmi9o6MiO320DCUzypORHLtvh0I4i04tUhCNHNQ==", "dev": true, "funding": [ { @@ -4533,11 +4411,18 @@ "license": "CC-BY-4.0" }, "node_modules/chai": { - "version": "6.2.2", - "resolved": "https://registry.npmjs.org/chai/-/chai-6.2.2.tgz", - "integrity": "sha512-NUPRluOfOiTKBKvWPtSD4PhFvWCqOi0BGStNWs57X9js7XGTprSmFoz5F0tWhR4WPjNeR9jXqdC7/UpSJTnlRg==", + "version": "5.3.3", + "resolved": "https://registry.npmjs.org/chai/-/chai-5.3.3.tgz", + "integrity": "sha512-4zNhdJD/iOjSH0A05ea+Ke6MU5mmpQcbQsSOkgdaUMJ9zTlDTD/GYlwohmIE2u0gaxHYiVHEn1Fw9mZ/ktJWgw==", "dev": true, "license": "MIT", + "dependencies": { + "assertion-error": "^2.0.1", + "check-error": "^2.1.1", + "deep-eql": "^5.0.1", + "loupe": "^3.1.0", + "pathval": "^2.0.0" + }, "engines": { "node": ">=18" } @@ -4770,13 +4655,12 @@ "resolved": "https://registry.npmjs.org/dom-accessibility-api/-/dom-accessibility-api-0.5.16.tgz", "integrity": "sha512-X7BJ2yElsnOJ30pZF4uIIDfBEVgF4XEBxL9Bxhy6dnrm5hkzqmsWHGTiHqRiITNhMyFLyAiWndIJP7Z1NTteDg==", "dev": true, - "license": "MIT", - "peer": true + "license": "MIT" }, "node_modules/electron-to-chromium": { - "version": "1.5.387", - "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.387.tgz", - "integrity": "sha512-TaxwufTFDufvPEoXdhwVrA3UdFWBeWGkYoJ1K8ldF1xe6gKfth6iRNS5lTQ5JPNOHdGQm8PT1QYKUqFLCiUefQ==", + "version": "1.5.403", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.403.tgz", + "integrity": "sha512-MQsYmdaLzvaCX5j+ZZBr5Fm6uCCnPQcRtlvmvRlWqrXy+BH2O4ffXIAScF+JQznQWB9brWp4lSD9Z4yNmaf2BA==", "dev": true, "license": "ISC" }, @@ -4791,9 +4675,9 @@ } }, "node_modules/enhanced-resolve": { - "version": "5.21.6", - "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.21.6.tgz", - "integrity": "sha512-aNnGCvbJ/RIyWo1IuhNdVjnNF+EjH9wpzpNHt+ci/m9He9LJvUN8wrCcXjp9cWsGNAuvSpVFTx/vraAFQ8qGjQ==", + "version": "5.24.5", + "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.24.5.tgz", + "integrity": "sha512-L1l8TNvomm6UVW5B253AGxQagSQr+vGwhMlrrfRS2qmhx46AMpMVJKQYLvWYbysTMY8VoicOvzHzoHMbyzB+4A==", "dev": true, "license": "MIT", "dependencies": { @@ -4828,16 +4712,16 @@ } }, "node_modules/es-module-lexer": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/es-module-lexer/-/es-module-lexer-2.1.0.tgz", - "integrity": "sha512-n27zTYMjYu1aj4MjCWzSP7G9r75utsaoc8m61weK+W8JMBGGQybd43GstCXZ3WNmSFtGT9wi59qQTW6mhTR5LQ==", + "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==", "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", @@ -4848,32 +4732,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": { @@ -4900,9 +4784,9 @@ } }, "node_modules/eslint": { - "version": "10.7.0", - "resolved": "https://registry.npmjs.org/eslint/-/eslint-10.7.0.tgz", - "integrity": "sha512-GVTD7s1vdIl6UYvAfriOPeY1Df8LIZjfofLvHwde+erDHGGuHyuM6xoxRxmHiebhYuD2p1vN4wWh0XzPARSGDQ==", + "version": "10.8.1", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-10.8.1.tgz", + "integrity": "sha512-wqA7W2jbsC/BnV9Iv1UZpKVFkO1AdNoSmYW8NWG4HNOBbkAMvIqDZ27pI2f07dqn583NcIC44ckjAcOXDL1QbQ==", "dev": true, "license": "MIT", "workspaces": [ @@ -4912,7 +4796,7 @@ "@eslint-community/eslint-utils": "^4.8.0", "@eslint-community/regexpp": "^4.12.2", "@eslint/config-array": "^0.23.5", - "@eslint/config-helpers": "^0.6.0", + "@eslint/config-helpers": "^0.7.0", "@eslint/core": "^1.2.1", "@eslint/plugin-kit": "^0.7.2", "@humanfs/node": "^0.16.6", @@ -4936,7 +4820,7 @@ "imurmurhash": "^0.1.4", "is-glob": "^4.0.0", "json-stable-stringify-without-jsonify": "^1.0.1", - "minimatch": "^10.2.4", + "minimatch": "^10.2.5", "natural-compare": "^1.4.0", "optionator": "^0.9.3" }, @@ -4959,13 +4843,13 @@ } }, "node_modules/eslint-plugin-jsdoc": { - "version": "63.0.13", - "resolved": "https://registry.npmjs.org/eslint-plugin-jsdoc/-/eslint-plugin-jsdoc-63.0.13.tgz", - "integrity": "sha512-ahG1kWA8jYNwaQJtzJlnF+v4Gb9w5r+WL98gp+L8qjLN9ErpL5sevGuemN+fCYsU3Np27F36KmDc8UPi1ml/dg==", + "version": "63.3.3", + "resolved": "https://registry.npmjs.org/eslint-plugin-jsdoc/-/eslint-plugin-jsdoc-63.3.3.tgz", + "integrity": "sha512-xI4IeVRzRFA2DGHrPLIxF3U+oJHU3FE+P9Zb27fVs5dPHgfcpoAs0PyCbznVhK7pwR+9BPUztFeXSgpw/CL4Yg==", "dev": true, "license": "BSD-3-Clause", "dependencies": { - "@es-joy/jsdoccomment": "~0.88.0", + "@es-joy/jsdoccomment": "~0.91.0", "@es-joy/resolve.exports": "1.2.0", "are-docs-informative": "^0.0.2", "comment-parser": "1.4.7", @@ -4977,7 +4861,7 @@ "object-deep-merge": "^2.0.1", "parse-imports-exports": "^0.2.4", "semver": "^7.8.5", - "spdx-expression-parse": "^4.0.0", + "spdx-expression-parse": "^5.0.0", "to-valid-identifier": "^1.0.0" }, "engines": { @@ -5088,14 +4972,11 @@ } }, "node_modules/estree-walker": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-3.0.3.tgz", - "integrity": "sha512-7RUKfXgSMMkzt6ZuXmqapOurLGPPfgj6l9uRZ7lRGolvk0y2yocc35LdcxKC5PQZdn2DMqioAQ2NoWcrTKmm6g==", + "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", - "dependencies": { - "@types/estree": "^1.0.0" - } + "license": "MIT" }, "node_modules/esutils": { "version": "2.0.3", @@ -5108,9 +4989,9 @@ } }, "node_modules/expect-type": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/expect-type/-/expect-type-1.3.0.tgz", - "integrity": "sha512-knvyeauYhqjOYvQ66MznSMs83wmHrCycNEN6Ao+2AeYEfxUIkuiVxdEa1qlGEPK+We3n0THiDciYSsCcgW/DoA==", + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/expect-type/-/expect-type-1.4.0.tgz", + "integrity": "sha512-KfYbmpRm0VbLjEvVa9yGwCi9GI34xvi7A/HXYWQO65CSD2u3MczUJSuwXKFIxlGsgBQizV9q5J9NHj4VG0n+pA==", "dev": true, "license": "Apache-2.0", "engines": { @@ -5118,9 +4999,9 @@ } }, "node_modules/fast-check": { - "version": "4.8.0", - "resolved": "https://registry.npmjs.org/fast-check/-/fast-check-4.8.0.tgz", - "integrity": "sha512-GOJ158CUMnN6cSahsv4+ExARvIDuzzinFjkp0E9WtiBa5zcVeLozVkWaE4IzFcc+Y48Wp1EDlUZsXRyAztQcSg==", + "version": "4.9.0", + "resolved": "https://registry.npmjs.org/fast-check/-/fast-check-4.9.0.tgz", + "integrity": "sha512-7ms6T7SybUev/PQITciI0yLM2pOSFy5zpG8Ty7tQofcVaQUvrMXp6CBwqF6fThLCLOrfBtuHAtwq6Yu4XPCllg==", "dev": true, "funding": [ { @@ -5224,9 +5105,9 @@ } }, "node_modules/flatted": { - "version": "3.4.2", - "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.4.2.tgz", - "integrity": "sha512-PjDse7RzhcPkIJwy5t7KPWQSZ9cAbzQXcafsetQoD7sOJRQlGikNbx7yZp2OotDnJyrDcbyRq3Ttb18iYOqkxA==", + "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" }, @@ -5554,9 +5435,9 @@ "license": "MIT" }, "node_modules/jsdoc-type-pratt-parser": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/jsdoc-type-pratt-parser/-/jsdoc-type-pratt-parser-7.2.0.tgz", - "integrity": "sha512-dh140MMgjyg3JhJZY/+iEzW+NO5xR2gpbDFKHqotCmexElVntw7GjWjt511+C/Ef02RU5TKYrJo/Xlzk+OLaTw==", + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/jsdoc-type-pratt-parser/-/jsdoc-type-pratt-parser-8.0.0.tgz", + "integrity": "sha512-uQu/fXVqVaMg6gM8/E5G5+eygVcZ1NV0Z51CvqhNa2bDWxvHMl484ETr6vph4oPyC+KUcbP/w2W2pewfCiR9aQ==", "dev": true, "license": "MIT", "engines": { @@ -5651,6 +5532,13 @@ "node": ">=6" } }, + "node_modules/jsonc-parser": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/jsonc-parser/-/jsonc-parser-3.3.1.tgz", + "integrity": "sha512-HUgH65KyejrUFPvHFPbqOY0rsFip3Bo5wb4ngvdi1EpCYWUQDC5V+Y7mZws+DLkr4M//zQJoanu1SP+87Dv1oQ==", + "dev": true, + "license": "MIT" + }, "node_modules/keyv": { "version": "4.5.4", "resolved": "https://registry.npmjs.org/keyv/-/keyv-4.5.4.tgz", @@ -5818,6 +5706,9 @@ "arm64" ], "dev": true, + "libc": [ + "glibc" + ], "license": "MPL-2.0", "optional": true, "os": [ @@ -5839,6 +5730,9 @@ "arm64" ], "dev": true, + "libc": [ + "musl" + ], "license": "MPL-2.0", "optional": true, "os": [ @@ -5860,6 +5754,9 @@ "x64" ], "dev": true, + "libc": [ + "glibc" + ], "license": "MPL-2.0", "optional": true, "os": [ @@ -5881,6 +5778,9 @@ "x64" ], "dev": true, + "libc": [ + "musl" + ], "license": "MPL-2.0", "optional": true, "os": [ @@ -5960,9 +5860,9 @@ "license": "MIT" }, "node_modules/lru-cache": { - "version": "11.5.1", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-11.5.1.tgz", - "integrity": "sha512-RPimw/7aMdv2oqRrxKwvZXcPfwBrn/JZ2xYcY9Hus/6LaS3VOAKVWKWgNLCFSiOm1ESXinjsDlidVU7JlnCN2A==", + "version": "11.5.2", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-11.5.2.tgz", + "integrity": "sha512-4pfM1Ff0x50o0tQwb5ucw/RzNyD0/YJME6IVcStalZuMWxdt3sR3huStTtxz4PUmvZfRguvDejasvQ2kifR11g==", "dev": true, "license": "BlueOak-1.0.0", "engines": { @@ -5970,9 +5870,9 @@ } }, "node_modules/lucide-react": { - "version": "1.24.0", - "resolved": "https://registry.npmjs.org/lucide-react/-/lucide-react-1.24.0.tgz", - "integrity": "sha512-YT6mBD8lGKkg4nM39enlm94/sfJIiW0YKUT60fBy4YK8tai31ylg1VhGNWxkpSKHo9UagfnZqwIff3HTDQwXeA==", + "version": "1.30.0", + "resolved": "https://registry.npmjs.org/lucide-react/-/lucide-react-1.30.0.tgz", + "integrity": "sha512-tUIr2jXLbWpCkdtH8XP7P7YppM9ueWgTky99lpWDY6z5REs6B+O6ZQ3U5tHkUUY59ANyOv/PBcs8E4Fe3KO3eA==", "license": "ISC", "peerDependencies": { "react": "^16.5.1 || ^17.0.0 || ^18.0.0 || ^19.0.0" @@ -5984,7 +5884,6 @@ "integrity": "sha512-h5bgJWpxJNswbU7qCrV0tIKQCaS3blPDrqKWx+QxzuzL1zGUzij9XCWLrSLsJPu5t+eWA/ycetzYAO5IOMcWAQ==", "dev": true, "license": "MIT", - "peer": true, "bin": { "lz-string": "bin/bin.js" } @@ -6000,14 +5899,14 @@ } }, "node_modules/magicast": { - "version": "0.5.2", - "resolved": "https://registry.npmjs.org/magicast/-/magicast-0.5.2.tgz", - "integrity": "sha512-E3ZJh4J3S9KfwdjZhe2afj6R9lGIN5Pher1pF39UGrXRqq/VDaGVIGN13BjHd2u8B61hArAGOnso7nBOouW3TQ==", + "version": "0.5.4", + "resolved": "https://registry.npmjs.org/magicast/-/magicast-0.5.4.tgz", + "integrity": "sha512-llBEhWm1SacoRwgHUoQJYtwp4PBLF4faQi5TCpIGyGs9n4y5+juI0tDgyKIfpqxckRHaHzouUEph3THklWh03w==", "dev": true, "license": "MIT", "dependencies": { - "@babel/parser": "^7.29.0", - "@babel/types": "^7.29.0", + "@babel/parser": "^7.29.7", + "@babel/types": "^7.29.7", "source-map-js": "^1.2.1" } }, @@ -6045,13 +5944,13 @@ } }, "node_modules/minimatch": { - "version": "10.2.4", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-10.2.4.tgz", - "integrity": "sha512-oRjTw/97aTBN0RHbYCdtF1MQfvusSIBQM0IZEgzl6426+8jSC0nF1a/GmnVLpfB9yyr6g6FTqWqiZVbxrtaCIg==", + "version": "10.2.6", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-10.2.6.tgz", + "integrity": "sha512-vpLQEs+VLCr1nU0BXS07maYoFwlDAH0gngQuuttxIwutDFEMHq2blX+8vpgxDdK3J1PwjCJiep77OitTZ4Ll1A==", "dev": true, "license": "BlueOak-1.0.0", "dependencies": { - "brace-expansion": "^5.0.2" + "brace-expansion": "^5.0.8" }, "engines": { "node": "18 || 20 || >=22" @@ -6088,10 +5987,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==", - "dev": true, + "version": "3.3.18", + "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.18.tgz", + "integrity": "sha512-DTg4MJbGMWkfi6VZFdNt2/caMbQy4Ou+Op/hJQvGEWcnVfoA1QA+xzRKAzw9jD6+GVOOeYr/mIcuDSdug6F6+w==", "funding": [ { "type": "github", @@ -6114,9 +6012,9 @@ "license": "MIT" }, "node_modules/node-releases": { - "version": "2.0.50", - "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.50.tgz", - "integrity": "sha512-J6l92tKHX6w8Jy5nO1Vuc01NoIiRGi/d6qBKVxh+IQ8Cr3b6HbVNfKiF8ZpFKufTwpwxMmce2W3iQZ861ZRyTg==", + "version": "2.0.53", + "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.53.tgz", + "integrity": "sha512-D9UOmYG3UH1V+ENW56t5QXBwJw1YEY18ruVeus89Rw+SyIgjPkCO84bRzO3uNIYosJbNwiabWVn48o3uJLjxFQ==", "dev": true, "license": "MIT", "engines": { @@ -6131,15 +6029,18 @@ "license": "MIT" }, "node_modules/obug": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/obug/-/obug-2.1.1.tgz", - "integrity": "sha512-uTqF9MuPraAQ+IsnPf366RG4cP9RtUi7MLO1N3KEc+wb0a6yKpeL0lmk2IB1jY5KHPAlTc6T/JRdC/YqxHNwkQ==", + "version": "2.1.4", + "resolved": "https://registry.npmjs.org/obug/-/obug-2.1.4.tgz", + "integrity": "sha512-4a+OsYv9UktOJKE+l1A4OufDgdRF9PifWj+tJnHURo/P+WOxpG4GzUFL9qCalmWauao6ogiG+QvnCovwPoyAWA==", "dev": true, "funding": [ "https://github.com/sponsors/sxzz", "https://opencollective.com/debug" ], - "license": "MIT" + "license": "MIT", + "engines": { + "node": ">=12.20.0" + } }, "node_modules/open": { "version": "10.2.0", @@ -6216,45 +6117,35 @@ "@oxc-parser/binding-win32-x64-msvc": "0.127.0" } }, - "node_modules/oxc-parser/node_modules/@oxc-project/types": { - "version": "0.127.0", - "resolved": "https://registry.npmjs.org/@oxc-project/types/-/types-0.127.0.tgz", - "integrity": "sha512-aIYXQBo4lCbO4z0R3FHeucQHpF46l2LbMdxRvqvuRuW2OxdnSkcng5B8+K12spgLDj93rtN3+J2Vac/TIO+ciQ==", - "dev": true, - "license": "MIT", - "funding": { - "url": "https://github.com/sponsors/Boshen" - } - }, "node_modules/oxc-resolver": { - "version": "11.23.0", - "resolved": "https://registry.npmjs.org/oxc-resolver/-/oxc-resolver-11.23.0.tgz", - "integrity": "sha512-f0+l598CJMOLnYPXsXxttJALH0ljtivdRMKtvHhxRuWa5FYmw5+qODARl8oYjMC/brpzKcrpdORsOBrTqhBZ9A==", + "version": "11.24.2", + "resolved": "https://registry.npmjs.org/oxc-resolver/-/oxc-resolver-11.24.2.tgz", + "integrity": "sha512-FY91FiDBj7ls5MsFS9jN3tjz2o0/zsdSsymlakySaBwVJZorHhkWyICLZMKxlu1R9vYo+sd3z1jwb4J8x7bNDw==", "dev": true, "license": "MIT", "funding": { "url": "https://github.com/sponsors/Boshen" }, "optionalDependencies": { - "@oxc-resolver/binding-android-arm-eabi": "11.23.0", - "@oxc-resolver/binding-android-arm64": "11.23.0", - "@oxc-resolver/binding-darwin-arm64": "11.23.0", - "@oxc-resolver/binding-darwin-x64": "11.23.0", - "@oxc-resolver/binding-freebsd-x64": "11.23.0", - "@oxc-resolver/binding-linux-arm-gnueabihf": "11.23.0", - "@oxc-resolver/binding-linux-arm-musleabihf": "11.23.0", - "@oxc-resolver/binding-linux-arm64-gnu": "11.23.0", - "@oxc-resolver/binding-linux-arm64-musl": "11.23.0", - "@oxc-resolver/binding-linux-ppc64-gnu": "11.23.0", - "@oxc-resolver/binding-linux-riscv64-gnu": "11.23.0", - "@oxc-resolver/binding-linux-riscv64-musl": "11.23.0", - "@oxc-resolver/binding-linux-s390x-gnu": "11.23.0", - "@oxc-resolver/binding-linux-x64-gnu": "11.23.0", - "@oxc-resolver/binding-linux-x64-musl": "11.23.0", - "@oxc-resolver/binding-openharmony-arm64": "11.23.0", - "@oxc-resolver/binding-wasm32-wasi": "11.23.0", - "@oxc-resolver/binding-win32-arm64-msvc": "11.23.0", - "@oxc-resolver/binding-win32-x64-msvc": "11.23.0" + "@oxc-resolver/binding-android-arm-eabi": "11.24.2", + "@oxc-resolver/binding-android-arm64": "11.24.2", + "@oxc-resolver/binding-darwin-arm64": "11.24.2", + "@oxc-resolver/binding-darwin-x64": "11.24.2", + "@oxc-resolver/binding-freebsd-x64": "11.24.2", + "@oxc-resolver/binding-linux-arm-gnueabihf": "11.24.2", + "@oxc-resolver/binding-linux-arm-musleabihf": "11.24.2", + "@oxc-resolver/binding-linux-arm64-gnu": "11.24.2", + "@oxc-resolver/binding-linux-arm64-musl": "11.24.2", + "@oxc-resolver/binding-linux-ppc64-gnu": "11.24.2", + "@oxc-resolver/binding-linux-riscv64-gnu": "11.24.2", + "@oxc-resolver/binding-linux-riscv64-musl": "11.24.2", + "@oxc-resolver/binding-linux-s390x-gnu": "11.24.2", + "@oxc-resolver/binding-linux-x64-gnu": "11.24.2", + "@oxc-resolver/binding-linux-x64-musl": "11.24.2", + "@oxc-resolver/binding-openharmony-arm64": "11.24.2", + "@oxc-resolver/binding-wasm32-wasi": "11.24.2", + "@oxc-resolver/binding-win32-arm64-msvc": "11.24.2", + "@oxc-resolver/binding-win32-x64-msvc": "11.24.2" } }, "node_modules/p-limit": { @@ -6380,6 +6271,18 @@ "node": ">= 14.16" } }, + "node_modules/pdfjs-dist": { + "version": "6.2.108", + "resolved": "https://registry.npmjs.org/pdfjs-dist/-/pdfjs-dist-6.2.108.tgz", + "integrity": "sha512-YxFb+SQcodN2rnX9Tn3dHYlqfb7NjlzzfONPpJd+AKoKtUjEdevTfbC07d5TcczzOK6261auRkP/M8OBHs9vFQ==", + "license": "Apache-2.0", + "engines": { + "node": ">=22.13.0 || >=24" + }, + "optionalDependencies": { + "@napi-rs/canvas": "^1.0.0" + } + }, "node_modules/picocolors": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz", @@ -6445,7 +6348,6 @@ "integrity": "sha512-Qb1gy5OrP5+zDf2Bvnzdl3jsTf1qXVMazbvCoKhtKqVs4/YK4ozX4gKQJJVyNe+cajNPn0KoC0MC3FUmaHWEmQ==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "ansi-regex": "^5.0.1", "ansi-styles": "^5.0.0", @@ -6466,9 +6368,9 @@ } }, "node_modules/pure-rand": { - "version": "8.4.0", - "resolved": "https://registry.npmjs.org/pure-rand/-/pure-rand-8.4.0.tgz", - "integrity": "sha512-IoM8YF/jY0hiugFo/wOWqfmarlE6J0wc6fDK1PhftMk7MGhVZl88sZimmqBBFomLOCSmcCCpsfj7wXASCpvK9A==", + "version": "8.4.2", + "resolved": "https://registry.npmjs.org/pure-rand/-/pure-rand-8.4.2.tgz", + "integrity": "sha512-vvuOGgcuPJAirlHvuQw1TrOiw7ptaIXXmIbNuiNOY6lNGJJH49PQ1Kj4nd783nPdQhQdicgOjVI2yI/9BD6/Ng==", "dev": true, "funding": [ { @@ -6483,9 +6385,9 @@ "license": "MIT" }, "node_modules/react": { - "version": "19.2.7", - "resolved": "https://registry.npmjs.org/react/-/react-19.2.7.tgz", - "integrity": "sha512-HNe9WslTbXmFK8o8cmwgAeJFSBvt1bPdHCVKtaaV+WlAN36mpT4hcRpwbf3fY56ar2oIXzsBpOAiIRHAdY0OlQ==", + "version": "19.2.8", + "resolved": "https://registry.npmjs.org/react/-/react-19.2.8.tgz", + "integrity": "sha512-PWaYA1L/q9u2u7xYQi+Y3L3Yfnie7XyLeaJICV1MGD6LprsBxcAqGjYyr0eY3p+QdsA+x/Irkt4Qif8D63+Sbw==", "license": "MIT", "engines": { "node": ">=0.10.0" @@ -6523,29 +6425,16 @@ "typescript": ">= 4.3.x" } }, - "node_modules/react-docgen/node_modules/strip-indent": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/strip-indent/-/strip-indent-4.1.1.tgz", - "integrity": "sha512-SlyRoSkdh1dYP0PzclLE7r0M9sgbFKKMFXpFRUMNuKhQSbC6VQIGzq3E0qsfvGJaUFJPGv6Ws1NZ/haTAjfbMA==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, "node_modules/react-dom": { - "version": "19.2.7", - "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-19.2.7.tgz", - "integrity": "sha512-t0BRVXvbiE/o20Hfw669rLbMCDWtYZLvmJigy2f0MxsXF+71pxhR3xOkspmsO8h3ZlNzyibAmtCa3l4lYKk6gQ==", + "version": "19.2.8", + "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-19.2.8.tgz", + "integrity": "sha512-rVprimfGBG3DR+Tq0IQG2DT5PxKth1WIGDmj5yPmlzr4YBe7uyE+Du4oVqTDXZSHGGGXRtTJEGSSePyQCMBglQ==", "license": "MIT", "dependencies": { "scheduler": "^0.27.0" }, "peerDependencies": { - "react": "^19.2.7" + "react": "^19.2.8" } }, "node_modules/react-is": { @@ -6553,13 +6442,12 @@ "resolved": "https://registry.npmjs.org/react-is/-/react-is-17.0.2.tgz", "integrity": "sha512-w2GsyukL62IJnlaff/nRegPQR94C/XXamvMWmSHRJ4y7Ts/4ocGRmTHvOs8PSE6pB3dWOrD/nueuU5sduBsQ4w==", "dev": true, - "license": "MIT", - "peer": true + "license": "MIT" }, "node_modules/recast": { - "version": "0.23.12", - "resolved": "https://registry.npmjs.org/recast/-/recast-0.23.12.tgz", - "integrity": "sha512-dEWRjcINDu/F4l2dYx57ugBtD7HV9KXESyxhzw/MqWLeglJrsjJKqACPyUPg+6AF8mIgm+Zi0dZ3ACoIg+QtpA==", + "version": "0.23.19", + "resolved": "https://registry.npmjs.org/recast/-/recast-0.23.19.tgz", + "integrity": "sha512-T98lym7kH+pnZmRaD8yDRdaNqyUbwnbEBx0MuchrzMFOEMray4AO3ZJoTUZ5r78Ao78X/OhzW0DL8GB85w/I2w==", "dev": true, "license": "MIT", "dependencies": { @@ -6587,12 +6475,25 @@ "node": ">=8" } }, - "node_modules/require-from-string": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/require-from-string/-/require-from-string-2.0.2.tgz", - "integrity": "sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==", - "dev": true, - "license": "MIT", + "node_modules/redent/node_modules/strip-indent": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/strip-indent/-/strip-indent-3.0.0.tgz", + "integrity": "sha512-laJTa3Jb+VQpaC6DseHhF7dXVqHTfJPCRDaEbid/drOhgitgYku/letMUqOXFoWV0zIIUbjpdH2t+tYj4bQMRQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "min-indent": "^1.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/require-from-string": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/require-from-string/-/require-from-string-2.0.2.tgz", + "integrity": "sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==", + "dev": true, + "license": "MIT", "engines": { "node": ">=0.10.0" } @@ -6639,13 +6540,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.3", + "resolved": "https://registry.npmjs.org/rolldown/-/rolldown-1.2.3.tgz", + "integrity": "sha512-rn9wpmxplLf7NLNyCk9FyWh3FM43DbY8jOzCdEPzH7uflhTftRbCEpqi6Ly2osgoU8OwObtmavMbWLaWy4LX7A==", "dev": true, "license": "MIT", "dependencies": { - "@oxc-project/types": "=0.139.0", + "@oxc-project/types": "=0.143.0", "@rolldown/pluginutils": "^1.0.0" }, "bin": { @@ -6655,21 +6556,30 @@ "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-arm64": "1.2.3", + "@rolldown/binding-darwin-arm64": "1.2.3", + "@rolldown/binding-darwin-x64": "1.2.3", + "@rolldown/binding-freebsd-x64": "1.2.3", + "@rolldown/binding-linux-arm-gnueabihf": "1.2.3", + "@rolldown/binding-linux-arm64-gnu": "1.2.3", + "@rolldown/binding-linux-arm64-musl": "1.2.3", + "@rolldown/binding-linux-ppc64-gnu": "1.2.3", + "@rolldown/binding-linux-s390x-gnu": "1.2.3", + "@rolldown/binding-linux-x64-gnu": "1.2.3", + "@rolldown/binding-linux-x64-musl": "1.2.3", + "@rolldown/binding-openharmony-arm64": "1.2.3", + "@rolldown/binding-win32-arm64-msvc": "1.2.3", + "@rolldown/binding-win32-x64-msvc": "1.2.3" + } + }, + "node_modules/rolldown/node_modules/@oxc-project/types": { + "version": "0.143.0", + "resolved": "https://registry.npmjs.org/@oxc-project/types/-/types-0.143.0.tgz", + "integrity": "sha512-u6JZdLBTLotrNC9Vd6vPssINdzcCzleKAH6EJKImQb7GtYvX5keN2dxkoK44stCc4tffE6QQRtZTXVSzsLUlWA==", + "dev": true, + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/Boshen" } }, "node_modules/run-applescript": { @@ -6748,13 +6658,19 @@ "license": "ISC" }, "node_modules/sonner": { - "version": "2.0.7", - "resolved": "https://registry.npmjs.org/sonner/-/sonner-2.0.7.tgz", - "integrity": "sha512-W6ZN4p58k8aDKA4XPcx2hpIQXBRAgyiWVkYhT7CvK6D3iAu7xjvVyhQHg2/iaKJZ1XVJ4r7XuwGL+WGEK37i9w==", + "version": "2.0.8", + "resolved": "https://registry.npmjs.org/sonner/-/sonner-2.0.8.tgz", + "integrity": "sha512-UM/ByIoFra8yzV75n1o0Puu0bw5U/9UNnDacrJNspekBewIfsQ3D6ez1nvlWpt7aTsO6rujQtifBpycwIivqlg==", "license": "MIT", "peerDependencies": { + "@types/react": "^18.0.0 || ^19.0.0", "react": "^18.0.0 || ^19.0.0 || ^19.0.0-rc", "react-dom": "^18.0.0 || ^19.0.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } } }, "node_modules/source-map": { @@ -6785,9 +6701,9 @@ "license": "CC-BY-3.0" }, "node_modules/spdx-expression-parse": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/spdx-expression-parse/-/spdx-expression-parse-4.0.0.tgz", - "integrity": "sha512-Clya5JIij/7C6bRR22+tnGXbc4VKlibKSVj2iHvVeX5iMW7s1SIQlqu699JkODJJIhh/pUu8L0/VLh8xflD+LQ==", + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/spdx-expression-parse/-/spdx-expression-parse-5.0.0.tgz", + "integrity": "sha512-vngmw3Rgn+o2arXNbnZaj5UtOEBuWBfvaI+Wc8GFfykIhA5/vdK9/Sp/XkLv63dykz2rxKDvKEHupF5P0FORcQ==", "dev": true, "license": "MIT", "dependencies": { @@ -6810,34 +6726,36 @@ "license": "MIT" }, "node_modules/std-env": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/std-env/-/std-env-4.1.0.tgz", - "integrity": "sha512-Rq7ybcX2RuC55r9oaPVEW7/xu3tj8u4GeBYHBWCychFtzMIr86A7e3PPEBPT37sHStKX3+TiX/Fr/ACmJLVlLQ==", + "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/storybook": { - "version": "10.4.6", - "resolved": "https://registry.npmjs.org/storybook/-/storybook-10.4.6.tgz", - "integrity": "sha512-6wkA6LxfDSSilloITsrFOJfsnw0mDUP2h8Ls+lRt8oRsudtz2RWFhLv+Toiwg6NW7hUpdTDc2hzR7DztJid6+A==", + "version": "10.5.7", + "resolved": "https://registry.npmjs.org/storybook/-/storybook-10.5.7.tgz", + "integrity": "sha512-oiKvWIwIoOhFP1i6dASYyMXwPHKEtVZMshqSB7EvIVYjWRh0l9H7gHEt1z4Gh2rLGFMekWdsm4s94rvwpR7gkg==", "dev": true, "license": "MIT", "dependencies": { "@storybook/global": "^5.0.0", "@storybook/icons": "^2.0.2", - "@testing-library/jest-dom": "^6.9.1", + "@testing-library/dom": "^10.4.1", + "@testing-library/jest-dom": "6.9.1", "@testing-library/user-event": "^14.6.1", "@vitest/expect": "3.2.4", "@vitest/spy": "3.2.4", "@webcontainer/env": "^1.1.1", "esbuild": "^0.18.0 || ^0.19.0 || ^0.20.0 || ^0.21.0 || ^0.22.0 || ^0.23.0 || ^0.24.0 || ^0.25.0 || ^0.26.0 || ^0.27.0 || ^0.28.0", + "jsonc-parser": "^3.3.1", "open": "^10.2.0", "oxc-parser": "^0.127.0", "oxc-resolver": "^11.19.1", "recast": "^0.23.5", "semver": "^7.7.3", "use-sync-external-store": "^1.5.0", - "ws": "^8.18.0" + "ws": "^8.21.1" }, "bin": { "storybook": "dist/bin/dispatcher.js" @@ -6849,7 +6767,7 @@ "peerDependencies": { "@types/react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0", "prettier": "^2 || ^3", - "vite-plus": "^0.1.15" + "vite-plus": "^0.1.15 || ^0.2.0" }, "peerDependenciesMeta": { "@types/react": { @@ -6874,16 +6792,16 @@ } }, "node_modules/strip-indent": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/strip-indent/-/strip-indent-3.0.0.tgz", - "integrity": "sha512-laJTa3Jb+VQpaC6DseHhF7dXVqHTfJPCRDaEbid/drOhgitgYku/letMUqOXFoWV0zIIUbjpdH2t+tYj4bQMRQ==", + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/strip-indent/-/strip-indent-4.1.1.tgz", + "integrity": "sha512-SlyRoSkdh1dYP0PzclLE7r0M9sgbFKKMFXpFRUMNuKhQSbC6VQIGzq3E0qsfvGJaUFJPGv6Ws1NZ/haTAjfbMA==", "dev": true, "license": "MIT", - "dependencies": { - "min-indent": "^1.0.0" - }, "engines": { - "node": ">=8" + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, "node_modules/supports-color": { @@ -6930,9 +6848,9 @@ } }, "node_modules/tailwindcss": { - "version": "4.3.2", - "resolved": "https://registry.npmjs.org/tailwindcss/-/tailwindcss-4.3.2.tgz", - "integrity": "sha512-WtctNNSH8A9jlMIqxzuYumOHU5uGZyRv0Q5svQl+oEPy5w84YpBxdb7MdqyiSPQge5jTJ6zFQLq0PFygdccSBA==", + "version": "4.3.3", + "resolved": "https://registry.npmjs.org/tailwindcss/-/tailwindcss-4.3.3.tgz", + "integrity": "sha512-gOhV3P7ufE62QDGg1zVaTgCR+EtPv92k2nIhVcVKcLmxT1sUBsQGhnZj175j+MqRt4zLF7ic+sCYjfhxMxj7YQ==", "dev": true, "license": "MIT" }, @@ -6965,9 +6883,9 @@ "license": "MIT" }, "node_modules/tinyexec": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/tinyexec/-/tinyexec-1.1.2.tgz", - "integrity": "sha512-dAqSqE/RabpBKI8+h26GfLq6Vb3JVXs30XYQjdMjaj/c2tS8IYYMbIzP599KtRj7c57/wYApb3QjgRgXmrCukA==", + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/tinyexec/-/tinyexec-1.3.0.tgz", + "integrity": "sha512-QKAl9m8gWWGHV8jZcPeym6j+XULi6tOf1mT83WYJ4Lk2ytW/uwAWkrP0uFsdoYMdueVJ0qs26wZ+23xeB4ibNQ==", "dev": true, "license": "MIT", "engines": { @@ -6992,9 +6910,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.1.1", + "resolved": "https://registry.npmjs.org/tinyrainbow/-/tinyrainbow-3.1.1.tgz", + "integrity": "sha512-yau8yJdTt989Mm0Bd/236QnzEiPf2xLLTqUZRUJOo/3CB078LSwzei343DgtJVmfJKJE3TMINY1u42SQsP6mXw==", "dev": true, "license": "MIT", "engines": { @@ -7012,22 +6930,22 @@ } }, "node_modules/tldts": { - "version": "7.0.27", - "resolved": "https://registry.npmjs.org/tldts/-/tldts-7.0.27.tgz", - "integrity": "sha512-I4FZcVFcqCRuT0ph6dCDpPuO4Xgzvh+spkcTr1gK7peIvxWauoloVO0vuy1FQnijT63ss6AsHB6+OIM4aXHbPg==", + "version": "7.4.10", + "resolved": "https://registry.npmjs.org/tldts/-/tldts-7.4.10.tgz", + "integrity": "sha512-GgouD1B+sWwvkaEq8vXC15DjQitxbvs12oIXELpconwm+Tg3zfcEv4jgzq3vtKverDXsg3VI8aRgNL2Nra0Iog==", "dev": true, "license": "MIT", "dependencies": { - "tldts-core": "^7.0.27" + "tldts-core": "^7.4.10" }, "bin": { "tldts": "bin/cli.js" } }, "node_modules/tldts-core": { - "version": "7.0.27", - "resolved": "https://registry.npmjs.org/tldts-core/-/tldts-core-7.0.27.tgz", - "integrity": "sha512-YQ7uPjgWUibIK6DW5lrKujGwUKhLevU4hcGbP5O6TcIUb+oTjJYJVWPS4nZsIHrEEEG6myk/oqAJUEQmpZrHsg==", + "version": "7.4.10", + "resolved": "https://registry.npmjs.org/tldts-core/-/tldts-core-7.4.10.tgz", + "integrity": "sha512-KnQjp53ZekKgm/r3l+u8kJGGzYgrWdP8+Mql7a4vijh2WE0IrZWspQj/TpTxDho/YxO+AnOZnIjQcCD+q6iJsw==", "dev": true, "license": "MIT" }, @@ -7049,9 +6967,9 @@ } }, "node_modules/tough-cookie": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-6.0.1.tgz", - "integrity": "sha512-LktZQb3IeoUWB9lqR5EWTHgW/VTITCXg4D21M+lvybRVdylLrRMnqaIONLVb5mav8vM19m44HIcGq4qASeu2Qw==", + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-6.0.2.tgz", + "integrity": "sha512-exgYmnmL/sJpR3upZfXG5PoatXQii55xAiXGXzY+sROLZ/Y+SLcp9PgJNI9Vz37HpQ74WvDcLT8eqm+kV3FzrA==", "dev": true, "license": "BSD-3-Clause", "dependencies": { @@ -7156,16 +7074,16 @@ } }, "node_modules/typescript-eslint": { - "version": "8.63.0", - "resolved": "https://registry.npmjs.org/typescript-eslint/-/typescript-eslint-8.63.0.tgz", - "integrity": "sha512-xgwXyzG4sK9ALkBxbyGkTMMOS+imnW65iPhxCQMK83KhxyoDNW7l+IDqEf9vMdoUidHpOoS967RCq4eMiTexwQ==", + "version": "8.66.0", + "resolved": "https://registry.npmjs.org/typescript-eslint/-/typescript-eslint-8.66.0.tgz", + "integrity": "sha512-QlEbBPz/RuJ1XUHj29nm3t0F/O/cSlEnntozqPOYHnnTGAXFamnMBu5i9Vn6vhUPHGAjR+Vl+5J8vPN/BMUrJw==", "dev": true, "license": "MIT", "dependencies": { - "@typescript-eslint/eslint-plugin": "8.63.0", - "@typescript-eslint/parser": "8.63.0", - "@typescript-eslint/typescript-estree": "8.63.0", - "@typescript-eslint/utils": "8.63.0" + "@typescript-eslint/eslint-plugin": "8.66.0", + "@typescript-eslint/parser": "8.66.0", + "@typescript-eslint/typescript-estree": "8.66.0", + "@typescript-eslint/utils": "8.66.0" }, "engines": { "node": "^18.18.0 || ^20.9.0 || >=21.1.0" @@ -7183,7 +7101,6 @@ "version": "7.29.0", "resolved": "https://registry.npmjs.org/undici/-/undici-7.29.0.tgz", "integrity": "sha512-IDxfleLmmbSskfWSUATiN1nfn2rDuvnMOqb5CWR92iIfojA0Ud+ulOAAEQ57LPr9rWmsreUyf5lwyao+7GNNVw==", - "dev": true, "license": "MIT", "engines": { "node": ">=20.18.1" @@ -7213,9 +7130,9 @@ } }, "node_modules/update-browserslist-db": { - "version": "1.2.3", - "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.2.3.tgz", - "integrity": "sha512-Js0m9cx+qOgDxo0eMiFGEueWztz+d4+M3rGlmKPT+T4IS/jP4ylw3Nwpu6cpTTP8R1MAC1kF4VbdLt3ARf209w==", + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.3.0.tgz", + "integrity": "sha512-x/M6q3w4Ybp91CNaS4S69UnliqR3BzRpOT6LWbksjth0S/+jhfaPJsWjt/TewpT8j9eLIojUf5jr29WextHroA==", "dev": true, "funding": [ { @@ -7263,16 +7180,16 @@ } }, "node_modules/vite": { - "version": "8.1.4", - "resolved": "https://registry.npmjs.org/vite/-/vite-8.1.4.tgz", - "integrity": "sha512-bTT9PsdWO+MQMNG9ZXIP/qM9wGh37DFxTV/sPq9cFpHr3w4jkgef032PkAL9jAqhk3Nz8NQw3O8n6/xFkqO4QQ==", + "version": "8.2.1", + "resolved": "https://registry.npmjs.org/vite/-/vite-8.2.1.tgz", + "integrity": "sha512-EU/eS7BH3XROHh2YnBefjM6DBKA6ZeMZEYQbj7NLWg5wHYlhB8B/Mayd5XsgWq+NFYccDOTemRpdETWR6Ka/lw==", "dev": true, "license": "MIT", "dependencies": { - "lightningcss": "^1.32.0", + "lightningcss": "^1.33.0", "picomatch": "^4.0.5", - "postcss": "^8.5.16", - "rolldown": "~1.1.4", + "postcss": "^8.5.25", + "rolldown": "~1.2.1", "tinyglobby": "^0.2.17" }, "bin": { @@ -7289,7 +7206,7 @@ }, "peerDependencies": { "@types/node": "^20.19.0 || >=22.12.0", - "@vitejs/devtools": "^0.3.0", + "@vitejs/devtools": "^0.4.0", "esbuild": "^0.27.0 || ^0.28.0", "jiti": ">=1.21.0", "less": "^4.0.0", @@ -7340,337 +7257,280 @@ } } }, - "node_modules/w3c-xmlserializer": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/w3c-xmlserializer/-/w3c-xmlserializer-5.0.0.tgz", - "integrity": "sha512-o8qghlI8NZHU1lLPrpi2+Uq7abh4GGPpYANlalzWxyWteJOCsr/P+oPBA49TOLu5FTZO4d3F9MnWJfiMo4BkmA==", + "node_modules/vite/node_modules/lightningcss": { + "version": "1.33.0", + "resolved": "https://registry.npmjs.org/lightningcss/-/lightningcss-1.33.0.tgz", + "integrity": "sha512-WkUDrojuJs0xkgGf2udWxa3yGBRxPtxUkB79i6aCZLRgc7PM8fZe9TosfPDcvEpQZbuFASnHYmRLBLUbmLOIIA==", "dev": true, - "license": "MIT", + "license": "MPL-2.0", "dependencies": { - "xml-name-validator": "^5.0.0" + "detect-libc": "^2.0.3" }, "engines": { - "node": ">=18" - } - }, - "node_modules/webidl-conversions": { - "version": "8.0.1", - "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-8.0.1.tgz", - "integrity": "sha512-BMhLD/Sw+GbJC21C/UgyaZX41nPt8bUTg+jWyDeg7e7YN4xOM05YPSIXceACnXVtqyEw/LMClUQMtMZ+PGGpqQ==", + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + }, + "optionalDependencies": { + "lightningcss-android-arm64": "1.33.0", + "lightningcss-darwin-arm64": "1.33.0", + "lightningcss-darwin-x64": "1.33.0", + "lightningcss-freebsd-x64": "1.33.0", + "lightningcss-linux-arm-gnueabihf": "1.33.0", + "lightningcss-linux-arm64-gnu": "1.33.0", + "lightningcss-linux-arm64-musl": "1.33.0", + "lightningcss-linux-x64-gnu": "1.33.0", + "lightningcss-linux-x64-musl": "1.33.0", + "lightningcss-win32-arm64-msvc": "1.33.0", + "lightningcss-win32-x64-msvc": "1.33.0" + } + }, + "node_modules/vite/node_modules/lightningcss-android-arm64": { + "version": "1.33.0", + "resolved": "https://registry.npmjs.org/lightningcss-android-arm64/-/lightningcss-android-arm64-1.33.0.tgz", + "integrity": "sha512-gEpRTalKdosp4Bb8qWtc2iOgE5SeIHlpS1up9bFq2wAyYhl1UdTObYiHe98zEM9SQvSoqQZ1IQD0JNpg3Ml5pg==", + "cpu": [ + "arm64" + ], "dev": true, - "license": "BSD-2-Clause", + "license": "MPL-2.0", + "optional": true, + "os": [ + "android" + ], "engines": { - "node": ">=20" + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" } }, - "node_modules/webpack-virtual-modules": { - "version": "0.6.2", - "resolved": "https://registry.npmjs.org/webpack-virtual-modules/-/webpack-virtual-modules-0.6.2.tgz", - "integrity": "sha512-66/V2i5hQanC51vBQKPH4aI8NMAcBW59FVBs+rC7eGHupMyfn34q7rZIE+ETlJ+XTevqfUhVVBgSUNSW2flEUQ==", - "dev": true, - "license": "MIT" - }, - "node_modules/whatwg-mimetype": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/whatwg-mimetype/-/whatwg-mimetype-5.0.0.tgz", - "integrity": "sha512-sXcNcHOC51uPGF0P/D4NVtrkjSU2fNsm9iog4ZvZJsL3rjoDAzXZhkm2MWt1y+PUdggKAYVoMAIYcs78wJ51Cw==", + "node_modules/vite/node_modules/lightningcss-darwin-arm64": { + "version": "1.33.0", + "resolved": "https://registry.npmjs.org/lightningcss-darwin-arm64/-/lightningcss-darwin-arm64-1.33.0.tgz", + "integrity": "sha512-Sciaz8eenNTKn9b3t7+xr0ipTp9YxKQY4npwQ3mrRuL0BAVHBLyZxofhaKBAVtzmtRZ/zTyo0/to4B1uWG/Djg==", + "cpu": [ + "arm64" + ], "dev": true, - "license": "MIT", + "license": "MPL-2.0", + "optional": true, + "os": [ + "darwin" + ], "engines": { - "node": ">=20" - } - }, - "node_modules/whatwg-url": { - "version": "16.0.1", - "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-16.0.1.tgz", - "integrity": "sha512-1to4zXBxmXHV3IiSSEInrreIlu02vUOvrhxJJH5vcxYTBDAx51cqZiKdyTxlecdKNSjj8EcxGBxNf6Vg+945gw==", - "dev": true, - "license": "MIT", - "dependencies": { - "@exodus/bytes": "^1.11.0", - "tr46": "^6.0.0", - "webidl-conversions": "^8.0.1" + "node": ">= 12.0.0" }, - "engines": { - "node": "^20.19.0 || ^22.12.0 || >=24.0.0" + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" } }, - "node_modules/which": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", - "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", + "node_modules/vite/node_modules/lightningcss-darwin-x64": { + "version": "1.33.0", + "resolved": "https://registry.npmjs.org/lightningcss-darwin-x64/-/lightningcss-darwin-x64-1.33.0.tgz", + "integrity": "sha512-Z5UPAxzrjlWNNyGy6i65cJzzvgJ5D3T6wMvs+gWpY9d7qRhANrxqAp6LhxIgZhWEw18RfJTGcRxjuLIBr+m8XQ==", + "cpu": [ + "x64" + ], "dev": true, - "license": "ISC", - "dependencies": { - "isexe": "^2.0.0" - }, - "bin": { - "node-which": "bin/node-which" - }, + "license": "MPL-2.0", + "optional": true, + "os": [ + "darwin" + ], "engines": { - "node": ">= 8" + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" } }, - "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==", + "node_modules/vite/node_modules/lightningcss-freebsd-x64": { + "version": "1.33.0", + "resolved": "https://registry.npmjs.org/lightningcss-freebsd-x64/-/lightningcss-freebsd-x64-1.33.0.tgz", + "integrity": "sha512-QQM/Ti/hQajJwCY+RiWuCZ9sdtI/XQk7nDK5vC8kkdwixezOlDgvDx7+RT+QjK6FcFT4MpsuoBnHIo/O3StRRg==", + "cpu": [ + "x64" + ], "dev": true, - "license": "MIT", - "dependencies": { - "siginfo": "^2.0.0", - "stackback": "0.0.2" - }, - "bin": { - "why-is-node-running": "cli.js" - }, + "license": "MPL-2.0", + "optional": true, + "os": [ + "freebsd" + ], "engines": { - "node": ">=8" + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" } }, - "node_modules/word-wrap": { - "version": "1.2.5", - "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.5.tgz", - "integrity": "sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA==", + "node_modules/vite/node_modules/lightningcss-linux-arm-gnueabihf": { + "version": "1.33.0", + "resolved": "https://registry.npmjs.org/lightningcss-linux-arm-gnueabihf/-/lightningcss-linux-arm-gnueabihf-1.33.0.tgz", + "integrity": "sha512-N7FVBe6iS24MlM6R/4RBTxGhQheZGs7tiQ9U32UtF75NzP5Q7xWPRqLBCKxlRQRk3rY1jCIPLzx7WzOhuUIRLQ==", + "cpu": [ + "arm" + ], "dev": true, - "license": "MIT", + "license": "MPL-2.0", + "optional": true, + "os": [ + "linux" + ], "engines": { - "node": ">=0.10.0" + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" } }, - "node_modules/ws": { - "version": "8.21.0", - "resolved": "https://registry.npmjs.org/ws/-/ws-8.21.0.tgz", - "integrity": "sha512-Vsp28b7DRcimFQvrqu2Wek3z1iYxDCWqHYB8Qsnk/S4RfaCQzPGPyBNuVjJV3cd6UiKtUtp6sNM77gWvzcCH+g==", + "node_modules/vite/node_modules/lightningcss-linux-arm64-gnu": { + "version": "1.33.0", + "resolved": "https://registry.npmjs.org/lightningcss-linux-arm64-gnu/-/lightningcss-linux-arm64-gnu-1.33.0.tgz", + "integrity": "sha512-j2v/itmy4HlNxlc6voKXYgBqNi0Ng2LShg4z7GufpEgs05P+2suBVyi9I6YHq5uoVFx9ETin3eCEhLVyXGQnKg==", + "cpu": [ + "arm64" + ], "dev": true, - "license": "MIT", + "libc": [ + "glibc" + ], + "license": "MPL-2.0", + "optional": true, + "os": [ + "linux" + ], "engines": { - "node": ">=10.0.0" - }, - "peerDependencies": { - "bufferutil": "^4.0.1", - "utf-8-validate": ">=5.0.2" + "node": ">= 12.0.0" }, - "peerDependenciesMeta": { - "bufferutil": { - "optional": true - }, - "utf-8-validate": { - "optional": true - } + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" } }, - "node_modules/wsl-utils": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/wsl-utils/-/wsl-utils-0.1.0.tgz", - "integrity": "sha512-h3Fbisa2nKGPxCpm89Hk33lBLsnaGBvctQopaBSOW/uIs6FTe1ATyAnKFJrzVs9vpGdsTe73WF3V4lIsk4Gacw==", + "node_modules/vite/node_modules/lightningcss-linux-arm64-musl": { + "version": "1.33.0", + "resolved": "https://registry.npmjs.org/lightningcss-linux-arm64-musl/-/lightningcss-linux-arm64-musl-1.33.0.tgz", + "integrity": "sha512-yiO5ROMuYQgXbC60yjZU5CYSFZGKXL0HFATXt9mHJn1+zW55oCtMI9NfcVhYLMFDL7gV7oBPon/EmMMGg2OvtQ==", + "cpu": [ + "arm64" + ], "dev": true, - "license": "MIT", - "dependencies": { - "is-wsl": "^3.1.0" - }, + "libc": [ + "musl" + ], + "license": "MPL-2.0", + "optional": true, + "os": [ + "linux" + ], "engines": { - "node": ">=18" + "node": ">= 12.0.0" }, "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "type": "opencollective", + "url": "https://opencollective.com/parcel" } }, - "node_modules/xml-name-validator": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/xml-name-validator/-/xml-name-validator-5.0.0.tgz", - "integrity": "sha512-EvGK8EJ3DhaHfbRlETOWAS5pO9MZITeauHKJyb8wyajUfQUenkIg2MvLDTZ4T/TgIcm3HU0TFBgWWboAZ30UHg==", - "dev": true, - "license": "Apache-2.0", - "engines": { - "node": ">=18" - } - }, - "node_modules/xmlchars": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/xmlchars/-/xmlchars-2.2.0.tgz", - "integrity": "sha512-JZnDKK8B0RCDw84FNdDAIpZK+JuJw+s7Lz8nksI7SIuU3UXJJslUthsi+uWBUYOwPFwW7W7PRLRfUKpxjtjFCw==", - "dev": true, - "license": "MIT" - }, - "node_modules/yallist": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz", - "integrity": "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==", - "dev": true, - "license": "ISC" - }, - "node_modules/yocto-queue": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz", - "integrity": "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==", + "node_modules/vite/node_modules/lightningcss-linux-x64-gnu": { + "version": "1.33.0", + "resolved": "https://registry.npmjs.org/lightningcss-linux-x64-gnu/-/lightningcss-linux-x64-gnu-1.33.0.tgz", + "integrity": "sha512-ar+Ju7LmcN0Jo4FpL4hpFybwNG9/3A/Br5KW2n2jyODg3MEZXaDYADdemoNS+BDNfMgKvylJLj4S5tyRActuAg==", + "cpu": [ + "x64" + ], "dev": true, - "license": "MIT", + "libc": [ + "glibc" + ], + "license": "MPL-2.0", + "optional": true, + "os": [ + "linux" + ], "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "packages/shared-types": { - "name": "@bandscope/shared-types", - "version": "0.1.0", - "devDependencies": { - "@types/node": "^26.1.1", - "@vitest/coverage-v8": "^4.1.10", - "eslint": "^10.7.0", - "fast-check": "^4.8.0", - "typescript": "^6.0.3", - "typescript-eslint": "^8.63.0", - "vitest": "^4.1.10" - } - }, - "packages/shared-types/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==", - "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" - }, - "funding": { - "url": "https://opencollective.com/vitest" - }, - "peerDependencies": { - "@vitest/browser": "4.1.10", - "vitest": "4.1.10" - }, - "peerDependenciesMeta": { - "@vitest/browser": { - "optional": true - } - } - }, - "packages/shared-types/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==", - "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" - }, - "funding": { - "url": "https://opencollective.com/vitest" - } - }, - "packages/shared-types/node_modules/@vitest/mocker": { - "version": "4.1.10", - "resolved": "https://registry.npmjs.org/@vitest/mocker/-/mocker-4.1.10.tgz", - "integrity": "sha512-v0xaezt+DKEmKfaxg133ldzADrwLGd7Ze1MfQQTYfvs8OqZIwbxyxaYURivwV7sWy5fqn3rH5uOrSp07bp44Ow==", - "dev": true, - "license": "MIT", - "dependencies": { - "@vitest/spy": "4.1.10", - "estree-walker": "^3.0.3", - "magic-string": "^0.30.21" - }, - "funding": { - "url": "https://opencollective.com/vitest" - }, - "peerDependencies": { - "msw": "^2.4.9", - "vite": "^6.0.0 || ^7.0.0 || ^8.0.0" - }, - "peerDependenciesMeta": { - "msw": { - "optional": true - }, - "vite": { - "optional": true - } - } - }, - "packages/shared-types/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" + "node": ">= 12.0.0" }, "funding": { - "url": "https://opencollective.com/vitest" + "type": "opencollective", + "url": "https://opencollective.com/parcel" } }, - "packages/shared-types/node_modules/@vitest/runner": { - "version": "4.1.10", - "resolved": "https://registry.npmjs.org/@vitest/runner/-/runner-4.1.10.tgz", - "integrity": "sha512-IKI6kpIH+LmpROplyLwBBaCfMgOZOMsygVa6BARD6ahA04VRuJSa6OaVG7kRvSEMD870Vd91rSSw0eegtWyLGg==", + "node_modules/vite/node_modules/lightningcss-linux-x64-musl": { + "version": "1.33.0", + "resolved": "https://registry.npmjs.org/lightningcss-linux-x64-musl/-/lightningcss-linux-x64-musl-1.33.0.tgz", + "integrity": "sha512-RYiYbkokw0trfKqqzfF55lginwEPrD3OJDfTuJzFs1MK6iFnDenaz1fqLLtX4ITG3OktJQXOeTaw1awrBAlZPw==", + "cpu": [ + "x64" + ], "dev": true, - "license": "MIT", - "dependencies": { - "@vitest/utils": "4.1.10", - "pathe": "^2.0.3" + "libc": [ + "musl" + ], + "license": "MPL-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 12.0.0" }, "funding": { - "url": "https://opencollective.com/vitest" + "type": "opencollective", + "url": "https://opencollective.com/parcel" } }, - "packages/shared-types/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==", + "node_modules/vite/node_modules/lightningcss-win32-arm64-msvc": { + "version": "1.33.0", + "resolved": "https://registry.npmjs.org/lightningcss-win32-arm64-msvc/-/lightningcss-win32-arm64-msvc-1.33.0.tgz", + "integrity": "sha512-1K+MPfLSFVpphzpdbfkhlWk6wBrTObBzS2T6db10PNOZgR9GoVsAWzwNyuhUYYbTp23j+4RrncfujZ4uAzXvwA==", + "cpu": [ + "arm64" + ], "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" + "license": "MPL-2.0", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 12.0.0" }, "funding": { - "url": "https://opencollective.com/vitest" - } - }, - "packages/shared-types/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" + "type": "opencollective", + "url": "https://opencollective.com/parcel" } }, - "packages/shared-types/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==", + "node_modules/vite/node_modules/lightningcss-win32-x64-msvc": { + "version": "1.33.0", + "resolved": "https://registry.npmjs.org/lightningcss-win32-x64-msvc/-/lightningcss-win32-x64-msvc-1.33.0.tgz", + "integrity": "sha512-OlEICDx/Xl0FqSp4bry8zFnCvGpig3Gl4gCquvYwHuqJKEC1+n9NgDniFvqHGmMv1ZkqDJrDqKKSykTDX+ehuA==", + "cpu": [ + "x64" + ], "dev": true, - "license": "MIT", - "dependencies": { - "@vitest/pretty-format": "4.1.10", - "convert-source-map": "^2.0.0", - "tinyrainbow": "^3.1.0" + "license": "MPL-2.0", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 12.0.0" }, "funding": { - "url": "https://opencollective.com/vitest" + "type": "opencollective", + "url": "https://opencollective.com/parcel" } }, - "packages/shared-types/node_modules/vitest": { + "node_modules/vitest": { "version": "4.1.10", "resolved": "https://registry.npmjs.org/vitest/-/vitest-4.1.10.tgz", "integrity": "sha512-R9jUTe5S4Qb0HCd4TNqpC7oGcrMssMRGXLW80ubjWsW9VH5GF8y1Y0SFLY9AbqSk6nt0PnOx4H4WNJYZ13GUPw==", @@ -7759,6 +7619,230 @@ "optional": false } } + }, + "node_modules/vitest/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==", + "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" + }, + "funding": { + "url": "https://opencollective.com/vitest" + } + }, + "node_modules/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/node_modules/chai": { + "version": "6.2.2", + "resolved": "https://registry.npmjs.org/chai/-/chai-6.2.2.tgz", + "integrity": "sha512-NUPRluOfOiTKBKvWPtSD4PhFvWCqOi0BGStNWs57X9js7XGTprSmFoz5F0tWhR4WPjNeR9jXqdC7/UpSJTnlRg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + } + }, + "node_modules/w3c-xmlserializer": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/w3c-xmlserializer/-/w3c-xmlserializer-5.0.0.tgz", + "integrity": "sha512-o8qghlI8NZHU1lLPrpi2+Uq7abh4GGPpYANlalzWxyWteJOCsr/P+oPBA49TOLu5FTZO4d3F9MnWJfiMo4BkmA==", + "dev": true, + "license": "MIT", + "dependencies": { + "xml-name-validator": "^5.0.0" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/webidl-conversions": { + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-8.0.1.tgz", + "integrity": "sha512-BMhLD/Sw+GbJC21C/UgyaZX41nPt8bUTg+jWyDeg7e7YN4xOM05YPSIXceACnXVtqyEw/LMClUQMtMZ+PGGpqQ==", + "dev": true, + "license": "BSD-2-Clause", + "engines": { + "node": ">=20" + } + }, + "node_modules/webpack-virtual-modules": { + "version": "0.6.2", + "resolved": "https://registry.npmjs.org/webpack-virtual-modules/-/webpack-virtual-modules-0.6.2.tgz", + "integrity": "sha512-66/V2i5hQanC51vBQKPH4aI8NMAcBW59FVBs+rC7eGHupMyfn34q7rZIE+ETlJ+XTevqfUhVVBgSUNSW2flEUQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/whatwg-mimetype": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/whatwg-mimetype/-/whatwg-mimetype-5.0.0.tgz", + "integrity": "sha512-sXcNcHOC51uPGF0P/D4NVtrkjSU2fNsm9iog4ZvZJsL3rjoDAzXZhkm2MWt1y+PUdggKAYVoMAIYcs78wJ51Cw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=20" + } + }, + "node_modules/whatwg-url": { + "version": "16.0.1", + "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-16.0.1.tgz", + "integrity": "sha512-1to4zXBxmXHV3IiSSEInrreIlu02vUOvrhxJJH5vcxYTBDAx51cqZiKdyTxlecdKNSjj8EcxGBxNf6Vg+945gw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@exodus/bytes": "^1.11.0", + "tr46": "^6.0.0", + "webidl-conversions": "^8.0.1" + }, + "engines": { + "node": "^20.19.0 || ^22.12.0 || >=24.0.0" + } + }, + "node_modules/which": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", + "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", + "dev": true, + "license": "ISC", + "dependencies": { + "isexe": "^2.0.0" + }, + "bin": { + "node-which": "bin/node-which" + }, + "engines": { + "node": ">= 8" + } + }, + "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==", + "dev": true, + "license": "MIT", + "dependencies": { + "siginfo": "^2.0.0", + "stackback": "0.0.2" + }, + "bin": { + "why-is-node-running": "cli.js" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/word-wrap": { + "version": "1.2.5", + "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.5.tgz", + "integrity": "sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/ws": { + "version": "8.21.3", + "resolved": "https://registry.npmjs.org/ws/-/ws-8.21.3.tgz", + "integrity": "sha512-201TZ/kPWxoPr/OKWjquZR1SWKXcvxdH+e1xrx89b3YbmzLMFCLfnaG1HFIgWzJOEWZ7MvpK++odZufgYR50Rw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10.0.0" + }, + "peerDependencies": { + "bufferutil": "^4.0.1", + "utf-8-validate": ">=5.0.2" + }, + "peerDependenciesMeta": { + "bufferutil": { + "optional": true + }, + "utf-8-validate": { + "optional": true + } + } + }, + "node_modules/wsl-utils": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/wsl-utils/-/wsl-utils-0.1.0.tgz", + "integrity": "sha512-h3Fbisa2nKGPxCpm89Hk33lBLsnaGBvctQopaBSOW/uIs6FTe1ATyAnKFJrzVs9vpGdsTe73WF3V4lIsk4Gacw==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-wsl": "^3.1.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/xml-name-validator": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/xml-name-validator/-/xml-name-validator-5.0.0.tgz", + "integrity": "sha512-EvGK8EJ3DhaHfbRlETOWAS5pO9MZITeauHKJyb8wyajUfQUenkIg2MvLDTZ4T/TgIcm3HU0TFBgWWboAZ30UHg==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": ">=18" + } + }, + "node_modules/xmlchars": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/xmlchars/-/xmlchars-2.2.0.tgz", + "integrity": "sha512-JZnDKK8B0RCDw84FNdDAIpZK+JuJw+s7Lz8nksI7SIuU3UXJJslUthsi+uWBUYOwPFwW7W7PRLRfUKpxjtjFCw==", + "dev": true, + "license": "MIT" + }, + "node_modules/yallist": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz", + "integrity": "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==", + "dev": true, + "license": "ISC" + }, + "node_modules/yocto-queue": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz", + "integrity": "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "packages/shared-types": { + "name": "@bandscope/shared-types", + "version": "0.1.0", + "devDependencies": { + "@types/node": "^26.1.1", + "@vitest/coverage-v8": "^4.1.10", + "eslint": "^10.7.0", + "fast-check": "^4.8.0", + "typescript": "^6.0.3", + "typescript-eslint": "^8.63.0", + "vitest": "^4.1.10" + } } } } From 63d0ae6c11ad674f2b06560ad562644670fa06fc Mon Sep 17 00:00:00 2001 From: Seongho Bae Date: Wed, 12 Aug 2026 03:54:00 +0900 Subject: [PATCH 39/92] fix(deps): restore manifest-lock consistency --- package-lock.json | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/package-lock.json b/package-lock.json index 973344f3b..c85ae3cea 100644 --- a/package-lock.json +++ b/package-lock.json @@ -11,16 +11,12 @@ "apps/*", "packages/*" ], - "dependencies": { - "nanoid": "^3.3.18", - "pdfjs-dist": "^6.2.108", - "undici": "^7.29.0" - }, "devDependencies": { "@eslint/js": "^10.0.1", "eslint-plugin-jsdoc": "^63.0.13", "react": "^19.2.4", - "react-dom": "^19.2.7" + "react-dom": "^19.2.7", + "undici": "7.29.0" }, "engines": { "node": ">=22.13 <23" From 6bba612e76b64060c968eb2caf7936724377db22 Mon Sep 17 00:00:00 2001 From: Seongho Bae Date: Fri, 14 Aug 2026 16:48:40 +0900 Subject: [PATCH 40/92] ci: add one-shot canonical lock repair for PR 783 --- .github/workflows/repair-pr-783-lock.yml | 90 ++++++++++++++++++++++++ 1 file changed, 90 insertions(+) create mode 100644 .github/workflows/repair-pr-783-lock.yml diff --git a/.github/workflows/repair-pr-783-lock.yml b/.github/workflows/repair-pr-783-lock.yml new file mode 100644 index 000000000..f83ff8d0a --- /dev/null +++ b/.github/workflows/repair-pr-783-lock.yml @@ -0,0 +1,90 @@ +name: repair-pr-783-lock + +on: + push: + branches: + - fix/high-security-dependency-baseline + workflow_dispatch: + +permissions: + contents: write + +concurrency: + group: repair-pr-783-lock + cancel-in-progress: false + +jobs: + regenerate-lock: + name: regenerate canonical npm lock + runs-on: ubuntu-latest + timeout-minutes: 15 + env: + EXPECTED_NODE_VERSION: "v22.22.3" + EXPECTED_NPM_VERSION: "10.9.8" + steps: + - name: Check out the exact feature branch + uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0 + with: + ref: fix/high-security-dependency-baseline + fetch-depth: 1 + + - name: Install the pinned Node runtime + uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6.4.0 + with: + node-version: "22.22.3" + cache: npm + + - name: Verify the lock generator contract + shell: bash + run: | + set -euo pipefail + test "$(node --version)" = "$EXPECTED_NODE_VERSION" + test "$(npm --version)" = "$EXPECTED_NPM_VERSION" + python3 - <<'PY' + import json + from pathlib import Path + + root = json.loads(Path("package.json").read_text(encoding="utf-8")) + desktop = json.loads(Path("apps/desktop/package.json").read_text(encoding="utf-8")) + assert root["packageManager"] == "npm@10.9.8" + assert root["devDependencies"]["undici"] == "7.29.0" + assert root["overrides"]["undici"] == "$undici" + assert desktop["dependencies"]["pdfjs-dist"] == "6.2.108" + PY + + - name: Regenerate without lifecycle execution + shell: bash + run: | + set -euo pipefail + npm install --package-lock-only --ignore-scripts --no-audit --no-fund + test -z "$(git diff --name-only -- package.json apps/desktop/package.json)" + + - name: Verify generated dependency identities and audit + shell: bash + run: | + set -euo pipefail + python3 - <<'PY' + import json + from pathlib import Path + + lock = json.loads(Path("package-lock.json").read_text(encoding="utf-8")) + packages = lock["packages"] + assert lock["lockfileVersion"] == 3 + assert packages[""]["devDependencies"]["undici"] == "7.29.0" + assert packages["apps/desktop"]["dependencies"]["pdfjs-dist"] == "6.2.108" + assert packages["node_modules/undici"]["version"] == "7.29.0" + assert packages["node_modules/pdfjs-dist"]["version"] == "6.2.108" + PY + npm audit --workspaces --audit-level=high + + - name: Commit the canonical artifact and remove this one-shot workflow + shell: bash + run: | + set -euo pipefail + rm .github/workflows/repair-pr-783-lock.yml + git config user.name "github-actions[bot]" + git config user.email "41898282+github-actions[bot]@users.noreply.github.com" + git add package-lock.json .github/workflows/repair-pr-783-lock.yml + git diff --cached --check + git commit -m "fix(deps): regenerate canonical npm 10.9.8 lock" + git push origin HEAD:fix/high-security-dependency-baseline From ef938fa7450485bf5dbdb56fe1e5e6fea1ddf2a5 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Fri, 14 Aug 2026 07:48:55 +0000 Subject: [PATCH 41/92] fix(deps): regenerate canonical npm 10.9.8 lock --- .github/workflows/repair-pr-783-lock.yml | 90 ------------- package-lock.json | 160 ++++------------------- 2 files changed, 28 insertions(+), 222 deletions(-) delete mode 100644 .github/workflows/repair-pr-783-lock.yml diff --git a/.github/workflows/repair-pr-783-lock.yml b/.github/workflows/repair-pr-783-lock.yml deleted file mode 100644 index f83ff8d0a..000000000 --- a/.github/workflows/repair-pr-783-lock.yml +++ /dev/null @@ -1,90 +0,0 @@ -name: repair-pr-783-lock - -on: - push: - branches: - - fix/high-security-dependency-baseline - workflow_dispatch: - -permissions: - contents: write - -concurrency: - group: repair-pr-783-lock - cancel-in-progress: false - -jobs: - regenerate-lock: - name: regenerate canonical npm lock - runs-on: ubuntu-latest - timeout-minutes: 15 - env: - EXPECTED_NODE_VERSION: "v22.22.3" - EXPECTED_NPM_VERSION: "10.9.8" - steps: - - name: Check out the exact feature branch - uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0 - with: - ref: fix/high-security-dependency-baseline - fetch-depth: 1 - - - name: Install the pinned Node runtime - uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6.4.0 - with: - node-version: "22.22.3" - cache: npm - - - name: Verify the lock generator contract - shell: bash - run: | - set -euo pipefail - test "$(node --version)" = "$EXPECTED_NODE_VERSION" - test "$(npm --version)" = "$EXPECTED_NPM_VERSION" - python3 - <<'PY' - import json - from pathlib import Path - - root = json.loads(Path("package.json").read_text(encoding="utf-8")) - desktop = json.loads(Path("apps/desktop/package.json").read_text(encoding="utf-8")) - assert root["packageManager"] == "npm@10.9.8" - assert root["devDependencies"]["undici"] == "7.29.0" - assert root["overrides"]["undici"] == "$undici" - assert desktop["dependencies"]["pdfjs-dist"] == "6.2.108" - PY - - - name: Regenerate without lifecycle execution - shell: bash - run: | - set -euo pipefail - npm install --package-lock-only --ignore-scripts --no-audit --no-fund - test -z "$(git diff --name-only -- package.json apps/desktop/package.json)" - - - name: Verify generated dependency identities and audit - shell: bash - run: | - set -euo pipefail - python3 - <<'PY' - import json - from pathlib import Path - - lock = json.loads(Path("package-lock.json").read_text(encoding="utf-8")) - packages = lock["packages"] - assert lock["lockfileVersion"] == 3 - assert packages[""]["devDependencies"]["undici"] == "7.29.0" - assert packages["apps/desktop"]["dependencies"]["pdfjs-dist"] == "6.2.108" - assert packages["node_modules/undici"]["version"] == "7.29.0" - assert packages["node_modules/pdfjs-dist"]["version"] == "6.2.108" - PY - npm audit --workspaces --audit-level=high - - - name: Commit the canonical artifact and remove this one-shot workflow - shell: bash - run: | - set -euo pipefail - rm .github/workflows/repair-pr-783-lock.yml - git config user.name "github-actions[bot]" - git config user.email "41898282+github-actions[bot]@users.noreply.github.com" - git add package-lock.json .github/workflows/repair-pr-783-lock.yml - git diff --cached --check - git commit -m "fix(deps): regenerate canonical npm 10.9.8 lock" - git push origin HEAD:fix/high-security-dependency-baseline diff --git a/package-lock.json b/package-lock.json index c85ae3cea..1b2ceef69 100644 --- a/package-lock.json +++ b/package-lock.json @@ -703,6 +703,7 @@ "os": [ "aix" ], + "peer": true, "engines": { "node": ">=18" } @@ -720,6 +721,7 @@ "os": [ "android" ], + "peer": true, "engines": { "node": ">=18" } @@ -737,6 +739,7 @@ "os": [ "android" ], + "peer": true, "engines": { "node": ">=18" } @@ -754,6 +757,7 @@ "os": [ "android" ], + "peer": true, "engines": { "node": ">=18" } @@ -771,6 +775,7 @@ "os": [ "darwin" ], + "peer": true, "engines": { "node": ">=18" } @@ -788,6 +793,7 @@ "os": [ "darwin" ], + "peer": true, "engines": { "node": ">=18" } @@ -805,6 +811,7 @@ "os": [ "freebsd" ], + "peer": true, "engines": { "node": ">=18" } @@ -822,6 +829,7 @@ "os": [ "freebsd" ], + "peer": true, "engines": { "node": ">=18" } @@ -839,6 +847,7 @@ "os": [ "linux" ], + "peer": true, "engines": { "node": ">=18" } @@ -856,6 +865,7 @@ "os": [ "linux" ], + "peer": true, "engines": { "node": ">=18" } @@ -873,6 +883,7 @@ "os": [ "linux" ], + "peer": true, "engines": { "node": ">=18" } @@ -890,6 +901,7 @@ "os": [ "linux" ], + "peer": true, "engines": { "node": ">=18" } @@ -907,6 +919,7 @@ "os": [ "linux" ], + "peer": true, "engines": { "node": ">=18" } @@ -924,6 +937,7 @@ "os": [ "linux" ], + "peer": true, "engines": { "node": ">=18" } @@ -941,6 +955,7 @@ "os": [ "linux" ], + "peer": true, "engines": { "node": ">=18" } @@ -958,6 +973,7 @@ "os": [ "linux" ], + "peer": true, "engines": { "node": ">=18" } @@ -975,6 +991,7 @@ "os": [ "linux" ], + "peer": true, "engines": { "node": ">=18" } @@ -992,6 +1009,7 @@ "os": [ "netbsd" ], + "peer": true, "engines": { "node": ">=18" } @@ -1009,6 +1027,7 @@ "os": [ "netbsd" ], + "peer": true, "engines": { "node": ">=18" } @@ -1026,6 +1045,7 @@ "os": [ "openbsd" ], + "peer": true, "engines": { "node": ">=18" } @@ -1043,6 +1063,7 @@ "os": [ "openbsd" ], + "peer": true, "engines": { "node": ">=18" } @@ -1060,6 +1081,7 @@ "os": [ "openharmony" ], + "peer": true, "engines": { "node": ">=18" } @@ -1077,6 +1099,7 @@ "os": [ "sunos" ], + "peer": true, "engines": { "node": ">=18" } @@ -1094,6 +1117,7 @@ "os": [ "win32" ], + "peer": true, "engines": { "node": ">=18" } @@ -1111,6 +1135,7 @@ "os": [ "win32" ], + "peer": true, "engines": { "node": ">=18" } @@ -1128,6 +1153,7 @@ "os": [ "win32" ], + "peer": true, "engines": { "node": ">=18" } @@ -1578,9 +1604,6 @@ "cpu": [ "arm64" ], - "libc": [ - "glibc" - ], "license": "MIT", "optional": true, "os": [ @@ -1601,9 +1624,6 @@ "cpu": [ "arm64" ], - "libc": [ - "musl" - ], "license": "MIT", "optional": true, "os": [ @@ -1624,9 +1644,6 @@ "cpu": [ "riscv64" ], - "libc": [ - "glibc" - ], "license": "MIT", "optional": true, "os": [ @@ -1647,9 +1664,6 @@ "cpu": [ "x64" ], - "libc": [ - "glibc" - ], "license": "MIT", "optional": true, "os": [ @@ -1670,9 +1684,6 @@ "cpu": [ "x64" ], - "libc": [ - "musl" - ], "license": "MIT", "optional": true, "os": [ @@ -1875,9 +1886,6 @@ "arm64" ], "dev": true, - "libc": [ - "glibc" - ], "license": "MIT", "optional": true, "os": [ @@ -1895,9 +1903,6 @@ "arm64" ], "dev": true, - "libc": [ - "musl" - ], "license": "MIT", "optional": true, "os": [ @@ -1915,9 +1920,6 @@ "ppc64" ], "dev": true, - "libc": [ - "glibc" - ], "license": "MIT", "optional": true, "os": [ @@ -1935,9 +1937,6 @@ "riscv64" ], "dev": true, - "libc": [ - "glibc" - ], "license": "MIT", "optional": true, "os": [ @@ -1955,9 +1954,6 @@ "riscv64" ], "dev": true, - "libc": [ - "musl" - ], "license": "MIT", "optional": true, "os": [ @@ -1975,9 +1971,6 @@ "s390x" ], "dev": true, - "libc": [ - "glibc" - ], "license": "MIT", "optional": true, "os": [ @@ -1995,9 +1988,6 @@ "x64" ], "dev": true, - "libc": [ - "glibc" - ], "license": "MIT", "optional": true, "os": [ @@ -2015,9 +2005,6 @@ "x64" ], "dev": true, - "libc": [ - "musl" - ], "license": "MIT", "optional": true, "os": [ @@ -2230,9 +2217,6 @@ "arm64" ], "dev": true, - "libc": [ - "glibc" - ], "license": "MIT", "optional": true, "os": [ @@ -2247,9 +2231,6 @@ "arm64" ], "dev": true, - "libc": [ - "musl" - ], "license": "MIT", "optional": true, "os": [ @@ -2264,9 +2245,6 @@ "ppc64" ], "dev": true, - "libc": [ - "glibc" - ], "license": "MIT", "optional": true, "os": [ @@ -2281,9 +2259,6 @@ "riscv64" ], "dev": true, - "libc": [ - "glibc" - ], "license": "MIT", "optional": true, "os": [ @@ -2298,9 +2273,6 @@ "riscv64" ], "dev": true, - "libc": [ - "musl" - ], "license": "MIT", "optional": true, "os": [ @@ -2315,9 +2287,6 @@ "s390x" ], "dev": true, - "libc": [ - "glibc" - ], "license": "MIT", "optional": true, "os": [ @@ -2332,9 +2301,6 @@ "x64" ], "dev": true, - "libc": [ - "glibc" - ], "license": "MIT", "optional": true, "os": [ @@ -2349,9 +2315,6 @@ "x64" ], "dev": true, - "libc": [ - "musl" - ], "license": "MIT", "optional": true, "os": [ @@ -2546,9 +2509,6 @@ "arm64" ], "dev": true, - "libc": [ - "glibc" - ], "license": "MIT", "optional": true, "os": [ @@ -2566,9 +2526,6 @@ "arm64" ], "dev": true, - "libc": [ - "musl" - ], "license": "MIT", "optional": true, "os": [ @@ -2586,9 +2543,6 @@ "ppc64" ], "dev": true, - "libc": [ - "glibc" - ], "license": "MIT", "optional": true, "os": [ @@ -2606,9 +2560,6 @@ "s390x" ], "dev": true, - "libc": [ - "glibc" - ], "license": "MIT", "optional": true, "os": [ @@ -2626,9 +2577,6 @@ "x64" ], "dev": true, - "libc": [ - "glibc" - ], "license": "MIT", "optional": true, "os": [ @@ -2646,9 +2594,6 @@ "x64" ], "dev": true, - "libc": [ - "musl" - ], "license": "MIT", "optional": true, "os": [ @@ -3059,9 +3004,6 @@ "arm64" ], "dev": true, - "libc": [ - "glibc" - ], "license": "MIT", "optional": true, "os": [ @@ -3079,9 +3021,6 @@ "arm64" ], "dev": true, - "libc": [ - "musl" - ], "license": "MIT", "optional": true, "os": [ @@ -3099,9 +3038,6 @@ "x64" ], "dev": true, - "libc": [ - "glibc" - ], "license": "MIT", "optional": true, "os": [ @@ -3119,9 +3055,6 @@ "x64" ], "dev": true, - "libc": [ - "musl" - ], "license": "MIT", "optional": true, "os": [ @@ -3309,9 +3242,6 @@ "arm64" ], "dev": true, - "libc": [ - "glibc" - ], "license": "Apache-2.0 OR MIT", "optional": true, "os": [ @@ -3329,9 +3259,6 @@ "arm64" ], "dev": true, - "libc": [ - "musl" - ], "license": "Apache-2.0 OR MIT", "optional": true, "os": [ @@ -3349,9 +3276,6 @@ "riscv64" ], "dev": true, - "libc": [ - "glibc" - ], "license": "Apache-2.0 OR MIT", "optional": true, "os": [ @@ -3369,9 +3293,6 @@ "x64" ], "dev": true, - "libc": [ - "glibc" - ], "license": "Apache-2.0 OR MIT", "optional": true, "os": [ @@ -3389,9 +3310,6 @@ "x64" ], "dev": true, - "libc": [ - "musl" - ], "license": "Apache-2.0 OR MIT", "optional": true, "os": [ @@ -5702,9 +5620,6 @@ "arm64" ], "dev": true, - "libc": [ - "glibc" - ], "license": "MPL-2.0", "optional": true, "os": [ @@ -5726,9 +5641,6 @@ "arm64" ], "dev": true, - "libc": [ - "musl" - ], "license": "MPL-2.0", "optional": true, "os": [ @@ -5750,9 +5662,6 @@ "x64" ], "dev": true, - "libc": [ - "glibc" - ], "license": "MPL-2.0", "optional": true, "os": [ @@ -5774,9 +5683,6 @@ "x64" ], "dev": true, - "libc": [ - "musl" - ], "license": "MPL-2.0", "optional": true, "os": [ @@ -5986,6 +5892,7 @@ "version": "3.3.18", "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.18.tgz", "integrity": "sha512-DTg4MJbGMWkfi6VZFdNt2/caMbQy4Ou+Op/hJQvGEWcnVfoA1QA+xzRKAzw9jD6+GVOOeYr/mIcuDSdug6F6+w==", + "dev": true, "funding": [ { "type": "github", @@ -7097,6 +7004,7 @@ "version": "7.29.0", "resolved": "https://registry.npmjs.org/undici/-/undici-7.29.0.tgz", "integrity": "sha512-IDxfleLmmbSskfWSUATiN1nfn2rDuvnMOqb5CWR92iIfojA0Ud+ulOAAEQ57LPr9rWmsreUyf5lwyao+7GNNVw==", + "dev": true, "license": "MIT", "engines": { "node": ">=20.18.1" @@ -7396,9 +7304,6 @@ "arm64" ], "dev": true, - "libc": [ - "glibc" - ], "license": "MPL-2.0", "optional": true, "os": [ @@ -7420,9 +7325,6 @@ "arm64" ], "dev": true, - "libc": [ - "musl" - ], "license": "MPL-2.0", "optional": true, "os": [ @@ -7444,9 +7346,6 @@ "x64" ], "dev": true, - "libc": [ - "glibc" - ], "license": "MPL-2.0", "optional": true, "os": [ @@ -7468,9 +7367,6 @@ "x64" ], "dev": true, - "libc": [ - "musl" - ], "license": "MPL-2.0", "optional": true, "os": [ From a48ff96be362e8915c976867b9c2ef1b5c807433 Mon Sep 17 00:00:00 2001 From: Seongho Bae Date: Fri, 14 Aug 2026 16:56:10 +0900 Subject: [PATCH 42/92] ci: retrigger exact-head validation after canonical lock generation From fd9389a91b73e651888799cae58e201b1ecd7360 Mon Sep 17 00:00:00 2001 From: Seongho Bae Date: Fri, 14 Aug 2026 17:04:15 +0900 Subject: [PATCH 43/92] ci: add one-shot Ruff formatter for PR 783 --- .github/workflows/repair-pr-783-format.yml | 60 ++++++++++++++++++++++ 1 file changed, 60 insertions(+) create mode 100644 .github/workflows/repair-pr-783-format.yml diff --git a/.github/workflows/repair-pr-783-format.yml b/.github/workflows/repair-pr-783-format.yml new file mode 100644 index 000000000..b6ad6cb18 --- /dev/null +++ b/.github/workflows/repair-pr-783-format.yml @@ -0,0 +1,60 @@ +name: repair-pr-783-format + +on: + push: + branches: + - fix/high-security-dependency-baseline + workflow_dispatch: + +permissions: + contents: write + +concurrency: + group: repair-pr-783-format + cancel-in-progress: false + +jobs: + format: + runs-on: ubuntu-latest + timeout-minutes: 10 + steps: + - name: Check out the exact feature branch + uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0 + with: + ref: fix/high-security-dependency-baseline + fetch-depth: 1 + + - name: Install pinned uv + uses: astral-sh/setup-uv@11f9893b081a58869d3b5fccaea48c9e9e46f990 # v6.7.0 + with: + version: "0.8.6" + enable-cache: false + + - name: Format only the failing test files + shell: bash + run: | + set -euo pipefail + uvx ruff@0.15.5 format \ + services/analysis-engine/tests/test_high_security_dependency_baseline.py \ + services/analysis-engine/tests/test_npm_toolchain_contract.py + changed="$(git diff --name-only)" + expected=$'services/analysis-engine/tests/test_high_security_dependency_baseline.py\nservices/analysis-engine/tests/test_npm_toolchain_contract.py' + test "$changed" = "$expected" + uvx ruff@0.15.5 format --check \ + services/analysis-engine/tests/test_high_security_dependency_baseline.py \ + services/analysis-engine/tests/test_npm_toolchain_contract.py + + - name: Commit the formatter result and remove this one-shot workflow + shell: bash + run: | + set -euo pipefail + rm .github/workflows/repair-pr-783-format.yml + git config user.name "github-actions[bot]" + git config user.email "41898282+github-actions[bot]@users.noreply.github.com" + git add \ + services/analysis-engine/tests/test_high_security_dependency_baseline.py \ + services/analysis-engine/tests/test_npm_toolchain_contract.py \ + .github/workflows/repair-pr-783-format.yml + git diff --cached --check + git commit -m "style(test): apply canonical Ruff formatting" + git push origin HEAD:fix/high-security-dependency-baseline From afba132610da0c2bd0c943bd43f823a588d7a343 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Fri, 14 Aug 2026 08:08:24 +0000 Subject: [PATCH 44/92] style(test): apply canonical Ruff formatting --- .github/workflows/repair-pr-783-format.yml | 60 ------------------- .../test_high_security_dependency_baseline.py | 3 +- .../tests/test_npm_toolchain_contract.py | 3 +- 3 files changed, 2 insertions(+), 64 deletions(-) delete mode 100644 .github/workflows/repair-pr-783-format.yml diff --git a/.github/workflows/repair-pr-783-format.yml b/.github/workflows/repair-pr-783-format.yml deleted file mode 100644 index b6ad6cb18..000000000 --- a/.github/workflows/repair-pr-783-format.yml +++ /dev/null @@ -1,60 +0,0 @@ -name: repair-pr-783-format - -on: - push: - branches: - - fix/high-security-dependency-baseline - workflow_dispatch: - -permissions: - contents: write - -concurrency: - group: repair-pr-783-format - cancel-in-progress: false - -jobs: - format: - runs-on: ubuntu-latest - timeout-minutes: 10 - steps: - - name: Check out the exact feature branch - uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0 - with: - ref: fix/high-security-dependency-baseline - fetch-depth: 1 - - - name: Install pinned uv - uses: astral-sh/setup-uv@11f9893b081a58869d3b5fccaea48c9e9e46f990 # v6.7.0 - with: - version: "0.8.6" - enable-cache: false - - - name: Format only the failing test files - shell: bash - run: | - set -euo pipefail - uvx ruff@0.15.5 format \ - services/analysis-engine/tests/test_high_security_dependency_baseline.py \ - services/analysis-engine/tests/test_npm_toolchain_contract.py - changed="$(git diff --name-only)" - expected=$'services/analysis-engine/tests/test_high_security_dependency_baseline.py\nservices/analysis-engine/tests/test_npm_toolchain_contract.py' - test "$changed" = "$expected" - uvx ruff@0.15.5 format --check \ - services/analysis-engine/tests/test_high_security_dependency_baseline.py \ - services/analysis-engine/tests/test_npm_toolchain_contract.py - - - name: Commit the formatter result and remove this one-shot workflow - shell: bash - run: | - set -euo pipefail - rm .github/workflows/repair-pr-783-format.yml - git config user.name "github-actions[bot]" - git config user.email "41898282+github-actions[bot]@users.noreply.github.com" - git add \ - services/analysis-engine/tests/test_high_security_dependency_baseline.py \ - services/analysis-engine/tests/test_npm_toolchain_contract.py \ - .github/workflows/repair-pr-783-format.yml - git diff --cached --check - git commit -m "style(test): apply canonical Ruff formatting" - git push origin HEAD:fix/high-security-dependency-baseline diff --git a/services/analysis-engine/tests/test_high_security_dependency_baseline.py b/services/analysis-engine/tests/test_high_security_dependency_baseline.py index 7be5df944..259b5e58f 100644 --- a/services/analysis-engine/tests/test_high_security_dependency_baseline.py +++ b/services/analysis-engine/tests/test_high_security_dependency_baseline.py @@ -53,8 +53,7 @@ def test_lock_records_match_exact_registry_artifacts_and_preserve_peer_metadata( assert isinstance(pdfjs, dict) assert pdfjs["version"] == _PDFJS_VERSION assert pdfjs["resolved"] == ( - "https://registry.npmjs.org/pdfjs-dist/-/" - f"pdfjs-dist-{_PDFJS_VERSION}.tgz" + f"https://registry.npmjs.org/pdfjs-dist/-/pdfjs-dist-{_PDFJS_VERSION}.tgz" ) assert pdfjs["integrity"] == _PDFJS_INTEGRITY assert pdfjs["license"] == "Apache-2.0" diff --git a/services/analysis-engine/tests/test_npm_toolchain_contract.py b/services/analysis-engine/tests/test_npm_toolchain_contract.py index 5e9a65dbc..d68532826 100644 --- a/services/analysis-engine/tests/test_npm_toolchain_contract.py +++ b/services/analysis-engine/tests/test_npm_toolchain_contract.py @@ -47,8 +47,7 @@ def test_primary_ci_proves_exact_npm_before_install_and_lock_reproduction() -> N assert "--no-fund" in workflow assert "actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a" in workflow assert ( - "npm-lock-reproduction-${{ github.event.pull_request.head.sha || github.sha }}" - in workflow + "npm-lock-reproduction-${{ github.event.pull_request.head.sha || github.sha }}" in workflow ) assert "if-no-files-found: error" in workflow assert "git diff --exit-code -- package-lock.json" in workflow From e214e968c1bca2bc632c70b7addacfe4be355227 Mon Sep 17 00:00:00 2001 From: Seongho Bae Date: Fri, 14 Aug 2026 17:09:22 +0900 Subject: [PATCH 45/92] ci: retrigger exact-head validation after canonical Ruff formatting From 0cd68360103375f35536e6b8c929ff8c15aebfc4 Mon Sep 17 00:00:00 2001 From: Seongho Bae Date: Fri, 14 Aug 2026 17:35:25 +0900 Subject: [PATCH 46/92] fix(test): verify canonical hoisted PDF.js lock record --- .../tests/test_high_security_dependency_baseline.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/services/analysis-engine/tests/test_high_security_dependency_baseline.py b/services/analysis-engine/tests/test_high_security_dependency_baseline.py index 259b5e58f..80a4eb1ff 100644 --- a/services/analysis-engine/tests/test_high_security_dependency_baseline.py +++ b/services/analysis-engine/tests/test_high_security_dependency_baseline.py @@ -49,7 +49,7 @@ def test_lock_records_match_exact_registry_artifacts_and_preserve_peer_metadata( assert isinstance(desktop, dict) assert desktop["dependencies"]["pdfjs-dist"] == _PDFJS_VERSION # type: ignore[index] - pdfjs = packages["apps/desktop/node_modules/pdfjs-dist"] + pdfjs = packages["node_modules/pdfjs-dist"] assert isinstance(pdfjs, dict) assert pdfjs["version"] == _PDFJS_VERSION assert pdfjs["resolved"] == ( @@ -74,4 +74,4 @@ def test_lock_records_match_exact_registry_artifacts_and_preserve_peer_metadata( assert all( isinstance(metadata, dict) and metadata.get("peer") is True for metadata in esbuild_locations.values() - ) + ) \ No newline at end of file From f4a5a19201069a3e2be6895345ce43387ed6ef6c Mon Sep 17 00:00:00 2001 From: Seongho Bae Date: Fri, 14 Aug 2026 17:44:33 +0900 Subject: [PATCH 47/92] ci: add final one-shot Ruff formatter for PR 783 --- .../workflows/repair-pr-783-format-final.yml | 51 +++++++++++++++++++ 1 file changed, 51 insertions(+) create mode 100644 .github/workflows/repair-pr-783-format-final.yml diff --git a/.github/workflows/repair-pr-783-format-final.yml b/.github/workflows/repair-pr-783-format-final.yml new file mode 100644 index 000000000..8c9dc2c96 --- /dev/null +++ b/.github/workflows/repair-pr-783-format-final.yml @@ -0,0 +1,51 @@ +name: repair-pr-783-format-final + +on: + push: + branches: + - fix/high-security-dependency-baseline + workflow_dispatch: + +permissions: + contents: write + +concurrency: + group: repair-pr-783-format-final + cancel-in-progress: false + +jobs: + format: + runs-on: ubuntu-latest + timeout-minutes: 10 + steps: + - name: Check out the exact feature branch + uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0 + with: + ref: fix/high-security-dependency-baseline + fetch-depth: 1 + + - name: Install pinned uv + uses: astral-sh/setup-uv@11f9893b081a58869d3b5fccaea48c9e9e46f990 # v6.7.0 + with: + version: "0.8.6" + enable-cache: false + + - name: Format the exact failing file + shell: bash + run: | + set -euo pipefail + uvx ruff@0.15.5 format services/analysis-engine/tests/test_high_security_dependency_baseline.py + test "$(git diff --name-only)" = "services/analysis-engine/tests/test_high_security_dependency_baseline.py" + uvx ruff@0.15.5 format --check services/analysis-engine/tests/test_high_security_dependency_baseline.py + + - name: Commit the formatter result and remove this one-shot workflow + shell: bash + run: | + set -euo pipefail + rm .github/workflows/repair-pr-783-format-final.yml + git config user.name "github-actions[bot]" + git config user.email "41898282+github-actions[bot]@users.noreply.github.com" + git add services/analysis-engine/tests/test_high_security_dependency_baseline.py .github/workflows/repair-pr-783-format-final.yml + git diff --cached --check + git commit -m "style(test): apply final canonical Ruff formatting" + git push origin HEAD:fix/high-security-dependency-baseline From 219267e0279cd153632520b270501315b69f78b6 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Fri, 14 Aug 2026 08:53:57 +0000 Subject: [PATCH 48/92] style(test): apply final canonical Ruff formatting --- .../workflows/repair-pr-783-format-final.yml | 51 ------------------- .../test_high_security_dependency_baseline.py | 2 +- 2 files changed, 1 insertion(+), 52 deletions(-) delete mode 100644 .github/workflows/repair-pr-783-format-final.yml diff --git a/.github/workflows/repair-pr-783-format-final.yml b/.github/workflows/repair-pr-783-format-final.yml deleted file mode 100644 index 8c9dc2c96..000000000 --- a/.github/workflows/repair-pr-783-format-final.yml +++ /dev/null @@ -1,51 +0,0 @@ -name: repair-pr-783-format-final - -on: - push: - branches: - - fix/high-security-dependency-baseline - workflow_dispatch: - -permissions: - contents: write - -concurrency: - group: repair-pr-783-format-final - cancel-in-progress: false - -jobs: - format: - runs-on: ubuntu-latest - timeout-minutes: 10 - steps: - - name: Check out the exact feature branch - uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0 - with: - ref: fix/high-security-dependency-baseline - fetch-depth: 1 - - - name: Install pinned uv - uses: astral-sh/setup-uv@11f9893b081a58869d3b5fccaea48c9e9e46f990 # v6.7.0 - with: - version: "0.8.6" - enable-cache: false - - - name: Format the exact failing file - shell: bash - run: | - set -euo pipefail - uvx ruff@0.15.5 format services/analysis-engine/tests/test_high_security_dependency_baseline.py - test "$(git diff --name-only)" = "services/analysis-engine/tests/test_high_security_dependency_baseline.py" - uvx ruff@0.15.5 format --check services/analysis-engine/tests/test_high_security_dependency_baseline.py - - - name: Commit the formatter result and remove this one-shot workflow - shell: bash - run: | - set -euo pipefail - rm .github/workflows/repair-pr-783-format-final.yml - git config user.name "github-actions[bot]" - git config user.email "41898282+github-actions[bot]@users.noreply.github.com" - git add services/analysis-engine/tests/test_high_security_dependency_baseline.py .github/workflows/repair-pr-783-format-final.yml - git diff --cached --check - git commit -m "style(test): apply final canonical Ruff formatting" - git push origin HEAD:fix/high-security-dependency-baseline diff --git a/services/analysis-engine/tests/test_high_security_dependency_baseline.py b/services/analysis-engine/tests/test_high_security_dependency_baseline.py index 80a4eb1ff..8ed27aea6 100644 --- a/services/analysis-engine/tests/test_high_security_dependency_baseline.py +++ b/services/analysis-engine/tests/test_high_security_dependency_baseline.py @@ -74,4 +74,4 @@ def test_lock_records_match_exact_registry_artifacts_and_preserve_peer_metadata( assert all( isinstance(metadata, dict) and metadata.get("peer") is True for metadata in esbuild_locations.values() - ) \ No newline at end of file + ) From db7b1c138a105042f64427748112708a362bdd87 Mon Sep 17 00:00:00 2001 From: Seongho Bae Date: Fri, 14 Aug 2026 18:38:06 +0900 Subject: [PATCH 49/92] chore(ci): retrigger exact-head protected checks From f4d8850c66a49713f0f42ac79f00ae4097ed4735 Mon Sep 17 00:00:00 2001 From: Seongho Bae Date: Fri, 14 Aug 2026 20:08:12 +0900 Subject: [PATCH 50/92] fix(ci): validate npm lock without mutable resolution --- .github/workflows/ci.yml | 24 ++---- CHANGELOG.md | 4 +- .../npm-lockfile-generator-provenance.md | 78 ++++++++++--------- .../tests/test_npm_toolchain_contract.py | 66 ++++++++++++---- 4 files changed, 103 insertions(+), 69 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 8311a1dae..abb7336c2 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -20,8 +20,8 @@ env: EXPECTED_NPM_VERSION: "10.9.8" jobs: - lock-reproduction: - name: gate / ci / npm-lock-reproduction + lock-validation: + name: gate / ci / npm-lock-validation runs-on: ubuntu-latest steps: - uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0 @@ -31,22 +31,14 @@ jobs: cache: npm - name: Verify exact npm lockfile generator run: test "$(npm --version)" = "$EXPECTED_NPM_VERSION" - - name: Reproduce package lock without lifecycle execution - run: npm install --package-lock-only --ignore-scripts --no-audit --no-fund - - name: Preserve the exact generated lock as review evidence - if: always() - uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1 - with: - name: npm-lock-reproduction-${{ github.event.pull_request.head.sha || github.sha }} - path: package-lock.json - if-no-files-found: error - retention-days: 3 - - name: Reject lockfile drift - run: git diff --exit-code -- package-lock.json + - name: Validate the frozen package lock without lifecycle execution + run: npm ci --ignore-scripts --no-audit --no-fund + - name: Reject manifest or lockfile drift + run: git diff --exit-code -- package.json package-lock.json verify: name: ci / build-and-test - needs: lock-reproduction + needs: lock-validation runs-on: ubuntu-latest steps: - uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0 @@ -79,7 +71,7 @@ jobs: rust-check: name: gate / ci / rust-check - needs: lock-reproduction + needs: lock-validation runs-on: macos-15 steps: - uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0 diff --git a/CHANGELOG.md b/CHANGELOG.md index c746043fc..9029bf8b2 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -9,7 +9,7 @@ ### Changed -- Pinned npm `10.9.8` as the lockfile generator and made primary CI reject a different npm version or any package-lock-only replay diff. +- Pinned npm `10.9.8` as the approved lockfile generator and made primary CI consume the committed lock only through frozen `npm ci` validation, rejecting mutable npm resolution in the lock gate and requiring integrity evidence for public-registry lock entries. ### Fixed @@ -73,4 +73,4 @@ - `ChordsFeature` (코드 분석) 화면에서 각 파트(Role)의 `transpositionPlan`(이조/조옮김 계획)을 표시하는 기능을 추가했습니다. - `RangesFeature` (음역대 분석) 화면에서 겹침 경고(Overlap warning) 외에 해당 파트의 채보(Transcription) 가능 노드 수를 요약하여 보여주는 기능을 추가했습니다. -- 신규 UI 요소에 대한 100% 테스트 커버리지를 보장하는 단위 테스트를 추가했습니다 (`apps/desktop/src/features/chords/index.test.tsx`, `apps/desktop/src/features/ranges/index.test.tsx`). +- 신규 UI 요소에 대한 100% 테스트 커버리지를 보장하는 단위 테스트를 추가했습니다 (`apps/desktop/src/features/chords/index.test.tsx`, `apps/desktop/src/features/ranges/index.test.tsx`). \ No newline at end of file diff --git a/docs/doctoring/npm-lockfile-generator-provenance.md b/docs/doctoring/npm-lockfile-generator-provenance.md index 1d50f2a5d..45345f3be 100644 --- a/docs/doctoring/npm-lockfile-generator-provenance.md +++ b/docs/doctoring/npm-lockfile-generator-provenance.md @@ -2,75 +2,83 @@ ## Decision -BandScope generates and verifies its root npm workspace lock with exactly npm `10.9.8`. The root manifest records that decision through: +BandScope records npm `10.9.8` as the approved generator for root workspace dependency updates. The root manifest records that decision through: - `packageManager: npm@10.9.8` as package-manager selection metadata; and - `devEngines.packageManager` with `onFail: error` as npm's source-tree command gate. -The npm version is intentionally not repeated under `engines`. npm serializes `engines` into the root lock package, so adding an npm-only source-tool constraint there creates lock metadata churn unrelated to dependency resolution. `devEngines`, the explicit CI assertion, and the replay gate enforce the generator while the published `engines.node` range remains the runtime compatibility contract. +The npm version is intentionally not repeated under `engines`. npm serializes `engines` into the root lock package, so adding an npm-only source-tool constraint there creates lock metadata churn unrelated to dependency resolution. `devEngines` and the explicit CI assertion enforce the approved generator while the published `engines.node` range remains the runtime compatibility contract. -The primary GitHub Actions workflow uses Node `22.22.3`, verifies the bundled npm version before any installation, runs `npm ci`, then runs a package-lock-only regeneration with scripts, audit, and funding output disabled. Any `package-lock.json` diff fails the exact head. +Primary CI does **not** regenerate or update `package-lock.json`. It uses Node `22.22.3`, verifies npm `10.9.8`, and validates the committed lock with `npm ci --ignore-scripts --no-audit --no-fund`. The gate then rejects any manifest or lockfile working-tree change. The normal verification job performs the repository's reviewed `npm ci` installation before lint, typecheck, tests, build, and security checks. The Node runtime support decision remains separate. This change does not raise the public `>=22.13 <23` Node range; a coordinated Node-floor migration is tracked independently. -## Why the generator is part of the lock identity +## Why generator provenance still matters -npm documents `package-lock.json` as the location-keyed description of the exact dependency tree. Lockfile version 3 is intended for npm 9 and newer. npm also notes that different package-manager versions may use different installation algorithms and metadata representations. A committed lockfile therefore is not fully reproducible unless the generator version and install-shaping flags are versioned with it. +npm documents `package-lock.json` as the location-keyed description of the exact dependency tree. Lockfile version 3 is intended for npm 9 and newer. npm also notes that package-manager versions and tree-shaping configuration can affect the generated dependency graph and metadata. Dependency updates therefore use the reviewed npm `10.9.8` toolchain, and reviewers examine the complete generated lock diff together with its manifest change. -`npm ci` is the immutable consumption path: it requires a lockfile, rejects manifest/lock dependency disagreement, removes an existing `node_modules`, and does not write the manifest or lock. It does not prove that a future dependency update will regenerate byte-identical metadata. The additional package-lock-only replay closes that gap. +That provenance is distinct from CI validation. `npm ci` is the immutable consumption path: it requires a lockfile, rejects manifest/lock dependency disagreement, removes an existing `node_modules`, and never writes the manifest or lock. CI relies on that frozen behavior instead of running `npm install`, `npm update`, or `npx` commands that may perform mutable resolution. + +The repository additionally requires a Subresource Integrity value for every package-lock entry resolved from the public npm registry. npm documents `integrity` as the SHA-512 or SHA-1 SRI string for the artifact unpacked at that location. ```mermaid flowchart LR - M[package.json ranges and workspaces] --> G[npm 10.9.8] - C[project npm configuration] --> G - G --> L[package-lock.json v3] - L --> I[npm ci clean install] - I --> R[npm 10.9.8 package-lock-only replay] - R --> D{lock diff?} - D -->|no| A[reproducible exact-head evidence] + M[package.json dependency intent] --> G[approved npm 10.9.8 update toolchain] + G --> L[reviewed package-lock.json v3] + L --> V[npm ci frozen validation, lifecycle disabled] + V --> D{manifest or lock drift?} D -->|yes| F[fail closed] + D -->|no| S[verify public-registry SRI evidence] + S --> C[normal npm ci and repository checks] ``` ## Security and operational boundary -- Dependency PRs may change only manifest ranges and the lock records produced by npm `10.9.8`. -- Reviewers must reject unrelated lock metadata that cannot be reproduced by the pinned generator. -- No lock record may be added or removed by hand to satisfy a validator. -- Install-shaping flags that change the tree, such as `legacy-peer-deps` or `install-links`, must be committed in project configuration and used identically by `npm ci` and regeneration. -- Dependency lifecycle scripts remain disabled for the reproduction pass. The normal clean install retains the repository's reviewed execution behavior. -- The exact npm version check occurs before `npm ci`; a different bundled or globally installed npm cannot generate acceptance evidence. -- The lockfile remains the sole npm workspace lock. Nested workspace locks are prohibited. +- CI lock validation must not run `npm install`, `npm update`, `npx`, or another mutable dependency-resolution command. +- Dependency PRs change manifest intent and the complete lock artifact produced by the approved npm `10.9.8` update toolchain; reviewers reject unexplained lock churn rather than hand-editing records. +- The lock-validation job disables dependency lifecycle scripts. The normal clean install retains the repository's reviewed execution behavior. +- The exact npm version check occurs before either frozen install; a different bundled or globally installed npm cannot provide acceptance evidence. +- Registry-resolved package records require SRI evidence in the committed lock. +- Install-shaping flags that affect the dependency tree, such as `legacy-peer-deps` or `install-links`, must be committed in project configuration and applied consistently to generation and `npm ci`. +- The root `package-lock.json` remains the sole npm workspace lock. Nested workspace locks are prohibited. -`packageManager` alone is not the enforcement boundary for npm because Corepack's npm shim is not enabled by default in Node distributions. Enforcement is provided by npm `devEngines`, the explicit CI version assertion, and the lock replay. +`packageManager` alone is not the enforcement boundary for npm because Corepack's npm shim is not enabled by default in Node distributions. Enforcement is provided by npm `devEngines`, the explicit CI version assertion, the frozen `npm ci` contract, and repository tests that prohibit mutable resolution in the lock gate. ## Verification -`services/analysis-engine/tests/test_npm_toolchain_contract.py` verifies the manifest metadata, separation of runtime and generator constraints, exact CI Node/npm identity, replay command and flags, clean lock diff, and lockfile version 3. Repository CI then executes the replay using the hosted toolchain. +`services/analysis-engine/tests/test_npm_toolchain_contract.py` verifies: + +1. the manifest's approved npm metadata and Node/runtime separation; +2. the exact Node/npm identity used by primary CI; +3. frozen `npm ci` lock validation with lifecycle execution disabled; +4. absence of `npm install`, `npm update`, and `npx` from the lock-validation job; +5. a clean manifest/lock working tree after validation; +6. package-lock version 3; and +7. SRI evidence for every public npm-registry artifact in the root lock. + +The exact PDF.js and Undici baseline is covered separately by `test_high_security_dependency_baseline.py` and the desktop PDF loader tests. -A dependency update is mergeable only after: +A dependency update is mergeable only after the updated manifest and complete generated lock are reviewed together and the exact current head passes frozen lock validation, normal install, lint, strict typecheck, measured tests, production build, Rust/Tauri checks, security/supply-chain gates, current review, independent approval, and branch protection without bypass. -1. npm `10.9.8` produces the checked-in lock from the updated manifest; -2. a second package-lock-only replay is byte-clean; -3. `npm ci`, lint, strict typecheck, measured tests, production build, Rust/Tauri checks, and security/supply-chain gates succeed on the same head; and -4. current-head review, unresolved-thread, independent-approval, and branch-protection requirements succeed without bypass. +## Claim boundary + +CI proves that the committed manifest and lock can be consumed as a frozen pair by the approved toolchain and that public-registry lock entries carry integrity evidence. It does **not** claim that resolving mutable manifest ranges again at a later time will reproduce byte-identical lock metadata. When a dependency update is needed, npm `10.9.8` remains the approved generator and its entire resulting lock diff is review evidence. ## Incident response and rollback -When replay changes the lock unexpectedly: +When an update produces unexpected lock churn: -1. preserve the exact head SHA, npm and Node versions, command flags, original lock blob SHA, regenerated lock, and CI run ID; -2. determine whether the manifest changed, npm changed, project configuration changed, or the protected lock was generated by a different toolchain; -3. never accept a partial or hand-edited lock; -4. regenerate from a clean checkout using the reviewed npm version and run the replay twice; +1. preserve the exact head SHA, npm and Node versions, project npm configuration, original lock blob SHA, generated lock, and relevant CI run IDs; +2. determine whether manifest intent, npm, project configuration, registry metadata, or transitive dependency resolution changed; +3. never accept a partial or hand-edited lock to satisfy a validator; +4. regenerate the complete lock in a dedicated update branch using the reviewed npm version, then review the full diff before relying on it; and 5. if rollback is necessary, restore the prior manifest and complete lock together, then rerun the entire exact-head gate. ## References npm, Inc. (2026). *npm ci*. npm Docs. https://docs.npmjs.com/cli/v11/commands/npm-ci/ -npm, Inc. (2026). *npm install*. npm Docs. https://docs.npmjs.com/cli/v10/commands/npm-install/ - -npm, Inc. (2026). *package-lock.json*. npm Docs. https://docs.npmjs.com/cli/v11/configuring-npm/package-lock-json/ +npm, Inc. (2026). *package-lock.json*. npm Docs. https://docs.npmjs.com/cli/v10/configuring-npm/package-lock-json/ npm, Inc. (2026). *package.json*. npm Docs. https://docs.npmjs.com/cli/configuring-npm/package-json/ diff --git a/services/analysis-engine/tests/test_npm_toolchain_contract.py b/services/analysis-engine/tests/test_npm_toolchain_contract.py index d68532826..857a27497 100644 --- a/services/analysis-engine/tests/test_npm_toolchain_contract.py +++ b/services/analysis-engine/tests/test_npm_toolchain_contract.py @@ -17,6 +17,20 @@ def _root_manifest() -> dict[str, object]: return manifest +def _primary_ci_workflow() -> str: + """Return the primary CI workflow as source text.""" + return (_REPOSITORY_ROOT / ".github" / "workflows" / "ci.yml").read_text( + encoding="utf-8" + ) + + +def _lock_validation_job(workflow: str) -> str: + """Return only the frozen npm lock-validation job from the CI workflow.""" + start = workflow.index(" lock-validation:") + end = workflow.index("\n verify:", start) + return workflow[start:end] + + def test_root_manifest_pins_the_lockfile_generator_and_fails_on_drift() -> None: """Require npm and source-tree commands to reject a different generator.""" manifest = _root_manifest() @@ -32,25 +46,20 @@ def test_root_manifest_pins_the_lockfile_generator_and_fails_on_drift() -> None: } -def test_primary_ci_proves_exact_npm_before_install_and_lock_reproduction() -> None: - """Keep the clean installer and lock reproduction on one explicit toolchain.""" - workflow = (_REPOSITORY_ROOT / ".github" / "workflows" / "ci.yml").read_text(encoding="utf-8") +def test_primary_ci_consumes_the_lock_without_mutable_resolution() -> None: + """Keep lock validation frozen while retaining exact Node and npm provenance.""" + workflow = _primary_ci_workflow() + lock_job = _lock_validation_job(workflow) assert f'node-version: "{_EXPECTED_NODE_VERSION}"' in workflow assert f'EXPECTED_NPM_VERSION: "{_EXPECTED_NPM_VERSION}"' in workflow - assert 'test "$(npm --version)" = "$EXPECTED_NPM_VERSION"' in workflow - assert "lock-reproduction:" in workflow - assert "needs: lock-reproduction" in workflow - assert "npm install --package-lock-only" in workflow - assert "--ignore-scripts" in workflow - assert "--no-audit" in workflow - assert "--no-fund" in workflow - assert "actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a" in workflow - assert ( - "npm-lock-reproduction-${{ github.event.pull_request.head.sha || github.sha }}" in workflow - ) - assert "if-no-files-found: error" in workflow - assert "git diff --exit-code -- package-lock.json" in workflow + assert 'test "$(npm --version)" = "$EXPECTED_NPM_VERSION"' in lock_job + assert "npm ci --ignore-scripts --no-audit --no-fund" in lock_job + assert "git diff --exit-code -- package.json package-lock.json" in lock_job + assert "needs: lock-validation" in workflow + assert "npm install " not in lock_job + assert "npm update " not in lock_job + assert "npx " not in lock_job def test_root_lock_uses_the_supported_location_keyed_format() -> None: @@ -59,3 +68,28 @@ def test_root_lock_uses_the_supported_location_keyed_format() -> None: assert lock_document["lockfileVersion"] == 3 assert isinstance(lock_document["packages"], dict) + + +def test_public_registry_lock_entries_have_integrity_evidence() -> None: + """Require SRI for every public npm-registry artifact recorded in the root lock.""" + lock_document = json.loads((_REPOSITORY_ROOT / "package-lock.json").read_text(encoding="utf-8")) + packages = lock_document["packages"] + assert isinstance(packages, dict) + + for location, package_record in packages.items(): + assert isinstance(location, str) + assert isinstance(package_record, dict) + resolved = package_record.get("resolved") + if not isinstance(resolved, str): + continue + if not ( + resolved == "registry.npmjs.org" + or resolved.startswith("registry.npmjs.org/") + or resolved.startswith("https://registry.npmjs.org/") + ): + continue + integrity = package_record.get("integrity") + assert isinstance(integrity, str), f"missing integrity for {location}" + assert integrity.startswith(("sha512-", "sha1-")), ( + f"unsupported integrity for {location}" + ) From 8a143ab8f06cd8733c0076fa3cf38aedeeaf4d82 Mon Sep 17 00:00:00 2001 From: Seongho Bae Date: Fri, 14 Aug 2026 20:32:35 +0900 Subject: [PATCH 51/92] test(supply-chain): format npm toolchain contract --- .../analysis-engine/tests/test_npm_toolchain_contract.py | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/services/analysis-engine/tests/test_npm_toolchain_contract.py b/services/analysis-engine/tests/test_npm_toolchain_contract.py index 857a27497..b3639a595 100644 --- a/services/analysis-engine/tests/test_npm_toolchain_contract.py +++ b/services/analysis-engine/tests/test_npm_toolchain_contract.py @@ -64,7 +64,9 @@ def test_primary_ci_consumes_the_lock_without_mutable_resolution() -> None: def test_root_lock_uses_the_supported_location_keyed_format() -> None: """Require the npm-v9-and-newer lock format used by the pinned generator.""" - lock_document = json.loads((_REPOSITORY_ROOT / "package-lock.json").read_text(encoding="utf-8")) + lock_document = json.loads( + (_REPOSITORY_ROOT / "package-lock.json").read_text(encoding="utf-8") + ) assert lock_document["lockfileVersion"] == 3 assert isinstance(lock_document["packages"], dict) @@ -72,7 +74,9 @@ def test_root_lock_uses_the_supported_location_keyed_format() -> None: def test_public_registry_lock_entries_have_integrity_evidence() -> None: """Require SRI for every public npm-registry artifact recorded in the root lock.""" - lock_document = json.loads((_REPOSITORY_ROOT / "package-lock.json").read_text(encoding="utf-8")) + lock_document = json.loads( + (_REPOSITORY_ROOT / "package-lock.json").read_text(encoding="utf-8") + ) packages = lock_document["packages"] assert isinstance(packages, dict) From b3ac82665f727a2653ac71b9ab92f22dec25d96c Mon Sep 17 00:00:00 2001 From: Seongho Bae Date: Fri, 14 Aug 2026 21:13:34 +0900 Subject: [PATCH 52/92] test(supply-chain): satisfy ruff formatting gate --- .../analysis-engine/tests/test_npm_toolchain_contract.py | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/services/analysis-engine/tests/test_npm_toolchain_contract.py b/services/analysis-engine/tests/test_npm_toolchain_contract.py index b3639a595..2b76336b9 100644 --- a/services/analysis-engine/tests/test_npm_toolchain_contract.py +++ b/services/analysis-engine/tests/test_npm_toolchain_contract.py @@ -94,6 +94,5 @@ def test_public_registry_lock_entries_have_integrity_evidence() -> None: continue integrity = package_record.get("integrity") assert isinstance(integrity, str), f"missing integrity for {location}" - assert integrity.startswith(("sha512-", "sha1-")), ( - f"unsupported integrity for {location}" - ) + supported_algorithm = integrity.startswith(("sha512-", "sha1-")) + assert supported_algorithm, f"unsupported integrity for {location}" From 885c03759aee436e4f81a1e7884d8335bd58dc0b Mon Sep 17 00:00:00 2001 From: Seongho Bae Date: Fri, 14 Aug 2026 22:09:38 +0900 Subject: [PATCH 53/92] test(supply-chain): format npm toolchain contract --- services/analysis-engine/tests/test_npm_toolchain_contract.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/services/analysis-engine/tests/test_npm_toolchain_contract.py b/services/analysis-engine/tests/test_npm_toolchain_contract.py index 2b76336b9..79b570fc0 100644 --- a/services/analysis-engine/tests/test_npm_toolchain_contract.py +++ b/services/analysis-engine/tests/test_npm_toolchain_contract.py @@ -12,7 +12,9 @@ def _root_manifest() -> dict[str, object]: """Return the checked-in root package manifest as a JSON object.""" - manifest = json.loads((_REPOSITORY_ROOT / "package.json").read_text(encoding="utf-8")) + manifest = json.loads( + (_REPOSITORY_ROOT / "package.json").read_text(encoding="utf-8") + ) assert isinstance(manifest, dict) return manifest From de0cd6beea8fab1ee26deb4c733e50ea3d37d1d1 Mon Sep 17 00:00:00 2001 From: Seongho Bae Date: Fri, 14 Aug 2026 22:39:41 +0900 Subject: [PATCH 54/92] test(supply-chain): apply repository Ruff width --- .../tests/test_npm_toolchain_contract.py | 16 ++++------------ 1 file changed, 4 insertions(+), 12 deletions(-) diff --git a/services/analysis-engine/tests/test_npm_toolchain_contract.py b/services/analysis-engine/tests/test_npm_toolchain_contract.py index 79b570fc0..2eafcbe19 100644 --- a/services/analysis-engine/tests/test_npm_toolchain_contract.py +++ b/services/analysis-engine/tests/test_npm_toolchain_contract.py @@ -12,18 +12,14 @@ def _root_manifest() -> dict[str, object]: """Return the checked-in root package manifest as a JSON object.""" - manifest = json.loads( - (_REPOSITORY_ROOT / "package.json").read_text(encoding="utf-8") - ) + manifest = json.loads((_REPOSITORY_ROOT / "package.json").read_text(encoding="utf-8")) assert isinstance(manifest, dict) return manifest def _primary_ci_workflow() -> str: """Return the primary CI workflow as source text.""" - return (_REPOSITORY_ROOT / ".github" / "workflows" / "ci.yml").read_text( - encoding="utf-8" - ) + return (_REPOSITORY_ROOT / ".github" / "workflows" / "ci.yml").read_text(encoding="utf-8") def _lock_validation_job(workflow: str) -> str: @@ -66,9 +62,7 @@ def test_primary_ci_consumes_the_lock_without_mutable_resolution() -> None: def test_root_lock_uses_the_supported_location_keyed_format() -> None: """Require the npm-v9-and-newer lock format used by the pinned generator.""" - lock_document = json.loads( - (_REPOSITORY_ROOT / "package-lock.json").read_text(encoding="utf-8") - ) + lock_document = json.loads((_REPOSITORY_ROOT / "package-lock.json").read_text(encoding="utf-8")) assert lock_document["lockfileVersion"] == 3 assert isinstance(lock_document["packages"], dict) @@ -76,9 +70,7 @@ def test_root_lock_uses_the_supported_location_keyed_format() -> None: def test_public_registry_lock_entries_have_integrity_evidence() -> None: """Require SRI for every public npm-registry artifact recorded in the root lock.""" - lock_document = json.loads( - (_REPOSITORY_ROOT / "package-lock.json").read_text(encoding="utf-8") - ) + lock_document = json.loads((_REPOSITORY_ROOT / "package-lock.json").read_text(encoding="utf-8")) packages = lock_document["packages"] assert isinstance(packages, dict) From f3cfae42db0529a80f032bf8657e17a0610ae1c7 Mon Sep 17 00:00:00 2001 From: Seongho Bae Date: Sat, 15 Aug 2026 00:35:15 +0900 Subject: [PATCH 55/92] docs(security): align npm lock provenance with frozen validation --- .../high-security-pdf-http-baseline.md | 29 ++++++++++--------- 1 file changed, 16 insertions(+), 13 deletions(-) diff --git a/docs/doctoring/high-security-pdf-http-baseline.md b/docs/doctoring/high-security-pdf-http-baseline.md index d83a63eb7..5e56be8bf 100644 --- a/docs/doctoring/high-security-pdf-http-baseline.md +++ b/docs/doctoring/high-security-pdf-http-baseline.md @@ -6,7 +6,7 @@ BandScope treats the PDF parser and its transitive HTTP client as one security-r - `pdfjs-dist` is pinned exactly to `6.2.108`; - `undici` is pinned exactly to `7.29.0` through the root npm override; and -- the complete npm workspace lock is generated only by the repository-pinned npm `10.9.8` workflow and imported unchanged from the workflow artifact. +- npm `10.9.8` is the approved generator for reviewed root-workspace dependency updates, while primary CI consumes the committed lock through frozen validation rather than re-resolving it. PDF.js `6.2.108` no longer exposes the legacy `isEvalSupported` member in its public `DocumentInitParameters` contract, and `getDocument` no longer reads that member. BandScope therefore does not cast or pass an unknown option that would be ignored while creating false assurance. The primary remediation is the patched parser release, reinforced by a narrow data-only call, copied caller-owned bytes, and a same-origin bundled worker. @@ -18,9 +18,10 @@ flowchart LR C --> W[Same-origin bundled worker] W --> R[Canvas render] J[jsdom development path] --> U[undici 7.29.0 override] - N[npm 10.9.8] --> L[Exact package-lock artifact] - L --> C - L --> U + N[npm 10.9.8 approved update toolchain] --> L[Reviewed package-lock artifact] + L --> V[npm ci frozen validation] + V --> C + V --> U ``` ## Threat boundary @@ -33,16 +34,18 @@ Undici is currently a development dependency reached through jsdom, but developm ## Lockfile provenance -The security manifests are changed before the lock. The exact branch workflow then: +The dependency manifests and complete lock artifact were generated and reconciled on this branch with the approved Node `22.22.3` / npm `10.9.8` toolchain before the current frozen-validation gate was finalized. The historical generation run and artifact are provenance evidence only; they do **not** satisfy a later head's merge gate and primary CI intentionally does not repeat mutable dependency resolution. -1. verifies Node `22.22.3` and npm `10.9.8`; -2. runs `npm install --package-lock-only --ignore-scripts --no-audit --no-fund`; -3. uploads the generated `package-lock.json` under a head-SHA-bound artifact name; and -4. fails while the generated lock differs from the branch. +For every current head, primary CI instead: -The maintainer imports that generated artifact byte-for-byte and reruns the workflow. The second run must produce a clean diff. No tarball URL, SRI, dependency range, `peer` classification, or workspace record is edited by hand. +1. verifies npm `10.9.8` before dependency consumption; +2. runs `npm ci --ignore-scripts --no-audit --no-fund` in the dedicated lock-validation job; +3. rejects any `package.json` or `package-lock.json` working-tree drift; and +4. proceeds to normal repository verification only after the frozen lock is consumable by the approved toolchain. -The lock contract requires the exact public-registry tarball and SHA-512 SRI for both patched packages and requires every existing `node_modules/@esbuild/*` location to retain npm 10.9.8's `peer: true` classification. This distinguishes the intended security graph from unrelated Dependabot generator churn. +Future dependency updates must use npm `10.9.8` to generate the complete lock in a dedicated update branch, review the entire resulting manifest/lock diff, and then prove frozen consumption on the resulting exact head. No tarball URL, SRI, dependency range, `peer` classification, or workspace record may be hand-edited merely to satisfy a validator. + +The lock contract requires the exact public-registry tarball and SHA-512 SRI for both patched packages and requires every existing `node_modules/@esbuild/*` location to retain npm 10.9.8's `peer: true` classification. This distinguishes the intended security graph from unrelated Dependabot generator churn. The narrower provenance and validation contract is specified in `docs/doctoring/npm-lockfile-generator-provenance.md`. ## Verification @@ -62,7 +65,7 @@ The merge gate includes: ## Failure, rollback, and incident evidence -On a failed lock replay or parser regression, preserve the exact head SHA, Node/npm versions, generated-lock artifact ID and digest, original and generated lock blob SHA, test output, audit report, and workflow run ID. Do not merge a partially updated graph. +On a failed frozen-lock validation or parser regression, preserve the exact head SHA, Node/npm versions, original lock blob SHA, test output, audit report, and workflow run ID. If the incident concerns a dependency-generation change, also preserve the generated complete lock and the generation environment/configuration. Do not merge a partially updated graph. Rollback restores the previous desktop manifest, root override, complete lock, PDF loader, tests, and CHANGELOG entry together. Because the previous graph contains known high findings, rollback is an emergency availability action only and requires an explicit security exception, compensating controls, owner, expiration, and immediate replacement plan. @@ -78,4 +81,4 @@ Node.js contributors. (2026). *Undici 7.29.0* [Software release]. https://github npm, Inc. (2026). *npm ci*. npm Docs. https://docs.npmjs.com/cli/v11/commands/npm-ci/ -npm, Inc. (2026). *package-lock.json*. npm Docs. https://docs.npmjs.com/cli/v11/configuring-npm/package-lock-json/ +npm, Inc. (2026). *package-lock.json*. npm Docs. https://docs.npmjs.com/cli/v11/configuring-npm/package-lock-json/ \ No newline at end of file From de75178205db244ca44cb105262398585a189881 Mon Sep 17 00:00:00 2001 From: Seongho Bae Date: Sat, 15 Aug 2026 02:11:13 +0900 Subject: [PATCH 56/92] fix(ci): disable persisted checkout credentials --- .github/workflows/ci.yml | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index abb7336c2..4ec39fc9d 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -42,6 +42,8 @@ jobs: runs-on: ubuntu-latest steps: - uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0 + with: + persist-credentials: false - uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6.4.0 with: node-version: "22.22.3" @@ -75,6 +77,8 @@ jobs: runs-on: macos-15 steps: - uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0 + with: + persist-credentials: false - uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6.4.0 with: node-version: "22.22.3" From 164e6f2e7d8deec07d885d2ef00a0f684bc6ef47 Mon Sep 17 00:00:00 2001 From: Seongho Bae Date: Sat, 15 Aug 2026 02:11:26 +0900 Subject: [PATCH 57/92] docs(changelog): correct UI test coverage claim --- CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 9029bf8b2..9fee41aec 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -73,4 +73,4 @@ - `ChordsFeature` (코드 분석) 화면에서 각 파트(Role)의 `transpositionPlan`(이조/조옮김 계획)을 표시하는 기능을 추가했습니다. - `RangesFeature` (음역대 분석) 화면에서 겹침 경고(Overlap warning) 외에 해당 파트의 채보(Transcription) 가능 노드 수를 요약하여 보여주는 기능을 추가했습니다. -- 신규 UI 요소에 대한 100% 테스트 커버리지를 보장하는 단위 테스트를 추가했습니다 (`apps/desktop/src/features/chords/index.test.tsx`, `apps/desktop/src/features/ranges/index.test.tsx`). \ No newline at end of file +- 신규 UI 요소에 대한 단위 테스트를 추가했습니다 (`apps/desktop/src/features/chords/index.test.tsx`, `apps/desktop/src/features/ranges/index.test.tsx`). \ No newline at end of file From 07c1dd2d5bf8109d0d2c74f8c8b6120e0eae188e Mon Sep 17 00:00:00 2001 From: Seongho Bae Date: Sat, 15 Aug 2026 16:07:59 +0900 Subject: [PATCH 58/92] test(lock): reject esbuild peer metadata drift --- .../tests/test_npm_toolchain_contract.py | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/services/analysis-engine/tests/test_npm_toolchain_contract.py b/services/analysis-engine/tests/test_npm_toolchain_contract.py index 2eafcbe19..6f38db8c0 100644 --- a/services/analysis-engine/tests/test_npm_toolchain_contract.py +++ b/services/analysis-engine/tests/test_npm_toolchain_contract.py @@ -90,3 +90,21 @@ def test_public_registry_lock_entries_have_integrity_evidence() -> None: assert isinstance(integrity, str), f"missing integrity for {location}" supported_algorithm = integrity.startswith(("sha512-", "sha1-")) assert supported_algorithm, f"unsupported integrity for {location}" + + +def test_root_lock_preserves_esbuild_peer_metadata() -> None: + """Reject serializer drift that strips the root @esbuild peer markers.""" + lock_document = json.loads((_REPOSITORY_ROOT / "package-lock.json").read_text(encoding="utf-8")) + packages = lock_document["packages"] + assert isinstance(packages, dict) + + esbuild_records = { + location: package_record + for location, package_record in packages.items() + if isinstance(location, str) and location.startswith("node_modules/@esbuild/") + } + assert esbuild_records, "root lock must contain @esbuild platform packages" + + for location, package_record in esbuild_records.items(): + assert isinstance(package_record, dict) + assert package_record.get("peer") is True, f"missing peer metadata for {location}" From ad4551bdc4e91206a14f3825430663ee19c1176f Mon Sep 17 00:00:00 2001 From: Seongho Bae Date: Sat, 15 Aug 2026 16:09:53 +0900 Subject: [PATCH 59/92] docs(lock): record esbuild metadata sentinel --- docs/doctoring/npm-lockfile-generator-provenance.md | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/docs/doctoring/npm-lockfile-generator-provenance.md b/docs/doctoring/npm-lockfile-generator-provenance.md index 45345f3be..53488de48 100644 --- a/docs/doctoring/npm-lockfile-generator-provenance.md +++ b/docs/doctoring/npm-lockfile-generator-provenance.md @@ -21,6 +21,8 @@ That provenance is distinct from CI validation. `npm ci` is the immutable consum The repository additionally requires a Subresource Integrity value for every package-lock entry resolved from the public npm registry. npm documents `integrity` as the SHA-512 or SHA-1 SRI string for the artifact unpacked at that location. +The root lock also retains `peer: true` on the platform-specific `node_modules/@esbuild/*` records produced by the approved tree. Multiple dependency-update branches generated with a different serialization path were observed removing those markers even when the requested package change was unrelated to esbuild. Because frozen `npm ci` consumes rather than regenerates the lock, ordinary frozen-install validation alone cannot prove that this generator-sensitive metadata was preserved. The repository therefore treats those markers as a regression sentinel: a dependency PR that strips them must be regenerated with the approved npm toolchain rather than normalizing the unrelated churn by hand. + ```mermaid flowchart LR M[package.json dependency intent] --> G[approved npm 10.9.8 update toolchain] @@ -28,7 +30,7 @@ flowchart LR L --> V[npm ci frozen validation, lifecycle disabled] V --> D{manifest or lock drift?} D -->|yes| F[fail closed] - D -->|no| S[verify public-registry SRI evidence] + D -->|no| S[verify SRI and generator-sensitive metadata] S --> C[normal npm ci and repository checks] ``` @@ -36,6 +38,7 @@ flowchart LR - CI lock validation must not run `npm install`, `npm update`, `npx`, or another mutable dependency-resolution command. - Dependency PRs change manifest intent and the complete lock artifact produced by the approved npm `10.9.8` update toolchain; reviewers reject unexplained lock churn rather than hand-editing records. +- Platform-specific root `@esbuild/*` lock records must retain their expected `peer: true` metadata. Missing markers are treated as generator drift, not as an acceptable side effect of an unrelated dependency update. - The lock-validation job disables dependency lifecycle scripts. The normal clean install retains the repository's reviewed execution behavior. - The exact npm version check occurs before either frozen install; a different bundled or globally installed npm cannot provide acceptance evidence. - Registry-resolved package records require SRI evidence in the committed lock. @@ -53,8 +56,9 @@ flowchart LR 3. frozen `npm ci` lock validation with lifecycle execution disabled; 4. absence of `npm install`, `npm update`, and `npx` from the lock-validation job; 5. a clean manifest/lock working tree after validation; -6. package-lock version 3; and -7. SRI evidence for every public npm-registry artifact in the root lock. +6. package-lock version 3; +7. SRI evidence for every public npm-registry artifact in the root lock; and +8. preservation of `peer: true` on every root `node_modules/@esbuild/*` platform record. The exact PDF.js and Undici baseline is covered separately by `test_high_security_dependency_baseline.py` and the desktop PDF loader tests. @@ -62,7 +66,7 @@ A dependency update is mergeable only after the updated manifest and complete ge ## Claim boundary -CI proves that the committed manifest and lock can be consumed as a frozen pair by the approved toolchain and that public-registry lock entries carry integrity evidence. It does **not** claim that resolving mutable manifest ranges again at a later time will reproduce byte-identical lock metadata. When a dependency update is needed, npm `10.9.8` remains the approved generator and its entire resulting lock diff is review evidence. +CI proves that the committed manifest and lock can be consumed as a frozen pair by the approved toolchain, that public-registry lock entries carry integrity evidence, and that the known generator-sensitive `@esbuild/*` peer markers remain present. It does **not** claim that resolving mutable manifest ranges again at a later time will reproduce byte-identical lock metadata. When a dependency update is needed, npm `10.9.8` remains the approved generator and its entire resulting lock diff is review evidence. ## Incident response and rollback From 6f81f52c193c1e327d078eba7a2ea3bdbfbc87c2 Mon Sep 17 00:00:00 2001 From: Seongho Bae Date: Sat, 15 Aug 2026 16:13:07 +0900 Subject: [PATCH 60/92] docs(changelog): record lock metadata drift gate --- CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 9fee41aec..cfe599265 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -9,7 +9,7 @@ ### Changed -- Pinned npm `10.9.8` as the approved lockfile generator and made primary CI consume the committed lock only through frozen `npm ci` validation, rejecting mutable npm resolution in the lock gate and requiring integrity evidence for public-registry lock entries. +- Pinned npm `10.9.8` as the approved lockfile generator and made primary CI consume the committed lock only through frozen `npm ci` validation, rejecting mutable npm resolution in the lock gate, requiring integrity evidence for public-registry lock entries, and rejecting generator-sensitive loss of root `@esbuild/*` peer metadata. ### Fixed From 6665f029564e2eb5b82b009ef90aa5242de7d043 Mon Sep 17 00:00:00 2001 From: Seongho Bae Date: Sun, 16 Aug 2026 05:06:25 +0900 Subject: [PATCH 61/92] fix(security): make PDF XML boundary explicit --- apps/desktop/src/features/score/pdfjs.ts | 21 ++++++++++++++------- 1 file changed, 14 insertions(+), 7 deletions(-) diff --git a/apps/desktop/src/features/score/pdfjs.ts b/apps/desktop/src/features/score/pdfjs.ts index e0ce7692d..ec622d42d 100644 --- a/apps/desktop/src/features/score/pdfjs.ts +++ b/apps/desktop/src/features/score/pdfjs.ts @@ -19,16 +19,23 @@ export function configureScorePdfWorker(): void { * Start parsing validated in-memory score PDF bytes with pdf.js. * * Only caller-provided bytes are accepted (validated-resource-only rule); - * this helper never fetches arbitrary URLs. The bytes are copied before they - * are handed to pdf.js because pdf.js transfers the underlying buffer to its + * this helper never supplies a URL. The bytes are copied before they are + * handed to pdf.js because pdf.js transfers the underlying buffer to its * worker, which would otherwise detach the caller's copy and break retries. * - * PDF.js 6.2.108 no longer exposes the legacy `isEvalSupported` initialization - * option. Security therefore relies on the patched parser release plus this - * narrow data-only, same-origin-worker boundary rather than an ignored and - * falsely reassuring unknown option. + * XFA rendering is explicitly disabled even though pdf.js 6.2.108 defaults it + * to `false`, and worker-side resource fetching is explicitly disabled. These + * settings make the parser boundary fail closed against XML-form activation + * and remote helper-resource acquisition instead of relying on upstream + * defaults. In the pinned pdf.js XML parser, DOCTYPE declarations are reported + * to a no-op hook and unknown named entities are preserved literally rather + * than dereferenced, so no external-entity resolver is exposed by this API. */ export function loadScorePdf(data: Uint8Array): PDFDocumentLoadingTask { configureScorePdfWorker(); - return getDocument({ data: new Uint8Array(data) }); + return getDocument({ + data: new Uint8Array(data), + enableXfa: false, + useWorkerFetch: false + }); } From bf5a3a3e296a34c84c18775409ebae71f354c23c Mon Sep 17 00:00:00 2001 From: Seongho Bae Date: Sun, 16 Aug 2026 05:06:33 +0900 Subject: [PATCH 62/92] test(security): lock down PDF parser options --- apps/desktop/src/features/score/pdfjs.test.ts | 20 ++++++++++++++----- 1 file changed, 15 insertions(+), 5 deletions(-) diff --git a/apps/desktop/src/features/score/pdfjs.test.ts b/apps/desktop/src/features/score/pdfjs.test.ts index b225830e5..8ef36a785 100644 --- a/apps/desktop/src/features/score/pdfjs.test.ts +++ b/apps/desktop/src/features/score/pdfjs.test.ts @@ -26,7 +26,7 @@ describe("score PDF.js boundary", () => { expect(GlobalWorkerOptions.workerSrc).toBe("/assets/pdf.worker.min.mjs"); }); - it("copies validated bytes through the supported data-only API", () => { + it("copies validated bytes through the hardened data-only API", () => { const source = new Uint8Array([0x25, 0x50, 0x44, 0x46]); loadScorePdf(source); @@ -34,9 +34,19 @@ describe("score PDF.js boundary", () => { expect(getDocument).toHaveBeenCalledTimes(1); const parameters = vi.mocked(getDocument).mock.calls[0]?.[0]; expect(parameters).toBeTypeOf("object"); - expect(Object.keys(parameters as object)).toEqual(["data"]); - const copiedBytes = (parameters as { data: Uint8Array }).data; - expect(copiedBytes).toEqual(source); - expect(copiedBytes).not.toBe(source); + expect(Object.keys(parameters as object)).toEqual([ + "data", + "enableXfa", + "useWorkerFetch" + ]); + const hardenedParameters = parameters as { + data: Uint8Array; + enableXfa: boolean; + useWorkerFetch: boolean; + }; + expect(hardenedParameters.data).toEqual(source); + expect(hardenedParameters.data).not.toBe(source); + expect(hardenedParameters.enableXfa).toBe(false); + expect(hardenedParameters.useWorkerFetch).toBe(false); }); }); From c65f5b12274caf046c6da05b1633baaae21199c2 Mon Sep 17 00:00:00 2001 From: Seongho Bae Date: Sun, 16 Aug 2026 05:09:42 +0900 Subject: [PATCH 63/92] docs(security): record PDF parser hardening evidence --- .../high-security-pdf-http-baseline.md | 26 ++++++++++++++----- 1 file changed, 20 insertions(+), 6 deletions(-) diff --git a/docs/doctoring/high-security-pdf-http-baseline.md b/docs/doctoring/high-security-pdf-http-baseline.md index 5e56be8bf..ab2d2035e 100644 --- a/docs/doctoring/high-security-pdf-http-baseline.md +++ b/docs/doctoring/high-security-pdf-http-baseline.md @@ -8,13 +8,16 @@ BandScope treats the PDF parser and its transitive HTTP client as one security-r - `undici` is pinned exactly to `7.29.0` through the root npm override; and - npm `10.9.8` is the approved generator for reviewed root-workspace dependency updates, while primary CI consumes the committed lock through frozen validation rather than re-resolving it. -PDF.js `6.2.108` no longer exposes the legacy `isEvalSupported` member in its public `DocumentInitParameters` contract, and `getDocument` no longer reads that member. BandScope therefore does not cast or pass an unknown option that would be ignored while creating false assurance. The primary remediation is the patched parser release, reinforced by a narrow data-only call, copied caller-owned bytes, and a same-origin bundled worker. +PDF.js `6.2.108` no longer exposes the legacy `isEvalSupported` member in its public `DocumentInitParameters` contract, and `getDocument` no longer reads that member. BandScope therefore does not cast or pass an unknown option that would be ignored while creating false assurance. The primary remediation is the patched parser release, reinforced by a narrow data-only call, copied caller-owned bytes, a same-origin bundled worker, explicit `enableXfa: false`, and explicit `useWorkerFetch: false`. ```mermaid flowchart LR A[Validated local PDF bytes] --> B[Copied Uint8Array] B --> D[Data-only DocumentInitParameters] - D --> C[pdfjs-dist 6.2.108] + D --> X[XFA disabled] + D --> F[Worker helper fetch disabled] + X --> C[pdfjs-dist 6.2.108] + F --> C C --> W[Same-origin bundled worker] W --> R[Canvas render] J[jsdom development path] --> U[undici 7.29.0 override] @@ -26,12 +29,20 @@ flowchart LR ## Threat boundary -The score viewer accepts only bytes already copied into the app-owned workspace through the native PDF intake boundary. It does not accept a URL, credentials, custom request headers, or a remote worker. This prevents a PDF from selecting an attacker-controlled fetch origin or script asset. +The score viewer accepts only bytes already copied into the app-owned workspace through the native PDF intake boundary. It does not accept a URL, credentials, custom request headers, or a remote worker. It also disables XFA rendering and PDF.js worker-side fetching of helper resources at this wrapper boundary. These controls prevent the caller from selecting an attacker-controlled document origin or worker asset and make the intended no-XML-form/no-worker-fetch policy explicit rather than relying on upstream defaults. -PDF bytes remain untrusted after the native magic-byte, size, and path checks. Parser vulnerabilities, malformed object graphs, embedded actions, and resource-exhaustion paths can still occur inside a syntactically valid PDF. The patched parser, exact dependency lock, copied data-only input, same-origin worker, and existing native intake limits therefore remain mandatory for locally selected files. +PDF bytes remain untrusted after the native magic-byte, size, and path checks. Parser vulnerabilities, malformed object graphs, embedded actions, metadata/XML parsing, and resource-exhaustion paths can still occur inside a syntactically valid PDF. The patched parser, exact dependency lock, copied data-only input, explicit parser options, same-origin worker, and existing native intake limits therefore remain mandatory for locally selected files. + +The pinned PDF.js XML parser does not expose an external-entity resolver through this wrapper: its default `onDoctype()` hook is a no-op, and `onResolveEntity()` resolves only the built-in XML entities before returning an unknown named entity literally. This source-level observation narrows what BandScope can claim; it is not a general assertion that every future PDF.js XML path is immune to entity-processing defects. Any parser upgrade must re-check the upstream implementation and repeat adversarial PDF verification. Undici is currently a development dependency reached through jsdom, but development and CI parsers process attacker-controlled fixtures, generated HTML, and network-like request bodies. A dev-only label does not make header injection, shared-cache disclosure, retry desynchronization, or cookie-attribute injection acceptable in the trusted build boundary. +## Strix finding adjudication boundary + +Strix run `31871388084` on predecessor head `6f81f52c193c1e327d078eba7a2ea3bdbfbc87c2` reported a possible XXE path through `loadScorePdf`. Its attached proof-of-concept returned only a four-byte `%PDF` prefix and stated that construction of an actual PDF containing the alleged XML payload remained necessary. It did not demonstrate entity expansion, local-file disclosure, a network request, or parser output containing an external entity. + +The finding was therefore not suppressed and was not treated as proven exploitation. Instead, the exact dependency source was inspected and the wrapper was hardened at the narrowest supported API boundary: XFA rendering and worker-side helper fetching are now explicitly disabled and regression-locked. A fresh exact-head Strix result remains mandatory; a predecessor report, whether pass or fail, is not transferable merge evidence. + ## Lockfile provenance The dependency manifests and complete lock artifact were generated and reconciled on this branch with the approved Node `22.22.3` / npm `10.9.8` toolchain before the current frozen-validation gate was finalized. The historical generation run and artifact are provenance evidence only; they do **not** satisfy a later head's merge gate and primary CI intentionally does not repeat mutable dependency resolution. @@ -52,13 +63,14 @@ The lock contract requires the exact public-registry tarball and SHA-512 SRI for The merge gate includes: - exact manifest and lock artifact tests; -- a direct PDF.js wrapper test proving copied bytes, the locally bundled worker, and an exact data-only initialization object; +- a direct PDF.js wrapper test proving copied bytes, the locally bundled worker, `enableXfa: false`, `useWorkerFetch: false`, and no URL-bearing initialization member; - TypeScript compilation against the installed PDF.js `DocumentInitParameters` rather than an unsafe cast; - valid and malformed local score-PDF component tests; - desktop lint, strict typecheck, complete measured tests, and production build; - Tauri/Rust checks and native PDF intake regressions; - `npm audit --workspaces --audit-level=high` with no high finding; - repository SAST, CodeQL, security scan, secret scan, SBOM, and dependency evidence; +- current-head Strix evidence rather than predecessor-head scanner output; - current-head central coverage and automated review; - zero unresolved actionable threads and a qualifying independent non-author approval; and - normal branch protection without administrative bypass. @@ -75,10 +87,12 @@ GitHub. (2026). *PDF.js vulnerable to arbitrary JavaScript execution upon openin Mozilla. (2026). *Document initialization parameters in PDF.js 6.2.108* [Source code]. GitHub. https://github.com/mozilla/pdf.js/blob/v6.2.108/src/display/api.js +Mozilla. (2026). *PDF.js XML parser in version 6.2.108* [Source code]. GitHub. https://github.com/mozilla/pdf.js/blob/v6.2.108/src/core/xml_parser.js + Mozilla. (2026). *PDF.js 6.2.108* [Software release]. https://github.com/mozilla/pdf.js/releases/tag/v6.2.108 Node.js contributors. (2026). *Undici 7.29.0* [Software release]. https://github.com/nodejs/undici/releases/tag/v7.29.0 npm, Inc. (2026). *npm ci*. npm Docs. https://docs.npmjs.com/cli/v11/commands/npm-ci/ -npm, Inc. (2026). *package-lock.json*. npm Docs. https://docs.npmjs.com/cli/v11/configuring-npm/package-lock-json/ \ No newline at end of file +npm, Inc. (2026). *package-lock.json*. npm Docs. https://docs.npmjs.com/cli/v11/configuring-npm/package-lock-json/ From dae5d3c8d055381d57c0971d8e40456711499476 Mon Sep 17 00:00:00 2001 From: Seongho Bae Date: Sun, 16 Aug 2026 05:11:40 +0900 Subject: [PATCH 64/92] docs(security): correct PDF.js advisory attribution --- docs/doctoring/high-security-pdf-http-baseline.md | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/docs/doctoring/high-security-pdf-http-baseline.md b/docs/doctoring/high-security-pdf-http-baseline.md index ab2d2035e..87dbd83cf 100644 --- a/docs/doctoring/high-security-pdf-http-baseline.md +++ b/docs/doctoring/high-security-pdf-http-baseline.md @@ -8,7 +8,9 @@ BandScope treats the PDF parser and its transitive HTTP client as one security-r - `undici` is pinned exactly to `7.29.0` through the root npm override; and - npm `10.9.8` is the approved generator for reviewed root-workspace dependency updates, while primary CI consumes the committed lock through frozen validation rather than re-resolving it. -PDF.js `6.2.108` no longer exposes the legacy `isEvalSupported` member in its public `DocumentInitParameters` contract, and `getDocument` no longer reads that member. BandScope therefore does not cast or pass an unknown option that would be ignored while creating false assurance. The primary remediation is the patched parser release, reinforced by a narrow data-only call, copied caller-owned bytes, a same-origin bundled worker, explicit `enableXfa: false`, and explicit `useWorkerFetch: false`. +Repository dependency/security tooling reported the protected-base `pdfjs-dist@6.1.200` as requiring a newer floor. That finding is kept distinct from the older, GitHub-reviewed CVE-2024-4367 / GHSA-wgrm-67xf-hhpq: the 2024 advisory affected `pdfjs-dist <=4.1.392` and was fixed in `4.2.67`, so it is historical parser-risk context and is **not** evidence that `6.1.200` was affected by that CVE. BandScope pins the current `6.2.108` artifact selected by the repository security baseline and requires current-head audit/security evidence rather than misattributing a scanner result to an unrelated advisory. + +PDF.js `6.2.108` no longer exposes the legacy `isEvalSupported` member in its public `DocumentInitParameters` contract, and `getDocument` no longer reads that member. BandScope therefore does not cast or pass an unknown option that would be ignored while creating false assurance. The parser boundary is reinforced by a narrow data-only call, copied caller-owned bytes, a same-origin bundled worker, explicit `enableXfa: false`, and explicit `useWorkerFetch: false`. ```mermaid flowchart LR @@ -31,7 +33,7 @@ flowchart LR The score viewer accepts only bytes already copied into the app-owned workspace through the native PDF intake boundary. It does not accept a URL, credentials, custom request headers, or a remote worker. It also disables XFA rendering and PDF.js worker-side fetching of helper resources at this wrapper boundary. These controls prevent the caller from selecting an attacker-controlled document origin or worker asset and make the intended no-XML-form/no-worker-fetch policy explicit rather than relying on upstream defaults. -PDF bytes remain untrusted after the native magic-byte, size, and path checks. Parser vulnerabilities, malformed object graphs, embedded actions, metadata/XML parsing, and resource-exhaustion paths can still occur inside a syntactically valid PDF. The patched parser, exact dependency lock, copied data-only input, explicit parser options, same-origin worker, and existing native intake limits therefore remain mandatory for locally selected files. +PDF bytes remain untrusted after the native magic-byte, size, and path checks. Parser vulnerabilities, malformed object graphs, embedded actions, metadata/XML parsing, and resource-exhaustion paths can still occur inside a syntactically valid PDF. The exact dependency lock, copied data-only input, explicit parser options, same-origin worker, and existing native intake limits therefore remain mandatory for locally selected files. The pinned PDF.js XML parser does not expose an external-entity resolver through this wrapper: its default `onDoctype()` hook is a no-op, and `onResolveEntity()` resolves only the built-in XML entities before returning an unknown named entity literally. This source-level observation narrows what BandScope can claim; it is not a general assertion that every future PDF.js XML path is immune to entity-processing defects. Any parser upgrade must re-check the upstream implementation and repeat adversarial PDF verification. @@ -83,7 +85,7 @@ Rollback restores the previous desktop manifest, root override, complete lock, P ## References -GitHub. (2026). *PDF.js vulnerable to arbitrary JavaScript execution upon opening a malicious PDF* (GHSA-hq66-cqwq-w95j) [Security advisory]. https://github.com/advisories/GHSA-hq66-cqwq-w95j +GitHub. (2024). *PDF.js vulnerable to arbitrary JavaScript execution upon opening a malicious PDF* (GHSA-wgrm-67xf-hhpq) [Security advisory]. https://github.com/advisories/GHSA-wgrm-67xf-hhpq Mozilla. (2026). *Document initialization parameters in PDF.js 6.2.108* [Source code]. GitHub. https://github.com/mozilla/pdf.js/blob/v6.2.108/src/display/api.js From d1d86419f3e10715c75c2edf169b92fe09622e8f Mon Sep 17 00:00:00 2001 From: Seongho Bae Date: Sun, 16 Aug 2026 10:12:36 +0900 Subject: [PATCH 65/92] test: measure Python branch coverage --- services/analysis-engine/pyproject.toml | 1 + 1 file changed, 1 insertion(+) diff --git a/services/analysis-engine/pyproject.toml b/services/analysis-engine/pyproject.toml index 092372dd2..fb8f7f062 100644 --- a/services/analysis-engine/pyproject.toml +++ b/services/analysis-engine/pyproject.toml @@ -37,6 +37,7 @@ filterwarnings = [ ] [tool.coverage.run] +branch = true source = ["src/bandscope_analysis"] [tool.mypy] From 2b543d5d5c027a3298ca2258a2e2e5d657a331bb Mon Sep 17 00:00:00 2001 From: Seongho Bae Date: Sun, 16 Aug 2026 10:20:30 +0900 Subject: [PATCH 66/92] test: cover previously hidden Python branch arcs --- .../tests/test_branch_coverage_contract.py | 215 ++++++++++++++++++ 1 file changed, 215 insertions(+) create mode 100644 services/analysis-engine/tests/test_branch_coverage_contract.py diff --git a/services/analysis-engine/tests/test_branch_coverage_contract.py b/services/analysis-engine/tests/test_branch_coverage_contract.py new file mode 100644 index 000000000..b92aa7f6f --- /dev/null +++ b/services/analysis-engine/tests/test_branch_coverage_contract.py @@ -0,0 +1,215 @@ +"""Regression tests for branch arcs hidden by the former statement-only gate.""" + +from __future__ import annotations + +import io +import json +from pathlib import Path +from unittest.mock import patch + +import numpy as np +import pytest + +from bandscope_analysis import api as analysis_api +from bandscope_analysis import cli +from bandscope_analysis.chords.analyzer import ChordAnalyzer +from bandscope_analysis.chords.chord_recognizer import ChordRecognizer +from bandscope_analysis.exports import chart +from bandscope_analysis.roles.activity import compute_handoffs +from bandscope_analysis.roles.extractor import RoleExtractor +from bandscope_analysis.sections.segmenter import detect_boundaries +from bandscope_analysis.temporal import hits +from bandscope_analysis.transcription import api as transcription_api + + +def test_local_audio_feature_builder_preserves_untyped_empty_stem_result() -> None: + """Keep a separator result unchanged when no stem-role map can be inferred.""" + request = { + "sourceKind": "local_audio", + "localSource": {"sourcePath": "/tmp/song.wav"}, + } + separation_result = {"stems": {}} + + with ( + patch.object( + analysis_api, + "_stem_work_arrays_path", + return_value=Path("/tmp/bandscope-arrays.npz"), + ), + patch.object( + analysis_api, + "_run_stem_separation_with_timeout", + return_value=separation_result, + ), + patch.object(analysis_api, "_normalize_stem_role_types", return_value=None), + ): + result = analysis_api._build_local_audio_features(request) # type: ignore[arg-type] + + assert result == separation_result + + +def test_chord_analyzer_deduplicates_user_and_recognized_chords() -> None: + """Exercise duplicate branches for both user-entered and DSP chord sources.""" + analyzer = ChordAnalyzer() + user_roles = [ + {"harmony": {"chord": "Am", "functionLabel": "vi", "source": "user"}}, + {"harmony": {"chord": "Am", "functionLabel": "repeat", "source": "user"}}, + ] + recognized = [ + {"start_time": 0.0, "end_time": 1.0, "chord": "C", "confidence": "high"}, + {"start_time": 1.0, "end_time": 2.0, "chord": "C", "confidence": "low"}, + ] + + assert [item["chord"] for item in analyzer._extract_user_chords(user_roles)] == ["Am"] + assert [item["chord"] for item in analyzer._chords_for_section(recognized, None)] == ["C"] + + +def test_chord_analyzer_all_no_chord_recognition_falls_back_to_legacy_confidence() -> None: + """Use legacy confidence when recognizer output exists but every frame is no-chord.""" + analyzer = ChordAnalyzer() + chords = [{"chord": "G", "functionLabel": "I", "source": "model"}] + recognized = [ + {"start_time": 0.0, "end_time": 1.0, "chord": "N", "confidence": "low"} + ] + + assert analyzer._compute_section_confidence(chords, recognized, []) == ("medium", "model") + + +def test_chord_segment_builder_handles_zero_frames_without_final_segment() -> None: + """Return no segment when the frame decoder has no frames to materialize.""" + recognizer = ChordRecognizer() + empty_observations = np.empty((len(recognizer.chord_labels), 0), dtype=np.float64) + + with ( + patch.object(recognizer, "_build_observation_probs", return_value=empty_observations), + patch.object(recognizer, "_viterbi_decode", return_value=np.array([], dtype=np.int64)), + ): + result = recognizer._create_chord_segments( + np.empty((12, 0), dtype=np.float64), + empty_observations, + np.empty(0, dtype=np.float64), + 22_050, + ) + + assert result == [] + + +def test_cli_skips_temporal_probe_when_local_source_path_is_empty( + monkeypatch: pytest.MonkeyPatch, +) -> None: + """Do not invoke the temporary temporal probe for an empty local source path.""" + payload = { + "jobId": "job-empty-source", + "request": { + "sourceKind": "local_audio", + "localSource": {"sourcePath": "", "fileName": "song.wav"}, + }, + } + stdout = io.StringIO() + monkeypatch.setattr(cli.sys, "argv", ["cli.py"]) + monkeypatch.setattr(cli.sys, "stdin", io.StringIO(json.dumps(payload))) + monkeypatch.setattr(cli.sys, "stdout", stdout) + + with ( + patch.object(cli, "TemporalAnalyzer") as temporal_analyzer, + patch.object( + cli, + "run_analysis_job", + return_value={"jobId": "job-empty-source", "state": "failed"}, + ), + ): + assert cli.main() == 0 + + temporal_analyzer.assert_not_called() + assert json.loads(stdout.getvalue())["jobId"] == "job-empty-source" + + +def test_chart_section_without_active_roles_and_duplicate_priority_footer() -> None: + """Render role-free section lines and deduplicate repeated footer priorities.""" + section = { + "label": "verse", + "timeRange": {"start": 0, "end": 10}, + "roles": [], + "partGraph": [], + } + assert chart._section_lines([section]) == ["[00:00-00:10] VERSE"] + + role = {"id": "bass", "name": "Bass", "rehearsalPriority": "Lock with kick"} + footer = chart._footer_lines( + {"exportSummary": {}}, + [{"roles": [role]}, {"roles": [dict(role)]}], + ) + assert footer == ["Priorities:", " - Bass: Lock with kick"] + + +def test_handoffs_ignore_roles_that_exist_only_in_the_next_section() -> None: + """Keep current-section output bounded when a new role appears next section.""" + handoffs = compute_handoffs( + {"lead-vocal": True}, + {"lead-vocal": False, "new-synth": True}, + ) + + assert handoffs == {"lead-vocal": (["new-synth"], [])} + + +def test_role_feature_extraction_handles_absent_and_partial_stem_evidence() -> None: + """Leave fields empty when stems omit vocals or yield incomplete/no-chord evidence.""" + extractor = RoleExtractor() + stems = { + "bass": np.zeros(16, dtype=np.float32), + "other": np.zeros(16, dtype=np.float32), + } + + with ( + patch( + "bandscope_analysis.ranges.pitch_tracker.PitchTracker.track", + return_value={"lowest_note": "E1", "highest_note": ""}, + ), + patch( + "bandscope_analysis.chords.chord_recognizer.ChordRecognizer.recognize", + return_value=[{"chord": "N"}], + ), + ): + vocal_range, vocal_chord, bass_range, bass_chord = extractor._extract_features( + stems, 22_050 + ) + + assert vocal_range == {"lowestNote": "", "highestNote": ""} + assert bass_range == {"lowestNote": "", "highestNote": ""} + assert vocal_chord == "" + assert bass_chord == "" + + +def test_boundary_detection_skips_peak_without_matching_frame_time() -> None: + """Ignore a novelty peak whose frame index has no corresponding timestamp.""" + novelty = np.array([0.0, 0.0, 1.0, 0.0, 0.0], dtype=np.float64) + frame_times = np.array([0.0, 1.0], dtype=np.float64) + + assert detect_boundaries(novelty, frame_times, duration=20.0) == [0.0] + + +def test_shared_hits_continue_after_an_energetic_stem_has_no_onsets() -> None: + """Skip an onset-free energetic stem while continuing to inspect later stems.""" + energetic = { + "vocals": np.ones(8, dtype=np.float64), + "bass": np.ones(8, dtype=np.float64), + } + + with ( + patch.object(hits, "_energetic_stems", return_value=energetic), + patch.object( + hits.librosa.onset, + "onset_detect", + side_effect=[np.array([], dtype=np.float64), np.array([1.0], dtype=np.float64)], + ), + ): + result = hits.detect_shared_hits(energetic, 22_050) + + assert result == [] + + +def test_contiguous_regions_finishes_cleanly_after_an_unvoiced_frame() -> None: + """Do not append a second region when the final frame already closed the region.""" + mask = np.array([True, False], dtype=np.bool_) + + assert transcription_api._contiguous_regions(mask) == [(0, 0)] From 4ec36a6c0e03104127b197dd18361956accaccff Mon Sep 17 00:00:00 2001 From: Seongho Bae Date: Sun, 16 Aug 2026 10:20:48 +0900 Subject: [PATCH 67/92] refactor: remove impossible handoff membership branch --- .../src/bandscope_analysis/roles/activity.py | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/services/analysis-engine/src/bandscope_analysis/roles/activity.py b/services/analysis-engine/src/bandscope_analysis/roles/activity.py index 9925d6a2d..d91eaeb1e 100644 --- a/services/analysis-engine/src/bandscope_analysis/roles/activity.py +++ b/services/analysis-engine/src/bandscope_analysis/roles/activity.py @@ -147,14 +147,18 @@ def compute_handoffs( # Find roles that activate in the next section activating = [r for r in next_roles if next_roles[r] and not current_roles.get(r, False)] - # Roles that deactivate hand off to roles that activate + # Every deactivating role comes from current_roles, so it is guaranteed to + # have been initialized in handoffs above. Keeping a second membership test + # only creates an unreachable branch and obscures the current-section output + # invariant. for deact_role in deactivating: - if deact_role in handoffs: - handoffs[deact_role] = (activating[:], handoffs[deact_role][1]) + handoffs[deact_role] = (activating[:], handoffs[deact_role][1]) - # Roles that activate receive handoffs from roles that deactivated + # Roles that already existed but become active receive handoffs from roles + # that deactivated. Roles introduced only in the next section are not part + # of the current section's output mapping. for act_role in activating: if act_role in handoffs: handoffs[act_role] = (handoffs[act_role][0], deactivating[:]) - return handoffs + return handoffs \ No newline at end of file From e18894aa08d6a759254eba668c85a709e0612d20 Mon Sep 17 00:00:00 2001 From: Seongho Bae Date: Sun, 16 Aug 2026 10:31:14 +0900 Subject: [PATCH 68/92] style: format branch-coverage source repair --- .../analysis-engine/src/bandscope_analysis/roles/activity.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/services/analysis-engine/src/bandscope_analysis/roles/activity.py b/services/analysis-engine/src/bandscope_analysis/roles/activity.py index d91eaeb1e..623e24e77 100644 --- a/services/analysis-engine/src/bandscope_analysis/roles/activity.py +++ b/services/analysis-engine/src/bandscope_analysis/roles/activity.py @@ -161,4 +161,4 @@ def compute_handoffs( if act_role in handoffs: handoffs[act_role] = (handoffs[act_role][0], deactivating[:]) - return handoffs \ No newline at end of file + return handoffs From 42e0b1642e9843dae5e3cde009c8154a5b2479fd Mon Sep 17 00:00:00 2001 From: Seongho Bae Date: Sun, 16 Aug 2026 10:33:25 +0900 Subject: [PATCH 69/92] chore: run one-shot Ruff formatter for PR 861 --- .github/workflows/repair-861-format.yml | 51 +++++++++++++++++++++++++ 1 file changed, 51 insertions(+) create mode 100644 .github/workflows/repair-861-format.yml diff --git a/.github/workflows/repair-861-format.yml b/.github/workflows/repair-861-format.yml new file mode 100644 index 000000000..b7dcebcef --- /dev/null +++ b/.github/workflows/repair-861-format.yml @@ -0,0 +1,51 @@ +name: Repair PR 861 Python formatting + +on: + push: + branches: + - test/enforce-python-branch-coverage + paths: + - .github/workflows/repair-861-format.yml + +permissions: + contents: write + +jobs: + format-python: + runs-on: ubuntu-24.04 + steps: + - name: Checkout contributor branch + uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 + with: + ref: test/enforce-python-branch-coverage + fetch-depth: 0 + - name: Set up Python + uses: actions/setup-python@a309ff8b426b58ec0e2a45f0f869d46889d02405 + with: + python-version: '3.12' + - name: Set up uv + uses: astral-sh/setup-uv@11f9893b081a58869d3b5fccaea48c9e9e46f990 + with: + version: '0.8.6' + enable-cache: false + - name: Sync analysis development dependencies + run: uv sync --project services/analysis-engine --group dev --frozen + - name: Apply repository Ruff formatter + run: | + cd services/analysis-engine + uv run ruff format src/bandscope_analysis/roles/activity.py tests/test_branch_coverage_contract.py + - name: Remove one-shot workflow and commit repair + shell: bash + run: | + set -euo pipefail + rm .github/workflows/repair-861-format.yml + git diff --check + git config user.name 'github-actions[bot]' + git config user.email '41898282+github-actions[bot]@users.noreply.github.com' + git add services/analysis-engine/src/bandscope_analysis/roles/activity.py services/analysis-engine/tests/test_branch_coverage_contract.py .github/workflows/repair-861-format.yml + if git diff --cached --quiet; then + echo 'Formatter produced no tree change; refusing to leave repair workflow behind.' >&2 + exit 1 + fi + git commit -m 'style: apply repository Python formatter' + git push origin HEAD:test/enforce-python-branch-coverage From f3a0c27db3b9388cc7fa8316b024ab0e4d97b220 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Sun, 16 Aug 2026 01:33:58 +0000 Subject: [PATCH 70/92] style: apply repository Python formatter --- .github/workflows/repair-861-format.yml | 51 ------------------- .../tests/test_branch_coverage_contract.py | 4 +- 2 files changed, 1 insertion(+), 54 deletions(-) delete mode 100644 .github/workflows/repair-861-format.yml diff --git a/.github/workflows/repair-861-format.yml b/.github/workflows/repair-861-format.yml deleted file mode 100644 index b7dcebcef..000000000 --- a/.github/workflows/repair-861-format.yml +++ /dev/null @@ -1,51 +0,0 @@ -name: Repair PR 861 Python formatting - -on: - push: - branches: - - test/enforce-python-branch-coverage - paths: - - .github/workflows/repair-861-format.yml - -permissions: - contents: write - -jobs: - format-python: - runs-on: ubuntu-24.04 - steps: - - name: Checkout contributor branch - uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 - with: - ref: test/enforce-python-branch-coverage - fetch-depth: 0 - - name: Set up Python - uses: actions/setup-python@a309ff8b426b58ec0e2a45f0f869d46889d02405 - with: - python-version: '3.12' - - name: Set up uv - uses: astral-sh/setup-uv@11f9893b081a58869d3b5fccaea48c9e9e46f990 - with: - version: '0.8.6' - enable-cache: false - - name: Sync analysis development dependencies - run: uv sync --project services/analysis-engine --group dev --frozen - - name: Apply repository Ruff formatter - run: | - cd services/analysis-engine - uv run ruff format src/bandscope_analysis/roles/activity.py tests/test_branch_coverage_contract.py - - name: Remove one-shot workflow and commit repair - shell: bash - run: | - set -euo pipefail - rm .github/workflows/repair-861-format.yml - git diff --check - git config user.name 'github-actions[bot]' - git config user.email '41898282+github-actions[bot]@users.noreply.github.com' - git add services/analysis-engine/src/bandscope_analysis/roles/activity.py services/analysis-engine/tests/test_branch_coverage_contract.py .github/workflows/repair-861-format.yml - if git diff --cached --quiet; then - echo 'Formatter produced no tree change; refusing to leave repair workflow behind.' >&2 - exit 1 - fi - git commit -m 'style: apply repository Python formatter' - git push origin HEAD:test/enforce-python-branch-coverage diff --git a/services/analysis-engine/tests/test_branch_coverage_contract.py b/services/analysis-engine/tests/test_branch_coverage_contract.py index b92aa7f6f..4bf75d1c9 100644 --- a/services/analysis-engine/tests/test_branch_coverage_contract.py +++ b/services/analysis-engine/tests/test_branch_coverage_contract.py @@ -68,9 +68,7 @@ def test_chord_analyzer_all_no_chord_recognition_falls_back_to_legacy_confidence """Use legacy confidence when recognizer output exists but every frame is no-chord.""" analyzer = ChordAnalyzer() chords = [{"chord": "G", "functionLabel": "I", "source": "model"}] - recognized = [ - {"start_time": 0.0, "end_time": 1.0, "chord": "N", "confidence": "low"} - ] + recognized = [{"start_time": 0.0, "end_time": 1.0, "chord": "N", "confidence": "low"}] assert analyzer._compute_section_confidence(chords, recognized, []) == ("medium", "model") From fcf7e52ac441c92a8950075f1b292c3b3dfc0ff7 Mon Sep 17 00:00:00 2001 From: Seongho Bae Date: Sun, 16 Aug 2026 10:34:19 +0900 Subject: [PATCH 71/92] test: revalidate formatted branch-coverage head From 6afbc9fff585a5a7c2bf0454b0673c3f71f1b0e1 Mon Sep 17 00:00:00 2001 From: Seongho Bae Date: Sun, 16 Aug 2026 10:40:08 +0900 Subject: [PATCH 72/92] test: cover flat novelty normalization branch --- .../tests/test_branch_coverage_contract.py | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/services/analysis-engine/tests/test_branch_coverage_contract.py b/services/analysis-engine/tests/test_branch_coverage_contract.py index 4bf75d1c9..ce6dfd44e 100644 --- a/services/analysis-engine/tests/test_branch_coverage_contract.py +++ b/services/analysis-engine/tests/test_branch_coverage_contract.py @@ -17,7 +17,10 @@ from bandscope_analysis.exports import chart from bandscope_analysis.roles.activity import compute_handoffs from bandscope_analysis.roles.extractor import RoleExtractor -from bandscope_analysis.sections.segmenter import detect_boundaries +from bandscope_analysis.sections.segmenter import ( + _checkerboard_novelty_reference, + detect_boundaries, +) from bandscope_analysis.temporal import hits from bandscope_analysis.transcription import api as transcription_api @@ -178,6 +181,16 @@ def test_role_feature_extraction_handles_absent_and_partial_stem_evidence() -> N assert bass_chord == "" +def test_checkerboard_reference_preserves_zero_novelty_without_division() -> None: + """Keep a flat full-size SSM finite instead of normalizing a zero peak.""" + flat_ssm = np.zeros((6, 6), dtype=np.float64) + + novelty = _checkerboard_novelty_reference(flat_ssm, kernel_size=4) + + np.testing.assert_array_equal(novelty, np.zeros(6, dtype=np.float64)) + assert np.isfinite(novelty).all() + + def test_boundary_detection_skips_peak_without_matching_frame_time() -> None: """Ignore a novelty peak whose frame index has no corresponding timestamp.""" novelty = np.array([0.0, 0.0, 1.0, 0.0, 0.0], dtype=np.float64) From ce35d3dd37a295c2b278ad1c7e7a4bda4d2fab53 Mon Sep 17 00:00:00 2001 From: Seongho Bae Date: Mon, 17 Aug 2026 21:02:16 -0700 Subject: [PATCH 73/92] test(ci): require credential-free lock validation checkout --- services/analysis-engine/tests/test_npm_toolchain_contract.py | 1 + 1 file changed, 1 insertion(+) diff --git a/services/analysis-engine/tests/test_npm_toolchain_contract.py b/services/analysis-engine/tests/test_npm_toolchain_contract.py index 6f38db8c0..f570d5a84 100644 --- a/services/analysis-engine/tests/test_npm_toolchain_contract.py +++ b/services/analysis-engine/tests/test_npm_toolchain_contract.py @@ -55,6 +55,7 @@ def test_primary_ci_consumes_the_lock_without_mutable_resolution() -> None: assert "npm ci --ignore-scripts --no-audit --no-fund" in lock_job assert "git diff --exit-code -- package.json package-lock.json" in lock_job assert "needs: lock-validation" in workflow + assert "persist-credentials: false" in lock_job assert "npm install " not in lock_job assert "npm update " not in lock_job assert "npx " not in lock_job From 99e6be9f0933df605c03c04e959b47c5c2405ca6 Mon Sep 17 00:00:00 2001 From: Seongho Bae Date: Mon, 17 Aug 2026 21:02:48 -0700 Subject: [PATCH 74/92] fix(ci): drop checkout credentials from lock validation --- .github/workflows/ci.yml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 4ec39fc9d..64b045d53 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -25,6 +25,8 @@ jobs: runs-on: ubuntu-latest steps: - uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0 + with: + persist-credentials: false - uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6.4.0 with: node-version: "22.22.3" From f8dc2e1e8260f456f7b422ac96a8055735b23124 Mon Sep 17 00:00:00 2001 From: Seongho Bae Date: Thu, 20 Aug 2026 07:27:53 -0700 Subject: [PATCH 75/92] test(score): prove PDF byte-buffer isolation --- apps/desktop/src/features/score/pdfjs.test.ts | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/apps/desktop/src/features/score/pdfjs.test.ts b/apps/desktop/src/features/score/pdfjs.test.ts index 8ef36a785..8b494ca70 100644 --- a/apps/desktop/src/features/score/pdfjs.test.ts +++ b/apps/desktop/src/features/score/pdfjs.test.ts @@ -46,7 +46,9 @@ describe("score PDF.js boundary", () => { }; expect(hardenedParameters.data).toEqual(source); expect(hardenedParameters.data).not.toBe(source); + source[0] = 0x00; + expect(hardenedParameters.data[0]).toBe(0x25); expect(hardenedParameters.enableXfa).toBe(false); expect(hardenedParameters.useWorkerFetch).toBe(false); }); -}); +}); \ No newline at end of file From 06e060bde341e2fee40e2c2ab2fd0edfaffb5903 Mon Sep 17 00:00:00 2001 From: Seongho Bae Date: Thu, 20 Aug 2026 07:44:39 -0700 Subject: [PATCH 76/92] test(coverage): prove shared-hit scan reaches later stems --- .../analysis-engine/tests/test_branch_coverage_contract.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/services/analysis-engine/tests/test_branch_coverage_contract.py b/services/analysis-engine/tests/test_branch_coverage_contract.py index ce6dfd44e..6198141c0 100644 --- a/services/analysis-engine/tests/test_branch_coverage_contract.py +++ b/services/analysis-engine/tests/test_branch_coverage_contract.py @@ -212,11 +212,12 @@ def test_shared_hits_continue_after_an_energetic_stem_has_no_onsets() -> None: hits.librosa.onset, "onset_detect", side_effect=[np.array([], dtype=np.float64), np.array([1.0], dtype=np.float64)], - ), + ) as onset_detect, ): result = hits.detect_shared_hits(energetic, 22_050) assert result == [] + assert onset_detect.call_count == 2 def test_contiguous_regions_finishes_cleanly_after_an_unvoiced_frame() -> None: From 4fac4e74572e2752a484ba5b20ddae6582ef23b1 Mon Sep 17 00:00:00 2001 From: Seongho Bae Date: Thu, 20 Aug 2026 07:45:39 -0700 Subject: [PATCH 77/92] test(supply-chain): validate npm CI structure fail-closed --- .../tests/test_npm_toolchain_contract.py | 64 +++++++++++++++++-- 1 file changed, 60 insertions(+), 4 deletions(-) diff --git a/services/analysis-engine/tests/test_npm_toolchain_contract.py b/services/analysis-engine/tests/test_npm_toolchain_contract.py index f570d5a84..9904afb4d 100644 --- a/services/analysis-engine/tests/test_npm_toolchain_contract.py +++ b/services/analysis-engine/tests/test_npm_toolchain_contract.py @@ -3,8 +3,11 @@ from __future__ import annotations import json +import re from pathlib import Path +import yaml + _REPOSITORY_ROOT = Path(__file__).resolve().parents[3] _EXPECTED_NPM_VERSION = "10.9.8" _EXPECTED_NODE_VERSION = "22.22.3" @@ -22,6 +25,29 @@ def _primary_ci_workflow() -> str: return (_REPOSITORY_ROOT / ".github" / "workflows" / "ci.yml").read_text(encoding="utf-8") +def _primary_ci_jobs(workflow: str) -> dict[str, object]: + """Parse and return the primary CI job mapping for structural assertions.""" + document = yaml.safe_load(workflow) + assert isinstance(document, dict) + jobs = document.get("jobs") + assert isinstance(jobs, dict) + return jobs + + +def _job_steps(jobs: dict[str, object], job_name: str) -> list[dict[str, object]]: + """Return one CI job's structurally parsed step mappings.""" + job = jobs.get(job_name) + assert isinstance(job, dict) + steps = job.get("steps") + assert isinstance(steps, list) + + parsed_steps: list[dict[str, object]] = [] + for step in steps: + assert isinstance(step, dict) + parsed_steps.append(step) + return parsed_steps + + def _lock_validation_job(workflow: str) -> str: """Return only the frozen npm lock-validation job from the CI workflow.""" start = workflow.index(" lock-validation:") @@ -29,6 +55,34 @@ def _lock_validation_job(workflow: str) -> str: return workflow[start:end] +def _assert_checkout_credentials_not_persisted(steps: list[dict[str, object]]) -> None: + """Require the owning checkout step itself to disable credential persistence.""" + checkout_steps = [ + step + for step in steps + if isinstance(step.get("uses"), str) and str(step["uses"]).startswith("actions/checkout@") + ] + assert len(checkout_steps) == 1 + checkout_options = checkout_steps[0].get("with") + assert isinstance(checkout_options, dict) + assert checkout_options.get("persist-credentials") is False + + +def _assert_no_mutable_npm_commands(steps: list[dict[str, object]]) -> None: + """Reject mutable npm/npx commands at executable shell-command boundaries.""" + mutable_npm = re.compile(r"(?:^|[;&|]\s*)npm\s+(?:install|update)(?:\s|$)") + mutable_npx = re.compile(r"(?:^|[;&|]\s*)npx(?:\s|$)") + + for step in steps: + run = step.get("run") + if not isinstance(run, str): + continue + for line in run.splitlines(): + command = line.strip() + assert mutable_npm.search(command) is None + assert mutable_npx.search(command) is None + + def test_root_manifest_pins_the_lockfile_generator_and_fails_on_drift() -> None: """Require npm and source-tree commands to reject a different generator.""" manifest = _root_manifest() @@ -47,6 +101,8 @@ def test_root_manifest_pins_the_lockfile_generator_and_fails_on_drift() -> None: def test_primary_ci_consumes_the_lock_without_mutable_resolution() -> None: """Keep lock validation frozen while retaining exact Node and npm provenance.""" workflow = _primary_ci_workflow() + jobs = _primary_ci_jobs(workflow) + lock_steps = _job_steps(jobs, "lock-validation") lock_job = _lock_validation_job(workflow) assert f'node-version: "{_EXPECTED_NODE_VERSION}"' in workflow @@ -55,10 +111,10 @@ def test_primary_ci_consumes_the_lock_without_mutable_resolution() -> None: assert "npm ci --ignore-scripts --no-audit --no-fund" in lock_job assert "git diff --exit-code -- package.json package-lock.json" in lock_job assert "needs: lock-validation" in workflow - assert "persist-credentials: false" in lock_job - assert "npm install " not in lock_job - assert "npm update " not in lock_job - assert "npx " not in lock_job + + for job_name in ("lock-validation", "verify", "rust-check"): + _assert_checkout_credentials_not_persisted(_job_steps(jobs, job_name)) + _assert_no_mutable_npm_commands(lock_steps) def test_root_lock_uses_the_supported_location_keyed_format() -> None: From 445041611de94b3aa375e0eefa016f78dc2f18a6 Mon Sep 17 00:00:00 2001 From: Seongho Bae Date: Thu, 20 Aug 2026 09:42:57 -0700 Subject: [PATCH 78/92] test(supply-chain): reject vulnerable npm tar runtime --- .../tests/test_npm_toolchain_contract.py | 39 ++++++++++++++++++- 1 file changed, 37 insertions(+), 2 deletions(-) diff --git a/services/analysis-engine/tests/test_npm_toolchain_contract.py b/services/analysis-engine/tests/test_npm_toolchain_contract.py index 9904afb4d..56277dba9 100644 --- a/services/analysis-engine/tests/test_npm_toolchain_contract.py +++ b/services/analysis-engine/tests/test_npm_toolchain_contract.py @@ -9,8 +9,10 @@ import yaml _REPOSITORY_ROOT = Path(__file__).resolve().parents[3] -_EXPECTED_NPM_VERSION = "10.9.8" +_EXPECTED_NPM_VERSION = "10.9.9" _EXPECTED_NODE_VERSION = "22.22.3" +_MINIMUM_NPM_TAR_VERSION = "7.5.19" +_NPM_RUNTIME_CHECK = "node scripts/checks/verify_npm_runtime.mjs" def _root_manifest() -> dict[str, object]: @@ -83,6 +85,28 @@ def _assert_no_mutable_npm_commands(steps: list[dict[str, object]]) -> None: assert mutable_npx.search(command) is None +def _assert_patched_npm_precedes_dependency_consumption(steps: list[dict[str, object]]) -> None: + """Require Corepack npm activation and runtime audit before the first npm dependency read.""" + run_steps = [str(step["run"]) for step in steps if isinstance(step.get("run"), str)] + activation_index = next( + (index for index, command in enumerate(run_steps) if "corepack enable npm" in command), + None, + ) + audit_index = next( + (index for index, command in enumerate(run_steps) if "npm run check:npm-runtime" in command), + None, + ) + consumption_index = next( + (index for index, command in enumerate(run_steps) if re.search(r"(?:^|\n)\s*npm ci(?:\s|$)", command)), + None, + ) + + assert activation_index is not None + assert audit_index is not None + assert consumption_index is not None + assert activation_index < audit_index < consumption_index + + def test_root_manifest_pins_the_lockfile_generator_and_fails_on_drift() -> None: """Require npm and source-tree commands to reject a different generator.""" manifest = _root_manifest() @@ -96,6 +120,15 @@ def test_root_manifest_pins_the_lockfile_generator_and_fails_on_drift() -> None: "onFail": "error", } } + scripts = manifest.get("scripts") + assert isinstance(scripts, dict) + assert scripts.get("check:npm-runtime") == _NPM_RUNTIME_CHECK + + runtime_check = (_REPOSITORY_ROOT / "scripts" / "checks" / "verify_npm_runtime.mjs").read_text( + encoding="utf-8" + ) + assert f'EXPECTED_NPM_VERSION = "{_EXPECTED_NPM_VERSION}"' in runtime_check + assert f'MINIMUM_TAR_VERSION = "{_MINIMUM_NPM_TAR_VERSION}"' in runtime_check def test_primary_ci_consumes_the_lock_without_mutable_resolution() -> None: @@ -113,7 +146,9 @@ def test_primary_ci_consumes_the_lock_without_mutable_resolution() -> None: assert "needs: lock-validation" in workflow for job_name in ("lock-validation", "verify", "rust-check"): - _assert_checkout_credentials_not_persisted(_job_steps(jobs, job_name)) + job_steps = _job_steps(jobs, job_name) + _assert_checkout_credentials_not_persisted(job_steps) + _assert_patched_npm_precedes_dependency_consumption(job_steps) _assert_no_mutable_npm_commands(lock_steps) From b77ff7c254fa297722a3717ad558cb19e8f3df4c Mon Sep 17 00:00:00 2001 From: Seongho Bae Date: Thu, 20 Aug 2026 09:43:35 -0700 Subject: [PATCH 79/92] fix(supply-chain): verify patched npm tar runtime --- scripts/checks/verify_npm_runtime.mjs | 59 +++++++++++++++++++++++++++ 1 file changed, 59 insertions(+) create mode 100644 scripts/checks/verify_npm_runtime.mjs diff --git a/scripts/checks/verify_npm_runtime.mjs b/scripts/checks/verify_npm_runtime.mjs new file mode 100644 index 000000000..43eaf0ab4 --- /dev/null +++ b/scripts/checks/verify_npm_runtime.mjs @@ -0,0 +1,59 @@ +import { readFileSync } from "node:fs"; +import { dirname, resolve } from "node:path"; + +const EXPECTED_NPM_VERSION = "10.9.9"; +const MINIMUM_TAR_VERSION = "7.5.19"; + +function failClosed() { + console.error("npm runtime provenance check failed"); + process.exit(1); +} + +function readPackageVersion(packagePath) { + try { + const document = JSON.parse(readFileSync(packagePath, "utf8")); + if ( + typeof document !== "object" || + document === null || + typeof document.version !== "string" + ) { + failClosed(); + } + return document.version; + } catch { + failClosed(); + } +} + +function parseNumericVersion(version) { + const match = /^(\d+)\.(\d+)\.(\d+)$/.exec(version); + if (match === null) { + failClosed(); + } + return match.slice(1).map((part) => Number.parseInt(part, 10)); +} + +function versionAtLeast(actual, minimum) { + const actualParts = parseNumericVersion(actual); + const minimumParts = parseNumericVersion(minimum); + for (let index = 0; index < minimumParts.length; index += 1) { + if (actualParts[index] > minimumParts[index]) return true; + if (actualParts[index] < minimumParts[index]) return false; + } + return true; +} + +const npmExecPath = process.env.npm_execpath; +if (typeof npmExecPath !== "string" || npmExecPath.length === 0) { + failClosed(); +} + +const npmRoot = resolve(dirname(npmExecPath), ".."); +const npmVersion = readPackageVersion(resolve(npmRoot, "package.json")); +const tarVersion = readPackageVersion(resolve(npmRoot, "node_modules", "tar", "package.json")); + +if (npmVersion !== EXPECTED_NPM_VERSION || !versionAtLeast(tarVersion, MINIMUM_TAR_VERSION)) { + failClosed(); +} + +console.log(`verified npm ${npmVersion} with bundled tar ${tarVersion}`); From 1cd71db0677544797d0e45eac4fb13b6a5f53fdf Mon Sep 17 00:00:00 2001 From: Seongho Bae Date: Thu, 20 Aug 2026 09:43:59 -0700 Subject: [PATCH 80/92] fix(supply-chain): pin patched npm runtime --- package.json | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/package.json b/package.json index 2c3a4e945..8c118c48f 100644 --- a/package.json +++ b/package.json @@ -3,14 +3,14 @@ "private": true, "version": "0.1.3", "type": "module", - "packageManager": "npm@10.9.8", + "packageManager": "npm@10.9.9", "engines": { "node": ">=22.13 <23" }, "devEngines": { "packageManager": { "name": "npm", - "version": "10.9.8", + "version": "10.9.9", "onFail": "error" } }, @@ -26,6 +26,7 @@ "check:security-gates": "python3 scripts/checks/security_gates.py", "check:supply-chain": "python3 scripts/checks/verify_supply_chain.py", "check:github-bootstrap": "python3 scripts/checks/verify_github_bootstrap_policy.py", + "check:npm-runtime": "node scripts/checks/verify_npm_runtime.mjs", "check:python-docstrings": "python3 scripts/checks/run_analysis_command.py ruff check src tests ../../scripts --select D100,D101,D102,D103,D104,D105,D106,D107", "ruff:check": "python3 scripts/checks/run_analysis_command.py ruff check src tests", "ruff:format:check": "python3 scripts/checks/run_analysis_command.py ruff format --check src tests", From f29622dd69ef569837014504add743f14a457a51 Mon Sep 17 00:00:00 2001 From: Seongho Bae Date: Thu, 20 Aug 2026 09:44:26 -0700 Subject: [PATCH 81/92] fix(ci): activate patched npm before dependency reads --- .github/workflows/ci.yml | 26 +++++++++++++++++++------- 1 file changed, 19 insertions(+), 7 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 64b045d53..f97cfedad 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -17,7 +17,7 @@ env: GIT_CONFIG_COUNT: "1" GIT_CONFIG_KEY_0: init.defaultBranch GIT_CONFIG_VALUE_0: develop - EXPECTED_NPM_VERSION: "10.9.8" + EXPECTED_NPM_VERSION: "10.9.9" jobs: lock-validation: @@ -31,8 +31,12 @@ jobs: with: node-version: "22.22.3" cache: npm - - name: Verify exact npm lockfile generator - run: test "$(npm --version)" = "$EXPECTED_NPM_VERSION" + - name: Activate pinned npm runtime + run: corepack enable npm + - name: Verify exact npm lockfile generator and bundled tar + run: | + test "$(npm --version)" = "$EXPECTED_NPM_VERSION" + npm run check:npm-runtime - name: Validate the frozen package lock without lifecycle execution run: npm ci --ignore-scripts --no-audit --no-fund - name: Reject manifest or lockfile drift @@ -50,8 +54,12 @@ jobs: with: node-version: "22.22.3" cache: npm - - name: Verify exact npm lockfile generator - run: test "$(npm --version)" = "$EXPECTED_NPM_VERSION" + - name: Activate pinned npm runtime + run: corepack enable npm + - name: Verify exact npm lockfile generator and bundled tar + run: | + test "$(npm --version)" = "$EXPECTED_NPM_VERSION" + npm run check:npm-runtime - uses: astral-sh/setup-uv@11f9893b081a58869d3b5fccaea48c9e9e46f990 # v8.3.2 with: version: "0.8.6" @@ -85,8 +93,12 @@ jobs: with: node-version: "22.22.3" cache: npm - - name: Verify exact npm lockfile generator - run: test "$(npm --version)" = "$EXPECTED_NPM_VERSION" + - name: Activate pinned npm runtime + run: corepack enable npm + - name: Verify exact npm lockfile generator and bundled tar + run: | + test "$(npm --version)" = "$EXPECTED_NPM_VERSION" + npm run check:npm-runtime - name: Install stable Rust toolchain run: rustup toolchain install stable --profile minimal - name: Install node dependencies From 9e06df0c2bcee6ca0c7cc15fca3cf92d732f650a Mon Sep 17 00:00:00 2001 From: Seongho Bae Date: Thu, 20 Aug 2026 09:45:46 -0700 Subject: [PATCH 82/92] docs(supply-chain): record patched npm runtime boundary --- .../npm-lockfile-generator-provenance.md | 68 ++++++++++++------- 1 file changed, 42 insertions(+), 26 deletions(-) diff --git a/docs/doctoring/npm-lockfile-generator-provenance.md b/docs/doctoring/npm-lockfile-generator-provenance.md index 53488de48..72a31befc 100644 --- a/docs/doctoring/npm-lockfile-generator-provenance.md +++ b/docs/doctoring/npm-lockfile-generator-provenance.md @@ -2,20 +2,28 @@ ## Decision -BandScope records npm `10.9.8` as the approved generator for root workspace dependency updates. The root manifest records that decision through: +BandScope records npm `10.9.9` as the approved generator for root workspace dependency updates. The root manifest records that decision through: -- `packageManager: npm@10.9.8` as package-manager selection metadata; and +- `packageManager: npm@10.9.9` as package-manager selection metadata; and - `devEngines.packageManager` with `onFail: error` as npm's source-tree command gate. The npm version is intentionally not repeated under `engines`. npm serializes `engines` into the root lock package, so adding an npm-only source-tool constraint there creates lock metadata churn unrelated to dependency resolution. `devEngines` and the explicit CI assertion enforce the approved generator while the published `engines.node` range remains the runtime compatibility contract. -Primary CI does **not** regenerate or update `package-lock.json`. It uses Node `22.22.3`, verifies npm `10.9.8`, and validates the committed lock with `npm ci --ignore-scripts --no-audit --no-fund`. The gate then rejects any manifest or lockfile working-tree change. The normal verification job performs the repository's reviewed `npm ci` installation before lint, typecheck, tests, build, and security checks. +Primary CI does **not** regenerate or update `package-lock.json`. It uses Node `22.22.3`, enables the npm shim supplied by the Node-bundled Corepack, resolves the project-pinned npm `10.9.9`, verifies that exact npm runtime and its own bundled `tar` package before dependency consumption, and validates the committed lock with `npm ci --ignore-scripts --no-audit --no-fund`. The gate then rejects any manifest or lockfile working-tree change. The normal verification jobs repeat the same runtime provenance gate before the repository's reviewed `npm ci` installation. The Node runtime support decision remains separate. This change does not raise the public `>=22.13 <23` Node range; a coordinated Node-floor migration is tracked independently. +## Why the npm runtime was advanced + +The prior approved npm `10.9.8` bundled `tar 7.5.11`. GitHub's reviewed advisory GHSA-23hp-3jrh-7fpw / CVE-2026-59873 marks `tar <=7.5.18` affected by an unbounded decompression/parse denial-of-service vulnerability and records `7.5.19` as the patched floor. npm `10.9.9` updates its bundled `tar` to `7.5.22`. + +The Node 22 distribution line still bundled npm `10.9.8` when this repair was made, so merely advancing the Node 22 patch selector did not remove the vulnerable package-manager runtime. BandScope therefore keeps the supported Node 22 contract and activates the repository-pinned npm `10.9.9` through bundled Corepack before any `npm ci` step. `scripts/checks/verify_npm_runtime.mjs`, executed through that npm runtime, locates the running npm package via `npm_execpath`, verifies npm `10.9.9`, reads npm's own `node_modules/tar/package.json`, and rejects a tar version below `7.5.19` before dependency extraction is allowed. + +This is a package-manager execution boundary, not an application dependency override. BandScope does not add `tar` to the application graph or suppress the advisory. + ## Why generator provenance still matters -npm documents `package-lock.json` as the location-keyed description of the exact dependency tree. Lockfile version 3 is intended for npm 9 and newer. npm also notes that package-manager versions and tree-shaping configuration can affect the generated dependency graph and metadata. Dependency updates therefore use the reviewed npm `10.9.8` toolchain, and reviewers examine the complete generated lock diff together with its manifest change. +npm documents `package-lock.json` as the location-keyed description of the exact dependency tree. Lockfile version 3 is intended for npm 9 and newer. npm also notes that package-manager versions and tree-shaping configuration can affect the generated dependency graph and metadata. Dependency updates therefore use the reviewed npm `10.9.9` toolchain, and reviewers examine the complete generated lock diff together with its manifest change. That provenance is distinct from CI validation. `npm ci` is the immutable consumption path: it requires a lockfile, rejects manifest/lock dependency disagreement, removes an existing `node_modules`, and never writes the manifest or lock. CI relies on that frozen behavior instead of running `npm install`, `npm update`, or `npx` commands that may perform mutable resolution. @@ -25,27 +33,30 @@ The root lock also retains `peer: true` on the platform-specific `node_modules/@ ```mermaid flowchart LR - M[package.json dependency intent] --> G[approved npm 10.9.8 update toolchain] + M[package.json dependency intent] --> C[Corepack enables project-pinned npm 10.9.9] + C --> R[verify npm 10.9.9 and bundled tar >= 7.5.19] + R --> G[approved npm update toolchain] G --> L[reviewed package-lock.json v3] L --> V[npm ci frozen validation, lifecycle disabled] V --> D{manifest or lock drift?} D -->|yes| F[fail closed] D -->|no| S[verify SRI and generator-sensitive metadata] - S --> C[normal npm ci and repository checks] + S --> N[normal npm ci and repository checks] ``` ## Security and operational boundary +- Every primary CI job that consumes npm dependencies activates the project-pinned npm runtime and runs `check:npm-runtime` before its first `npm ci`. +- The runtime check fails closed unless the executing npm is exactly `10.9.9` and its own bundled `tar` is at least `7.5.19`. - CI lock validation must not run `npm install`, `npm update`, `npx`, or another mutable dependency-resolution command. -- Dependency PRs change manifest intent and the complete lock artifact produced by the approved npm `10.9.8` update toolchain; reviewers reject unexplained lock churn rather than hand-editing records. +- Dependency PRs change manifest intent and the complete lock artifact produced by the approved npm `10.9.9` update toolchain; reviewers reject unexplained lock churn rather than hand-editing records. - Platform-specific root `@esbuild/*` lock records must retain their expected `peer: true` metadata. Missing markers are treated as generator drift, not as an acceptable side effect of an unrelated dependency update. - The lock-validation job disables dependency lifecycle scripts. The normal clean install retains the repository's reviewed execution behavior. -- The exact npm version check occurs before either frozen install; a different bundled or globally installed npm cannot provide acceptance evidence. - Registry-resolved package records require SRI evidence in the committed lock. - Install-shaping flags that affect the dependency tree, such as `legacy-peer-deps` or `install-links`, must be committed in project configuration and applied consistently to generation and `npm ci`. - The root `package-lock.json` remains the sole npm workspace lock. Nested workspace locks are prohibited. -`packageManager` alone is not the enforcement boundary for npm because Corepack's npm shim is not enabled by default in Node distributions. Enforcement is provided by npm `devEngines`, the explicit CI version assertion, the frozen `npm ci` contract, and repository tests that prohibit mutable resolution in the lock gate. +`packageManager` alone is not the enforcement boundary for npm because Node distributions do not enable Corepack's npm shim by default. Enforcement is provided by explicit `corepack enable npm`, npm `devEngines`, the exact runtime/tar provenance check, the frozen `npm ci` contract, and repository tests that prohibit mutable resolution in the lock gate. ## Verification @@ -53,37 +64,42 @@ flowchart LR 1. the manifest's approved npm metadata and Node/runtime separation; 2. the exact Node/npm identity used by primary CI; -3. frozen `npm ci` lock validation with lifecycle execution disabled; -4. absence of `npm install`, `npm update`, and `npx` from the lock-validation job; -5. a clean manifest/lock working tree after validation; -6. package-lock version 3; -7. SRI evidence for every public npm-registry artifact in the root lock; and -8. preservation of `peer: true` on every root `node_modules/@esbuild/*` platform record. +3. Corepack activation and npm runtime/tar verification before every primary npm dependency-consumption step; +4. frozen `npm ci` lock validation with lifecycle execution disabled; +5. absence of `npm install`, `npm update`, and `npx` from the lock-validation job; +6. a clean manifest/lock working tree after validation; +7. package-lock version 3; +8. SRI evidence for every public npm-registry artifact in the root lock; and +9. preservation of `peer: true` on every root `node_modules/@esbuild/*` platform record. The exact PDF.js and Undici baseline is covered separately by `test_high_security_dependency_baseline.py` and the desktop PDF loader tests. -A dependency update is mergeable only after the updated manifest and complete generated lock are reviewed together and the exact current head passes frozen lock validation, normal install, lint, strict typecheck, measured tests, production build, Rust/Tauri checks, security/supply-chain gates, current review, independent approval, and branch protection without bypass. +A dependency update is mergeable only after the updated manifest and complete generated lock are reviewed together and the exact current head passes npm runtime provenance, frozen lock validation, normal install, lint, strict typecheck, measured tests, production build, Rust/Tauri checks, security/supply-chain gates, current review, independent approval, and branch protection without bypass. ## Claim boundary -CI proves that the committed manifest and lock can be consumed as a frozen pair by the approved toolchain, that public-registry lock entries carry integrity evidence, and that the known generator-sensitive `@esbuild/*` peer markers remain present. It does **not** claim that resolving mutable manifest ranges again at a later time will reproduce byte-identical lock metadata. When a dependency update is needed, npm `10.9.8` remains the approved generator and its entire resulting lock diff is review evidence. +CI proves that the committed manifest and lock can be consumed as a frozen pair by the approved toolchain, that the npm runtime used for dependency extraction is the reviewed version with a non-vulnerable bundled tar floor, that public-registry lock entries carry integrity evidence, and that the known generator-sensitive `@esbuild/*` peer markers remain present. It does **not** claim that resolving mutable manifest ranges again at a later time will reproduce byte-identical lock metadata. When a dependency update is needed, npm `10.9.9` remains the approved generator and its entire resulting lock diff is review evidence. ## Incident response and rollback -When an update produces unexpected lock churn: +When an update produces unexpected lock churn or npm runtime provenance fails: -1. preserve the exact head SHA, npm and Node versions, project npm configuration, original lock blob SHA, generated lock, and relevant CI run IDs; -2. determine whether manifest intent, npm, project configuration, registry metadata, or transitive dependency resolution changed; -3. never accept a partial or hand-edited lock to satisfy a validator; +1. preserve the exact head SHA, npm, bundled tar and Node versions, project npm configuration, original lock blob SHA, generated lock, and relevant CI run IDs; +2. determine whether manifest intent, npm, project configuration, registry metadata, transitive dependency resolution, or the package-manager runtime changed; +3. never accept a partial or hand-edited lock or disable the runtime check to satisfy a validator; 4. regenerate the complete lock in a dedicated update branch using the reviewed npm version, then review the full diff before relying on it; and -5. if rollback is necessary, restore the prior manifest and complete lock together, then rerun the entire exact-head gate. +5. if rollback is necessary, restore the prior manifest and complete lock together, then rerun the entire exact-head gate. Do not roll back to a package-manager runtime with a known unfixed extraction vulnerability without an explicit temporary security exception. ## References -npm, Inc. (2026). *npm ci*. npm Docs. https://docs.npmjs.com/cli/v11/commands/npm-ci/ +GitHub. (2026). *node-tar: Decompression/parse DoS via unlimited input* (GHSA-23hp-3jrh-7fpw; CVE-2026-59873) [Security advisory]. https://github.com/advisories/GHSA-23hp-3jrh-7fpw -npm, Inc. (2026). *package-lock.json*. npm Docs. https://docs.npmjs.com/cli/v10/configuring-npm/package-lock-json/ +Node.js contributors. (2026). *Corepack* [Software documentation]. GitHub. https://github.com/nodejs/corepack -npm, Inc. (2026). *package.json*. npm Docs. https://docs.npmjs.com/cli/configuring-npm/package-json/ +npm, Inc. (2026). *npm 10.9.9* [Software release]. GitHub. https://github.com/npm/cli/releases/tag/v10.9.9 -Node.js contributors. (2026). *Corepack* [Software documentation]. GitHub. https://github.com/nodejs/corepack +npm, Inc. (2026). *npm ci*. npm Docs. https://docs.npmjs.com/cli/v10/commands/npm-ci/ + +npm, Inc. (2026). *package-lock.json*. npm Docs. https://docs.npmjs.com/cli/v10/configuring-npm/package-lock-json/ + +npm, Inc. (2026). *package.json*. npm Docs. https://docs.npmjs.com/cli/v10/configuring-npm/package-json/ From ec40ddafac5a90c53281ff4f2cc89ca8c54c4b0f Mon Sep 17 00:00:00 2001 From: Seongho Bae Date: Thu, 20 Aug 2026 09:46:38 -0700 Subject: [PATCH 83/92] docs(security): align dependency baseline with patched npm --- .../high-security-pdf-http-baseline.md | 40 ++++++++++++------- 1 file changed, 26 insertions(+), 14 deletions(-) diff --git a/docs/doctoring/high-security-pdf-http-baseline.md b/docs/doctoring/high-security-pdf-http-baseline.md index 87dbd83cf..554b494aa 100644 --- a/docs/doctoring/high-security-pdf-http-baseline.md +++ b/docs/doctoring/high-security-pdf-http-baseline.md @@ -2,11 +2,11 @@ ## Decision -BandScope treats the PDF parser and its transitive HTTP client as one security-release boundary: +BandScope treats the PDF parser, its transitive HTTP client, and the package-manager runtime that materializes their reviewed lock as one security-release boundary: - `pdfjs-dist` is pinned exactly to `6.2.108`; - `undici` is pinned exactly to `7.29.0` through the root npm override; and -- npm `10.9.8` is the approved generator for reviewed root-workspace dependency updates, while primary CI consumes the committed lock through frozen validation rather than re-resolving it. +- npm `10.9.9` is the approved generator for reviewed root-workspace dependency updates. Primary CI activates that project-pinned npm through Node-bundled Corepack, verifies npm's own bundled `tar` is at least `7.5.19`, and only then consumes the committed lock through frozen validation rather than re-resolving it. Repository dependency/security tooling reported the protected-base `pdfjs-dist@6.1.200` as requiring a newer floor. That finding is kept distinct from the older, GitHub-reviewed CVE-2024-4367 / GHSA-wgrm-67xf-hhpq: the 2024 advisory affected `pdfjs-dist <=4.1.392` and was fixed in `4.2.67`, so it is historical parser-risk context and is **not** evidence that `6.1.200` was affected by that CVE. BandScope pins the current `6.2.108` artifact selected by the repository security baseline and requires current-head audit/security evidence rather than misattributing a scanner result to an unrelated advisory. @@ -23,7 +23,8 @@ flowchart LR C --> W[Same-origin bundled worker] W --> R[Canvas render] J[jsdom development path] --> U[undici 7.29.0 override] - N[npm 10.9.8 approved update toolchain] --> L[Reviewed package-lock artifact] + N[Corepack-activated npm 10.9.9] --> T[verify bundled tar >= 7.5.19] + T --> L[Reviewed package-lock artifact] L --> V[npm ci frozen validation] V --> C V --> U @@ -39,6 +40,8 @@ The pinned PDF.js XML parser does not expose an external-entity resolver through Undici is currently a development dependency reached through jsdom, but development and CI parsers process attacker-controlled fixtures, generated HTML, and network-like request bodies. A dev-only label does not make header injection, shared-cache disclosure, retry desynchronization, or cookie-attribute injection acceptable in the trusted build boundary. +The package-manager runtime is also part of that build trust boundary. npm `10.9.8` bundled `tar 7.5.11`, which falls inside GitHub-reviewed GHSA-23hp-3jrh-7fpw / CVE-2026-59873 (`tar <=7.5.18`). npm `10.9.9` updates its bundled tar to `7.5.22`. BandScope therefore rejects the previous generator runtime rather than relying on `--ignore-scripts`: archive extraction occurs before lifecycle-script policy can make a vulnerable tar implementation safe. + ## Strix finding adjudication boundary Strix run `31871388084` on predecessor head `6f81f52c193c1e327d078eba7a2ea3bdbfbc87c2` reported a possible XXE path through `loadScorePdf`. Its attached proof-of-concept returned only a four-byte `%PDF` prefix and stated that construction of an actual PDF containing the alleged XML payload remained necessary. It did not demonstrate entity expansion, local-file disclosure, a network request, or parser output containing an external entity. @@ -47,24 +50,27 @@ The finding was therefore not suppressed and was not treated as proven exploitat ## Lockfile provenance -The dependency manifests and complete lock artifact were generated and reconciled on this branch with the approved Node `22.22.3` / npm `10.9.8` toolchain before the current frozen-validation gate was finalized. The historical generation run and artifact are provenance evidence only; they do **not** satisfy a later head's merge gate and primary CI intentionally does not repeat mutable dependency resolution. +The dependency manifests and complete lock artifact were originally generated and reconciled on this branch with Node `22.22.3` and the then-approved npm `10.9.8` toolchain before the frozen-validation gate was finalized. That historical generation run and artifact are provenance evidence only. The current approved generator is npm `10.9.9`; a future dependency-resolution change must be generated with that runtime and the complete resulting lock reviewed. Primary CI intentionally does not repeat mutable dependency resolution. For every current head, primary CI instead: -1. verifies npm `10.9.8` before dependency consumption; -2. runs `npm ci --ignore-scripts --no-audit --no-fund` in the dedicated lock-validation job; -3. rejects any `package.json` or `package-lock.json` working-tree drift; and -4. proceeds to normal repository verification only after the frozen lock is consumable by the approved toolchain. +1. sets up Node `22.22.3` while keeping the public `>=22.13 <23` runtime contract unchanged; +2. explicitly enables Corepack's npm shim so `packageManager: npm@10.9.9` controls the executable package manager; +3. verifies npm `10.9.9` and reads that runtime's own bundled `tar` package, rejecting anything below `7.5.19`; +4. runs `npm ci --ignore-scripts --no-audit --no-fund` in the dedicated lock-validation job; +5. rejects any `package.json` or `package-lock.json` working-tree drift; and +6. proceeds to normal repository verification only after the frozen lock is consumable by the approved runtime. -Future dependency updates must use npm `10.9.8` to generate the complete lock in a dedicated update branch, review the entire resulting manifest/lock diff, and then prove frozen consumption on the resulting exact head. No tarball URL, SRI, dependency range, `peer` classification, or workspace record may be hand-edited merely to satisfy a validator. +Future dependency updates must use npm `10.9.9` to generate the complete lock in a dedicated update branch, review the entire resulting manifest/lock diff, and then prove frozen consumption on the resulting exact head. No tarball URL, SRI, dependency range, `peer` classification, or workspace record may be hand-edited merely to satisfy a validator. -The lock contract requires the exact public-registry tarball and SHA-512 SRI for both patched packages and requires every existing `node_modules/@esbuild/*` location to retain npm 10.9.8's `peer: true` classification. This distinguishes the intended security graph from unrelated Dependabot generator churn. The narrower provenance and validation contract is specified in `docs/doctoring/npm-lockfile-generator-provenance.md`. +The lock contract requires the exact public-registry tarball and SHA-512 SRI for patched application packages and requires every existing `node_modules/@esbuild/*` location to retain the approved generator's `peer: true` classification. This distinguishes the intended security graph from unrelated Dependabot generator churn. The narrower provenance and validation contract is specified in `docs/doctoring/npm-lockfile-generator-provenance.md`. ## Verification The merge gate includes: - exact manifest and lock artifact tests; +- npm `10.9.9` plus bundled `tar >=7.5.19` runtime provenance before every primary CI dependency-consumption step; - a direct PDF.js wrapper test proving copied bytes, the locally bundled worker, `enableXfa: false`, `useWorkerFetch: false`, and no URL-bearing initialization member; - TypeScript compilation against the installed PDF.js `DocumentInitParameters` rather than an unsafe cast; - valid and malformed local score-PDF component tests; @@ -79,22 +85,28 @@ The merge gate includes: ## Failure, rollback, and incident evidence -On a failed frozen-lock validation or parser regression, preserve the exact head SHA, Node/npm versions, original lock blob SHA, test output, audit report, and workflow run ID. If the incident concerns a dependency-generation change, also preserve the generated complete lock and the generation environment/configuration. Do not merge a partially updated graph. +On a failed frozen-lock validation, npm runtime-provenance failure, or parser regression, preserve the exact head SHA, Node/npm/bundled-tar versions, original lock blob SHA, test output, audit report, and workflow run ID. If the incident concerns a dependency-generation change, also preserve the generated complete lock and the generation environment/configuration. Do not merge a partially updated graph and do not bypass the package-manager runtime check. -Rollback restores the previous desktop manifest, root override, complete lock, PDF loader, tests, and CHANGELOG entry together. Because the previous graph contains known high findings, rollback is an emergency availability action only and requires an explicit security exception, compensating controls, owner, expiration, and immediate replacement plan. +Rollback restores the previous desktop manifest, root override, complete lock, PDF loader, tests, and CHANGELOG entry together. Because the previous dependency graph or package-manager runtime may contain known security findings, rollback is an emergency availability action only and requires an explicit security exception, compensating controls, owner, expiration, and immediate replacement plan. ## References GitHub. (2024). *PDF.js vulnerable to arbitrary JavaScript execution upon opening a malicious PDF* (GHSA-wgrm-67xf-hhpq) [Security advisory]. https://github.com/advisories/GHSA-wgrm-67xf-hhpq +GitHub. (2026). *node-tar: Decompression/parse DoS via unlimited input* (GHSA-23hp-3jrh-7fpw; CVE-2026-59873) [Security advisory]. https://github.com/advisories/GHSA-23hp-3jrh-7fpw + Mozilla. (2026). *Document initialization parameters in PDF.js 6.2.108* [Source code]. GitHub. https://github.com/mozilla/pdf.js/blob/v6.2.108/src/display/api.js Mozilla. (2026). *PDF.js XML parser in version 6.2.108* [Source code]. GitHub. https://github.com/mozilla/pdf.js/blob/v6.2.108/src/core/xml_parser.js Mozilla. (2026). *PDF.js 6.2.108* [Software release]. https://github.com/mozilla/pdf.js/releases/tag/v6.2.108 +Node.js contributors. (2026). *Corepack* [Software documentation]. GitHub. https://github.com/nodejs/corepack + Node.js contributors. (2026). *Undici 7.29.0* [Software release]. https://github.com/nodejs/undici/releases/tag/v7.29.0 -npm, Inc. (2026). *npm ci*. npm Docs. https://docs.npmjs.com/cli/v11/commands/npm-ci/ +npm, Inc. (2026). *npm 10.9.9* [Software release]. GitHub. https://github.com/npm/cli/releases/tag/v10.9.9 + +npm, Inc. (2026). *npm ci*. npm Docs. https://docs.npmjs.com/cli/v10/commands/npm-ci/ -npm, Inc. (2026). *package-lock.json*. npm Docs. https://docs.npmjs.com/cli/v11/configuring-npm/package-lock-json/ +npm, Inc. (2026). *package-lock.json*. npm Docs. https://docs.npmjs.com/cli/v10/configuring-npm/package-lock-json/ From c516f1d09becd171ea3ff4cee46903be67f4afd3 Mon Sep 17 00:00:00 2001 From: Seongho Bae Date: Thu, 20 Aug 2026 09:47:14 -0700 Subject: [PATCH 84/92] docs(changelog): record patched npm tar runtime --- CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index cfe599265..6027f1a81 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -9,7 +9,7 @@ ### Changed -- Pinned npm `10.9.8` as the approved lockfile generator and made primary CI consume the committed lock only through frozen `npm ci` validation, rejecting mutable npm resolution in the lock gate, requiring integrity evidence for public-registry lock entries, and rejecting generator-sensitive loss of root `@esbuild/*` peer metadata. +- Pinned npm `10.9.9` as the approved lockfile generator, activated it through Node-bundled Corepack before dependency consumption, and fail closed unless its bundled `tar` is at least `7.5.19`; primary CI still consumes the committed lock only through frozen `npm ci` validation, rejects mutable npm resolution in the lock gate, requires integrity evidence for public-registry lock entries, and preserves generator-sensitive root `@esbuild/*` peer metadata. ### Fixed From 81b2901c7094af1a46d7d348509b664bbf9b1e6c Mon Sep 17 00:00:00 2001 From: Seongho Bae Date: Thu, 20 Aug 2026 10:38:28 -0700 Subject: [PATCH 85/92] test(ci): expose pre-Corepack npm cache bootstrap --- .../tests/test_npm_toolchain_contract.py | 41 +++++++++++++++++++ 1 file changed, 41 insertions(+) diff --git a/services/analysis-engine/tests/test_npm_toolchain_contract.py b/services/analysis-engine/tests/test_npm_toolchain_contract.py index 56277dba9..4486ea645 100644 --- a/services/analysis-engine/tests/test_npm_toolchain_contract.py +++ b/services/analysis-engine/tests/test_npm_toolchain_contract.py @@ -200,3 +200,44 @@ def test_root_lock_preserves_esbuild_peer_metadata() -> None: for location, package_record in esbuild_records.items(): assert isinstance(package_record, dict) assert package_record.get("peer") is True, f"missing peer metadata for {location}" + + +def test_npm_consuming_workflows_activate_pinned_runtime_before_dependency_reads() -> None: + """Prevent setup-node from invoking its bundled npm before Corepack selects the reviewed runtime.""" + workflow_names = ("ci.yml", "release.yml", "security-audit.yml", "build-baseline.yml") + + for workflow_name in workflow_names: + workflow_path = _REPOSITORY_ROOT / ".github" / "workflows" / workflow_name + document = yaml.safe_load(workflow_path.read_text(encoding="utf-8")) + assert isinstance(document, dict) + jobs = document.get("jobs") + assert isinstance(jobs, dict) + npm_consumers = 0 + + for job_name in jobs: + steps = _job_steps(jobs, str(job_name)) + consumes_npm = any( + isinstance(step.get("run"), str) + and re.search(r"(?:^|\n)\s*npm ci(?:\s|$)", str(step["run"])) + for step in steps + ) + if not consumes_npm: + continue + npm_consumers += 1 + + setup_node_steps = [ + step + for step in steps + if isinstance(step.get("uses"), str) + and str(step["uses"]).startswith("actions/setup-node@") + ] + assert len(setup_node_steps) == 1, f"{workflow_name}:{job_name} setup-node ownership" + setup_options = setup_node_steps[0].get("with") + assert isinstance(setup_options, dict) + assert "cache" not in setup_options, f"{workflow_name}:{job_name} pre-Corepack npm cache" + assert setup_options.get("package-manager-cache") is False, ( + f"{workflow_name}:{job_name} must disable setup-node package-manager cache" + ) + _assert_patched_npm_precedes_dependency_consumption(steps) + + assert npm_consumers > 0, f"{workflow_name} must contain an npm dependency consumer" From 27a633d3619e7abadcd3b5a220cd049787241bf4 Mon Sep 17 00:00:00 2001 From: Seongho Bae Date: Thu, 20 Aug 2026 10:39:16 -0700 Subject: [PATCH 86/92] fix(ci): defer npm use until pinned Corepack runtime --- .github/workflows/ci.yml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index f97cfedad..d17468129 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -30,7 +30,7 @@ jobs: - uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6.4.0 with: node-version: "22.22.3" - cache: npm + package-manager-cache: false - name: Activate pinned npm runtime run: corepack enable npm - name: Verify exact npm lockfile generator and bundled tar @@ -53,7 +53,7 @@ jobs: - uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6.4.0 with: node-version: "22.22.3" - cache: npm + package-manager-cache: false - name: Activate pinned npm runtime run: corepack enable npm - name: Verify exact npm lockfile generator and bundled tar @@ -92,7 +92,7 @@ jobs: - uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6.4.0 with: node-version: "22.22.3" - cache: npm + package-manager-cache: false - name: Activate pinned npm runtime run: corepack enable npm - name: Verify exact npm lockfile generator and bundled tar From 05ca2866b2788263f961096a8b4e19b6c8650a3a Mon Sep 17 00:00:00 2001 From: Seongho Bae Date: Thu, 20 Aug 2026 10:39:35 -0700 Subject: [PATCH 87/92] fix(release): activate pinned npm before dependency install --- .github/workflows/release.yml | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 84ace55d4..c4728136e 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -32,7 +32,7 @@ jobs: - uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6.4.0 with: node-version: 22.22.3 - cache: npm + package-manager-cache: false - uses: actions/setup-python@a309ff8b426b58ec0e2a45f0f869d46889d02405 # v6.2.0 with: python-version: "3.12" @@ -42,6 +42,10 @@ jobs: enable-cache: false - name: Install Rust stable run: rustup toolchain install stable --profile minimal + - name: Activate and verify pinned npm runtime + run: | + corepack enable npm + npm run check:npm-runtime - name: Install node dependencies run: npm ci - name: Sync Python dependencies From cf1b728acd1ffe1d5bd19c4a2f0edac2ae9993f0 Mon Sep 17 00:00:00 2001 From: Seongho Bae Date: Thu, 20 Aug 2026 10:39:58 -0700 Subject: [PATCH 88/92] fix(security): verify pinned npm before audit install --- .github/workflows/security-audit.yml | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/.github/workflows/security-audit.yml b/.github/workflows/security-audit.yml index 7d880c1a1..00708f437 100644 --- a/.github/workflows/security-audit.yml +++ b/.github/workflows/security-audit.yml @@ -27,7 +27,7 @@ jobs: - uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6.4.0 with: node-version: 22.22.3 - cache: npm + package-manager-cache: false - uses: actions/setup-python@a309ff8b426b58ec0e2a45f0f869d46889d02405 # v6.2.0 with: python-version: "3.12" @@ -35,6 +35,10 @@ jobs: with: version: "0.8.6" enable-cache: false + - name: Activate and verify pinned npm runtime + run: | + corepack enable npm + npm run check:npm-runtime - name: Install node dependencies run: npm ci - name: Audit npm dependencies From 0facdbf745d877f09ba4178f6359c377f69ed52b Mon Sep 17 00:00:00 2001 From: Seongho Bae Date: Thu, 20 Aug 2026 10:40:56 -0700 Subject: [PATCH 89/92] fix(build): use pinned npm after Corepack activation --- .github/workflows/build-baseline.yml | 24 ++++++++++++++++++++---- 1 file changed, 20 insertions(+), 4 deletions(-) diff --git a/.github/workflows/build-baseline.yml b/.github/workflows/build-baseline.yml index 552f6d69d..abec57b6b 100644 --- a/.github/workflows/build-baseline.yml +++ b/.github/workflows/build-baseline.yml @@ -39,7 +39,7 @@ jobs: - uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6.4.0 with: node-version: 22.22.3 - cache: npm + package-manager-cache: false - uses: actions/setup-python@a309ff8b426b58ec0e2a45f0f869d46889d02405 # v6.2.0 with: python-version: "3.12" @@ -90,6 +90,10 @@ jobs: } Write-AntivirusEvidence "Antivirus check: no explicit antivirus telemetry was available on this hosted runner." + - name: Activate and verify pinned npm runtime + run: | + corepack enable npm + npm run check:npm-runtime - name: Install node dependencies run: npm ci - name: Sync Python dependencies @@ -134,7 +138,7 @@ jobs: - uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6.4.0 with: node-version: 22.22.3 - cache: npm + package-manager-cache: false - uses: actions/setup-python@a309ff8b426b58ec0e2a45f0f869d46889d02405 # v6.2.0 with: python-version: "3.12" @@ -185,6 +189,10 @@ jobs: } Write-AntivirusEvidence "Antivirus check: no explicit antivirus telemetry was available on this hosted runner." + - name: Activate and verify pinned npm runtime + run: | + corepack enable npm + npm run check:npm-runtime - name: Install node dependencies run: npm ci - name: Sync Python dependencies @@ -240,7 +248,7 @@ jobs: - uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6.4.0 with: node-version: 22.22.3 - cache: npm + package-manager-cache: false - uses: actions/setup-python@a309ff8b426b58ec0e2a45f0f869d46889d02405 # v6.2.0 with: python-version: "3.12" @@ -254,6 +262,10 @@ jobs: run: rustup target add "$BANDSCOPE_TARGET_TRIPLE" --toolchain stable - name: Install create-dmg run: brew install create-dmg + - name: Activate and verify pinned npm runtime + run: | + corepack enable npm + npm run check:npm-runtime - name: Install node dependencies run: npm ci - name: Sync Python dependencies @@ -298,7 +310,7 @@ jobs: - uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6.4.0 with: node-version: 22.22.3 - cache: npm + package-manager-cache: false - uses: actions/setup-python@a309ff8b426b58ec0e2a45f0f869d46889d02405 # v6.2.0 with: python-version: "3.12" @@ -312,6 +324,10 @@ jobs: run: rustup target add "$BANDSCOPE_TARGET_TRIPLE" --toolchain stable - name: Install create-dmg run: brew install create-dmg + - name: Activate and verify pinned npm runtime + run: | + corepack enable npm + npm run check:npm-runtime - name: Install node dependencies run: npm ci - name: Sync Python dependencies From 96674b27852bb874e549831cbbb4f2bb122deb2b Mon Sep 17 00:00:00 2001 From: Seongho Bae Date: Thu, 20 Aug 2026 13:06:58 -0700 Subject: [PATCH 90/92] test(ci): accept combined npm activation audit step --- .../tests/test_npm_toolchain_contract.py | 20 ++++++++++++++----- 1 file changed, 15 insertions(+), 5 deletions(-) diff --git a/services/analysis-engine/tests/test_npm_toolchain_contract.py b/services/analysis-engine/tests/test_npm_toolchain_contract.py index 4486ea645..bfd7a209a 100644 --- a/services/analysis-engine/tests/test_npm_toolchain_contract.py +++ b/services/analysis-engine/tests/test_npm_toolchain_contract.py @@ -93,18 +93,26 @@ def _assert_patched_npm_precedes_dependency_consumption(steps: list[dict[str, ob None, ) audit_index = next( - (index for index, command in enumerate(run_steps) if "npm run check:npm-runtime" in command), + ( + index + for index, command in enumerate(run_steps) + if "npm run check:npm-runtime" in command + ), None, ) consumption_index = next( - (index for index, command in enumerate(run_steps) if re.search(r"(?:^|\n)\s*npm ci(?:\s|$)", command)), + ( + index + for index, command in enumerate(run_steps) + if re.search(r"(?:^|\n)\s*npm ci(?:\s|$)", command) + ), None, ) assert activation_index is not None assert audit_index is not None assert consumption_index is not None - assert activation_index < audit_index < consumption_index + assert activation_index <= audit_index < consumption_index def test_root_manifest_pins_the_lockfile_generator_and_fails_on_drift() -> None: @@ -203,7 +211,7 @@ def test_root_lock_preserves_esbuild_peer_metadata() -> None: def test_npm_consuming_workflows_activate_pinned_runtime_before_dependency_reads() -> None: - """Prevent setup-node from invoking its bundled npm before Corepack selects the reviewed runtime.""" + """Prevent dependency reads before Corepack selects and verifies the reviewed npm runtime.""" workflow_names = ("ci.yml", "release.yml", "security-audit.yml", "build-baseline.yml") for workflow_name in workflow_names: @@ -234,7 +242,9 @@ def test_npm_consuming_workflows_activate_pinned_runtime_before_dependency_reads assert len(setup_node_steps) == 1, f"{workflow_name}:{job_name} setup-node ownership" setup_options = setup_node_steps[0].get("with") assert isinstance(setup_options, dict) - assert "cache" not in setup_options, f"{workflow_name}:{job_name} pre-Corepack npm cache" + assert "cache" not in setup_options, ( + f"{workflow_name}:{job_name} pre-Corepack npm cache" + ) assert setup_options.get("package-manager-cache") is False, ( f"{workflow_name}:{job_name} must disable setup-node package-manager cache" ) From db4aa09351687f8245576bcfb232e5d3040e333e Mon Sep 17 00:00:00 2001 From: Seongho Bae Date: Mon, 24 Aug 2026 11:25:20 +0900 Subject: [PATCH 91/92] fix(ci): disable checkout credentials for npm consumers --- .github/workflows/release.yml | 2 ++ .github/workflows/security-audit.yml | 2 ++ services/analysis-engine/tests/test_npm_toolchain_contract.py | 1 + 3 files changed, 5 insertions(+) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index c4728136e..34583b414 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -29,6 +29,8 @@ jobs: contents: read steps: - uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0 + with: + persist-credentials: false - uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6.4.0 with: node-version: 22.22.3 diff --git a/.github/workflows/security-audit.yml b/.github/workflows/security-audit.yml index 00708f437..f6737f1f6 100644 --- a/.github/workflows/security-audit.yml +++ b/.github/workflows/security-audit.yml @@ -24,6 +24,8 @@ jobs: runs-on: ubuntu-latest steps: - uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0 + with: + persist-credentials: false - uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6.4.0 with: node-version: 22.22.3 diff --git a/services/analysis-engine/tests/test_npm_toolchain_contract.py b/services/analysis-engine/tests/test_npm_toolchain_contract.py index bfd7a209a..f50c9adef 100644 --- a/services/analysis-engine/tests/test_npm_toolchain_contract.py +++ b/services/analysis-engine/tests/test_npm_toolchain_contract.py @@ -232,6 +232,7 @@ def test_npm_consuming_workflows_activate_pinned_runtime_before_dependency_reads if not consumes_npm: continue npm_consumers += 1 + _assert_checkout_credentials_not_persisted(steps) setup_node_steps = [ step From 1168c8f4257de5de036ea54bf5ee73edb83e775e Mon Sep 17 00:00:00 2001 From: seonghobae Date: Mon, 24 Aug 2026 15:18:41 +0900 Subject: [PATCH 92/92] chore(ci): re-trigger required checks after provider-prefix migration Strix was cancelled on the previous head during the org provider-prefix migration; push an empty commit so current-head review and security evidence are regenerated for merge.