From 4b31354d65b7d9f4014b53c73d664d1eba763546 Mon Sep 17 00:00:00 2001 From: Arthur Date: Sat, 8 Aug 2026 03:07:44 +0800 Subject: [PATCH 1/6] fix(registry): close 0.23 audit findings --- .github/dependabot.yml | 27 + .github/workflows/ci.yml | 10 +- .github/workflows/release.yml | 20 +- .github/workflows/website-build.yml | 6 +- CHANGELOG.md | 12 + .../releases/CELLSCRIPT_0_23_RELEASE_NOTES.md | 4 +- roadmap/CELLSCRIPT_0_23_ROADMAP.md | 6 +- scripts/cellscript_gate.sh | 6 +- services/registry-api/README.md | 10 + .../deploy/docker-compose.production.yml | 1 + .../deploy/docker-compose.testnet.yml | 1 + services/registry-api/package-lock.json | 668 +++++++++--------- services/registry-api/package.json | 6 +- services/registry-api/src/domain.ts | 52 +- services/registry-api/src/index.ts | 6 +- .../registry-api/src/node-request-identity.ts | 14 + services/registry-api/src/node-server.ts | 13 +- .../registry-api/src/verification-worker.ts | 6 + .../test/node-request-identity.test.ts | 18 + .../registry-api/test/registry-api.test.ts | 42 +- .../test/sql-registry-store.test.ts | 5 +- services/registry-verifier/src/main.rs | 99 +++ src/package/registry.rs | 85 ++- website | 2 +- 24 files changed, 760 insertions(+), 359 deletions(-) create mode 100644 .github/dependabot.yml create mode 100644 services/registry-api/src/node-request-identity.ts create mode 100644 services/registry-api/test/node-request-identity.test.ts diff --git a/.github/dependabot.yml b/.github/dependabot.yml new file mode 100644 index 0000000..fb81314 --- /dev/null +++ b/.github/dependabot.yml @@ -0,0 +1,27 @@ +version: 2 +updates: + - package-ecosystem: cargo + directory: / + schedule: + interval: weekly + open-pull-requests-limit: 5 + - package-ecosystem: cargo + directory: /services/registry-verifier + schedule: + interval: weekly + open-pull-requests-limit: 5 + - package-ecosystem: npm + directory: /services/registry-api + schedule: + interval: weekly + open-pull-requests-limit: 5 + - package-ecosystem: gitsubmodule + directory: / + schedule: + interval: weekly + open-pull-requests-limit: 5 + - package-ecosystem: github-actions + directory: / + schedule: + interval: weekly + open-pull-requests-limit: 5 diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 6e2d659..de0633b 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -42,7 +42,7 @@ jobs: REGISTRY_TEST_DATABASE_URL: postgresql://cellscript_test:cellscript_test_password@127.0.0.1:5432/cellscript_registry_test steps: - name: Check out repository - uses: actions/checkout@v4 + uses: actions/checkout@11d5960a326750d5838078e36cf38b85af677262 # v4 with: submodules: recursive @@ -73,7 +73,7 @@ jobs: git config --global user.email "ci@cellscript.dev" - name: Cache Cargo dependencies - uses: actions/cache@v4 + uses: actions/cache@0057852bfaa89a56745cba8c7296529d2fc39830 # v4 with: path: | ~/.cargo/git @@ -90,7 +90,7 @@ jobs: - name: Upload backend shape report if: always() - uses: actions/upload-artifact@v4 + uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4 with: name: cellscript-backend-shape-report if-no-files-found: error @@ -98,7 +98,7 @@ jobs: - name: Upload syntax combination audit report if: always() - uses: actions/upload-artifact@v4 + uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4 with: name: cellscript-syntax-combo-audit if-no-files-found: ignore @@ -106,7 +106,7 @@ jobs: - name: Upload strict backend audit report if: always() - uses: actions/upload-artifact@v4 + uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4 with: name: cellscript-strict-backend-audit if-no-files-found: ignore diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 2aebc5c..bcf1567 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -26,13 +26,13 @@ jobs: timeout-minutes: 180 steps: - name: Check out tagged source - uses: actions/checkout@v4 + uses: actions/checkout@11d5960a326750d5838078e36cf38b85af677262 # v4 with: fetch-depth: 0 submodules: recursive - name: Install Node.js - uses: actions/setup-node@v4 + uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4 with: node-version: "22" cache: npm @@ -41,7 +41,7 @@ jobs: editors/vscode-cellscript/package-lock.json - name: Install Rust release toolchain - uses: dtolnay/rust-toolchain@stable + uses: dtolnay/rust-toolchain@4360b52568e2003a75bf9bc1d59f33a8e3fc893c # stable with: toolchain: "1.97.1" components: rustfmt, clippy, llvm-tools-preview @@ -99,7 +99,7 @@ jobs: - name: Upload release evidence if: always() - uses: actions/upload-artifact@v4 + uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4 with: name: cellscript-release-gate-evidence if-no-files-found: warn @@ -126,7 +126,7 @@ jobs: os: ubuntu-latest steps: - name: Check out repository - uses: actions/checkout@v4 + uses: actions/checkout@11d5960a326750d5838078e36cf38b85af677262 # v4 with: fetch-depth: 0 submodules: recursive @@ -139,7 +139,7 @@ jobs: git -C "$GITHUB_WORKSPACE/../ckb-sdk-rust" rev-parse --short HEAD - name: Install Rust toolchain - uses: dtolnay/rust-toolchain@stable + uses: dtolnay/rust-toolchain@4360b52568e2003a75bf9bc1d59f33a8e3fc893c # stable with: toolchain: "1.97.1" targets: ${{ matrix.target }} @@ -179,7 +179,7 @@ jobs: sha256sum "${{ steps.package.outputs.archive }}" > SHA256SUMS.${{ matrix.target }} - name: Upload artifact - uses: actions/upload-artifact@v4 + uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4 with: name: cellscript-${{ matrix.target }} path: | @@ -194,12 +194,12 @@ jobs: contents: write steps: - name: Check out repository - uses: actions/checkout@v4 + uses: actions/checkout@11d5960a326750d5838078e36cf38b85af677262 # v4 with: submodules: recursive - name: Download all artifacts - uses: actions/download-artifact@v4 + uses: actions/download-artifact@d3f86a106a0bac45b974a628896c90dbdf5c8093 # v4 with: path: artifacts merge-multiple: false @@ -220,7 +220,7 @@ jobs: printf 'version=%s\n' "$VERSION" >> "$GITHUB_OUTPUT" - name: Create GitHub Release - uses: softprops/action-gh-release@v2 + uses: softprops/action-gh-release@3bb12739c298aeb8a4eeaf626c5b8d85266b0e65 # v2 with: tag_name: v${{ steps.version.outputs.version }} name: CellScript ${{ steps.version.outputs.version }} diff --git a/.github/workflows/website-build.yml b/.github/workflows/website-build.yml index 93db582..f6e1210 100644 --- a/.github/workflows/website-build.yml +++ b/.github/workflows/website-build.yml @@ -13,12 +13,12 @@ jobs: timeout-minutes: 15 steps: - name: Check out repository - uses: actions/checkout@v4 + uses: actions/checkout@11d5960a326750d5838078e36cf38b85af677262 # v4 with: submodules: recursive - name: Set up Node.js - uses: actions/setup-node@v4 + uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4 with: node-version: "22" cache: "npm" @@ -46,7 +46,7 @@ jobs: npm exec -- astro build - name: Upload website dist - uses: actions/upload-artifact@v4 + uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4 with: name: cellscript-website-dist path: website/dist/ diff --git a/CHANGELOG.md b/CHANGELOG.md index 71da81e..f8c19e4 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,18 @@ ## Unreleased +- Close the 0.23 Registry audit findings across admission, verification, and + delivery. Publisher-controlled repository and homepage fields now require + credential-free HTTPS URLs, malformed base64 is a stable client error, and + unexpected server failures no longer disclose internal messages. Source + hashing confines manifest entry/source-root paths to the package, the + isolated verifier rejects path/Git dependencies, and signed dependency + metadata must exactly match the materialized `Cell.toml`. The Node adapter + derives quota identity only across an explicitly configured trusted-proxy + boundary. Fix Registry CI under a shared `CARGO_TARGET_DIR` and additive + migrations, pin GitHub Actions by commit, add Dependabot coverage, and + update vulnerable Registry/website build dependencies. The website filters + Registry navigation URLs and adds a defense-in-depth CSP. - Make Registry chain confirmation compatible with the standard CKB v0.207.0 RPC schema by resolving a live Cell's committed block through `get_transaction.tx_status` instead of depending on a proxy-specific diff --git a/docs/releases/CELLSCRIPT_0_23_RELEASE_NOTES.md b/docs/releases/CELLSCRIPT_0_23_RELEASE_NOTES.md index 8888246..4bbde2a 100644 --- a/docs/releases/CELLSCRIPT_0_23_RELEASE_NOTES.md +++ b/docs/releases/CELLSCRIPT_0_23_RELEASE_NOTES.md @@ -3,7 +3,7 @@ **Status**: Development release notes for `nightly-0.23`; not a stable release certificate. -**Updated**: 2026-08-02. +**Updated**: 2026-08-08. CellScript 0.23 makes its source semantics and compatibility axes explicit. Edition 2026 is the first and only CellScript source-semantics epoch. The @@ -30,12 +30,14 @@ work. | Build identity | The resolved profile independently combines edition, target, primitive assurance, metadata schemas, and entry/witness ABIs, then binds them into metadata, registry, lock, deployment, receipt, and builder records. | | Registry contract | The deployed publish contract requires Edition 2026 plus its compatibility-profile hash from CLI signature through API, Postgres, version-addressed JSON, and website; assurance states require ordered evidence. | | Registry operations | `api.registry.cellscript.dev` and `registry.cellscript.dev` run as an isolated self-hosted Postgres/Node/object-volume/read-only-nginx stack behind trusted TLS. | +| Registry testnet | Pudge runs as a separate short-lived testnet sandbox with distinct API, object, database, wallet-session, RPC, and website state; it is not a mode of the production Registry. | | Registry retry safety | Pre-admission failures release only the failed request's nonce and retry reservation; accepted metadata commits transactionally, and readiness covers the actual managed object prefixes. | | Registry verification | Publish transactionally queues a leased, bounded real-compiler verification job; verified evidence/status commit atomically before crash-safe static-index convergence, and default search stays hidden until the baseline passes. | | Registry artifact profiles | CellScript dependencies, CKB executables, runtime verifiers, reproducible binaries, and copy-only templates share discovery but retain different resolver, TCB, deployment, and copy contracts. | | Registry reproducibility | Reproducible profiles stay `evidence_required` until independent builder reports bind the signed environment, source, recipe, executable, and build logs. | | Registry chain evidence | Mainnet deployment records are RPC-checked; configured Registry Type/Lock Scripts produce wallet transaction intents and a bounded Type-Script indexer reconciles live commitments without erasing history. | | Production HTTP boundary | API/static JSON responses use HSTS, deny-all content policy, anti-framing, no-sniff, and restrictive browser permissions; the website ships a reproducible read-only nginx deployment with health checks and bounded logs/temp storage. | +| Audit closure | Registry links are HTTPS-only, source paths and dependency sources are verifier-confined, signed dependencies are manifest-bound, proxy identity is explicit, and CI/supply-chain dependencies are deterministic and monitored. | | Registry install policy | Explicit unverified/quarantined install acknowledgements persist per dependency, so lock refresh and subsequent builds retain the same auditable risk choice. | | Tooling | CLI, LSP, WASM, website bindings, examples, and package tooling use the same edition contract. | | Syntax audit | Canonical type fields use trailing commas, checked examples use named `u64` boundaries, and compatibility plus CKB-VM regressions cover both source and witness placement. | diff --git a/roadmap/CELLSCRIPT_0_23_ROADMAP.md b/roadmap/CELLSCRIPT_0_23_ROADMAP.md index b1cf4f5..9d05b7c 100644 --- a/roadmap/CELLSCRIPT_0_23_ROADMAP.md +++ b/roadmap/CELLSCRIPT_0_23_ROADMAP.md @@ -144,7 +144,7 @@ Source documents: ## Pillar 1: Public Registry Production Deployment -**Status (2026-08-02): production infrastructure, public reads, website, CLI +**Status (2026-08-08): production infrastructure, public reads, website, CLI resolution, evidence promotion, and the bounded automatic source/build verification pipeline are implemented and deployed. The generalized artifact, independent reproduction, mainnet deployment, and configured chain-commitment @@ -320,7 +320,9 @@ runtime or the optional Cloudflare/R2/Hyperdrive/Neon adapter. remain under their own Lock/Type Scripts and transaction protocols. - No bond or refundable deposit mechanism; the schema leaves `policy_hooks` and `bond_policy_hooks` for later. -- No testnet Registry authorisation, deployment, or commitment state. +- No testnet state or network selector inside the production Registry. Pudge + authorisation, deployment, and commitment testing runs in a separately + isolated, expiring sandbox. - No D1 as primary database. Source documents: diff --git a/scripts/cellscript_gate.sh b/scripts/cellscript_gate.sh index bccac81..4994640 100755 --- a/scripts/cellscript_gate.sh +++ b/scripts/cellscript_gate.sh @@ -390,7 +390,11 @@ run_registry_api_check() { fi run npm --prefix services/registry-api run check run cargo build --locked --manifest-path services/registry-verifier/Cargo.toml - run env CELLSCRIPT_REGISTRY_VERIFIER_TEST_BINARY="$ROOT_DIR/services/registry-verifier/target/debug/cellscript-registry-verify" \ + local verifier_target_dir="${CARGO_TARGET_DIR:-$ROOT_DIR/services/registry-verifier/target}" + if [[ "$verifier_target_dir" != /* ]]; then + verifier_target_dir="$ROOT_DIR/$verifier_target_dir" + fi + run env CELLSCRIPT_REGISTRY_VERIFIER_TEST_BINARY="$verifier_target_dir/debug/cellscript-registry-verify" \ npm --prefix services/registry-api test run npm --prefix services/registry-api run build run npm --prefix services/registry-api run build:node diff --git a/services/registry-api/README.md b/services/registry-api/README.md index b10d3e0..2c8b82a 100644 --- a/services/registry-api/README.md +++ b/services/registry-api/README.md @@ -472,6 +472,14 @@ use `CKB_MIN_CONFIRMATIONS` to raise or lower the default 24-block confirmation floor. The Node adapter, production Compose file, and Worker example pass the same settings. +The Node adapter never trusts client-supplied `CF-Connecting-IP`, +`CF-ASN`, or internal Registry identity headers. `REGISTRY_TRUST_PROXY_HOPS` +defaults to `0`; the checked-in Compose stacks set it to `1` because ingress is +restricted to the external TLS proxy. That proxy must overwrite or append the +actual peer to `X-Forwarded-For`, and direct client access to the API container +must remain blocked. Change the hop count only when the ingress topology +changes. + The API container applies tracked additive migrations before serving traffic. `0001_initial.sql` is the frozen deployed baseline. `0002` adds the verifier queue; `0003` adds multi-wallet principals; `0004` converts an empty legacy @@ -482,6 +490,8 @@ hash-integrity evidence from semantic verification with `hash_bound`; and renames historical chain evidence, adds the current-commitment pointer and status projection constraints, and deliberately demotes legacy current claims until the mainnet indexer re-observes a sufficiently confirmed live Cell. +`0008` adds expiring Pudge sandbox state and purge tombstones; `0009` adds the +browser/CLI authorisation-session lifecycle. `GET /health` is process liveness and is the Compose container healthcheck. `GET /ready` is the traffic and operator gate: it checks store/object access, diff --git a/services/registry-api/deploy/docker-compose.production.yml b/services/registry-api/deploy/docker-compose.production.yml index 37d6b41..e719695 100644 --- a/services/registry-api/deploy/docker-compose.production.yml +++ b/services/registry-api/deploy/docker-compose.production.yml @@ -66,6 +66,7 @@ services: CKB_MIN_CONFIRMATIONS: ${CKB_MIN_CONFIRMATIONS:-24} ENVIRONMENT: production REGISTRY_ENVIRONMENT: production + REGISTRY_TRUST_PROXY_HOPS: "1" MAX_INCOMING_BODY_BYTES: "7340032" MAX_JSON_BODY_BYTES: "6291456" MAX_SNAPSHOT_BYTES: "5242880" diff --git a/services/registry-api/deploy/docker-compose.testnet.yml b/services/registry-api/deploy/docker-compose.testnet.yml index c263dea..ba5ac63 100644 --- a/services/registry-api/deploy/docker-compose.testnet.yml +++ b/services/registry-api/deploy/docker-compose.testnet.yml @@ -55,6 +55,7 @@ services: CKB_REGISTRY_SCAN_MAX_CELLS: "1000" ENVIRONMENT: testnet-sandbox REGISTRY_ENVIRONMENT: testnet-sandbox + REGISTRY_TRUST_PROXY_HOPS: "1" MAX_INCOMING_BODY_BYTES: "7340032" MAX_JSON_BODY_BYTES: "6291456" MAX_SNAPSHOT_BYTES: "5242880" diff --git a/services/registry-api/package-lock.json b/services/registry-api/package-lock.json index 882d078..9fd3758 100644 --- a/services/registry-api/package-lock.json +++ b/services/registry-api/package-lock.json @@ -14,13 +14,13 @@ "pg": "^8.13.1" }, "devDependencies": { - "@cloudflare/workers-types": "^4.20250617.0", + "@cloudflare/workers-types": "^5.20260804.1", "@types/node": "^22.20.1", - "@types/pg": "^8.11.10", + "@types/pg": "^8.20.4", "esbuild": "^0.25.12", "typescript": "^5.8.3", "vitest": "^3.2.4", - "wrangler": "^4.20.5" + "wrangler": "^4.120.0" } }, "node_modules/@cloudflare/kv-asset-handler": { @@ -50,9 +50,9 @@ } }, "node_modules/@cloudflare/workerd-darwin-64": { - "version": "1.20260617.1", - "resolved": "https://registry.npmmirror.com/@cloudflare/workerd-darwin-64/-/workerd-darwin-64-1.20260617.1.tgz", - "integrity": "sha512-jWwmgEVVWbsHNrLSNXzwjJaH90VzRxq1cWkQFUidxyeUPnMxemeNE8I9qFAfrpzGgE11e9sKDcE3ettJW08swQ==", + "version": "1.20260801.1", + "resolved": "https://registry.npmjs.org/@cloudflare/workerd-darwin-64/-/workerd-darwin-64-1.20260801.1.tgz", + "integrity": "sha512-wuJWbXpKvncJi1P0GKS+iYpN5tHdb7JPJJ/+6ZQe8zzovHHVMkLJPNBsgWpqeUhpM3g9qTwEKd2rglNKejuh5A==", "cpu": [ "x64" ], @@ -67,9 +67,9 @@ } }, "node_modules/@cloudflare/workerd-darwin-arm64": { - "version": "1.20260617.1", - "resolved": "https://registry.npmmirror.com/@cloudflare/workerd-darwin-arm64/-/workerd-darwin-arm64-1.20260617.1.tgz", - "integrity": "sha512-LHH7b565g9znfCUOkwbec6FG2rmRbsgCy6aJiU9KN662mNheWl5sw/iKleiFSiljPKQQP3HkjnC/NSkdgi/aSA==", + "version": "1.20260801.1", + "resolved": "https://registry.npmjs.org/@cloudflare/workerd-darwin-arm64/-/workerd-darwin-arm64-1.20260801.1.tgz", + "integrity": "sha512-kwoZiTpnhNrF3+APx84Q/oAqvJ3sU9yefGagwm/ASaH/2W19x0vghkW/r4qCoHCK0WW7EPugZ+aXjgPMRtlq1Q==", "cpu": [ "arm64" ], @@ -84,9 +84,9 @@ } }, "node_modules/@cloudflare/workerd-linux-64": { - "version": "1.20260617.1", - "resolved": "https://registry.npmmirror.com/@cloudflare/workerd-linux-64/-/workerd-linux-64-1.20260617.1.tgz", - "integrity": "sha512-FMnaAKXe4Cfd8TQurCVd9fs2XQVBFRCsP+Id/SRdUv89MlwYu9zXfoyx6BxM+brPTIUK38SHbo8iaxiwzLi9JQ==", + "version": "1.20260801.1", + "resolved": "https://registry.npmjs.org/@cloudflare/workerd-linux-64/-/workerd-linux-64-1.20260801.1.tgz", + "integrity": "sha512-r0vAxCZH+Jih9Unm1yoyiByPNWNgawcKciOHDm5Q37ZVGOkKLsT9AtLe3yLSaul76WrKqtf+JP2n0WW32VBLJg==", "cpu": [ "x64" ], @@ -101,9 +101,9 @@ } }, "node_modules/@cloudflare/workerd-linux-arm64": { - "version": "1.20260617.1", - "resolved": "https://registry.npmmirror.com/@cloudflare/workerd-linux-arm64/-/workerd-linux-arm64-1.20260617.1.tgz", - "integrity": "sha512-MRoifFYcqbxxIIQy7PqO5tFY/qPFSnjXzakWl0sO93l+HLyG35jRAgOi6jfqa4kBxc7gKKtH861DcewjxUfkjA==", + "version": "1.20260801.1", + "resolved": "https://registry.npmjs.org/@cloudflare/workerd-linux-arm64/-/workerd-linux-arm64-1.20260801.1.tgz", + "integrity": "sha512-zWgpdZtSozvIgzQNmQiDSF8yEOQJUkRAWNsDXXzAAoy+fCn8YUoSibj3mpFSbZRvbUldeBEaW6SCdC2VEMkhNQ==", "cpu": [ "arm64" ], @@ -118,9 +118,9 @@ } }, "node_modules/@cloudflare/workerd-windows-64": { - "version": "1.20260617.1", - "resolved": "https://registry.npmmirror.com/@cloudflare/workerd-windows-64/-/workerd-windows-64-1.20260617.1.tgz", - "integrity": "sha512-rgBV9wQrv0OSKgCTTbhFUFY3sLGNANZ88aqaLvtmEn2gmbFVb1J4PDGochVUdB7NSEp4D/ghHva6/8SZmbONpw==", + "version": "1.20260801.1", + "resolved": "https://registry.npmjs.org/@cloudflare/workerd-windows-64/-/workerd-windows-64-1.20260801.1.tgz", + "integrity": "sha512-2oQz+Ksu4ji6e/+ZoYX+tWQEcxAii2p7l+iR8kx48W1llMalaufAsmVxTlk+3/vrM7D3/2c0iK448e0UQTcIMg==", "cpu": [ "x64" ], @@ -135,15 +135,15 @@ } }, "node_modules/@cloudflare/workers-types": { - "version": "4.20260623.1", - "resolved": "https://registry.npmmirror.com/@cloudflare/workers-types/-/workers-types-4.20260623.1.tgz", - "integrity": "sha512-J/0POl0HeLepbwDE5Yx5c7jQrHFkvCEFu3TS+TQsDDlg/vTs5og7wdGP6eNGXOAntgWUrjcvvKTmVLTP7OrnAg==", + "version": "5.20260804.1", + "resolved": "https://registry.npmjs.org/@cloudflare/workers-types/-/workers-types-5.20260804.1.tgz", + "integrity": "sha512-B1dwxpN6e5RZXZkE5zpZj+ooNeNZ1mwavLIyHDYe10ojhlGTwDfe8sAl7R1mMXc1cyIsbr+jKVdvmMEyVcdTdg==", "dev": true, "license": "MIT OR Apache-2.0" }, "node_modules/@cspotcode/source-map-support": { "version": "0.8.1", - "resolved": "https://registry.npmmirror.com/@cspotcode/source-map-support/-/source-map-support-0.8.1.tgz", + "resolved": "https://registry.npmjs.org/@cspotcode/source-map-support/-/source-map-support-0.8.1.tgz", "integrity": "sha512-IchNf6dN4tHoMFIn/7OE8LWZ19Y6q/67Bmf6vnGREv8RSbBVb9LPJxEcnwrcwX6ixSvaiGoomAUvu4YSxXrVgw==", "dev": true, "license": "MIT", @@ -155,9 +155,9 @@ } }, "node_modules/@emnapi/runtime": { - "version": "1.11.1", - "resolved": "https://registry.npmmirror.com/@emnapi/runtime/-/runtime-1.11.1.tgz", - "integrity": "sha512-vgj7R3y3Wgx24IQaGPA/R6YFXLHVMOZ0uVEyIQPaWs+rd1AzfEMXlAC22FYwO1XkKR6NPsq7mUandH8oIRdZFw==", + "version": "1.11.3", + "resolved": "https://registry.npmjs.org/@emnapi/runtime/-/runtime-1.11.3.tgz", + "integrity": "sha512-Xz4Tpyki7XyrpbUK1jR1AhdAdaXyhhY4lZ3neLodmhpuWfy2PAQN5B46sAiU4liOXGLkHypn/qU+jvfWSCYYLA==", "dev": true, "license": "MIT", "optional": true, @@ -167,7 +167,7 @@ }, "node_modules/@emnapi/runtime/node_modules/tslib": { "version": "2.8.1", - "resolved": "https://registry.npmmirror.com/tslib/-/tslib-2.8.1.tgz", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz", "integrity": "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==", "dev": true, "license": "0BSD", @@ -617,7 +617,7 @@ }, "node_modules/@img/colour": { "version": "1.1.0", - "resolved": "https://registry.npmmirror.com/@img/colour/-/colour-1.1.0.tgz", + "resolved": "https://registry.npmjs.org/@img/colour/-/colour-1.1.0.tgz", "integrity": "sha512-Td76q7j57o/tLVdgS746cYARfSyxk8iEfRxewL9h4OMzYhbW4TAcppl0mT4eyqXddh6L/jwoM75mo7ixa/pCeQ==", "dev": true, "license": "MIT", @@ -626,9 +626,9 @@ } }, "node_modules/@img/sharp-darwin-arm64": { - "version": "0.34.5", - "resolved": "https://registry.npmmirror.com/@img/sharp-darwin-arm64/-/sharp-darwin-arm64-0.34.5.tgz", - "integrity": "sha512-imtQ3WMJXbMY4fxb/Ndp6HBTNVtWCUI0WdobyheGf5+ad6xX8VIDO8u2xE4qc/fr08CKG/7dDseFtn6M6g/r3w==", + "version": "0.35.2", + "resolved": "https://registry.npmjs.org/@img/sharp-darwin-arm64/-/sharp-darwin-arm64-0.35.2.tgz", + "integrity": "sha512-eEieHsMksAW4IiO5NzauESRl2D2qz3J/kwUxUrSfV06A93eEaRfMpHXyUb1mAqrR7i8U9A0GRqE9pjn6u1Jjpg==", "cpu": [ "arm64" ], @@ -639,19 +639,19 @@ "darwin" ], "engines": { - "node": "^18.17.0 || ^20.3.0 || >=21.0.0" + "node": ">=20.9.0" }, "funding": { "url": "https://opencollective.com/libvips" }, "optionalDependencies": { - "@img/sharp-libvips-darwin-arm64": "1.2.4" + "@img/sharp-libvips-darwin-arm64": "1.3.1" } }, "node_modules/@img/sharp-darwin-x64": { - "version": "0.34.5", - "resolved": "https://registry.npmmirror.com/@img/sharp-darwin-x64/-/sharp-darwin-x64-0.34.5.tgz", - "integrity": "sha512-YNEFAF/4KQ/PeW0N+r+aVVsoIY0/qxxikF2SWdp+NRkmMB7y9LBZAVqQ4yhGCm/H3H270OSykqmQMKLBhBJDEw==", + "version": "0.35.2", + "resolved": "https://registry.npmjs.org/@img/sharp-darwin-x64/-/sharp-darwin-x64-0.35.2.tgz", + "integrity": "sha512-BaktuGPCeHJMARpodR8jK4uKiZrPAy9WrfQW0sdI37clracq8Bp01AYS3SZgi5FS/y5twa9t4+LIuuxQjqRrWw==", "cpu": [ "x64" ], @@ -662,19 +662,39 @@ "darwin" ], "engines": { - "node": "^18.17.0 || ^20.3.0 || >=21.0.0" + "node": ">=20.9.0" }, "funding": { "url": "https://opencollective.com/libvips" }, "optionalDependencies": { - "@img/sharp-libvips-darwin-x64": "1.2.4" + "@img/sharp-libvips-darwin-x64": "1.3.1" + } + }, + "node_modules/@img/sharp-freebsd-wasm32": { + "version": "0.35.2", + "resolved": "https://registry.npmjs.org/@img/sharp-freebsd-wasm32/-/sharp-freebsd-wasm32-0.35.2.tgz", + "integrity": "sha512-YoAxdnd8hPUkvLHd3bWY+YA8nw3xM/RyRopYucNsWHVSan8NLVM3X2volsfoRDcXdUJPg6tXahSd7HXPK7lRnw==", + "dev": true, + "license": "Apache-2.0", + "optional": true, + "os": [ + "freebsd" + ], + "dependencies": { + "@img/sharp-wasm32": "0.35.2" + }, + "engines": { + "node": ">=20.9.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" } }, "node_modules/@img/sharp-libvips-darwin-arm64": { - "version": "1.2.4", - "resolved": "https://registry.npmmirror.com/@img/sharp-libvips-darwin-arm64/-/sharp-libvips-darwin-arm64-1.2.4.tgz", - "integrity": "sha512-zqjjo7RatFfFoP0MkQ51jfuFZBnVE2pRiaydKJ1G/rHZvnsrHAOcQALIi9sA5co5xenQdTugCvtb1cuf78Vf4g==", + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/@img/sharp-libvips-darwin-arm64/-/sharp-libvips-darwin-arm64-1.3.1.tgz", + "integrity": "sha512-4V/M3roRMTYjiwZY9IOVQOE8OyeCxFAkYmyZDrZl51uOKjibm3oeEJ4WAmLxutAfzFbC9jqUiPs2gbnGflH+7g==", "cpu": [ "arm64" ], @@ -689,9 +709,9 @@ } }, "node_modules/@img/sharp-libvips-darwin-x64": { - "version": "1.2.4", - "resolved": "https://registry.npmmirror.com/@img/sharp-libvips-darwin-x64/-/sharp-libvips-darwin-x64-1.2.4.tgz", - "integrity": "sha512-1IOd5xfVhlGwX+zXv2N93k0yMONvUlANylbJw1eTah8K/Jtpi15KC+WSiaX/nBmbm2HxRM1gZ0nSdjSsrZbGKg==", + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/@img/sharp-libvips-darwin-x64/-/sharp-libvips-darwin-x64-1.3.1.tgz", + "integrity": "sha512-c0/DxItpJv2+dGhgycJBBgotdqruGYDvA79drdh0MD1dFpy7JzJ/PlXwi1H4rFf0eTy8tgbI91aHDnZIceY3jQ==", "cpu": [ "x64" ], @@ -706,9 +726,9 @@ } }, "node_modules/@img/sharp-libvips-linux-arm": { - "version": "1.2.4", - "resolved": "https://registry.npmmirror.com/@img/sharp-libvips-linux-arm/-/sharp-libvips-linux-arm-1.2.4.tgz", - "integrity": "sha512-bFI7xcKFELdiNCVov8e44Ia4u2byA+l3XtsAj+Q8tfCwO6BQ8iDojYdvoPMqsKDkuoOo+X6HZA0s0q11ANMQ8A==", + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-arm/-/sharp-libvips-linux-arm-1.3.1.tgz", + "integrity": "sha512-aGGy9aWzXgHBG7HNyQPWorZthlp7+x6fDRoPAQbGO3ThcttuTyKIx3NuSHb6zb4gBNq6/yNn9f1cy9nFKS/Vmg==", "cpu": [ "arm" ], @@ -726,9 +746,9 @@ } }, "node_modules/@img/sharp-libvips-linux-arm64": { - "version": "1.2.4", - "resolved": "https://registry.npmmirror.com/@img/sharp-libvips-linux-arm64/-/sharp-libvips-linux-arm64-1.2.4.tgz", - "integrity": "sha512-excjX8DfsIcJ10x1Kzr4RcWe1edC9PquDRRPx3YVCvQv+U5p7Yin2s32ftzikXojb1PIFc/9Mt28/y+iRklkrw==", + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-arm64/-/sharp-libvips-linux-arm64-1.3.1.tgz", + "integrity": "sha512-JznefmcK9j1JKPz8AkQDh89kjojubyfOasWBPKfzMIhPwsgDy9evpE/naJTXXXmghS1iFwR8u/kTwh/I2/+GCw==", "cpu": [ "arm64" ], @@ -746,9 +766,9 @@ } }, "node_modules/@img/sharp-libvips-linux-ppc64": { - "version": "1.2.4", - "resolved": "https://registry.npmmirror.com/@img/sharp-libvips-linux-ppc64/-/sharp-libvips-linux-ppc64-1.2.4.tgz", - "integrity": "sha512-FMuvGijLDYG6lW+b/UvyilUWu5Ayu+3r2d1S8notiGCIyYU/76eig1UfMmkZ7vwgOrzKzlQbFSuQfgm7GYUPpA==", + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-ppc64/-/sharp-libvips-linux-ppc64-1.3.1.tgz", + "integrity": "sha512-1EkwGNCZk6iWNCMWqrvdJ+r1j0PT1zIz60CNPhYnJlK/zyeWqlsPZIe+ocBVqPF8k/Ssee/NCk+tE9Ryrko6ng==", "cpu": [ "ppc64" ], @@ -766,9 +786,9 @@ } }, "node_modules/@img/sharp-libvips-linux-riscv64": { - "version": "1.2.4", - "resolved": "https://registry.npmmirror.com/@img/sharp-libvips-linux-riscv64/-/sharp-libvips-linux-riscv64-1.2.4.tgz", - "integrity": "sha512-oVDbcR4zUC0ce82teubSm+x6ETixtKZBh/qbREIOcI3cULzDyb18Sr/Wcyx7NRQeQzOiHTNbZFF1UwPS2scyGA==", + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-riscv64/-/sharp-libvips-linux-riscv64-1.3.1.tgz", + "integrity": "sha512-Ilays+w2bXdnxzxtQdmXR62u8o8GYa3eL4+Gr+1KiE4xperMZUslRaVPJwwPkzlHEjGfXAfRVAa/7CYCtSqsBw==", "cpu": [ "riscv64" ], @@ -786,9 +806,9 @@ } }, "node_modules/@img/sharp-libvips-linux-s390x": { - "version": "1.2.4", - "resolved": "https://registry.npmmirror.com/@img/sharp-libvips-linux-s390x/-/sharp-libvips-linux-s390x-1.2.4.tgz", - "integrity": "sha512-qmp9VrzgPgMoGZyPvrQHqk02uyjA0/QrTO26Tqk6l4ZV0MPWIW6LTkqOIov+J1yEu7MbFQaDpwdwJKhbJvuRxQ==", + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-s390x/-/sharp-libvips-linux-s390x-1.3.1.tgz", + "integrity": "sha512-VfBwVHQTbRoj4XlpA/KLZ7ltgMpz+4WSejFzQ+GnoImjo1PtEJ59QB2qR1xQEeRPYIkNrPIm2L4cICMvz4C2ew==", "cpu": [ "s390x" ], @@ -806,9 +826,9 @@ } }, "node_modules/@img/sharp-libvips-linux-x64": { - "version": "1.2.4", - "resolved": "https://registry.npmmirror.com/@img/sharp-libvips-linux-x64/-/sharp-libvips-linux-x64-1.2.4.tgz", - "integrity": "sha512-tJxiiLsmHc9Ax1bz3oaOYBURTXGIRDODBqhveVHonrHJ9/+k89qbLl0bcJns+e4t4rvaNBxaEZsFtSfAdquPrw==", + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-x64/-/sharp-libvips-linux-x64-1.3.1.tgz", + "integrity": "sha512-+c8ukgwU62DS54nCAjw7keOfHUkmr0B5QHEdcOqRnodF/MNXJbVI8Eopoj4B/0H8Asr65I+A4Amrn7a85/md6A==", "cpu": [ "x64" ], @@ -826,9 +846,9 @@ } }, "node_modules/@img/sharp-libvips-linuxmusl-arm64": { - "version": "1.2.4", - "resolved": "https://registry.npmmirror.com/@img/sharp-libvips-linuxmusl-arm64/-/sharp-libvips-linuxmusl-arm64-1.2.4.tgz", - "integrity": "sha512-FVQHuwx1IIuNow9QAbYUzJ+En8KcVm9Lk5+uGUQJHaZmMECZmOlix9HnH7n1TRkXMS0pGxIJokIVB9SuqZGGXw==", + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linuxmusl-arm64/-/sharp-libvips-linuxmusl-arm64-1.3.1.tgz", + "integrity": "sha512-qlKb/pwbkAi1WMsJrYHk7CuDrd12s27U2QnRhFYUoJNrRCmkosMTttuRFat/DDB3IlDm5qE1TJgZ4JDnHX8Ldw==", "cpu": [ "arm64" ], @@ -846,9 +866,9 @@ } }, "node_modules/@img/sharp-libvips-linuxmusl-x64": { - "version": "1.2.4", - "resolved": "https://registry.npmmirror.com/@img/sharp-libvips-linuxmusl-x64/-/sharp-libvips-linuxmusl-x64-1.2.4.tgz", - "integrity": "sha512-+LpyBk7L44ZIXwz/VYfglaX/okxezESc6UxDSoyo2Ks6Jxc4Y7sGjpgU9s4PMgqgjj1gZCylTieNamqA1MF7Dg==", + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linuxmusl-x64/-/sharp-libvips-linuxmusl-x64-1.3.1.tgz", + "integrity": "sha512-yO21HwoUVLN8Qa+/SBjQLMYwBWAVJjeGPNe+hc0OUeMeifEtJqu5a1c4HayE1nNpDih9y3/KkoltfkDodmKAlg==", "cpu": [ "x64" ], @@ -866,9 +886,9 @@ } }, "node_modules/@img/sharp-linux-arm": { - "version": "0.34.5", - "resolved": "https://registry.npmmirror.com/@img/sharp-linux-arm/-/sharp-linux-arm-0.34.5.tgz", - "integrity": "sha512-9dLqsvwtg1uuXBGZKsxem9595+ujv0sJ6Vi8wcTANSFpwV/GONat5eCkzQo/1O6zRIkh0m/8+5BjrRr7jDUSZw==", + "version": "0.35.2", + "resolved": "https://registry.npmjs.org/@img/sharp-linux-arm/-/sharp-linux-arm-0.35.2.tgz", + "integrity": "sha512-SE4kzF2mepn6z+6E7L6lsV8FzuLL6IPQdyX8ZiwROAG/G8td+hP/m7FsFPwidtrF19gvajuC9l6TxAVcsA4S7A==", "cpu": [ "arm" ], @@ -882,19 +902,19 @@ "linux" ], "engines": { - "node": "^18.17.0 || ^20.3.0 || >=21.0.0" + "node": ">=20.9.0" }, "funding": { "url": "https://opencollective.com/libvips" }, "optionalDependencies": { - "@img/sharp-libvips-linux-arm": "1.2.4" + "@img/sharp-libvips-linux-arm": "1.3.1" } }, "node_modules/@img/sharp-linux-arm64": { - "version": "0.34.5", - "resolved": "https://registry.npmmirror.com/@img/sharp-linux-arm64/-/sharp-linux-arm64-0.34.5.tgz", - "integrity": "sha512-bKQzaJRY/bkPOXyKx5EVup7qkaojECG6NLYswgktOZjaXecSAeCWiZwwiFf3/Y+O1HrauiE3FVsGxFg8c24rZg==", + "version": "0.35.2", + "resolved": "https://registry.npmjs.org/@img/sharp-linux-arm64/-/sharp-linux-arm64-0.35.2.tgz", + "integrity": "sha512-af12Pnd0ZGu2HfP8NayB0kk6eC/lrfbQE6HlR4jD+34wdJ1Vw9TF6TMn6ZvffT+WgqVsl0hRbmNvz2u/23VmwA==", "cpu": [ "arm64" ], @@ -908,19 +928,19 @@ "linux" ], "engines": { - "node": "^18.17.0 || ^20.3.0 || >=21.0.0" + "node": ">=20.9.0" }, "funding": { "url": "https://opencollective.com/libvips" }, "optionalDependencies": { - "@img/sharp-libvips-linux-arm64": "1.2.4" + "@img/sharp-libvips-linux-arm64": "1.3.1" } }, "node_modules/@img/sharp-linux-ppc64": { - "version": "0.34.5", - "resolved": "https://registry.npmmirror.com/@img/sharp-linux-ppc64/-/sharp-linux-ppc64-0.34.5.tgz", - "integrity": "sha512-7zznwNaqW6YtsfrGGDA6BRkISKAAE1Jo0QdpNYXNMHu2+0dTrPflTLNkpc8l7MUP5M16ZJcUvysVWWrMefZquA==", + "version": "0.35.2", + "resolved": "https://registry.npmjs.org/@img/sharp-linux-ppc64/-/sharp-linux-ppc64-0.35.2.tgz", + "integrity": "sha512-hYSBm7zcNtDCozCxQHYZJiu63b/bXsgRZuOxCIBZsStMM9Vap47iFHdbX4kCvQsblPB/k+clhELpdQJHQLSHvg==", "cpu": [ "ppc64" ], @@ -934,19 +954,19 @@ "linux" ], "engines": { - "node": "^18.17.0 || ^20.3.0 || >=21.0.0" + "node": ">=20.9.0" }, "funding": { "url": "https://opencollective.com/libvips" }, "optionalDependencies": { - "@img/sharp-libvips-linux-ppc64": "1.2.4" + "@img/sharp-libvips-linux-ppc64": "1.3.1" } }, "node_modules/@img/sharp-linux-riscv64": { - "version": "0.34.5", - "resolved": "https://registry.npmmirror.com/@img/sharp-linux-riscv64/-/sharp-linux-riscv64-0.34.5.tgz", - "integrity": "sha512-51gJuLPTKa7piYPaVs8GmByo7/U7/7TZOq+cnXJIHZKavIRHAP77e3N2HEl3dgiqdD/w0yUfiJnII77PuDDFdw==", + "version": "0.35.2", + "resolved": "https://registry.npmjs.org/@img/sharp-linux-riscv64/-/sharp-linux-riscv64-0.35.2.tgz", + "integrity": "sha512-qQt0Kc13+Hoan/Awq/qMSQw3L+RI1NCRPgD5cUJ/1WSSmIoysLOc72jlRM3E0OHN9Yr313jgeQ2T+zW+F03QFA==", "cpu": [ "riscv64" ], @@ -960,19 +980,19 @@ "linux" ], "engines": { - "node": "^18.17.0 || ^20.3.0 || >=21.0.0" + "node": ">=20.9.0" }, "funding": { "url": "https://opencollective.com/libvips" }, "optionalDependencies": { - "@img/sharp-libvips-linux-riscv64": "1.2.4" + "@img/sharp-libvips-linux-riscv64": "1.3.1" } }, "node_modules/@img/sharp-linux-s390x": { - "version": "0.34.5", - "resolved": "https://registry.npmmirror.com/@img/sharp-linux-s390x/-/sharp-linux-s390x-0.34.5.tgz", - "integrity": "sha512-nQtCk0PdKfho3eC5MrbQoigJ2gd1CgddUMkabUj+rBevs8tZ2cULOx46E7oyX+04WGfABgIwmMC0VqieTiR4jg==", + "version": "0.35.2", + "resolved": "https://registry.npmjs.org/@img/sharp-linux-s390x/-/sharp-linux-s390x-0.35.2.tgz", + "integrity": "sha512-E4fLLfRPzDLlEeDaTzI98OFLcv++WL5ChLLMwPoVd0CIoZQqupBSNbOisPL5am9XsbQ9T84+iiMpUvbFtkunbA==", "cpu": [ "s390x" ], @@ -986,19 +1006,19 @@ "linux" ], "engines": { - "node": "^18.17.0 || ^20.3.0 || >=21.0.0" + "node": ">=20.9.0" }, "funding": { "url": "https://opencollective.com/libvips" }, "optionalDependencies": { - "@img/sharp-libvips-linux-s390x": "1.2.4" + "@img/sharp-libvips-linux-s390x": "1.3.1" } }, "node_modules/@img/sharp-linux-x64": { - "version": "0.34.5", - "resolved": "https://registry.npmmirror.com/@img/sharp-linux-x64/-/sharp-linux-x64-0.34.5.tgz", - "integrity": "sha512-MEzd8HPKxVxVenwAa+JRPwEC7QFjoPWuS5NZnBt6B3pu7EG2Ge0id1oLHZpPJdn3OQK+BQDiw9zStiHBTJQQQQ==", + "version": "0.35.2", + "resolved": "https://registry.npmjs.org/@img/sharp-linux-x64/-/sharp-linux-x64-0.35.2.tgz", + "integrity": "sha512-gi0zFJJRLswfCZmHtJdikXPOc5u7qamSOS3NHedLqLd4W8Q0NqjdBr6TTRIgsfFjqfTsHFgdfvJ9LwqSgcHiAA==", "cpu": [ "x64" ], @@ -1012,19 +1032,19 @@ "linux" ], "engines": { - "node": "^18.17.0 || ^20.3.0 || >=21.0.0" + "node": ">=20.9.0" }, "funding": { "url": "https://opencollective.com/libvips" }, "optionalDependencies": { - "@img/sharp-libvips-linux-x64": "1.2.4" + "@img/sharp-libvips-linux-x64": "1.3.1" } }, "node_modules/@img/sharp-linuxmusl-arm64": { - "version": "0.34.5", - "resolved": "https://registry.npmmirror.com/@img/sharp-linuxmusl-arm64/-/sharp-linuxmusl-arm64-0.34.5.tgz", - "integrity": "sha512-fprJR6GtRsMt6Kyfq44IsChVZeGN97gTD331weR1ex1c1rypDEABN6Tm2xa1wE6lYb5DdEnk03NZPqA7Id21yg==", + "version": "0.35.2", + "resolved": "https://registry.npmjs.org/@img/sharp-linuxmusl-arm64/-/sharp-linuxmusl-arm64-0.35.2.tgz", + "integrity": "sha512-siWbOW1u6HFnFLrp0waKyW7VEf7jYvcDWdrXEFa8AkdAQgEvuu5Fz8/Y70w9EeqAdwDtfU012BhEHHaDqvQNzg==", "cpu": [ "arm64" ], @@ -1038,19 +1058,19 @@ "linux" ], "engines": { - "node": "^18.17.0 || ^20.3.0 || >=21.0.0" + "node": ">=20.9.0" }, "funding": { "url": "https://opencollective.com/libvips" }, "optionalDependencies": { - "@img/sharp-libvips-linuxmusl-arm64": "1.2.4" + "@img/sharp-libvips-linuxmusl-arm64": "1.3.1" } }, "node_modules/@img/sharp-linuxmusl-x64": { - "version": "0.34.5", - "resolved": "https://registry.npmmirror.com/@img/sharp-linuxmusl-x64/-/sharp-linuxmusl-x64-0.34.5.tgz", - "integrity": "sha512-Jg8wNT1MUzIvhBFxViqrEhWDGzqymo3sV7z7ZsaWbZNDLXRJZoRGrjulp60YYtV4wfY8VIKcWidjojlLcWrd8Q==", + "version": "0.35.2", + "resolved": "https://registry.npmjs.org/@img/sharp-linuxmusl-x64/-/sharp-linuxmusl-x64-0.35.2.tgz", + "integrity": "sha512-YBqMMcjDi4QGYiSn4vNOYBhmlC4z5AXqkOUUqI2e0AFA4urNv4ESgOgwNl3K+4etQhha0twXlzeF20bbULm9Yg==", "cpu": [ "x64" ], @@ -1064,39 +1084,56 @@ "linux" ], "engines": { - "node": "^18.17.0 || ^20.3.0 || >=21.0.0" + "node": ">=20.9.0" }, "funding": { "url": "https://opencollective.com/libvips" }, "optionalDependencies": { - "@img/sharp-libvips-linuxmusl-x64": "1.2.4" + "@img/sharp-libvips-linuxmusl-x64": "1.3.1" } }, "node_modules/@img/sharp-wasm32": { - "version": "0.34.5", - "resolved": "https://registry.npmmirror.com/@img/sharp-wasm32/-/sharp-wasm32-0.34.5.tgz", - "integrity": "sha512-OdWTEiVkY2PHwqkbBI8frFxQQFekHaSSkUIJkwzclWZe64O1X4UlUjqqqLaPbUpMOQk6FBu/HtlGXNblIs0huw==", + "version": "0.35.2", + "resolved": "https://registry.npmjs.org/@img/sharp-wasm32/-/sharp-wasm32-0.35.2.tgz", + "integrity": "sha512-Mrv4JQNYVQ94xH+jzZ9r+gowleN8mv2FTgKT+PI6bx5C0G8TdNYndu161pg2i7uoBwxy2ImPMHrJOM2LZef7Bw==", + "dev": true, + "license": "Apache-2.0 AND LGPL-3.0-or-later AND MIT", + "optional": true, + "dependencies": { + "@emnapi/runtime": "^1.11.1" + }, + "engines": { + "node": ">=20.9.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "node_modules/@img/sharp-webcontainers-wasm32": { + "version": "0.35.2", + "resolved": "https://registry.npmjs.org/@img/sharp-webcontainers-wasm32/-/sharp-webcontainers-wasm32-0.35.2.tgz", + "integrity": "sha512-QNV27pxs9wpApEiCfvHM1RDoP1w1+2KrUWWDPEhEwg+latvOrfuhWrHWZKwdSFwU6jh3myjw/yOCRsUIuOft3g==", "cpu": [ "wasm32" ], "dev": true, - "license": "Apache-2.0 AND LGPL-3.0-or-later AND MIT", + "license": "Apache-2.0", "optional": true, "dependencies": { - "@emnapi/runtime": "^1.7.0" + "@img/sharp-wasm32": "0.35.2" }, "engines": { - "node": "^18.17.0 || ^20.3.0 || >=21.0.0" + "node": ">=20.9.0" }, "funding": { "url": "https://opencollective.com/libvips" } }, "node_modules/@img/sharp-win32-arm64": { - "version": "0.34.5", - "resolved": "https://registry.npmmirror.com/@img/sharp-win32-arm64/-/sharp-win32-arm64-0.34.5.tgz", - "integrity": "sha512-WQ3AgWCWYSb2yt+IG8mnC6Jdk9Whs7O0gxphblsLvdhSpSTtmu69ZG1Gkb6NuvxsNACwiPV6cNSZNzt0KPsw7g==", + "version": "0.35.2", + "resolved": "https://registry.npmjs.org/@img/sharp-win32-arm64/-/sharp-win32-arm64-0.35.2.tgz", + "integrity": "sha512-BiVRYc/t6/Vl3e1hBx0hugG4oN9Pydf4fgMSpxTQJmwGUg/YoXTWHiFeRymHfCZzifxu4F4rpk/I67D0LQ20wQ==", "cpu": [ "arm64" ], @@ -1107,16 +1144,16 @@ "win32" ], "engines": { - "node": "^18.17.0 || ^20.3.0 || >=21.0.0" + "node": ">=20.9.0" }, "funding": { "url": "https://opencollective.com/libvips" } }, "node_modules/@img/sharp-win32-ia32": { - "version": "0.34.5", - "resolved": "https://registry.npmmirror.com/@img/sharp-win32-ia32/-/sharp-win32-ia32-0.34.5.tgz", - "integrity": "sha512-FV9m/7NmeCmSHDD5j4+4pNI8Cp3aW+JvLoXcTUo0IqyjSfAZJ8dIUmijx1qaJsIiU+Hosw6xM5KijAWRJCSgNg==", + "version": "0.35.2", + "resolved": "https://registry.npmjs.org/@img/sharp-win32-ia32/-/sharp-win32-ia32-0.35.2.tgz", + "integrity": "sha512-YYEhx9PImCC7T0tI8JDMi4DB9LwLCXCU5OWNYEXAxh5Q1ShKkyC6byxzoBJ3gEFDnH2lQckWuDe70G7mB2XJog==", "cpu": [ "ia32" ], @@ -1127,16 +1164,16 @@ "win32" ], "engines": { - "node": "^18.17.0 || ^20.3.0 || >=21.0.0" + "node": "^20.9.0" }, "funding": { "url": "https://opencollective.com/libvips" } }, "node_modules/@img/sharp-win32-x64": { - "version": "0.34.5", - "resolved": "https://registry.npmmirror.com/@img/sharp-win32-x64/-/sharp-win32-x64-0.34.5.tgz", - "integrity": "sha512-+29YMsqY2/9eFEiW93eqWnuLcWcufowXewwSNIT6UwZdUUCrM3oFjMWH/Z6/TMmb4hlFenmfAVbpWeup2jryCw==", + "version": "0.35.2", + "resolved": "https://registry.npmjs.org/@img/sharp-win32-x64/-/sharp-win32-x64-0.35.2.tgz", + "integrity": "sha512-imoOyBcoM/iiUr4J6VPpCNjPnjvP/Gks95898yB8YqoGGYmHYbOyCuNv9FMhFgtaiHFGbHW8bxKqRV6VjtXThQ==", "cpu": [ "x64" ], @@ -1147,7 +1184,7 @@ "win32" ], "engines": { - "node": "^18.17.0 || ^20.3.0 || >=21.0.0" + "node": ">=20.9.0" }, "funding": { "url": "https://opencollective.com/libvips" @@ -1177,7 +1214,7 @@ }, "node_modules/@jridgewell/resolve-uri": { "version": "3.1.2", - "resolved": "https://registry.npmmirror.com/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz", + "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz", "integrity": "sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==", "dev": true, "license": "MIT", @@ -1194,7 +1231,7 @@ }, "node_modules/@jridgewell/trace-mapping": { "version": "0.3.9", - "resolved": "https://registry.npmmirror.com/@jridgewell/trace-mapping/-/trace-mapping-0.3.9.tgz", + "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.9.tgz", "integrity": "sha512-3Belt6tdc8bPgAtbcmdtNJlirVoTmEb5e2gC94PnkwEW9jI6CAHUeoG85tjWP5WquqfavoMtMwiG4P926ZKKuQ==", "dev": true, "license": "MIT", @@ -1251,7 +1288,7 @@ }, "node_modules/@poppinss/colors": { "version": "4.1.6", - "resolved": "https://registry.npmmirror.com/@poppinss/colors/-/colors-4.1.6.tgz", + "resolved": "https://registry.npmjs.org/@poppinss/colors/-/colors-4.1.6.tgz", "integrity": "sha512-H9xkIdFswbS8n1d6vmRd8+c10t2Qe+rZITbbDHHkQixH5+2x1FDGmi/0K+WgWiqQFKPSlIYB7jlH6Kpfn6Fleg==", "dev": true, "license": "MIT", @@ -1261,7 +1298,7 @@ }, "node_modules/@poppinss/dumper": { "version": "0.6.5", - "resolved": "https://registry.npmmirror.com/@poppinss/dumper/-/dumper-0.6.5.tgz", + "resolved": "https://registry.npmjs.org/@poppinss/dumper/-/dumper-0.6.5.tgz", "integrity": "sha512-NBdYIb90J7LfOI32dOewKI1r7wnkiH6m920puQ3qHUeZkxNkQiFnXVWoE6YtFSv6QOiPPf7ys6i+HWWecDz7sw==", "dev": true, "license": "MIT", @@ -1273,7 +1310,7 @@ }, "node_modules/@poppinss/exception": { "version": "1.2.3", - "resolved": "https://registry.npmmirror.com/@poppinss/exception/-/exception-1.2.3.tgz", + "resolved": "https://registry.npmjs.org/@poppinss/exception/-/exception-1.2.3.tgz", "integrity": "sha512-dCED+QRChTVatE9ibtoaxc+WkdzOSjYTKi/+uacHWIsfodVfpsueo3+DKpgU5Px8qXjgmXkSvhXvSCz3fnP9lw==", "dev": true, "license": "MIT" @@ -1669,7 +1706,7 @@ }, "node_modules/@sindresorhus/is": { "version": "7.2.0", - "resolved": "https://registry.npmmirror.com/@sindresorhus/is/-/is-7.2.0.tgz", + "resolved": "https://registry.npmjs.org/@sindresorhus/is/-/is-7.2.0.tgz", "integrity": "sha512-P1Cz1dWaFfR4IR+U13mqqiGsLFf1KbayybWwdd2vfctdV6hDpUkgCY0nKOLLTMSoRd/jJNjtbqzf13K8DCCXQw==", "dev": true, "license": "MIT", @@ -1681,9 +1718,9 @@ } }, "node_modules/@speed-highlight/core": { - "version": "1.2.17", - "resolved": "https://registry.npmmirror.com/@speed-highlight/core/-/core-1.2.17.tgz", - "integrity": "sha512-Z92FwKpCtfaW1V0jTU/fh3QzYEZN8wDwrzRIBoADCJfn4mJCNcJN/XegifX7BDrQ8/h9Xh/JnbyMchL0FqXrkg==", + "version": "1.2.23", + "resolved": "https://registry.npmjs.org/@speed-highlight/core/-/core-1.2.23.tgz", + "integrity": "sha512-iRoq6i6JDJP6Mt2A5JaPvzw0pgYHH6k92ij+yXiTrB7T2y9N789aWE3EHWj/5ztlJBokcCBja3iYLVdu5wgnkg==", "dev": true, "license": "CC0-1.0" }, @@ -1723,9 +1760,9 @@ } }, "node_modules/@types/pg": { - "version": "8.20.0", - "resolved": "https://registry.npmmirror.com/@types/pg/-/pg-8.20.0.tgz", - "integrity": "sha512-bEPFOaMAHTEP1EzpvHTbmwR8UsFyHSKsRisLIHVMXnpNefSbGA1bD6CVy+qKjGSqmZqNqBDV2azOBo8TgkcVow==", + "version": "8.20.4", + "resolved": "https://registry.npmjs.org/@types/pg/-/pg-8.20.4.tgz", + "integrity": "sha512-Jz7UDOlIiFJuacC0TlBoLyNtmwlA/wpIyPDd3tvUqlRM+HzkWy2xUgpFpaXtbfTAFF6sIGq5lsCDBdJnhky1Xg==", "dev": true, "license": "MIT", "dependencies": { @@ -1938,7 +1975,7 @@ }, "node_modules/cookie": { "version": "1.1.1", - "resolved": "https://registry.npmmirror.com/cookie/-/cookie-1.1.1.tgz", + "resolved": "https://registry.npmjs.org/cookie/-/cookie-1.1.1.tgz", "integrity": "sha512-ei8Aos7ja0weRpFzJnEA9UHJ/7XQmqglbRwnf2ATjcB9Wq874VKH9kfjjirM6UhU2/E5fFYadylyhFldcqSidQ==", "dev": true, "license": "MIT", @@ -1989,7 +2026,7 @@ }, "node_modules/detect-libc": { "version": "2.1.2", - "resolved": "https://registry.npmmirror.com/detect-libc/-/detect-libc-2.1.2.tgz", + "resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-2.1.2.tgz", "integrity": "sha512-Btj2BOOO83o3WyH59e8MgXsxEQVcarkUOpEYrubB0urwnN10yQ364rsiByU11nZlqWYZm05i/of7io4mzihBtQ==", "dev": true, "license": "Apache-2.0", @@ -2014,7 +2051,7 @@ }, "node_modules/error-stack-parser-es": { "version": "1.0.5", - "resolved": "https://registry.npmmirror.com/error-stack-parser-es/-/error-stack-parser-es-1.0.5.tgz", + "resolved": "https://registry.npmjs.org/error-stack-parser-es/-/error-stack-parser-es-1.0.5.tgz", "integrity": "sha512-5qucVt2XcuGMcEGgWI7i+yZpmpByQ8J1lHhcL7PwqCwu9FPP3VUXzT4ltHe5i2z9dePwEHcDVOAfSnHsOlCXRA==", "dev": true, "license": "MIT", @@ -2166,7 +2203,7 @@ }, "node_modules/kleur": { "version": "4.1.5", - "resolved": "https://registry.npmmirror.com/kleur/-/kleur-4.1.5.tgz", + "resolved": "https://registry.npmjs.org/kleur/-/kleur-4.1.5.tgz", "integrity": "sha512-o+NO+8WrRiQEE4/7nwRJhN1HWpVmJm511pBHUxPLtp0BUISzlBplORYSmTclCnJvQq2tKu/sgl3xVpkc7ZWuQQ==", "dev": true, "license": "MIT", @@ -2192,22 +2229,19 @@ } }, "node_modules/miniflare": { - "version": "4.20260617.1", - "resolved": "https://registry.npmmirror.com/miniflare/-/miniflare-4.20260617.1.tgz", - "integrity": "sha512-Go3/gzStm99QHptsSgU+q1S+xDfLoRgwjJNY80kaTVi0ENhTyqKq+sc4xZiWBSbM7uUcJwmzm8+QFKtcYLJ9nw==", + "version": "5.20260801.1-alpha", + "resolved": "https://registry.npmjs.org/miniflare/-/miniflare-5.20260801.1-alpha.tgz", + "integrity": "sha512-BHPVzIDA6mbx7LefxpvkXW7DHx9FKB9GorZatbnrrFTt3CVMU8zuUpbgyCuebwDKcTTOZos43ta8GQ0eMVEpxA==", "dev": true, "license": "MIT", "dependencies": { "@cspotcode/source-map-support": "0.8.1", - "sharp": "0.34.5", - "undici": "7.28.0", - "workerd": "1.20260617.1", + "sharp": "0.35.2", + "undici": "7.29.0", + "workerd": "1.20260801.1", "ws": "8.21.0", "youch": "4.1.0-beta.10" }, - "bin": { - "miniflare": "bootstrap.js" - }, "engines": { "node": ">=22.0.0" } @@ -2232,9 +2266,9 @@ "license": "MIT" }, "node_modules/nanoid": { - "version": "3.3.15", - "resolved": "https://registry.npmmirror.com/nanoid/-/nanoid-3.3.15.tgz", - "integrity": "sha512-y7Wygv/7mEOvxTuEQDB8StXdMRBWf1kR/tlhAzBRUFkB2jfcLOAxO/SHmOO2zgz1pVgK29/kyupn059/bCHdjA==", + "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": [ { @@ -2404,9 +2438,9 @@ } }, "node_modules/postcss": { - "version": "8.5.15", - "resolved": "https://registry.npmmirror.com/postcss/-/postcss-8.5.15.tgz", - "integrity": "sha512-FfR8sjd4em2T6fb3I2MwAJU7HWVMr9zba+enmQeeWFfCbm+UOC/0X4DS8XtpUTMwWMGbjKYP7xjfNekzyGmB3A==", + "version": "8.5.26", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.26.tgz", + "integrity": "sha512-u82N74LFzG8ca+dD8puPnplTXoGH4fTPpVGuIbt36G3qvNlkvfD0lEAZSxaly3KX8TS/L1A1gsCEmvKmBcVbkQ==", "dev": true, "funding": [ { @@ -2424,7 +2458,7 @@ ], "license": "MIT", "dependencies": { - "nanoid": "^3.3.12", + "nanoid": "^3.3.17", "picocolors": "^1.1.1", "source-map-js": "^1.2.1" }, @@ -2518,7 +2552,7 @@ }, "node_modules/semver": { "version": "7.8.5", - "resolved": "https://registry.npmmirror.com/semver/-/semver-7.8.5.tgz", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.8.5.tgz", "integrity": "sha512-Y7/KDsb8LjooZpwaqGyulO6DQlksgCncchHGk+sZIY4SBvUocMBEFH5Ur1fI4dV+Jvl0w6cjvucaIi40puRioA==", "dev": true, "license": "ISC", @@ -2530,48 +2564,48 @@ } }, "node_modules/sharp": { - "version": "0.34.5", - "resolved": "https://registry.npmmirror.com/sharp/-/sharp-0.34.5.tgz", - "integrity": "sha512-Ou9I5Ft9WNcCbXrU9cMgPBcCK8LiwLqcbywW3t4oDV37n1pzpuNLsYiAV8eODnjbtQlSDwZ2cUEeQz4E54Hltg==", + "version": "0.35.2", + "resolved": "https://registry.npmjs.org/sharp/-/sharp-0.35.2.tgz", + "integrity": "sha512-FVtFjtBCMiJS6yb5CX7Sop45WFMpeGw6oRKuJnXYgf/f1ms/D7LE/ZUSNxnW7rZ/dbslQWYkoqFHGPaDBtaK4w==", "dev": true, - "hasInstallScript": true, "license": "Apache-2.0", "dependencies": { - "@img/colour": "^1.0.0", + "@img/colour": "^1.1.0", "detect-libc": "^2.1.2", - "semver": "^7.7.3" + "semver": "^7.8.4" }, "engines": { - "node": "^18.17.0 || ^20.3.0 || >=21.0.0" + "node": ">=20.9.0" }, "funding": { "url": "https://opencollective.com/libvips" }, "optionalDependencies": { - "@img/sharp-darwin-arm64": "0.34.5", - "@img/sharp-darwin-x64": "0.34.5", - "@img/sharp-libvips-darwin-arm64": "1.2.4", - "@img/sharp-libvips-darwin-x64": "1.2.4", - "@img/sharp-libvips-linux-arm": "1.2.4", - "@img/sharp-libvips-linux-arm64": "1.2.4", - "@img/sharp-libvips-linux-ppc64": "1.2.4", - "@img/sharp-libvips-linux-riscv64": "1.2.4", - "@img/sharp-libvips-linux-s390x": "1.2.4", - "@img/sharp-libvips-linux-x64": "1.2.4", - "@img/sharp-libvips-linuxmusl-arm64": "1.2.4", - "@img/sharp-libvips-linuxmusl-x64": "1.2.4", - "@img/sharp-linux-arm": "0.34.5", - "@img/sharp-linux-arm64": "0.34.5", - "@img/sharp-linux-ppc64": "0.34.5", - "@img/sharp-linux-riscv64": "0.34.5", - "@img/sharp-linux-s390x": "0.34.5", - "@img/sharp-linux-x64": "0.34.5", - "@img/sharp-linuxmusl-arm64": "0.34.5", - "@img/sharp-linuxmusl-x64": "0.34.5", - "@img/sharp-wasm32": "0.34.5", - "@img/sharp-win32-arm64": "0.34.5", - "@img/sharp-win32-ia32": "0.34.5", - "@img/sharp-win32-x64": "0.34.5" + "@img/sharp-darwin-arm64": "0.35.2", + "@img/sharp-darwin-x64": "0.35.2", + "@img/sharp-freebsd-wasm32": "0.35.2", + "@img/sharp-libvips-darwin-arm64": "1.3.1", + "@img/sharp-libvips-darwin-x64": "1.3.1", + "@img/sharp-libvips-linux-arm": "1.3.1", + "@img/sharp-libvips-linux-arm64": "1.3.1", + "@img/sharp-libvips-linux-ppc64": "1.3.1", + "@img/sharp-libvips-linux-riscv64": "1.3.1", + "@img/sharp-libvips-linux-s390x": "1.3.1", + "@img/sharp-libvips-linux-x64": "1.3.1", + "@img/sharp-libvips-linuxmusl-arm64": "1.3.1", + "@img/sharp-libvips-linuxmusl-x64": "1.3.1", + "@img/sharp-linux-arm": "0.35.2", + "@img/sharp-linux-arm64": "0.35.2", + "@img/sharp-linux-ppc64": "0.35.2", + "@img/sharp-linux-riscv64": "0.35.2", + "@img/sharp-linux-s390x": "0.35.2", + "@img/sharp-linux-x64": "0.35.2", + "@img/sharp-linuxmusl-arm64": "0.35.2", + "@img/sharp-linuxmusl-x64": "0.35.2", + "@img/sharp-webcontainers-wasm32": "0.35.2", + "@img/sharp-win32-arm64": "0.35.2", + "@img/sharp-win32-ia32": "0.35.2", + "@img/sharp-win32-x64": "0.35.2" } }, "node_modules/siginfo": { @@ -2629,7 +2663,7 @@ }, "node_modules/supports-color": { "version": "10.2.2", - "resolved": "https://registry.npmmirror.com/supports-color/-/supports-color-10.2.2.tgz", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-10.2.2.tgz", "integrity": "sha512-SS+jx45GF1QjgEXQx4NJZV9ImqmO2NPz5FNsIHrsDjh2YsHnawpan7SNQ1o8NuhrbHZy9AZhIoCUiCeaW/C80g==", "dev": true, "license": "MIT", @@ -2745,9 +2779,9 @@ "license": "MIT" }, "node_modules/undici": { - "version": "7.28.0", - "resolved": "https://registry.npmmirror.com/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": { @@ -2870,9 +2904,9 @@ } }, "node_modules/vite/node_modules/@esbuild/aix-ppc64": { - "version": "0.27.7", - "resolved": "https://registry.npmmirror.com/@esbuild/aix-ppc64/-/aix-ppc64-0.27.7.tgz", - "integrity": "sha512-EKX3Qwmhz1eMdEJokhALr0YiD0lhQNwDqkPYyPhiSwKrh7/4KRjQc04sZ8db+5DVVnZ1LmbNDI1uAMPEUBnQPg==", + "version": "0.27.2", + "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.27.2.tgz", + "integrity": "sha512-GZMB+a0mOMZs4MpDbj8RJp4cw+w1WV5NYD6xzgvzUJ5Ek2jerwfO2eADyI6ExDSUED+1X8aMbegahsJi+8mgpw==", "cpu": [ "ppc64" ], @@ -2887,9 +2921,9 @@ } }, "node_modules/vite/node_modules/@esbuild/android-arm": { - "version": "0.27.7", - "resolved": "https://registry.npmmirror.com/@esbuild/android-arm/-/android-arm-0.27.7.tgz", - "integrity": "sha512-jbPXvB4Yj2yBV7HUfE2KHe4GJX51QplCN1pGbYjvsyCZbQmies29EoJbkEc+vYuU5o45AfQn37vZlyXy4YJ8RQ==", + "version": "0.27.2", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.27.2.tgz", + "integrity": "sha512-DVNI8jlPa7Ujbr1yjU2PfUSRtAUZPG9I1RwW4F4xFB1Imiu2on0ADiI/c3td+KmDtVKNbi+nffGDQMfcIMkwIA==", "cpu": [ "arm" ], @@ -2904,9 +2938,9 @@ } }, "node_modules/vite/node_modules/@esbuild/android-arm64": { - "version": "0.27.7", - "resolved": "https://registry.npmmirror.com/@esbuild/android-arm64/-/android-arm64-0.27.7.tgz", - "integrity": "sha512-62dPZHpIXzvChfvfLJow3q5dDtiNMkwiRzPylSCfriLvZeq0a1bWChrGx/BbUbPwOrsWKMn8idSllklzBy+dgQ==", + "version": "0.27.2", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.27.2.tgz", + "integrity": "sha512-pvz8ZZ7ot/RBphf8fv60ljmaoydPU12VuXHImtAs0XhLLw+EXBi2BLe3OYSBslR4rryHvweW5gmkKFwTiFy6KA==", "cpu": [ "arm64" ], @@ -2921,9 +2955,9 @@ } }, "node_modules/vite/node_modules/@esbuild/android-x64": { - "version": "0.27.7", - "resolved": "https://registry.npmmirror.com/@esbuild/android-x64/-/android-x64-0.27.7.tgz", - "integrity": "sha512-x5VpMODneVDb70PYV2VQOmIUUiBtY3D3mPBG8NxVk5CogneYhkR7MmM3yR/uMdITLrC1ml/NV1rj4bMJuy9MCg==", + "version": "0.27.2", + "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.27.2.tgz", + "integrity": "sha512-z8Ank4Byh4TJJOh4wpz8g2vDy75zFL0TlZlkUkEwYXuPSgX8yzep596n6mT7905kA9uHZsf/o2OJZubl2l3M7A==", "cpu": [ "x64" ], @@ -2938,9 +2972,9 @@ } }, "node_modules/vite/node_modules/@esbuild/darwin-arm64": { - "version": "0.27.7", - "resolved": "https://registry.npmmirror.com/@esbuild/darwin-arm64/-/darwin-arm64-0.27.7.tgz", - "integrity": "sha512-5lckdqeuBPlKUwvoCXIgI2D9/ABmPq3Rdp7IfL70393YgaASt7tbju3Ac+ePVi3KDH6N2RqePfHnXkaDtY9fkw==", + "version": "0.27.2", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.27.2.tgz", + "integrity": "sha512-davCD2Zc80nzDVRwXTcQP/28fiJbcOwvdolL0sOiOsbwBa72kegmVU0Wrh1MYrbuCL98Omp5dVhQFWRKR2ZAlg==", "cpu": [ "arm64" ], @@ -2955,9 +2989,9 @@ } }, "node_modules/vite/node_modules/@esbuild/darwin-x64": { - "version": "0.27.7", - "resolved": "https://registry.npmmirror.com/@esbuild/darwin-x64/-/darwin-x64-0.27.7.tgz", - "integrity": "sha512-rYnXrKcXuT7Z+WL5K980jVFdvVKhCHhUwid+dDYQpH+qu+TefcomiMAJpIiC2EM3Rjtq0sO3StMV/+3w3MyyqQ==", + "version": "0.27.2", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.27.2.tgz", + "integrity": "sha512-ZxtijOmlQCBWGwbVmwOF/UCzuGIbUkqB1faQRf5akQmxRJ1ujusWsb3CVfk/9iZKr2L5SMU5wPBi1UWbvL+VQA==", "cpu": [ "x64" ], @@ -2972,9 +3006,9 @@ } }, "node_modules/vite/node_modules/@esbuild/freebsd-arm64": { - "version": "0.27.7", - "resolved": "https://registry.npmmirror.com/@esbuild/freebsd-arm64/-/freebsd-arm64-0.27.7.tgz", - "integrity": "sha512-B48PqeCsEgOtzME2GbNM2roU29AMTuOIN91dsMO30t+Ydis3z/3Ngoj5hhnsOSSwNzS+6JppqWsuhTp6E82l2w==", + "version": "0.27.2", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.27.2.tgz", + "integrity": "sha512-lS/9CN+rgqQ9czogxlMcBMGd+l8Q3Nj1MFQwBZJyoEKI50XGxwuzznYdwcav6lpOGv5BqaZXqvBSiB/kJ5op+g==", "cpu": [ "arm64" ], @@ -2989,9 +3023,9 @@ } }, "node_modules/vite/node_modules/@esbuild/freebsd-x64": { - "version": "0.27.7", - "resolved": "https://registry.npmmirror.com/@esbuild/freebsd-x64/-/freebsd-x64-0.27.7.tgz", - "integrity": "sha512-jOBDK5XEjA4m5IJK3bpAQF9/Lelu/Z9ZcdhTRLf4cajlB+8VEhFFRjWgfy3M1O4rO2GQ/b2dLwCUGpiF/eATNQ==", + "version": "0.27.2", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.27.2.tgz", + "integrity": "sha512-tAfqtNYb4YgPnJlEFu4c212HYjQWSO/w/h/lQaBK7RbwGIkBOuNKQI9tqWzx7Wtp7bTPaGC6MJvWI608P3wXYA==", "cpu": [ "x64" ], @@ -3006,9 +3040,9 @@ } }, "node_modules/vite/node_modules/@esbuild/linux-arm": { - "version": "0.27.7", - "resolved": "https://registry.npmmirror.com/@esbuild/linux-arm/-/linux-arm-0.27.7.tgz", - "integrity": "sha512-RkT/YXYBTSULo3+af8Ib0ykH8u2MBh57o7q/DAs3lTJlyVQkgQvlrPTnjIzzRPQyavxtPtfg0EopvDyIt0j1rA==", + "version": "0.27.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.27.2.tgz", + "integrity": "sha512-vWfq4GaIMP9AIe4yj1ZUW18RDhx6EPQKjwe7n8BbIecFtCQG4CfHGaHuh7fdfq+y3LIA2vGS/o9ZBGVxIDi9hw==", "cpu": [ "arm" ], @@ -3023,9 +3057,9 @@ } }, "node_modules/vite/node_modules/@esbuild/linux-arm64": { - "version": "0.27.7", - "resolved": "https://registry.npmmirror.com/@esbuild/linux-arm64/-/linux-arm64-0.27.7.tgz", - "integrity": "sha512-RZPHBoxXuNnPQO9rvjh5jdkRmVizktkT7TCDkDmQ0W2SwHInKCAV95GRuvdSvA7w4VMwfCjUiPwDi0ZO6Nfe9A==", + "version": "0.27.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.27.2.tgz", + "integrity": "sha512-hYxN8pr66NsCCiRFkHUAsxylNOcAQaxSSkHMMjcpx0si13t1LHFphxJZUiGwojB1a/Hd5OiPIqDdXONia6bhTw==", "cpu": [ "arm64" ], @@ -3040,9 +3074,9 @@ } }, "node_modules/vite/node_modules/@esbuild/linux-ia32": { - "version": "0.27.7", - "resolved": "https://registry.npmmirror.com/@esbuild/linux-ia32/-/linux-ia32-0.27.7.tgz", - "integrity": "sha512-GA48aKNkyQDbd3KtkplYWT102C5sn/EZTY4XROkxONgruHPU72l+gW+FfF8tf2cFjeHaRbWpOYa/uRBz/Xq1Pg==", + "version": "0.27.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.27.2.tgz", + "integrity": "sha512-MJt5BRRSScPDwG2hLelYhAAKh9imjHK5+NE/tvnRLbIqUWa+0E9N4WNMjmp/kXXPHZGqPLxggwVhz7QP8CTR8w==", "cpu": [ "ia32" ], @@ -3057,9 +3091,9 @@ } }, "node_modules/vite/node_modules/@esbuild/linux-loong64": { - "version": "0.27.7", - "resolved": "https://registry.npmmirror.com/@esbuild/linux-loong64/-/linux-loong64-0.27.7.tgz", - "integrity": "sha512-a4POruNM2oWsD4WKvBSEKGIiWQF8fZOAsycHOt6JBpZ+JN2n2JH9WAv56SOyu9X5IqAjqSIPTaJkqN8F7XOQ5Q==", + "version": "0.27.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.27.2.tgz", + "integrity": "sha512-lugyF1atnAT463aO6KPshVCJK5NgRnU4yb3FUumyVz+cGvZbontBgzeGFO1nF+dPueHD367a2ZXe1NtUkAjOtg==", "cpu": [ "loong64" ], @@ -3074,9 +3108,9 @@ } }, "node_modules/vite/node_modules/@esbuild/linux-mips64el": { - "version": "0.27.7", - "resolved": "https://registry.npmmirror.com/@esbuild/linux-mips64el/-/linux-mips64el-0.27.7.tgz", - "integrity": "sha512-KabT5I6StirGfIz0FMgl1I+R1H73Gp0ofL9A3nG3i/cYFJzKHhouBV5VWK1CSgKvVaG4q1RNpCTR2LuTVB3fIw==", + "version": "0.27.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.27.2.tgz", + "integrity": "sha512-nlP2I6ArEBewvJ2gjrrkESEZkB5mIoaTswuqNFRv/WYd+ATtUpe9Y09RnJvgvdag7he0OWgEZWhviS1OTOKixw==", "cpu": [ "mips64el" ], @@ -3091,9 +3125,9 @@ } }, "node_modules/vite/node_modules/@esbuild/linux-ppc64": { - "version": "0.27.7", - "resolved": "https://registry.npmmirror.com/@esbuild/linux-ppc64/-/linux-ppc64-0.27.7.tgz", - "integrity": "sha512-gRsL4x6wsGHGRqhtI+ifpN/vpOFTQtnbsupUF5R5YTAg+y/lKelYR1hXbnBdzDjGbMYjVJLJTd2OFmMewAgwlQ==", + "version": "0.27.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.27.2.tgz", + "integrity": "sha512-C92gnpey7tUQONqg1n6dKVbx3vphKtTHJaNG2Ok9lGwbZil6DrfyecMsp9CrmXGQJmZ7iiVXvvZH6Ml5hL6XdQ==", "cpu": [ "ppc64" ], @@ -3108,9 +3142,9 @@ } }, "node_modules/vite/node_modules/@esbuild/linux-riscv64": { - "version": "0.27.7", - "resolved": "https://registry.npmmirror.com/@esbuild/linux-riscv64/-/linux-riscv64-0.27.7.tgz", - "integrity": "sha512-hL25LbxO1QOngGzu2U5xeXtxXcW+/GvMN3ejANqXkxZ/opySAZMrc+9LY/WyjAan41unrR3YrmtTsUpwT66InQ==", + "version": "0.27.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.27.2.tgz", + "integrity": "sha512-B5BOmojNtUyN8AXlK0QJyvjEZkWwy/FKvakkTDCziX95AowLZKR6aCDhG7LeF7uMCXEJqwa8Bejz5LTPYm8AvA==", "cpu": [ "riscv64" ], @@ -3125,9 +3159,9 @@ } }, "node_modules/vite/node_modules/@esbuild/linux-s390x": { - "version": "0.27.7", - "resolved": "https://registry.npmmirror.com/@esbuild/linux-s390x/-/linux-s390x-0.27.7.tgz", - "integrity": "sha512-2k8go8Ycu1Kb46vEelhu1vqEP+UeRVj2zY1pSuPdgvbd5ykAw82Lrro28vXUrRmzEsUV0NzCf54yARIK8r0fdw==", + "version": "0.27.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.27.2.tgz", + "integrity": "sha512-p4bm9+wsPwup5Z8f4EpfN63qNagQ47Ua2znaqGH6bqLlmJ4bx97Y9JdqxgGZ6Y8xVTixUnEkoKSHcpRlDnNr5w==", "cpu": [ "s390x" ], @@ -3142,9 +3176,9 @@ } }, "node_modules/vite/node_modules/@esbuild/linux-x64": { - "version": "0.27.7", - "resolved": "https://registry.npmmirror.com/@esbuild/linux-x64/-/linux-x64-0.27.7.tgz", - "integrity": "sha512-hzznmADPt+OmsYzw1EE33ccA+HPdIqiCRq7cQeL1Jlq2gb1+OyWBkMCrYGBJ+sxVzve2ZJEVeePbLM2iEIZSxA==", + "version": "0.27.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.27.2.tgz", + "integrity": "sha512-uwp2Tip5aPmH+NRUwTcfLb+W32WXjpFejTIOWZFw/v7/KnpCDKG66u4DLcurQpiYTiYwQ9B7KOeMJvLCu/OvbA==", "cpu": [ "x64" ], @@ -3159,9 +3193,9 @@ } }, "node_modules/vite/node_modules/@esbuild/netbsd-arm64": { - "version": "0.27.7", - "resolved": "https://registry.npmmirror.com/@esbuild/netbsd-arm64/-/netbsd-arm64-0.27.7.tgz", - "integrity": "sha512-b6pqtrQdigZBwZxAn1UpazEisvwaIDvdbMbmrly7cDTMFnw/+3lVxxCTGOrkPVnsYIosJJXAsILG9XcQS+Yu6w==", + "version": "0.27.2", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-arm64/-/netbsd-arm64-0.27.2.tgz", + "integrity": "sha512-Kj6DiBlwXrPsCRDeRvGAUb/LNrBASrfqAIok+xB0LxK8CHqxZ037viF13ugfsIpePH93mX7xfJp97cyDuTZ3cw==", "cpu": [ "arm64" ], @@ -3176,9 +3210,9 @@ } }, "node_modules/vite/node_modules/@esbuild/netbsd-x64": { - "version": "0.27.7", - "resolved": "https://registry.npmmirror.com/@esbuild/netbsd-x64/-/netbsd-x64-0.27.7.tgz", - "integrity": "sha512-OfatkLojr6U+WN5EDYuoQhtM+1xco+/6FSzJJnuWiUw5eVcicbyK3dq5EeV/QHT1uy6GoDhGbFpprUiHUYggrw==", + "version": "0.27.2", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.27.2.tgz", + "integrity": "sha512-HwGDZ0VLVBY3Y+Nw0JexZy9o/nUAWq9MlV7cahpaXKW6TOzfVno3y3/M8Ga8u8Yr7GldLOov27xiCnqRZf0tCA==", "cpu": [ "x64" ], @@ -3193,9 +3227,9 @@ } }, "node_modules/vite/node_modules/@esbuild/openbsd-arm64": { - "version": "0.27.7", - "resolved": "https://registry.npmmirror.com/@esbuild/openbsd-arm64/-/openbsd-arm64-0.27.7.tgz", - "integrity": "sha512-AFuojMQTxAz75Fo8idVcqoQWEHIXFRbOc1TrVcFSgCZtQfSdc1RXgB3tjOn/krRHENUB4j00bfGjyl2mJrU37A==", + "version": "0.27.2", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-arm64/-/openbsd-arm64-0.27.2.tgz", + "integrity": "sha512-DNIHH2BPQ5551A7oSHD0CKbwIA/Ox7+78/AWkbS5QoRzaqlev2uFayfSxq68EkonB+IKjiuxBFoV8ESJy8bOHA==", "cpu": [ "arm64" ], @@ -3210,9 +3244,9 @@ } }, "node_modules/vite/node_modules/@esbuild/openbsd-x64": { - "version": "0.27.7", - "resolved": "https://registry.npmmirror.com/@esbuild/openbsd-x64/-/openbsd-x64-0.27.7.tgz", - "integrity": "sha512-+A1NJmfM8WNDv5CLVQYJ5PshuRm/4cI6WMZRg1by1GwPIQPCTs1GLEUHwiiQGT5zDdyLiRM/l1G0Pv54gvtKIg==", + "version": "0.27.2", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.27.2.tgz", + "integrity": "sha512-/it7w9Nb7+0KFIzjalNJVR5bOzA9Vay+yIPLVHfIQYG/j+j9VTH84aNB8ExGKPU4AzfaEvN9/V4HV+F+vo8OEg==", "cpu": [ "x64" ], @@ -3227,9 +3261,9 @@ } }, "node_modules/vite/node_modules/@esbuild/openharmony-arm64": { - "version": "0.27.7", - "resolved": "https://registry.npmmirror.com/@esbuild/openharmony-arm64/-/openharmony-arm64-0.27.7.tgz", - "integrity": "sha512-+KrvYb/C8zA9CU/g0sR6w2RBw7IGc5J2BPnc3dYc5VJxHCSF1yNMxTV5LQ7GuKteQXZtspjFbiuW5/dOj7H4Yw==", + "version": "0.27.2", + "resolved": "https://registry.npmjs.org/@esbuild/openharmony-arm64/-/openharmony-arm64-0.27.2.tgz", + "integrity": "sha512-LRBbCmiU51IXfeXk59csuX/aSaToeG7w48nMwA6049Y4J4+VbWALAuXcs+qcD04rHDuSCSRKdmY63sruDS5qag==", "cpu": [ "arm64" ], @@ -3244,9 +3278,9 @@ } }, "node_modules/vite/node_modules/@esbuild/sunos-x64": { - "version": "0.27.7", - "resolved": "https://registry.npmmirror.com/@esbuild/sunos-x64/-/sunos-x64-0.27.7.tgz", - "integrity": "sha512-ikktIhFBzQNt/QDyOL580ti9+5mL/YZeUPKU2ivGtGjdTYoqz6jObj6nOMfhASpS4GU4Q/Clh1QtxWAvcYKamA==", + "version": "0.27.2", + "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.27.2.tgz", + "integrity": "sha512-kMtx1yqJHTmqaqHPAzKCAkDaKsffmXkPHThSfRwZGyuqyIeBvf08KSsYXl+abf5HDAPMJIPnbBfXvP2ZC2TfHg==", "cpu": [ "x64" ], @@ -3261,9 +3295,9 @@ } }, "node_modules/vite/node_modules/@esbuild/win32-arm64": { - "version": "0.27.7", - "resolved": "https://registry.npmmirror.com/@esbuild/win32-arm64/-/win32-arm64-0.27.7.tgz", - "integrity": "sha512-7yRhbHvPqSpRUV7Q20VuDwbjW5kIMwTHpptuUzV+AA46kiPze5Z7qgt6CLCK3pWFrHeNfDd1VKgyP4O+ng17CA==", + "version": "0.27.2", + "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.27.2.tgz", + "integrity": "sha512-Yaf78O/B3Kkh+nKABUF++bvJv5Ijoy9AN1ww904rOXZFLWVc5OLOfL56W+C8F9xn5JQZa3UX6m+IktJnIb1Jjg==", "cpu": [ "arm64" ], @@ -3278,9 +3312,9 @@ } }, "node_modules/vite/node_modules/@esbuild/win32-ia32": { - "version": "0.27.7", - "resolved": "https://registry.npmmirror.com/@esbuild/win32-ia32/-/win32-ia32-0.27.7.tgz", - "integrity": "sha512-SmwKXe6VHIyZYbBLJrhOoCJRB/Z1tckzmgTLfFYOfpMAx63BJEaL9ExI8x7v0oAO3Zh6D/Oi1gVxEYr5oUCFhw==", + "version": "0.27.2", + "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.27.2.tgz", + "integrity": "sha512-Iuws0kxo4yusk7sw70Xa2E2imZU5HoixzxfGCdxwBdhiDgt9vX9VUCBhqcwY7/uh//78A1hMkkROMJq9l27oLQ==", "cpu": [ "ia32" ], @@ -3295,9 +3329,9 @@ } }, "node_modules/vite/node_modules/@esbuild/win32-x64": { - "version": "0.27.7", - "resolved": "https://registry.npmmirror.com/@esbuild/win32-x64/-/win32-x64-0.27.7.tgz", - "integrity": "sha512-56hiAJPhwQ1R4i+21FVF7V8kSD5zZTdHcVuRFMW0hn753vVfQN8xlx4uOPT4xoGH0Z/oVATuR82AiqSTDIpaHg==", + "version": "0.27.2", + "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.27.2.tgz", + "integrity": "sha512-sRdU18mcKf7F+YgheI/zGf5alZatMUTKj/jNS6l744f9u3WFu4v7twcUI9vu4mknF4Y9aDlblIie0IM+5xxaqQ==", "cpu": [ "x64" ], @@ -3312,9 +3346,9 @@ } }, "node_modules/vite/node_modules/esbuild": { - "version": "0.27.7", - "resolved": "https://registry.npmmirror.com/esbuild/-/esbuild-0.27.7.tgz", - "integrity": "sha512-IxpibTjyVnmrIQo5aqNpCgoACA/dTKLTlhMHihVHhdkxKyPO1uBBthumT0rdHmcsk9uMonIWS0m4FljWzILh3w==", + "version": "0.27.2", + "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.27.2.tgz", + "integrity": "sha512-HyNQImnsOC7X9PMNaCIeAm4ISCQXs5a5YasTXVliKv4uuBo1dKrG0A+uQS8M5eXjVMnLg3WgXaKvprHlFJQffw==", "dev": true, "hasInstallScript": true, "license": "MIT", @@ -3325,32 +3359,32 @@ "node": ">=18" }, "optionalDependencies": { - "@esbuild/aix-ppc64": "0.27.7", - "@esbuild/android-arm": "0.27.7", - "@esbuild/android-arm64": "0.27.7", - "@esbuild/android-x64": "0.27.7", - "@esbuild/darwin-arm64": "0.27.7", - "@esbuild/darwin-x64": "0.27.7", - "@esbuild/freebsd-arm64": "0.27.7", - "@esbuild/freebsd-x64": "0.27.7", - "@esbuild/linux-arm": "0.27.7", - "@esbuild/linux-arm64": "0.27.7", - "@esbuild/linux-ia32": "0.27.7", - "@esbuild/linux-loong64": "0.27.7", - "@esbuild/linux-mips64el": "0.27.7", - "@esbuild/linux-ppc64": "0.27.7", - "@esbuild/linux-riscv64": "0.27.7", - "@esbuild/linux-s390x": "0.27.7", - "@esbuild/linux-x64": "0.27.7", - "@esbuild/netbsd-arm64": "0.27.7", - "@esbuild/netbsd-x64": "0.27.7", - "@esbuild/openbsd-arm64": "0.27.7", - "@esbuild/openbsd-x64": "0.27.7", - "@esbuild/openharmony-arm64": "0.27.7", - "@esbuild/sunos-x64": "0.27.7", - "@esbuild/win32-arm64": "0.27.7", - "@esbuild/win32-ia32": "0.27.7", - "@esbuild/win32-x64": "0.27.7" + "@esbuild/aix-ppc64": "0.27.2", + "@esbuild/android-arm": "0.27.2", + "@esbuild/android-arm64": "0.27.2", + "@esbuild/android-x64": "0.27.2", + "@esbuild/darwin-arm64": "0.27.2", + "@esbuild/darwin-x64": "0.27.2", + "@esbuild/freebsd-arm64": "0.27.2", + "@esbuild/freebsd-x64": "0.27.2", + "@esbuild/linux-arm": "0.27.2", + "@esbuild/linux-arm64": "0.27.2", + "@esbuild/linux-ia32": "0.27.2", + "@esbuild/linux-loong64": "0.27.2", + "@esbuild/linux-mips64el": "0.27.2", + "@esbuild/linux-ppc64": "0.27.2", + "@esbuild/linux-riscv64": "0.27.2", + "@esbuild/linux-s390x": "0.27.2", + "@esbuild/linux-x64": "0.27.2", + "@esbuild/netbsd-arm64": "0.27.2", + "@esbuild/netbsd-x64": "0.27.2", + "@esbuild/openbsd-arm64": "0.27.2", + "@esbuild/openbsd-x64": "0.27.2", + "@esbuild/openharmony-arm64": "0.27.2", + "@esbuild/sunos-x64": "0.27.2", + "@esbuild/win32-arm64": "0.27.2", + "@esbuild/win32-ia32": "0.27.2", + "@esbuild/win32-x64": "0.27.2" } }, "node_modules/vitest": { @@ -3460,9 +3494,9 @@ } }, "node_modules/workerd": { - "version": "1.20260617.1", - "resolved": "https://registry.npmmirror.com/workerd/-/workerd-1.20260617.1.tgz", - "integrity": "sha512-Re5pl6pdowt3ZmWUzGlOuB7jbRIIPetgKalmo4cYmucQnVhpo7/3e4MfpekbhLi2EhZZz5EY9NWRu8zFzuEZew==", + "version": "1.20260801.1", + "resolved": "https://registry.npmjs.org/workerd/-/workerd-1.20260801.1.tgz", + "integrity": "sha512-/g9JGTyqnHtoIscpBHqKD8swE2V4StBs2i69PmLiOhH45OP95jCFICl4F1hKlgN57rqfni5LiCitttoX5OOkVA==", "dev": true, "hasInstallScript": true, "license": "Apache-2.0", @@ -3473,17 +3507,17 @@ "node": ">=16" }, "optionalDependencies": { - "@cloudflare/workerd-darwin-64": "1.20260617.1", - "@cloudflare/workerd-darwin-arm64": "1.20260617.1", - "@cloudflare/workerd-linux-64": "1.20260617.1", - "@cloudflare/workerd-linux-arm64": "1.20260617.1", - "@cloudflare/workerd-windows-64": "1.20260617.1" + "@cloudflare/workerd-darwin-64": "1.20260801.1", + "@cloudflare/workerd-darwin-arm64": "1.20260801.1", + "@cloudflare/workerd-linux-64": "1.20260801.1", + "@cloudflare/workerd-linux-arm64": "1.20260801.1", + "@cloudflare/workerd-windows-64": "1.20260801.1" } }, "node_modules/wrangler": { - "version": "4.103.0", - "resolved": "https://registry.npmmirror.com/wrangler/-/wrangler-4.103.0.tgz", - "integrity": "sha512-3Lv1P5t2xcSEkSTKtG+Lz+3JFryuU7YPLkaCUj7gNe+CJsjZJLtUwqsh1x595QBxkIbCE0GAvDx2DCJUU4+oqw==", + "version": "4.120.0", + "resolved": "https://registry.npmjs.org/wrangler/-/wrangler-4.120.0.tgz", + "integrity": "sha512-cBmu/MeaB/fPacC0JpATs4duTOCagBxrZo+vBzuTX06tLzwSyAHE1drlHUZ8rP0VqVz1fy3ReGYTiHdKkoHltg==", "dev": true, "license": "MIT OR Apache-2.0", "dependencies": { @@ -3491,10 +3525,10 @@ "@cloudflare/unenv-preset": "2.16.1", "blake3-wasm": "2.1.5", "esbuild": "0.28.1", - "miniflare": "4.20260617.1", + "miniflare": "5.20260801.1-alpha", "path-to-regexp": "6.3.0", "unenv": "2.0.0-rc.24", - "workerd": "1.20260617.1" + "workerd": "1.20260801.1" }, "bin": { "cf-wrangler": "bin/cf-wrangler.js", @@ -3508,7 +3542,7 @@ "fsevents": "2.3.3" }, "peerDependencies": { - "@cloudflare/workers-types": "^4.20260617.1" + "@cloudflare/workers-types": "^5.20260801.1" }, "peerDependenciesMeta": { "@cloudflare/workers-types": { @@ -4002,7 +4036,7 @@ }, "node_modules/ws": { "version": "8.21.0", - "resolved": "https://registry.npmmirror.com/ws/-/ws-8.21.0.tgz", + "resolved": "https://registry.npmjs.org/ws/-/ws-8.21.0.tgz", "integrity": "sha512-Vsp28b7DRcimFQvrqu2Wek3z1iYxDCWqHYB8Qsnk/S4RfaCQzPGPyBNuVjJV3cd6UiKtUtp6sNM77gWvzcCH+g==", "dev": true, "license": "MIT", @@ -4033,7 +4067,7 @@ }, "node_modules/youch": { "version": "4.1.0-beta.10", - "resolved": "https://registry.npmmirror.com/youch/-/youch-4.1.0-beta.10.tgz", + "resolved": "https://registry.npmjs.org/youch/-/youch-4.1.0-beta.10.tgz", "integrity": "sha512-rLfVLB4FgQneDr0dv1oddCVZmKjcJ6yX6mS4pU82Mq/Dt9a3cLZQ62pDBL4AUO+uVrCvtWz3ZFUL2HFAFJ/BXQ==", "dev": true, "license": "MIT", @@ -4047,7 +4081,7 @@ }, "node_modules/youch-core": { "version": "0.3.3", - "resolved": "https://registry.npmmirror.com/youch-core/-/youch-core-0.3.3.tgz", + "resolved": "https://registry.npmjs.org/youch-core/-/youch-core-0.3.3.tgz", "integrity": "sha512-ho7XuGjLaJ2hWHoK8yFnsUGy2Y5uDpqSTq1FkHLK4/oqKtyUU1AFbOOxY4IpC9f0fTLjwYbslUz0Po5BpD1wrA==", "dev": true, "license": "MIT", diff --git a/services/registry-api/package.json b/services/registry-api/package.json index ffcc14a..6a87580 100644 --- a/services/registry-api/package.json +++ b/services/registry-api/package.json @@ -22,12 +22,12 @@ "pg": "^8.13.1" }, "devDependencies": { - "@cloudflare/workers-types": "^4.20250617.0", + "@cloudflare/workers-types": "^5.20260804.1", "@types/node": "^22.20.1", - "@types/pg": "^8.11.10", + "@types/pg": "^8.20.4", "esbuild": "^0.25.12", "typescript": "^5.8.3", "vitest": "^3.2.4", - "wrangler": "^4.20.5" + "wrangler": "^4.120.0" } } diff --git a/services/registry-api/src/domain.ts b/services/registry-api/src/domain.ts index 6154c01..e237862 100644 --- a/services/registry-api/src/domain.ts +++ b/services/registry-api/src/domain.ts @@ -250,7 +250,12 @@ export function ckbBlake2bHex(input: string | Uint8Array): string { } export function base64ToBytes(value: string): Uint8Array { - const binary = atob(value); + let binary: string; + try { + binary = atob(value); + } catch { + throw new ApiError(400, "invalid_base64", "base64 content is malformed"); + } const out = new Uint8Array(binary.length); for (let i = 0; i < binary.length; i += 1) { out[i] = binary.charCodeAt(i); @@ -745,6 +750,9 @@ function validateRegistryEntry( if (requireString(published, "tag") !== `v${outer.version}`) { throw new ApiError(400, "invalid_registry_tag", "registry version tag must be v"); } + validateOptionalHttpsUrl(entry, "repository"); + validateOptionalHttpsUrl(entry, "homepage"); + validateOptionalDocumentationLocation(entry); const initialStates = initialArtifactStates(artifact); if ( published["verification_status"] !== initialStates.verification_status @@ -765,6 +773,9 @@ function validateRegistryEntry( const compatibilityProfileHash = requireString(published, "compatibility_profile_hash"); validateHash(compatibilityProfileHash, "compatibility_profile_hash", "invalid_compatibility_profile_hash"); const dependencies = assertPlainObject(published["dependencies"], "invalid_registry_dependencies"); + if (Object.keys(dependencies).length > 128) { + throw new ApiError(400, "invalid_registry_dependencies", "registry version dependencies must contain at most 128 entries"); + } for (const [dependencyName, dependencyValue] of Object.entries(dependencies)) { validatePackageIdent(dependencyName, "dependency name"); const dependency = assertPlainObject(dependencyValue, "invalid_registry_dependency"); @@ -787,6 +798,45 @@ function validateRegistryEntry( return entry as unknown as RegistryIndexEntry; } +function validateOptionalHttpsUrl(entry: Record, field: "repository" | "homepage" | "documentation"): void { + const value = entry[field]; + if (value === undefined) return; + if (typeof value !== "string" || value.length === 0 || value.length > 2_048 || value !== value.trim()) { + throw new ApiError(400, `invalid_${field}`, `registry_entry.${field} must be a non-empty HTTPS URL`); + } + let url: URL; + try { + url = new URL(value); + } catch { + throw new ApiError(400, `invalid_${field}`, `registry_entry.${field} must be a valid HTTPS URL`); + } + if (url.protocol !== "https:" || url.username !== "" || url.password !== "") { + throw new ApiError(400, `invalid_${field}`, `registry_entry.${field} must be a credential-free HTTPS URL`); + } +} + +function validateOptionalDocumentationLocation(entry: Record): void { + const value = entry["documentation"]; + if (value === undefined) return; + if (typeof value !== "string" || value.length === 0 || value.length > 2_048 || value !== value.trim()) { + throw new ApiError(400, "invalid_documentation", "registry_entry.documentation must be a non-empty HTTPS URL or package-relative path"); + } + try { + new URL(value); + validateOptionalHttpsUrl(entry, "documentation"); + return; + } catch { + // Package-relative documentation is handled below. + } + if ( + !/^[A-Za-z0-9._~/-]+$/.test(value) + || value.startsWith("/") + || value.split("/").some((segment) => segment === ".." || segment === "") + ) { + throw new ApiError(400, "invalid_documentation", "registry_entry.documentation package path must stay within the package"); + } +} + function validateArtifactProfileContract( input: unknown, artifact: ArtifactDescriptor, diff --git a/services/registry-api/src/index.ts b/services/registry-api/src/index.ts index 924ea1e..692b152 100644 --- a/services/registry-api/src/index.ts +++ b/services/registry-api/src/index.ts @@ -4476,13 +4476,13 @@ function namespaceClaimCooldownSeconds(env: Env): number { } async function requestIpHash(request: Request): Promise { - const ip = request.headers.get("cf-connecting-ip") ?? request.headers.get("x-forwarded-for"); + const ip = request.headers.get("x-registry-client-ip"); return ip ? `sha256:${await sha256Hex(ip)}` : undefined; } function requestAsn(request: Request): string | undefined { const cf = (request as Request & { cf?: { asn?: number | string } }).cf; - const asn = cf?.asn ?? request.headers.get("cf-asn"); + const asn = cf?.asn ?? request.headers.get("x-registry-client-asn"); return asn === undefined || asn === null || `${asn}`.trim() === "" ? undefined : `${asn}`.trim(); } @@ -4514,7 +4514,7 @@ function errorResponse(error: unknown, requestId: string): Response { const headers = corsHeaders(requestId); const status = error instanceof ApiError ? error.status : 500; const code = error instanceof ApiError ? error.code : "internal_error"; - const message = error instanceof Error ? error.message : "internal error"; + const message = error instanceof ApiError ? error.message : "internal error"; return json({ request_id: requestId, error: { code, message } }, status, headers); } diff --git a/services/registry-api/src/node-request-identity.ts b/services/registry-api/src/node-request-identity.ts new file mode 100644 index 0000000..b2b9b3c --- /dev/null +++ b/services/registry-api/src/node-request-identity.ts @@ -0,0 +1,14 @@ +export function trustedClientIp( + forwardedHeader: string | undefined, + socketIp: string | undefined, + trustedProxyHops: number, +): string | undefined { + const directPeer = socketIp?.trim(); + if (trustedProxyHops === 0) return directPeer || undefined; + const forwarded = forwardedHeader + ?.split(",") + .map((value) => value.trim()) + .filter(Boolean) ?? []; + const candidateIndex = forwarded.length - trustedProxyHops; + return candidateIndex >= 0 ? forwarded[candidateIndex] : directPeer || undefined; +} diff --git a/services/registry-api/src/node-server.ts b/services/registry-api/src/node-server.ts index d667100..50a143a 100644 --- a/services/registry-api/src/node-server.ts +++ b/services/registry-api/src/node-server.ts @@ -7,6 +7,7 @@ import { randomUUID } from "node:crypto"; import { createApp, type Env } from "./index"; import { FilesystemObjectStore } from "./filesystem-object-store"; import { nodeCkbRpcEnv } from "./node-runtime-env"; +import { trustedClientIp } from "./node-request-identity"; import { SqlRegistryStore } from "./sql-store"; const port = integerEnv("PORT", 8787, 1, 65_535); @@ -17,6 +18,7 @@ const maxIncomingBodyBytes = integerEnv("MAX_INCOMING_BODY_BYTES", 7 * 1024 * 10 const requireVerifierReady = process.env["REQUIRE_REGISTRY_VERIFIER_READY"] === "true"; const verifierHeartbeatPath = resolve(process.env["REGISTRY_VERIFIER_SHARED_HEARTBEAT"] ?? `${objectRoot}/.health/verifier-ready`); const verifierHeartbeatMaxAgeSeconds = integerEnv("REGISTRY_VERIFIER_HEARTBEAT_MAX_AGE_SECONDS", 120, 30, 600); +const trustedProxyHops = integerEnv("REGISTRY_TRUST_PROXY_HOPS", 0, 0, 8); await mkdir(objectRoot, { recursive: true, mode: 0o750 }); const managedObjectPrefixes = ["source-snapshots", "artifacts"].map((prefix) => resolve(objectRoot, prefix)); @@ -97,6 +99,9 @@ const server = createServer(async (request, response) => { const headers = new Headers(); for (const [name, value] of Object.entries(request.headers)) { if (value === undefined) continue; + if (["cf-connecting-ip", "cf-asn", "x-forwarded-for", "x-registry-client-ip", "x-registry-client-asn"].includes(name)) { + continue; + } if (Array.isArray(value)) { for (const item of value) headers.append(name, item); } else { @@ -104,6 +109,12 @@ const server = createServer(async (request, response) => { } } headers.set("x-request-id", requestId); + const clientIp = trustedClientIp( + firstHeader(request.headers["x-forwarded-for"]), + request.socket.remoteAddress, + trustedProxyHops, + ); + if (clientIp) headers.set("x-registry-client-ip", clientIp); const method = request.method ?? "GET"; const body = method === "GET" || method === "HEAD" ? undefined : await readIncomingBody(request, maxIncomingBodyBytes); const requestInit: RequestInit = { method, headers }; @@ -148,7 +159,7 @@ const server = createServer(async (request, response) => { server.requestTimeout = 30_000; server.headersTimeout = 15_000; server.keepAliveTimeout = 5_000; -server.listen(port, "0.0.0.0", () => log("server.started", { port, object_root: objectRoot })); +server.listen(port, "0.0.0.0", () => log("server.started", { port, object_root: objectRoot, trusted_proxy_hops: trustedProxyHops })); let maintenanceRunning = false; const runMaintenance = () => { diff --git a/services/registry-api/src/verification-worker.ts b/services/registry-api/src/verification-worker.ts index 9090c2d..0cd43d7 100644 --- a/services/registry-api/src/verification-worker.ts +++ b/services/registry-api/src/verification-worker.ts @@ -241,6 +241,12 @@ async function runBuildVerification(job: VerificationJobRecord, version: Package job.artifact.profile, ]; if (job.compatibility_profile_hash) verifierArgs.push("--compatibility-profile-hash", job.compatibility_profile_hash); + if (job.artifact.profile === "cellscript_source") { + verifierArgs.push( + "--expected-dependencies-base64", + Buffer.from(canonicalJson(published.dependencies ?? {}), "utf8").toString("base64url"), + ); + } if (published.artifact_hash) verifierArgs.push("--artifact-hash", published.artifact_hash); if (published.abi_hash) verifierArgs.push("--abi-hash", published.abi_hash); if (published.build_recipe_hash) verifierArgs.push("--build-recipe-hash", published.build_recipe_hash); diff --git a/services/registry-api/test/node-request-identity.test.ts b/services/registry-api/test/node-request-identity.test.ts new file mode 100644 index 0000000..7795f95 --- /dev/null +++ b/services/registry-api/test/node-request-identity.test.ts @@ -0,0 +1,18 @@ +import { describe, expect, it } from "vitest"; + +import { trustedClientIp } from "../src/node-request-identity"; + +describe("Node trusted-proxy identity", () => { + it("ignores forwarded identity without a configured trusted proxy", () => { + expect(trustedClientIp("198.51.100.9", "203.0.113.7", 0)).toBe("203.0.113.7"); + }); + + it("selects identity from the trusted right edge of the forwarding chain", () => { + expect(trustedClientIp("192.0.2.99, 198.51.100.9", "203.0.113.7", 1)).toBe("198.51.100.9"); + expect(trustedClientIp("192.0.2.99, 198.51.100.9", "203.0.113.7", 2)).toBe("192.0.2.99"); + }); + + it("falls back to the direct peer when the configured chain is absent", () => { + expect(trustedClientIp(undefined, "203.0.113.7", 1)).toBe("203.0.113.7"); + }); +}); diff --git a/services/registry-api/test/registry-api.test.ts b/services/registry-api/test/registry-api.test.ts index 958c379..1ca4bf1 100644 --- a/services/registry-api/test/registry-api.test.ts +++ b/services/registry-api/test/registry-api.test.ts @@ -14,6 +14,7 @@ import { PUBLISH_ACTION, PUBLISH_PROTOCOL, ApiError, + base64ToBytes, canonicalJson, capabilityKeyId, ckbBlake2bHex, @@ -53,6 +54,18 @@ const reproducerPublicKeys = { "builder-b": "p256-spki:MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEcZljLFjOhAdes8hm88phoxoMmsya3kKGRbmwjtH1eW4tWV_sn81NRL5EwkrqhjPuYxXfEbYBfuSVPMVD3at7hQ", } as const; +describe("binary input validation", () => { + it("reports malformed base64 as a stable client error", () => { + let error: unknown; + try { + base64ToBytes("%%%not-base64%%%"); + } catch (value) { + error = value; + } + expect(error).toMatchObject({ status: 400, code: "invalid_base64" }); + }); +}); + describe("Node CKB RPC environment", () => { it("forwards every bounded RPC control used by the shared API", () => { expect(nodeCkbRpcEnv({ @@ -442,6 +455,29 @@ function declareReproducibleBuild(payload: PublishPayload): void { } describe("generic artifact profile contracts", () => { + it("rejects executable and credential-bearing registry links", async () => { + for (const [field, value] of [ + ["repository", "javascript:alert(document.domain)"], + ["homepage", "https://user:secret@example.com/project"], + ["documentation", "../private/notes.md"], + ["documentation", " javascript:alert(document.domain)"], + ] as const) { + const payload = await publishPayload("cap_test"); + payload.registry_entry[field] = value; + expect(() => validatePublishPayload(payload, DEFAULT_REGISTRY_ORIGIN, now)).toThrow(`registry_entry.${field}`); + } + }); + + it("accepts HTTPS links and package-relative documentation", async () => { + const payload = await publishPayload("cap_test"); + payload.registry_entry.homepage = "https://cellscript.dev/packages/demo"; + payload.registry_entry.documentation = "docs/PROFILE.md"; + expect(validatePublishPayload(payload, DEFAULT_REGISTRY_ORIGIN, now).registry_entry).toMatchObject({ + homepage: payload.registry_entry.homepage, + documentation: payload.registry_entry.documentation, + }); + }); + it("requires a typed profile contract for non-CellScript releases", async () => { const payload = await ckbExecutablePublishPayload("cap_test"); delete payload.registry_entry.versions[0].profile_contract; @@ -533,7 +569,7 @@ async function post( return app.fetch( new Request(`https://api.registry.cellscript.dev${path}`, { method: "POST", - headers: { "content-type": "application/json", "cf-connecting-ip": "203.0.113.5", ...headers }, + headers: { "content-type": "application/json", "x-registry-client-ip": "203.0.113.5", ...headers }, body: JSON.stringify(body), }), { REGISTRY_ORIGIN: DEFAULT_REGISTRY_ORIGIN, ...env }, @@ -549,7 +585,7 @@ async function get( return app.fetch( new Request(`https://api.registry.cellscript.dev${path}`, { method: "GET", - headers: { "cf-connecting-ip": "203.0.113.5", ...headers }, + headers: { "x-registry-client-ip": "203.0.113.5", ...headers }, }), { REGISTRY_ORIGIN: DEFAULT_REGISTRY_ORIGIN, ...env }, ); @@ -2562,7 +2598,7 @@ describe("registry api", () => { ); expect(response.status).toBe(500); - expect((await response.json() as any).error.code).toBe("internal_error"); + expect((await response.json() as any).error).toEqual({ code: "internal_error", message: "internal error" }); expect(store.packageVersions.get("cellscript/demo@1.2.3")?.availability_status).toBe("active"); expect(store.auditEvents.some((event) => event.event_type === "admin.package_version.status_updated")).toBe(false); const staticEntryWrites = snapshots.filter((snapshot) => snapshot.key === "artifacts/cellscript/demo/releases/1.2.3.json"); diff --git a/services/registry-api/test/sql-registry-store.test.ts b/services/registry-api/test/sql-registry-store.test.ts index b7f55e3..5218bd4 100644 --- a/services/registry-api/test/sql-registry-store.test.ts +++ b/services/registry-api/test/sql-registry-store.test.ts @@ -43,7 +43,7 @@ describePostgres("SqlRegistryStore PostgreSQL contract", () => { .sort(); const currentCommitmentMigration = "0007_current_commitment_state.sql"; const sandboxRetentionMigration = "0008_testnet_sandbox_retention.sql"; - expect(migrationFiles.at(-1)).toBe(sandboxRetentionMigration); + expect(migrationFiles).toEqual(expect.arrayContaining([currentCommitmentMigration, sandboxRetentionMigration])); for (const file of migrationFiles.filter((item) => item < currentCommitmentMigration)) { await client.query(await readFile(new URL(`../migrations/${file}`, import.meta.url), "utf8")); @@ -105,6 +105,9 @@ describePostgres("SqlRegistryStore PostgreSQL contract", () => { )).rows[0]?.kind).toBe("on_chain_committed"); await client.query(await readFile(new URL(`../migrations/${sandboxRetentionMigration}`, import.meta.url), "utf8")); + for (const file of migrationFiles.filter((item) => item > sandboxRetentionMigration)) { + await client.query(await readFile(new URL(`../migrations/${file}`, import.meta.url), "utf8")); + } const store = new SqlRegistryStore({ connectionString: scopedConnectionString }); await client.query(` diff --git a/services/registry-verifier/src/main.rs b/services/registry-verifier/src/main.rs index 1080287..579cffd 100644 --- a/services/registry-verifier/src/main.rs +++ b/services/registry-verifier/src/main.rs @@ -25,6 +25,7 @@ struct Args { artifact_kind: String, profile: String, compatibility_profile_hash: Option, + expected_dependencies_base64: Option, artifact_hash: Option, abi_hash: Option, build_recipe_hash: Option, @@ -62,6 +63,13 @@ struct ArtifactBundleObject { content_base64: String, } +#[derive(Debug, Deserialize, PartialEq, Eq)] +#[serde(deny_unknown_fields)] +struct ExpectedDependency { + namespace: String, + version: String, +} + #[derive(Serialize)] struct FailureOutput<'a> { status: &'static str, @@ -116,6 +124,10 @@ fn verifier_error_code(error: &anyhow::Error) -> &'static str { "identity_hash_mismatch" } else if contains("CellScript package compilation failed") { "cellscript_compilation_failed" + } else if contains("dependency metadata") { + "dependency_metadata_mismatch" + } else if contains("Registry verification does not permit") { + "unsupported_dependency_source" } else if contains("artifact bundle") { "artifact_bundle_invalid" } else if contains("artifact profile contract") { @@ -172,6 +184,10 @@ fn verify_cellscript_source(args: Args, snapshot: &[u8]) -> Result Result Result<()> { + if encoded.len() > 96 * 1024 { + bail!("signed registry dependency metadata is too large"); + } + let expected_bytes = base64::engine::general_purpose::URL_SAFE_NO_PAD + .decode(encoded) + .context("signed registry dependency metadata is not valid base64url")?; + let expected: BTreeMap = + serde_json::from_slice(&expected_bytes).context("signed registry dependency metadata is not valid JSON")?; + let package_namespace = manifest.package.namespace.clone().unwrap_or_default(); + let mut actual = BTreeMap::new(); + for (name, dependency) in &manifest.dependencies { + let (namespace, version) = match dependency { + cellscript::package::Dependency::Simple(version) => (package_namespace.clone(), version.clone()), + cellscript::package::Dependency::Detailed(detail) => { + if detail.path.is_some() + || detail.git.is_some() + || detail.branch.is_some() + || detail.tag.is_some() + || detail.rev.is_some() + { + bail!("Registry verification does not permit path or Git dependencies"); + } + (detail.namespace.clone().unwrap_or_else(|| package_namespace.clone()), detail.version.clone()) + } + }; + actual.insert(name.clone(), ExpectedDependency { namespace, version }); + } + for dependency in manifest.dev_dependencies.values() { + if matches!(dependency, cellscript::package::Dependency::Detailed(detail) if detail.path.is_some() || detail.git.is_some()) { + bail!("Registry verification does not permit path or Git dev-dependencies"); + } + } + if actual != expected { + bail!("registry dependency metadata does not match the materialized Cell.toml"); + } + Ok(()) +} + fn verify_artifact_bundle(args: Args, snapshot: &[u8]) -> Result { let bundle: ArtifactBundle = serde_json::from_slice(snapshot).context("artifact bundle must be valid JSON")?; if bundle.schema != "cellscript-registry-bundle" { @@ -379,6 +434,7 @@ fn parse_args() -> Result { artifact_kind: take("--artifact-kind")?, profile: take("--profile")?, compatibility_profile_hash: values.remove("--compatibility-profile-hash"), + expected_dependencies_base64: values.remove("--expected-dependencies-base64"), artifact_hash: values.remove("--artifact-hash"), abi_hash: values.remove("--abi-hash"), build_recipe_hash: values.remove("--build-recipe-hash"), @@ -447,6 +503,47 @@ mod tests { assert_eq!(verifier_error_code(&authenticated), "snapshot_authentication_failed"); } + #[test] + fn binds_signed_dependencies_and_rejects_local_sources() { + let root = tempfile::tempdir().unwrap(); + fs::write( + root.path().join("Cell.toml"), + r#"[package] +name = "demo" +namespace = "cellscript" +version = "1.2.3" +edition = "2026" + +[dependencies] +base = { namespace = "shared", version = "2.0.0" } +"#, + ) + .unwrap(); + let manifest = cellscript::package::PackageManager::new(root.path()).read_manifest().unwrap(); + let expected = + base64::engine::general_purpose::URL_SAFE_NO_PAD.encode(br#"{"base":{"namespace":"shared","version":"2.0.0"}}"#); + verify_manifest_dependencies(&manifest, &expected).unwrap(); + + let mismatched = base64::engine::general_purpose::URL_SAFE_NO_PAD.encode(b"{}"); + assert!(verify_manifest_dependencies(&manifest, &mismatched).unwrap_err().to_string().contains("does not match")); + + fs::write( + root.path().join("Cell.toml"), + r#"[package] +name = "demo" +namespace = "cellscript" +version = "1.2.3" +edition = "2026" + +[dependencies] +base = { path = "../base", version = "2.0.0" } +"#, + ) + .unwrap(); + let local_manifest = cellscript::package::PackageManager::new(root.path()).read_manifest().unwrap(); + assert!(verify_manifest_dependencies(&local_manifest, &expected).unwrap_err().to_string().contains("does not permit path")); + } + #[test] fn verifies_generated_snapshot_with_the_real_compiler() { let source_root = tempfile::tempdir().unwrap(); @@ -511,6 +608,7 @@ action identity(value: u64) -> u64 { artifact_kind: "source_library".to_string(), profile: "cellscript_source".to_string(), compatibility_profile_hash: Some(compatibility_profile_hash.clone()), + expected_dependencies_base64: Some(base64::engine::general_purpose::URL_SAFE_NO_PAD.encode(b"{}")), artifact_hash: None, abi_hash: None, build_recipe_hash: None, @@ -718,6 +816,7 @@ action identity(value: u64) -> u64 { artifact_kind: kind.to_string(), profile: profile.to_string(), compatibility_profile_hash: None, + expected_dependencies_base64: None, artifact_hash, abi_hash, build_recipe_hash, diff --git a/src/package/registry.rs b/src/package/registry.rs index 0c178e4..8a27577 100644 --- a/src/package/registry.rs +++ b/src/package/registry.rs @@ -1307,6 +1307,7 @@ pub fn compute_source_hash(root: &Path) -> Result { let manifest_path = root.join("Cell.toml"); let mut manifest = SourceHashManifest::default(); if manifest_path.exists() { + reject_source_symlink(&manifest_path)?; let content = std::fs::read_to_string(&manifest_path)?; manifest = toml::from_str(&content) .map_err(|e| CompileError::without_span(format!("failed to parse Cell.toml for source hashing: {}", e)))?; @@ -1352,7 +1353,7 @@ fn collect_hash_source_files(root: &Path, manifest: &SourceHashManifest) -> Resu if let Some(package) = &manifest.package { for source_root in &package.source_roots { - let source_root_path = root.join(source_root); + let source_root_path = package_relative_path(root, source_root, "configured source root")?; if !source_root_path.exists() { return Err(CompileError::without_span(format!( "configured source root '{}' does not exist", @@ -1365,6 +1366,8 @@ fn collect_hash_source_files(root: &Path, manifest: &SourceHashManifest) -> Resu source_root_path.display() ))); } + ensure_source_path_confined(root, &source_root_path, "configured source root")?; + reject_source_symlink(&source_root_path)?; if seen_roots.insert(source_root_path.clone()) { roots.push(source_root_path); } @@ -1373,19 +1376,27 @@ fn collect_hash_source_files(root: &Path, manifest: &SourceHashManifest) -> Resu if roots.is_empty() { let src_dir = root.join("src"); - if src_dir.exists() && src_dir.is_dir() && seen_roots.insert(src_dir.clone()) { - roots.push(src_dir); + if src_dir.exists() && src_dir.is_dir() { + ensure_source_path_confined(root, &src_dir, "default source root")?; + reject_source_symlink(&src_dir)?; + if seen_roots.insert(src_dir.clone()) { + roots.push(src_dir); + } } } let mut explicit_entry = None; if let Some(entry) = manifest.package.as_ref().and_then(|package| package.entry.as_deref()) { - let entry_path = root.join(entry); + let entry_path = package_relative_path(root, entry, "package entry")?; if !entry_path.exists() { return Err(CompileError::without_span(format!("package entry '{}' does not exist", entry_path.display()))); } + ensure_source_path_confined(root, &entry_path, "package entry")?; + reject_source_symlink(&entry_path)?; if let Some(parent) = entry_path.parent() { let parent = parent.to_path_buf(); + ensure_source_path_confined(root, &parent, "package entry parent")?; + reject_source_symlink(&parent)?; if seen_roots.insert(parent.clone()) { roots.push(parent); } @@ -1395,7 +1406,7 @@ fn collect_hash_source_files(root: &Path, manifest: &SourceHashManifest) -> Resu let mut files = Vec::new(); for source_root in roots { - files.extend(collect_cell_files(&source_root)?); + files.extend(collect_cell_files(root, &source_root)?); } if let Some(entry_path) = explicit_entry { files.push(entry_path); @@ -1403,7 +1414,38 @@ fn collect_hash_source_files(root: &Path, manifest: &SourceHashManifest) -> Resu Ok(files) } -fn collect_cell_files(dir: &Path) -> Result> { +fn package_relative_path(root: &Path, configured: &str, label: &str) -> Result { + let relative = Path::new(configured); + if configured.is_empty() + || relative.is_absolute() + || relative.components().any(|component| !matches!(component, std::path::Component::Normal(_))) + { + return Err(CompileError::without_span(format!("{label} '{configured}' must stay within the package root"))); + } + Ok(root.join(relative)) +} + +fn ensure_source_path_confined(root: &Path, path: &Path, label: &str) -> Result<()> { + let canonical_root = std::fs::canonicalize(root) + .map_err(|e| CompileError::without_span(format!("failed to canonicalize package root '{}': {e}", root.display())))?; + let canonical_path = std::fs::canonicalize(path) + .map_err(|e| CompileError::without_span(format!("failed to canonicalize {label} '{}': {e}", path.display())))?; + if !canonical_path.starts_with(&canonical_root) { + return Err(CompileError::without_span(format!("{label} '{}' escapes the package root", path.display()))); + } + Ok(()) +} + +fn reject_source_symlink(path: &Path) -> Result<()> { + let metadata = std::fs::symlink_metadata(path) + .map_err(|e| CompileError::without_span(format!("failed to inspect source path '{}': {e}", path.display())))?; + if metadata.file_type().is_symlink() { + return Err(CompileError::without_span(format!("source hashing does not permit symbolic link '{}'", path.display()))); + } + Ok(()) +} + +fn collect_cell_files(package_root: &Path, dir: &Path) -> Result> { let mut files = Vec::new(); if !dir.exists() { return Ok(files); @@ -1413,8 +1455,10 @@ fn collect_cell_files(dir: &Path) -> Result> { for entry in entries { let entry = entry.map_err(|e| CompileError::without_span(format!("failed to read directory entry: {}", e)))?; let path = entry.path(); + ensure_source_path_confined(package_root, &path, "source path")?; + reject_source_symlink(&path)?; if path.is_dir() { - files.extend(collect_cell_files(&path)?); + files.extend(collect_cell_files(package_root, &path)?); } else if path.extension().is_some_and(|ext| ext == "cell") { files.push(path); } @@ -1725,6 +1769,33 @@ left = "a" assert_eq!(snapshots["1.2.3"].source_hash, "source-hash"); } + #[test] + fn source_hash_rejects_manifest_paths_outside_the_package() { + let root = tempfile::tempdir().unwrap(); + let package = root.path().join("package"); + let outside_sources = root.path().join("outside"); + std::fs::create_dir_all(&package).unwrap(); + std::fs::create_dir_all(&outside_sources).unwrap(); + std::fs::write(root.path().join("outside.cell"), "script Outside {}\n").unwrap(); + std::fs::write(outside_sources.join("lib.cell"), "script OutsideLib {}\n").unwrap(); + + std::fs::write(package.join("Cell.toml"), "[package]\nentry = \"../outside.cell\"\n").unwrap(); + let entry_error = compute_source_hash(&package).unwrap_err(); + assert!(entry_error.to_string().contains("must stay within the package root")); + + std::fs::write(package.join("Cell.toml"), "[package]\nsource_roots = [\"../outside\"]\n").unwrap(); + let root_error = compute_source_hash(&package).unwrap_err(); + assert!(root_error.to_string().contains("must stay within the package root")); + + std::fs::write( + package.join("Cell.toml"), + format!("[package]\nentry = {:?}\n", root.path().join("outside.cell").to_string_lossy()), + ) + .unwrap(); + let absolute_error = compute_source_hash(&package).unwrap_err(); + assert!(absolute_error.to_string().contains("must stay within the package root")); + } + #[cfg(feature = "cli")] #[test] fn generated_source_snapshot_materialization_checks_paths_and_file_hashes() { diff --git a/website b/website index abcce84..3643b2d 160000 --- a/website +++ b/website @@ -1 +1 @@ -Subproject commit abcce840996ca9f792119a493384ee705dbf72ab +Subproject commit 3643b2de670adb3e00c97edc15122ab386e9cb51 From d84e0661aaf311ea6b3516d3aa2770b9b422d6af Mon Sep 17 00:00:00 2001 From: Arthur Date: Sat, 8 Aug 2026 03:18:36 +0800 Subject: [PATCH 2/6] fix(website): align audited 0.23 submodule --- website | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/website b/website index 3643b2d..8681760 160000 --- a/website +++ b/website @@ -1 +1 @@ -Subproject commit 3643b2de670adb3e00c97edc15122ab386e9cb51 +Subproject commit 8681760a1ee4cc9b881f0509b4c7703b697df47d From bf427f75230e2ea8b60de5fec932f077ab98df4c Mon Sep 17 00:00:00 2001 From: Arthur Date: Sat, 8 Aug 2026 03:20:39 +0800 Subject: [PATCH 3/6] fix(website): include standalone CI correction --- website | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/website b/website index 8681760..c510fd0 160000 --- a/website +++ b/website @@ -1 +1 @@ -Subproject commit 8681760a1ee4cc9b881f0509b4c7703b697df47d +Subproject commit c510fd040baf6c62512b926f79cb2a2251cd17cf From af18ee3f74e941c571c1f815ab94e78ada646702 Mon Sep 17 00:00:00 2001 From: Arthur Date: Sat, 8 Aug 2026 03:23:08 +0800 Subject: [PATCH 4/6] fix(website): pin Registry source-aware CI --- website | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/website b/website index c510fd0..f3c4cb7 160000 --- a/website +++ b/website @@ -1 +1 @@ -Subproject commit c510fd040baf6c62512b926f79cb2a2251cd17cf +Subproject commit f3c4cb7b8c701b4705e2bcf7e47b909055a736d3 From ac62102987475d8f1752c0fe25133bd11d259abd Mon Sep 17 00:00:00 2001 From: Arthur Date: Sat, 8 Aug 2026 03:33:36 +0800 Subject: [PATCH 5/6] fix(tooling): accept canonical Registry route --- crates/cellscript-tools/src/tooling_release.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/crates/cellscript-tools/src/tooling_release.rs b/crates/cellscript-tools/src/tooling_release.rs index 1476462..d446993 100644 --- a/crates/cellscript-tools/src/tooling_release.rs +++ b/crates/cellscript-tools/src/tooling_release.rs @@ -428,7 +428,7 @@ pub fn run(root: &Path) -> Result<()> { "npm run check:deploy", ], )?; - require_contains(root, "website/src/pages/index.astro", &[r#"href="/registry""#, r#"data-i18n="nav.registryBrowse""#])?; + require_contains(root, "website/src/pages/index.astro", &[r#"href="/registry/""#, r#"data-i18n="nav.registryBrowse""#])?; require_contains( root, "scripts/cellscript_gate.sh", From 012107e7b2aed8a8a7cca8286813fa780f0e8443 Mon Sep 17 00:00:00 2001 From: Arthur Date: Sat, 8 Aug 2026 19:50:34 +0800 Subject: [PATCH 6/6] fix browser artifact lifecycle support --- CHANGELOG.md | 8 ++++++++ website | 2 +- 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index f8c19e4..56790aa 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,14 @@ ## Unreleased +- Complete the browser-facing package and artifact lifecycle. Playground ZIP + exports now emit a valid Edition 2026 `Cell.toml`. Artifact detail views let + readers select a release and scope status, evidence, deployments, immutable + links, and consumer commands to that exact release. Registry maintenance now + supports active/deprecated/yanked transitions, least-privilege deployment + and availability capability requests, live scope checks, and wallet-signed + capability revocation; the API page documents the corresponding public + authorisation endpoints. - Close the 0.23 Registry audit findings across admission, verification, and delivery. Publisher-controlled repository and homepage fields now require credential-free HTTPS URLs, malformed base64 is a stable client error, and diff --git a/website b/website index f3c4cb7..544ee2e 160000 --- a/website +++ b/website @@ -1 +1 @@ -Subproject commit f3c4cb7b8c701b4705e2bcf7e47b909055a736d3 +Subproject commit 544ee2ee9914200384784ce9e509136c89e730f7