From 48f9c240a26486309c1f7040950f22ead22be3ac Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 13 Apr 2026 06:43:54 +0000 Subject: [PATCH 01/37] chore(deps): bump actions/github-script from 8.0.0 to 9.0.0 Bumps [actions/github-script](https://github.com/actions/github-script) from 8.0.0 to 9.0.0. - [Release notes](https://github.com/actions/github-script/releases) - [Commits](https://github.com/actions/github-script/compare/ed597411d8f924073f98dfc5c65a23a2325f34cd...3a2844b7e9c422d3c10d287c895573f7108da1b3) --- updated-dependencies: - dependency-name: actions/github-script dependency-version: 9.0.0 dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] --- .github/workflows/beta.yml | 4 ++-- .github/workflows/nightly.yml | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/.github/workflows/beta.yml b/.github/workflows/beta.yml index 76b729bd..4aeb9a7e 100644 --- a/.github/workflows/beta.yml +++ b/.github/workflows/beta.yml @@ -38,7 +38,7 @@ jobs: - name: Compute metadata (date, short SHA) id: meta - uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8 + uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9.0.0 with: script: | const date = new Date().toISOString().slice(0, 10); @@ -89,7 +89,7 @@ jobs: run: cargo clippy --all-targets -- -D warnings - name: Remove existing 'openvcs-beta' release & tag - uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8 + uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9.0.0 with: script: | const owner = context.repo.owner; diff --git a/.github/workflows/nightly.yml b/.github/workflows/nightly.yml index a2f67423..0e229db3 100644 --- a/.github/workflows/nightly.yml +++ b/.github/workflows/nightly.yml @@ -101,7 +101,7 @@ jobs: - name: Compute metadata (date, short SHA, compare, changelog) id: meta - uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8 + uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9.0.0 with: script: | const date = new Date().toISOString().slice(0, 10); // UTC date @@ -197,7 +197,7 @@ jobs: # ---------- Reset rolling tag (optional but keeps things tidy) ---------- - name: Remove existing 'openvcs-nightly' release & tag (if any) - uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8 + uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9.0.0 with: script: | const owner = context.repo.owner; From dec09fb098db84368149fc3ea8abe63cd47438f7 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 13 Apr 2026 06:53:18 +0000 Subject: [PATCH 02/37] chore(deps)(deps): bump the npm-minor-patch group Bumps the npm-minor-patch group in /Frontend with 5 updates: | Package | From | To | | --- | --- | --- | | [overlayscrollbars](https://github.com/KingSora/OverlayScrollbars/tree/HEAD/packages/overlayscrollbars) | `2.14.0` | `2.15.1` | | [@types/node](https://github.com/DefinitelyTyped/DefinitelyTyped/tree/HEAD/types/node) | `25.5.2` | `25.6.0` | | [jsdom](https://github.com/jsdom/jsdom) | `29.0.1` | `29.0.2` | | [vite](https://github.com/vitejs/vite/tree/HEAD/packages/vite) | `8.0.5` | `8.0.8` | | [vitest](https://github.com/vitest-dev/vitest/tree/HEAD/packages/vitest) | `4.1.2` | `4.1.4` | Updates `overlayscrollbars` from 2.14.0 to 2.15.1 - [Release notes](https://github.com/KingSora/OverlayScrollbars/releases) - [Changelog](https://github.com/KingSora/OverlayScrollbars/blob/master/packages/overlayscrollbars/CHANGELOG.md) - [Commits](https://github.com/KingSora/OverlayScrollbars/commits/HEAD/packages/overlayscrollbars) Updates `@types/node` from 25.5.2 to 25.6.0 - [Release notes](https://github.com/DefinitelyTyped/DefinitelyTyped/releases) - [Commits](https://github.com/DefinitelyTyped/DefinitelyTyped/commits/HEAD/types/node) Updates `jsdom` from 29.0.1 to 29.0.2 - [Release notes](https://github.com/jsdom/jsdom/releases) - [Commits](https://github.com/jsdom/jsdom/compare/v29.0.1...v29.0.2) Updates `vite` from 8.0.5 to 8.0.8 - [Release notes](https://github.com/vitejs/vite/releases) - [Changelog](https://github.com/vitejs/vite/blob/main/packages/vite/CHANGELOG.md) - [Commits](https://github.com/vitejs/vite/commits/v8.0.8/packages/vite) Updates `vitest` from 4.1.2 to 4.1.4 - [Release notes](https://github.com/vitest-dev/vitest/releases) - [Commits](https://github.com/vitest-dev/vitest/commits/v4.1.4/packages/vitest) --- updated-dependencies: - dependency-name: overlayscrollbars dependency-version: 2.15.1 dependency-type: direct:production update-type: version-update:semver-minor dependency-group: npm-minor-patch - dependency-name: "@types/node" dependency-version: 25.6.0 dependency-type: direct:development update-type: version-update:semver-minor dependency-group: npm-minor-patch - dependency-name: jsdom dependency-version: 29.0.2 dependency-type: direct:development update-type: version-update:semver-patch dependency-group: npm-minor-patch - dependency-name: vite dependency-version: 8.0.8 dependency-type: direct:development update-type: version-update:semver-patch dependency-group: npm-minor-patch - dependency-name: vitest dependency-version: 4.1.4 dependency-type: direct:development update-type: version-update:semver-patch dependency-group: npm-minor-patch ... Signed-off-by: dependabot[bot] --- Frontend/package-lock.json | 353 +++++++++++++++++++------------------ Frontend/package.json | 10 +- 2 files changed, 184 insertions(+), 179 deletions(-) diff --git a/Frontend/package-lock.json b/Frontend/package-lock.json index 1f2889d8..b5fe5908 100644 --- a/Frontend/package-lock.json +++ b/Frontend/package-lock.json @@ -9,45 +9,43 @@ "version": "1.0.0", "license": "ISC", "dependencies": { - "overlayscrollbars": "^2.14.0" + "overlayscrollbars": "^2.15.1" }, "devDependencies": { - "@types/node": "^25.5.2", - "jsdom": "^29.0.1", + "@types/node": "^25.6.0", + "jsdom": "^29.0.2", "typescript": "^6.0.2", - "vite": "^8.0.5", - "vitest": "^4.1.2" + "vite": "^8.0.8", + "vitest": "^4.1.4" } }, "node_modules/@asamuzakjp/css-color": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/@asamuzakjp/css-color/-/css-color-5.0.1.tgz", - "integrity": "sha512-2SZFvqMyvboVV1d15lMf7XiI3m7SDqXUuKaTymJYLN6dSGadqp+fVojqJlVoMlbZnlTmu3S0TLwLTJpvBMO1Aw==", + "version": "5.1.10", + "resolved": "https://registry.npmjs.org/@asamuzakjp/css-color/-/css-color-5.1.10.tgz", + "integrity": "sha512-02OhhkKtgNRuicQ/nF3TRnGsxL9wp0r3Y7VlKWyOHHGmGyvXv03y+PnymU8FKFJMTjIr1Bk8U2g1HWSLrpAHww==", "dev": true, "license": "MIT", "dependencies": { "@csstools/css-calc": "^3.1.1", "@csstools/css-color-parser": "^4.0.2", "@csstools/css-parser-algorithms": "^4.0.0", - "@csstools/css-tokenizer": "^4.0.0", - "lru-cache": "^11.2.6" + "@csstools/css-tokenizer": "^4.0.0" }, "engines": { "node": "^20.19.0 || ^22.12.0 || >=24.0.0" } }, "node_modules/@asamuzakjp/dom-selector": { - "version": "7.0.3", - "resolved": "https://registry.npmjs.org/@asamuzakjp/dom-selector/-/dom-selector-7.0.3.tgz", - "integrity": "sha512-Q6mU0Z6bfj6YvnX2k9n0JxiIwrCFN59x/nWmYQnAqP000ruX/yV+5bp/GRcF5T8ncvfwJQ7fgfP74DlpKExILA==", + "version": "7.0.9", + "resolved": "https://registry.npmjs.org/@asamuzakjp/dom-selector/-/dom-selector-7.0.9.tgz", + "integrity": "sha512-r3ElRr7y8ucyN2KdICwGsmj19RoN13CLCa/pvGydghWK6ZzeKQ+TcDjVdtEZz2ElpndM5jXw//B9CEee0mWnVg==", "dev": true, "license": "MIT", "dependencies": { "@asamuzakjp/nwsapi": "^2.3.9", "bidi-js": "^1.0.3", "css-tree": "^3.2.1", - "is-potential-custom-element-name": "^1.0.1", - "lru-cache": "^11.2.7" + "is-potential-custom-element-name": "^1.0.1" }, "engines": { "node": "^20.19.0 || ^22.12.0 || >=24.0.0" @@ -94,9 +92,9 @@ } }, "node_modules/@csstools/css-calc": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/@csstools/css-calc/-/css-calc-3.1.1.tgz", - "integrity": "sha512-HJ26Z/vmsZQqs/o3a6bgKslXGFAungXGbinULZO3eMsOyNJHeBBZfup5FiZInOghgoM4Hwnmw+OgbJCNg1wwUQ==", + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/@csstools/css-calc/-/css-calc-3.2.0.tgz", + "integrity": "sha512-bR9e6o2BDB12jzN/gIbjHa5wLJ4UjD1CB9pM7ehlc0ddk6EBz+yYS1EV2MF55/HUxrHcB/hehAyt5vhsA3hx7w==", "dev": true, "funding": [ { @@ -118,9 +116,9 @@ } }, "node_modules/@csstools/css-color-parser": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/@csstools/css-color-parser/-/css-color-parser-4.0.2.tgz", - "integrity": "sha512-0GEfbBLmTFf0dJlpsNU7zwxRIH0/BGEMuXLTCvFYxuL1tNhqzTbtnFICyJLTNK4a+RechKP75e7w42ClXSnJQw==", + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/@csstools/css-color-parser/-/css-color-parser-4.1.0.tgz", + "integrity": "sha512-U0KhLYmy2GVj6q4T3WaAe6NPuFYCPQoE3b0dRGxejWDgcPp8TP7S5rVdM5ZrFaqu4N67X8YaPBw14dQSYx3IyQ==", "dev": true, "funding": [ { @@ -135,7 +133,7 @@ "license": "MIT", "dependencies": { "@csstools/color-helpers": "^6.0.2", - "@csstools/css-calc": "^3.1.1" + "@csstools/css-calc": "^3.2.0" }, "engines": { "node": ">=20.19.0" @@ -214,38 +212,35 @@ } }, "node_modules/@emnapi/core": { - "version": "1.9.1", - "resolved": "https://registry.npmjs.org/@emnapi/core/-/core-1.9.1.tgz", - "integrity": "sha512-mukuNALVsoix/w1BJwFzwXBN/dHeejQtuVzcDsfOEsdpCumXb/E9j8w11h5S54tT1xhifGfbbSm/ICrObRb3KA==", + "version": "1.9.2", + "resolved": "https://registry.npmjs.org/@emnapi/core/-/core-1.9.2.tgz", + "integrity": "sha512-UC+ZhH3XtczQYfOlu3lNEkdW/p4dsJ1r/bP7H8+rhao3TTTMO1ATq/4DdIi23XuGoFY+Cz0JmCbdVl0hz9jZcA==", "dev": true, "license": "MIT", "optional": true, - "peer": true, "dependencies": { - "@emnapi/wasi-threads": "1.2.0", + "@emnapi/wasi-threads": "1.2.1", "tslib": "^2.4.0" } }, "node_modules/@emnapi/runtime": { - "version": "1.9.1", - "resolved": "https://registry.npmjs.org/@emnapi/runtime/-/runtime-1.9.1.tgz", - "integrity": "sha512-VYi5+ZVLhpgK4hQ0TAjiQiZ6ol0oe4mBx7mVv7IflsiEp0OWoVsp/+f9Vc1hOhE0TtkORVrI1GvzyreqpgWtkA==", + "version": "1.9.2", + "resolved": "https://registry.npmjs.org/@emnapi/runtime/-/runtime-1.9.2.tgz", + "integrity": "sha512-3U4+MIWHImeyu1wnmVygh5WlgfYDtyf0k8AbLhMFxOipihf6nrWC4syIm/SwEeec0mNSafiiNnMJwbza/Is6Lw==", "dev": true, "license": "MIT", "optional": true, - "peer": true, "dependencies": { "tslib": "^2.4.0" } }, "node_modules/@emnapi/wasi-threads": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/@emnapi/wasi-threads/-/wasi-threads-1.2.0.tgz", - "integrity": "sha512-N10dEJNSsUx41Z6pZsXU8FjPjpBEplgH24sfkmITrBED1/U2Esum9F3lfLrMjKHHjmi557zQn7kR9R+XWXu5Rg==", + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/@emnapi/wasi-threads/-/wasi-threads-1.2.1.tgz", + "integrity": "sha512-uTII7OYF+/Mes/MrcIOYp5yOtSMLBWSIoLPpcgwipoiKbli6k322tcoFsxoIIxPDqW01SQGAgko4EzZi2BNv2w==", "dev": true, "license": "MIT", "optional": true, - "peer": true, "dependencies": { "tslib": "^2.4.0" } @@ -276,9 +271,9 @@ "license": "MIT" }, "node_modules/@napi-rs/wasm-runtime": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/@napi-rs/wasm-runtime/-/wasm-runtime-1.1.2.tgz", - "integrity": "sha512-sNXv5oLJ7ob93xkZ1XnxisYhGYXfaG9f65/ZgYuAu3qt7b3NadcOEhLvx28hv31PgX8SZJRYrAIPQilQmFpLVw==", + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/@napi-rs/wasm-runtime/-/wasm-runtime-1.1.3.tgz", + "integrity": "sha512-xK9sGVbJWYb08+mTJt3/YV24WxvxpXcXtP6B172paPZ+Ts69Re9dAr7lKwJoeIx8OoeuimEiRZ7umkiUVClmmQ==", "dev": true, "license": "MIT", "optional": true, @@ -295,9 +290,9 @@ } }, "node_modules/@oxc-project/types": { - "version": "0.122.0", - "resolved": "https://registry.npmjs.org/@oxc-project/types/-/types-0.122.0.tgz", - "integrity": "sha512-oLAl5kBpV4w69UtFZ9xqcmTi+GENWOcPF7FCrczTiBbmC0ibXxCwyvZGbO39rCVEuLGAZM84DH0pUIyyv/YJzA==", + "version": "0.124.0", + "resolved": "https://registry.npmjs.org/@oxc-project/types/-/types-0.124.0.tgz", + "integrity": "sha512-VBFWMTBvHxS11Z5Lvlr3IWgrwhMTXV+Md+EQF0Xf60+wAdsGFTBx7X7K/hP4pi8N7dcm1RvcHwDxZ16Qx8keUg==", "dev": true, "license": "MIT", "funding": { @@ -305,9 +300,9 @@ } }, "node_modules/@rolldown/binding-android-arm64": { - "version": "1.0.0-rc.12", - "resolved": "https://registry.npmjs.org/@rolldown/binding-android-arm64/-/binding-android-arm64-1.0.0-rc.12.tgz", - "integrity": "sha512-pv1y2Fv0JybcykuiiD3qBOBdz6RteYojRFY1d+b95WVuzx211CRh+ytI/+9iVyWQ6koTh5dawe4S/yRfOFjgaA==", + "version": "1.0.0-rc.15", + "resolved": "https://registry.npmjs.org/@rolldown/binding-android-arm64/-/binding-android-arm64-1.0.0-rc.15.tgz", + "integrity": "sha512-YYe6aWruPZDtHNpwu7+qAHEMbQ/yRl6atqb/AhznLTnD3UY99Q1jE7ihLSahNWkF4EqRPVC4SiR4O0UkLK02tA==", "cpu": [ "arm64" ], @@ -322,9 +317,9 @@ } }, "node_modules/@rolldown/binding-darwin-arm64": { - "version": "1.0.0-rc.12", - "resolved": "https://registry.npmjs.org/@rolldown/binding-darwin-arm64/-/binding-darwin-arm64-1.0.0-rc.12.tgz", - "integrity": "sha512-cFYr6zTG/3PXXF3pUO+umXxt1wkRK/0AYT8lDwuqvRC+LuKYWSAQAQZjCWDQpAH172ZV6ieYrNnFzVVcnSflAg==", + "version": "1.0.0-rc.15", + "resolved": "https://registry.npmjs.org/@rolldown/binding-darwin-arm64/-/binding-darwin-arm64-1.0.0-rc.15.tgz", + "integrity": "sha512-oArR/ig8wNTPYsXL+Mzhs0oxhxfuHRfG7Ikw7jXsw8mYOtk71W0OkF2VEVh699pdmzjPQsTjlD1JIOoHkLP1Fg==", "cpu": [ "arm64" ], @@ -339,9 +334,9 @@ } }, "node_modules/@rolldown/binding-darwin-x64": { - "version": "1.0.0-rc.12", - "resolved": "https://registry.npmjs.org/@rolldown/binding-darwin-x64/-/binding-darwin-x64-1.0.0-rc.12.tgz", - "integrity": "sha512-ZCsYknnHzeXYps0lGBz8JrF37GpE9bFVefrlmDrAQhOEi4IOIlcoU1+FwHEtyXGx2VkYAvhu7dyBf75EJQffBw==", + "version": "1.0.0-rc.15", + "resolved": "https://registry.npmjs.org/@rolldown/binding-darwin-x64/-/binding-darwin-x64-1.0.0-rc.15.tgz", + "integrity": "sha512-YzeVqOqjPYvUbJSWJ4EDL8ahbmsIXQpgL3JVipmN+MX0XnXMeWomLN3Fb+nwCmP/jfyqte5I3XRSm7OfQrbyxw==", "cpu": [ "x64" ], @@ -356,9 +351,9 @@ } }, "node_modules/@rolldown/binding-freebsd-x64": { - "version": "1.0.0-rc.12", - "resolved": "https://registry.npmjs.org/@rolldown/binding-freebsd-x64/-/binding-freebsd-x64-1.0.0-rc.12.tgz", - "integrity": "sha512-dMLeprcVsyJsKolRXyoTH3NL6qtsT0Y2xeuEA8WQJquWFXkEC4bcu1rLZZSnZRMtAqwtrF/Ib9Ddtpa/Gkge9Q==", + "version": "1.0.0-rc.15", + "resolved": "https://registry.npmjs.org/@rolldown/binding-freebsd-x64/-/binding-freebsd-x64-1.0.0-rc.15.tgz", + "integrity": "sha512-9Erhx956jeQ0nNTyif1+QWAXDRD38ZNjr//bSHrt6wDwB+QkAfl2q6Mn1k6OBPerznjRmbM10lgRb1Pli4xZPw==", "cpu": [ "x64" ], @@ -373,9 +368,9 @@ } }, "node_modules/@rolldown/binding-linux-arm-gnueabihf": { - "version": "1.0.0-rc.12", - "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-arm-gnueabihf/-/binding-linux-arm-gnueabihf-1.0.0-rc.12.tgz", - "integrity": "sha512-YqWjAgGC/9M1lz3GR1r1rP79nMgo3mQiiA+Hfo+pvKFK1fAJ1bCi0ZQVh8noOqNacuY1qIcfyVfP6HoyBRZ85Q==", + "version": "1.0.0-rc.15", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-arm-gnueabihf/-/binding-linux-arm-gnueabihf-1.0.0-rc.15.tgz", + "integrity": "sha512-cVwk0w8QbZJGTnP/AHQBs5yNwmpgGYStL88t4UIaqcvYJWBfS0s3oqVLZPwsPU6M0zlW4GqjP0Zq5MnAGwFeGA==", "cpu": [ "arm" ], @@ -390,9 +385,9 @@ } }, "node_modules/@rolldown/binding-linux-arm64-gnu": { - "version": "1.0.0-rc.12", - "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-arm64-gnu/-/binding-linux-arm64-gnu-1.0.0-rc.12.tgz", - "integrity": "sha512-/I5AS4cIroLpslsmzXfwbe5OmWvSsrFuEw3mwvbQ1kDxJ822hFHIx+vsN/TAzNVyepI/j/GSzrtCIwQPeKCLIg==", + "version": "1.0.0-rc.15", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-arm64-gnu/-/binding-linux-arm64-gnu-1.0.0-rc.15.tgz", + "integrity": "sha512-eBZ/u8iAK9SoHGanqe/jrPnY0JvBN6iXbVOsbO38mbz+ZJsaobExAm1Iu+rxa4S1l2FjG0qEZn4Rc6X8n+9M+w==", "cpu": [ "arm64" ], @@ -407,9 +402,9 @@ } }, "node_modules/@rolldown/binding-linux-arm64-musl": { - "version": "1.0.0-rc.12", - "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-arm64-musl/-/binding-linux-arm64-musl-1.0.0-rc.12.tgz", - "integrity": "sha512-V6/wZztnBqlx5hJQqNWwFdxIKN0m38p8Jas+VoSfgH54HSj9tKTt1dZvG6JRHcjh6D7TvrJPWFGaY9UBVOaWPw==", + "version": "1.0.0-rc.15", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-arm64-musl/-/binding-linux-arm64-musl-1.0.0-rc.15.tgz", + "integrity": "sha512-ZvRYMGrAklV9PEkgt4LQM6MjQX2P58HPAuecwYObY2DhS2t35R0I810bKi0wmaYORt6m/2Sm+Z+nFgb0WhXNcQ==", "cpu": [ "arm64" ], @@ -424,9 +419,9 @@ } }, "node_modules/@rolldown/binding-linux-ppc64-gnu": { - "version": "1.0.0-rc.12", - "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-ppc64-gnu/-/binding-linux-ppc64-gnu-1.0.0-rc.12.tgz", - "integrity": "sha512-AP3E9BpcUYliZCxa3w5Kwj9OtEVDYK6sVoUzy4vTOJsjPOgdaJZKFmN4oOlX0Wp0RPV2ETfmIra9x1xuayFB7g==", + "version": "1.0.0-rc.15", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-ppc64-gnu/-/binding-linux-ppc64-gnu-1.0.0-rc.15.tgz", + "integrity": "sha512-VDpgGBzgfg5hLg+uBpCLoFG5kVvEyafmfxGUV0UHLcL5irxAK7PKNeC2MwClgk6ZAiNhmo9FLhRYgvMmedLtnQ==", "cpu": [ "ppc64" ], @@ -441,9 +436,9 @@ } }, "node_modules/@rolldown/binding-linux-s390x-gnu": { - "version": "1.0.0-rc.12", - "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-s390x-gnu/-/binding-linux-s390x-gnu-1.0.0-rc.12.tgz", - "integrity": "sha512-nWwpvUSPkoFmZo0kQazZYOrT7J5DGOJ/+QHHzjvNlooDZED8oH82Yg67HvehPPLAg5fUff7TfWFHQS8IV1n3og==", + "version": "1.0.0-rc.15", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-s390x-gnu/-/binding-linux-s390x-gnu-1.0.0-rc.15.tgz", + "integrity": "sha512-y1uXY3qQWCzcPgRJATPSOUP4tCemh4uBdY7e3EZbVwCJTY3gLJWnQABgeUetvED+bt1FQ01OeZwvhLS2bpNrAQ==", "cpu": [ "s390x" ], @@ -458,9 +453,9 @@ } }, "node_modules/@rolldown/binding-linux-x64-gnu": { - "version": "1.0.0-rc.12", - "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-x64-gnu/-/binding-linux-x64-gnu-1.0.0-rc.12.tgz", - "integrity": "sha512-RNrafz5bcwRy+O9e6P8Z/OCAJW/A+qtBczIqVYwTs14pf4iV1/+eKEjdOUta93q2TsT/FI0XYDP3TCky38LMAg==", + "version": "1.0.0-rc.15", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-x64-gnu/-/binding-linux-x64-gnu-1.0.0-rc.15.tgz", + "integrity": "sha512-023bTPBod7J3Y/4fzAN6QtpkSABR0rigtrwaP+qSEabUh5zf6ELr9Nc7GujaROuPY3uwdSIXWrvhn1KxOvurWA==", "cpu": [ "x64" ], @@ -475,9 +470,9 @@ } }, "node_modules/@rolldown/binding-linux-x64-musl": { - "version": "1.0.0-rc.12", - "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-x64-musl/-/binding-linux-x64-musl-1.0.0-rc.12.tgz", - "integrity": "sha512-Jpw/0iwoKWx3LJ2rc1yjFrj+T7iHZn2JDg1Yny1ma0luviFS4mhAIcd1LFNxK3EYu3DHWCps0ydXQ5i/rrJ2ig==", + "version": "1.0.0-rc.15", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-x64-musl/-/binding-linux-x64-musl-1.0.0-rc.15.tgz", + "integrity": "sha512-witB2O0/hU4CgfOOKUoeFgQ4GktPi1eEbAhaLAIpgD6+ZnhcPkUtPsoKKHRzmOoWPZue46IThdSgdo4XneOLYw==", "cpu": [ "x64" ], @@ -492,9 +487,9 @@ } }, "node_modules/@rolldown/binding-openharmony-arm64": { - "version": "1.0.0-rc.12", - "resolved": "https://registry.npmjs.org/@rolldown/binding-openharmony-arm64/-/binding-openharmony-arm64-1.0.0-rc.12.tgz", - "integrity": "sha512-vRugONE4yMfVn0+7lUKdKvN4D5YusEiPilaoO2sgUWpCvrncvWgPMzK00ZFFJuiPgLwgFNP5eSiUlv2tfc+lpA==", + "version": "1.0.0-rc.15", + "resolved": "https://registry.npmjs.org/@rolldown/binding-openharmony-arm64/-/binding-openharmony-arm64-1.0.0-rc.15.tgz", + "integrity": "sha512-UCL68NJ0Ud5zRipXZE9dF5PmirzJE4E4BCIOOssEnM7wLDsxjc6Qb0sGDxTNRTP53I6MZpygyCpY8Aa8sPfKPg==", "cpu": [ "arm64" ], @@ -509,9 +504,9 @@ } }, "node_modules/@rolldown/binding-wasm32-wasi": { - "version": "1.0.0-rc.12", - "resolved": "https://registry.npmjs.org/@rolldown/binding-wasm32-wasi/-/binding-wasm32-wasi-1.0.0-rc.12.tgz", - "integrity": "sha512-ykGiLr/6kkiHc0XnBfmFJuCjr5ZYKKofkx+chJWDjitX+KsJuAmrzWhwyOMSHzPhzOHOy7u9HlFoa5MoAOJ/Zg==", + "version": "1.0.0-rc.15", + "resolved": "https://registry.npmjs.org/@rolldown/binding-wasm32-wasi/-/binding-wasm32-wasi-1.0.0-rc.15.tgz", + "integrity": "sha512-ApLruZq/ig+nhaE7OJm4lDjayUnOHVUa77zGeqnqZ9pn0ovdVbbNPerVibLXDmWeUZXjIYIT8V3xkT58Rm9u5Q==", "cpu": [ "wasm32" ], @@ -519,16 +514,18 @@ "license": "MIT", "optional": true, "dependencies": { - "@napi-rs/wasm-runtime": "^1.1.1" + "@emnapi/core": "1.9.2", + "@emnapi/runtime": "1.9.2", + "@napi-rs/wasm-runtime": "^1.1.3" }, "engines": { "node": ">=14.0.0" } }, "node_modules/@rolldown/binding-win32-arm64-msvc": { - "version": "1.0.0-rc.12", - "resolved": "https://registry.npmjs.org/@rolldown/binding-win32-arm64-msvc/-/binding-win32-arm64-msvc-1.0.0-rc.12.tgz", - "integrity": "sha512-5eOND4duWkwx1AzCxadcOrNeighiLwMInEADT0YM7xeEOOFcovWZCq8dadXgcRHSf3Ulh1kFo/qvzoFiCLOL1Q==", + "version": "1.0.0-rc.15", + "resolved": "https://registry.npmjs.org/@rolldown/binding-win32-arm64-msvc/-/binding-win32-arm64-msvc-1.0.0-rc.15.tgz", + "integrity": "sha512-KmoUoU7HnN+Si5YWJigfTws1jz1bKBYDQKdbLspz0UaqjjFkddHsqorgiW1mxcAj88lYUE6NC/zJNwT+SloqtA==", "cpu": [ "arm64" ], @@ -543,9 +540,9 @@ } }, "node_modules/@rolldown/binding-win32-x64-msvc": { - "version": "1.0.0-rc.12", - "resolved": "https://registry.npmjs.org/@rolldown/binding-win32-x64-msvc/-/binding-win32-x64-msvc-1.0.0-rc.12.tgz", - "integrity": "sha512-PyqoipaswDLAZtot351MLhrlrh6lcZPo2LSYE+VDxbVk24LVKAGOuE4hb8xZQmrPAuEtTZW8E6D2zc5EUZX4Lw==", + "version": "1.0.0-rc.15", + "resolved": "https://registry.npmjs.org/@rolldown/binding-win32-x64-msvc/-/binding-win32-x64-msvc-1.0.0-rc.15.tgz", + "integrity": "sha512-3P2A8L+x75qavWLe/Dll3EYBJLQmtkJN8rfh+U/eR3MqMgL/h98PhYI+JFfXuDPgPeCB7iZAKiqii5vqOvnA0g==", "cpu": [ "x64" ], @@ -560,9 +557,9 @@ } }, "node_modules/@rolldown/pluginutils": { - "version": "1.0.0-rc.12", - "resolved": "https://registry.npmjs.org/@rolldown/pluginutils/-/pluginutils-1.0.0-rc.12.tgz", - "integrity": "sha512-HHMwmarRKvoFsJorqYlFeFRzXZqCt2ETQlEDOb9aqssrnVBB1/+xgTGtuTrIk5vzLNX1MjMtTf7W9z3tsSbrxw==", + "version": "1.0.0-rc.15", + "resolved": "https://registry.npmjs.org/@rolldown/pluginutils/-/pluginutils-1.0.0-rc.15.tgz", + "integrity": "sha512-UromN0peaE53IaBRe9W7CjrZgXl90fqGpK+mIZbA3qSTeYqg3pqpROBdIPvOG3F5ereDHNwoHBI2e50n1BDr1g==", "dev": true, "license": "MIT" }, @@ -610,26 +607,26 @@ "license": "MIT" }, "node_modules/@types/node": { - "version": "25.5.2", - "resolved": "https://registry.npmjs.org/@types/node/-/node-25.5.2.tgz", - "integrity": "sha512-tO4ZIRKNC+MDWV4qKVZe3Ql/woTnmHDr5JD8UI5hn2pwBrHEwOEMZK7WlNb5RKB6EoJ02gwmQS9OrjuFnZYdpg==", + "version": "25.6.0", + "resolved": "https://registry.npmjs.org/@types/node/-/node-25.6.0.tgz", + "integrity": "sha512-+qIYRKdNYJwY3vRCZMdJbPLJAtGjQBudzZzdzwQYkEPQd+PJGixUL5QfvCLDaULoLv+RhT3LDkwEfKaAkgSmNQ==", "dev": true, "license": "MIT", "dependencies": { - "undici-types": "~7.18.0" + "undici-types": "~7.19.0" } }, "node_modules/@vitest/expect": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/@vitest/expect/-/expect-4.1.2.tgz", - "integrity": "sha512-gbu+7B0YgUJ2nkdsRJrFFW6X7NTP44WlhiclHniUhxADQJH5Szt9mZ9hWnJPJ8YwOK5zUOSSlSvyzRf0u1DSBQ==", + "version": "4.1.4", + "resolved": "https://registry.npmjs.org/@vitest/expect/-/expect-4.1.4.tgz", + "integrity": "sha512-iPBpra+VDuXmBFI3FMKHSFXp3Gx5HfmSCE8X67Dn+bwephCnQCaB7qWK2ldHa+8ncN8hJU8VTMcxjPpyMkUjww==", "dev": true, "license": "MIT", "dependencies": { "@standard-schema/spec": "^1.1.0", "@types/chai": "^5.2.2", - "@vitest/spy": "4.1.2", - "@vitest/utils": "4.1.2", + "@vitest/spy": "4.1.4", + "@vitest/utils": "4.1.4", "chai": "^6.2.2", "tinyrainbow": "^3.1.0" }, @@ -638,13 +635,13 @@ } }, "node_modules/@vitest/mocker": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/@vitest/mocker/-/mocker-4.1.2.tgz", - "integrity": "sha512-Ize4iQtEALHDttPRCmN+FKqOl2vxTiNUhzobQFFt/BM1lRUTG7zRCLOykG/6Vo4E4hnUdfVLo5/eqKPukcWW7Q==", + "version": "4.1.4", + "resolved": "https://registry.npmjs.org/@vitest/mocker/-/mocker-4.1.4.tgz", + "integrity": "sha512-R9HTZBhW6yCSGbGQnDnH3QHfJxokKN4KB+Yvk9Q1le7eQNYwiCyKxmLmurSpFy6BzJanSLuEUDrD+j97Q+ZLPg==", "dev": true, "license": "MIT", "dependencies": { - "@vitest/spy": "4.1.2", + "@vitest/spy": "4.1.4", "estree-walker": "^3.0.3", "magic-string": "^0.30.21" }, @@ -665,9 +662,9 @@ } }, "node_modules/@vitest/pretty-format": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/@vitest/pretty-format/-/pretty-format-4.1.2.tgz", - "integrity": "sha512-dwQga8aejqeuB+TvXCMzSQemvV9hNEtDDpgUKDzOmNQayl2OG241PSWeJwKRH3CiC+sESrmoFd49rfnq7T4RnA==", + "version": "4.1.4", + "resolved": "https://registry.npmjs.org/@vitest/pretty-format/-/pretty-format-4.1.4.tgz", + "integrity": "sha512-ddmDHU0gjEUyEVLxtZa7xamrpIefdEETu3nZjWtHeZX4QxqJ7tRxSteHVXJOcr8jhiLoGAhkK4WJ3WqBpjx42A==", "dev": true, "license": "MIT", "dependencies": { @@ -678,13 +675,13 @@ } }, "node_modules/@vitest/runner": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/@vitest/runner/-/runner-4.1.2.tgz", - "integrity": "sha512-Gr+FQan34CdiYAwpGJmQG8PgkyFVmARK8/xSijia3eTFgVfpcpztWLuP6FttGNfPLJhaZVP/euvujeNYar36OQ==", + "version": "4.1.4", + "resolved": "https://registry.npmjs.org/@vitest/runner/-/runner-4.1.4.tgz", + "integrity": "sha512-xTp7VZ5aXP5ZJrn15UtJUWlx6qXLnGtF6jNxHepdPHpMfz/aVPx+htHtgcAL2mDXJgKhpoo2e9/hVJsIeFbytQ==", "dev": true, "license": "MIT", "dependencies": { - "@vitest/utils": "4.1.2", + "@vitest/utils": "4.1.4", "pathe": "^2.0.3" }, "funding": { @@ -692,14 +689,14 @@ } }, "node_modules/@vitest/snapshot": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/@vitest/snapshot/-/snapshot-4.1.2.tgz", - "integrity": "sha512-g7yfUmxYS4mNxk31qbOYsSt2F4m1E02LFqO53Xpzg3zKMhLAPZAjjfyl9e6z7HrW6LvUdTwAQR3HHfLjpko16A==", + "version": "4.1.4", + "resolved": "https://registry.npmjs.org/@vitest/snapshot/-/snapshot-4.1.4.tgz", + "integrity": "sha512-MCjCFgaS8aZz+m5nTcEcgk/xhWv0rEH4Yl53PPlMXOZ1/Ka2VcZU6CJ+MgYCZbcJvzGhQRjVrGQNZqkGPttIKw==", "dev": true, "license": "MIT", "dependencies": { - "@vitest/pretty-format": "4.1.2", - "@vitest/utils": "4.1.2", + "@vitest/pretty-format": "4.1.4", + "@vitest/utils": "4.1.4", "magic-string": "^0.30.21", "pathe": "^2.0.3" }, @@ -708,9 +705,9 @@ } }, "node_modules/@vitest/spy": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/@vitest/spy/-/spy-4.1.2.tgz", - "integrity": "sha512-DU4fBnbVCJGNBwVA6xSToNXrkZNSiw59H8tcuUspVMsBDBST4nfvsPsEHDHGtWRRnqBERBQu7TrTKskmjqTXKA==", + "version": "4.1.4", + "resolved": "https://registry.npmjs.org/@vitest/spy/-/spy-4.1.4.tgz", + "integrity": "sha512-XxNdAsKW7C+FLydqFJLb5KhJtl3PGCMmYwFRfhvIgxJvLSXhhVI1zM8f1qD3Zg7RCjTSzDVyct6sghs9UEgBEQ==", "dev": true, "license": "MIT", "funding": { @@ -718,13 +715,13 @@ } }, "node_modules/@vitest/utils": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/@vitest/utils/-/utils-4.1.2.tgz", - "integrity": "sha512-xw2/TiX82lQHA06cgbqRKFb5lCAy3axQ4H4SoUFhUsg+wztiet+co86IAMDtF6Vm1hc7J6j09oh/rgDn+JdKIQ==", + "version": "4.1.4", + "resolved": "https://registry.npmjs.org/@vitest/utils/-/utils-4.1.4.tgz", + "integrity": "sha512-13QMT+eysM5uVGa1rG4kegGYNp6cnQcsTc67ELFbhNLQO+vgsygtYJx2khvdt4gVQqSSpC/KT5FZZxUpP3Oatw==", "dev": true, "license": "MIT", "dependencies": { - "@vitest/pretty-format": "4.1.2", + "@vitest/pretty-format": "4.1.4", "convert-source-map": "^2.0.0", "tinyrainbow": "^3.1.0" }, @@ -908,14 +905,14 @@ "license": "MIT" }, "node_modules/jsdom": { - "version": "29.0.1", - "resolved": "https://registry.npmjs.org/jsdom/-/jsdom-29.0.1.tgz", - "integrity": "sha512-z6JOK5gRO7aMybVq/y/MlIpKh8JIi68FBKMUtKkK2KH/wMSRlCxQ682d08LB9fYXplyY/UXG8P4XXTScmdjApg==", + "version": "29.0.2", + "resolved": "https://registry.npmjs.org/jsdom/-/jsdom-29.0.2.tgz", + "integrity": "sha512-9VnGEBosc/ZpwyOsJBCQ/3I5p7Q5ngOY14a9bf5btenAORmZfDse1ZEheMiWcJ3h81+Fv7HmJFdS0szo/waF2w==", "dev": true, "license": "MIT", "dependencies": { - "@asamuzakjp/css-color": "^5.0.1", - "@asamuzakjp/dom-selector": "^7.0.3", + "@asamuzakjp/css-color": "^5.1.5", + "@asamuzakjp/dom-selector": "^7.0.6", "@bramus/specificity": "^2.4.2", "@csstools/css-syntax-patches-for-csstree": "^1.1.1", "@exodus/bytes": "^1.15.0", @@ -1210,9 +1207,9 @@ } }, "node_modules/lru-cache": { - "version": "11.2.7", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-11.2.7.tgz", - "integrity": "sha512-aY/R+aEsRelme17KGQa/1ZSIpLpNYYrhcrepKTZgE+W3WM16YMCaPwOHLHsmopZHELU0Ojin1lPVxKR0MihncA==", + "version": "11.3.3", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-11.3.3.tgz", + "integrity": "sha512-JvNw9Y81y33E+BEYPr0U7omo+U9AySnsMsEiXgwT6yqd31VQWTLNQqmT4ou5eqPFUrTfIDFta2wKhB1hyohtAQ==", "dev": true, "license": "BlueOak-1.0.0", "engines": { @@ -1267,9 +1264,9 @@ "license": "MIT" }, "node_modules/overlayscrollbars": { - "version": "2.14.0", - "resolved": "https://registry.npmjs.org/overlayscrollbars/-/overlayscrollbars-2.14.0.tgz", - "integrity": "sha512-RjV0pqc79kYhQLC3vTcLRb5GLpI1n6qh0Oua3g+bGH4EgNOJHVBGP7u0zZtxoAa0dkHlAqTTSYRb9MMmxNLjig==", + "version": "2.15.1", + "resolved": "https://registry.npmjs.org/overlayscrollbars/-/overlayscrollbars-2.15.1.tgz", + "integrity": "sha512-glX26JwjL+Tkzv0JNOWdW4VozP5dGXO+Wx8+TPrdTEJTSYT/8eJS8yXM+fewjU0nFq/JeCa+X+BqABNjC4YZSA==", "license": "MIT" }, "node_modules/parse5": { @@ -1362,14 +1359,14 @@ } }, "node_modules/rolldown": { - "version": "1.0.0-rc.12", - "resolved": "https://registry.npmjs.org/rolldown/-/rolldown-1.0.0-rc.12.tgz", - "integrity": "sha512-yP4USLIMYrwpPHEFB5JGH1uxhcslv6/hL0OyvTuY+3qlOSJvZ7ntYnoWpehBxufkgN0cvXxppuTu5hHa/zPh+A==", + "version": "1.0.0-rc.15", + "resolved": "https://registry.npmjs.org/rolldown/-/rolldown-1.0.0-rc.15.tgz", + "integrity": "sha512-Ff31guA5zT6WjnGp0SXw76X6hzGRk/OQq2hE+1lcDe+lJdHSgnSX6nK3erbONHyCbpSj9a9E+uX/OvytZoWp2g==", "dev": true, "license": "MIT", "dependencies": { - "@oxc-project/types": "=0.122.0", - "@rolldown/pluginutils": "1.0.0-rc.12" + "@oxc-project/types": "=0.124.0", + "@rolldown/pluginutils": "1.0.0-rc.15" }, "bin": { "rolldown": "bin/cli.mjs" @@ -1378,21 +1375,21 @@ "node": "^20.19.0 || >=22.12.0" }, "optionalDependencies": { - "@rolldown/binding-android-arm64": "1.0.0-rc.12", - "@rolldown/binding-darwin-arm64": "1.0.0-rc.12", - "@rolldown/binding-darwin-x64": "1.0.0-rc.12", - "@rolldown/binding-freebsd-x64": "1.0.0-rc.12", - "@rolldown/binding-linux-arm-gnueabihf": "1.0.0-rc.12", - "@rolldown/binding-linux-arm64-gnu": "1.0.0-rc.12", - "@rolldown/binding-linux-arm64-musl": "1.0.0-rc.12", - "@rolldown/binding-linux-ppc64-gnu": "1.0.0-rc.12", - "@rolldown/binding-linux-s390x-gnu": "1.0.0-rc.12", - "@rolldown/binding-linux-x64-gnu": "1.0.0-rc.12", - "@rolldown/binding-linux-x64-musl": "1.0.0-rc.12", - "@rolldown/binding-openharmony-arm64": "1.0.0-rc.12", - "@rolldown/binding-wasm32-wasi": "1.0.0-rc.12", - "@rolldown/binding-win32-arm64-msvc": "1.0.0-rc.12", - "@rolldown/binding-win32-x64-msvc": "1.0.0-rc.12" + "@rolldown/binding-android-arm64": "1.0.0-rc.15", + "@rolldown/binding-darwin-arm64": "1.0.0-rc.15", + "@rolldown/binding-darwin-x64": "1.0.0-rc.15", + "@rolldown/binding-freebsd-x64": "1.0.0-rc.15", + "@rolldown/binding-linux-arm-gnueabihf": "1.0.0-rc.15", + "@rolldown/binding-linux-arm64-gnu": "1.0.0-rc.15", + "@rolldown/binding-linux-arm64-musl": "1.0.0-rc.15", + "@rolldown/binding-linux-ppc64-gnu": "1.0.0-rc.15", + "@rolldown/binding-linux-s390x-gnu": "1.0.0-rc.15", + "@rolldown/binding-linux-x64-gnu": "1.0.0-rc.15", + "@rolldown/binding-linux-x64-musl": "1.0.0-rc.15", + "@rolldown/binding-openharmony-arm64": "1.0.0-rc.15", + "@rolldown/binding-wasm32-wasi": "1.0.0-rc.15", + "@rolldown/binding-win32-arm64-msvc": "1.0.0-rc.15", + "@rolldown/binding-win32-x64-msvc": "1.0.0-rc.15" } }, "node_modules/saxes": { @@ -1569,23 +1566,23 @@ } }, "node_modules/undici-types": { - "version": "7.18.2", - "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-7.18.2.tgz", - "integrity": "sha512-AsuCzffGHJybSaRrmr5eHr81mwJU3kjw6M+uprWvCXiNeN9SOGwQ3Jn8jb8m3Z6izVgknn1R0FTCEAP2QrLY/w==", + "version": "7.19.2", + "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-7.19.2.tgz", + "integrity": "sha512-qYVnV5OEm2AW8cJMCpdV20CDyaN3g0AjDlOGf1OW4iaDEx8MwdtChUp4zu4H0VP3nDRF/8RKWH+IPp9uW0YGZg==", "dev": true, "license": "MIT" }, "node_modules/vite": { - "version": "8.0.5", - "resolved": "https://registry.npmjs.org/vite/-/vite-8.0.5.tgz", - "integrity": "sha512-nmu43Qvq9UopTRfMx2jOYW5l16pb3iDC1JH6yMuPkpVbzK0k+L7dfsEDH4jRgYFmsg0sTAqkojoZgzLMlwHsCQ==", + "version": "8.0.8", + "resolved": "https://registry.npmjs.org/vite/-/vite-8.0.8.tgz", + "integrity": "sha512-dbU7/iLVa8KZALJyLOBOQ88nOXtNG8vxKuOT4I2mD+Ya70KPceF4IAmDsmU0h1Qsn5bPrvsY9HJstCRh3hG6Uw==", "dev": true, "license": "MIT", "dependencies": { "lightningcss": "^1.32.0", "picomatch": "^4.0.4", "postcss": "^8.5.8", - "rolldown": "1.0.0-rc.12", + "rolldown": "1.0.0-rc.15", "tinyglobby": "^0.2.15" }, "bin": { @@ -1654,19 +1651,19 @@ } }, "node_modules/vitest": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/vitest/-/vitest-4.1.2.tgz", - "integrity": "sha512-xjR1dMTVHlFLh98JE3i/f/WePqJsah4A0FK9cc8Ehp9Udk0AZk6ccpIZhh1qJ/yxVWRZ+Q54ocnD8TXmkhspGg==", + "version": "4.1.4", + "resolved": "https://registry.npmjs.org/vitest/-/vitest-4.1.4.tgz", + "integrity": "sha512-tFuJqTxKb8AvfyqMfnavXdzfy3h3sWZRWwfluGbkeR7n0HUev+FmNgZ8SDrRBTVrVCjgH5cA21qGbCffMNtWvg==", "dev": true, "license": "MIT", "dependencies": { - "@vitest/expect": "4.1.2", - "@vitest/mocker": "4.1.2", - "@vitest/pretty-format": "4.1.2", - "@vitest/runner": "4.1.2", - "@vitest/snapshot": "4.1.2", - "@vitest/spy": "4.1.2", - "@vitest/utils": "4.1.2", + "@vitest/expect": "4.1.4", + "@vitest/mocker": "4.1.4", + "@vitest/pretty-format": "4.1.4", + "@vitest/runner": "4.1.4", + "@vitest/snapshot": "4.1.4", + "@vitest/spy": "4.1.4", + "@vitest/utils": "4.1.4", "es-module-lexer": "^2.0.0", "expect-type": "^1.3.0", "magic-string": "^0.30.21", @@ -1694,10 +1691,12 @@ "@edge-runtime/vm": "*", "@opentelemetry/api": "^1.9.0", "@types/node": "^20.0.0 || ^22.0.0 || >=24.0.0", - "@vitest/browser-playwright": "4.1.2", - "@vitest/browser-preview": "4.1.2", - "@vitest/browser-webdriverio": "4.1.2", - "@vitest/ui": "4.1.2", + "@vitest/browser-playwright": "4.1.4", + "@vitest/browser-preview": "4.1.4", + "@vitest/browser-webdriverio": "4.1.4", + "@vitest/coverage-istanbul": "4.1.4", + "@vitest/coverage-v8": "4.1.4", + "@vitest/ui": "4.1.4", "happy-dom": "*", "jsdom": "*", "vite": "^6.0.0 || ^7.0.0 || ^8.0.0" @@ -1721,6 +1720,12 @@ "@vitest/browser-webdriverio": { "optional": true }, + "@vitest/coverage-istanbul": { + "optional": true + }, + "@vitest/coverage-v8": { + "optional": true + }, "@vitest/ui": { "optional": true }, diff --git a/Frontend/package.json b/Frontend/package.json index 8a7aa0b8..3b5048d0 100644 --- a/Frontend/package.json +++ b/Frontend/package.json @@ -6,7 +6,7 @@ "author": "Jordon Brooks", "license": "ISC", "dependencies": { - "overlayscrollbars": "^2.14.0" + "overlayscrollbars": "^2.15.1" }, "scripts": { "dev": "vite", @@ -16,10 +16,10 @@ "preview": "vite preview --strictPort --port 1420" }, "devDependencies": { - "@types/node": "^25.5.2", - "jsdom": "^29.0.1", + "@types/node": "^25.6.0", + "jsdom": "^29.0.2", "typescript": "^6.0.2", - "vite": "^8.0.5", - "vitest": "^4.1.2" + "vite": "^8.0.8", + "vitest": "^4.1.4" } } From 4c7b3a36ece6e3dea349609e47608e66eecafea2 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 13 Apr 2026 07:13:38 +0000 Subject: [PATCH 03/37] chore(deps): bump the cargo-minor-patch group with 2 updates Bumps the cargo-minor-patch group with 2 updates: [tokio](https://github.com/tokio-rs/tokio) and [zip](https://github.com/zip-rs/zip2). Updates `tokio` from 1.51.0 to 1.51.1 - [Release notes](https://github.com/tokio-rs/tokio/releases) - [Commits](https://github.com/tokio-rs/tokio/compare/tokio-1.51.0...tokio-1.51.1) Updates `zip` from 8.5.0 to 8.5.1 - [Release notes](https://github.com/zip-rs/zip2/releases) - [Changelog](https://github.com/zip-rs/zip2/blob/master/CHANGELOG.md) - [Commits](https://github.com/zip-rs/zip2/compare/v8.5.0...v8.5.1) --- updated-dependencies: - dependency-name: tokio dependency-version: 1.51.1 dependency-type: direct:production update-type: version-update:semver-patch dependency-group: cargo-minor-patch - dependency-name: zip dependency-version: 8.5.1 dependency-type: direct:production update-type: version-update:semver-patch dependency-group: cargo-minor-patch ... Signed-off-by: dependabot[bot] --- Cargo.lock | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index d63ec839..36c2ecb6 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2792,7 +2792,7 @@ dependencies = [ "time", "tokio", "toml 1.1.0+spec-1.1.0", - "zip 8.5.0", + "zip 8.5.1", ] [[package]] @@ -4777,9 +4777,9 @@ dependencies = [ [[package]] name = "tokio" -version = "1.51.0" +version = "1.51.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2bd1c4c0fc4a7ab90fc15ef6daaa3ec3b893f004f915f2392557ed23237820cd" +checksum = "f66bf9585cda4b724d3e78ab34b73fb2bbaba9011b9bfdf69dc836382ea13b8c" dependencies = [ "bytes", "libc", @@ -6302,9 +6302,9 @@ dependencies = [ [[package]] name = "zip" -version = "8.5.0" +version = "8.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2726508a48f38dceb22b35ecbbd2430efe34ff05c62bd3285f965d7911b33464" +checksum = "dcab981e19633ebcf0b001ddd37dd802996098bc1864f90b7c5d970ce76c1d59" dependencies = [ "aes", "bzip2", From 107331779e78b5e3c419d83bbe3c56a5516d5708 Mon Sep 17 00:00:00 2001 From: Jordon Date: Fri, 17 Apr 2026 19:48:13 +0100 Subject: [PATCH 04/37] Update package-lock.json --- .opencode/package-lock.json | 281 ++++++++++++++++++++++++++++++++++-- 1 file changed, 271 insertions(+), 10 deletions(-) diff --git a/.opencode/package-lock.json b/.opencode/package-lock.json index 6aa38cb4..ae941df7 100644 --- a/.opencode/package-lock.json +++ b/.opencode/package-lock.json @@ -5,21 +5,100 @@ "packages": { "": { "dependencies": { - "@opencode-ai/plugin": "1.3.15" + "@opencode-ai/plugin": "1.4.9" } }, + "node_modules/@msgpackr-extract/msgpackr-extract-darwin-arm64": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/@msgpackr-extract/msgpackr-extract-darwin-arm64/-/msgpackr-extract-darwin-arm64-3.0.3.tgz", + "integrity": "sha512-QZHtlVgbAdy2zAqNA9Gu1UpIuI8Xvsd1v8ic6B2pZmeFnFcMWiPLfWXh7TVw4eGEZ/C9TH281KwhVoeQUKbyjw==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ] + }, + "node_modules/@msgpackr-extract/msgpackr-extract-darwin-x64": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/@msgpackr-extract/msgpackr-extract-darwin-x64/-/msgpackr-extract-darwin-x64-3.0.3.tgz", + "integrity": "sha512-mdzd3AVzYKuUmiWOQ8GNhl64/IoFGol569zNRdkLReh6LRLHOXxU4U8eq0JwaD8iFHdVGqSy4IjFL4reoWCDFw==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ] + }, + "node_modules/@msgpackr-extract/msgpackr-extract-linux-arm": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/@msgpackr-extract/msgpackr-extract-linux-arm/-/msgpackr-extract-linux-arm-3.0.3.tgz", + "integrity": "sha512-fg0uy/dG/nZEXfYilKoRe7yALaNmHoYeIoJuJ7KJ+YyU2bvY8vPv27f7UKhGRpY6euFYqEVhxCFZgAUNQBM3nw==", + "cpu": [ + "arm" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@msgpackr-extract/msgpackr-extract-linux-arm64": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/@msgpackr-extract/msgpackr-extract-linux-arm64/-/msgpackr-extract-linux-arm64-3.0.3.tgz", + "integrity": "sha512-YxQL+ax0XqBJDZiKimS2XQaf+2wDGVa1enVRGzEvLLVFeqa5kx2bWbtcSXgsxjQB7nRqqIGFIcLteF/sHeVtQg==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@msgpackr-extract/msgpackr-extract-linux-x64": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/@msgpackr-extract/msgpackr-extract-linux-x64/-/msgpackr-extract-linux-x64-3.0.3.tgz", + "integrity": "sha512-cvwNfbP07pKUfq1uH+S6KJ7dT9K8WOE4ZiAcsrSes+UY55E/0jLYc+vq+DO7jlmqRb5zAggExKm0H7O/CBaesg==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@msgpackr-extract/msgpackr-extract-win32-x64": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/@msgpackr-extract/msgpackr-extract-win32-x64/-/msgpackr-extract-win32-x64-3.0.3.tgz", + "integrity": "sha512-x0fWaQtYp4E6sktbsdAqnehxDgEc/VwM7uLsRCYWaiGu0ykYdZPiS8zCWdnjHwyiumousxfBm4SO31eXqwEZhQ==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, "node_modules/@opencode-ai/plugin": { - "version": "1.3.15", - "resolved": "https://registry.npmjs.org/@opencode-ai/plugin/-/plugin-1.3.15.tgz", - "integrity": "sha512-jZJbuvUXc5Limz8pacQl+ffATjjKGlq+xaA4wTUeW+/spwOf7Yr5Ryyvan8eNlYM8wy6h5SLfznl1rlFpjYC8w==", + "version": "1.4.9", + "resolved": "https://registry.npmjs.org/@opencode-ai/plugin/-/plugin-1.4.9.tgz", + "integrity": "sha512-tUtPbPs5xP9wonwuz5d/2y8QTrqFR8HOtAVTXvZ6iG26NJfW0dnnw9oTusVOayEIemd5abytCESm7X9ZZOMftQ==", "license": "MIT", "dependencies": { - "@opencode-ai/sdk": "1.3.15", + "@opencode-ai/sdk": "1.4.9", + "effect": "4.0.0-beta.48", "zod": "4.1.8" }, "peerDependencies": { - "@opentui/core": ">=0.1.96", - "@opentui/solid": ">=0.1.96" + "@opentui/core": ">=0.1.100", + "@opentui/solid": ">=0.1.100" }, "peerDependenciesMeta": { "@opentui/core": { @@ -31,14 +110,20 @@ } }, "node_modules/@opencode-ai/sdk": { - "version": "1.3.15", - "resolved": "https://registry.npmjs.org/@opencode-ai/sdk/-/sdk-1.3.15.tgz", - "integrity": "sha512-Uk59C7wsK20wpdr277yx7Xz7TqG5jGqlZUpSW3wDH/7a2K2iBg0lXc2wskHuCXLRXMhXpPZtb4a3SOpPENkkbg==", + "version": "1.4.9", + "resolved": "https://registry.npmjs.org/@opencode-ai/sdk/-/sdk-1.4.9.tgz", + "integrity": "sha512-S8WQLuBFu2WwvSc1wupsV4qskniBA+JN1VaZZs52BPWwiN2zQFTD5/6dMh6oiYOMDtPjKsTFZ6qLFxDvVPNggQ==", "license": "MIT", "dependencies": { "cross-spawn": "7.0.6" } }, + "node_modules/@standard-schema/spec": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@standard-schema/spec/-/spec-1.1.0.tgz", + "integrity": "sha512-l2aFy5jALhniG5HgqrD6jXLi/rUWrKvqN/qJx6yoJsgKhblVd+iqqU4RCXavm/jPityDo5TCvKMnpjKnOriy0w==", + "license": "MIT" + }, "node_modules/cross-spawn": { "version": "7.0.6", "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.6.tgz", @@ -53,12 +138,135 @@ "node": ">= 8" } }, + "node_modules/detect-libc": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-2.1.2.tgz", + "integrity": "sha512-Btj2BOOO83o3WyH59e8MgXsxEQVcarkUOpEYrubB0urwnN10yQ364rsiByU11nZlqWYZm05i/of7io4mzihBtQ==", + "license": "Apache-2.0", + "optional": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/effect": { + "version": "4.0.0-beta.48", + "resolved": "https://registry.npmjs.org/effect/-/effect-4.0.0-beta.48.tgz", + "integrity": "sha512-MMAM/ZabuNdNmgXiin+BAanQXK7qM8mlt7nfXDoJ/Gn9V8i89JlCq+2N0AiWmqFLXjGLA0u3FjiOjSOYQk5uMw==", + "license": "MIT", + "dependencies": { + "@standard-schema/spec": "^1.1.0", + "fast-check": "^4.6.0", + "find-my-way-ts": "^0.1.6", + "ini": "^6.0.0", + "kubernetes-types": "^1.30.0", + "msgpackr": "^1.11.9", + "multipasta": "^0.2.7", + "toml": "^4.1.1", + "uuid": "^13.0.0", + "yaml": "^2.8.3" + } + }, + "node_modules/fast-check": { + "version": "4.7.0", + "resolved": "https://registry.npmjs.org/fast-check/-/fast-check-4.7.0.tgz", + "integrity": "sha512-NsZRtqvSSoCP0HbNjUD+r1JH8zqZalyp6gLY9e7OYs7NK9b6AHOs2baBFeBG7bVNsuoukh89x2Yg3rPsul8ziQ==", + "funding": [ + { + "type": "individual", + "url": "https://github.com/sponsors/dubzzz" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/fast-check" + } + ], + "license": "MIT", + "dependencies": { + "pure-rand": "^8.0.0" + }, + "engines": { + "node": ">=12.17.0" + } + }, + "node_modules/find-my-way-ts": { + "version": "0.1.6", + "resolved": "https://registry.npmjs.org/find-my-way-ts/-/find-my-way-ts-0.1.6.tgz", + "integrity": "sha512-a85L9ZoXtNAey3Y6Z+eBWW658kO/MwR7zIafkIUPUMf3isZG0NCs2pjW2wtjxAKuJPxMAsHUIP4ZPGv0o5gyTA==", + "license": "MIT" + }, + "node_modules/ini": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/ini/-/ini-6.0.0.tgz", + "integrity": "sha512-IBTdIkzZNOpqm7q3dRqJvMaldXjDHWkEDfrwGEQTs5eaQMWV+djAhR+wahyNNMAa+qpbDUhBMVt4ZKNwpPm7xQ==", + "license": "ISC", + "engines": { + "node": "^20.17.0 || >=22.9.0" + } + }, "node_modules/isexe": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==", "license": "ISC" }, + "node_modules/kubernetes-types": { + "version": "1.30.0", + "resolved": "https://registry.npmjs.org/kubernetes-types/-/kubernetes-types-1.30.0.tgz", + "integrity": "sha512-Dew1okvhM/SQcIa2rcgujNndZwU8VnSapDgdxlYoB84ZlpAD43U6KLAFqYo17ykSFGHNPrg0qry0bP+GJd9v7Q==", + "license": "Apache-2.0" + }, + "node_modules/msgpackr": { + "version": "1.11.9", + "resolved": "https://registry.npmjs.org/msgpackr/-/msgpackr-1.11.9.tgz", + "integrity": "sha512-FkoAAyyA6HM8wL882EcEyFZ9s7hVADSwG9xrVx3dxxNQAtgADTrJoEWivID82Iv1zWDsv/OtbrrcZAzGzOMdNw==", + "license": "MIT", + "optionalDependencies": { + "msgpackr-extract": "^3.0.2" + } + }, + "node_modules/msgpackr-extract": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/msgpackr-extract/-/msgpackr-extract-3.0.3.tgz", + "integrity": "sha512-P0efT1C9jIdVRefqjzOQ9Xml57zpOXnIuS+csaB4MdZbTdmGDLo8XhzBG1N7aO11gKDDkJvBLULeFTo46wwreA==", + "hasInstallScript": true, + "license": "MIT", + "optional": true, + "dependencies": { + "node-gyp-build-optional-packages": "5.2.2" + }, + "bin": { + "download-msgpackr-prebuilds": "bin/download-prebuilds.js" + }, + "optionalDependencies": { + "@msgpackr-extract/msgpackr-extract-darwin-arm64": "3.0.3", + "@msgpackr-extract/msgpackr-extract-darwin-x64": "3.0.3", + "@msgpackr-extract/msgpackr-extract-linux-arm": "3.0.3", + "@msgpackr-extract/msgpackr-extract-linux-arm64": "3.0.3", + "@msgpackr-extract/msgpackr-extract-linux-x64": "3.0.3", + "@msgpackr-extract/msgpackr-extract-win32-x64": "3.0.3" + } + }, + "node_modules/multipasta": { + "version": "0.2.7", + "resolved": "https://registry.npmjs.org/multipasta/-/multipasta-0.2.7.tgz", + "integrity": "sha512-KPA58d68KgGil15oDqXjkUBEBYc00XvbPj5/X+dyzeo/lWm9Nc25pQRlf1D+gv4OpK7NM0J1odrbu9JNNGvynA==", + "license": "MIT" + }, + "node_modules/node-gyp-build-optional-packages": { + "version": "5.2.2", + "resolved": "https://registry.npmjs.org/node-gyp-build-optional-packages/-/node-gyp-build-optional-packages-5.2.2.tgz", + "integrity": "sha512-s+w+rBWnpTMwSFbaE0UXsRlg7hU4FjekKU4eyAih5T8nJuNZT1nNsskXpxmeqSK9UzkBl6UgRlnKc8hz8IEqOw==", + "license": "MIT", + "optional": true, + "dependencies": { + "detect-libc": "^2.0.1" + }, + "bin": { + "node-gyp-build-optional-packages": "bin.js", + "node-gyp-build-optional-packages-optional": "optional.js", + "node-gyp-build-optional-packages-test": "build-test.js" + } + }, "node_modules/path-key": { "version": "3.1.1", "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", @@ -68,6 +276,22 @@ "node": ">=8" } }, + "node_modules/pure-rand": { + "version": "8.4.0", + "resolved": "https://registry.npmjs.org/pure-rand/-/pure-rand-8.4.0.tgz", + "integrity": "sha512-IoM8YF/jY0hiugFo/wOWqfmarlE6J0wc6fDK1PhftMk7MGhVZl88sZimmqBBFomLOCSmcCCpsfj7wXASCpvK9A==", + "funding": [ + { + "type": "individual", + "url": "https://github.com/sponsors/dubzzz" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/fast-check" + } + ], + "license": "MIT" + }, "node_modules/shebang-command": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", @@ -89,6 +313,28 @@ "node": ">=8" } }, + "node_modules/toml": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/toml/-/toml-4.1.1.tgz", + "integrity": "sha512-EBJnVBr3dTXdA89WVFoAIPUqkBjxPMwRqsfuo1r240tKFHXv3zgca4+NJib/h6TyvGF7vOawz0jGuryJCdNHrw==", + "license": "MIT", + "engines": { + "node": ">=20" + } + }, + "node_modules/uuid": { + "version": "13.0.0", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-13.0.0.tgz", + "integrity": "sha512-XQegIaBTVUjSHliKqcnFqYypAd4S+WCYt5NIeRs6w/UAry7z8Y9j5ZwRRL4kzq9U3sD6v+85er9FvkEaBpji2w==", + "funding": [ + "https://github.com/sponsors/broofa", + "https://github.com/sponsors/ctavan" + ], + "license": "MIT", + "bin": { + "uuid": "dist-node/bin/uuid" + } + }, "node_modules/which": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", @@ -104,6 +350,21 @@ "node": ">= 8" } }, + "node_modules/yaml": { + "version": "2.8.3", + "resolved": "https://registry.npmjs.org/yaml/-/yaml-2.8.3.tgz", + "integrity": "sha512-AvbaCLOO2Otw/lW5bmh9d/WEdcDFdQp2Z2ZUH3pX9U2ihyUY0nvLv7J6TrWowklRGPYbB/IuIMfYgxaCPg5Bpg==", + "license": "ISC", + "bin": { + "yaml": "bin.mjs" + }, + "engines": { + "node": ">= 14.6" + }, + "funding": { + "url": "https://github.com/sponsors/eemeli" + } + }, "node_modules/zod": { "version": "4.1.8", "license": "MIT", From 9913a6e6040fa3f77a3f54284f020d47dad21a82 Mon Sep 17 00:00:00 2001 From: Jordon Date: Fri, 17 Apr 2026 19:48:29 +0100 Subject: [PATCH 05/37] Fix Spinner issue --- Frontend/src/styles/components.css | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/Frontend/src/styles/components.css b/Frontend/src/styles/components.css index a74eee4a..a1d48718 100644 --- a/Frontend/src/styles/components.css +++ b/Frontend/src/styles/components.css @@ -350,7 +350,11 @@ button.saved-state,.btn.saved-state,.tbtn.saved-state{ #status.busy::after{ content:""; display:inline-block; width:12px; height:12px; margin-left:.5rem; border:2px solid var(--muted); border-top-color:var(--accent); - border-radius:50%; vertical-align:-2px; + border-radius:50%; vertical-align:-2px; animation:status-spin .8s linear infinite; +} + +@keyframes status-spin{ + to{ transform:rotate(360deg); } } /* ========== Branch switcher (button only) ========== */ From 7d38037ffd91c5ceb7a53a164ed96b37298e4672 Mon Sep 17 00:00:00 2001 From: Jordon Date: Fri, 17 Apr 2026 19:58:07 +0100 Subject: [PATCH 06/37] Improved threading --- Frontend/src/scripts/features/repo/hydrate.ts | 22 +++++++++++++++++++ Frontend/src/scripts/features/repo/index.ts | 2 +- Frontend/src/scripts/main.ts | 20 ++++++++++++----- 3 files changed, 38 insertions(+), 6 deletions(-) diff --git a/Frontend/src/scripts/features/repo/hydrate.ts b/Frontend/src/scripts/features/repo/hydrate.ts index 096baca1..c22980f5 100644 --- a/Frontend/src/scripts/features/repo/hydrate.ts +++ b/Frontend/src/scripts/features/repo/hydrate.ts @@ -5,6 +5,24 @@ import { state, prefs } from '../../state/state'; import { renderList } from './list'; import { autoOpenFirstConflict } from '../conflicts'; +/** + * Yields control long enough for the browser to paint pending UI updates. + * + * This keeps the webview responsive before expensive repo refresh work starts. + * + * @returns A promise that resolves on the next paint opportunity. + */ +export function yieldToPaint(): Promise { + return new Promise((resolve) => { + if (document.visibilityState === 'visible') { + window.requestAnimationFrame(() => resolve()); + return; + } + + window.setTimeout(() => resolve(), 0); + }); +} + function normalizeFiles(files: any[]): any[] { return [...files].sort((a, b) => String(a?.path || '').localeCompare(String(b?.path || ''))); } @@ -38,6 +56,7 @@ let lastStatusSignature = ''; export async function hydrateBranches(): Promise { if (!TAURI.has) return false; try { + await yieldToPaint(); const list = await TAURI.invoke('git_list_branches'); const head = await TAURI.invoke<{ detached: boolean; branch?: string; commit?: string }>('git_head_status').catch(() => ({ detached: false } as any)); const has = Array.isArray(list) && list.length > 0; @@ -63,6 +82,7 @@ export async function hydrateBranches(): Promise { export async function hydrateStatus() { if (!TAURI.has) return; try { + await yieldToPaint(); const result = await TAURI.invoke<{ files: any[]; ahead?: number; behind?: number }>('git_status'); const nextFiles = Array.isArray(result?.files) ? (result.files as any) : []; let nextMergeInProgress = false; @@ -130,6 +150,7 @@ export async function hydrateStatus() { export async function hydrateCommits() { if (!TAURI.has) return; try { + await yieldToPaint(); const list = await TAURI.invoke('git_log', { limit: 100 }); state.hasRepo = true; const baseCommits = Array.isArray(list) ? (list as any) : []; @@ -189,6 +210,7 @@ export async function hydrateCommits() { export async function hydrateStash() { if (!TAURI.has) return; try { + await yieldToPaint(); const list = await TAURI.invoke('git_stash_list'); (state as any).stash = Array.isArray(list) ? (list as any) : []; if (prefs.tab === 'stash') renderList(); diff --git a/Frontend/src/scripts/features/repo/index.ts b/Frontend/src/scripts/features/repo/index.ts index 38391e5a..a65a07f1 100644 --- a/Frontend/src/scripts/features/repo/index.ts +++ b/Frontend/src/scripts/features/repo/index.ts @@ -3,4 +3,4 @@ export { bindRepoHotkeys } from './hotkeys'; export { bindFilter } from './filter'; export { renderList, wireRenderListCallbacks } from './list'; -export { hydrateBranches, hydrateStatus, hydrateCommits, hydrateStash } from './hydrate'; +export { hydrateBranches, hydrateStatus, hydrateCommits, hydrateStash, yieldToPaint } from './hydrate'; diff --git a/Frontend/src/scripts/main.ts b/Frontend/src/scripts/main.ts index 7f231a83..f87898e5 100644 --- a/Frontend/src/scripts/main.ts +++ b/Frontend/src/scripts/main.ts @@ -14,7 +14,7 @@ import { import { clearPluginMenubarMenus, initMenubar, refreshPluginMenubarMenus } from './ui/menubar'; import { closeAllModals } from './ui/modals'; import { bindCommandSheet, openSheet, closeSheet } from './features/commandSheet'; -import { bindRepoHotkeys, bindFilter, renderList, wireRenderListCallbacks, hydrateBranches, hydrateStatus, hydrateCommits, hydrateStash } from './features/repo'; +import { bindRepoHotkeys, bindFilter, renderList, wireRenderListCallbacks, hydrateBranches, hydrateStatus, hydrateCommits, hydrateStash, yieldToPaint } from './features/repo'; import { bindBranchUI } from './features/branches'; import { bindCommit } from './features/diff'; import { openAbout } from './features/about'; @@ -184,7 +184,8 @@ async function boot() { await TAURI.invoke('git_fetch', {}); notify('Fetched'); if (hydrate) { - await Promise.allSettled([hydrateStatus(), hydrateCommits()]); + await yieldToPaint(); + void Promise.allSettled([hydrateStatus(), hydrateCommits()]); } success = true; } catch { @@ -207,7 +208,8 @@ async function boot() { await TAURI.invoke('git_fetch_all', {}); notify('Fetched all remotes'); if (hydrate) { - await Promise.allSettled([hydrateStatus(), hydrateCommits()]); + await yieldToPaint(); + void Promise.allSettled([hydrateStatus(), hydrateCommits()]); } success = true; } catch { @@ -461,6 +463,7 @@ async function boot() { // Global busy indicator for any Git activity (function(){ let busyTimer: any = null; + let busyFrame: number | null = null; const setBusy = (msg: string, showSpinner = true) => { const s = document.getElementById('status'); if (!s) return; @@ -474,13 +477,20 @@ async function boot() { s.textContent = 'Ready'; }, 1500); }; + const queueBusyUpdate = () => { + if (busyFrame !== null) return; + busyFrame = window.requestAnimationFrame(() => { + busyFrame = null; + const focused = document.visibilityState === 'visible' && document.hasFocus(); + setBusy('Working…', focused); + }); + }; TAURI.listen?.('git-progress', ({ payload }) => { // Don't spam the footer with raw git output; keep it generic. void payload; // Avoid spinner-driven repaint churn for passive/background progress. // Explicit user actions already set busy state via their own controllers. - const focused = document.visibilityState === 'visible' && document.hasFocus(); - setBusy('Working…', focused); + queueBusyUpdate(); }); })(); From b3e3496a3c3cb13e4cfd92c9a0de807721f6c388 Mon Sep 17 00:00:00 2001 From: Jordon Date: Mon, 20 Apr 2026 00:56:24 +0100 Subject: [PATCH 07/37] Fixed file delete not working --- Frontend/src/modals/confirm.html | 22 +++++ Frontend/src/scripts/features/confirmModal.ts | 94 +++++++++++++++++++ Frontend/src/scripts/lib/confirm.test.ts | 75 +++++++++++++++ Frontend/src/scripts/lib/confirm.ts | 25 ++++- Frontend/src/scripts/ui/modals.ts | 10 +- Frontend/src/styles/index.css | 1 + Frontend/src/styles/modal/confirm.css | 10 ++ 7 files changed, 233 insertions(+), 4 deletions(-) create mode 100644 Frontend/src/modals/confirm.html create mode 100644 Frontend/src/scripts/features/confirmModal.ts create mode 100644 Frontend/src/scripts/lib/confirm.test.ts create mode 100644 Frontend/src/styles/modal/confirm.css diff --git a/Frontend/src/modals/confirm.html b/Frontend/src/modals/confirm.html new file mode 100644 index 00000000..f7ecc614 --- /dev/null +++ b/Frontend/src/modals/confirm.html @@ -0,0 +1,22 @@ + + diff --git a/Frontend/src/scripts/features/confirmModal.ts b/Frontend/src/scripts/features/confirmModal.ts new file mode 100644 index 00000000..5be97641 --- /dev/null +++ b/Frontend/src/scripts/features/confirmModal.ts @@ -0,0 +1,94 @@ +// Copyright © 2025-2026 OpenVCS Contributors +// SPDX-License-Identifier: GPL-3.0-or-later + +import { closeModal, hydrate, openModal } from '../ui/modals'; + +/** Options that control the shared confirmation modal content. */ +export interface ConfirmModalOptions { + title?: string; + message: string; + hint?: string; + confirmLabel?: string; + cancelLabel?: string; + danger?: boolean; +} + +let pendingResolve: ((ok: boolean) => void) | null = null; + +/** Returns the shared confirmation modal element if it exists. */ +function getModal(): HTMLElement | null { + return document.getElementById('confirm-modal'); +} + +/** Resolves and clears any pending confirmation promise. */ +function resolvePending(ok: boolean) { + if (!pendingResolve) return; + const resolve = pendingResolve; + pendingResolve = null; + resolve(ok); +} + +/** Wires the shared confirmation modal once. */ +export function wireConfirmModal() { + const modal = getModal(); + if (!modal || (modal as HTMLElement & { __wired?: boolean }).__wired) return; + (modal as HTMLElement & { __wired?: boolean }).__wired = true; + + const titleEl = modal.querySelector('#confirm-modal-title'); + const hintEl = modal.querySelector('#confirm-modal-hint'); + const messageEl = modal.querySelector('#confirm-modal-message'); + const cancelBtn = modal.querySelector('#confirm-modal-cancel-btn'); + const confirmBtn = modal.querySelector('#confirm-modal-confirm-btn'); + + modal.addEventListener('click', (event) => { + const target = event.target as HTMLElement; + const wantsClose = target.classList?.contains('backdrop') || !!target.closest('[data-close]'); + if (wantsClose) resolvePending(false); + }); + + document.addEventListener('keydown', (event) => { + if (event.key !== 'Escape') return; + const current = getModal(); + if (!current || current.getAttribute('aria-hidden') !== 'false') return; + resolvePending(false); + }); + + confirmBtn?.addEventListener('click', () => { + resolvePending(true); + closeModal('confirm-modal'); + }); + + (modal as HTMLElement & { setContent?: (opts: ConfirmModalOptions) => void }).setContent = (opts) => { + const title = String(opts.title || 'Confirm action').trim() || 'Confirm action'; + const hint = String(opts.hint || 'This cannot be undone.').trim() || 'This cannot be undone.'; + const confirmLabel = String(opts.confirmLabel || 'Confirm').trim() || 'Confirm'; + const cancelLabel = String(opts.cancelLabel || 'Cancel').trim() || 'Cancel'; + const isDanger = !!opts.danger; + + if (titleEl) titleEl.textContent = title; + if (hintEl) hintEl.textContent = hint; + if (messageEl) messageEl.textContent = opts.message; + if (cancelBtn) cancelBtn.textContent = cancelLabel; + if (confirmBtn) { + confirmBtn.textContent = confirmLabel; + confirmBtn.classList.toggle('danger', isDanger); + confirmBtn.classList.toggle('primary', !isDanger); + } + window.setTimeout(() => cancelBtn?.focus(), 0); + }; +} + +/** Opens the shared confirmation modal and resolves with the user's choice. */ +export function confirmWithModal(opts: ConfirmModalOptions): Promise { + hydrate('confirm-modal'); + wireConfirmModal(); + + const modal = getModal() as (HTMLElement & { setContent?: (opts: ConfirmModalOptions) => void }) | null; + modal?.setContent?.(opts); + + return new Promise((resolve) => { + resolvePending(false); + pendingResolve = resolve; + openModal('confirm-modal'); + }); +} diff --git a/Frontend/src/scripts/lib/confirm.test.ts b/Frontend/src/scripts/lib/confirm.test.ts new file mode 100644 index 00000000..73f6c2c0 --- /dev/null +++ b/Frontend/src/scripts/lib/confirm.test.ts @@ -0,0 +1,75 @@ +// Copyright © 2025-2026 OpenVCS Contributors +// SPDX-License-Identifier: GPL-3.0-or-later + +import { afterEach, describe, expect, it, vi } from 'vitest'; + +import { confirmBool } from './confirm'; + +const originalConfirm = window.confirm; + +/** Restores the original global confirm implementation after each test. */ +afterEach(() => { + document.body.innerHTML = ''; + vi.restoreAllMocks(); + Object.defineProperty(window, 'confirm', { + configurable: true, + writable: true, + value: originalConfirm, + }); +}); + +describe('confirmBool', () => { + it('uses the in-app modal when the modal root exists', async () => { + document.body.innerHTML = '
'; + + const pending = confirmBool('Discard changes?'); + const confirmBtn = document.getElementById('confirm-modal-confirm-btn') as HTMLButtonElement | null; + + expect(document.getElementById('confirm-modal')?.getAttribute('aria-hidden')).toBe('false'); + expect(confirmBtn?.textContent).toBe('Confirm'); + confirmBtn?.click(); + + await expect(pending).resolves.toBe(true); + }); + + it('invokes window.confirm with the window receiver', async () => { + document.body.innerHTML = ''; + const confirmSpy = vi.fn(function (this: Window, message: string) { + expect(this).toBe(window); + expect(message).toBe('Discard changes?'); + return true; + }); + + Object.defineProperty(window, 'confirm', { + configurable: true, + writable: true, + value: confirmSpy, + }); + + await expect(confirmBool('Discard changes?')).resolves.toBe(true); + }); + + it('supports promise-based confirm implementations', async () => { + document.body.innerHTML = ''; + Object.defineProperty(window, 'confirm', { + configurable: true, + writable: true, + value: vi.fn().mockResolvedValue({ confirmed: true }), + }); + + await expect(confirmBool('Discard changes?')).resolves.toBe(true); + }); + + it('returns false when confirm throws', async () => { + document.body.innerHTML = ''; + Object.defineProperty(window, 'confirm', { + configurable: true, + writable: true, + value: () => { + throw new TypeError('Illegal invocation'); + }, + }); + + await expect(confirmBool('Discard changes?')).resolves.toBe(false); + }); +}); diff --git a/Frontend/src/scripts/lib/confirm.ts b/Frontend/src/scripts/lib/confirm.ts index 9d7febed..06addc8e 100644 --- a/Frontend/src/scripts/lib/confirm.ts +++ b/Frontend/src/scripts/lib/confirm.ts @@ -1,6 +1,8 @@ // Copyright © 2025-2026 OpenVCS Contributors // SPDX-License-Identifier: GPL-3.0-or-later +import { confirmWithModal } from '../features/confirmModal'; + /** * Attempts to coerce arbitrary confirm-return payloads into a boolean. * @@ -29,18 +31,35 @@ function coerceConfirmResult(value: unknown): boolean { /** * Shows a confirmation prompt and returns a normalized boolean result. * - * Supports both synchronous browser `window.confirm` and Promise-returning - * confirm implementations exposed by embedded runtimes. + * Prefers the shared in-app confirmation modal when the modal host is mounted, + * then falls back to browser `window.confirm` for runtimes that do not render + * the main modal shell. * * @param message - Prompt text shown to the user. * @returns `true` when the user confirms; otherwise `false`. */ export async function confirmBool(message: string): Promise { + const modalRoot = document.getElementById('modals-root'); + if (modalRoot) { + try { + return await confirmWithModal({ + title: 'Confirm action', + message, + hint: 'This cannot be undone.', + confirmLabel: 'Confirm', + cancelLabel: 'Cancel', + danger: true, + }); + } catch { + // Fall through to browser confirm when modal rendering is unavailable. + } + } + const confirmFn = (window as any).confirm; if (typeof confirmFn !== 'function') return false; try { - const maybe = confirmFn(message) as unknown; + const maybe = Reflect.apply(confirmFn, window, [message]) as unknown; if (maybe && typeof (maybe as PromiseLike).then === 'function') { const resolved = await (maybe as PromiseLike); return coerceConfirmResult(resolved); diff --git a/Frontend/src/scripts/ui/modals.ts b/Frontend/src/scripts/ui/modals.ts index 3f8a9a60..45521fbc 100644 --- a/Frontend/src/scripts/ui/modals.ts +++ b/Frontend/src/scripts/ui/modals.ts @@ -19,6 +19,8 @@ import { wireRenameBranch } from "../features/renameBranch"; import cherryPickHtml from "@modals/cherry-pick.html?raw"; import { wireCherryPick } from "../features/cherryPick"; import deleteBranchHtml from "@modals/delete-branch.html?raw"; +import confirmHtml from "@modals/confirm.html?raw"; +import { wireConfirmModal } from "../features/confirmModal"; import { wireDeleteBranchConfirm } from "../features/deleteBranchConfirm"; import setUpstreamHtml from "@modals/set-upstream.html?raw"; import { wireSetUpstream } from "../features/setUpstream"; @@ -44,6 +46,7 @@ const FRAGMENTS: Record = { "new-branch-modal": newBranchHtml, "rename-branch-modal": renameBranchHtml, "cherry-pick-modal": cherryPickHtml, + "confirm-modal": confirmHtml, "delete-branch-modal": deleteBranchHtml, "set-upstream-modal": setUpstreamHtml, "update-modal": updateHtml, @@ -53,7 +56,10 @@ const FRAGMENTS: Record = { }; const loaded = new Set(); -const root = qs("#modals-root"); +/** Returns the modal root where lazily-hydrated fragments are injected. */ +function getRoot(): HTMLElement | null { + return qs('#modals-root'); +} // scroll lock counter (supports multiple modals) let openCount = 0; @@ -90,6 +96,7 @@ export function hydrate(id: string): void { loaded.add(id); return; } + const root = getRoot(); if (!root || loaded.has(id)) return; const html = FRAGMENTS[id]; @@ -110,6 +117,7 @@ export function hydrate(id: string): void { if (id === "new-branch-modal") wireNewBranch(); if (id === "rename-branch-modal") wireRenameBranch(); if (id === "cherry-pick-modal") wireCherryPick(); + if (id === "confirm-modal") wireConfirmModal(); if (id === "delete-branch-modal") wireDeleteBranchConfirm(); if (id === "set-upstream-modal") wireSetUpstream(); if (id === "update-modal") wireUpdate(); diff --git a/Frontend/src/styles/index.css b/Frontend/src/styles/index.css index 0790b19e..6acd72d3 100644 --- a/Frontend/src/styles/index.css +++ b/Frontend/src/styles/index.css @@ -14,6 +14,7 @@ @import "./modal/repo-settings.css"; @import "./output-log.css"; @import "./modal/new-branch.css"; +@import "./modal/confirm.css"; @import "./modal/stash-confirm.css"; @import "./modal/merge.css"; @import "./modal/ssh-keys.css"; diff --git a/Frontend/src/styles/modal/confirm.css b/Frontend/src/styles/modal/confirm.css new file mode 100644 index 00000000..f135074d --- /dev/null +++ b/Frontend/src/styles/modal/confirm.css @@ -0,0 +1,10 @@ +/* src/styles/modal/confirm.css */ + +#confirm-modal .dialog.sheet { + width: clamp(420px, 92vw, 520px); + max-height: min(70vh, 360px); +} + +#confirm-modal #confirm-modal-message { + white-space: pre-wrap; +} From 367968470885378cda5a0d3d13d7c88c47447827 Mon Sep 17 00:00:00 2001 From: Jordon Date: Mon, 20 Apr 2026 01:36:26 +0100 Subject: [PATCH 08/37] Update opencode-review.yml --- .github/workflows/opencode-review.yml | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/.github/workflows/opencode-review.yml b/.github/workflows/opencode-review.yml index 3e2c7ff8..d9061d7c 100644 --- a/.github/workflows/opencode-review.yml +++ b/.github/workflows/opencode-review.yml @@ -35,6 +35,11 @@ jobs: - Check for code quality issues - Look for potential bugs - Suggest improvements + - Leave feedback as comments only + - Do not edit any files + - Do not use write, edit, or patch tools + - Do not create commits or push changes + - Keep the working tree unchanged - name: fallback if: steps.review_primary.outcome == 'failure' @@ -50,4 +55,9 @@ jobs: Review this pull request: - Check for code quality issues - Look for potential bugs - - Suggest improvements \ No newline at end of file + - Suggest improvements + - Leave feedback as comments only + - Do not edit any files + - Do not use write, edit, or patch tools + - Do not create commits or push changes + - Keep the working tree unchanged From ca81bd64a65dfe33794ca9c70202fd47f07bdf1e Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 20 Apr 2026 06:54:24 +0000 Subject: [PATCH 09/37] chore(deps): bump the actions-minor-patch group with 2 updates Bumps the actions-minor-patch group with 2 updates: [actions/setup-node](https://github.com/actions/setup-node) and [github/codeql-action](https://github.com/github/codeql-action). Updates `actions/setup-node` from 6.3.0 to 6.4.0 - [Release notes](https://github.com/actions/setup-node/releases) - [Commits](https://github.com/actions/setup-node/compare/53b83947a5a98c8d113130e565377fae1a50d02f...48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e) Updates `github/codeql-action` from 4.35.1 to 4.35.2 - [Release notes](https://github.com/github/codeql-action/releases) - [Changelog](https://github.com/github/codeql-action/blob/main/CHANGELOG.md) - [Commits](https://github.com/github/codeql-action/compare/c10b8064de6f491fea524254123dbe5e09572f13...95e58e9a2cdfd71adc6e0353d5c52f41a045d225) --- updated-dependencies: - dependency-name: actions/setup-node dependency-version: 6.4.0 dependency-type: direct:production update-type: version-update:semver-minor dependency-group: actions-minor-patch - dependency-name: github/codeql-action dependency-version: 4.35.2 dependency-type: direct:production update-type: version-update:semver-patch dependency-group: actions-minor-patch ... Signed-off-by: dependabot[bot] --- .github/workflows/beta.yml | 2 +- .github/workflows/codeql.yml | 6 +++--- .github/workflows/development.yml | 2 +- .github/workflows/nightly.yml | 2 +- .github/workflows/publish-stable.yml | 2 +- 5 files changed, 7 insertions(+), 7 deletions(-) diff --git a/.github/workflows/beta.yml b/.github/workflows/beta.yml index 4aeb9a7e..0cbbb80f 100644 --- a/.github/workflows/beta.yml +++ b/.github/workflows/beta.yml @@ -47,7 +47,7 @@ jobs: core.setOutput('date', date); - name: Setup Node - uses: actions/setup-node@53b83947a5a98c8d113130e565377fae1a50d02f # v6.3.0 + uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6.4.0 with: node-version: '24' cache: 'npm' diff --git a/.github/workflows/codeql.yml b/.github/workflows/codeql.yml index 348cc1bc..7709ad8e 100644 --- a/.github/workflows/codeql.yml +++ b/.github/workflows/codeql.yml @@ -53,7 +53,7 @@ jobs: fetch-depth: 0 - name: Initialize CodeQL - uses: github/codeql-action/init@c10b8064de6f491fea524254123dbe5e09572f13 # v3 + uses: github/codeql-action/init@95e58e9a2cdfd71adc6e0353d5c52f41a045d225 # v3 with: languages: ${{ matrix.language }} build-mode: ${{ matrix.build-mode }} @@ -64,9 +64,9 @@ jobs: - name: Autobuild if: matrix.build-mode == 'autobuild' - uses: github/codeql-action/autobuild@c10b8064de6f491fea524254123dbe5e09572f13 # v3 + uses: github/codeql-action/autobuild@95e58e9a2cdfd71adc6e0353d5c52f41a045d225 # v3 - name: Perform CodeQL Analysis - uses: github/codeql-action/analyze@c10b8064de6f491fea524254123dbe5e09572f13 # v3 + uses: github/codeql-action/analyze@95e58e9a2cdfd71adc6e0353d5c52f41a045d225 # v3 with: category: "/language:${{ matrix.language }}" diff --git a/.github/workflows/development.yml b/.github/workflows/development.yml index e7ace271..b41aa0c6 100644 --- a/.github/workflows/development.yml +++ b/.github/workflows/development.yml @@ -59,7 +59,7 @@ jobs: # ---------- Frontend: lint + typecheck ---------- - name: Setup Node - uses: actions/setup-node@53b83947a5a98c8d113130e565377fae1a50d02f # v6.3.0 + uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6.4.0 with: node-version: '24' cache: 'npm' diff --git a/.github/workflows/nightly.yml b/.github/workflows/nightly.yml index 0e229db3..c1fd8700 100644 --- a/.github/workflows/nightly.yml +++ b/.github/workflows/nightly.yml @@ -152,7 +152,7 @@ jobs: # ---------- Frontend ---------- - name: Setup Node - uses: actions/setup-node@53b83947a5a98c8d113130e565377fae1a50d02f # v6.3.0 + uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6.4.0 with: node-version: '24' cache: 'npm' diff --git a/.github/workflows/publish-stable.yml b/.github/workflows/publish-stable.yml index 6440e18a..5baf497a 100644 --- a/.github/workflows/publish-stable.yml +++ b/.github/workflows/publish-stable.yml @@ -45,7 +45,7 @@ jobs: # ---------- Frontend (Node + Vite) ---------- - name: Setup Node - uses: actions/setup-node@53b83947a5a98c8d113130e565377fae1a50d02f # v6.3.0 + uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6.4.0 with: node-version: '24' cache: 'npm' From 0746ceac3536f3f0a5a16e774d383ae8d669fae6 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 20 Apr 2026 07:04:53 +0000 Subject: [PATCH 10/37] chore(deps)(deps-dev): bump the npm-minor-patch group Bumps the npm-minor-patch group in /Frontend with 2 updates: [typescript](https://github.com/microsoft/TypeScript) and [vite](https://github.com/vitejs/vite/tree/HEAD/packages/vite). Updates `typescript` from 6.0.2 to 6.0.3 - [Release notes](https://github.com/microsoft/TypeScript/releases) - [Commits](https://github.com/microsoft/TypeScript/compare/v6.0.2...v6.0.3) Updates `vite` from 8.0.8 to 8.0.9 - [Release notes](https://github.com/vitejs/vite/releases) - [Changelog](https://github.com/vitejs/vite/blob/main/packages/vite/CHANGELOG.md) - [Commits](https://github.com/vitejs/vite/commits/v8.0.9/packages/vite) --- updated-dependencies: - dependency-name: typescript dependency-version: 6.0.3 dependency-type: direct:development update-type: version-update:semver-patch dependency-group: npm-minor-patch - dependency-name: vite dependency-version: 8.0.9 dependency-type: direct:development update-type: version-update:semver-patch dependency-group: npm-minor-patch ... Signed-off-by: dependabot[bot] --- Frontend/package-lock.json | 188 ++++++++++++++++++------------------- Frontend/package.json | 4 +- 2 files changed, 96 insertions(+), 96 deletions(-) diff --git a/Frontend/package-lock.json b/Frontend/package-lock.json index b5fe5908..355897ea 100644 --- a/Frontend/package-lock.json +++ b/Frontend/package-lock.json @@ -14,8 +14,8 @@ "devDependencies": { "@types/node": "^25.6.0", "jsdom": "^29.0.2", - "typescript": "^6.0.2", - "vite": "^8.0.8", + "typescript": "^6.0.3", + "vite": "^8.0.9", "vitest": "^4.1.4" } }, @@ -271,9 +271,9 @@ "license": "MIT" }, "node_modules/@napi-rs/wasm-runtime": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/@napi-rs/wasm-runtime/-/wasm-runtime-1.1.3.tgz", - "integrity": "sha512-xK9sGVbJWYb08+mTJt3/YV24WxvxpXcXtP6B172paPZ+Ts69Re9dAr7lKwJoeIx8OoeuimEiRZ7umkiUVClmmQ==", + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/@napi-rs/wasm-runtime/-/wasm-runtime-1.1.4.tgz", + "integrity": "sha512-3NQNNgA1YSlJb/kMH1ildASP9HW7/7kYnRI2szWJaofaS1hWmbGI4H+d3+22aGzXXN9IJ+n+GiFVcGipJP18ow==", "dev": true, "license": "MIT", "optional": true, @@ -290,9 +290,9 @@ } }, "node_modules/@oxc-project/types": { - "version": "0.124.0", - "resolved": "https://registry.npmjs.org/@oxc-project/types/-/types-0.124.0.tgz", - "integrity": "sha512-VBFWMTBvHxS11Z5Lvlr3IWgrwhMTXV+Md+EQF0Xf60+wAdsGFTBx7X7K/hP4pi8N7dcm1RvcHwDxZ16Qx8keUg==", + "version": "0.126.0", + "resolved": "https://registry.npmjs.org/@oxc-project/types/-/types-0.126.0.tgz", + "integrity": "sha512-oGfVtjAgwQVVpfBrbtk4e1XDyWHRFta6BS3GWVzrF8xYBT2VGQAk39yJS/wFSMrZqoiCU4oghT3Ch0HaHGIHcQ==", "dev": true, "license": "MIT", "funding": { @@ -300,9 +300,9 @@ } }, "node_modules/@rolldown/binding-android-arm64": { - "version": "1.0.0-rc.15", - "resolved": "https://registry.npmjs.org/@rolldown/binding-android-arm64/-/binding-android-arm64-1.0.0-rc.15.tgz", - "integrity": "sha512-YYe6aWruPZDtHNpwu7+qAHEMbQ/yRl6atqb/AhznLTnD3UY99Q1jE7ihLSahNWkF4EqRPVC4SiR4O0UkLK02tA==", + "version": "1.0.0-rc.16", + "resolved": "https://registry.npmjs.org/@rolldown/binding-android-arm64/-/binding-android-arm64-1.0.0-rc.16.tgz", + "integrity": "sha512-rhY3k7Bsae9qQfOtph2Pm2jZEA+s8Gmjoz4hhmx70K9iMQ/ddeae+xhRQcM5IuVx5ry1+bGfkvMn7D6MJggVSA==", "cpu": [ "arm64" ], @@ -317,9 +317,9 @@ } }, "node_modules/@rolldown/binding-darwin-arm64": { - "version": "1.0.0-rc.15", - "resolved": "https://registry.npmjs.org/@rolldown/binding-darwin-arm64/-/binding-darwin-arm64-1.0.0-rc.15.tgz", - "integrity": "sha512-oArR/ig8wNTPYsXL+Mzhs0oxhxfuHRfG7Ikw7jXsw8mYOtk71W0OkF2VEVh699pdmzjPQsTjlD1JIOoHkLP1Fg==", + "version": "1.0.0-rc.16", + "resolved": "https://registry.npmjs.org/@rolldown/binding-darwin-arm64/-/binding-darwin-arm64-1.0.0-rc.16.tgz", + "integrity": "sha512-rNz0yK078yrNn3DrdgN+PKiMOW8HfQ92jQiXxwX8yW899ayV00MLVdaCNeVBhG/TbH3ouYVObo8/yrkiectkcQ==", "cpu": [ "arm64" ], @@ -334,9 +334,9 @@ } }, "node_modules/@rolldown/binding-darwin-x64": { - "version": "1.0.0-rc.15", - "resolved": "https://registry.npmjs.org/@rolldown/binding-darwin-x64/-/binding-darwin-x64-1.0.0-rc.15.tgz", - "integrity": "sha512-YzeVqOqjPYvUbJSWJ4EDL8ahbmsIXQpgL3JVipmN+MX0XnXMeWomLN3Fb+nwCmP/jfyqte5I3XRSm7OfQrbyxw==", + "version": "1.0.0-rc.16", + "resolved": "https://registry.npmjs.org/@rolldown/binding-darwin-x64/-/binding-darwin-x64-1.0.0-rc.16.tgz", + "integrity": "sha512-r/OmdR00HmD4i79Z//xO06uEPOq5hRXdhw7nzkxQxwSavs3PSHa1ijntdpOiZ2mzOQ3fVVu8C1M19FoNM+dMUQ==", "cpu": [ "x64" ], @@ -351,9 +351,9 @@ } }, "node_modules/@rolldown/binding-freebsd-x64": { - "version": "1.0.0-rc.15", - "resolved": "https://registry.npmjs.org/@rolldown/binding-freebsd-x64/-/binding-freebsd-x64-1.0.0-rc.15.tgz", - "integrity": "sha512-9Erhx956jeQ0nNTyif1+QWAXDRD38ZNjr//bSHrt6wDwB+QkAfl2q6Mn1k6OBPerznjRmbM10lgRb1Pli4xZPw==", + "version": "1.0.0-rc.16", + "resolved": "https://registry.npmjs.org/@rolldown/binding-freebsd-x64/-/binding-freebsd-x64-1.0.0-rc.16.tgz", + "integrity": "sha512-KcRE5w8h0OnjUatG8pldyD14/CQ5Phs1oxfR+3pKDjboHRo9+MkqQaiIZlZRpsxC15paeXme/I127tUa9TXJ6g==", "cpu": [ "x64" ], @@ -368,9 +368,9 @@ } }, "node_modules/@rolldown/binding-linux-arm-gnueabihf": { - "version": "1.0.0-rc.15", - "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-arm-gnueabihf/-/binding-linux-arm-gnueabihf-1.0.0-rc.15.tgz", - "integrity": "sha512-cVwk0w8QbZJGTnP/AHQBs5yNwmpgGYStL88t4UIaqcvYJWBfS0s3oqVLZPwsPU6M0zlW4GqjP0Zq5MnAGwFeGA==", + "version": "1.0.0-rc.16", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-arm-gnueabihf/-/binding-linux-arm-gnueabihf-1.0.0-rc.16.tgz", + "integrity": "sha512-bT0guA1bpxEJ/ZhTRniQf7rNF8ybvXOuWbNIeLABaV5NGjx4EtOWBTSRGWFU9ZWVkPOZ+HNFP8RMcBokBiZ0Kg==", "cpu": [ "arm" ], @@ -385,9 +385,9 @@ } }, "node_modules/@rolldown/binding-linux-arm64-gnu": { - "version": "1.0.0-rc.15", - "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-arm64-gnu/-/binding-linux-arm64-gnu-1.0.0-rc.15.tgz", - "integrity": "sha512-eBZ/u8iAK9SoHGanqe/jrPnY0JvBN6iXbVOsbO38mbz+ZJsaobExAm1Iu+rxa4S1l2FjG0qEZn4Rc6X8n+9M+w==", + "version": "1.0.0-rc.16", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-arm64-gnu/-/binding-linux-arm64-gnu-1.0.0-rc.16.tgz", + "integrity": "sha512-+tHktCHWV8BDQSjemUqm/Jl/TPk3QObCTIjmdDy/nlupcujZghmKK2962LYrqFpWu+ai01AN/REOH3NEpqvYQg==", "cpu": [ "arm64" ], @@ -402,9 +402,9 @@ } }, "node_modules/@rolldown/binding-linux-arm64-musl": { - "version": "1.0.0-rc.15", - "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-arm64-musl/-/binding-linux-arm64-musl-1.0.0-rc.15.tgz", - "integrity": "sha512-ZvRYMGrAklV9PEkgt4LQM6MjQX2P58HPAuecwYObY2DhS2t35R0I810bKi0wmaYORt6m/2Sm+Z+nFgb0WhXNcQ==", + "version": "1.0.0-rc.16", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-arm64-musl/-/binding-linux-arm64-musl-1.0.0-rc.16.tgz", + "integrity": "sha512-3fPzdREH806oRLxpTWW1Gt4tQHs0TitZFOECB2xzCFLPKnSOy90gwA7P29cksYilFO6XVRY1kzga0cL2nRjKPg==", "cpu": [ "arm64" ], @@ -419,9 +419,9 @@ } }, "node_modules/@rolldown/binding-linux-ppc64-gnu": { - "version": "1.0.0-rc.15", - "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-ppc64-gnu/-/binding-linux-ppc64-gnu-1.0.0-rc.15.tgz", - "integrity": "sha512-VDpgGBzgfg5hLg+uBpCLoFG5kVvEyafmfxGUV0UHLcL5irxAK7PKNeC2MwClgk6ZAiNhmo9FLhRYgvMmedLtnQ==", + "version": "1.0.0-rc.16", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-ppc64-gnu/-/binding-linux-ppc64-gnu-1.0.0-rc.16.tgz", + "integrity": "sha512-EKwI1tSrLs7YVw+JPJT/G2dJQ1jl9qlTTTEG0V2Ok/RdOenRfBw2PQdLPyjhIu58ocdBfP7vIRN/pvMsPxs/AQ==", "cpu": [ "ppc64" ], @@ -436,9 +436,9 @@ } }, "node_modules/@rolldown/binding-linux-s390x-gnu": { - "version": "1.0.0-rc.15", - "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-s390x-gnu/-/binding-linux-s390x-gnu-1.0.0-rc.15.tgz", - "integrity": "sha512-y1uXY3qQWCzcPgRJATPSOUP4tCemh4uBdY7e3EZbVwCJTY3gLJWnQABgeUetvED+bt1FQ01OeZwvhLS2bpNrAQ==", + "version": "1.0.0-rc.16", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-s390x-gnu/-/binding-linux-s390x-gnu-1.0.0-rc.16.tgz", + "integrity": "sha512-Uknladnb3Sxqu6SEcqBldQyJUpk8NleooZEc0MbRBJ4inEhRYWZX0NJu12vNf2mqAq7gsofAxHrGghiUYjhaLQ==", "cpu": [ "s390x" ], @@ -453,9 +453,9 @@ } }, "node_modules/@rolldown/binding-linux-x64-gnu": { - "version": "1.0.0-rc.15", - "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-x64-gnu/-/binding-linux-x64-gnu-1.0.0-rc.15.tgz", - "integrity": "sha512-023bTPBod7J3Y/4fzAN6QtpkSABR0rigtrwaP+qSEabUh5zf6ELr9Nc7GujaROuPY3uwdSIXWrvhn1KxOvurWA==", + "version": "1.0.0-rc.16", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-x64-gnu/-/binding-linux-x64-gnu-1.0.0-rc.16.tgz", + "integrity": "sha512-FIb8+uG49sZBtLTn+zt1AJ20TqVcqWeSIyoVt0or7uAWesgKaHbiBh6OpA/k9v0LTt+PTrb1Lao133kP4uVxkg==", "cpu": [ "x64" ], @@ -470,9 +470,9 @@ } }, "node_modules/@rolldown/binding-linux-x64-musl": { - "version": "1.0.0-rc.15", - "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-x64-musl/-/binding-linux-x64-musl-1.0.0-rc.15.tgz", - "integrity": "sha512-witB2O0/hU4CgfOOKUoeFgQ4GktPi1eEbAhaLAIpgD6+ZnhcPkUtPsoKKHRzmOoWPZue46IThdSgdo4XneOLYw==", + "version": "1.0.0-rc.16", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-x64-musl/-/binding-linux-x64-musl-1.0.0-rc.16.tgz", + "integrity": "sha512-RuERhF9/EgWxZEXYWCOaViUWHIboceK4/ivdtQ3R0T44NjLkIIlGIAVAuCddFxsZ7vnRHtNQUrt2vR2n2slB2w==", "cpu": [ "x64" ], @@ -487,9 +487,9 @@ } }, "node_modules/@rolldown/binding-openharmony-arm64": { - "version": "1.0.0-rc.15", - "resolved": "https://registry.npmjs.org/@rolldown/binding-openharmony-arm64/-/binding-openharmony-arm64-1.0.0-rc.15.tgz", - "integrity": "sha512-UCL68NJ0Ud5zRipXZE9dF5PmirzJE4E4BCIOOssEnM7wLDsxjc6Qb0sGDxTNRTP53I6MZpygyCpY8Aa8sPfKPg==", + "version": "1.0.0-rc.16", + "resolved": "https://registry.npmjs.org/@rolldown/binding-openharmony-arm64/-/binding-openharmony-arm64-1.0.0-rc.16.tgz", + "integrity": "sha512-mXcXnvd9GpazCxeUCCnZ2+YF7nut+ZOEbE4GtaiPtyY6AkhZWbK70y1KK3j+RDhjVq5+U8FySkKRb/+w0EeUwA==", "cpu": [ "arm64" ], @@ -504,9 +504,9 @@ } }, "node_modules/@rolldown/binding-wasm32-wasi": { - "version": "1.0.0-rc.15", - "resolved": "https://registry.npmjs.org/@rolldown/binding-wasm32-wasi/-/binding-wasm32-wasi-1.0.0-rc.15.tgz", - "integrity": "sha512-ApLruZq/ig+nhaE7OJm4lDjayUnOHVUa77zGeqnqZ9pn0ovdVbbNPerVibLXDmWeUZXjIYIT8V3xkT58Rm9u5Q==", + "version": "1.0.0-rc.16", + "resolved": "https://registry.npmjs.org/@rolldown/binding-wasm32-wasi/-/binding-wasm32-wasi-1.0.0-rc.16.tgz", + "integrity": "sha512-3Q2KQxnC8IJOLqXmUMoYwyIPZU9hzRbnHaoV3Euz+VVnjZKcY8ktnNP8T9R4/GGQtb27C/UYKABxesKWb8lsvQ==", "cpu": [ "wasm32" ], @@ -516,16 +516,16 @@ "dependencies": { "@emnapi/core": "1.9.2", "@emnapi/runtime": "1.9.2", - "@napi-rs/wasm-runtime": "^1.1.3" + "@napi-rs/wasm-runtime": "^1.1.4" }, "engines": { - "node": ">=14.0.0" + "node": "^20.19.0 || >=22.12.0" } }, "node_modules/@rolldown/binding-win32-arm64-msvc": { - "version": "1.0.0-rc.15", - "resolved": "https://registry.npmjs.org/@rolldown/binding-win32-arm64-msvc/-/binding-win32-arm64-msvc-1.0.0-rc.15.tgz", - "integrity": "sha512-KmoUoU7HnN+Si5YWJigfTws1jz1bKBYDQKdbLspz0UaqjjFkddHsqorgiW1mxcAj88lYUE6NC/zJNwT+SloqtA==", + "version": "1.0.0-rc.16", + "resolved": "https://registry.npmjs.org/@rolldown/binding-win32-arm64-msvc/-/binding-win32-arm64-msvc-1.0.0-rc.16.tgz", + "integrity": "sha512-tj7XRemQcOcFwv7qhpUxMTBbI5mWMlE4c1Omhg5+h8GuLXzyj8HviYgR+bB2DMDgRqUE+jiDleqSCRjx4aYk/Q==", "cpu": [ "arm64" ], @@ -540,9 +540,9 @@ } }, "node_modules/@rolldown/binding-win32-x64-msvc": { - "version": "1.0.0-rc.15", - "resolved": "https://registry.npmjs.org/@rolldown/binding-win32-x64-msvc/-/binding-win32-x64-msvc-1.0.0-rc.15.tgz", - "integrity": "sha512-3P2A8L+x75qavWLe/Dll3EYBJLQmtkJN8rfh+U/eR3MqMgL/h98PhYI+JFfXuDPgPeCB7iZAKiqii5vqOvnA0g==", + "version": "1.0.0-rc.16", + "resolved": "https://registry.npmjs.org/@rolldown/binding-win32-x64-msvc/-/binding-win32-x64-msvc-1.0.0-rc.16.tgz", + "integrity": "sha512-PH5DRZT+F4f2PTXRXR8uJxnBq2po/xFtddyabTJVJs/ZYVHqXPEgNIr35IHTEa6bpa0Q8Awg+ymkTaGnKITw4g==", "cpu": [ "x64" ], @@ -557,9 +557,9 @@ } }, "node_modules/@rolldown/pluginutils": { - "version": "1.0.0-rc.15", - "resolved": "https://registry.npmjs.org/@rolldown/pluginutils/-/pluginutils-1.0.0-rc.15.tgz", - "integrity": "sha512-UromN0peaE53IaBRe9W7CjrZgXl90fqGpK+mIZbA3qSTeYqg3pqpROBdIPvOG3F5ereDHNwoHBI2e50n1BDr1g==", + "version": "1.0.0-rc.16", + "resolved": "https://registry.npmjs.org/@rolldown/pluginutils/-/pluginutils-1.0.0-rc.16.tgz", + "integrity": "sha512-45+YtqxLYKDWQouLKCrpIZhke+nXxhsw+qAHVzHDVwttyBlHNBVs2K25rDXrZzhpTp9w1FlAlvweV1H++fdZoA==", "dev": true, "license": "MIT" }, @@ -1310,9 +1310,9 @@ } }, "node_modules/postcss": { - "version": "8.5.8", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.8.tgz", - "integrity": "sha512-OW/rX8O/jXnm82Ey1k44pObPtdblfiuWnrd8X7GJ7emImCOstunGbXUpp7HdBrFQX6rJzn3sPT397Wp5aCwCHg==", + "version": "8.5.10", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.10.tgz", + "integrity": "sha512-pMMHxBOZKFU6HgAZ4eyGnwXF/EvPGGqUr0MnZ5+99485wwW41kW91A4LOGxSHhgugZmSChL5AlElNdwlNgcnLQ==", "dev": true, "funding": [ { @@ -1359,14 +1359,14 @@ } }, "node_modules/rolldown": { - "version": "1.0.0-rc.15", - "resolved": "https://registry.npmjs.org/rolldown/-/rolldown-1.0.0-rc.15.tgz", - "integrity": "sha512-Ff31guA5zT6WjnGp0SXw76X6hzGRk/OQq2hE+1lcDe+lJdHSgnSX6nK3erbONHyCbpSj9a9E+uX/OvytZoWp2g==", + "version": "1.0.0-rc.16", + "resolved": "https://registry.npmjs.org/rolldown/-/rolldown-1.0.0-rc.16.tgz", + "integrity": "sha512-rzi5WqKzEZw3SooTt7cgm4eqIoujPIyGcJNGFL7iPEuajQw7vxMHUkXylu4/vhCkJGXsgRmxqMKXUpT6FEgl0g==", "dev": true, "license": "MIT", "dependencies": { - "@oxc-project/types": "=0.124.0", - "@rolldown/pluginutils": "1.0.0-rc.15" + "@oxc-project/types": "=0.126.0", + "@rolldown/pluginutils": "1.0.0-rc.16" }, "bin": { "rolldown": "bin/cli.mjs" @@ -1375,21 +1375,21 @@ "node": "^20.19.0 || >=22.12.0" }, "optionalDependencies": { - "@rolldown/binding-android-arm64": "1.0.0-rc.15", - "@rolldown/binding-darwin-arm64": "1.0.0-rc.15", - "@rolldown/binding-darwin-x64": "1.0.0-rc.15", - "@rolldown/binding-freebsd-x64": "1.0.0-rc.15", - "@rolldown/binding-linux-arm-gnueabihf": "1.0.0-rc.15", - "@rolldown/binding-linux-arm64-gnu": "1.0.0-rc.15", - "@rolldown/binding-linux-arm64-musl": "1.0.0-rc.15", - "@rolldown/binding-linux-ppc64-gnu": "1.0.0-rc.15", - "@rolldown/binding-linux-s390x-gnu": "1.0.0-rc.15", - "@rolldown/binding-linux-x64-gnu": "1.0.0-rc.15", - "@rolldown/binding-linux-x64-musl": "1.0.0-rc.15", - "@rolldown/binding-openharmony-arm64": "1.0.0-rc.15", - "@rolldown/binding-wasm32-wasi": "1.0.0-rc.15", - "@rolldown/binding-win32-arm64-msvc": "1.0.0-rc.15", - "@rolldown/binding-win32-x64-msvc": "1.0.0-rc.15" + "@rolldown/binding-android-arm64": "1.0.0-rc.16", + "@rolldown/binding-darwin-arm64": "1.0.0-rc.16", + "@rolldown/binding-darwin-x64": "1.0.0-rc.16", + "@rolldown/binding-freebsd-x64": "1.0.0-rc.16", + "@rolldown/binding-linux-arm-gnueabihf": "1.0.0-rc.16", + "@rolldown/binding-linux-arm64-gnu": "1.0.0-rc.16", + "@rolldown/binding-linux-arm64-musl": "1.0.0-rc.16", + "@rolldown/binding-linux-ppc64-gnu": "1.0.0-rc.16", + "@rolldown/binding-linux-s390x-gnu": "1.0.0-rc.16", + "@rolldown/binding-linux-x64-gnu": "1.0.0-rc.16", + "@rolldown/binding-linux-x64-musl": "1.0.0-rc.16", + "@rolldown/binding-openharmony-arm64": "1.0.0-rc.16", + "@rolldown/binding-wasm32-wasi": "1.0.0-rc.16", + "@rolldown/binding-win32-arm64-msvc": "1.0.0-rc.16", + "@rolldown/binding-win32-x64-msvc": "1.0.0-rc.16" } }, "node_modules/saxes": { @@ -1461,14 +1461,14 @@ } }, "node_modules/tinyglobby": { - "version": "0.2.15", - "resolved": "https://registry.npmjs.org/tinyglobby/-/tinyglobby-0.2.15.tgz", - "integrity": "sha512-j2Zq4NyQYG5XMST4cbs02Ak8iJUdxRM0XI5QyxXuZOzKOINmWurp3smXu3y5wDcJrptwpSjgXHzIQxR0omXljQ==", + "version": "0.2.16", + "resolved": "https://registry.npmjs.org/tinyglobby/-/tinyglobby-0.2.16.tgz", + "integrity": "sha512-pn99VhoACYR8nFHhxqix+uvsbXineAasWm5ojXoN8xEwK5Kd3/TrhNn1wByuD52UxWRLy8pu+kRMniEi6Eq9Zg==", "dev": true, "license": "MIT", "dependencies": { "fdir": "^6.5.0", - "picomatch": "^4.0.3" + "picomatch": "^4.0.4" }, "engines": { "node": ">=12.0.0" @@ -1542,9 +1542,9 @@ "optional": true }, "node_modules/typescript": { - "version": "6.0.2", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-6.0.2.tgz", - "integrity": "sha512-bGdAIrZ0wiGDo5l8c++HWtbaNCWTS4UTv7RaTH/ThVIgjkveJt83m74bBHMJkuCbslY8ixgLBVZJIOiQlQTjfQ==", + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-6.0.3.tgz", + "integrity": "sha512-y2TvuxSZPDyQakkFRPZHKFm+KKVqIisdg9/CZwm9ftvKXLP8NRWj38/ODjNbr43SsoXqNuAisEf1GdCxqWcdBw==", "dev": true, "license": "Apache-2.0", "bin": { @@ -1573,17 +1573,17 @@ "license": "MIT" }, "node_modules/vite": { - "version": "8.0.8", - "resolved": "https://registry.npmjs.org/vite/-/vite-8.0.8.tgz", - "integrity": "sha512-dbU7/iLVa8KZALJyLOBOQ88nOXtNG8vxKuOT4I2mD+Ya70KPceF4IAmDsmU0h1Qsn5bPrvsY9HJstCRh3hG6Uw==", + "version": "8.0.9", + "resolved": "https://registry.npmjs.org/vite/-/vite-8.0.9.tgz", + "integrity": "sha512-t7g7GVRpMXjNpa67HaVWI/8BWtdVIQPCL2WoozXXA7LBGEFK4AkkKkHx2hAQf5x1GZSlcmEDPkVLSGahxnEEZw==", "dev": true, "license": "MIT", "dependencies": { "lightningcss": "^1.32.0", "picomatch": "^4.0.4", - "postcss": "^8.5.8", - "rolldown": "1.0.0-rc.15", - "tinyglobby": "^0.2.15" + "postcss": "^8.5.10", + "rolldown": "1.0.0-rc.16", + "tinyglobby": "^0.2.16" }, "bin": { "vite": "bin/vite.js" diff --git a/Frontend/package.json b/Frontend/package.json index 3b5048d0..eed8d97b 100644 --- a/Frontend/package.json +++ b/Frontend/package.json @@ -18,8 +18,8 @@ "devDependencies": { "@types/node": "^25.6.0", "jsdom": "^29.0.2", - "typescript": "^6.0.2", - "vite": "^8.0.8", + "typescript": "^6.0.3", + "vite": "^8.0.9", "vitest": "^4.1.4" } } From 71b8defe451378f0822b982c8fa2f7bcb6207138 Mon Sep 17 00:00:00 2001 From: Jordon Date: Mon, 20 Apr 2026 17:11:01 +0100 Subject: [PATCH 11/37] Fixed compile issues --- Backend/src/plugins.rs | 2 +- Backend/src/state.rs | 6 ++---- Backend/src/tauri_commands/repo_files.rs | 2 +- Backend/src/themes.rs | 2 +- 4 files changed, 5 insertions(+), 7 deletions(-) diff --git a/Backend/src/plugins.rs b/Backend/src/plugins.rs index a3dc660f..5136f70b 100644 --- a/Backend/src/plugins.rs +++ b/Backend/src/plugins.rs @@ -281,7 +281,7 @@ impl PluginCache { } } - summaries.sort_by(|a, b| a.name.to_lowercase().cmp(&b.name.to_lowercase())); + summaries.sort_by_key(|a| a.name.to_lowercase()); let mut data = self.data.write().unwrap(); data.list = summaries; data.entries = entries; diff --git a/Backend/src/state.rs b/Backend/src/state.rs index 46452e94..5d687d09 100644 --- a/Backend/src/state.rs +++ b/Backend/src/state.rs @@ -311,10 +311,8 @@ fn load_recents_from_disk() -> Result, String> { if let Ok(serde_json::Value::Array(items)) = serde_json::from_str::(&data) { for it in items { match it { - serde_json::Value::String(s) => { - if !s.trim().is_empty() { - out.push(PathBuf::from(s)); - } + serde_json::Value::String(s) if !s.trim().is_empty() => { + out.push(PathBuf::from(s)); } serde_json::Value::Object(map) => { if let Some(serde_json::Value::String(s)) = map.get("path") { diff --git a/Backend/src/tauri_commands/repo_files.rs b/Backend/src/tauri_commands/repo_files.rs index 4aa4cbd2..7db42002 100644 --- a/Backend/src/tauri_commands/repo_files.rs +++ b/Backend/src/tauri_commands/repo_files.rs @@ -197,7 +197,7 @@ fn decode_repo_text(bytes: &[u8]) -> String { i += 2; } let mut out = String::new(); - for ch in std::char::decode_utf16(u16s.into_iter()) { + for ch in std::char::decode_utf16(u16s) { match ch { Ok(c) => out.push(c), Err(_) => return String::from_utf8_lossy(bytes).to_string(), diff --git a/Backend/src/themes.rs b/Backend/src/themes.rs index deb0ddf8..206bd99a 100644 --- a/Backend/src/themes.rs +++ b/Backend/src/themes.rs @@ -330,7 +330,7 @@ pub fn list_themes() -> Vec { } } - summaries.sort_by(|a, b| a.name.to_lowercase().cmp(&b.name.to_lowercase())); + summaries.sort_by_key(|a| a.name.to_lowercase()); let mut out = Vec::with_capacity(summaries.len() + 1); out.push(default_theme_summary()); From 0e7cebfe5f2b692136d7c496595ed89d4f5ea025 Mon Sep 17 00:00:00 2001 From: Jordon Date: Mon, 20 Apr 2026 18:34:09 +0100 Subject: [PATCH 12/37] Update opencode-review.yml --- .github/workflows/opencode-review.yml | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/.github/workflows/opencode-review.yml b/.github/workflows/opencode-review.yml index 3e2c7ff8..48643b6b 100644 --- a/.github/workflows/opencode-review.yml +++ b/.github/workflows/opencode-review.yml @@ -26,10 +26,10 @@ jobs: env: OPENCODE_API_KEY: ${{ secrets.ZEN_API_KEY }} OPENAI_API_KEY: ${{ secrets.OPENAI_API_KEY }} - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + #GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} with: model: ${{ vars.OPENCODE_REVIEW_MODEL }} - use_github_token: true + #use_github_token: true prompt: | Review this pull request: - Check for code quality issues @@ -42,12 +42,12 @@ jobs: env: OPENCODE_API_KEY: ${{ secrets.ZEN_API_KEY }} OPENAI_API_KEY: ${{ secrets.OPENAI_API_KEY }} - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + #GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} with: model: ${{ vars.OPENCODE_REVIEW_MODEL_FALLBACK }} - use_github_token: true + #use_github_token: true prompt: | Review this pull request: - Check for code quality issues - Look for potential bugs - - Suggest improvements \ No newline at end of file + - Suggest improvements From 1c0863aa0aca19b706e4c1acbcae1c71309f0653 Mon Sep 17 00:00:00 2001 From: "opencode-agent[bot]" Date: Mon, 20 Apr 2026 17:35:13 +0000 Subject: [PATCH 13/37] Fix: remove continue-on-error to enable fallback Co-authored-by: Jordonbc --- .opencode/package-lock.json | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/.opencode/package-lock.json b/.opencode/package-lock.json index ae941df7..4b8761e5 100644 --- a/.opencode/package-lock.json +++ b/.opencode/package-lock.json @@ -5,7 +5,7 @@ "packages": { "": { "dependencies": { - "@opencode-ai/plugin": "1.4.9" + "@opencode-ai/plugin": "1.14.19" } }, "node_modules/@msgpackr-extract/msgpackr-extract-darwin-arm64": { @@ -87,18 +87,18 @@ ] }, "node_modules/@opencode-ai/plugin": { - "version": "1.4.9", - "resolved": "https://registry.npmjs.org/@opencode-ai/plugin/-/plugin-1.4.9.tgz", - "integrity": "sha512-tUtPbPs5xP9wonwuz5d/2y8QTrqFR8HOtAVTXvZ6iG26NJfW0dnnw9oTusVOayEIemd5abytCESm7X9ZZOMftQ==", + "version": "1.14.19", + "resolved": "https://registry.npmjs.org/@opencode-ai/plugin/-/plugin-1.14.19.tgz", + "integrity": "sha512-g0C8Viocybmet7nBqJK/1xrQnacRS1f30VmqRTPScPmWz+4knIZzc2TEQp8+920sN8rB6BuoGwfBUVRXJmavhQ==", "license": "MIT", "dependencies": { - "@opencode-ai/sdk": "1.4.9", + "@opencode-ai/sdk": "1.14.19", "effect": "4.0.0-beta.48", "zod": "4.1.8" }, "peerDependencies": { - "@opentui/core": ">=0.1.100", - "@opentui/solid": ">=0.1.100" + "@opentui/core": ">=0.1.101", + "@opentui/solid": ">=0.1.101" }, "peerDependenciesMeta": { "@opentui/core": { @@ -110,9 +110,9 @@ } }, "node_modules/@opencode-ai/sdk": { - "version": "1.4.9", - "resolved": "https://registry.npmjs.org/@opencode-ai/sdk/-/sdk-1.4.9.tgz", - "integrity": "sha512-S8WQLuBFu2WwvSc1wupsV4qskniBA+JN1VaZZs52BPWwiN2zQFTD5/6dMh6oiYOMDtPjKsTFZ6qLFxDvVPNggQ==", + "version": "1.14.19", + "resolved": "https://registry.npmjs.org/@opencode-ai/sdk/-/sdk-1.14.19.tgz", + "integrity": "sha512-9sTGsi8/HlBBeaWfsUjdJ2yi/SqpRvqSld0IFXc3ldaPb1w1uIPvgCGzhlHYQtqatXxSaX5lTN7zpudMaE21aw==", "license": "MIT", "dependencies": { "cross-spawn": "7.0.6" From eaed4b3936fc45ba3130f8018d4027ed5501d42c Mon Sep 17 00:00:00 2001 From: Jordon Date: Mon, 20 Apr 2026 18:44:35 +0100 Subject: [PATCH 14/37] Fix issues --- .gitignore | 1 + .opencode/package-lock.json | 376 ------------------------------------ 2 files changed, 1 insertion(+), 376 deletions(-) delete mode 100644 .opencode/package-lock.json diff --git a/.gitignore b/.gitignore index fff1e6ec..0eb5d6e4 100644 --- a/.gitignore +++ b/.gitignore @@ -27,3 +27,4 @@ dist-ssr /Backend/icons/ios /Core .env.tauri.local +.opencode/ diff --git a/.opencode/package-lock.json b/.opencode/package-lock.json deleted file mode 100644 index 4b8761e5..00000000 --- a/.opencode/package-lock.json +++ /dev/null @@ -1,376 +0,0 @@ -{ - "name": ".opencode", - "lockfileVersion": 3, - "requires": true, - "packages": { - "": { - "dependencies": { - "@opencode-ai/plugin": "1.14.19" - } - }, - "node_modules/@msgpackr-extract/msgpackr-extract-darwin-arm64": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/@msgpackr-extract/msgpackr-extract-darwin-arm64/-/msgpackr-extract-darwin-arm64-3.0.3.tgz", - "integrity": "sha512-QZHtlVgbAdy2zAqNA9Gu1UpIuI8Xvsd1v8ic6B2pZmeFnFcMWiPLfWXh7TVw4eGEZ/C9TH281KwhVoeQUKbyjw==", - "cpu": [ - "arm64" - ], - "license": "MIT", - "optional": true, - "os": [ - "darwin" - ] - }, - "node_modules/@msgpackr-extract/msgpackr-extract-darwin-x64": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/@msgpackr-extract/msgpackr-extract-darwin-x64/-/msgpackr-extract-darwin-x64-3.0.3.tgz", - "integrity": "sha512-mdzd3AVzYKuUmiWOQ8GNhl64/IoFGol569zNRdkLReh6LRLHOXxU4U8eq0JwaD8iFHdVGqSy4IjFL4reoWCDFw==", - "cpu": [ - "x64" - ], - "license": "MIT", - "optional": true, - "os": [ - "darwin" - ] - }, - "node_modules/@msgpackr-extract/msgpackr-extract-linux-arm": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/@msgpackr-extract/msgpackr-extract-linux-arm/-/msgpackr-extract-linux-arm-3.0.3.tgz", - "integrity": "sha512-fg0uy/dG/nZEXfYilKoRe7yALaNmHoYeIoJuJ7KJ+YyU2bvY8vPv27f7UKhGRpY6euFYqEVhxCFZgAUNQBM3nw==", - "cpu": [ - "arm" - ], - "license": "MIT", - "optional": true, - "os": [ - "linux" - ] - }, - "node_modules/@msgpackr-extract/msgpackr-extract-linux-arm64": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/@msgpackr-extract/msgpackr-extract-linux-arm64/-/msgpackr-extract-linux-arm64-3.0.3.tgz", - "integrity": "sha512-YxQL+ax0XqBJDZiKimS2XQaf+2wDGVa1enVRGzEvLLVFeqa5kx2bWbtcSXgsxjQB7nRqqIGFIcLteF/sHeVtQg==", - "cpu": [ - "arm64" - ], - "license": "MIT", - "optional": true, - "os": [ - "linux" - ] - }, - "node_modules/@msgpackr-extract/msgpackr-extract-linux-x64": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/@msgpackr-extract/msgpackr-extract-linux-x64/-/msgpackr-extract-linux-x64-3.0.3.tgz", - "integrity": "sha512-cvwNfbP07pKUfq1uH+S6KJ7dT9K8WOE4ZiAcsrSes+UY55E/0jLYc+vq+DO7jlmqRb5zAggExKm0H7O/CBaesg==", - "cpu": [ - "x64" - ], - "license": "MIT", - "optional": true, - "os": [ - "linux" - ] - }, - "node_modules/@msgpackr-extract/msgpackr-extract-win32-x64": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/@msgpackr-extract/msgpackr-extract-win32-x64/-/msgpackr-extract-win32-x64-3.0.3.tgz", - "integrity": "sha512-x0fWaQtYp4E6sktbsdAqnehxDgEc/VwM7uLsRCYWaiGu0ykYdZPiS8zCWdnjHwyiumousxfBm4SO31eXqwEZhQ==", - "cpu": [ - "x64" - ], - "license": "MIT", - "optional": true, - "os": [ - "win32" - ] - }, - "node_modules/@opencode-ai/plugin": { - "version": "1.14.19", - "resolved": "https://registry.npmjs.org/@opencode-ai/plugin/-/plugin-1.14.19.tgz", - "integrity": "sha512-g0C8Viocybmet7nBqJK/1xrQnacRS1f30VmqRTPScPmWz+4knIZzc2TEQp8+920sN8rB6BuoGwfBUVRXJmavhQ==", - "license": "MIT", - "dependencies": { - "@opencode-ai/sdk": "1.14.19", - "effect": "4.0.0-beta.48", - "zod": "4.1.8" - }, - "peerDependencies": { - "@opentui/core": ">=0.1.101", - "@opentui/solid": ">=0.1.101" - }, - "peerDependenciesMeta": { - "@opentui/core": { - "optional": true - }, - "@opentui/solid": { - "optional": true - } - } - }, - "node_modules/@opencode-ai/sdk": { - "version": "1.14.19", - "resolved": "https://registry.npmjs.org/@opencode-ai/sdk/-/sdk-1.14.19.tgz", - "integrity": "sha512-9sTGsi8/HlBBeaWfsUjdJ2yi/SqpRvqSld0IFXc3ldaPb1w1uIPvgCGzhlHYQtqatXxSaX5lTN7zpudMaE21aw==", - "license": "MIT", - "dependencies": { - "cross-spawn": "7.0.6" - } - }, - "node_modules/@standard-schema/spec": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/@standard-schema/spec/-/spec-1.1.0.tgz", - "integrity": "sha512-l2aFy5jALhniG5HgqrD6jXLi/rUWrKvqN/qJx6yoJsgKhblVd+iqqU4RCXavm/jPityDo5TCvKMnpjKnOriy0w==", - "license": "MIT" - }, - "node_modules/cross-spawn": { - "version": "7.0.6", - "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.6.tgz", - "integrity": "sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==", - "license": "MIT", - "dependencies": { - "path-key": "^3.1.0", - "shebang-command": "^2.0.0", - "which": "^2.0.1" - }, - "engines": { - "node": ">= 8" - } - }, - "node_modules/detect-libc": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-2.1.2.tgz", - "integrity": "sha512-Btj2BOOO83o3WyH59e8MgXsxEQVcarkUOpEYrubB0urwnN10yQ364rsiByU11nZlqWYZm05i/of7io4mzihBtQ==", - "license": "Apache-2.0", - "optional": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/effect": { - "version": "4.0.0-beta.48", - "resolved": "https://registry.npmjs.org/effect/-/effect-4.0.0-beta.48.tgz", - "integrity": "sha512-MMAM/ZabuNdNmgXiin+BAanQXK7qM8mlt7nfXDoJ/Gn9V8i89JlCq+2N0AiWmqFLXjGLA0u3FjiOjSOYQk5uMw==", - "license": "MIT", - "dependencies": { - "@standard-schema/spec": "^1.1.0", - "fast-check": "^4.6.0", - "find-my-way-ts": "^0.1.6", - "ini": "^6.0.0", - "kubernetes-types": "^1.30.0", - "msgpackr": "^1.11.9", - "multipasta": "^0.2.7", - "toml": "^4.1.1", - "uuid": "^13.0.0", - "yaml": "^2.8.3" - } - }, - "node_modules/fast-check": { - "version": "4.7.0", - "resolved": "https://registry.npmjs.org/fast-check/-/fast-check-4.7.0.tgz", - "integrity": "sha512-NsZRtqvSSoCP0HbNjUD+r1JH8zqZalyp6gLY9e7OYs7NK9b6AHOs2baBFeBG7bVNsuoukh89x2Yg3rPsul8ziQ==", - "funding": [ - { - "type": "individual", - "url": "https://github.com/sponsors/dubzzz" - }, - { - "type": "opencollective", - "url": "https://opencollective.com/fast-check" - } - ], - "license": "MIT", - "dependencies": { - "pure-rand": "^8.0.0" - }, - "engines": { - "node": ">=12.17.0" - } - }, - "node_modules/find-my-way-ts": { - "version": "0.1.6", - "resolved": "https://registry.npmjs.org/find-my-way-ts/-/find-my-way-ts-0.1.6.tgz", - "integrity": "sha512-a85L9ZoXtNAey3Y6Z+eBWW658kO/MwR7zIafkIUPUMf3isZG0NCs2pjW2wtjxAKuJPxMAsHUIP4ZPGv0o5gyTA==", - "license": "MIT" - }, - "node_modules/ini": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/ini/-/ini-6.0.0.tgz", - "integrity": "sha512-IBTdIkzZNOpqm7q3dRqJvMaldXjDHWkEDfrwGEQTs5eaQMWV+djAhR+wahyNNMAa+qpbDUhBMVt4ZKNwpPm7xQ==", - "license": "ISC", - "engines": { - "node": "^20.17.0 || >=22.9.0" - } - }, - "node_modules/isexe": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", - "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==", - "license": "ISC" - }, - "node_modules/kubernetes-types": { - "version": "1.30.0", - "resolved": "https://registry.npmjs.org/kubernetes-types/-/kubernetes-types-1.30.0.tgz", - "integrity": "sha512-Dew1okvhM/SQcIa2rcgujNndZwU8VnSapDgdxlYoB84ZlpAD43U6KLAFqYo17ykSFGHNPrg0qry0bP+GJd9v7Q==", - "license": "Apache-2.0" - }, - "node_modules/msgpackr": { - "version": "1.11.9", - "resolved": "https://registry.npmjs.org/msgpackr/-/msgpackr-1.11.9.tgz", - "integrity": "sha512-FkoAAyyA6HM8wL882EcEyFZ9s7hVADSwG9xrVx3dxxNQAtgADTrJoEWivID82Iv1zWDsv/OtbrrcZAzGzOMdNw==", - "license": "MIT", - "optionalDependencies": { - "msgpackr-extract": "^3.0.2" - } - }, - "node_modules/msgpackr-extract": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/msgpackr-extract/-/msgpackr-extract-3.0.3.tgz", - "integrity": "sha512-P0efT1C9jIdVRefqjzOQ9Xml57zpOXnIuS+csaB4MdZbTdmGDLo8XhzBG1N7aO11gKDDkJvBLULeFTo46wwreA==", - "hasInstallScript": true, - "license": "MIT", - "optional": true, - "dependencies": { - "node-gyp-build-optional-packages": "5.2.2" - }, - "bin": { - "download-msgpackr-prebuilds": "bin/download-prebuilds.js" - }, - "optionalDependencies": { - "@msgpackr-extract/msgpackr-extract-darwin-arm64": "3.0.3", - "@msgpackr-extract/msgpackr-extract-darwin-x64": "3.0.3", - "@msgpackr-extract/msgpackr-extract-linux-arm": "3.0.3", - "@msgpackr-extract/msgpackr-extract-linux-arm64": "3.0.3", - "@msgpackr-extract/msgpackr-extract-linux-x64": "3.0.3", - "@msgpackr-extract/msgpackr-extract-win32-x64": "3.0.3" - } - }, - "node_modules/multipasta": { - "version": "0.2.7", - "resolved": "https://registry.npmjs.org/multipasta/-/multipasta-0.2.7.tgz", - "integrity": "sha512-KPA58d68KgGil15oDqXjkUBEBYc00XvbPj5/X+dyzeo/lWm9Nc25pQRlf1D+gv4OpK7NM0J1odrbu9JNNGvynA==", - "license": "MIT" - }, - "node_modules/node-gyp-build-optional-packages": { - "version": "5.2.2", - "resolved": "https://registry.npmjs.org/node-gyp-build-optional-packages/-/node-gyp-build-optional-packages-5.2.2.tgz", - "integrity": "sha512-s+w+rBWnpTMwSFbaE0UXsRlg7hU4FjekKU4eyAih5T8nJuNZT1nNsskXpxmeqSK9UzkBl6UgRlnKc8hz8IEqOw==", - "license": "MIT", - "optional": true, - "dependencies": { - "detect-libc": "^2.0.1" - }, - "bin": { - "node-gyp-build-optional-packages": "bin.js", - "node-gyp-build-optional-packages-optional": "optional.js", - "node-gyp-build-optional-packages-test": "build-test.js" - } - }, - "node_modules/path-key": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", - "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", - "license": "MIT", - "engines": { - "node": ">=8" - } - }, - "node_modules/pure-rand": { - "version": "8.4.0", - "resolved": "https://registry.npmjs.org/pure-rand/-/pure-rand-8.4.0.tgz", - "integrity": "sha512-IoM8YF/jY0hiugFo/wOWqfmarlE6J0wc6fDK1PhftMk7MGhVZl88sZimmqBBFomLOCSmcCCpsfj7wXASCpvK9A==", - "funding": [ - { - "type": "individual", - "url": "https://github.com/sponsors/dubzzz" - }, - { - "type": "opencollective", - "url": "https://opencollective.com/fast-check" - } - ], - "license": "MIT" - }, - "node_modules/shebang-command": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", - "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", - "license": "MIT", - "dependencies": { - "shebang-regex": "^3.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/shebang-regex": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", - "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", - "license": "MIT", - "engines": { - "node": ">=8" - } - }, - "node_modules/toml": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/toml/-/toml-4.1.1.tgz", - "integrity": "sha512-EBJnVBr3dTXdA89WVFoAIPUqkBjxPMwRqsfuo1r240tKFHXv3zgca4+NJib/h6TyvGF7vOawz0jGuryJCdNHrw==", - "license": "MIT", - "engines": { - "node": ">=20" - } - }, - "node_modules/uuid": { - "version": "13.0.0", - "resolved": "https://registry.npmjs.org/uuid/-/uuid-13.0.0.tgz", - "integrity": "sha512-XQegIaBTVUjSHliKqcnFqYypAd4S+WCYt5NIeRs6w/UAry7z8Y9j5ZwRRL4kzq9U3sD6v+85er9FvkEaBpji2w==", - "funding": [ - "https://github.com/sponsors/broofa", - "https://github.com/sponsors/ctavan" - ], - "license": "MIT", - "bin": { - "uuid": "dist-node/bin/uuid" - } - }, - "node_modules/which": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", - "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", - "license": "ISC", - "dependencies": { - "isexe": "^2.0.0" - }, - "bin": { - "node-which": "bin/node-which" - }, - "engines": { - "node": ">= 8" - } - }, - "node_modules/yaml": { - "version": "2.8.3", - "resolved": "https://registry.npmjs.org/yaml/-/yaml-2.8.3.tgz", - "integrity": "sha512-AvbaCLOO2Otw/lW5bmh9d/WEdcDFdQp2Z2ZUH3pX9U2ihyUY0nvLv7J6TrWowklRGPYbB/IuIMfYgxaCPg5Bpg==", - "license": "ISC", - "bin": { - "yaml": "bin.mjs" - }, - "engines": { - "node": ">= 14.6" - }, - "funding": { - "url": "https://github.com/sponsors/eemeli" - } - }, - "node_modules/zod": { - "version": "4.1.8", - "license": "MIT", - "funding": { - "url": "https://github.com/sponsors/colinhacks" - } - } - } -} From 8026a8e7c3be4cade86ecea02db3c32d95139950 Mon Sep 17 00:00:00 2001 From: Jordon Date: Mon, 20 Apr 2026 18:52:30 +0100 Subject: [PATCH 15/37] Update confirmModal.ts --- Frontend/src/scripts/features/confirmModal.ts | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/Frontend/src/scripts/features/confirmModal.ts b/Frontend/src/scripts/features/confirmModal.ts index 5be97641..75f986dc 100644 --- a/Frontend/src/scripts/features/confirmModal.ts +++ b/Frontend/src/scripts/features/confirmModal.ts @@ -87,8 +87,9 @@ export function confirmWithModal(opts: ConfirmModalOptions): Promise { modal?.setContent?.(opts); return new Promise((resolve) => { - resolvePending(false); + const previousResolve = pendingResolve; pendingResolve = resolve; + previousResolve?.(false); openModal('confirm-modal'); }); } From f1b82c43c125a56ca999cf2d7e1df3c7f62ffeb9 Mon Sep 17 00:00:00 2001 From: Jordon Date: Mon, 20 Apr 2026 18:58:19 +0100 Subject: [PATCH 16/37] Update confirm.test.ts --- Frontend/src/scripts/lib/confirm.test.ts | 19 ++++++++++++------- 1 file changed, 12 insertions(+), 7 deletions(-) diff --git a/Frontend/src/scripts/lib/confirm.test.ts b/Frontend/src/scripts/lib/confirm.test.ts index 73f6c2c0..4de7b243 100644 --- a/Frontend/src/scripts/lib/confirm.test.ts +++ b/Frontend/src/scripts/lib/confirm.test.ts @@ -1,21 +1,26 @@ // Copyright © 2025-2026 OpenVCS Contributors // SPDX-License-Identifier: GPL-3.0-or-later -import { afterEach, describe, expect, it, vi } from 'vitest'; +import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest'; import { confirmBool } from './confirm'; -const originalConfirm = window.confirm; +let originalConfirmDescriptor: PropertyDescriptor | undefined; + +/** Snapshots the current global confirm descriptor before each test. */ +beforeEach(() => { + originalConfirmDescriptor = Object.getOwnPropertyDescriptor(window, 'confirm'); +}); /** Restores the original global confirm implementation after each test. */ afterEach(() => { document.body.innerHTML = ''; vi.restoreAllMocks(); - Object.defineProperty(window, 'confirm', { - configurable: true, - writable: true, - value: originalConfirm, - }); + if (originalConfirmDescriptor) { + Object.defineProperty(window, 'confirm', originalConfirmDescriptor); + return; + } + Reflect.deleteProperty(window as unknown as Record, 'confirm'); }); describe('confirmBool', () => { From 2ea24d8db3fca69a89c4bb0bb3afeb954d2a9e4a Mon Sep 17 00:00:00 2001 From: Jordon Date: Mon, 20 Apr 2026 18:58:22 +0100 Subject: [PATCH 17/37] Update main.ts --- Frontend/src/scripts/main.ts | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/Frontend/src/scripts/main.ts b/Frontend/src/scripts/main.ts index f87898e5..37624777 100644 --- a/Frontend/src/scripts/main.ts +++ b/Frontend/src/scripts/main.ts @@ -42,9 +42,12 @@ const commitBtn = qs('#commit-btn'); const undoLeftBtn = qs('#undo-left-btn'); let fetchCloseTimer: number | null = null; let pluginMenuRefreshTimer: number | null = null; + /** Matches the fetch popover close animation so the element hides after the transition finishes. */ const FETCH_CLOSE_MS = 130; + /** Gives repo-open plugin state time to settle before rebuilding contributed menubar items. */ + const PLUGIN_MENU_REFRESH_SETTLE_MS = 400; - /** Schedules a delayed plugin menubar refresh to avoid repo-open races. */ + /** Schedules a delayed plugin menubar refresh to avoid repo-open races while plugin state settles. */ function schedulePluginMenuRefresh(delayMs = 250) { if (pluginMenuRefreshTimer !== null) { window.clearTimeout(pluginMenuRefreshTimer); @@ -452,7 +455,7 @@ async function boot() { initMenubar(runMenuAction); refreshPluginMenubarMenus().catch(() => {}); - schedulePluginMenuRefresh(400); + schedulePluginMenuRefresh(PLUGIN_MENU_REFRESH_SETTLE_MS); TAURI.listen?.('menu', async ({ payload: id }) => { const resolved = typeof id === 'string' ? id : String(id ?? ''); From bf0b2f57d94aaa72b175584850ca1eece5f2bc67 Mon Sep 17 00:00:00 2001 From: Jordon Date: Mon, 20 Apr 2026 19:12:13 +0100 Subject: [PATCH 18/37] Update confirmModal.ts --- Frontend/src/scripts/features/confirmModal.ts | 11 +---------- 1 file changed, 1 insertion(+), 10 deletions(-) diff --git a/Frontend/src/scripts/features/confirmModal.ts b/Frontend/src/scripts/features/confirmModal.ts index 75f986dc..e3d42971 100644 --- a/Frontend/src/scripts/features/confirmModal.ts +++ b/Frontend/src/scripts/features/confirmModal.ts @@ -40,16 +40,7 @@ export function wireConfirmModal() { const cancelBtn = modal.querySelector('#confirm-modal-cancel-btn'); const confirmBtn = modal.querySelector('#confirm-modal-confirm-btn'); - modal.addEventListener('click', (event) => { - const target = event.target as HTMLElement; - const wantsClose = target.classList?.contains('backdrop') || !!target.closest('[data-close]'); - if (wantsClose) resolvePending(false); - }); - - document.addEventListener('keydown', (event) => { - if (event.key !== 'Escape') return; - const current = getModal(); - if (!current || current.getAttribute('aria-hidden') !== 'false') return; + modal.addEventListener('modal:closed', () => { resolvePending(false); }); From 9adc0e604afc6681d420ff95f24754879d8fb84f Mon Sep 17 00:00:00 2001 From: Jordon Date: Mon, 20 Apr 2026 19:12:15 +0100 Subject: [PATCH 19/37] Update modals.ts --- Frontend/src/scripts/ui/modals.ts | 24 ++++++++++++++++++++---- 1 file changed, 20 insertions(+), 4 deletions(-) diff --git a/Frontend/src/scripts/ui/modals.ts b/Frontend/src/scripts/ui/modals.ts index 45521fbc..51ebed53 100644 --- a/Frontend/src/scripts/ui/modals.ts +++ b/Frontend/src/scripts/ui/modals.ts @@ -72,6 +72,22 @@ function unlockScroll() { if (openCount === 0) document.body.style.overflow = ""; } +/** Updates a modal's hidden state and emits lifecycle events when visibility changes. */ +function setModalHidden(el: HTMLElement, hidden: boolean) { + const wasHidden = el.getAttribute("aria-hidden") !== "false"; + const nextHidden = hidden ? "true" : "false"; + if (el.getAttribute("aria-hidden") !== nextHidden) { + el.setAttribute("aria-hidden", nextHidden); + } + if (!hidden && wasHidden) { + el.dispatchEvent(new CustomEvent("modal:opened")); + } + if (hidden && !wasHidden) { + el.dispatchEvent(new CustomEvent("modal:closed")); + } + return wasHidden; +} + function closeWithAnimation(id: string, el: HTMLElement) { const reduceMotion = window.matchMedia("(prefers-reduced-motion: reduce)").matches; if (reduceMotion) { @@ -141,8 +157,8 @@ export function openModal(id: string): void { window.clearTimeout(existing); (el as any).__animatedCloseTimer = undefined; } - el.setAttribute("aria-hidden", "false"); - lockScroll(); + const wasHidden = setModalHidden(el, false); + if (wasHidden) lockScroll(); refreshOverlayScrollbarsFor(el); // Click-to-close once @@ -161,7 +177,7 @@ export function closeModal(id: string): void { const el = document.getElementById(id); if (!el) return; if (el.getAttribute("aria-hidden") !== "true") { - el.setAttribute("aria-hidden", "true"); + setModalHidden(el, true); unlockScroll(); } } @@ -177,7 +193,7 @@ export function closeAllModals(): void { (el as any).__animatedCloseTimer = undefined; } el.classList.remove("is-closing"); - el.setAttribute("aria-hidden", "true"); + setModalHidden(el, true); } openCount = 0; document.body.style.overflow = ""; From dce8f1f8572a1230daf26c66db854091c7c32875 Mon Sep 17 00:00:00 2001 From: Jordon Date: Mon, 20 Apr 2026 19:47:02 +0100 Subject: [PATCH 20/37] Update package-lock.json --- Frontend/package-lock.json | 302 +++++++++++++++++++++---------------- 1 file changed, 172 insertions(+), 130 deletions(-) diff --git a/Frontend/package-lock.json b/Frontend/package-lock.json index b5fe5908..6152690c 100644 --- a/Frontend/package-lock.json +++ b/Frontend/package-lock.json @@ -20,14 +20,15 @@ } }, "node_modules/@asamuzakjp/css-color": { - "version": "5.1.10", - "resolved": "https://registry.npmjs.org/@asamuzakjp/css-color/-/css-color-5.1.10.tgz", - "integrity": "sha512-02OhhkKtgNRuicQ/nF3TRnGsxL9wp0r3Y7VlKWyOHHGmGyvXv03y+PnymU8FKFJMTjIr1Bk8U2g1HWSLrpAHww==", + "version": "5.1.11", + "resolved": "https://registry.npmjs.org/@asamuzakjp/css-color/-/css-color-5.1.11.tgz", + "integrity": "sha512-KVw6qIiCTUQhByfTd78h2yD1/00waTmm9uy/R7Ck/ctUyAPj+AEDLkQIdJW0T8+qGgj3j5bpNKK7Q3G+LedJWg==", "dev": true, "license": "MIT", "dependencies": { - "@csstools/css-calc": "^3.1.1", - "@csstools/css-color-parser": "^4.0.2", + "@asamuzakjp/generational-cache": "^1.0.1", + "@csstools/css-calc": "^3.2.0", + "@csstools/css-color-parser": "^4.1.0", "@csstools/css-parser-algorithms": "^4.0.0", "@csstools/css-tokenizer": "^4.0.0" }, @@ -36,12 +37,13 @@ } }, "node_modules/@asamuzakjp/dom-selector": { - "version": "7.0.9", - "resolved": "https://registry.npmjs.org/@asamuzakjp/dom-selector/-/dom-selector-7.0.9.tgz", - "integrity": "sha512-r3ElRr7y8ucyN2KdICwGsmj19RoN13CLCa/pvGydghWK6ZzeKQ+TcDjVdtEZz2ElpndM5jXw//B9CEee0mWnVg==", + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/@asamuzakjp/dom-selector/-/dom-selector-7.1.1.tgz", + "integrity": "sha512-67RZDnYRc8H/8MLDgQCDE//zoqVFwajkepHZgmXrbwybzXOEwOWGPYGmALYl9J2DOLfFPPs6kKCqmbzV895hTQ==", "dev": true, "license": "MIT", "dependencies": { + "@asamuzakjp/generational-cache": "^1.0.1", "@asamuzakjp/nwsapi": "^2.3.9", "bidi-js": "^1.0.3", "css-tree": "^3.2.1", @@ -51,6 +53,16 @@ "node": "^20.19.0 || ^22.12.0 || >=24.0.0" } }, + "node_modules/@asamuzakjp/generational-cache": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@asamuzakjp/generational-cache/-/generational-cache-1.0.1.tgz", + "integrity": "sha512-wajfB8KqzMCN2KGNFdLkReeHncd0AslUSrvHVvvYWuU8ghncRJoA50kT3zP9MVL0+9g4/67H+cdvBskj9THPzg==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^20.19.0 || ^22.12.0 || >=24.0.0" + } + }, "node_modules/@asamuzakjp/nwsapi": { "version": "2.3.9", "resolved": "https://registry.npmjs.org/@asamuzakjp/nwsapi/-/nwsapi-2.3.9.tgz", @@ -167,9 +179,9 @@ } }, "node_modules/@csstools/css-syntax-patches-for-csstree": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/@csstools/css-syntax-patches-for-csstree/-/css-syntax-patches-for-csstree-1.1.1.tgz", - "integrity": "sha512-BvqN0AMWNAnLk9G8jnUT77D+mUbY/H2b3uDTvg2isJkHaOufUE2R3AOwxWo7VBQKT1lOdwdvorddo2B/lk64+w==", + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/@csstools/css-syntax-patches-for-csstree/-/css-syntax-patches-for-csstree-1.1.3.tgz", + "integrity": "sha512-SH60bMfrRCJF3morcdk57WklujF4Jr/EsQUzqkarfHXEFcAR1gg7fS/chAE922Sehgzc1/+Tz5H3Ypa1HiEKrg==", "dev": true, "funding": [ { @@ -271,9 +283,9 @@ "license": "MIT" }, "node_modules/@napi-rs/wasm-runtime": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/@napi-rs/wasm-runtime/-/wasm-runtime-1.1.3.tgz", - "integrity": "sha512-xK9sGVbJWYb08+mTJt3/YV24WxvxpXcXtP6B172paPZ+Ts69Re9dAr7lKwJoeIx8OoeuimEiRZ7umkiUVClmmQ==", + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/@napi-rs/wasm-runtime/-/wasm-runtime-1.1.4.tgz", + "integrity": "sha512-3NQNNgA1YSlJb/kMH1ildASP9HW7/7kYnRI2szWJaofaS1hWmbGI4H+d3+22aGzXXN9IJ+n+GiFVcGipJP18ow==", "dev": true, "license": "MIT", "optional": true, @@ -290,9 +302,9 @@ } }, "node_modules/@oxc-project/types": { - "version": "0.124.0", - "resolved": "https://registry.npmjs.org/@oxc-project/types/-/types-0.124.0.tgz", - "integrity": "sha512-VBFWMTBvHxS11Z5Lvlr3IWgrwhMTXV+Md+EQF0Xf60+wAdsGFTBx7X7K/hP4pi8N7dcm1RvcHwDxZ16Qx8keUg==", + "version": "0.126.0", + "resolved": "https://registry.npmjs.org/@oxc-project/types/-/types-0.126.0.tgz", + "integrity": "sha512-oGfVtjAgwQVVpfBrbtk4e1XDyWHRFta6BS3GWVzrF8xYBT2VGQAk39yJS/wFSMrZqoiCU4oghT3Ch0HaHGIHcQ==", "dev": true, "license": "MIT", "funding": { @@ -300,9 +312,9 @@ } }, "node_modules/@rolldown/binding-android-arm64": { - "version": "1.0.0-rc.15", - "resolved": "https://registry.npmjs.org/@rolldown/binding-android-arm64/-/binding-android-arm64-1.0.0-rc.15.tgz", - "integrity": "sha512-YYe6aWruPZDtHNpwu7+qAHEMbQ/yRl6atqb/AhznLTnD3UY99Q1jE7ihLSahNWkF4EqRPVC4SiR4O0UkLK02tA==", + "version": "1.0.0-rc.16", + "resolved": "https://registry.npmjs.org/@rolldown/binding-android-arm64/-/binding-android-arm64-1.0.0-rc.16.tgz", + "integrity": "sha512-rhY3k7Bsae9qQfOtph2Pm2jZEA+s8Gmjoz4hhmx70K9iMQ/ddeae+xhRQcM5IuVx5ry1+bGfkvMn7D6MJggVSA==", "cpu": [ "arm64" ], @@ -317,9 +329,9 @@ } }, "node_modules/@rolldown/binding-darwin-arm64": { - "version": "1.0.0-rc.15", - "resolved": "https://registry.npmjs.org/@rolldown/binding-darwin-arm64/-/binding-darwin-arm64-1.0.0-rc.15.tgz", - "integrity": "sha512-oArR/ig8wNTPYsXL+Mzhs0oxhxfuHRfG7Ikw7jXsw8mYOtk71W0OkF2VEVh699pdmzjPQsTjlD1JIOoHkLP1Fg==", + "version": "1.0.0-rc.16", + "resolved": "https://registry.npmjs.org/@rolldown/binding-darwin-arm64/-/binding-darwin-arm64-1.0.0-rc.16.tgz", + "integrity": "sha512-rNz0yK078yrNn3DrdgN+PKiMOW8HfQ92jQiXxwX8yW899ayV00MLVdaCNeVBhG/TbH3ouYVObo8/yrkiectkcQ==", "cpu": [ "arm64" ], @@ -334,9 +346,9 @@ } }, "node_modules/@rolldown/binding-darwin-x64": { - "version": "1.0.0-rc.15", - "resolved": "https://registry.npmjs.org/@rolldown/binding-darwin-x64/-/binding-darwin-x64-1.0.0-rc.15.tgz", - "integrity": "sha512-YzeVqOqjPYvUbJSWJ4EDL8ahbmsIXQpgL3JVipmN+MX0XnXMeWomLN3Fb+nwCmP/jfyqte5I3XRSm7OfQrbyxw==", + "version": "1.0.0-rc.16", + "resolved": "https://registry.npmjs.org/@rolldown/binding-darwin-x64/-/binding-darwin-x64-1.0.0-rc.16.tgz", + "integrity": "sha512-r/OmdR00HmD4i79Z//xO06uEPOq5hRXdhw7nzkxQxwSavs3PSHa1ijntdpOiZ2mzOQ3fVVu8C1M19FoNM+dMUQ==", "cpu": [ "x64" ], @@ -351,9 +363,9 @@ } }, "node_modules/@rolldown/binding-freebsd-x64": { - "version": "1.0.0-rc.15", - "resolved": "https://registry.npmjs.org/@rolldown/binding-freebsd-x64/-/binding-freebsd-x64-1.0.0-rc.15.tgz", - "integrity": "sha512-9Erhx956jeQ0nNTyif1+QWAXDRD38ZNjr//bSHrt6wDwB+QkAfl2q6Mn1k6OBPerznjRmbM10lgRb1Pli4xZPw==", + "version": "1.0.0-rc.16", + "resolved": "https://registry.npmjs.org/@rolldown/binding-freebsd-x64/-/binding-freebsd-x64-1.0.0-rc.16.tgz", + "integrity": "sha512-KcRE5w8h0OnjUatG8pldyD14/CQ5Phs1oxfR+3pKDjboHRo9+MkqQaiIZlZRpsxC15paeXme/I127tUa9TXJ6g==", "cpu": [ "x64" ], @@ -368,9 +380,9 @@ } }, "node_modules/@rolldown/binding-linux-arm-gnueabihf": { - "version": "1.0.0-rc.15", - "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-arm-gnueabihf/-/binding-linux-arm-gnueabihf-1.0.0-rc.15.tgz", - "integrity": "sha512-cVwk0w8QbZJGTnP/AHQBs5yNwmpgGYStL88t4UIaqcvYJWBfS0s3oqVLZPwsPU6M0zlW4GqjP0Zq5MnAGwFeGA==", + "version": "1.0.0-rc.16", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-arm-gnueabihf/-/binding-linux-arm-gnueabihf-1.0.0-rc.16.tgz", + "integrity": "sha512-bT0guA1bpxEJ/ZhTRniQf7rNF8ybvXOuWbNIeLABaV5NGjx4EtOWBTSRGWFU9ZWVkPOZ+HNFP8RMcBokBiZ0Kg==", "cpu": [ "arm" ], @@ -385,13 +397,16 @@ } }, "node_modules/@rolldown/binding-linux-arm64-gnu": { - "version": "1.0.0-rc.15", - "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-arm64-gnu/-/binding-linux-arm64-gnu-1.0.0-rc.15.tgz", - "integrity": "sha512-eBZ/u8iAK9SoHGanqe/jrPnY0JvBN6iXbVOsbO38mbz+ZJsaobExAm1Iu+rxa4S1l2FjG0qEZn4Rc6X8n+9M+w==", + "version": "1.0.0-rc.16", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-arm64-gnu/-/binding-linux-arm64-gnu-1.0.0-rc.16.tgz", + "integrity": "sha512-+tHktCHWV8BDQSjemUqm/Jl/TPk3QObCTIjmdDy/nlupcujZghmKK2962LYrqFpWu+ai01AN/REOH3NEpqvYQg==", "cpu": [ "arm64" ], "dev": true, + "libc": [ + "glibc" + ], "license": "MIT", "optional": true, "os": [ @@ -402,13 +417,16 @@ } }, "node_modules/@rolldown/binding-linux-arm64-musl": { - "version": "1.0.0-rc.15", - "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-arm64-musl/-/binding-linux-arm64-musl-1.0.0-rc.15.tgz", - "integrity": "sha512-ZvRYMGrAklV9PEkgt4LQM6MjQX2P58HPAuecwYObY2DhS2t35R0I810bKi0wmaYORt6m/2Sm+Z+nFgb0WhXNcQ==", + "version": "1.0.0-rc.16", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-arm64-musl/-/binding-linux-arm64-musl-1.0.0-rc.16.tgz", + "integrity": "sha512-3fPzdREH806oRLxpTWW1Gt4tQHs0TitZFOECB2xzCFLPKnSOy90gwA7P29cksYilFO6XVRY1kzga0cL2nRjKPg==", "cpu": [ "arm64" ], "dev": true, + "libc": [ + "musl" + ], "license": "MIT", "optional": true, "os": [ @@ -419,13 +437,16 @@ } }, "node_modules/@rolldown/binding-linux-ppc64-gnu": { - "version": "1.0.0-rc.15", - "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-ppc64-gnu/-/binding-linux-ppc64-gnu-1.0.0-rc.15.tgz", - "integrity": "sha512-VDpgGBzgfg5hLg+uBpCLoFG5kVvEyafmfxGUV0UHLcL5irxAK7PKNeC2MwClgk6ZAiNhmo9FLhRYgvMmedLtnQ==", + "version": "1.0.0-rc.16", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-ppc64-gnu/-/binding-linux-ppc64-gnu-1.0.0-rc.16.tgz", + "integrity": "sha512-EKwI1tSrLs7YVw+JPJT/G2dJQ1jl9qlTTTEG0V2Ok/RdOenRfBw2PQdLPyjhIu58ocdBfP7vIRN/pvMsPxs/AQ==", "cpu": [ "ppc64" ], "dev": true, + "libc": [ + "glibc" + ], "license": "MIT", "optional": true, "os": [ @@ -436,13 +457,16 @@ } }, "node_modules/@rolldown/binding-linux-s390x-gnu": { - "version": "1.0.0-rc.15", - "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-s390x-gnu/-/binding-linux-s390x-gnu-1.0.0-rc.15.tgz", - "integrity": "sha512-y1uXY3qQWCzcPgRJATPSOUP4tCemh4uBdY7e3EZbVwCJTY3gLJWnQABgeUetvED+bt1FQ01OeZwvhLS2bpNrAQ==", + "version": "1.0.0-rc.16", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-s390x-gnu/-/binding-linux-s390x-gnu-1.0.0-rc.16.tgz", + "integrity": "sha512-Uknladnb3Sxqu6SEcqBldQyJUpk8NleooZEc0MbRBJ4inEhRYWZX0NJu12vNf2mqAq7gsofAxHrGghiUYjhaLQ==", "cpu": [ "s390x" ], "dev": true, + "libc": [ + "glibc" + ], "license": "MIT", "optional": true, "os": [ @@ -453,13 +477,16 @@ } }, "node_modules/@rolldown/binding-linux-x64-gnu": { - "version": "1.0.0-rc.15", - "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-x64-gnu/-/binding-linux-x64-gnu-1.0.0-rc.15.tgz", - "integrity": "sha512-023bTPBod7J3Y/4fzAN6QtpkSABR0rigtrwaP+qSEabUh5zf6ELr9Nc7GujaROuPY3uwdSIXWrvhn1KxOvurWA==", + "version": "1.0.0-rc.16", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-x64-gnu/-/binding-linux-x64-gnu-1.0.0-rc.16.tgz", + "integrity": "sha512-FIb8+uG49sZBtLTn+zt1AJ20TqVcqWeSIyoVt0or7uAWesgKaHbiBh6OpA/k9v0LTt+PTrb1Lao133kP4uVxkg==", "cpu": [ "x64" ], "dev": true, + "libc": [ + "glibc" + ], "license": "MIT", "optional": true, "os": [ @@ -470,13 +497,16 @@ } }, "node_modules/@rolldown/binding-linux-x64-musl": { - "version": "1.0.0-rc.15", - "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-x64-musl/-/binding-linux-x64-musl-1.0.0-rc.15.tgz", - "integrity": "sha512-witB2O0/hU4CgfOOKUoeFgQ4GktPi1eEbAhaLAIpgD6+ZnhcPkUtPsoKKHRzmOoWPZue46IThdSgdo4XneOLYw==", + "version": "1.0.0-rc.16", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-x64-musl/-/binding-linux-x64-musl-1.0.0-rc.16.tgz", + "integrity": "sha512-RuERhF9/EgWxZEXYWCOaViUWHIboceK4/ivdtQ3R0T44NjLkIIlGIAVAuCddFxsZ7vnRHtNQUrt2vR2n2slB2w==", "cpu": [ "x64" ], "dev": true, + "libc": [ + "musl" + ], "license": "MIT", "optional": true, "os": [ @@ -487,9 +517,9 @@ } }, "node_modules/@rolldown/binding-openharmony-arm64": { - "version": "1.0.0-rc.15", - "resolved": "https://registry.npmjs.org/@rolldown/binding-openharmony-arm64/-/binding-openharmony-arm64-1.0.0-rc.15.tgz", - "integrity": "sha512-UCL68NJ0Ud5zRipXZE9dF5PmirzJE4E4BCIOOssEnM7wLDsxjc6Qb0sGDxTNRTP53I6MZpygyCpY8Aa8sPfKPg==", + "version": "1.0.0-rc.16", + "resolved": "https://registry.npmjs.org/@rolldown/binding-openharmony-arm64/-/binding-openharmony-arm64-1.0.0-rc.16.tgz", + "integrity": "sha512-mXcXnvd9GpazCxeUCCnZ2+YF7nut+ZOEbE4GtaiPtyY6AkhZWbK70y1KK3j+RDhjVq5+U8FySkKRb/+w0EeUwA==", "cpu": [ "arm64" ], @@ -504,9 +534,9 @@ } }, "node_modules/@rolldown/binding-wasm32-wasi": { - "version": "1.0.0-rc.15", - "resolved": "https://registry.npmjs.org/@rolldown/binding-wasm32-wasi/-/binding-wasm32-wasi-1.0.0-rc.15.tgz", - "integrity": "sha512-ApLruZq/ig+nhaE7OJm4lDjayUnOHVUa77zGeqnqZ9pn0ovdVbbNPerVibLXDmWeUZXjIYIT8V3xkT58Rm9u5Q==", + "version": "1.0.0-rc.16", + "resolved": "https://registry.npmjs.org/@rolldown/binding-wasm32-wasi/-/binding-wasm32-wasi-1.0.0-rc.16.tgz", + "integrity": "sha512-3Q2KQxnC8IJOLqXmUMoYwyIPZU9hzRbnHaoV3Euz+VVnjZKcY8ktnNP8T9R4/GGQtb27C/UYKABxesKWb8lsvQ==", "cpu": [ "wasm32" ], @@ -516,16 +546,16 @@ "dependencies": { "@emnapi/core": "1.9.2", "@emnapi/runtime": "1.9.2", - "@napi-rs/wasm-runtime": "^1.1.3" + "@napi-rs/wasm-runtime": "^1.1.4" }, "engines": { - "node": ">=14.0.0" + "node": "^20.19.0 || >=22.12.0" } }, "node_modules/@rolldown/binding-win32-arm64-msvc": { - "version": "1.0.0-rc.15", - "resolved": "https://registry.npmjs.org/@rolldown/binding-win32-arm64-msvc/-/binding-win32-arm64-msvc-1.0.0-rc.15.tgz", - "integrity": "sha512-KmoUoU7HnN+Si5YWJigfTws1jz1bKBYDQKdbLspz0UaqjjFkddHsqorgiW1mxcAj88lYUE6NC/zJNwT+SloqtA==", + "version": "1.0.0-rc.16", + "resolved": "https://registry.npmjs.org/@rolldown/binding-win32-arm64-msvc/-/binding-win32-arm64-msvc-1.0.0-rc.16.tgz", + "integrity": "sha512-tj7XRemQcOcFwv7qhpUxMTBbI5mWMlE4c1Omhg5+h8GuLXzyj8HviYgR+bB2DMDgRqUE+jiDleqSCRjx4aYk/Q==", "cpu": [ "arm64" ], @@ -540,9 +570,9 @@ } }, "node_modules/@rolldown/binding-win32-x64-msvc": { - "version": "1.0.0-rc.15", - "resolved": "https://registry.npmjs.org/@rolldown/binding-win32-x64-msvc/-/binding-win32-x64-msvc-1.0.0-rc.15.tgz", - "integrity": "sha512-3P2A8L+x75qavWLe/Dll3EYBJLQmtkJN8rfh+U/eR3MqMgL/h98PhYI+JFfXuDPgPeCB7iZAKiqii5vqOvnA0g==", + "version": "1.0.0-rc.16", + "resolved": "https://registry.npmjs.org/@rolldown/binding-win32-x64-msvc/-/binding-win32-x64-msvc-1.0.0-rc.16.tgz", + "integrity": "sha512-PH5DRZT+F4f2PTXRXR8uJxnBq2po/xFtddyabTJVJs/ZYVHqXPEgNIr35IHTEa6bpa0Q8Awg+ymkTaGnKITw4g==", "cpu": [ "x64" ], @@ -557,9 +587,9 @@ } }, "node_modules/@rolldown/pluginutils": { - "version": "1.0.0-rc.15", - "resolved": "https://registry.npmjs.org/@rolldown/pluginutils/-/pluginutils-1.0.0-rc.15.tgz", - "integrity": "sha512-UromN0peaE53IaBRe9W7CjrZgXl90fqGpK+mIZbA3qSTeYqg3pqpROBdIPvOG3F5ereDHNwoHBI2e50n1BDr1g==", + "version": "1.0.0-rc.16", + "resolved": "https://registry.npmjs.org/@rolldown/pluginutils/-/pluginutils-1.0.0-rc.16.tgz", + "integrity": "sha512-45+YtqxLYKDWQouLKCrpIZhke+nXxhsw+qAHVzHDVwttyBlHNBVs2K25rDXrZzhpTp9w1FlAlvweV1H++fdZoA==", "dev": true, "license": "MIT" }, @@ -812,13 +842,13 @@ } }, "node_modules/entities": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/entities/-/entities-6.0.1.tgz", - "integrity": "sha512-aN97NXWF6AWBTahfVOIrB/NShkzi5H7F9r1s9mD3cDj4Ko5f2qhhVoYMibXF7GlLveb/D2ioWay8lxI97Ven3g==", + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/entities/-/entities-8.0.0.tgz", + "integrity": "sha512-zwfzJecQ/Uej6tusMqwAqU/6KL2XaB2VZ2Jg54Je6ahNBGNH6Ek6g3jjNCF0fG9EWQKGZNddNjU5F1ZQn/sBnA==", "dev": true, "license": "BSD-2-Clause", "engines": { - "node": ">=0.12" + "node": ">=20.19.0" }, "funding": { "url": "https://github.com/fb55/entities?sponsor=1" @@ -1088,6 +1118,9 @@ "arm64" ], "dev": true, + "libc": [ + "glibc" + ], "license": "MPL-2.0", "optional": true, "os": [ @@ -1109,6 +1142,9 @@ "arm64" ], "dev": true, + "libc": [ + "musl" + ], "license": "MPL-2.0", "optional": true, "os": [ @@ -1130,6 +1166,9 @@ "x64" ], "dev": true, + "libc": [ + "glibc" + ], "license": "MPL-2.0", "optional": true, "os": [ @@ -1151,6 +1190,9 @@ "x64" ], "dev": true, + "libc": [ + "musl" + ], "license": "MPL-2.0", "optional": true, "os": [ @@ -1207,9 +1249,9 @@ } }, "node_modules/lru-cache": { - "version": "11.3.3", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-11.3.3.tgz", - "integrity": "sha512-JvNw9Y81y33E+BEYPr0U7omo+U9AySnsMsEiXgwT6yqd31VQWTLNQqmT4ou5eqPFUrTfIDFta2wKhB1hyohtAQ==", + "version": "11.3.5", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-11.3.5.tgz", + "integrity": "sha512-NxVFwLAnrd9i7KUBxC4DrUhmgjzOs+1Qm50D3oF1/oL+r1NpZ4gA7xvG0/zJ8evR7zIKn4vLf7qTNduWFtCrRw==", "dev": true, "license": "BlueOak-1.0.0", "engines": { @@ -1270,13 +1312,13 @@ "license": "MIT" }, "node_modules/parse5": { - "version": "8.0.0", - "resolved": "https://registry.npmjs.org/parse5/-/parse5-8.0.0.tgz", - "integrity": "sha512-9m4m5GSgXjL4AjumKzq1Fgfp3Z8rsvjRNbnkVwfu2ImRqE5D0LnY2QfDen18FSY9C573YU5XxSapdHZTZ2WolA==", + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/parse5/-/parse5-8.0.1.tgz", + "integrity": "sha512-z1e/HMG90obSGeidlli3hj7cbocou0/wa5HacvI3ASx34PecNjNQeaHNo5WIZpWofN9kgkqV1q5YvXe3F0FoPw==", "dev": true, "license": "MIT", "dependencies": { - "entities": "^6.0.0" + "entities": "^8.0.0" }, "funding": { "url": "https://github.com/inikulin/parse5?sponsor=1" @@ -1310,9 +1352,9 @@ } }, "node_modules/postcss": { - "version": "8.5.8", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.8.tgz", - "integrity": "sha512-OW/rX8O/jXnm82Ey1k44pObPtdblfiuWnrd8X7GJ7emImCOstunGbXUpp7HdBrFQX6rJzn3sPT397Wp5aCwCHg==", + "version": "8.5.10", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.10.tgz", + "integrity": "sha512-pMMHxBOZKFU6HgAZ4eyGnwXF/EvPGGqUr0MnZ5+99485wwW41kW91A4LOGxSHhgugZmSChL5AlElNdwlNgcnLQ==", "dev": true, "funding": [ { @@ -1359,14 +1401,14 @@ } }, "node_modules/rolldown": { - "version": "1.0.0-rc.15", - "resolved": "https://registry.npmjs.org/rolldown/-/rolldown-1.0.0-rc.15.tgz", - "integrity": "sha512-Ff31guA5zT6WjnGp0SXw76X6hzGRk/OQq2hE+1lcDe+lJdHSgnSX6nK3erbONHyCbpSj9a9E+uX/OvytZoWp2g==", + "version": "1.0.0-rc.16", + "resolved": "https://registry.npmjs.org/rolldown/-/rolldown-1.0.0-rc.16.tgz", + "integrity": "sha512-rzi5WqKzEZw3SooTt7cgm4eqIoujPIyGcJNGFL7iPEuajQw7vxMHUkXylu4/vhCkJGXsgRmxqMKXUpT6FEgl0g==", "dev": true, "license": "MIT", "dependencies": { - "@oxc-project/types": "=0.124.0", - "@rolldown/pluginutils": "1.0.0-rc.15" + "@oxc-project/types": "=0.126.0", + "@rolldown/pluginutils": "1.0.0-rc.16" }, "bin": { "rolldown": "bin/cli.mjs" @@ -1375,21 +1417,21 @@ "node": "^20.19.0 || >=22.12.0" }, "optionalDependencies": { - "@rolldown/binding-android-arm64": "1.0.0-rc.15", - "@rolldown/binding-darwin-arm64": "1.0.0-rc.15", - "@rolldown/binding-darwin-x64": "1.0.0-rc.15", - "@rolldown/binding-freebsd-x64": "1.0.0-rc.15", - "@rolldown/binding-linux-arm-gnueabihf": "1.0.0-rc.15", - "@rolldown/binding-linux-arm64-gnu": "1.0.0-rc.15", - "@rolldown/binding-linux-arm64-musl": "1.0.0-rc.15", - "@rolldown/binding-linux-ppc64-gnu": "1.0.0-rc.15", - "@rolldown/binding-linux-s390x-gnu": "1.0.0-rc.15", - "@rolldown/binding-linux-x64-gnu": "1.0.0-rc.15", - "@rolldown/binding-linux-x64-musl": "1.0.0-rc.15", - "@rolldown/binding-openharmony-arm64": "1.0.0-rc.15", - "@rolldown/binding-wasm32-wasi": "1.0.0-rc.15", - "@rolldown/binding-win32-arm64-msvc": "1.0.0-rc.15", - "@rolldown/binding-win32-x64-msvc": "1.0.0-rc.15" + "@rolldown/binding-android-arm64": "1.0.0-rc.16", + "@rolldown/binding-darwin-arm64": "1.0.0-rc.16", + "@rolldown/binding-darwin-x64": "1.0.0-rc.16", + "@rolldown/binding-freebsd-x64": "1.0.0-rc.16", + "@rolldown/binding-linux-arm-gnueabihf": "1.0.0-rc.16", + "@rolldown/binding-linux-arm64-gnu": "1.0.0-rc.16", + "@rolldown/binding-linux-arm64-musl": "1.0.0-rc.16", + "@rolldown/binding-linux-ppc64-gnu": "1.0.0-rc.16", + "@rolldown/binding-linux-s390x-gnu": "1.0.0-rc.16", + "@rolldown/binding-linux-x64-gnu": "1.0.0-rc.16", + "@rolldown/binding-linux-x64-musl": "1.0.0-rc.16", + "@rolldown/binding-openharmony-arm64": "1.0.0-rc.16", + "@rolldown/binding-wasm32-wasi": "1.0.0-rc.16", + "@rolldown/binding-win32-arm64-msvc": "1.0.0-rc.16", + "@rolldown/binding-win32-x64-msvc": "1.0.0-rc.16" } }, "node_modules/saxes": { @@ -1430,9 +1472,9 @@ "license": "MIT" }, "node_modules/std-env": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/std-env/-/std-env-4.0.0.tgz", - "integrity": "sha512-zUMPtQ/HBY3/50VbpkupYHbRroTRZJPRLvreamgErJVys0ceuzMkD44J/QjqhHjOzK42GQ3QZIeFG1OYfOtKqQ==", + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/std-env/-/std-env-4.1.0.tgz", + "integrity": "sha512-Rq7ybcX2RuC55r9oaPVEW7/xu3tj8u4GeBYHBWCychFtzMIr86A7e3PPEBPT37sHStKX3+TiX/Fr/ACmJLVlLQ==", "dev": true, "license": "MIT" }, @@ -1451,9 +1493,9 @@ "license": "MIT" }, "node_modules/tinyexec": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/tinyexec/-/tinyexec-1.0.4.tgz", - "integrity": "sha512-u9r3uZC0bdpGOXtlxUIdwf9pkmvhqJdrVCH9fapQtgy/OeTTMZ1nqH7agtvEfmGui6e1XxjcdrlxvxJvc3sMqw==", + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/tinyexec/-/tinyexec-1.1.1.tgz", + "integrity": "sha512-VKS/ZaQhhkKFMANmAOhhXVoIfBXblQxGX1myCQ2faQrfmobMftXeJPcZGp0gS07ocvGJWDLZGyOZDadDBqYIJg==", "dev": true, "license": "MIT", "engines": { @@ -1461,14 +1503,14 @@ } }, "node_modules/tinyglobby": { - "version": "0.2.15", - "resolved": "https://registry.npmjs.org/tinyglobby/-/tinyglobby-0.2.15.tgz", - "integrity": "sha512-j2Zq4NyQYG5XMST4cbs02Ak8iJUdxRM0XI5QyxXuZOzKOINmWurp3smXu3y5wDcJrptwpSjgXHzIQxR0omXljQ==", + "version": "0.2.16", + "resolved": "https://registry.npmjs.org/tinyglobby/-/tinyglobby-0.2.16.tgz", + "integrity": "sha512-pn99VhoACYR8nFHhxqix+uvsbXineAasWm5ojXoN8xEwK5Kd3/TrhNn1wByuD52UxWRLy8pu+kRMniEi6Eq9Zg==", "dev": true, "license": "MIT", "dependencies": { "fdir": "^6.5.0", - "picomatch": "^4.0.3" + "picomatch": "^4.0.4" }, "engines": { "node": ">=12.0.0" @@ -1488,22 +1530,22 @@ } }, "node_modules/tldts": { - "version": "7.0.26", - "resolved": "https://registry.npmjs.org/tldts/-/tldts-7.0.26.tgz", - "integrity": "sha512-WiGwQjr0qYdNNG8KpMKlSvpxz652lqa3Rd+/hSaDcY4Uo6SKWZq2LAF+hsAhUewTtYhXlorBKgNF3Kk8hnjGoQ==", + "version": "7.0.28", + "resolved": "https://registry.npmjs.org/tldts/-/tldts-7.0.28.tgz", + "integrity": "sha512-+Zg3vWhRUv8B1maGSTFdev9mjoo8Etn2Ayfs4cnjlD3CsGkxXX4QyW3j2WJ0wdjYcYmy7Lx2RDsZMhgCWafKIw==", "dev": true, "license": "MIT", "dependencies": { - "tldts-core": "^7.0.26" + "tldts-core": "^7.0.28" }, "bin": { "tldts": "bin/cli.js" } }, "node_modules/tldts-core": { - "version": "7.0.26", - "resolved": "https://registry.npmjs.org/tldts-core/-/tldts-core-7.0.26.tgz", - "integrity": "sha512-5WJ2SqFsv4G2Dwi7ZFVRnz6b2H1od39QME1lc2y5Ew3eWiZMAeqOAfWpRP9jHvhUl881406QtZTODvjttJs+ew==", + "version": "7.0.28", + "resolved": "https://registry.npmjs.org/tldts-core/-/tldts-core-7.0.28.tgz", + "integrity": "sha512-7W5Efjhsc3chVdFhqtaU0KtK32J37Zcr9RKtID54nG+tIpcY79CQK/veYPODxtD/LJ4Lue66jvrQzIX2Z2/pUQ==", "dev": true, "license": "MIT" }, @@ -1542,9 +1584,9 @@ "optional": true }, "node_modules/typescript": { - "version": "6.0.2", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-6.0.2.tgz", - "integrity": "sha512-bGdAIrZ0wiGDo5l8c++HWtbaNCWTS4UTv7RaTH/ThVIgjkveJt83m74bBHMJkuCbslY8ixgLBVZJIOiQlQTjfQ==", + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-6.0.3.tgz", + "integrity": "sha512-y2TvuxSZPDyQakkFRPZHKFm+KKVqIisdg9/CZwm9ftvKXLP8NRWj38/ODjNbr43SsoXqNuAisEf1GdCxqWcdBw==", "dev": true, "license": "Apache-2.0", "bin": { @@ -1556,9 +1598,9 @@ } }, "node_modules/undici": { - "version": "7.24.5", - "resolved": "https://registry.npmjs.org/undici/-/undici-7.24.5.tgz", - "integrity": "sha512-3IWdCpjgxp15CbJnsi/Y9TCDE7HWVN19j1hmzVhoAkY/+CJx449tVxT5wZc1Gwg8J+P0LWvzlBzxYRnHJ+1i7Q==", + "version": "7.25.0", + "resolved": "https://registry.npmjs.org/undici/-/undici-7.25.0.tgz", + "integrity": "sha512-xXnp4kTyor2Zq+J1FfPI6Eq3ew5h6Vl0F/8d9XU5zZQf1tX9s2Su1/3PiMmUANFULpmksxkClamIZcaUqryHsQ==", "dev": true, "license": "MIT", "engines": { @@ -1573,17 +1615,17 @@ "license": "MIT" }, "node_modules/vite": { - "version": "8.0.8", - "resolved": "https://registry.npmjs.org/vite/-/vite-8.0.8.tgz", - "integrity": "sha512-dbU7/iLVa8KZALJyLOBOQ88nOXtNG8vxKuOT4I2mD+Ya70KPceF4IAmDsmU0h1Qsn5bPrvsY9HJstCRh3hG6Uw==", + "version": "8.0.9", + "resolved": "https://registry.npmjs.org/vite/-/vite-8.0.9.tgz", + "integrity": "sha512-t7g7GVRpMXjNpa67HaVWI/8BWtdVIQPCL2WoozXXA7LBGEFK4AkkKkHx2hAQf5x1GZSlcmEDPkVLSGahxnEEZw==", "dev": true, "license": "MIT", "dependencies": { "lightningcss": "^1.32.0", "picomatch": "^4.0.4", - "postcss": "^8.5.8", - "rolldown": "1.0.0-rc.15", - "tinyglobby": "^0.2.15" + "postcss": "^8.5.10", + "rolldown": "1.0.0-rc.16", + "tinyglobby": "^0.2.16" }, "bin": { "vite": "bin/vite.js" From 36a8d1b7f1e73cf5cac08da39ad32b4092b61b39 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 21 Apr 2026 15:04:54 +0000 Subject: [PATCH 21/37] chore(deps): bump rustls-webpki in the cargo group across 1 directory Bumps the cargo group with 1 update in the / directory: [rustls-webpki](https://github.com/rustls/webpki). Updates `rustls-webpki` from 0.103.10 to 0.103.13 - [Release notes](https://github.com/rustls/webpki/releases) - [Commits](https://github.com/rustls/webpki/compare/v/0.103.10...v/0.103.13) --- updated-dependencies: - dependency-name: rustls-webpki dependency-version: 0.103.13 dependency-type: indirect dependency-group: cargo ... Signed-off-by: dependabot[bot] --- Cargo.lock | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 36c2ecb6..a1968023 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3666,9 +3666,9 @@ checksum = "f87165f0995f63a9fbeea62b64d10b4d9d8e78ec6d7d51fb2125fda7bb36788f" [[package]] name = "rustls-webpki" -version = "0.103.10" +version = "0.103.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "df33b2b81ac578cabaf06b89b0631153a3f416b0a886e8a7a1707fb51abbd1ef" +checksum = "61c429a8649f110dddef65e2a5ad240f747e85f7758a6bccc7e5777bd33f756e" dependencies = [ "ring", "rustls-pki-types", From d53354809b4adde4d248630bc808f0b58d06458b Mon Sep 17 00:00:00 2001 From: Jordon Date: Tue, 21 Apr 2026 17:39:27 +0100 Subject: [PATCH 22/37] Delete openvcs-git-plugin-0.1.0.tgz --- Backend/openvcs-git-plugin-0.1.0.tgz | Bin 50099 -> 0 bytes 1 file changed, 0 insertions(+), 0 deletions(-) delete mode 100644 Backend/openvcs-git-plugin-0.1.0.tgz diff --git a/Backend/openvcs-git-plugin-0.1.0.tgz b/Backend/openvcs-git-plugin-0.1.0.tgz deleted file mode 100644 index 1ceb42d1645579cc2384a168216fe9c89763f30a..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 50099 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 i+vf$DcbD&LHDMct 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 Date: Tue, 21 Apr 2026 18:22:48 +0100 Subject: [PATCH 23/37] Implement Sentry --- .github/workflows/beta.yml | 8 + .github/workflows/nightly.yml | 8 + .github/workflows/publish-stable.yml | 8 + .gitignore | 1 + ARCHITECTURE.md | 11 + Backend/Cargo.toml | 6 +- Backend/build.rs | 24 + Backend/src/lib.rs | 50 +- Backend/src/logging.rs | 69 +- Backend/src/monitoring.rs | 371 ++++ Backend/src/settings.rs | 8 +- Backend/src/state.rs | 1 + Backend/src/tauri_commands/mod.rs | 2 + Backend/src/tauri_commands/monitoring.rs | 17 + Backend/src/tauri_commands/output_log.rs | 21 +- Backend/src/tauri_commands/shared.rs | 16 +- Cargo.lock | 543 ++++- Frontend/package-lock.json | 1878 ++++++++++++++++- Frontend/package.json | 1 + Frontend/src/modals/settings.html | 8 + Frontend/src/scripts/features/repo/hydrate.ts | 20 +- Frontend/src/scripts/features/settings.ts | 59 +- .../scripts/features/settingsGeneral.test.ts | 55 + .../src/scripts/features/settingsGeneral.ts | 76 + Frontend/src/scripts/lib/logger.ts | 53 +- Frontend/src/scripts/lib/monitoring.test.ts | 152 ++ Frontend/src/scripts/lib/monitoring.ts | 195 ++ Frontend/src/scripts/main.ts | 21 +- Frontend/src/vite-env.d.ts | 14 + Frontend/vite.config.mts | 28 +- 30 files changed, 3519 insertions(+), 205 deletions(-) create mode 100644 Backend/src/monitoring.rs create mode 100644 Backend/src/tauri_commands/monitoring.rs create mode 100644 Frontend/src/scripts/features/settingsGeneral.test.ts create mode 100644 Frontend/src/scripts/features/settingsGeneral.ts create mode 100644 Frontend/src/scripts/lib/monitoring.test.ts create mode 100644 Frontend/src/scripts/lib/monitoring.ts create mode 100644 Frontend/src/vite-env.d.ts diff --git a/.github/workflows/beta.yml b/.github/workflows/beta.yml index 0cbbb80f..54700c0b 100644 --- a/.github/workflows/beta.yml +++ b/.github/workflows/beta.yml @@ -59,6 +59,12 @@ jobs: - name: Build frontend working-directory: Frontend + env: + VITE_SENTRY_ENVIRONMENT: beta + VITE_SENTRY_RELEASE: openvcs-beta-${{ steps.meta.outputs.short_sha }} + SENTRY_AUTH_TOKEN: ${{ matrix.platform == 'ubuntu-24.04' && secrets.SENTRY_AUTH_TOKEN || '' }} + SENTRY_ORG: ${{ matrix.platform == 'ubuntu-24.04' && secrets.SENTRY_ORG || '' }} + SENTRY_PROJECT: ${{ matrix.platform == 'ubuntu-24.04' && secrets.SENTRY_PROJECT || '' }} run: npm run build - name: Install Rust (stable) @@ -115,6 +121,8 @@ jobs: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} FRONTEND_SKIP_BUILD: '1' OPENVCS_UPDATE_CHANNEL: beta + OPENVCS_SENTRY_DSN: ${{ secrets.OPENVCS_SENTRY_DSN }} + OPENVCS_SENTRY_ENVIRONMENT: beta TAURI_SIGNING_PRIVATE_KEY: ${{ secrets.TAURI_PRIVATE_KEY }} TAURI_SIGNING_PRIVATE_KEY_PASSWORD: ${{ secrets.TAURI_PRIVATE_KEY_PASSWORD }} with: diff --git a/.github/workflows/nightly.yml b/.github/workflows/nightly.yml index c1fd8700..6fbb9e2a 100644 --- a/.github/workflows/nightly.yml +++ b/.github/workflows/nightly.yml @@ -164,6 +164,12 @@ jobs: - name: Build frontend working-directory: Frontend + env: + VITE_SENTRY_ENVIRONMENT: nightly + VITE_SENTRY_RELEASE: openvcs-nightly-${{ steps.meta.outputs.short_sha }} + SENTRY_AUTH_TOKEN: ${{ matrix.platform == 'ubuntu-24.04' && secrets.SENTRY_AUTH_TOKEN || '' }} + SENTRY_ORG: ${{ matrix.platform == 'ubuntu-24.04' && secrets.SENTRY_ORG || '' }} + SENTRY_PROJECT: ${{ matrix.platform == 'ubuntu-24.04' && secrets.SENTRY_PROJECT || '' }} run: npm run build # ---------- Rust & platform deps ---------- @@ -224,6 +230,8 @@ jobs: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} FRONTEND_SKIP_BUILD: '1' OPENVCS_UPDATE_CHANNEL: nightly + OPENVCS_SENTRY_DSN: ${{ secrets.OPENVCS_SENTRY_DSN }} + OPENVCS_SENTRY_ENVIRONMENT: nightly TAURI_SIGNING_PRIVATE_KEY: ${{ secrets.TAURI_PRIVATE_KEY }} TAURI_SIGNING_PRIVATE_KEY_PASSWORD: ${{ secrets.TAURI_PRIVATE_KEY_PASSWORD }} with: diff --git a/.github/workflows/publish-stable.yml b/.github/workflows/publish-stable.yml index 5baf497a..61ea930f 100644 --- a/.github/workflows/publish-stable.yml +++ b/.github/workflows/publish-stable.yml @@ -57,6 +57,12 @@ jobs: - name: Build frontend working-directory: Frontend + env: + VITE_SENTRY_ENVIRONMENT: stable + VITE_SENTRY_RELEASE: ${{ steps.version.outputs.tag }} + SENTRY_AUTH_TOKEN: ${{ matrix.platform == 'ubuntu-24.04' && secrets.SENTRY_AUTH_TOKEN || '' }} + SENTRY_ORG: ${{ matrix.platform == 'ubuntu-24.04' && secrets.SENTRY_ORG || '' }} + SENTRY_PROJECT: ${{ matrix.platform == 'ubuntu-24.04' && secrets.SENTRY_PROJECT || '' }} run: npm run build # ---------- Rust toolchain & deps ---------- @@ -144,6 +150,8 @@ jobs: # We already built the Frontend; tell Backend/Tauri to skip any beforeBuildCommand FRONTEND_SKIP_BUILD: '1' OPENVCS_UPDATE_CHANNEL: stable + OPENVCS_SENTRY_DSN: ${{ secrets.OPENVCS_SENTRY_DSN }} + OPENVCS_SENTRY_ENVIRONMENT: stable # Stable production builds should report the plain package version (not git metadata). OPENVCS_OFFICIAL_RELEASE: '1' TAURI_SIGNING_PRIVATE_KEY: ${{ secrets.TAURI_PRIVATE_KEY }} diff --git a/.gitignore b/.gitignore index 0eb5d6e4..f8dfbef6 100644 --- a/.gitignore +++ b/.gitignore @@ -27,4 +27,5 @@ dist-ssr /Backend/icons/ios /Core .env.tauri.local +.env .opencode/ diff --git a/ARCHITECTURE.md b/ARCHITECTURE.md index 568b198e..0306417c 100644 --- a/ARCHITECTURE.md +++ b/ARCHITECTURE.md @@ -57,6 +57,17 @@ Backend: - State lifecycle: Startup config load, optional reopen-last-repo, runtime config updates. +- Monitoring: + Optional Sentry reporting is initialized separately in `Backend/src/monitoring.rs` and + `Frontend/src/scripts/lib/monitoring.ts`, with backend/frontend events gated by + `general.crash_reports`. The frontend captures errors and relays them to a + backend-owned Sentry client over Tauri IPC, while backend Sentry uses runtime + process env values with a build-time embedded fallback for packaged builds. + Recent frontend console output is retained as breadcrumbs and attached to + frontend monitoring events. Backend Rust `log` records are bridged into + Sentry without replacing the existing console/file logger: `error!` records + produce Sentry events, `warn!` records become breadcrumbs/logs, and `info!` + records become breadcrumbs when crash reporting is enabled. - Plugin lifecycle: Built-in/user plugin discovery, config-driven sync, install/uninstall, and approval gating. - Reliability: diff --git a/Backend/Cargo.toml b/Backend/Cargo.toml index 1be6664b..2511f518 100644 --- a/Backend/Cargo.toml +++ b/Backend/Cargo.toml @@ -18,6 +18,7 @@ name = "openvcs_lib" crate-type = ["staticlib", "cdylib", "rlib"] [build-dependencies] +dotenvy = "0.15" tauri-build = { version = "2.4", default-features = false, features = [] } serde = { version = "1", features = ["derive"] } serde_json = "1.0" @@ -26,6 +27,7 @@ serde_json = "1.0" default = [] [dependencies] +dotenvy = "0.15" tauri = { version = "2.10", features = [] } tauri-plugin-opener = "2.5" serde = { version = "1", features = ["derive"] } @@ -35,9 +37,11 @@ tauri-plugin-updater = "2.10" tokio = { version = "1.51", features = ["io-util", "process", "rt", "sync", "time"] } dirs = "6" regex = "1.12" -log = "0.4" +log = "0.4" env_logger = "0.11" parking_lot = "0.12" +sentry = { version = "0.46", default-features = false, features = ["backtrace", "contexts", "panic", "reqwest", "rustls", "log", "logs"] } +sentry-log = { version = "0.46", features = ["logs"] } toml = "1.0.6" directories = "6" serde_json = "1.0" diff --git a/Backend/build.rs b/Backend/build.rs index 0cf32e86..6df5596f 100644 --- a/Backend/build.rs +++ b/Backend/build.rs @@ -1,8 +1,25 @@ // Copyright © 2025-2026 OpenVCS Contributors // SPDX-License-Identifier: GPL-3.0-or-later +use dotenvy::from_path_iter; use serde::Deserialize; use std::{env, fs, path::PathBuf, process::Command}; +/// Loads `Client/.env` into the build environment without overriding existing vars. +fn load_local_dotenv(manifest_dir: &std::path::Path) { + let dotenv_path = manifest_dir.join("../.env"); + println!("cargo:rerun-if-changed={}", dotenv_path.display()); + + let Ok(iter) = from_path_iter(&dotenv_path) else { + return; + }; + + for (key, value) in iter.flatten() { + if env::var_os(&key).is_none() { + env::set_var(key, value); + } + } +} + fn load_channel_metadata() -> ChannelMetadata { let manifest_dir = PathBuf::from(env::var("CARGO_MANIFEST_DIR").expect("CARGO_MANIFEST_DIR")); let config_path = manifest_dir.join("../channel-metadata.json"); @@ -220,6 +237,7 @@ fn ensure_generated_node_runtime_resource_dir(manifest_dir: &std::path::Path) { fn main() { // Base config path (in the Backend crate) let manifest_dir = PathBuf::from(env::var("CARGO_MANIFEST_DIR").expect("CARGO_MANIFEST_DIR")); + load_local_dotenv(&manifest_dir); let base = manifest_dir.join("tauri.conf.json"); let data = fs::read_to_string(&base).expect("read tauri.conf.json"); @@ -378,6 +396,12 @@ fn main() { println!("cargo:rustc-env=OPENVCS_VERSION={}", version); println!("cargo:rustc-env=OPENVCS_BUILD={}", build_id); + if let Ok(value) = env::var("OPENVCS_SENTRY_DSN") { + println!("cargo:rustc-env=OPENVCS_SENTRY_DSN_BUILT={}", value); + } + if let Ok(value) = env::var("OPENVCS_SENTRY_ENVIRONMENT") { + println!("cargo:rustc-env=OPENVCS_SENTRY_ENVIRONMENT_BUILT={}", value); + } ensure_generated_builtins_resource_dir(&manifest_dir); ensure_generated_node_runtime_resource_dir(&manifest_dir); diff --git a/Backend/src/lib.rs b/Backend/src/lib.rs index 7fb119c8..3be8f73c 100644 --- a/Backend/src/lib.rs +++ b/Backend/src/lib.rs @@ -5,7 +5,7 @@ //! This crate wires together Tauri command handlers, runtime state, //! plugin discovery, and startup behavior. -use log::warn; +use log::{error, warn}; use std::sync::Arc; use tauri::path::BaseDirectory; use tauri::WindowEvent; @@ -18,6 +18,7 @@ mod app_identity; mod config_watcher; mod core; mod logging; +mod monitoring; mod output_log; mod plugin_bundles; mod plugin_manifest; @@ -36,6 +37,12 @@ mod utilities; mod validate; mod workarounds; +/// Loads `Client/.env` for local development without overwriting existing env vars. +fn load_local_dotenv() { + let dotenv_path = std::path::Path::new(env!("CARGO_MANIFEST_DIR")).join("../.env"); + let _ = dotenvy::from_path(&dotenv_path); +} + /// Selects preferred backend from settings or first available plugin backend. /// /// # Parameters @@ -102,7 +109,13 @@ fn try_reopen_last_repo(app_handle: &tauri::AppHandle) { log::warn!("startup reopen: failed to emit repo:selected: {}", error); } } - Err(error) => log::warn!("startup reopen: failed to open repo: {}", error), + Err(error) => { + crate::monitoring::capture_startup_error( + "reopen_last_repo", + &error.to_string(), + ); + log::warn!("startup reopen: failed to open repo: {}", error) + } } } else { log::warn!("startup reopen: backend not available"); @@ -119,15 +132,18 @@ fn try_reopen_last_repo(app_handle: &tauri::AppHandle) { /// - `()`. This function runs the Tauri event loop until application exit. #[cfg_attr(mobile, tauri::mobile_entry_point)] pub fn run() { + load_local_dotenv(); // Initialize logging logging::init(); + let app_state = state::AppState::new_with_config(); + monitoring::sync_backend_monitoring(&app_state.config()); workarounds::apply_linux_nvidia_workaround(); println!("Running OpenVCS..."); tauri::Builder::default() - .manage(state::AppState::new_with_config()) + .manage(app_state) .setup(|app| { crate::plugin_runtime::host_api::set_status_event_emitter({ let app_handle = app.handle().clone(); @@ -191,16 +207,43 @@ pub fn run() { } let store = crate::plugin_bundles::PluginBundleStore::new_default(); if let Err(err) = store.sync_built_in_plugins() { + crate::monitoring::capture_startup_error("sync_built_in_plugins", &err.to_string()); warn!("plugins: failed to sync built-in plugins: {}", err); } let state = app.state::(); crate::config_watcher::start_config_watcher(app.handle().clone()); if let Err(err) = crate::plugin_sources::sync_configured_plugins(&state.config()) { + crate::monitoring::capture_startup_error( + "sync_configured_plugins", + &err.to_string(), + ); warn!("plugins: failed to sync configured plugins: {}", err); } if let Err(err) = state.plugin_runtime().sync_plugin_runtime() { + crate::monitoring::capture_startup_error("sync_plugin_runtime", &err.to_string()); warn!("plugins: failed to sync runtime on startup: {}", err); } + match crate::plugin_vcs_backends::list_plugin_vcs_backends() { + Ok(backends) if backends.is_empty() => { + let configured_default = state.config().general.default_backend; + error!( + "startup: no VCS backends are available; configured default backend='{}'; repo actions will remain unavailable until a backend plugin is installed, approved, and enabled", + configured_default + ); + } + Ok(backends) => { + log::info!( + "startup: {} VCS backend(s) available after plugin sync", + backends.len() + ); + } + Err(err) => { + warn!( + "startup: failed to discover VCS backends after plugin sync: {}", + err + ); + } + } // On startup, optionally reopen the last repository if enabled in settings. try_reopen_last_repo(app.handle()); @@ -344,6 +387,7 @@ fn build_invoke_handler( tauri_commands::log_frontend_message, tauri_commands::tail_app_log, tauri_commands::clear_app_log, + tauri_commands::report_frontend_error, tauri_commands::exit_app, tauri_commands::check_for_updates, ] diff --git a/Backend/src/logging.rs b/Backend/src/logging.rs index 853028d7..93f76ccf 100644 --- a/Backend/src/logging.rs +++ b/Backend/src/logging.rs @@ -3,12 +3,26 @@ use crate::settings::{AppConfig, LogLevel}; use std::fs::{self, OpenOptions}; use std::io::{Seek, SeekFrom, Write}; +use std::sync::atomic::{AtomicBool, Ordering}; use std::sync::{Arc, Mutex, OnceLock}; use std::time::Instant; +use sentry_log::{LogFilter, SentryLogger}; use time::{OffsetDateTime, UtcOffset}; use zip::{write::FileOptions, CompressionMethod, ZipWriter}; static ACTIVE_LOG_FILE: OnceLock>> = OnceLock::new(); +static SENTRY_LOG_FORWARDING_ENABLED: AtomicBool = AtomicBool::new(false); + +/// Updates whether backend log records should be forwarded into Sentry. +/// +/// # Parameters +/// - `enabled`: `true` when a backend Sentry client is active and crash reporting is allowed. +/// +/// # Returns +/// - `()`. +pub fn set_sentry_log_forwarding_enabled(enabled: bool) { + SENTRY_LOG_FORWARDING_ENABLED.store(enabled, Ordering::Relaxed); +} /// RAII timer that logs operation duration on drop. /// @@ -104,26 +118,6 @@ pub fn clear_active_log_file() -> Result<(), String> { Ok(()) } -/// Writes a line directly to the active log file. -/// -/// # Parameters -/// - `line`: The line to write (without trailing newline). -/// -/// # Returns -/// - `Ok(())` if the line was written. -/// - `Err(String)` if writing fails or log file not initialized. -pub fn write_to_log(line: &str) -> Result<(), String> { - let Some(file) = ACTIVE_LOG_FILE.get() else { - return Ok(()); - }; - let mut f = file - .lock() - .map_err(|_| "log file lock poisoned".to_string())?; - writeln!(f, "{}", line).map_err(|e| e.to_string())?; - f.flush().map_err(|e| e.to_string())?; - Ok(()) -} - /// Initialize logging: console (env_logger) + append to `./logs/openvcs.log`. /// Respects `RUST_LOG` for filtering; sets a sensible default if missing. /// @@ -363,15 +357,46 @@ pub fn init() { console: console_logger, file, }; - let _ = log::set_boxed_logger(Box::new(dual)); + let sentry_logger = build_sentry_logger(dual); + let _ = log::set_boxed_logger(Box::new(sentry_logger)); log::set_max_level(log::LevelFilter::Trace); } else { // Fallback to console-only - let _ = log::set_boxed_logger(Box::new(console_logger)); + let sentry_logger = build_sentry_logger(console_logger); + let _ = log::set_boxed_logger(Box::new(sentry_logger)); log::set_max_level(log::LevelFilter::Trace); } } +/// Wraps an existing backend logger so selected records are also forwarded to Sentry. +/// +/// Error-level records become Sentry events and logs, warn-level records become +/// breadcrumbs and logs, and info-level records become breadcrumbs. Local +/// console/file logging always continues through the wrapped destination logger. +/// +/// # Parameters +/// - `destination`: Existing logger that should continue receiving all records. +/// +/// # Returns +/// - A `SentryLogger` forwarding selected records to Sentry. +fn build_sentry_logger(destination: L) -> SentryLogger +where + L: log::Log + Send + Sync + 'static, +{ + SentryLogger::with_dest(destination).filter(|metadata| { + if !SENTRY_LOG_FORWARDING_ENABLED.load(Ordering::Relaxed) { + return LogFilter::Ignore; + } + + match metadata.level() { + log::Level::Error => LogFilter::Event | LogFilter::Log, + log::Level::Warn => LogFilter::Breadcrumb | LogFilter::Log, + log::Level::Info => LogFilter::Breadcrumb, + log::Level::Debug | log::Level::Trace => LogFilter::Ignore, + } + }) +} + /// Rotates existing active log into a timestamped zip archive. /// /// # Parameters diff --git a/Backend/src/monitoring.rs b/Backend/src/monitoring.rs new file mode 100644 index 00000000..b6733652 --- /dev/null +++ b/Backend/src/monitoring.rs @@ -0,0 +1,371 @@ +// Copyright © 2025-2026 OpenVCS Contributors +// SPDX-License-Identifier: GPL-3.0-or-later +//! Sentry-based crash reporting for the desktop backend. + +use std::borrow::Cow; +use std::sync::Mutex; + +use sentry::protocol::{Breadcrumb, Event, Exception, Frame, Map, Stacktrace, Value}; +use serde::Deserialize; + +use crate::settings::AppConfig; + +/// Environment variable containing the backend Sentry DSN. +const BACKEND_SENTRY_DSN_ENV: &str = "OPENVCS_SENTRY_DSN"; +/// Environment variable overriding the backend Sentry environment name. +const BACKEND_SENTRY_ENVIRONMENT_ENV: &str = "OPENVCS_SENTRY_ENVIRONMENT"; +/// Build-time fallback Sentry DSN embedded during CI/local builds. +const BACKEND_SENTRY_DSN_BUILT: Option<&str> = option_env!("OPENVCS_SENTRY_DSN_BUILT"); +/// Build-time fallback Sentry environment embedded during CI/local builds. +const BACKEND_SENTRY_ENVIRONMENT_BUILT: Option<&str> = + option_env!("OPENVCS_SENTRY_ENVIRONMENT_BUILT"); +/// Keeps the active backend Sentry guard alive for as long as reporting is enabled. +static BACKEND_MONITORING_GUARD: Mutex> = Mutex::new(None); + +/// Represents a relayed frontend breadcrumb forwarded to the backend. +#[derive(Debug, Clone, Deserialize)] +#[serde(rename_all = "camelCase")] +pub struct FrontendBreadcrumb { + /// Unix timestamp in milliseconds when the breadcrumb was recorded. + pub timestamp_ms: i64, + /// Severity level of the breadcrumb. + pub level: String, + /// Human-readable breadcrumb message. + pub message: String, +} + +/// Represents a normalized frontend error report captured in the webview. +#[derive(Debug, Clone, Deserialize)] +#[serde(rename_all = "camelCase")] +pub struct FrontendErrorReport { + /// Logical frontend error kind. + pub kind: String, + /// Primary error message. + pub message: String, + /// Optional JavaScript stack string. + pub stack: Option, + /// Optional script source URL or path. + pub source: Option, + /// Optional line number. + pub line: Option, + /// Optional column number. + pub column: Option, + /// Current window URL. + pub url: Option, + /// Current browser/webview user agent. + pub user_agent: Option, + /// Frontend release string from the build. + pub release: Option, + /// Frontend environment string from the build. + pub environment: Option, + /// Recent frontend breadcrumbs recorded before the error. + #[serde(default)] + pub breadcrumbs: Vec, +} + +/// Trims a string-like value and normalizes empty strings to `None`. +fn normalize_env_value(value: Option) -> Option { + value.and_then(|value| { + let normalized = value.trim().to_string(); + if normalized.is_empty() { + None + } else { + Some(normalized) + } + }) +} + +/// Returns whether backend crash reporting is allowed by current settings. +fn backend_monitoring_allowed(cfg: &AppConfig) -> bool { + cfg.general.crash_reports +} + +/// Builds a backend Sentry guard when configuration and environment permit it. +fn build_backend_monitoring_guard(cfg: &AppConfig) -> Option { + if !backend_monitoring_allowed(cfg) { + log::info!("monitoring: backend Sentry disabled by configuration"); + return None; + } + + let dsn = normalize_env_value(std::env::var(BACKEND_SENTRY_DSN_ENV).ok()).or_else(|| { + normalize_env_value(BACKEND_SENTRY_DSN_BUILT.map(str::to_string)) + }); + let Some(dsn) = dsn else { + log::info!( + "monitoring: backend Sentry disabled because {BACKEND_SENTRY_DSN_ENV} is unset and no build-time fallback was embedded" + ); + return None; + }; + + let environment = normalize_env_value(std::env::var(BACKEND_SENTRY_ENVIRONMENT_ENV).ok()) + .or_else(|| normalize_env_value(BACKEND_SENTRY_ENVIRONMENT_BUILT.map(str::to_string))) + .unwrap_or_else(|| "desktop".to_string()); + let release = format!("openvcs-client@{}", env!("OPENVCS_VERSION")); + + let guard = sentry::init(( + dsn, + sentry::ClientOptions { + release: Some(Cow::Owned(release)), + environment: Some(Cow::Owned(environment)), + attach_stacktrace: true, + enable_logs: true, + ..Default::default() + }, + )); + + sentry::configure_scope(|scope| { + scope.set_tag("component", "backend"); + scope.set_tag("channel", env!("OPENVCS_APP_CHANNEL")); + scope.set_tag("version", env!("OPENVCS_VERSION")); + }); + + log::info!("monitoring: backend Sentry enabled"); + Some(guard) +} + +/// Synchronizes backend Sentry reporting with the latest persisted configuration. +/// +/// # Parameters +/// - `cfg`: Current application configuration used for crash-report consent. +/// +/// # Returns +/// - `()`. +pub fn sync_backend_monitoring(cfg: &AppConfig) { + let mut active_guard = match BACKEND_MONITORING_GUARD.lock() { + Ok(guard) => guard, + Err(poisoned) => { + log::warn!("monitoring: recovering from poisoned backend monitoring mutex"); + poisoned.into_inner() + } + }; + *active_guard = build_backend_monitoring_guard(cfg); + crate::logging::set_sentry_log_forwarding_enabled(active_guard.is_some()); +} + +/// Captures a startup-time backend error with operation-specific tags. +/// +/// # Parameters +/// - `operation`: Short name of the failing startup step. +/// - `error`: Error description to attach to the captured event. +/// +/// # Returns +/// - `()`. +pub fn capture_startup_error(operation: &str, error: &str) { + if sentry::Hub::current().client().is_none() { + return; + } + + sentry::with_scope( + |scope| { + scope.set_tag("component", "backend"); + scope.set_tag("phase", "startup"); + scope.set_tag("operation", operation.to_string()); + }, + || { + sentry::capture_message( + &format!("startup {operation} failed: {error}"), + sentry::Level::Error, + ); + }, + ); +} + +/// Captures a normalized frontend error through the backend-owned Sentry client. +/// +/// # Parameters +/// - `payload`: Normalized frontend error report from the webview. +/// +/// # Returns +/// - `()`. +pub fn capture_frontend_error(payload: FrontendErrorReport) { + if sentry::Hub::current().client().is_none() { + return; + } + + let level = sentry::Level::Error; + let stack = payload.stack.clone(); + let message = payload.message.clone(); + let breadcrumbs = payload + .breadcrumbs + .iter() + .map(build_frontend_breadcrumb) + .collect::>(); + + let mut extra = Map::new(); + insert_extra(&mut extra, "source", payload.source.clone()); + insert_extra(&mut extra, "url", payload.url.clone()); + insert_extra(&mut extra, "user_agent", payload.user_agent.clone()); + insert_extra(&mut extra, "release", payload.release.clone()); + insert_extra(&mut extra, "environment", payload.environment.clone()); + insert_extra(&mut extra, "stack", stack); + if let Some(line) = payload.line { + extra.insert("line".into(), Value::from(line)); + } + if let Some(column) = payload.column { + extra.insert("column".into(), Value::from(column)); + } + + let event = Event { + level, + message: Some(message), + logger: Some("frontend".into()), + release: payload.release.map(Cow::Owned), + environment: payload.environment.map(Cow::Owned), + exception: vec![Exception { + ty: payload.kind.clone(), + value: Some(payload.message), + stacktrace: parse_frontend_stacktrace(payload.stack.as_deref()), + ..Default::default() + }] + .into(), + breadcrumbs: breadcrumbs.into(), + extra, + ..Default::default() + }; + + sentry::with_scope( + |scope| { + scope.set_tag("component", "frontend"); + scope.set_tag("runtime", "tauri-webview"); + scope.set_tag("frontend_kind", payload.kind.clone()); + }, + || { + sentry::capture_event(event); + }, + ); +} + +/// Parses a JavaScript stack string into a Sentry stacktrace when possible. +fn parse_frontend_stacktrace(stack: Option<&str>) -> Option { + let stack = stack?.trim(); + if stack.is_empty() { + return None; + } + + let mut frames = stack + .lines() + .filter_map(parse_frontend_stack_frame) + .collect::>(); + if frames.is_empty() { + return None; + } + + frames.reverse(); + Some(Stacktrace { + frames, + ..Default::default() + }) +} + +/// Parses a single JavaScript stack frame line into a Sentry frame. +fn parse_frontend_stack_frame(line: &str) -> Option { + let trimmed = line.trim(); + if trimmed.is_empty() { + return None; + } + + let without_at = trimmed.strip_prefix("at ").unwrap_or(trimmed); + let (function, location) = if let Some(open_paren) = without_at.rfind(" (") { + let function = without_at[..open_paren].trim(); + let location = without_at + .get(open_paren + 2..without_at.len().saturating_sub(1))? + .trim(); + (normalize_stack_part(function), location) + } else if let Some((function, location)) = without_at.rsplit_once('@') { + (normalize_stack_part(function), location.trim()) + } else { + (None, without_at) + }; + + let (filename, lineno, colno) = parse_frontend_location(location)?; + Some(Frame { + function, + filename: Some(filename), + lineno, + colno, + ..Default::default() + }) +} + +/// Normalizes an optional function name from a JavaScript stack frame. +fn normalize_stack_part(value: &str) -> Option { + let value = value.trim(); + (!value.is_empty()).then(|| value.to_string()) +} + +/// Parses a `url:line:column` location suffix from a JavaScript stack frame. +fn parse_frontend_location(location: &str) -> Option<(String, Option, Option)> { + let (prefix, colno_raw) = location.rsplit_once(':')?; + let (filename_raw, lineno_raw) = prefix.rsplit_once(':')?; + let filename = filename_raw.trim().to_string(); + if filename.is_empty() { + return None; + } + + let lineno = lineno_raw.trim().parse::().ok(); + let colno = colno_raw.trim().parse::().ok(); + Some((filename, lineno, colno)) +} + +/// Builds a Sentry breadcrumb from a relayed frontend breadcrumb payload. +fn build_frontend_breadcrumb(breadcrumb: &FrontendBreadcrumb) -> Breadcrumb { + Breadcrumb { + ty: "default".into(), + category: Some("console".into()), + level: parse_frontend_level(&breadcrumb.level), + message: Some(breadcrumb.message.clone()), + timestamp: std::time::UNIX_EPOCH + + std::time::Duration::from_millis(breadcrumb.timestamp_ms.max(0) as u64), + ..Default::default() + } +} + +/// Maps relayed frontend levels to Sentry levels. +fn parse_frontend_level(level: &str) -> sentry::Level { + match level { + "fatal" => sentry::Level::Fatal, + "error" => sentry::Level::Error, + "warning" | "warn" => sentry::Level::Warning, + "info" => sentry::Level::Info, + _ => sentry::Level::Debug, + } +} + +/// Inserts an optional string into a Sentry event extra map. +fn insert_extra(extra: &mut Map, key: &str, value: Option) { + if let Some(value) = value { + extra.insert(key.into(), Value::String(value)); + } +} + +#[cfg(test)] +mod tests { + use super::{parse_frontend_level, parse_frontend_location, parse_frontend_stacktrace}; + + #[test] + fn parses_frontend_location_suffix() { + let parsed = parse_frontend_location("app://index.js:12:34"); + assert_eq!(parsed, Some(("app://index.js".into(), Some(12), Some(34)))); + } + + #[test] + fn parses_frontend_stacktrace_frames() { + let stacktrace = parse_frontend_stacktrace(Some( + "Error: boom\n at alpha (app://index.js:2:3)\n at beta (app://index.js:4:5)", + )) + .expect("stacktrace expected"); + + assert_eq!(stacktrace.frames.len(), 2); + assert_eq!(stacktrace.frames[0].function.as_deref(), Some("beta")); + assert_eq!(stacktrace.frames[0].lineno, Some(4)); + assert_eq!(stacktrace.frames[1].function.as_deref(), Some("alpha")); + assert_eq!(stacktrace.frames[1].colno, Some(3)); + } + + #[test] + fn maps_frontend_levels_to_sentry_levels() { + assert_eq!(parse_frontend_level("warning"), sentry::Level::Warning); + assert_eq!(parse_frontend_level("error"), sentry::Level::Error); + assert_eq!(parse_frontend_level("other"), sentry::Level::Debug); + } +} diff --git a/Backend/src/settings.rs b/Backend/src/settings.rs index 69be2d4c..2df7739d 100644 --- a/Backend/src/settings.rs +++ b/Backend/src/settings.rs @@ -85,13 +85,13 @@ pub struct General { pub default_backend: String, #[serde(default)] pub update_channel: UpdateChannel, - #[serde(default)] + #[serde(default = "default_true")] pub reopen_last_repos: bool, - #[serde(default)] + #[serde(default = "default_true")] pub checks_on_launch: bool, #[serde(default)] pub telemetry: bool, - #[serde(default)] + #[serde(default = "default_true")] pub crash_reports: bool, } impl Default for General { @@ -109,7 +109,7 @@ impl Default for General { reopen_last_repos: true, checks_on_launch: true, telemetry: false, - crash_reports: false, + crash_reports: true, } } } diff --git a/Backend/src/state.rs b/Backend/src/state.rs index 5d687d09..1755152f 100644 --- a/Backend/src/state.rs +++ b/Backend/src/state.rs @@ -126,6 +126,7 @@ impl AppState { next.validate(); next.save().map_err(|e| e.to_string())?; apply_git_ssh_env(&next); + crate::monitoring::sync_backend_monitoring(&next); *self.config.write() = next; self.enforce_recents_limit_and_persist(); Ok(()) diff --git a/Backend/src/tauri_commands/mod.rs b/Backend/src/tauri_commands/mod.rs index 47f2f3a9..2d61d627 100644 --- a/Backend/src/tauri_commands/mod.rs +++ b/Backend/src/tauri_commands/mod.rs @@ -10,6 +10,7 @@ mod branches; mod commit; mod conflicts; mod general; +mod monitoring; mod output_log; mod plugins; mod remotes; @@ -27,6 +28,7 @@ pub use branches::*; pub use commit::*; pub use conflicts::*; pub use general::*; +pub use monitoring::*; pub use output_log::*; pub use plugins::*; pub use remotes::*; diff --git a/Backend/src/tauri_commands/monitoring.rs b/Backend/src/tauri_commands/monitoring.rs new file mode 100644 index 00000000..a7371dff --- /dev/null +++ b/Backend/src/tauri_commands/monitoring.rs @@ -0,0 +1,17 @@ +// Copyright © 2025-2026 OpenVCS Contributors +// SPDX-License-Identifier: GPL-3.0-or-later + +use crate::monitoring::FrontendErrorReport; + +#[tauri::command] +/// Reports a frontend error payload to the backend-owned monitoring pipeline. +/// +/// # Parameters +/// - `payload`: Normalized frontend error report from the Tauri webview. +/// +/// # Returns +/// - `Ok(())` after the payload has been offered to the monitoring backend. +pub fn report_frontend_error(payload: FrontendErrorReport) -> Result<(), String> { + crate::monitoring::capture_frontend_error(payload); + Ok(()) +} diff --git a/Backend/src/tauri_commands/output_log.rs b/Backend/src/tauri_commands/output_log.rs index d04cebb8..196c566c 100644 --- a/Backend/src/tauri_commands/output_log.rs +++ b/Backend/src/tauri_commands/output_log.rs @@ -97,20 +97,13 @@ pub fn log_frontend_message(state: tauri::State<'_, AppState>, level: String, me _ => (OutputLevel::Info, log::Level::Info), }; - // Write directly to stderr with [FRONTEND] tag - let now = time::OffsetDateTime::now_utc(); - let timestamp = format!( - "{:04}-{:02}-{:02} {:02}:{:02}:{:02}", - now.year(), - now.month() as u8, - now.day(), - now.hour(), - now.minute(), - now.second() - ); - let log_line = format!("{} {:5} [FRONTEND]: {}", timestamp, log_level, message); - eprintln!("{}", log_line); - let _ = crate::logging::write_to_log(&log_line); + let args = format_args!("{}", message); + let record = log::Record::builder() + .args(args) + .level(log_level) + .target("frontend") + .build(); + log::logger().log(&record); let entry = OutputLogEntry::new( std::time::SystemTime::now() diff --git a/Backend/src/tauri_commands/shared.rs b/Backend/src/tauri_commands/shared.rs index 3f4f3e36..b8570386 100644 --- a/Backend/src/tauri_commands/shared.rs +++ b/Backend/src/tauri_commands/shared.rs @@ -63,9 +63,15 @@ pub(crate) fn progress_bridge(app: AppHandle) -> OnEvent { /// - `Ok(Arc)` for the active repository. /// - `Err(String)` when no repo is selected or backend is unavailable. pub(crate) fn current_repo_or_err(state: &State<'_, AppState>) -> Result, String> { - let repo = state - .current_repo() - .ok_or_else(|| "No repository selected".to_string())?; + let repo = match state.current_repo() { + Some(repo) => repo, + None => { + log::warn!( + "repo command aborted: no repository selected; possible causes include no VCS backend available, reopen/startup failure, or the active repo being cleared" + ); + return Err("No repository selected".to_string()); + } + }; let backend_id = repo.id(); let is_available = plugin_vcs_backends::has_plugin_vcs_backend(&backend_id); @@ -73,6 +79,10 @@ pub(crate) fn current_repo_or_err(state: &State<'_, AppState>) -> Result=6.9.0" + } + }, + "node_modules/@babel/compat-data": { + "version": "7.29.0", + "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.29.0.tgz", + "integrity": "sha512-T1NCJqT/j9+cn8fvkt7jtwbLBfLC/1y1c7NtCeXFRgzGTsafi68MRv8yzkYSapBnFA6L3U2VSc02ciDzoAJhJg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/core": { + "version": "7.29.0", + "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.29.0.tgz", + "integrity": "sha512-CGOfOJqWjg2qW/Mb6zNsDm+u5vFQ8DxXfbM09z69p5Z6+mE1ikP2jUXw+j42Pf1XTYED2Rni5f95npYeuwMDQA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/code-frame": "^7.29.0", + "@babel/generator": "^7.29.0", + "@babel/helper-compilation-targets": "^7.28.6", + "@babel/helper-module-transforms": "^7.28.6", + "@babel/helpers": "^7.28.6", + "@babel/parser": "^7.29.0", + "@babel/template": "^7.28.6", + "@babel/traverse": "^7.29.0", + "@babel/types": "^7.29.0", + "@jridgewell/remapping": "^2.3.5", + "convert-source-map": "^2.0.0", + "debug": "^4.1.0", + "gensync": "^1.0.0-beta.2", + "json5": "^2.2.3", + "semver": "^6.3.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/babel" + } + }, + "node_modules/@babel/generator": { + "version": "7.29.1", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.29.1.tgz", + "integrity": "sha512-qsaF+9Qcm2Qv8SRIMMscAvG4O3lJ0F1GuMo5HR/Bp02LopNgnZBC/EkbevHFeGs4ls/oPz9v+Bsmzbkbe+0dUw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/parser": "^7.29.0", + "@babel/types": "^7.29.0", + "@jridgewell/gen-mapping": "^0.3.12", + "@jridgewell/trace-mapping": "^0.3.28", + "jsesc": "^3.0.2" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-compilation-targets": { + "version": "7.28.6", + "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.28.6.tgz", + "integrity": "sha512-JYtls3hqi15fcx5GaSNL7SCTJ2MNmjrkHXg4FSpOA/grxK8KwyZ5bubHsCq8FXCkua6xhuaaBit+3b7+VZRfcA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/compat-data": "^7.28.6", + "@babel/helper-validator-option": "^7.27.1", + "browserslist": "^4.24.0", + "lru-cache": "^5.1.1", + "semver": "^6.3.1" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-compilation-targets/node_modules/lru-cache": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-5.1.1.tgz", + "integrity": "sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==", + "dev": true, + "license": "ISC", + "dependencies": { + "yallist": "^3.0.2" + } + }, + "node_modules/@babel/helper-globals": { + "version": "7.28.0", + "resolved": "https://registry.npmjs.org/@babel/helper-globals/-/helper-globals-7.28.0.tgz", + "integrity": "sha512-+W6cISkXFa1jXsDEdYA8HeevQT/FULhxzR99pxphltZcVaugps53THCeiWA8SguxxpSp3gKPiuYfSWopkLQ4hw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-module-imports": { + "version": "7.28.6", + "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.28.6.tgz", + "integrity": "sha512-l5XkZK7r7wa9LucGw9LwZyyCUscb4x37JWTPz7swwFE/0FMQAGpiWUZn8u9DzkSBWEcK25jmvubfpw2dnAMdbw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/traverse": "^7.28.6", + "@babel/types": "^7.28.6" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-module-transforms": { + "version": "7.28.6", + "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.28.6.tgz", + "integrity": "sha512-67oXFAYr2cDLDVGLXTEABjdBJZ6drElUSI7WKp70NrpyISso3plG9SAGEF6y7zbha/wOzUByWWTJvEDVNIUGcA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-module-imports": "^7.28.6", + "@babel/helper-validator-identifier": "^7.28.5", + "@babel/traverse": "^7.28.6" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/helper-string-parser": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.27.1.tgz", + "integrity": "sha512-qMlSxKbpRlAridDExk92nSobyDdpPijUq2DW6oDnUqd0iOGxmQjyqhMIihI9+zv4LPyZdRje2cavWPbCbWm3eA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-validator-identifier": { + "version": "7.28.5", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.28.5.tgz", + "integrity": "sha512-qSs4ifwzKJSV39ucNjsvc6WVHs6b7S03sOh2OcHF9UHfVPqWWALUsNUVzhSBiItjRZoLHx7nIarVjqKVusUZ1Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-validator-option": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.27.1.tgz", + "integrity": "sha512-YvjJow9FxbhFFKDSuFnVCe2WxXk1zWc22fFePVNEaWJEu8IrZVlda6N0uHwzZrUM1il7NC9Mlp4MaJYbYd9JSg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helpers": { + "version": "7.29.2", + "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.29.2.tgz", + "integrity": "sha512-HoGuUs4sCZNezVEKdVcwqmZN8GoHirLUcLaYVNBK2J0DadGtdcqgr3BCbvH8+XUo4NGjNl3VOtSjEKNzqfFgKw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/template": "^7.28.6", + "@babel/types": "^7.29.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/parser": { + "version": "7.29.2", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.29.2.tgz", + "integrity": "sha512-4GgRzy/+fsBa72/RZVJmGKPmZu9Byn8o4MoLpmNe1m8ZfYnz5emHLQz3U4gLud6Zwl0RZIcgiLD7Uq7ySFuDLA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/types": "^7.29.0" + }, + "bin": { + "parser": "bin/babel-parser.js" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@babel/template": { + "version": "7.28.6", + "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.28.6.tgz", + "integrity": "sha512-YA6Ma2KsCdGb+WC6UpBVFJGXL58MDA6oyONbjyF/+5sBgxY/dwkhLogbMT2GXXyU84/IhRw/2D1Os1B/giz+BQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/code-frame": "^7.28.6", + "@babel/parser": "^7.28.6", + "@babel/types": "^7.28.6" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/traverse": { + "version": "7.29.0", + "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.29.0.tgz", + "integrity": "sha512-4HPiQr0X7+waHfyXPZpWPfWL/J7dcN1mx9gL6WdQVMbPnF3+ZhSMs8tCxN7oHddJE9fhNE7+lxdnlyemKfJRuA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/code-frame": "^7.29.0", + "@babel/generator": "^7.29.0", + "@babel/helper-globals": "^7.28.0", + "@babel/parser": "^7.29.0", + "@babel/template": "^7.28.6", + "@babel/types": "^7.29.0", + "debug": "^4.3.1" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/types": { + "version": "7.29.0", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.29.0.tgz", + "integrity": "sha512-LwdZHpScM4Qz8Xw2iKSzS+cfglZzJGvofQICy7W7v4caru4EaAmyUuO6BGrbyQ2mYV11W0U8j5mBhd14dd3B0A==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-string-parser": "^7.27.1", + "@babel/helper-validator-identifier": "^7.28.5" + }, + "engines": { + "node": ">=6.9.0" + } + }, "node_modules/@bramus/specificity": { "version": "2.4.2", "resolved": "https://registry.npmjs.org/@bramus/specificity/-/specificity-2.4.2.tgz", @@ -275,6 +526,56 @@ } } }, + "node_modules/@isaacs/cliui": { + "version": "8.0.2", + "resolved": "https://registry.npmjs.org/@isaacs/cliui/-/cliui-8.0.2.tgz", + "integrity": "sha512-O8jcjabXaleOG9DQ0+ARXWZBTfnP4WNAqzuiJK7ll44AmxGKv/J2M4TPjxjY3znBCfvBXFzucm1twdyFybFqEA==", + "dev": true, + "license": "ISC", + "dependencies": { + "string-width": "^5.1.2", + "string-width-cjs": "npm:string-width@^4.2.0", + "strip-ansi": "^7.0.1", + "strip-ansi-cjs": "npm:strip-ansi@^6.0.1", + "wrap-ansi": "^8.1.0", + "wrap-ansi-cjs": "npm:wrap-ansi@^7.0.0" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/@jridgewell/gen-mapping": { + "version": "0.3.13", + "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.13.tgz", + "integrity": "sha512-2kkt/7niJ6MgEPxF0bYdQ6etZaA+fQvDcLKckhy1yIQOzaoKjBBjSj63/aLVjYE3qhRt5dvM+uUyfCg6UKCBbA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jridgewell/sourcemap-codec": "^1.5.0", + "@jridgewell/trace-mapping": "^0.3.24" + } + }, + "node_modules/@jridgewell/remapping": { + "version": "2.3.5", + "resolved": "https://registry.npmjs.org/@jridgewell/remapping/-/remapping-2.3.5.tgz", + "integrity": "sha512-LI9u/+laYG4Ds1TDKSJW2YPrIlcVYOwi2fUC6xB43lueCjgxV4lffOCZCtYFiH6TNOX+tQKXx97T4IKHbhyHEQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jridgewell/gen-mapping": "^0.3.5", + "@jridgewell/trace-mapping": "^0.3.24" + } + }, + "node_modules/@jridgewell/resolve-uri": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz", + "integrity": "sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.0.0" + } + }, "node_modules/@jridgewell/sourcemap-codec": { "version": "1.5.5", "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.5.tgz", @@ -282,6 +583,17 @@ "dev": true, "license": "MIT" }, + "node_modules/@jridgewell/trace-mapping": { + "version": "0.3.31", + "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.31.tgz", + "integrity": "sha512-zzNR+SdQSDJzc8joaeP8QQoCQr8NuYx2dIIytl1QeBEZHJ9uW6hebsrYgbz8hJwUQao3TWCMtmfV8Nu1twOLAw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jridgewell/resolve-uri": "^3.1.0", + "@jridgewell/sourcemap-codec": "^1.4.14" + } + }, "node_modules/@napi-rs/wasm-runtime": { "version": "1.1.4", "resolved": "https://registry.npmjs.org/@napi-rs/wasm-runtime/-/wasm-runtime-1.1.4.tgz", @@ -311,6 +623,17 @@ "url": "https://github.com/sponsors/Boshen" } }, + "node_modules/@pkgjs/parseargs": { + "version": "0.11.0", + "resolved": "https://registry.npmjs.org/@pkgjs/parseargs/-/parseargs-0.11.0.tgz", + "integrity": "sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg==", + "dev": true, + "license": "MIT", + "optional": true, + "engines": { + "node": ">=14" + } + }, "node_modules/@rolldown/binding-android-arm64": { "version": "1.0.0-rc.16", "resolved": "https://registry.npmjs.org/@rolldown/binding-android-arm64/-/binding-android-arm64-1.0.0-rc.16.tgz", @@ -593,119 +916,350 @@ "dev": true, "license": "MIT" }, - "node_modules/@standard-schema/spec": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/@standard-schema/spec/-/spec-1.1.0.tgz", - "integrity": "sha512-l2aFy5jALhniG5HgqrD6jXLi/rUWrKvqN/qJx6yoJsgKhblVd+iqqU4RCXavm/jPityDo5TCvKMnpjKnOriy0w==", - "dev": true, - "license": "MIT" - }, - "node_modules/@tybys/wasm-util": { - "version": "0.10.1", - "resolved": "https://registry.npmjs.org/@tybys/wasm-util/-/wasm-util-0.10.1.tgz", - "integrity": "sha512-9tTaPJLSiejZKx+Bmog4uSubteqTvFrVrURwkmHixBo0G4seD0zUxp98E1DzUBJxLQ3NPwXrGKDiVjwx/DpPsg==", - "dev": true, - "license": "MIT", - "optional": true, - "dependencies": { - "tslib": "^2.4.0" - } - }, - "node_modules/@types/chai": { - "version": "5.2.3", - "resolved": "https://registry.npmjs.org/@types/chai/-/chai-5.2.3.tgz", - "integrity": "sha512-Mw558oeA9fFbv65/y4mHtXDs9bPnFMZAL/jxdPFUpOHHIXX91mcgEHbS5Lahr+pwZFR8A7GQleRWeI6cGFC2UA==", + "node_modules/@sentry/babel-plugin-component-annotate": { + "version": "4.9.1", + "resolved": "https://registry.npmjs.org/@sentry/babel-plugin-component-annotate/-/babel-plugin-component-annotate-4.9.1.tgz", + "integrity": "sha512-0gEoi2Lb54MFYPOmdTfxlNKxI7kCOvNV7gP8lxMXJ7nCazF5OqOOZIVshfWjDLrc0QrSV6XdVvwPV9GDn4wBMg==", "dev": true, "license": "MIT", - "dependencies": { - "@types/deep-eql": "*", - "assertion-error": "^2.0.1" + "engines": { + "node": ">= 14" } }, - "node_modules/@types/deep-eql": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/@types/deep-eql/-/deep-eql-4.0.2.tgz", - "integrity": "sha512-c9h9dVVMigMPc4bwTvC5dxqtqJZwQPePsWjPlpSOnojbor6pGqdk541lfA7AqFQr5pB1BRdq0juY9db81BwyFw==", - "dev": true, - "license": "MIT" - }, - "node_modules/@types/estree": { - "version": "1.0.8", - "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.8.tgz", - "integrity": "sha512-dWHzHa2WqEXI/O1E9OjrocMTKJl2mSrEolh1Iomrv6U+JuNwaHXsXx9bLu5gG7BUWFIN0skIQJQ/L1rIex4X6w==", - "dev": true, - "license": "MIT" - }, - "node_modules/@types/node": { - "version": "25.6.0", - "resolved": "https://registry.npmjs.org/@types/node/-/node-25.6.0.tgz", - "integrity": "sha512-+qIYRKdNYJwY3vRCZMdJbPLJAtGjQBudzZzdzwQYkEPQd+PJGixUL5QfvCLDaULoLv+RhT3LDkwEfKaAkgSmNQ==", + "node_modules/@sentry/bundler-plugin-core": { + "version": "4.9.1", + "resolved": "https://registry.npmjs.org/@sentry/bundler-plugin-core/-/bundler-plugin-core-4.9.1.tgz", + "integrity": "sha512-moii+w7N8k8WdvkX7qCDY9iRBlhgHlhTHTUQwF2FNMhBHuqlNpVcSJJqJMjFUQcjYMBDrZgxhfKV18bt5ixwlQ==", "dev": true, "license": "MIT", "dependencies": { - "undici-types": "~7.19.0" + "@babel/core": "^7.18.5", + "@sentry/babel-plugin-component-annotate": "4.9.1", + "@sentry/cli": "^2.57.0", + "dotenv": "^16.3.1", + "find-up": "^5.0.0", + "glob": "^10.5.0", + "magic-string": "0.30.8", + "unplugin": "1.0.1" + }, + "engines": { + "node": ">= 14" } }, - "node_modules/@vitest/expect": { - "version": "4.1.4", - "resolved": "https://registry.npmjs.org/@vitest/expect/-/expect-4.1.4.tgz", - "integrity": "sha512-iPBpra+VDuXmBFI3FMKHSFXp3Gx5HfmSCE8X67Dn+bwephCnQCaB7qWK2ldHa+8ncN8hJU8VTMcxjPpyMkUjww==", + "node_modules/@sentry/bundler-plugin-core/node_modules/magic-string": { + "version": "0.30.8", + "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.8.tgz", + "integrity": "sha512-ISQTe55T2ao7XtlAStud6qwYPZjE4GK1S/BeVPus4jrq6JuOnQ00YKQC581RWhR122W7msZV263KzVeLoqidyQ==", "dev": true, "license": "MIT", "dependencies": { - "@standard-schema/spec": "^1.1.0", - "@types/chai": "^5.2.2", - "@vitest/spy": "4.1.4", - "@vitest/utils": "4.1.4", - "chai": "^6.2.2", - "tinyrainbow": "^3.1.0" + "@jridgewell/sourcemap-codec": "^1.4.15" }, - "funding": { - "url": "https://opencollective.com/vitest" + "engines": { + "node": ">=12" } }, - "node_modules/@vitest/mocker": { - "version": "4.1.4", - "resolved": "https://registry.npmjs.org/@vitest/mocker/-/mocker-4.1.4.tgz", - "integrity": "sha512-R9HTZBhW6yCSGbGQnDnH3QHfJxokKN4KB+Yvk9Q1le7eQNYwiCyKxmLmurSpFy6BzJanSLuEUDrD+j97Q+ZLPg==", + "node_modules/@sentry/cli": { + "version": "2.58.5", + "resolved": "https://registry.npmjs.org/@sentry/cli/-/cli-2.58.5.tgz", + "integrity": "sha512-tavJ7yGUZV+z3Ct2/ZB6mg339i08sAk6HDkgqmSRuQEu2iLS5sl9HIvuXfM6xjv8fwlgFOSy++WNABNAcGHUbg==", "dev": true, - "license": "MIT", + "hasInstallScript": true, + "license": "FSL-1.1-MIT", "dependencies": { - "@vitest/spy": "4.1.4", - "estree-walker": "^3.0.3", - "magic-string": "^0.30.21" + "https-proxy-agent": "^5.0.0", + "node-fetch": "^2.6.7", + "progress": "^2.0.3", + "proxy-from-env": "^1.1.0", + "which": "^2.0.2" }, - "funding": { - "url": "https://opencollective.com/vitest" + "bin": { + "sentry-cli": "bin/sentry-cli" }, - "peerDependencies": { - "msw": "^2.4.9", - "vite": "^6.0.0 || ^7.0.0 || ^8.0.0" + "engines": { + "node": ">= 10" }, - "peerDependenciesMeta": { - "msw": { - "optional": true - }, - "vite": { - "optional": true - } + "optionalDependencies": { + "@sentry/cli-darwin": "2.58.5", + "@sentry/cli-linux-arm": "2.58.5", + "@sentry/cli-linux-arm64": "2.58.5", + "@sentry/cli-linux-i686": "2.58.5", + "@sentry/cli-linux-x64": "2.58.5", + "@sentry/cli-win32-arm64": "2.58.5", + "@sentry/cli-win32-i686": "2.58.5", + "@sentry/cli-win32-x64": "2.58.5" + } + }, + "node_modules/@sentry/cli-darwin": { + "version": "2.58.5", + "resolved": "https://registry.npmjs.org/@sentry/cli-darwin/-/cli-darwin-2.58.5.tgz", + "integrity": "sha512-lYrNzenZFJftfwSya7gwrHGxtE+Kob/e1sr9lmHMFOd4utDlmq0XFDllmdZAMf21fxcPRI1GL28ejZ3bId01fQ==", + "dev": true, + "license": "FSL-1.1-MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=10" } }, - "node_modules/@vitest/pretty-format": { - "version": "4.1.4", - "resolved": "https://registry.npmjs.org/@vitest/pretty-format/-/pretty-format-4.1.4.tgz", - "integrity": "sha512-ddmDHU0gjEUyEVLxtZa7xamrpIefdEETu3nZjWtHeZX4QxqJ7tRxSteHVXJOcr8jhiLoGAhkK4WJ3WqBpjx42A==", + "node_modules/@sentry/cli-linux-arm": { + "version": "2.58.5", + "resolved": "https://registry.npmjs.org/@sentry/cli-linux-arm/-/cli-linux-arm-2.58.5.tgz", + "integrity": "sha512-KtHweSIomYL4WVDrBrYSYJricKAAzxUgX86kc6OnlikbyOhoK6Fy8Vs6vwd52P6dvWPjgrMpUYjW2M5pYXQDUw==", + "cpu": [ + "arm" + ], "dev": true, - "license": "MIT", - "dependencies": { - "tinyrainbow": "^3.1.0" - }, - "funding": { - "url": "https://opencollective.com/vitest" - } - }, - "node_modules/@vitest/runner": { - "version": "4.1.4", + "license": "FSL-1.1-MIT", + "optional": true, + "os": [ + "linux", + "freebsd", + "android" + ], + "engines": { + "node": ">=10" + } + }, + "node_modules/@sentry/cli-linux-arm64": { + "version": "2.58.5", + "resolved": "https://registry.npmjs.org/@sentry/cli-linux-arm64/-/cli-linux-arm64-2.58.5.tgz", + "integrity": "sha512-/4gywFeBqRB6tR/iGMRAJ3HRqY6Z7Yp4l8ZCbl0TDLAfHNxu7schEw4tSnm2/Hh9eNMiOVy4z58uzAWlZXAYBQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "FSL-1.1-MIT", + "optional": true, + "os": [ + "linux", + "freebsd", + "android" + ], + "engines": { + "node": ">=10" + } + }, + "node_modules/@sentry/cli-linux-i686": { + "version": "2.58.5", + "resolved": "https://registry.npmjs.org/@sentry/cli-linux-i686/-/cli-linux-i686-2.58.5.tgz", + "integrity": "sha512-G7261dkmyxqlMdyvyP06b+RTIVzp1gZNgglj5UksxSouSUqRd/46W/2pQeOMPhloDYo9yLtCN2YFb3Mw4aUsWw==", + "cpu": [ + "x86", + "ia32" + ], + "dev": true, + "license": "FSL-1.1-MIT", + "optional": true, + "os": [ + "linux", + "freebsd", + "android" + ], + "engines": { + "node": ">=10" + } + }, + "node_modules/@sentry/cli-linux-x64": { + "version": "2.58.5", + "resolved": "https://registry.npmjs.org/@sentry/cli-linux-x64/-/cli-linux-x64-2.58.5.tgz", + "integrity": "sha512-rP04494RSmt86xChkQ+ecBNRYSPbyXc4u0IA7R7N1pSLCyO74e5w5Al+LnAq35cMfVbZgz5Sm0iGLjyiUu4I1g==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "FSL-1.1-MIT", + "optional": true, + "os": [ + "linux", + "freebsd", + "android" + ], + "engines": { + "node": ">=10" + } + }, + "node_modules/@sentry/cli-win32-arm64": { + "version": "2.58.5", + "resolved": "https://registry.npmjs.org/@sentry/cli-win32-arm64/-/cli-win32-arm64-2.58.5.tgz", + "integrity": "sha512-AOJ2nCXlQL1KBaCzv38m3i2VmSHNurUpm7xVKd6yAHX+ZoVBI8VT0EgvwmtJR2TY2N2hNCC7UrgRmdUsQ152bA==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "FSL-1.1-MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=10" + } + }, + "node_modules/@sentry/cli-win32-i686": { + "version": "2.58.5", + "resolved": "https://registry.npmjs.org/@sentry/cli-win32-i686/-/cli-win32-i686-2.58.5.tgz", + "integrity": "sha512-EsuboLSOnlrN7MMPJ1eFvfMDm+BnzOaSWl8eYhNo8W/BIrmNgpRUdBwnWn9Q2UOjJj5ZopukmsiMYtU/D7ml9g==", + "cpu": [ + "x86", + "ia32" + ], + "dev": true, + "license": "FSL-1.1-MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=10" + } + }, + "node_modules/@sentry/cli-win32-x64": { + "version": "2.58.5", + "resolved": "https://registry.npmjs.org/@sentry/cli-win32-x64/-/cli-win32-x64-2.58.5.tgz", + "integrity": "sha512-IZf+XIMiQwj+5NzqbOQfywlOitmCV424Vtf9c+ep61AaVScUFD1TSrQbOcJJv5xGxhlxNOMNgMeZhdexdzrKZg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "FSL-1.1-MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=10" + } + }, + "node_modules/@sentry/vite-plugin": { + "version": "4.9.1", + "resolved": "https://registry.npmjs.org/@sentry/vite-plugin/-/vite-plugin-4.9.1.tgz", + "integrity": "sha512-Tlyg2cyFYp/icX58GWvfpvZr9NLdLs2/xyFVyS8pQ0faZWmoXic3FMzoXYHV1gsdMbL1Yy5WQvGJy8j1rS8LGA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@sentry/bundler-plugin-core": "4.9.1", + "unplugin": "1.0.1" + }, + "engines": { + "node": ">= 14" + } + }, + "node_modules/@standard-schema/spec": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@standard-schema/spec/-/spec-1.1.0.tgz", + "integrity": "sha512-l2aFy5jALhniG5HgqrD6jXLi/rUWrKvqN/qJx6yoJsgKhblVd+iqqU4RCXavm/jPityDo5TCvKMnpjKnOriy0w==", + "dev": true, + "license": "MIT" + }, + "node_modules/@tybys/wasm-util": { + "version": "0.10.1", + "resolved": "https://registry.npmjs.org/@tybys/wasm-util/-/wasm-util-0.10.1.tgz", + "integrity": "sha512-9tTaPJLSiejZKx+Bmog4uSubteqTvFrVrURwkmHixBo0G4seD0zUxp98E1DzUBJxLQ3NPwXrGKDiVjwx/DpPsg==", + "dev": true, + "license": "MIT", + "optional": true, + "dependencies": { + "tslib": "^2.4.0" + } + }, + "node_modules/@types/chai": { + "version": "5.2.3", + "resolved": "https://registry.npmjs.org/@types/chai/-/chai-5.2.3.tgz", + "integrity": "sha512-Mw558oeA9fFbv65/y4mHtXDs9bPnFMZAL/jxdPFUpOHHIXX91mcgEHbS5Lahr+pwZFR8A7GQleRWeI6cGFC2UA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/deep-eql": "*", + "assertion-error": "^2.0.1" + } + }, + "node_modules/@types/deep-eql": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/@types/deep-eql/-/deep-eql-4.0.2.tgz", + "integrity": "sha512-c9h9dVVMigMPc4bwTvC5dxqtqJZwQPePsWjPlpSOnojbor6pGqdk541lfA7AqFQr5pB1BRdq0juY9db81BwyFw==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/estree": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.8.tgz", + "integrity": "sha512-dWHzHa2WqEXI/O1E9OjrocMTKJl2mSrEolh1Iomrv6U+JuNwaHXsXx9bLu5gG7BUWFIN0skIQJQ/L1rIex4X6w==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/node": { + "version": "25.6.0", + "resolved": "https://registry.npmjs.org/@types/node/-/node-25.6.0.tgz", + "integrity": "sha512-+qIYRKdNYJwY3vRCZMdJbPLJAtGjQBudzZzdzwQYkEPQd+PJGixUL5QfvCLDaULoLv+RhT3LDkwEfKaAkgSmNQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "undici-types": "~7.19.0" + } + }, + "node_modules/@vitest/expect": { + "version": "4.1.4", + "resolved": "https://registry.npmjs.org/@vitest/expect/-/expect-4.1.4.tgz", + "integrity": "sha512-iPBpra+VDuXmBFI3FMKHSFXp3Gx5HfmSCE8X67Dn+bwephCnQCaB7qWK2ldHa+8ncN8hJU8VTMcxjPpyMkUjww==", + "dev": true, + "license": "MIT", + "dependencies": { + "@standard-schema/spec": "^1.1.0", + "@types/chai": "^5.2.2", + "@vitest/spy": "4.1.4", + "@vitest/utils": "4.1.4", + "chai": "^6.2.2", + "tinyrainbow": "^3.1.0" + }, + "funding": { + "url": "https://opencollective.com/vitest" + } + }, + "node_modules/@vitest/mocker": { + "version": "4.1.4", + "resolved": "https://registry.npmjs.org/@vitest/mocker/-/mocker-4.1.4.tgz", + "integrity": "sha512-R9HTZBhW6yCSGbGQnDnH3QHfJxokKN4KB+Yvk9Q1le7eQNYwiCyKxmLmurSpFy6BzJanSLuEUDrD+j97Q+ZLPg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@vitest/spy": "4.1.4", + "estree-walker": "^3.0.3", + "magic-string": "^0.30.21" + }, + "funding": { + "url": "https://opencollective.com/vitest" + }, + "peerDependencies": { + "msw": "^2.4.9", + "vite": "^6.0.0 || ^7.0.0 || ^8.0.0" + }, + "peerDependenciesMeta": { + "msw": { + "optional": true + }, + "vite": { + "optional": true + } + } + }, + "node_modules/@vitest/pretty-format": { + "version": "4.1.4", + "resolved": "https://registry.npmjs.org/@vitest/pretty-format/-/pretty-format-4.1.4.tgz", + "integrity": "sha512-ddmDHU0gjEUyEVLxtZa7xamrpIefdEETu3nZjWtHeZX4QxqJ7tRxSteHVXJOcr8jhiLoGAhkK4WJ3WqBpjx42A==", + "dev": true, + "license": "MIT", + "dependencies": { + "tinyrainbow": "^3.1.0" + }, + "funding": { + "url": "https://opencollective.com/vitest" + } + }, + "node_modules/@vitest/runner": { + "version": "4.1.4", "resolved": "https://registry.npmjs.org/@vitest/runner/-/runner-4.1.4.tgz", "integrity": "sha512-xTp7VZ5aXP5ZJrn15UtJUWlx6qXLnGtF6jNxHepdPHpMfz/aVPx+htHtgcAL2mDXJgKhpoo2e9/hVJsIeFbytQ==", "dev": true, @@ -759,6 +1313,85 @@ "url": "https://opencollective.com/vitest" } }, + "node_modules/acorn": { + "version": "8.16.0", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.16.0.tgz", + "integrity": "sha512-UVJyE9MttOsBQIDKw1skb9nAwQuR5wuGD3+82K6JgJlm/Y+KI92oNsMNGZCYdDsVtRHSak0pcV5Dno5+4jh9sw==", + "dev": true, + "license": "MIT", + "bin": { + "acorn": "bin/acorn" + }, + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/agent-base": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-6.0.2.tgz", + "integrity": "sha512-RZNwNclF7+MS/8bDg70amg32dyeZGZxiDuQmZxKLAlQjr3jGyLx+4Kkk58UO7D2QdgFIQCovuSuZESne6RG6XQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "debug": "4" + }, + "engines": { + "node": ">= 6.0.0" + } + }, + "node_modules/ansi-regex": { + "version": "6.2.2", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.2.2.tgz", + "integrity": "sha512-Bq3SmSpyFHaWjPk8If9yc6svM8c56dB5BAtW4Qbw5jHTwwXXcTLoRMkpDJp6VL0XzlWaCHTXrkFURMYmD0sLqg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/ansi-regex?sponsor=1" + } + }, + "node_modules/ansi-styles": { + "version": "6.2.3", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-6.2.3.tgz", + "integrity": "sha512-4Dj6M28JB+oAH8kFkTLUo+a2jwOFkuqb3yucU0CANcRRUbxS0cP0nZYCGjcc3BNXwRIsUVmDGgzawme7zvJHvg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/anymatch": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.3.tgz", + "integrity": "sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==", + "dev": true, + "license": "ISC", + "dependencies": { + "normalize-path": "^3.0.0", + "picomatch": "^2.0.4" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/anymatch/node_modules/picomatch": { + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.2.tgz", + "integrity": "sha512-V7+vQEJ06Z+c5tSye8S+nHUfI51xoXIXjHQ99cQtKUkQqqO1kO/KCJUfZXuB47h/YBlDhah2H3hdUGXn8ie0oA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8.6" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, "node_modules/assertion-error": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/assertion-error/-/assertion-error-2.0.1.tgz", @@ -769,6 +1402,26 @@ "node": ">=12" } }, + "node_modules/balanced-match": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", + "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", + "dev": true, + "license": "MIT" + }, + "node_modules/baseline-browser-mapping": { + "version": "2.10.20", + "resolved": "https://registry.npmjs.org/baseline-browser-mapping/-/baseline-browser-mapping-2.10.20.tgz", + "integrity": "sha512-1AaXxEPfXT+GvTBJFuy4yXVHWJBXa4OdbIebGN/wX5DlsIkU0+wzGnd2lOzokSk51d5LUmqjgBLRLlypLUqInQ==", + "dev": true, + "license": "Apache-2.0", + "bin": { + "baseline-browser-mapping": "dist/cli.cjs" + }, + "engines": { + "node": ">=6.0.0" + } + }, "node_modules/bidi-js": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/bidi-js/-/bidi-js-1.0.3.tgz", @@ -779,6 +1432,97 @@ "require-from-string": "^2.0.2" } }, + "node_modules/binary-extensions": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.3.0.tgz", + "integrity": "sha512-Ceh+7ox5qe7LJuLHoY0feh3pHuUDHAcRUeyL2VYghZwfpkNIy/+8Ocg0a3UuSoYzavmylwuLWQOf3hl0jjMMIw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/brace-expansion": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.1.0.tgz", + "integrity": "sha512-TN1kCZAgdgweJhWWpgKYrQaMNHcDULHkWwQIspdtjV4Y5aurRdZpjAqn6yX3FPqTA9ngHCc4hJxMAMgGfve85w==", + "dev": true, + "license": "MIT", + "dependencies": { + "balanced-match": "^1.0.0" + } + }, + "node_modules/braces": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.3.tgz", + "integrity": "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==", + "dev": true, + "license": "MIT", + "dependencies": { + "fill-range": "^7.1.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/browserslist": { + "version": "4.28.2", + "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.28.2.tgz", + "integrity": "sha512-48xSriZYYg+8qXna9kwqjIVzuQxi+KYWp2+5nCYnYKPTr0LvD89Jqk2Or5ogxz0NUMfIjhh2lIUX/LyX9B4oIg==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/browserslist" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "dependencies": { + "baseline-browser-mapping": "^2.10.12", + "caniuse-lite": "^1.0.30001782", + "electron-to-chromium": "^1.5.328", + "node-releases": "^2.0.36", + "update-browserslist-db": "^1.2.3" + }, + "bin": { + "browserslist": "cli.js" + }, + "engines": { + "node": "^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7" + } + }, + "node_modules/caniuse-lite": { + "version": "1.0.30001788", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001788.tgz", + "integrity": "sha512-6q8HFp+lOQtcf7wBK+uEenxymVWkGKkjFpCvw5W25cmMwEDU45p1xQFBQv8JDlMMry7eNxyBaR+qxgmTUZkIRQ==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/caniuse-lite" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "CC-BY-4.0" + }, "node_modules/chai": { "version": "6.2.2", "resolved": "https://registry.npmjs.org/chai/-/chai-6.2.2.tgz", @@ -789,6 +1533,51 @@ "node": ">=18" } }, + "node_modules/chokidar": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.6.0.tgz", + "integrity": "sha512-7VT13fmjotKpGipCW9JEQAusEPE+Ei8nl6/g4FBAmIm0GOOLMua9NDDo/DWp0ZAxCr3cPq5ZpBqmPAQgDda2Pw==", + "dev": true, + "license": "MIT", + "dependencies": { + "anymatch": "~3.1.2", + "braces": "~3.0.2", + "glob-parent": "~5.1.2", + "is-binary-path": "~2.1.0", + "is-glob": "~4.0.1", + "normalize-path": "~3.0.0", + "readdirp": "~3.6.0" + }, + "engines": { + "node": ">= 8.10.0" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + }, + "optionalDependencies": { + "fsevents": "~2.3.2" + } + }, + "node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true, + "license": "MIT" + }, "node_modules/convert-source-map": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-2.0.0.tgz", @@ -796,6 +1585,21 @@ "dev": true, "license": "MIT" }, + "node_modules/cross-spawn": { + "version": "7.0.6", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.6.tgz", + "integrity": "sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==", + "dev": true, + "license": "MIT", + "dependencies": { + "path-key": "^3.1.0", + "shebang-command": "^2.0.0", + "which": "^2.0.1" + }, + "engines": { + "node": ">= 8" + } + }, "node_modules/css-tree": { "version": "3.2.1", "resolved": "https://registry.npmjs.org/css-tree/-/css-tree-3.2.1.tgz", @@ -817,11 +1621,29 @@ "dev": true, "license": "MIT", "dependencies": { - "whatwg-mimetype": "^5.0.0", - "whatwg-url": "^16.0.0" + "whatwg-mimetype": "^5.0.0", + "whatwg-url": "^16.0.0" + }, + "engines": { + "node": "^20.19.0 || ^22.12.0 || >=24.0.0" + } + }, + "node_modules/debug": { + "version": "4.4.3", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.3.tgz", + "integrity": "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==", + "dev": true, + "license": "MIT", + "dependencies": { + "ms": "^2.1.3" }, "engines": { - "node": "^20.19.0 || ^22.12.0 || >=24.0.0" + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } } }, "node_modules/decimal.js": { @@ -841,6 +1663,40 @@ "node": ">=8" } }, + "node_modules/dotenv": { + "version": "16.6.1", + "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-16.6.1.tgz", + "integrity": "sha512-uBq4egWHTcTt33a72vpSG0z3HnPuIl6NqYcTrKEg2azoEyl2hpW0zqlxysq2pK9HlDIHyHyakeYaYnSAwd8bow==", + "dev": true, + "license": "BSD-2-Clause", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://dotenvx.com" + } + }, + "node_modules/eastasianwidth": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/eastasianwidth/-/eastasianwidth-0.2.0.tgz", + "integrity": "sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==", + "dev": true, + "license": "MIT" + }, + "node_modules/electron-to-chromium": { + "version": "1.5.340", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.340.tgz", + "integrity": "sha512-908qahOGocRMinT2nM3ajCEM99H4iPdv84eagPP3FfZy/1ZGeOy2CZYzjhms81ckOPCXPlW7LkY4XpxD8r1DrA==", + "dev": true, + "license": "ISC" + }, + "node_modules/emoji-regex": { + "version": "9.2.2", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-9.2.2.tgz", + "integrity": "sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==", + "dev": true, + "license": "MIT" + }, "node_modules/entities": { "version": "8.0.0", "resolved": "https://registry.npmjs.org/entities/-/entities-8.0.0.tgz", @@ -861,6 +1717,16 @@ "dev": true, "license": "MIT" }, + "node_modules/escalade": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.2.0.tgz", + "integrity": "sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, "node_modules/estree-walker": { "version": "3.0.3", "resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-3.0.3.tgz", @@ -899,6 +1765,53 @@ } } }, + "node_modules/fill-range": { + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz", + "integrity": "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==", + "dev": true, + "license": "MIT", + "dependencies": { + "to-regex-range": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/find-up": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz", + "integrity": "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==", + "dev": true, + "license": "MIT", + "dependencies": { + "locate-path": "^6.0.0", + "path-exists": "^4.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/foreground-child": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/foreground-child/-/foreground-child-3.3.1.tgz", + "integrity": "sha512-gIXjKqtFuWEgzFRJA9WCQeSJLZDjgJUOMCMzxtvFq/37KojM1BFGufqsCy0r4qSQmYLsZYMeyRqzIWOMup03sw==", + "dev": true, + "license": "ISC", + "dependencies": { + "cross-spawn": "^7.0.6", + "signal-exit": "^4.0.1" + }, + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, "node_modules/fsevents": { "version": "2.3.3", "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", @@ -914,6 +1827,51 @@ "node": "^8.16.0 || ^10.6.0 || >=11.0.0" } }, + "node_modules/gensync": { + "version": "1.0.0-beta.2", + "resolved": "https://registry.npmjs.org/gensync/-/gensync-1.0.0-beta.2.tgz", + "integrity": "sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/glob": { + "version": "10.5.0", + "resolved": "https://registry.npmjs.org/glob/-/glob-10.5.0.tgz", + "integrity": "sha512-DfXN8DfhJ7NH3Oe7cFmu3NCu1wKbkReJ8TorzSAFbSKrlNaQSKfIzqYqVY8zlbs2NLBbWpRiU52GX2PbaBVNkg==", + "deprecated": "Old versions of glob are not supported, and contain widely publicized security vulnerabilities, which have been fixed in the current version. Please update. Support for old versions may be purchased (at exorbitant rates) by contacting i@izs.me", + "dev": true, + "license": "ISC", + "dependencies": { + "foreground-child": "^3.1.0", + "jackspeak": "^3.1.2", + "minimatch": "^9.0.4", + "minipass": "^7.1.2", + "package-json-from-dist": "^1.0.0", + "path-scurry": "^1.11.1" + }, + "bin": { + "glob": "dist/esm/bin.mjs" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/glob-parent": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", + "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", + "dev": true, + "license": "ISC", + "dependencies": { + "is-glob": "^4.0.1" + }, + "engines": { + "node": ">= 6" + } + }, "node_modules/html-encoding-sniffer": { "version": "6.0.0", "resolved": "https://registry.npmjs.org/html-encoding-sniffer/-/html-encoding-sniffer-6.0.0.tgz", @@ -927,6 +1885,76 @@ "node": "^20.19.0 || ^22.12.0 || >=24.0.0" } }, + "node_modules/https-proxy-agent": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-5.0.1.tgz", + "integrity": "sha512-dFcAjpTQFgoLMzC2VwU+C/CbS7uRL0lWmxDITmqm7C+7F0Odmj6s9l6alZc6AELXhrnggM2CeWSXHGOdX2YtwA==", + "dev": true, + "license": "MIT", + "dependencies": { + "agent-base": "6", + "debug": "4" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/is-binary-path": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz", + "integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==", + "dev": true, + "license": "MIT", + "dependencies": { + "binary-extensions": "^2.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/is-extglob": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", + "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-fullwidth-code-point": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", + "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/is-glob": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", + "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-extglob": "^2.1.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-number": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", + "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.12.0" + } + }, "node_modules/is-potential-custom-element-name": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/is-potential-custom-element-name/-/is-potential-custom-element-name-1.0.1.tgz", @@ -934,6 +1962,36 @@ "dev": true, "license": "MIT" }, + "node_modules/isexe": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", + "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==", + "dev": true, + "license": "ISC" + }, + "node_modules/jackspeak": { + "version": "3.4.3", + "resolved": "https://registry.npmjs.org/jackspeak/-/jackspeak-3.4.3.tgz", + "integrity": "sha512-OGlZQpz2yfahA/Rd1Y8Cd9SIEsqvXkLVoSw/cgwhnhFMDbsQFeZYoJJ7bIZBS9BcamUW96asq/npPWugM+RQBw==", + "dev": true, + "license": "BlueOak-1.0.0", + "dependencies": { + "@isaacs/cliui": "^8.0.2" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + }, + "optionalDependencies": { + "@pkgjs/parseargs": "^0.11.0" + } + }, + "node_modules/js-tokens": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", + "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==", + "dev": true, + "license": "MIT" + }, "node_modules/jsdom": { "version": "29.0.2", "resolved": "https://registry.npmjs.org/jsdom/-/jsdom-29.0.2.tgz", @@ -975,6 +2033,32 @@ } } }, + "node_modules/jsesc": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-3.1.0.tgz", + "integrity": "sha512-/sM3dO2FOzXjKQhJuo0Q173wf2KOo8t4I8vHy6lF9poUp7bKT0/NHE8fPX23PwfhnykfqnC2xRxOnVw5XuGIaA==", + "dev": true, + "license": "MIT", + "bin": { + "jsesc": "bin/jsesc" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/json5": { + "version": "2.2.3", + "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.3.tgz", + "integrity": "sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==", + "dev": true, + "license": "MIT", + "bin": { + "json5": "lib/cli.js" + }, + "engines": { + "node": ">=6" + } + }, "node_modules/lightningcss": { "version": "1.32.0", "resolved": "https://registry.npmjs.org/lightningcss/-/lightningcss-1.32.0.tgz", @@ -1248,6 +2332,22 @@ "url": "https://opencollective.com/parcel" } }, + "node_modules/locate-path": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz", + "integrity": "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==", + "dev": true, + "license": "MIT", + "dependencies": { + "p-locate": "^5.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/lru-cache": { "version": "11.3.5", "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-11.3.5.tgz", @@ -1275,6 +2375,39 @@ "dev": true, "license": "CC0-1.0" }, + "node_modules/minimatch": { + "version": "9.0.9", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.9.tgz", + "integrity": "sha512-OBwBN9AL4dqmETlpS2zasx+vTeWclWzkblfZk7KTA5j3jeOONz/tRCnZomUyvNg83wL5Zv9Ss6HMJXAgL8R2Yg==", + "dev": true, + "license": "ISC", + "dependencies": { + "brace-expansion": "^2.0.2" + }, + "engines": { + "node": ">=16 || 14 >=14.17" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/minipass": { + "version": "7.1.3", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-7.1.3.tgz", + "integrity": "sha512-tEBHqDnIoM/1rXME1zgka9g6Q2lcoCkxHLuc7ODJ5BxbP5d4c2Z5cGgtXAku59200Cx7diuHTOYfSBD8n6mm8A==", + "dev": true, + "license": "BlueOak-1.0.0", + "engines": { + "node": ">=16 || 14 >=14.17" + } + }, + "node_modules/ms": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", + "dev": true, + "license": "MIT" + }, "node_modules/nanoid": { "version": "3.3.11", "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.11.tgz", @@ -1294,6 +2427,69 @@ "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1" } }, + "node_modules/node-fetch": { + "version": "2.7.0", + "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.7.0.tgz", + "integrity": "sha512-c4FRfUm/dbcWZ7U+1Wq0AwCyFL+3nt2bEw05wfxSz+DWpWsitgmSgYmy2dQdWyKC1694ELPqMs/YzUSNozLt8A==", + "dev": true, + "license": "MIT", + "dependencies": { + "whatwg-url": "^5.0.0" + }, + "engines": { + "node": "4.x || >=6.0.0" + }, + "peerDependencies": { + "encoding": "^0.1.0" + }, + "peerDependenciesMeta": { + "encoding": { + "optional": true + } + } + }, + "node_modules/node-fetch/node_modules/tr46": { + "version": "0.0.3", + "resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz", + "integrity": "sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==", + "dev": true, + "license": "MIT" + }, + "node_modules/node-fetch/node_modules/webidl-conversions": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz", + "integrity": "sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==", + "dev": true, + "license": "BSD-2-Clause" + }, + "node_modules/node-fetch/node_modules/whatwg-url": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-5.0.0.tgz", + "integrity": "sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==", + "dev": true, + "license": "MIT", + "dependencies": { + "tr46": "~0.0.3", + "webidl-conversions": "^3.0.0" + } + }, + "node_modules/node-releases": { + "version": "2.0.37", + "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.37.tgz", + "integrity": "sha512-1h5gKZCF+pO/o3Iqt5Jp7wc9rH3eJJ0+nh/CIoiRwjRxde/hAHyLPXYN4V3CqKAbiZPSeJFSWHmJsbkicta0Eg==", + "dev": true, + "license": "MIT" + }, + "node_modules/normalize-path": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", + "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/obug": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/obug/-/obug-2.1.1.tgz", @@ -1311,19 +2507,102 @@ "integrity": "sha512-glX26JwjL+Tkzv0JNOWdW4VozP5dGXO+Wx8+TPrdTEJTSYT/8eJS8yXM+fewjU0nFq/JeCa+X+BqABNjC4YZSA==", "license": "MIT" }, - "node_modules/parse5": { - "version": "8.0.1", - "resolved": "https://registry.npmjs.org/parse5/-/parse5-8.0.1.tgz", - "integrity": "sha512-z1e/HMG90obSGeidlli3hj7cbocou0/wa5HacvI3ASx34PecNjNQeaHNo5WIZpWofN9kgkqV1q5YvXe3F0FoPw==", + "node_modules/p-limit": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz", + "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "yocto-queue": "^0.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/p-locate": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-5.0.0.tgz", + "integrity": "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==", + "dev": true, + "license": "MIT", + "dependencies": { + "p-limit": "^3.0.2" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/package-json-from-dist": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/package-json-from-dist/-/package-json-from-dist-1.0.1.tgz", + "integrity": "sha512-UEZIS3/by4OC8vL3P2dTXRETpebLI2NiI5vIrjaD/5UtrkFX/tNbwjTSRAGC/+7CAo2pIcBaRgWmcBBHcsaCIw==", + "dev": true, + "license": "BlueOak-1.0.0" + }, + "node_modules/parse5": { + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/parse5/-/parse5-8.0.1.tgz", + "integrity": "sha512-z1e/HMG90obSGeidlli3hj7cbocou0/wa5HacvI3ASx34PecNjNQeaHNo5WIZpWofN9kgkqV1q5YvXe3F0FoPw==", + "dev": true, + "license": "MIT", + "dependencies": { + "entities": "^8.0.0" + }, + "funding": { + "url": "https://github.com/inikulin/parse5?sponsor=1" + } + }, + "node_modules/path-exists": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", + "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/path-key": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", + "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", "dev": true, "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/path-scurry": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/path-scurry/-/path-scurry-1.11.1.tgz", + "integrity": "sha512-Xa4Nw17FS9ApQFJ9umLiJS4orGjm7ZzwUrwamcGQuHSzDyth9boKDaycYdDcZDuqYATXw4HFXgaqWTctW/v1HA==", + "dev": true, + "license": "BlueOak-1.0.0", "dependencies": { - "entities": "^8.0.0" + "lru-cache": "^10.2.0", + "minipass": "^5.0.0 || ^6.0.2 || ^7.0.0" + }, + "engines": { + "node": ">=16 || 14 >=14.18" }, "funding": { - "url": "https://github.com/inikulin/parse5?sponsor=1" + "url": "https://github.com/sponsors/isaacs" } }, + "node_modules/path-scurry/node_modules/lru-cache": { + "version": "10.4.3", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-10.4.3.tgz", + "integrity": "sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ==", + "dev": true, + "license": "ISC" + }, "node_modules/pathe": { "version": "2.0.3", "resolved": "https://registry.npmjs.org/pathe/-/pathe-2.0.3.tgz", @@ -1380,6 +2659,23 @@ "node": "^10 || ^12 || >=14" } }, + "node_modules/progress": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/progress/-/progress-2.0.3.tgz", + "integrity": "sha512-7PiHtLll5LdnKIMw100I+8xJXR5gW2QwWYkT6iJva0bXitZKa/XMrSbdmg3r2Xnaidz9Qumd0VPaMrZlF9V9sA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/proxy-from-env": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/proxy-from-env/-/proxy-from-env-1.1.0.tgz", + "integrity": "sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==", + "dev": true, + "license": "MIT" + }, "node_modules/punycode": { "version": "2.3.1", "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz", @@ -1390,6 +2686,32 @@ "node": ">=6" } }, + "node_modules/readdirp": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz", + "integrity": "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==", + "dev": true, + "license": "MIT", + "dependencies": { + "picomatch": "^2.2.1" + }, + "engines": { + "node": ">=8.10.0" + } + }, + "node_modules/readdirp/node_modules/picomatch": { + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.2.tgz", + "integrity": "sha512-V7+vQEJ06Z+c5tSye8S+nHUfI51xoXIXjHQ99cQtKUkQqqO1kO/KCJUfZXuB47h/YBlDhah2H3hdUGXn8ie0oA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8.6" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, "node_modules/require-from-string": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/require-from-string/-/require-from-string-2.0.2.tgz", @@ -1447,6 +2769,39 @@ "node": ">=v12.22.7" } }, + "node_modules/semver": { + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", + "dev": true, + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/shebang-command": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", + "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", + "dev": true, + "license": "MIT", + "dependencies": { + "shebang-regex": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/shebang-regex": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", + "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, "node_modules/siginfo": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/siginfo/-/siginfo-2.0.0.tgz", @@ -1454,6 +2809,19 @@ "dev": true, "license": "ISC" }, + "node_modules/signal-exit": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-4.1.0.tgz", + "integrity": "sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==", + "dev": true, + "license": "ISC", + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, "node_modules/source-map-js": { "version": "1.2.1", "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.1.tgz", @@ -1478,6 +2846,110 @@ "dev": true, "license": "MIT" }, + "node_modules/string-width": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-5.1.2.tgz", + "integrity": "sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA==", + "dev": true, + "license": "MIT", + "dependencies": { + "eastasianwidth": "^0.2.0", + "emoji-regex": "^9.2.2", + "strip-ansi": "^7.0.1" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/string-width-cjs": { + "name": "string-width", + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "dev": true, + "license": "MIT", + "dependencies": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/string-width-cjs/node_modules/ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/string-width-cjs/node_modules/emoji-regex": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", + "dev": true, + "license": "MIT" + }, + "node_modules/string-width-cjs/node_modules/strip-ansi": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/strip-ansi": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.2.0.tgz", + "integrity": "sha512-yDPMNjp4WyfYBkHnjIRLfca1i6KMyGCtsVgoKe/z1+6vukgaENdgGBZt+ZmKPc4gavvEZ5OgHfHdrazhgNyG7w==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-regex": "^6.2.2" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/strip-ansi?sponsor=1" + } + }, + "node_modules/strip-ansi-cjs": { + "name": "strip-ansi", + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/strip-ansi-cjs/node_modules/ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, "node_modules/symbol-tree": { "version": "3.2.4", "resolved": "https://registry.npmjs.org/symbol-tree/-/symbol-tree-3.2.4.tgz", @@ -1549,6 +3021,19 @@ "dev": true, "license": "MIT" }, + "node_modules/to-regex-range": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", + "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-number": "^7.0.0" + }, + "engines": { + "node": ">=8.0" + } + }, "node_modules/tough-cookie": { "version": "6.0.1", "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-6.0.1.tgz", @@ -1614,6 +3099,50 @@ "dev": true, "license": "MIT" }, + "node_modules/unplugin": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/unplugin/-/unplugin-1.0.1.tgz", + "integrity": "sha512-aqrHaVBWW1JVKBHmGo33T5TxeL0qWzfvjWokObHA9bYmN7eNDkwOxmLjhioHl9878qDFMAaT51XNroRyuz7WxA==", + "dev": true, + "license": "MIT", + "dependencies": { + "acorn": "^8.8.1", + "chokidar": "^3.5.3", + "webpack-sources": "^3.2.3", + "webpack-virtual-modules": "^0.5.0" + } + }, + "node_modules/update-browserslist-db": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.2.3.tgz", + "integrity": "sha512-Js0m9cx+qOgDxo0eMiFGEueWztz+d4+M3rGlmKPT+T4IS/jP4ylw3Nwpu6cpTTP8R1MAC1kF4VbdLt3ARf209w==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/browserslist" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "dependencies": { + "escalade": "^3.2.0", + "picocolors": "^1.1.1" + }, + "bin": { + "update-browserslist-db": "cli.js" + }, + "peerDependencies": { + "browserslist": ">= 4.21.0" + } + }, "node_modules/vite": { "version": "8.0.9", "resolved": "https://registry.npmjs.org/vite/-/vite-8.0.9.tgz", @@ -1805,6 +3334,23 @@ "node": ">=20" } }, + "node_modules/webpack-sources": { + "version": "3.3.4", + "resolved": "https://registry.npmjs.org/webpack-sources/-/webpack-sources-3.3.4.tgz", + "integrity": "sha512-7tP1PdV4vF+lYPnkMR0jMY5/la2ub5Fc/8VQrrU+lXkiM6C4TjVfGw7iKfyhnTQOsD+6Q/iKw0eFciziRgD58Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10.13.0" + } + }, + "node_modules/webpack-virtual-modules": { + "version": "0.5.0", + "resolved": "https://registry.npmjs.org/webpack-virtual-modules/-/webpack-virtual-modules-0.5.0.tgz", + "integrity": "sha512-kyDivFZ7ZM0BVOUteVbDFhlRt7Ah/CSPwJdi8hBpkK7QLumUqdLtVfm/PX/hkcnrvr0i77fO5+TjZ94Pe+C9iw==", + "dev": true, + "license": "MIT" + }, "node_modules/whatwg-mimetype": { "version": "5.0.0", "resolved": "https://registry.npmjs.org/whatwg-mimetype/-/whatwg-mimetype-5.0.0.tgz", @@ -1830,6 +3376,22 @@ "node": "^20.19.0 || ^22.12.0 || >=24.0.0" } }, + "node_modules/which": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", + "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", + "dev": true, + "license": "ISC", + "dependencies": { + "isexe": "^2.0.0" + }, + "bin": { + "node-which": "bin/node-which" + }, + "engines": { + "node": ">= 8" + } + }, "node_modules/why-is-node-running": { "version": "2.3.0", "resolved": "https://registry.npmjs.org/why-is-node-running/-/why-is-node-running-2.3.0.tgz", @@ -1847,6 +3409,104 @@ "node": ">=8" } }, + "node_modules/wrap-ansi": { + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-8.1.0.tgz", + "integrity": "sha512-si7QWI6zUMq56bESFvagtmzMdGOtoxfR+Sez11Mobfc7tm+VkUckk9bW2UeffTGVUbOksxmSw0AA2gs8g71NCQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-styles": "^6.1.0", + "string-width": "^5.0.1", + "strip-ansi": "^7.0.1" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/wrap-ansi?sponsor=1" + } + }, + "node_modules/wrap-ansi-cjs": { + "name": "wrap-ansi", + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", + "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-styles": "^4.0.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/wrap-ansi?sponsor=1" + } + }, + "node_modules/wrap-ansi-cjs/node_modules/ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/wrap-ansi-cjs/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "license": "MIT", + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/wrap-ansi-cjs/node_modules/emoji-regex": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", + "dev": true, + "license": "MIT" + }, + "node_modules/wrap-ansi-cjs/node_modules/string-width": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "dev": true, + "license": "MIT", + "dependencies": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/wrap-ansi-cjs/node_modules/strip-ansi": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, "node_modules/xml-name-validator": { "version": "5.0.0", "resolved": "https://registry.npmjs.org/xml-name-validator/-/xml-name-validator-5.0.0.tgz", @@ -1863,6 +3523,26 @@ "integrity": "sha512-JZnDKK8B0RCDw84FNdDAIpZK+JuJw+s7Lz8nksI7SIuU3UXJJslUthsi+uWBUYOwPFwW7W7PRLRfUKpxjtjFCw==", "dev": true, "license": "MIT" + }, + "node_modules/yallist": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz", + "integrity": "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==", + "dev": true, + "license": "ISC" + }, + "node_modules/yocto-queue": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz", + "integrity": "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } } } } diff --git a/Frontend/package.json b/Frontend/package.json index eed8d97b..befb08ce 100644 --- a/Frontend/package.json +++ b/Frontend/package.json @@ -16,6 +16,7 @@ "preview": "vite preview --strictPort --port 1420" }, "devDependencies": { + "@sentry/vite-plugin": "^4.5.0", "@types/node": "^25.6.0", "jsdom": "^29.0.2", "typescript": "^6.0.3", diff --git a/Frontend/src/modals/settings.html b/Frontend/src/modals/settings.html index a6b0162d..d8eb8857 100644 --- a/Frontend/src/modals/settings.html +++ b/Frontend/src/modals/settings.html @@ -89,6 +89,14 @@

Settings

+
+ +
+ diff --git a/Frontend/src/scripts/features/repo/hydrate.ts b/Frontend/src/scripts/features/repo/hydrate.ts index c22980f5..7167c8a2 100644 --- a/Frontend/src/scripts/features/repo/hydrate.ts +++ b/Frontend/src/scripts/features/repo/hydrate.ts @@ -53,6 +53,18 @@ function buildStatusSignature(input: { let lastStatusSignature = ''; +/** Returns a richer log message for common repository hydration failures. */ +function describeHydrationFailure(operation: string, error: unknown): string { + const message = String(error || '').trim(); + if (message === 'No repository selected') { + return `${operation} skipped: no repository selected; check whether a VCS backend is available and whether a repository was reopened successfully`; + } + if (message.includes('no longer available')) { + return `${operation} failed: active backend is no longer available; reopen the repository or re-enable the backend plugin`; + } + return `${operation} failed ${message}`.trim(); +} + export async function hydrateBranches(): Promise { if (!TAURI.has) return false; try { @@ -74,7 +86,7 @@ export async function hydrateBranches(): Promise { } return false; } catch (e) { - console.warn('hydrateBranches failed', e); + console.warn(describeHydrationFailure('hydrateBranches', e), e); return false; } } @@ -135,7 +147,7 @@ export async function hydrateStatus() { void autoOpenFirstConflict(state.files as any); window.dispatchEvent(new CustomEvent('app:status-updated')); } catch (e) { - console.warn('hydrateStatus failed', e); + console.warn(describeHydrationFailure('hydrateStatus', e), e); state.files = []; state.mergeInProgress = false; state.seenConflicts = new Set(); @@ -202,7 +214,7 @@ export async function hydrateCommits() { } if (prefs.tab === 'history') renderList(); } catch (e) { - console.warn('hydrateCommits failed', e); + console.warn(describeHydrationFailure('hydrateCommits', e), e); state.commits = []; } } @@ -215,7 +227,7 @@ export async function hydrateStash() { (state as any).stash = Array.isArray(list) ? (list as any) : []; if (prefs.tab === 'stash') renderList(); } catch (e) { - console.warn('hydrateStash failed', e); + console.warn(describeHydrationFailure('hydrateStash', e), e); (state as any).stash = []; } } diff --git a/Frontend/src/scripts/features/settings.ts b/Frontend/src/scripts/features/settings.ts index 40e4d976..64edf64a 100644 --- a/Frontend/src/scripts/features/settings.ts +++ b/Frontend/src/scripts/features/settings.ts @@ -1,11 +1,13 @@ // Copyright © 2025-2026 OpenVCS Contributors // SPDX-License-Identifier: GPL-3.0-or-later import { TAURI } from '../lib/tauri'; +import { syncFrontendMonitoring } from '../lib/monitoring'; import { openModal, closeModal } from '../ui/modals'; import { toKebab } from '../lib/dom'; import { confirmBool } from '../lib/confirm'; import { notify } from '../lib/notify'; import { setTheme } from '../ui/layout'; +import { collectGeneralSettings, loadGeneralSettingsIntoForm } from './settingsGeneral'; import { DEFAULT_DARK_THEME_ID, DEFAULT_LIGHT_THEME_ID, DEFAULT_THEME_ID, getActiveThemeId, getAvailableThemes, refreshAvailableThemes, selectThemePack } from '../themes'; import { invokePluginAction, reloadPlugins } from '../plugins'; import type { PluginSummary } from '../plugins'; @@ -690,6 +692,7 @@ export function wireSettings() { if (TAURI.has) { await TAURI.invoke('set_global_settings', { cfg: next }); + await syncFrontendMonitoring(next); } modal.dataset.currentCfg = JSON.stringify(next); @@ -752,7 +755,7 @@ export function wireSettings() { reopen_last_repos: true, checks_on_launch: true, telemetry: false, - crash_reports: false, + crash_reports: true, }; cur.diff = { tab_width: 4, ignore_whitespace: 'none', max_file_size_mb: 10, intraline: true, show_binary_placeholders: true, external_diff: {enabled:false,path:'',args:''}, external_merge: {enabled:false,path:'',args:''}, binary_exts: ['png','jpg','dds','uasset'] }; cur.lfs = { enabled: true, concurrency: 4, require_lock_before_edit: false, background_fetch_on_checkout: true }; @@ -762,6 +765,7 @@ export function wireSettings() { cur.plugins = { disabled: [], enabled: [] }; await TAURI.invoke('set_global_settings', { cfg: cur }); + await syncFrontendMonitoring(cur); applyAnimationPreference(cur.performance?.animations); await loadSettingsIntoForm(modal); setTheme('system'); @@ -780,20 +784,7 @@ function collectSettingsFromForm(root: HTMLElement): GlobalSettings { const o: GlobalSettings = { ...base }; - const autoTheme = !!get('#set-theme-auto')?.checked; - const themePack = get('#set-theme')?.value || DEFAULT_LIGHT_THEME_ID; - const theme = autoTheme ? 'system' : modeForTheme(themePack); - - o.general = { - ...o.general, - theme, - theme_pack: themePack || DEFAULT_LIGHT_THEME_ID, - language: get('#set-language')?.value, - default_backend: (get('#set-default-backend')?.value || 'git') as any, - update_channel: get('#set-update-channel')?.value || 'stable', - reopen_last_repos: !!get('#set-reopen-last')?.checked, - checks_on_launch: !!get('#set-checks-on-launch')?.checked, - }; + o.general = collectGeneralSettings(root, o, modeForTheme); o.diff = { ...o.diff, @@ -903,35 +894,8 @@ export async function loadSettingsIntoForm(root?: HTMLElement) { await loadPluginsIntoForm(m, cfg); - const themeSel = get('#set-theme'); - const elAuto = get('#set-theme-auto'); - const themePref = (cfg.general?.theme || 'system') as 'system'|'light'|'dark'; - - if (elAuto) elAuto.checked = themePref === 'system'; - - if (themeSel) { - let desiredId = String(cfg.general?.theme_pack || DEFAULT_LIGHT_THEME_ID); - if (desiredId.trim().toLowerCase() === DEFAULT_THEME_ID) { - desiredId = themePref === 'dark' ? DEFAULT_DARK_THEME_ID : DEFAULT_LIGHT_THEME_ID; - } - await rebuildThemePackOptions(themeSel, { - desiredId, - forceReload: true, - }); - themeSel.disabled = themePref === 'system'; - if (themePref === 'system') { - themeSel.value = getActiveThemeId() || themeSel.value; - } - } - - const elLang = get('#set-language'); if (elLang) elLang.value = toKebab(cfg.general?.language); - await refreshDefaultBackendOptions(m, cfg); - const elChan = get('#set-update-channel'); if (elChan) { - elChan.value = toKebab(cfg.general?.update_channel); - } - const elReo = get('#set-reopen-last'); if (elReo) elReo.checked = !!cfg.general?.reopen_last_repos; - const elChk = get('#set-checks-on-launch'); if (elChk) elChk.checked = !!cfg.general?.checks_on_launch; - const elRl = get('#set-recents-limit'); if (elRl) elRl.value = String(cfg.ux?.recents_limit ?? 10); + await loadGeneralSettingsIntoForm(m, cfg, toKebab, refreshDefaultBackendOptions, rebuildThemePackOptions); + const elRl = get('#set-recents-limit'); if (elRl) elRl.value = String(cfg.ux?.recents_limit ?? 10); const elTw = get('#set-tab-width'); if (elTw) elTw.value = String(cfg.diff?.tab_width ?? 0); const elIw = get('#set-ignore-whitespace'); if (elIw) elIw.value = toKebab(cfg.diff?.ignore_whitespace); @@ -996,7 +960,12 @@ async function refreshDefaultBackendOptions(modal: HTMLElement, cfg: GlobalSetti } el.disabled = backends.length === 0; - if (!backends.length) return; + if (!backends.length) { + console.warn( + 'settings: no VCS backends are currently available; default backend selection is disabled', + ); + return; + } if (desired && backends.some(([id]) => id === desired)) { el.value = desired; } else { diff --git a/Frontend/src/scripts/features/settingsGeneral.test.ts b/Frontend/src/scripts/features/settingsGeneral.test.ts new file mode 100644 index 00000000..1199f499 --- /dev/null +++ b/Frontend/src/scripts/features/settingsGeneral.test.ts @@ -0,0 +1,55 @@ +// Copyright © 2025-2026 OpenVCS Contributors +// SPDX-License-Identifier: GPL-3.0-or-later + +import { describe, expect, it, vi } from 'vitest'; + +import { collectGeneralSettings, loadGeneralSettingsIntoForm } from './settingsGeneral'; + +describe('collectGeneralSettings', () => { + it('captures the crash report toggle from the general settings panel', () => { + document.body.innerHTML = ` +
+ + + + + + + + +
+ `; + + const root = document.body.firstElementChild as HTMLElement; + const general = collectGeneralSettings(root, {}, () => 'dark'); + expect(general?.crash_reports).toBe(true); + expect(general?.theme).toBe('system'); + }); +}); + +describe('loadGeneralSettingsIntoForm', () => { + it('loads the crash report toggle into the general settings panel', async () => { + document.body.innerHTML = ` +
+ + + + + +
+ `; + + const root = document.body.firstElementChild as HTMLElement; + const refreshDefaultBackendOptions = vi.fn().mockResolvedValue(undefined); + await loadGeneralSettingsIntoForm( + root, + { general: { language: 'system', update_channel: 'stable', reopen_last_repos: true, checks_on_launch: true, crash_reports: true } }, + (value) => String(value ?? ''), + refreshDefaultBackendOptions, + vi.fn().mockResolvedValue(undefined), + ); + + expect(refreshDefaultBackendOptions).toHaveBeenCalledWith(root, expect.any(Object)); + expect((root.querySelector('#set-crash-reports') as HTMLInputElement).checked).toBe(true); + }); +}); diff --git a/Frontend/src/scripts/features/settingsGeneral.ts b/Frontend/src/scripts/features/settingsGeneral.ts new file mode 100644 index 00000000..ec288a53 --- /dev/null +++ b/Frontend/src/scripts/features/settingsGeneral.ts @@ -0,0 +1,76 @@ +// Copyright © 2025-2026 OpenVCS Contributors +// SPDX-License-Identifier: GPL-3.0-or-later + +import type { GlobalSettings } from '../types'; + +import { DEFAULT_DARK_THEME_ID, DEFAULT_LIGHT_THEME_ID, DEFAULT_THEME_ID, getActiveThemeId } from '../themes'; + +/** Collects the General panel settings from the settings modal. */ +export function collectGeneralSettings( + root: HTMLElement, + base: GlobalSettings, + modeForTheme: (themeId: string) => 'light' | 'dark', +): GlobalSettings['general'] { + const get = (sel: string) => root.querySelector(sel); + const autoTheme = !!get('#set-theme-auto')?.checked; + const themePack = get('#set-theme')?.value || DEFAULT_LIGHT_THEME_ID; + const theme = autoTheme ? 'system' : modeForTheme(themePack); + + return { + ...base.general, + theme, + theme_pack: themePack || DEFAULT_LIGHT_THEME_ID, + language: get('#set-language')?.value, + default_backend: (get('#set-default-backend')?.value || 'git') as any, + update_channel: get('#set-update-channel')?.value || 'stable', + reopen_last_repos: !!get('#set-reopen-last')?.checked, + checks_on_launch: !!get('#set-checks-on-launch')?.checked, + crash_reports: !!get('#set-crash-reports')?.checked, + }; +} + +/** Loads the General panel settings into the settings modal form controls. */ +export async function loadGeneralSettingsIntoForm( + root: HTMLElement, + cfg: GlobalSettings, + toKebab: (value: unknown) => string, + refreshDefaultBackendOptions: (modal: HTMLElement, cfg: GlobalSettings) => Promise, + rebuildThemePackOptions: ( + themeSelect: HTMLSelectElement, + options: { desiredId: string; forceReload: boolean }, + ) => Promise, +): Promise { + const get = (sel: string) => root.querySelector(sel); + const themeSel = get('#set-theme'); + const elAuto = get('#set-theme-auto'); + const themePref = (cfg.general?.theme || 'system') as 'system' | 'light' | 'dark'; + if (elAuto) elAuto.checked = themePref === 'system'; + if (themeSel) { + let desiredId = String(cfg.general?.theme_pack || DEFAULT_LIGHT_THEME_ID); + if (desiredId.trim().toLowerCase() === DEFAULT_THEME_ID) { + desiredId = themePref === 'dark' ? DEFAULT_DARK_THEME_ID : DEFAULT_LIGHT_THEME_ID; + } + await rebuildThemePackOptions(themeSel, { + desiredId, + forceReload: true, + }); + themeSel.disabled = themePref === 'system'; + if (themePref === 'system') { + themeSel.value = getActiveThemeId() || themeSel.value; + } + } + + const elLang = get('#set-language'); + if (elLang) elLang.value = toKebab(cfg.general?.language); + await refreshDefaultBackendOptions(root, cfg); + const elChan = get('#set-update-channel'); + if (elChan) { + elChan.value = toKebab(cfg.general?.update_channel); + } + const elReo = get('#set-reopen-last'); + if (elReo) elReo.checked = !!cfg.general?.reopen_last_repos; + const elChk = get('#set-checks-on-launch'); + if (elChk) elChk.checked = !!cfg.general?.checks_on_launch; + const elCrash = get('#set-crash-reports'); + if (elCrash) elCrash.checked = !!cfg.general?.crash_reports; +} diff --git a/Frontend/src/scripts/lib/logger.ts b/Frontend/src/scripts/lib/logger.ts index 36bac15e..f8a6d02b 100644 --- a/Frontend/src/scripts/lib/logger.ts +++ b/Frontend/src/scripts/lib/logger.ts @@ -2,8 +2,10 @@ // SPDX-License-Identifier: GPL-3.0-or-later import { TAURI } from "./tauri"; +import { addFrontendLogBreadcrumb } from "./monitoring"; type LogLevel = "trace" | "debug" | "info" | "warn" | "error"; +const LOGGER_PATCH_FLAG = "__OPENVCS_FRONTEND_LOGGER_INSTALLED__"; interface Logger { trace: (...args: unknown[]) => void; @@ -31,12 +33,34 @@ function formatMessage(...args: unknown[]): string { .join(" "); } -function sendToBackend(level: LogLevel, message: string): void { +function sendToBackend( + level: LogLevel, + message: string, + options: { breadcrumb?: boolean } = {}, +): void { + if (options.breadcrumb !== false) { + addFrontendLogBreadcrumb(toMonitoringBreadcrumbLevel(level), message); + } if (TAURI.has) { TAURI.invoke("log_frontend_message", { level, message }).catch(() => {}); } } +/** Maps logger levels to the breadcrumb levels sent through monitoring relay payloads. */ +function toMonitoringBreadcrumbLevel(level: LogLevel): "debug" | "info" | "warning" | "error" { + switch (level) { + case "trace": + case "debug": + return "debug"; + case "info": + return "info"; + case "warn": + return "warning"; + case "error": + return "error"; + } +} + function createLogger(module: string): Logger { const prefix = `[${module}]`; @@ -65,37 +89,56 @@ function createLogger(module: string): Logger { } function installFrontendLogger(): void { + if ((globalThis as Record)[LOGGER_PATCH_FLAG]) { + return; + } + const originalConsole = { - debug: console.debug, - log: console.log, - warn: console.warn, - error: console.error, + debug: console.debug.bind(console), + info: console.info.bind(console), + log: console.log.bind(console), + warn: console.warn.bind(console), + error: console.error.bind(console), + trace: console.trace.bind(console), }; console.debug = (...args: unknown[]) => { const msg = formatMessage(...args); sendToBackend("debug", msg); + originalConsole.debug(...args); + }; + + console.info = (...args: unknown[]) => { + const msg = formatMessage(...args); + sendToBackend("info", msg); + originalConsole.info(...args); }; console.log = (...args: unknown[]) => { const msg = formatMessage(...args); sendToBackend("info", msg); + originalConsole.log(...args); }; console.warn = (...args: unknown[]) => { const msg = formatMessage(...args); sendToBackend("warn", msg); + originalConsole.warn(...args); }; console.error = (...args: unknown[]) => { const msg = formatMessage(...args); sendToBackend("error", msg); + originalConsole.error(...args); }; console.trace = (...args: unknown[]) => { const msg = formatMessage(...args); sendToBackend("trace", msg); + originalConsole.trace(...args); }; + + (globalThis as Record)[LOGGER_PATCH_FLAG] = true; } installFrontendLogger(); diff --git a/Frontend/src/scripts/lib/monitoring.test.ts b/Frontend/src/scripts/lib/monitoring.test.ts new file mode 100644 index 00000000..daa1a033 --- /dev/null +++ b/Frontend/src/scripts/lib/monitoring.test.ts @@ -0,0 +1,152 @@ +// Copyright © 2025-2026 OpenVCS Contributors +// SPDX-License-Identifier: GPL-3.0-or-later + +import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest'; + +interface MonitoringModule { + normalizeOptionalString: (value: string | null | undefined) => string | null; + isFrontendMonitoringAllowed: (settings: unknown) => boolean; + shouldEnableFrontendMonitoring: (settings: unknown) => boolean; + syncFrontendMonitoring: (settings: unknown) => Promise; + addFrontendLogBreadcrumb: (level: 'debug' | 'info' | 'warning' | 'error', message: string) => void; +} + +beforeEach(() => { + vi.resetModules(); + vi.restoreAllMocks(); + delete (window as Window & { __TAURI__?: unknown }).__TAURI__; +}); + +afterEach(() => { + vi.unstubAllEnvs(); +}); + +describe('normalizeOptionalString', () => { + it('returns null for blank strings', async () => { + const monitoring = await import('./monitoring'); + expect(monitoring.normalizeOptionalString(' ')).toBeNull(); + }); + + it('trims populated strings', async () => { + const monitoring = await import('./monitoring'); + expect(monitoring.normalizeOptionalString(' value ')).toBe('value'); + }); +}); + +describe('isFrontendMonitoringAllowed', () => { + it('requires crash report consent', async () => { + const monitoring = await import('./monitoring'); + expect(monitoring.isFrontendMonitoringAllowed({ general: { crash_reports: true } })).toBe(true); + expect(monitoring.isFrontendMonitoringAllowed({ general: { crash_reports: false } })).toBe(false); + expect(monitoring.isFrontendMonitoringAllowed(null)).toBe(false); + }); +}); + +describe('shouldEnableFrontendMonitoring', () => { + it('requires tauri and crash report consent', async () => { + const monitoring = await import('./monitoring'); + expect(monitoring.shouldEnableFrontendMonitoring({ general: { crash_reports: true } })).toBe(false); + expect(monitoring.shouldEnableFrontendMonitoring({ general: { crash_reports: false } })).toBe(false); + }); +}); + +describe('syncFrontendMonitoring', () => { + it('relays frontend errors with capped breadcrumbs', async () => { + const invoke = vi.fn().mockResolvedValue(undefined); + (window as Window & { __TAURI__?: unknown }).__TAURI__ = { + core: { invoke }, + event: { listen: vi.fn() }, + }; + + const monitoring = (await import('./monitoring')) as MonitoringModule; + await monitoring.syncFrontendMonitoring({ general: { crash_reports: true } }); + + for (let index = 0; index < 45; index += 1) { + monitoring.addFrontendLogBreadcrumb('info', `crumb-${index}`); + } + + const error = new Error('boom'); + window.dispatchEvent(new ErrorEvent('error', { error, message: error.message, filename: 'app://index.js', lineno: 7, colno: 11 })); + + expect(invoke).toHaveBeenCalledTimes(1); + const [, payload] = invoke.mock.calls[0] ?? []; + expect(payload?.payload?.message).toBe('boom'); + expect(payload?.payload?.kind).toBe('error'); + expect(payload?.payload?.breadcrumbs).toHaveLength(40); + expect(payload?.payload?.breadcrumbs[0]?.message).toBe('crumb-5'); + expect(payload?.payload?.breadcrumbs[39]?.message).toBe('crumb-44'); + }); + + it('uninstalls listeners when crash reports are disabled', async () => { + const invoke = vi.fn().mockResolvedValue(undefined); + (window as Window & { __TAURI__?: unknown }).__TAURI__ = { + core: { invoke }, + event: { listen: vi.fn() }, + }; + + const monitoring = (await import('./monitoring')) as MonitoringModule; + await monitoring.syncFrontendMonitoring({ general: { crash_reports: true } }); + await monitoring.syncFrontendMonitoring({ general: { crash_reports: false } }); + + window.dispatchEvent(new ErrorEvent('error', { error: new Error('after-disable'), message: 'after-disable' })); + expect(invoke).not.toHaveBeenCalled(); + }); + + it('reports a fallback message for undefined rejection reasons', async () => { + const invoke = vi.fn().mockResolvedValue(undefined); + (window as Window & { __TAURI__?: unknown }).__TAURI__ = { + core: { invoke }, + event: { listen: vi.fn() }, + }; + + const monitoring = (await import('./monitoring')) as MonitoringModule; + await monitoring.syncFrontendMonitoring({ general: { crash_reports: true } }); + + const event = new Event('unhandledrejection') as PromiseRejectionEvent & { reason: unknown }; + Object.defineProperty(event, 'reason', { + value: undefined, + configurable: true, + }); + window.dispatchEvent(event); + + expect(invoke).toHaveBeenCalledTimes(1); + const [, payload] = invoke.mock.calls[0] ?? []; + expect(payload?.payload?.kind).toBe('unhandledrejection'); + expect(payload?.payload?.message).toBe('Unhandled promise rejection (no reason provided)'); + }); + + it('forwards build metadata with frontend reports', async () => { + vi.stubEnv('VITE_SENTRY_RELEASE', 'release-123'); + vi.stubEnv('VITE_SENTRY_ENVIRONMENT', 'qa'); + + const invoke = vi.fn().mockResolvedValue(undefined); + (window as Window & { __TAURI__?: unknown }).__TAURI__ = { + core: { invoke }, + event: { listen: vi.fn() }, + }; + + const monitoring = (await import('./monitoring')) as MonitoringModule; + await monitoring.syncFrontendMonitoring({ general: { crash_reports: true } }); + + window.dispatchEvent(new ErrorEvent('error', { error: new Error('meta'), message: 'meta' })); + + const [, payload] = invoke.mock.calls[0] ?? []; + expect(payload?.payload?.release).toBe('release-123'); + expect(payload?.payload?.environment).toBe('qa'); + }); + + it('is idempotent when enabling monitoring repeatedly', async () => { + const invoke = vi.fn().mockResolvedValue(undefined); + (window as Window & { __TAURI__?: unknown }).__TAURI__ = { + core: { invoke }, + event: { listen: vi.fn() }, + }; + + const monitoring = (await import('./monitoring')) as MonitoringModule; + await monitoring.syncFrontendMonitoring({ general: { crash_reports: true } }); + await monitoring.syncFrontendMonitoring({ general: { crash_reports: true } }); + + window.dispatchEvent(new ErrorEvent('error', { error: new Error('once'), message: 'once' })); + expect(invoke).toHaveBeenCalledTimes(1); + }); +}); diff --git a/Frontend/src/scripts/lib/monitoring.ts b/Frontend/src/scripts/lib/monitoring.ts new file mode 100644 index 00000000..4cab0768 --- /dev/null +++ b/Frontend/src/scripts/lib/monitoring.ts @@ -0,0 +1,195 @@ +// Copyright © 2025-2026 OpenVCS Contributors +// SPDX-License-Identifier: GPL-3.0-or-later + +import type { GlobalSettings } from '../types'; + +import { TAURI } from './tauri'; + +/** Represents the console breadcrumb level forwarded with frontend error reports. */ +type MonitoringBreadcrumbLevel = 'debug' | 'info' | 'warning' | 'error'; + +/** Maximum number of frontend breadcrumbs kept with an error report. */ +const MAX_FRONTEND_BREADCRUMBS = 40; +/** Sentry release metadata passed through the backend relay. */ +const FRONTEND_RELEASE = normalizeOptionalString(import.meta.env.VITE_SENTRY_RELEASE); +/** Sentry environment metadata passed through the backend relay. */ +const FRONTEND_ENVIRONMENT = + normalizeOptionalString(import.meta.env.VITE_SENTRY_ENVIRONMENT) ?? 'desktop'; + +/** Represents a single frontend breadcrumb included with a reported error. */ +interface FrontendBreadcrumb { + timestampMs: number; + level: MonitoringBreadcrumbLevel; + message: string; +} + +/** Represents a normalized frontend error payload sent to the backend. */ +interface FrontendErrorReport { + kind: 'error' | 'unhandledrejection'; + message: string; + stack?: string | null; + source?: string | null; + line?: number | null; + column?: number | null; + url?: string | null; + userAgent?: string | null; + release?: string | null; + environment?: string | null; + breadcrumbs: FrontendBreadcrumb[]; +} + +/** Tracks whether frontend monitoring listeners are currently installed. */ +let monitoringEnabled = false; +/** Stores recent console breadcrumbs for the next relayed frontend error. */ +const frontendBreadcrumbs: FrontendBreadcrumb[] = []; + +/** Handles global frontend `error` events. */ +let errorListener: ((event: ErrorEvent) => void) | null = null; +/** Handles global frontend `unhandledrejection` events. */ +let rejectionListener: ((event: PromiseRejectionEvent) => void) | null = null; + +/** Trims a string-like value and normalizes empty strings to `null`. */ +export function normalizeOptionalString(value: string | null | undefined): string | null { + const normalized = value?.trim(); + return normalized ? normalized : null; +} + +/** Returns whether current settings allow frontend crash reporting. */ +export function isFrontendMonitoringAllowed(settings: GlobalSettings | null | undefined): boolean { + return settings?.general?.crash_reports === true; +} + +/** Returns whether the frontend has everything needed to relay monitoring events. */ +export function shouldEnableFrontendMonitoring( + settings: GlobalSettings | null | undefined, +): boolean { + return Boolean(TAURI.has && isFrontendMonitoringAllowed(settings)); +} + +/** Synchronizes frontend error relay hooks with the latest settings. */ +export async function syncFrontendMonitoring( + settings: GlobalSettings | null | undefined, +): Promise { + const shouldEnable = shouldEnableFrontendMonitoring(settings); + + if (!shouldEnable) { + uninstallFrontendMonitoring(); + return; + } + + if (monitoringEnabled) { + return; + } + + installFrontendMonitoring(); +} + +/** Records a console breadcrumb when frontend monitoring is active. */ +export function addFrontendLogBreadcrumb( + level: MonitoringBreadcrumbLevel, + message: string, +): void { + if (!monitoringEnabled) { + return; + } + + frontendBreadcrumbs.push({ + timestampMs: Date.now(), + level, + message, + }); + if (frontendBreadcrumbs.length > MAX_FRONTEND_BREADCRUMBS) { + frontendBreadcrumbs.splice(0, frontendBreadcrumbs.length - MAX_FRONTEND_BREADCRUMBS); + } +} + +/** Installs global frontend error listeners that relay events to the backend. */ +function installFrontendMonitoring(): void { + errorListener = (event: ErrorEvent) => { + void reportFrontendError({ + kind: 'error', + message: event.error instanceof Error ? event.error.message : String(event.message || 'Unknown error'), + stack: event.error instanceof Error ? event.error.stack ?? null : null, + source: normalizeOptionalString(event.filename), + line: typeof event.lineno === 'number' ? event.lineno : null, + column: typeof event.colno === 'number' ? event.colno : null, + }); + }; + + rejectionListener = (event: PromiseRejectionEvent) => { + const rejection = event.reason; + void reportFrontendError({ + kind: 'unhandledrejection', + message: getUnhandledRejectionMessage(rejection), + stack: rejection instanceof Error ? rejection.stack ?? null : null, + source: null, + line: null, + column: null, + }); + }; + + window.addEventListener('error', errorListener); + window.addEventListener('unhandledrejection', rejectionListener); + monitoringEnabled = true; +} + +/** Removes global frontend monitoring listeners and clears queued breadcrumbs. */ +function uninstallFrontendMonitoring(): void { + if (errorListener) { + window.removeEventListener('error', errorListener); + errorListener = null; + } + if (rejectionListener) { + window.removeEventListener('unhandledrejection', rejectionListener); + rejectionListener = null; + } + frontendBreadcrumbs.length = 0; + monitoringEnabled = false; +} + +/** Reports a normalized frontend error payload to the backend monitoring command. */ +async function reportFrontendError( + report: Omit, +): Promise { + if (!monitoringEnabled || !TAURI.has) { + return; + } + + const payload: FrontendErrorReport = { + ...report, + url: normalizeOptionalString(window.location.href), + userAgent: normalizeOptionalString(window.navigator.userAgent), + release: FRONTEND_RELEASE, + environment: FRONTEND_ENVIRONMENT, + breadcrumbs: frontendBreadcrumbs.slice(), + }; + + await TAURI.invoke('report_frontend_error', { payload }).catch(() => {}); +} + +/** Derives a human-readable message for an unhandled promise rejection reason. */ +function getUnhandledRejectionMessage(reason: unknown): string { + if (reason instanceof Error) { + return reason.message; + } + if (typeof reason === 'string') { + const normalized = normalizeOptionalString(reason); + if (normalized) { + return normalized; + } + } + try { + const serialized = JSON.stringify(reason); + if (typeof serialized === 'string' && serialized.trim().length > 0) { + return serialized; + } + } catch { + // Fall through to the generic formatter below. + } + + if (typeof reason === 'undefined') { + return 'Unhandled promise rejection (no reason provided)'; + } + + return String(reason); +} diff --git a/Frontend/src/scripts/main.ts b/Frontend/src/scripts/main.ts index 37624777..0c131475 100644 --- a/Frontend/src/scripts/main.ts +++ b/Frontend/src/scripts/main.ts @@ -1,7 +1,9 @@ // Copyright © 2025-2026 OpenVCS Contributors // SPDX-License-Identifier: GPL-3.0-or-later import './lib/logger'; +import { syncFrontendMonitoring } from './lib/monitoring'; import { TAURI } from './lib/tauri'; +import type { GlobalSettings } from './types'; import { qs } from './lib/dom'; import { notify } from './lib/notify'; import { setStatus } from './lib/status'; @@ -97,6 +99,9 @@ function forceCloseTransientUi() { /** Boots the frontend shell, wires handlers, and hydrates initial state. */ async function boot() { + const cfg = await loadInitialGlobalSettings(); + await syncFrontendMonitoring(cfg); + // If launched as the Output Log window, render that view and skip the main app UI. if (await initOutputLogViewIfRequested()) return; initOverlayScrollbarsFor(document); @@ -104,10 +109,9 @@ async function boot() { await initPlugins(); // theme & basic layout // Prefer native settings for theme; fall back to current in-memory default - if (TAURI.has) { + if (cfg) { (async () => { try { - const cfg = await TAURI.invoke('get_global_settings'); const themeMode = cfg?.general?.theme as ('dark'|'light'|'system'|undefined); const modeForPack = themeMode ?? 'system'; const themePack = String(cfg?.general?.theme_pack || DEFAULT_LIGHT_THEME_ID); @@ -663,4 +667,17 @@ async function boot() { }); } +/** Loads persisted global settings for bootstrap-time features such as theming and monitoring. */ +async function loadInitialGlobalSettings(): Promise { + if (!TAURI.has) { + return null; + } + + try { + return await TAURI.invoke('get_global_settings'); + } catch { + return null; + } +} + boot(); diff --git a/Frontend/src/vite-env.d.ts b/Frontend/src/vite-env.d.ts new file mode 100644 index 00000000..774aa03a --- /dev/null +++ b/Frontend/src/vite-env.d.ts @@ -0,0 +1,14 @@ +// Copyright © 2025-2026 OpenVCS Contributors +// SPDX-License-Identifier: GPL-3.0-or-later +/// + +interface ImportMetaEnv { + readonly VITE_SENTRY_ENVIRONMENT?: string; + readonly VITE_SENTRY_RELEASE?: string; +} + +interface ImportMeta { + readonly env: ImportMetaEnv; +} + +export {}; diff --git a/Frontend/vite.config.mts b/Frontend/vite.config.mts index 720eb217..e6d8c16b 100644 --- a/Frontend/vite.config.mts +++ b/Frontend/vite.config.mts @@ -1,10 +1,17 @@ +// Copyright © 2025-2026 OpenVCS Contributors +// SPDX-License-Identifier: GPL-3.0-or-later /// -// vite.config.ts +import { sentryVitePlugin } from "@sentry/vite-plugin"; import { defineConfig } from "vite"; import { fileURLToPath, URL } from "node:url"; const host = process.env.TAURI_DEV_HOST; +const sentryAuthToken = process.env.SENTRY_AUTH_TOKEN?.trim(); +const sentryOrg = process.env.SENTRY_ORG?.trim(); +const sentryProject = process.env.SENTRY_PROJECT?.trim(); +const sentryRelease = process.env.VITE_SENTRY_RELEASE?.trim(); +const shouldUploadSourceMaps = Boolean(sentryAuthToken && sentryOrg && sentryProject && sentryRelease); export default defineConfig({ base: "./", // critical for packaged Tauri paths @@ -36,8 +43,27 @@ export default defineConfig({ target: "es2022", outDir: "dist", emptyOutDir: true, + sourcemap: shouldUploadSourceMaps ? "hidden" : false, }, optimizeDeps: { include: [], }, + plugins: shouldUploadSourceMaps + ? [ + sentryVitePlugin({ + authToken: sentryAuthToken, + org: sentryOrg, + project: sentryProject, + release: { + name: sentryRelease, + create: true, + finalize: true, + }, + sourcemaps: { + assets: "./dist/**", + }, + telemetry: false, + }), + ] + : [], }); From 4007ef07c9ef812edf97380ed825df6932d0ee87 Mon Sep 17 00:00:00 2001 From: Jordon Date: Wed, 22 Apr 2026 00:23:56 +0100 Subject: [PATCH 24/37] Update logging.rs --- Backend/src/logging.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Backend/src/logging.rs b/Backend/src/logging.rs index 93f76ccf..08f1eb23 100644 --- a/Backend/src/logging.rs +++ b/Backend/src/logging.rs @@ -1,12 +1,12 @@ // Copyright © 2025-2026 OpenVCS Contributors // SPDX-License-Identifier: GPL-3.0-or-later use crate::settings::{AppConfig, LogLevel}; +use sentry_log::{LogFilter, SentryLogger}; use std::fs::{self, OpenOptions}; use std::io::{Seek, SeekFrom, Write}; use std::sync::atomic::{AtomicBool, Ordering}; use std::sync::{Arc, Mutex, OnceLock}; use std::time::Instant; -use sentry_log::{LogFilter, SentryLogger}; use time::{OffsetDateTime, UtcOffset}; use zip::{write::FileOptions, CompressionMethod, ZipWriter}; From 2153f663bf47188e868cb5dcbc120fa78af693bb Mon Sep 17 00:00:00 2001 From: Jordon Date: Wed, 22 Apr 2026 00:24:08 +0100 Subject: [PATCH 25/37] Update monitoring.rs --- Backend/src/monitoring.rs | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/Backend/src/monitoring.rs b/Backend/src/monitoring.rs index b6733652..ec156544 100644 --- a/Backend/src/monitoring.rs +++ b/Backend/src/monitoring.rs @@ -87,9 +87,8 @@ fn build_backend_monitoring_guard(cfg: &AppConfig) -> Option Date: Wed, 22 Apr 2026 00:28:59 +0100 Subject: [PATCH 26/37] Update opencode-review.yml --- .github/workflows/opencode-review.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/opencode-review.yml b/.github/workflows/opencode-review.yml index 48643b6b..9cbdf8dc 100644 --- a/.github/workflows/opencode-review.yml +++ b/.github/workflows/opencode-review.yml @@ -37,7 +37,7 @@ jobs: - Suggest improvements - name: fallback - if: steps.review_primary.outcome == 'failure' + if: ${{ steps.review_primary.outcome == 'failure' }} uses: anomalyco/opencode/github@2410593023d2c61f05123c9b0faf189a28dfbeee env: OPENCODE_API_KEY: ${{ secrets.ZEN_API_KEY }} From f9b9cb67d77692149e0f82e10af9f6178ce2af8c Mon Sep 17 00:00:00 2001 From: Jordon Date: Wed, 22 Apr 2026 00:41:00 +0100 Subject: [PATCH 27/37] Update Cargo.lock --- Cargo.lock | 437 +++++++++++++++++++++++++++-------------------------- 1 file changed, 220 insertions(+), 217 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index c2e7cf75..8a7643a6 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -224,9 +224,9 @@ dependencies = [ [[package]] name = "async-signal" -version = "0.2.13" +version = "0.2.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "43c070bbf59cd3570b6b2dd54cd772527c7c3620fce8be898406dd3ed6adc64c" +checksum = "52b5aaafa020cf5053a01f2a60e8ff5dccf550f0f77ec54a4e47285ac2bab485" dependencies = [ "async-io", "async-lock", @@ -342,9 +342,9 @@ checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" [[package]] name = "bitflags" -version = "2.11.0" +version = "2.11.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "843867be96c8daad0d758b57df9392b6d8d271134fce549de6ce169ff98a92af" +checksum = "c4512299f36f043ab09a583e57bceb5a5aab7a73db1805848e8fef3c9e8c78b3" dependencies = [ "serde_core", ] @@ -452,7 +452,7 @@ version = "0.18.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8ca26ef0159422fb77631dc9d17b102f253b876fe1586b03b803e63a309b4ee2" dependencies = [ - "bitflags 2.11.0", + "bitflags 2.11.1", "cairo-sys-rs", "glib", "libc", @@ -515,9 +515,9 @@ dependencies = [ [[package]] name = "cc" -version = "1.2.57" +version = "1.2.60" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7a0dd1ca384932ff3641c8718a02769f1698e7563dc6974ffd03346116310423" +checksum = "43c5703da9466b66a946814e1adf53ea2c90f10063b86290cc9eb67ce3478a20" dependencies = [ "find-msvc-tools", "jobserver", @@ -661,7 +661,7 @@ version = "0.25.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "064badf302c3194842cf2c5d61f56cc88e54a759313879cdf03abdd27d0c3b97" dependencies = [ - "bitflags 2.11.0", + "bitflags 2.11.1", "core-foundation", "core-graphics-types", "foreign-types", @@ -674,7 +674,7 @@ version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3d44a101f213f6c4cdc1853d4b78aef6db6bdfa3468798cc1d9912f4735013eb" dependencies = [ - "bitflags 2.11.0", + "bitflags 2.11.1", "core-foundation", "libc", ] @@ -953,7 +953,7 @@ version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1e0e367e4e7da84520dedcac1901e4da967309406d1e51017ae1abfb97adbd38" dependencies = [ - "bitflags 2.11.0", + "bitflags 2.11.1", "block2", "libc", "objc2", @@ -1170,9 +1170,9 @@ dependencies = [ [[package]] name = "fastrand" -version = "2.3.0" +version = "2.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "37909eebbb50d72f9059c3b6d82c0463f2ff062c9e95845c43a6c9c0355411be" +checksum = "9f1f227452a390804cdb637b74a86990f2a7d7ba4b7d5693aac9b4dd6defd8d6" [[package]] name = "fdeflate" @@ -1594,7 +1594,7 @@ version = "0.18.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "233daaf6e83ae6a12a52055f568f9d7cf4671dabb78ff9560ab6da230ce00ee5" dependencies = [ - "bitflags 2.11.0", + "bitflags 2.11.1", "futures-channel", "futures-core", "futures-executor", @@ -1721,9 +1721,9 @@ dependencies = [ [[package]] name = "hashbrown" -version = "0.16.1" +version = "0.17.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "841d1cc9bed7f9236f321df977030373f4a4163ae1a7dbfe1a51a2c1a51d9100" +checksum = "4f467dd6dccf739c208452f8014c75c18bb8301b050ad1cfb27153803edb0f51" [[package]] name = "heck" @@ -1838,18 +1838,18 @@ checksum = "df3b46402a9d5adb4c86a0cf463f42e19994e3ee891101b1841f30a545cb49a9" [[package]] name = "hybrid-array" -version = "0.4.8" +version = "0.4.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8655f91cd07f2b9d0c24137bd650fe69617773435ee5ec83022377777ce65ef1" +checksum = "3944cf8cf766b40e2a1a333ee5e9b563f854d5fa49d6a8ca2764e97c6eddb214" dependencies = [ "typenum", ] [[package]] name = "hyper" -version = "1.8.1" +version = "1.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2ab2d4f250c3d7b1c9fcdff1cece94ea4e2dfbec68614f7b87cb205f24ca9d11" +checksum = "6299f016b246a94207e63da54dbe807655bf9e00044f73ded42c3ac5305fbcca" dependencies = [ "atomic-waker", "bytes", @@ -1860,7 +1860,6 @@ dependencies = [ "httparse", "itoa", "pin-project-lite", - "pin-utils", "smallvec", "tokio", "want", @@ -1868,15 +1867,14 @@ dependencies = [ [[package]] name = "hyper-rustls" -version = "0.27.7" +version = "0.27.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e3c93eb611681b207e1fe55d5a71ecf91572ec8a6705cdb6857f7d8d5242cf58" +checksum = "33ca68d021ef39cf6463ab54c1d0f5daf03377b70561305bb89a8f83aab66e0f" dependencies = [ "http", "hyper", "hyper-util", "rustls", - "rustls-pki-types", "tokio", "tokio-rustls", "tower-service", @@ -1942,12 +1940,13 @@ dependencies = [ [[package]] name = "icu_collections" -version = "2.1.1" +version = "2.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4c6b649701667bbe825c3b7e6388cb521c23d88644678e83c0c4d0a621a34b43" +checksum = "2984d1cd16c883d7935b9e07e44071dca8d917fd52ecc02c04d5fa0b5a3f191c" dependencies = [ "displaydoc", "potential_utf", + "utf8_iter", "yoke", "zerofrom", "zerovec", @@ -1955,9 +1954,9 @@ dependencies = [ [[package]] name = "icu_locale_core" -version = "2.1.1" +version = "2.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "edba7861004dd3714265b4db54a3c390e880ab658fec5f7db895fae2046b5bb6" +checksum = "92219b62b3e2b4d88ac5119f8904c10f8f61bf7e95b640d25ba3075e6cac2c29" dependencies = [ "displaydoc", "litemap", @@ -1968,9 +1967,9 @@ dependencies = [ [[package]] name = "icu_normalizer" -version = "2.1.1" +version = "2.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5f6c8828b67bf8908d82127b2054ea1b4427ff0230ee9141c54251934ab1b599" +checksum = "c56e5ee99d6e3d33bd91c5d85458b6005a22140021cc324cea84dd0e72cff3b4" dependencies = [ "icu_collections", "icu_normalizer_data", @@ -1982,15 +1981,15 @@ dependencies = [ [[package]] name = "icu_normalizer_data" -version = "2.1.1" +version = "2.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7aedcccd01fc5fe81e6b489c15b247b8b0690feb23304303a9e560f37efc560a" +checksum = "da3be0ae77ea334f4da67c12f149704f19f81d1adf7c51cf482943e84a2bad38" [[package]] name = "icu_properties" -version = "2.1.2" +version = "2.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "020bfc02fe870ec3a66d93e677ccca0562506e5872c650f893269e08615d74ec" +checksum = "bee3b67d0ea5c2cca5003417989af8996f8604e34fb9ddf96208a033901e70de" dependencies = [ "icu_collections", "icu_locale_core", @@ -2002,15 +2001,15 @@ dependencies = [ [[package]] name = "icu_properties_data" -version = "2.1.2" +version = "2.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "616c294cf8d725c6afcd8f55abc17c56464ef6211f9ed59cccffe534129c77af" +checksum = "8e2bbb201e0c04f7b4b3e14382af113e17ba4f63e2c9d2ee626b720cbce54a14" [[package]] name = "icu_provider" -version = "2.1.1" +version = "2.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "85962cf0ce02e1e0a629cc34e7ca3e373ce20dda4c4d7294bbd0bf1fdb59e614" +checksum = "139c4cf31c8b5f33d7e199446eff9c1e02decfc2f0eec2c8d71f65befa45b421" dependencies = [ "displaydoc", "icu_locale_core", @@ -2067,12 +2066,12 @@ dependencies = [ [[package]] name = "indexmap" -version = "2.13.0" +version = "2.14.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7714e70437a7dc3ac8eb7e6f8df75fd8eb422675fc7678aff7364301092b1017" +checksum = "d466e9454f08e4a911e14806c24e16fba1b4c121d1ea474396f396069cf949d9" dependencies = [ "equivalent", - "hashbrown 0.16.1", + "hashbrown 0.17.0", "serde", "serde_core", ] @@ -2092,7 +2091,7 @@ version = "0.11.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bd5b3eaf1a28b758ac0faa5a4254e8ab2705605496f1b1f3fbbc3988ad73d199" dependencies = [ - "bitflags 2.11.0", + "bitflags 2.11.1", "inotify-sys", "libc", ] @@ -2123,9 +2122,9 @@ checksum = "d98f6fed1fde3f8c21bc40a1abb88dd75e67924f9cffc3ef95607bad8017f8e2" [[package]] name = "iri-string" -version = "0.7.11" +version = "0.7.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d8e7418f59cc01c88316161279a7f665217ae316b388e58a0d10e29f54f1e5eb" +checksum = "25e659a4bb38e810ebc252e53b5814ff908a8c58c2a9ce2fae1bbec24cbf4e20" dependencies = [ "memchr", "serde", @@ -2265,10 +2264,12 @@ dependencies = [ [[package]] name = "js-sys" -version = "0.3.91" +version = "0.3.95" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b49715b7073f385ba4bc528e5747d02e66cb39c6146efb66b781f131f0fb399c" +checksum = "2964e92d1d9dc3364cae4d718d93f227e3abb088e747d92e0395bfdedf1c12ca" dependencies = [ + "cfg-if", + "futures-util", "once_cell", "wasm-bindgen", ] @@ -2301,7 +2302,7 @@ version = "0.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b750dcadc39a09dbadd74e118f6dd6598df77fa01df0cfcdc52c28dece74528a" dependencies = [ - "bitflags 2.11.0", + "bitflags 2.11.1", "serde", "unicode-segmentation", ] @@ -2334,7 +2335,7 @@ checksum = "02cb977175687f33fa4afa0c95c112b987ea1443e5a51c8f8ff27dc618270cc2" dependencies = [ "cssparser 0.29.6", "html5ever 0.29.1", - "indexmap 2.13.0", + "indexmap 2.14.0", "selectors 0.24.0", ] @@ -2370,15 +2371,15 @@ dependencies = [ [[package]] name = "libbz2-rs-sys" -version = "0.2.2" +version = "0.2.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2c4a545a15244c7d945065b5d392b2d2d7f21526fba56ce51467b06ed445e8f7" +checksum = "b3a6a8c165077efc8f3a971534c50ea6a1a18b329ef4a66e897a7e3a1494565f" [[package]] name = "libc" -version = "0.2.183" +version = "0.2.185" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b5b646652bf6661599e1da8901b3b9522896f01e736bad5f723fe7a3a27f899d" +checksum = "52ff2c0fe9bc6cb6b14a0592c2ff4fa9ceb83eea9db979b0487cd054946a2b8f" [[package]] name = "libloading" @@ -2392,14 +2393,14 @@ dependencies = [ [[package]] name = "libredox" -version = "0.1.15" +version = "0.1.16" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7ddbf48fd451246b1f8c2610bd3b4ac0cc6e149d89832867093ab69a17194f08" +checksum = "e02f3bb43d335493c96bf3fd3a321600bf6bd07ed34bc64118e9293bdffea46c" dependencies = [ - "bitflags 2.11.0", + "bitflags 2.11.1", "libc", "plain", - "redox_syscall 0.7.3", + "redox_syscall 0.7.4", ] [[package]] @@ -2410,9 +2411,9 @@ checksum = "32a66949e030da00e8c7d4434b251670a91556f4144941d37452769c25d58a53" [[package]] name = "litemap" -version = "0.8.1" +version = "0.8.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6373607a59f0be73a39b6fe456b8192fcc3585f602af20751600e974dd455e77" +checksum = "92daf443525c4cce67b150400bc2316076100ce0b3686209eb8cf3c31612e6f0" [[package]] name = "lock_api" @@ -2543,9 +2544,9 @@ dependencies = [ [[package]] name = "muda" -version = "0.17.1" +version = "0.17.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "01c1738382f66ed56b3b9c8119e794a2e23148ac8ea214eda86622d4cb9d415a" +checksum = "7c9fec5a4e89860383d778d10563a605838f8f0b2f9303868937e5ff32e86177" dependencies = [ "crossbeam-channel", "dpi", @@ -2568,7 +2569,7 @@ version = "0.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c3f42e7bbe13d351b6bead8286a43aac9534b82bd3cc43e47037f012ebfd62d4" dependencies = [ - "bitflags 2.11.0", + "bitflags 2.11.1", "jni-sys 0.3.1", "log", "ndk-sys", @@ -2604,7 +2605,7 @@ version = "0.30.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "74523f3a35e05aba87a1d978330aef40f67b0304ac79c1c00b294c9830543db6" dependencies = [ - "bitflags 2.11.0", + "bitflags 2.11.1", "cfg-if", "cfg_aliases", "libc", @@ -2622,7 +2623,7 @@ version = "8.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4d3d07927151ff8575b7087f245456e549fea62edf0ec4e565a5ee50c8402bc3" dependencies = [ - "bitflags 2.11.0", + "bitflags 2.11.1", "fsevent-sys", "inotify", "kqueue", @@ -2640,14 +2641,14 @@ version = "2.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "42b8cfee0e339a0337359f3c88165702ac6e600dc01c0cc9579a92d62b08477a" dependencies = [ - "bitflags 2.11.0", + "bitflags 2.11.1", ] [[package]] name = "num-conv" -version = "0.2.0" +version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cf97ec579c3c42f953ef76dbf8d55ac91fb219dde70e49aa4a6b7d74e9919050" +checksum = "c6673768db2d862beb9b39a78fdcb1a69439615d5794a1be50caa9bc92c81967" [[package]] name = "num-traits" @@ -2705,7 +2706,7 @@ version = "0.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d49e936b501e5c5bf01fda3a9452ff86dc3ea98ad5f283e1455153142d97518c" dependencies = [ - "bitflags 2.11.0", + "bitflags 2.11.1", "block2", "objc2", "objc2-core-foundation", @@ -2718,7 +2719,7 @@ version = "0.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "73ad74d880bb43877038da939b7427bba67e9dd42004a18b809ba7d87cee241c" dependencies = [ - "bitflags 2.11.0", + "bitflags 2.11.1", "objc2", "objc2-foundation", ] @@ -2739,7 +2740,7 @@ version = "0.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2a180dd8642fa45cdb7dd721cd4c11b1cadd4929ce112ebd8b9f5803cc79d536" dependencies = [ - "bitflags 2.11.0", + "bitflags 2.11.1", "dispatch2", "objc2", ] @@ -2750,7 +2751,7 @@ version = "0.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e022c9d066895efa1345f8e33e584b9f958da2fd4cd116792e15e07e4720a807" dependencies = [ - "bitflags 2.11.0", + "bitflags 2.11.1", "dispatch2", "objc2", "objc2-core-foundation", @@ -2783,7 +2784,7 @@ version = "0.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0cde0dfb48d25d2b4862161a4d5fcc0e3c24367869ad306b0c9ec0073bfed92d" dependencies = [ - "bitflags 2.11.0", + "bitflags 2.11.1", "objc2", "objc2-core-foundation", "objc2-core-graphics", @@ -2810,7 +2811,7 @@ version = "0.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e3e0adef53c21f888deb4fa59fc59f7eb17404926ee8a6f59f5df0fd7f9f3272" dependencies = [ - "bitflags 2.11.0", + "bitflags 2.11.1", "block2", "libc", "objc2", @@ -2823,7 +2824,7 @@ version = "0.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "180788110936d59bab6bd83b6060ffdfffb3b922ba1396b312ae795e1de9d81d" dependencies = [ - "bitflags 2.11.0", + "bitflags 2.11.1", "objc2", "objc2-core-foundation", ] @@ -2834,7 +2835,7 @@ version = "0.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f112d1746737b0da274ef79a23aac283376f335f4095a083a267a082f21db0c0" dependencies = [ - "bitflags 2.11.0", + "bitflags 2.11.1", "objc2", "objc2-app-kit", "objc2-foundation", @@ -2846,7 +2847,7 @@ version = "0.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "96c1358452b371bf9f104e21ec536d37a650eb10f7ee379fff67d2e08d537f1f" dependencies = [ - "bitflags 2.11.0", + "bitflags 2.11.1", "objc2", "objc2-core-foundation", "objc2-foundation", @@ -2858,7 +2859,7 @@ version = "0.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d87d638e33c06f577498cbcc50491496a3ed4246998a7fbba7ccb98b1e7eab22" dependencies = [ - "bitflags 2.11.0", + "bitflags 2.11.1", "block2", "objc2", "objc2-cloud-kit", @@ -2889,7 +2890,7 @@ version = "0.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b2e5aaab980c433cf470df9d7af96a7b46a9d892d521a2cbbb2f8a4c16751e7f" dependencies = [ - "bitflags 2.11.0", + "bitflags 2.11.1", "block2", "objc2", "objc2-app-kit", @@ -2920,9 +2921,9 @@ checksum = "384b8ab6d37215f3c5301a95a4accb5d64aa607f1fcb26a11b5303878451b4fe" [[package]] name = "open" -version = "5.3.3" +version = "5.3.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "43bb73a7fa3799b198970490a51174027ba0d4ec504b03cd08caf513d40024bc" +checksum = "9f3bab717c29a857abf75fcef718d441ec7cb2725f937343c734740a985d37fd" dependencies = [ "dunce", "is-wsl", @@ -2968,7 +2969,7 @@ dependencies = [ "thiserror 2.0.18", "time", "tokio", - "toml 1.1.0+spec-1.1.0", + "toml 1.1.2+spec-1.1.0", "zip 8.5.1", ] @@ -3192,7 +3193,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5d5285893bb5eb82e6aaf5d59ee909a06a16737a8970984dd7746ba9283498d6" dependencies = [ "phf_shared 0.10.0", - "rand 0.8.5", + "rand 0.8.6", ] [[package]] @@ -3202,7 +3203,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3c80231409c20246a13fddb31776fb942c38553c51e871f8cbd687a4cfb5843d" dependencies = [ "phf_shared 0.11.3", - "rand 0.8.5", + "rand 0.8.6", ] [[package]] @@ -3297,12 +3298,6 @@ version = "0.2.17" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a89322df9ebe1c1578d689c92318e070967d1042b512afbe49518723f4e6d5cd" -[[package]] -name = "pin-utils" -version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" - [[package]] name = "piper" version = "0.2.5" @@ -3316,9 +3311,9 @@ dependencies = [ [[package]] name = "pkg-config" -version = "0.3.32" +version = "0.3.33" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7edddbd0b52d732b21ad9a5fab5c704c14cd949e5e9a1ec5929a24fded1b904c" +checksum = "19f132c84eca552bf34cab8ec81f1c1dcc229b811638f9d283dceabe58c5569e" [[package]] name = "plain" @@ -3333,7 +3328,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "740ebea15c5d1428f910cd1a5f52cebf8d25006245ed8ade92702f4943d91e07" dependencies = [ "base64 0.22.1", - "indexmap 2.13.0", + "indexmap 2.14.0", "quick-xml", "serde", "time", @@ -3374,18 +3369,18 @@ checksum = "c33a9471896f1c69cecef8d20cbe2f7accd12527ce60845ff44c153bb2a21b49" [[package]] name = "portable-atomic-util" -version = "0.2.6" +version = "0.2.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "091397be61a01d4be58e7841595bd4bfedb15f1cd54977d79b8271e94ed799a3" +checksum = "c2a106d1259c23fac8e543272398ae0e3c0b8d33c88ed73d0cc71b0f1d902618" dependencies = [ "portable-atomic", ] [[package]] name = "potential_utf" -version = "0.1.4" +version = "0.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b73949432f5e2a09657003c25bca5e19a0e9c84f8058ca374f49e0ebe605af77" +checksum = "0103b1cef7ec0cf76490e969665504990193874ea05c85ff9bab8b911d0a0564" dependencies = [ "zerovec", ] @@ -3453,7 +3448,7 @@ version = "3.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e67ba7e9b2b56446f1d419b1d807906278ffa1a658a8a5d8a39dcb1f5a78614f" dependencies = [ - "toml_edit 0.25.8+spec-1.1.0", + "toml_edit 0.25.11+spec-1.1.0", ] [[package]] @@ -3526,9 +3521,9 @@ dependencies = [ [[package]] name = "quinn-proto" -version = "0.11.13" +version = "0.11.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f1906b49b0c3bc04b5fe5d86a77925ae6524a19b816ae38ce1e426255f1d8a31" +checksum = "434b42fec591c96ef50e21e886936e66d3cc3f737104fdb9b737c40ffb94c098" dependencies = [ "bytes", "getrandom 0.3.4", @@ -3596,9 +3591,9 @@ dependencies = [ [[package]] name = "rand" -version = "0.8.5" +version = "0.8.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404" +checksum = "5ca0ecfa931c29007047d1bc58e623ab12e5590e8c7cc53200d5202b69266d8a" dependencies = [ "libc", "rand_chacha 0.3.1", @@ -3702,16 +3697,16 @@ version = "0.5.18" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ed2bf2547551a7053d6fdfafda3f938979645c44812fbfcda098faae3f1a362d" dependencies = [ - "bitflags 2.11.0", + "bitflags 2.11.1", ] [[package]] name = "redox_syscall" -version = "0.7.3" +version = "0.7.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6ce70a74e890531977d37e532c34d45e9055d2409ed08ddba14529471ed0be16" +checksum = "f450ad9c3b1da563fb6948a8e0fb0fb9269711c9c73d9ea1de5058c79c8d643a" dependencies = [ - "bitflags 2.11.0", + "bitflags 2.11.1", ] [[package]] @@ -3899,9 +3894,9 @@ checksum = "b50b8869d9fc858ce7266cce0194bd74df58b9d0e3f6df3a9fc8eb470d95c09d" [[package]] name = "rustc-hash" -version = "2.1.1" +version = "2.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "357703d41365b4b27c590e3ed91eabb1b663f07c4c084095e60cbed4362dff0d" +checksum = "94300abf3f1ae2e2b8ffb7b58043de3d399c73fa6f4b73826402a5c457614dbe" [[package]] name = "rustc_version" @@ -3918,7 +3913,7 @@ version = "1.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b6fe4565b9518b83ef4f91bb47ce29620ca828bd32cb7e408f0062e9930ba190" dependencies = [ - "bitflags 2.11.0", + "bitflags 2.11.1", "errno", "libc", "linux-raw-sys", @@ -3927,9 +3922,9 @@ dependencies = [ [[package]] name = "rustls" -version = "0.23.37" +version = "0.23.38" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "758025cb5fccfd3bc2fd74708fd4682be41d99e5dff73c377c0646c6012c73a4" +checksum = "69f9466fb2c14ea04357e91413efb882e2a6d4a406e625449bc0a5d360d53a21" dependencies = [ "log", "once_cell", @@ -4093,7 +4088,7 @@ version = "3.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b7f4bc775c73d9a02cde8bf7b2ec4c9d12743edf609006c7facc23998404cd1d" dependencies = [ - "bitflags 2.11.0", + "bitflags 2.11.1", "core-foundation", "core-foundation-sys", "libc", @@ -4134,7 +4129,7 @@ version = "0.36.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c5d9c0c92a92d33f08817311cf3f2c29a3538a8240e94a6a3c622ce652d7e00c" dependencies = [ - "bitflags 2.11.0", + "bitflags 2.11.1", "cssparser 0.36.0", "derive_more 2.1.1", "log", @@ -4149,9 +4144,9 @@ dependencies = [ [[package]] name = "semver" -version = "1.0.27" +version = "1.0.28" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d767eb0aabc880b29956c35734170f26ed551a859dbd361d140cdbeca61ab1e2" +checksum = "8a7852d02fc848982e0c167ef163aaff9cd91dc640ba85e263cb1ce46fae51cd" dependencies = [ "serde", "serde_core", @@ -4221,7 +4216,7 @@ version = "0.46.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e200860daf76e09f9ad111bce25928f96bedbb84bc5934b37f05bb445727c70e" dependencies = [ - "bitflags 2.11.0", + "bitflags 2.11.1", "log", "sentry-core", ] @@ -4242,7 +4237,7 @@ version = "0.46.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5b07eefe04486316c57aba08ab53dd44753c25102d1d3fe05775cc93a13262d9" dependencies = [ - "bitflags 2.11.0", + "bitflags 2.11.1", "sentry-backtrace", "sentry-core", "tracing-core", @@ -4354,9 +4349,9 @@ dependencies = [ [[package]] name = "serde_spanned" -version = "1.1.0" +version = "1.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "876ac351060d4f882bb1032b6369eb0aef79ad9df1ea8bc404874d8cc3d0cd98" +checksum = "6662b5879511e06e8999a8a235d848113e942c9124f211511b16466ee2995f26" dependencies = [ "serde_core", ] @@ -4383,7 +4378,7 @@ dependencies = [ "chrono", "hex", "indexmap 1.9.3", - "indexmap 2.13.0", + "indexmap 2.14.0", "schemars 0.9.0", "schemars 1.2.1", "serde_core", @@ -4496,9 +4491,9 @@ dependencies = [ [[package]] name = "simd-adler32" -version = "0.3.8" +version = "0.3.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e320a6c5ad31d271ad523dcf3ad13e2767ad8b1cb8f047f75a8aeaf8da139da2" +checksum = "703d5c7ef118737c72f1af64ad2f6f8c5e1921f818cdcb97b8fe6fc69bf66214" [[package]] name = "siphasher" @@ -4721,7 +4716,7 @@ version = "0.34.8" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9103edf55f2da3c82aea4c7fab7c4241032bfeea0e71fa557d98e00e7ce7cc20" dependencies = [ - "bitflags 2.11.0", + "bitflags 2.11.1", "block2", "core-foundation", "core-graphics", @@ -5219,9 +5214,9 @@ dependencies = [ [[package]] name = "tinystr" -version = "0.8.2" +version = "0.8.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "42d3e9c45c09de15d06dd8acf5f4e0e399e85927b7f00711024eb7ae10fa4869" +checksum = "c8323304221c2a851516f22236c5722a72eaa19749016521d6dff0824447d96d" dependencies = [ "displaydoc", "zerovec", @@ -5229,9 +5224,9 @@ dependencies = [ [[package]] name = "tinyvec" -version = "1.10.0" +version = "1.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bfa5fdc3bce6191a1dbc8c02d5c8bffcf557bafa17c124c5264a458f1b0613fa" +checksum = "3e61e67053d25a4e82c844e8424039d9745781b3fc4f32b8d55ed50f5f667ef3" dependencies = [ "tinyvec_macros", ] @@ -5244,9 +5239,9 @@ checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20" [[package]] name = "tokio" -version = "1.51.1" +version = "1.52.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f66bf9585cda4b724d3e78ab34b73fb2bbaba9011b9bfdf69dc836382ea13b8c" +checksum = "b67dee974fe86fd92cc45b7a95fdd2f99a36a6d7b0d431a231178d3d670bbcc6" dependencies = [ "bytes", "libc", @@ -5298,9 +5293,9 @@ version = "0.9.12+spec-1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "cf92845e79fc2e2def6a5d828f0801e29a2f8acc037becc5ab08595c7d5e9863" dependencies = [ - "indexmap 2.13.0", + "indexmap 2.14.0", "serde_core", - "serde_spanned 1.1.0", + "serde_spanned 1.1.1", "toml_datetime 0.7.5+spec-1.1.0", "toml_parser", "toml_writer", @@ -5309,17 +5304,17 @@ dependencies = [ [[package]] name = "toml" -version = "1.1.0+spec-1.1.0" +version = "1.1.2+spec-1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f8195ca05e4eb728f4ba94f3e3291661320af739c4e43779cbdfae82ab239fcc" +checksum = "81f3d15e84cbcd896376e6730314d59fb5a87f31e4b038454184435cd57defee" dependencies = [ - "indexmap 2.13.0", + "indexmap 2.14.0", "serde_core", - "serde_spanned 1.1.0", - "toml_datetime 1.1.0+spec-1.1.0", + "serde_spanned 1.1.1", + "toml_datetime 1.1.1+spec-1.1.0", "toml_parser", "toml_writer", - "winnow 1.0.0", + "winnow 1.0.2", ] [[package]] @@ -5342,9 +5337,9 @@ dependencies = [ [[package]] name = "toml_datetime" -version = "1.1.0+spec-1.1.0" +version = "1.1.1+spec-1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "97251a7c317e03ad83774a8752a7e81fb6067740609f75ea2b585b569a59198f" +checksum = "3165f65f62e28e0115a00b2ebdd37eb6f3b641855f9d636d3cd4103767159ad7" dependencies = [ "serde_core", ] @@ -5355,7 +5350,7 @@ version = "0.19.15" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1b5bb770da30e5cbfde35a2d7b9b8a2c4b8ef89548a7a6aeab5c9a576e3e7421" dependencies = [ - "indexmap 2.13.0", + "indexmap 2.14.0", "toml_datetime 0.6.3", "winnow 0.5.40", ] @@ -5366,7 +5361,7 @@ version = "0.20.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "396e4d48bbb2b7554c944bde63101b5ae446cff6ec4a24227428f15eb72ef338" dependencies = [ - "indexmap 2.13.0", + "indexmap 2.14.0", "serde", "serde_spanned 0.6.9", "toml_datetime 0.6.3", @@ -5375,30 +5370,30 @@ dependencies = [ [[package]] name = "toml_edit" -version = "0.25.8+spec-1.1.0" +version = "0.25.11+spec-1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "16bff38f1d86c47f9ff0647e6838d7bb362522bdf44006c7068c2b1e606f1f3c" +checksum = "0b59c4d22ed448339746c59b905d24568fcbb3ab65a500494f7b8c3e97739f2b" dependencies = [ - "indexmap 2.13.0", - "toml_datetime 1.1.0+spec-1.1.0", + "indexmap 2.14.0", + "toml_datetime 1.1.1+spec-1.1.0", "toml_parser", - "winnow 1.0.0", + "winnow 1.0.2", ] [[package]] name = "toml_parser" -version = "1.1.0+spec-1.1.0" +version = "1.1.2+spec-1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2334f11ee363607eb04df9b8fc8a13ca1715a72ba8662a26ac285c98aabb4011" +checksum = "a2abe9b86193656635d2411dc43050282ca48aa31c2451210f4202550afb7526" dependencies = [ - "winnow 1.0.0", + "winnow 1.0.2", ] [[package]] name = "toml_writer" -version = "1.1.0+spec-1.1.0" +version = "1.1.1+spec-1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d282ade6016312faf3e41e57ebbba0c073e4056dab1232ab1cb624199648f8ed" +checksum = "756daf9b1013ebe47a8776667b466417e2d4c5679d441c26230efd9ef78692db" [[package]] name = "tower" @@ -5421,7 +5416,7 @@ version = "0.6.8" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d4e6559d53cc268e5031cd8429d05415bc4cb4aefc4aa5d6cc35fbf5b924a1f8" dependencies = [ - "bitflags 2.11.0", + "bitflags 2.11.1", "bytes", "futures-util", "http", @@ -5528,9 +5523,9 @@ checksum = "bc7d623258602320d5c55d1bc22793b57daff0ec7efc270ea7d55ce1d5f5471c" [[package]] name = "typenum" -version = "1.19.0" +version = "1.20.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "562d481066bde0658276a35467c4af00bdc6ee726305698a55b86e61d7ad82bb" +checksum = "40ce102ab67701b8526c123c1bab5cbe42d7040ccfd0f64af1a385808d2f43de" [[package]] name = "uds_windows" @@ -5601,9 +5596,9 @@ checksum = "e6e4313cd5fcd3dad5cafa179702e2b244f760991f45397d14d4ebf38247da75" [[package]] name = "unicode-segmentation" -version = "1.13.1" +version = "1.13.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "da36089a805484bcccfffe0739803392c8298778a2d2f09febf76fac5ad9025b" +checksum = "9629274872b2bfaf8d66f5f15725007f635594914870f65218920345aa11aa8c" [[package]] name = "unicode-xid" @@ -5619,9 +5614,9 @@ checksum = "8ecb6da28b8a351d773b68d5825ac39017e680750f980f3a1a85cd8dd28a47c1" [[package]] name = "ureq" -version = "3.2.0" +version = "3.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fdc97a28575b85cfedf2a7e7d3cc64b3e11bd8ac766666318003abbacc7a21fc" +checksum = "dea7109cdcd5864d4eeb1b58a1648dc9bf520360d7af16ec26d0a9354bafcfc0" dependencies = [ "base64 0.22.1", "log", @@ -5629,15 +5624,15 @@ dependencies = [ "rustls", "rustls-pki-types", "ureq-proto", - "utf-8", + "utf8-zero", "webpki-roots", ] [[package]] name = "ureq-proto" -version = "0.5.3" +version = "0.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d81f9efa9df032be5934a46a068815a10a042b494b6a58cb0a1a97bb5467ed6f" +checksum = "e994ba84b0bd1b1b0cf92878b7ef898a5c1760108fe7b6010327e274917a808c" dependencies = [ "base64 0.22.1", "http", @@ -5676,6 +5671,12 @@ version = "0.7.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "09cc8ee72d2a9becf2f2febe0205bbed8fc6615b7cb429ad062dc7b7ddd036a9" +[[package]] +name = "utf8-zero" +version = "0.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b8c0a043c9540bae7c578c88f91dda8bd82e59ae27c21baca69c8b191aaf5a6e" + [[package]] name = "utf8_iter" version = "1.0.4" @@ -5690,9 +5691,9 @@ checksum = "06abde3611657adf66d383f00b093d7faecc7fa57071cce2578660c9f1010821" [[package]] name = "uuid" -version = "1.22.0" +version = "1.23.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a68d3c8f01c0cfa54a75291d83601161799e4a89a39e0929f4b0354d88757a37" +checksum = "ddd74a9687298c6858e9b88ec8935ec45d22e8fd5e6394fa1bd4e99a87789c76" dependencies = [ "getrandom 0.4.2", "js-sys", @@ -5771,11 +5772,11 @@ checksum = "ccf3ec651a847eb01de73ccad15eb7d99f80485de043efb2f370cd654f4ea44b" [[package]] name = "wasip2" -version = "1.0.2+wasi-0.2.9" +version = "1.0.3+wasi-0.2.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9517f9239f02c069db75e65f174b3da828fe5f5b945c4dd26bd25d89c03ebcf5" +checksum = "20064672db26d7cdc89c7798c48a0fdfac8213434a1186e5ef29fd560ae223d6" dependencies = [ - "wit-bindgen", + "wit-bindgen 0.57.1", ] [[package]] @@ -5784,14 +5785,14 @@ version = "0.4.0+wasi-0.3.0-rc-2026-01-06" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5428f8bf88ea5ddc08faddef2ac4a67e390b88186c703ce6dbd955e1c145aca5" dependencies = [ - "wit-bindgen", + "wit-bindgen 0.51.0", ] [[package]] name = "wasm-bindgen" -version = "0.2.114" +version = "0.2.118" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6532f9a5c1ece3798cb1c2cfdba640b9b3ba884f5db45973a6f442510a87d38e" +checksum = "0bf938a0bacb0469e83c1e148908bd7d5a6010354cf4fb73279b7447422e3a89" dependencies = [ "cfg-if", "once_cell", @@ -5802,23 +5803,19 @@ dependencies = [ [[package]] name = "wasm-bindgen-futures" -version = "0.4.64" +version = "0.4.68" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e9c5522b3a28661442748e09d40924dfb9ca614b21c00d3fd135720e48b67db8" +checksum = "f371d383f2fb139252e0bfac3b81b265689bf45b6874af544ffa4c975ac1ebf8" dependencies = [ - "cfg-if", - "futures-util", "js-sys", - "once_cell", "wasm-bindgen", - "web-sys", ] [[package]] name = "wasm-bindgen-macro" -version = "0.2.114" +version = "0.2.118" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "18a2d50fcf105fb33bb15f00e7a77b772945a2ee45dcf454961fd843e74c18e6" +checksum = "eeff24f84126c0ec2db7a449f0c2ec963c6a49efe0698c4242929da037ca28ed" dependencies = [ "quote", "wasm-bindgen-macro-support", @@ -5826,9 +5823,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro-support" -version = "0.2.114" +version = "0.2.118" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "03ce4caeaac547cdf713d280eda22a730824dd11e6b8c3ca9e42247b25c631e3" +checksum = "9d08065faf983b2b80a79fd87d8254c409281cf7de75fc4b773019824196c904" dependencies = [ "bumpalo", "proc-macro2", @@ -5839,9 +5836,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-shared" -version = "0.2.114" +version = "0.2.118" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "75a326b8c223ee17883a4251907455a2431acc2791c98c26279376490c378c16" +checksum = "5fd04d9e306f1907bd13c6361b5c6bfc7b3b3c095ed3f8a9246390f8dbdee129" dependencies = [ "unicode-ident", ] @@ -5863,7 +5860,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bb0e353e6a2fbdc176932bbaab493762eb1255a7900fe0fea1a2f96c296cc909" dependencies = [ "anyhow", - "indexmap 2.13.0", + "indexmap 2.14.0", "wasm-encoder", "wasmparser", ] @@ -5887,17 +5884,17 @@ version = "0.244.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "47b807c72e1bac69382b3a6fb3dbe8ea4c0ed87ff5629b8685ae6b9a611028fe" dependencies = [ - "bitflags 2.11.0", + "bitflags 2.11.1", "hashbrown 0.15.5", - "indexmap 2.13.0", + "indexmap 2.14.0", "semver", ] [[package]] name = "web-sys" -version = "0.3.91" +version = "0.3.95" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "854ba17bb104abfb26ba36da9729addc7ce7f06f5c0f90f3c391f8461cca21f9" +checksum = "4f2dfbb17949fa2088e5d39408c48368947b86f7834484e87b73de55bc14d97d" dependencies = [ "js-sys", "wasm-bindgen", @@ -5915,9 +5912,9 @@ dependencies = [ [[package]] name = "web_atoms" -version = "0.2.3" +version = "0.2.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "57a9779e9f04d2ac1ce317aee707aa2f6b773afba7b931222bff6983843b1576" +checksum = "d7cff6eef815df1834fd250e3a2ff436044d82a9f1bc1980ca1dbdf07effc538" dependencies = [ "phf 0.13.1", "phf_codegen 0.13.1", @@ -5971,18 +5968,18 @@ dependencies = [ [[package]] name = "webpki-root-certs" -version = "1.0.6" +version = "1.0.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "804f18a4ac2676ffb4e8b5b5fa9ae38af06df08162314f96a68d2a363e21a8ca" +checksum = "f31141ce3fc3e300ae89b78c0dd67f9708061d1d2eda54b8209346fd6be9a92c" dependencies = [ "rustls-pki-types", ] [[package]] name = "webpki-roots" -version = "1.0.6" +version = "1.0.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "22cfaf3c063993ff62e73cb4311efde4db1efb31ab78a3e5c457939ad5cc0bed" +checksum = "52f5ee44c96cf55f1b349600768e3ece3a8f26010c05265ab73f945bb1a2eb9d" dependencies = [ "rustls-pki-types", ] @@ -6477,9 +6474,9 @@ dependencies = [ [[package]] name = "winnow" -version = "1.0.0" +version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a90e88e4667264a994d34e6d1ab2d26d398dcdca8b7f52bec8668957517fc7d8" +checksum = "2ee1708bef14716a11bae175f579062d4554d95be2c6829f518df847b7b3fdd0" dependencies = [ "memchr", ] @@ -6503,6 +6500,12 @@ dependencies = [ "wit-bindgen-rust-macro", ] +[[package]] +name = "wit-bindgen" +version = "0.57.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1ebf944e87a7c253233ad6766e082e3cd714b5d03812acc24c318f549614536e" + [[package]] name = "wit-bindgen-core" version = "0.51.0" @@ -6522,7 +6525,7 @@ checksum = "b7c566e0f4b284dd6561c786d9cb0142da491f46a9fbed79ea69cdad5db17f21" dependencies = [ "anyhow", "heck 0.5.0", - "indexmap 2.13.0", + "indexmap 2.14.0", "prettyplease", "syn 2.0.117", "wasm-metadata", @@ -6552,8 +6555,8 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9d66ea20e9553b30172b5e831994e35fbde2d165325bec84fc43dbf6f4eb9cb2" dependencies = [ "anyhow", - "bitflags 2.11.0", - "indexmap 2.13.0", + "bitflags 2.11.1", + "indexmap 2.14.0", "log", "serde", "serde_derive", @@ -6572,7 +6575,7 @@ checksum = "ecc8ac4bc1dc3381b7f59c34f00b67e18f910c2c0f50015669dde7def656a736" dependencies = [ "anyhow", "id-arena", - "indexmap 2.13.0", + "indexmap 2.14.0", "log", "semver", "serde", @@ -6584,9 +6587,9 @@ dependencies = [ [[package]] name = "writeable" -version = "0.6.2" +version = "0.6.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9edde0db4769d2dc68579893f2306b26c6ecfbe0ef499b013d731b7b9247e0b9" +checksum = "1ffae5123b2d3fc086436f8834ae3ab053a283cfac8fe0a0b8eaae044768a4c4" [[package]] name = "wry" @@ -6665,9 +6668,9 @@ dependencies = [ [[package]] name = "yoke" -version = "0.8.1" +version = "0.8.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "72d6e5c6afb84d73944e5cedb052c4680d5657337201555f9f2a16b7406d4954" +checksum = "abe8c5fda708d9ca3df187cae8bfb9ceda00dd96231bed36e445a1a48e66f9ca" dependencies = [ "stable_deref_trait", "yoke-derive", @@ -6676,9 +6679,9 @@ dependencies = [ [[package]] name = "yoke-derive" -version = "0.8.1" +version = "0.8.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b659052874eb698efe5b9e8cf382204678a0086ebf46982b79d6ca3182927e5d" +checksum = "de844c262c8848816172cef550288e7dc6c7b7814b4ee56b3e1553f275f1858e" dependencies = [ "proc-macro2", "quote", @@ -6749,18 +6752,18 @@ dependencies = [ [[package]] name = "zerocopy" -version = "0.8.47" +version = "0.8.48" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "efbb2a062be311f2ba113ce66f697a4dc589f85e78a4aea276200804cea0ed87" +checksum = "eed437bf9d6692032087e337407a86f04cd8d6a16a37199ed57949d415bd68e9" dependencies = [ "zerocopy-derive", ] [[package]] name = "zerocopy-derive" -version = "0.8.47" +version = "0.8.48" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0e8bc7269b54418e7aeeef514aa68f8690b8c0489a06b0136e5f57c4c5ccab89" +checksum = "70e3cd084b1788766f53af483dd21f93881ff30d7320490ec3ef7526d203bad4" dependencies = [ "proc-macro2", "quote", @@ -6769,18 +6772,18 @@ dependencies = [ [[package]] name = "zerofrom" -version = "0.1.6" +version = "0.1.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "50cc42e0333e05660c3587f3bf9d0478688e15d870fab3346451ce7f8c9fbea5" +checksum = "69faa1f2a1ea75661980b013019ed6687ed0e83d069bc1114e2cc74c6c04c4df" dependencies = [ "zerofrom-derive", ] [[package]] name = "zerofrom-derive" -version = "0.1.6" +version = "0.1.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d71e5d6e06ab090c67b5e44993ec16b72dcbaabc526db883a360057678b48502" +checksum = "11532158c46691caf0f2593ea8358fed6bbf68a0315e80aae9bd41fbade684a1" dependencies = [ "proc-macro2", "quote", @@ -6796,9 +6799,9 @@ checksum = "b97154e67e32c85465826e8bcc1c59429aaaf107c1e4a9e53c8d8ccd5eff88d0" [[package]] name = "zerotrie" -version = "0.2.3" +version = "0.2.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2a59c17a5562d507e4b54960e8569ebee33bee890c70aa3fe7b97e85a9fd7851" +checksum = "0f9152d31db0792fa83f70fb2f83148effb5c1f5b8c7686c3459e361d9bc20bf" dependencies = [ "displaydoc", "yoke", @@ -6807,9 +6810,9 @@ dependencies = [ [[package]] name = "zerovec" -version = "0.11.5" +version = "0.11.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6c28719294829477f525be0186d13efa9a3c602f7ec202ca9e353d310fb9a002" +checksum = "90f911cbc359ab6af17377d242225f4d75119aec87ea711a880987b18cd7b239" dependencies = [ "yoke", "zerofrom", @@ -6818,9 +6821,9 @@ dependencies = [ [[package]] name = "zerovec-derive" -version = "0.11.2" +version = "0.11.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eadce39539ca5cb3985590102671f2567e659fca9666581ad3411d59207951f3" +checksum = "625dc425cab0dca6dc3c3319506e6593dcb08a9f387ea3b284dbd52a92c40555" dependencies = [ "proc-macro2", "quote", @@ -6835,7 +6838,7 @@ checksum = "caa8cd6af31c3b31c6631b8f483848b91589021b28fffe50adada48d4f4d2ed1" dependencies = [ "arbitrary", "crc32fast", - "indexmap 2.13.0", + "indexmap 2.14.0", "memchr", ] @@ -6853,7 +6856,7 @@ dependencies = [ "flate2", "getrandom 0.4.2", "hmac", - "indexmap 2.13.0", + "indexmap 2.14.0", "lzma-rust2", "memchr", "pbkdf2", From 17b79513ea82b38d19f3e9d155e764a20577e904 Mon Sep 17 00:00:00 2001 From: Jordon Date: Wed, 22 Apr 2026 18:37:07 +0100 Subject: [PATCH 28/37] Update package-lock.json --- Frontend/package-lock.json | 307 ++++++++++++++++++++----------------- 1 file changed, 170 insertions(+), 137 deletions(-) diff --git a/Frontend/package-lock.json b/Frontend/package-lock.json index a6dba783..719bf283 100644 --- a/Frontend/package-lock.json +++ b/Frontend/package-lock.json @@ -161,16 +161,6 @@ "node": ">=6.9.0" } }, - "node_modules/@babel/helper-compilation-targets/node_modules/lru-cache": { - "version": "5.1.1", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-5.1.1.tgz", - "integrity": "sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==", - "dev": true, - "license": "ISC", - "dependencies": { - "yallist": "^3.0.2" - } - }, "node_modules/@babel/helper-globals": { "version": "7.28.0", "resolved": "https://registry.npmjs.org/@babel/helper-globals/-/helper-globals-7.28.0.tgz", @@ -946,19 +936,6 @@ "node": ">= 14" } }, - "node_modules/@sentry/bundler-plugin-core/node_modules/magic-string": { - "version": "0.30.8", - "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.8.tgz", - "integrity": "sha512-ISQTe55T2ao7XtlAStud6qwYPZjE4GK1S/BeVPus4jrq6JuOnQ00YKQC581RWhR122W7msZV263KzVeLoqidyQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "@jridgewell/sourcemap-codec": "^1.4.15" - }, - "engines": { - "node": ">=12" - } - }, "node_modules/@sentry/cli": { "version": "2.58.5", "resolved": "https://registry.npmjs.org/@sentry/cli/-/cli-2.58.5.tgz", @@ -1201,16 +1178,16 @@ } }, "node_modules/@vitest/expect": { - "version": "4.1.4", - "resolved": "https://registry.npmjs.org/@vitest/expect/-/expect-4.1.4.tgz", - "integrity": "sha512-iPBpra+VDuXmBFI3FMKHSFXp3Gx5HfmSCE8X67Dn+bwephCnQCaB7qWK2ldHa+8ncN8hJU8VTMcxjPpyMkUjww==", + "version": "4.1.5", + "resolved": "https://registry.npmjs.org/@vitest/expect/-/expect-4.1.5.tgz", + "integrity": "sha512-PWBaRY5JoKuRnHlUHfpV/KohFylaDZTupcXN1H9vYryNLOnitSw60Mw9IAE2r67NbwwzBw/Cc/8q9BK3kIX8Kw==", "dev": true, "license": "MIT", "dependencies": { "@standard-schema/spec": "^1.1.0", "@types/chai": "^5.2.2", - "@vitest/spy": "4.1.4", - "@vitest/utils": "4.1.4", + "@vitest/spy": "4.1.5", + "@vitest/utils": "4.1.5", "chai": "^6.2.2", "tinyrainbow": "^3.1.0" }, @@ -1219,13 +1196,13 @@ } }, "node_modules/@vitest/mocker": { - "version": "4.1.4", - "resolved": "https://registry.npmjs.org/@vitest/mocker/-/mocker-4.1.4.tgz", - "integrity": "sha512-R9HTZBhW6yCSGbGQnDnH3QHfJxokKN4KB+Yvk9Q1le7eQNYwiCyKxmLmurSpFy6BzJanSLuEUDrD+j97Q+ZLPg==", + "version": "4.1.5", + "resolved": "https://registry.npmjs.org/@vitest/mocker/-/mocker-4.1.5.tgz", + "integrity": "sha512-/x2EmFC4mT4NNzqvC3fmesuV97w5FC903KPmey4gsnJiMQ3Be1IlDKVaDaG8iqaLFHqJ2FVEkxZk5VmeLjIItw==", "dev": true, "license": "MIT", "dependencies": { - "@vitest/spy": "4.1.4", + "@vitest/spy": "4.1.5", "estree-walker": "^3.0.3", "magic-string": "^0.30.21" }, @@ -1245,10 +1222,20 @@ } } }, + "node_modules/@vitest/mocker/node_modules/magic-string": { + "version": "0.30.21", + "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.21.tgz", + "integrity": "sha512-vd2F4YUyEXKGcLHoq+TEyCjxueSeHnFxyyjNp80yg0XV4vUhnDer/lvvlqM/arB5bXQN5K2/3oinyCRyx8T2CQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jridgewell/sourcemap-codec": "^1.5.5" + } + }, "node_modules/@vitest/pretty-format": { - "version": "4.1.4", - "resolved": "https://registry.npmjs.org/@vitest/pretty-format/-/pretty-format-4.1.4.tgz", - "integrity": "sha512-ddmDHU0gjEUyEVLxtZa7xamrpIefdEETu3nZjWtHeZX4QxqJ7tRxSteHVXJOcr8jhiLoGAhkK4WJ3WqBpjx42A==", + "version": "4.1.5", + "resolved": "https://registry.npmjs.org/@vitest/pretty-format/-/pretty-format-4.1.5.tgz", + "integrity": "sha512-7I3q6l5qr03dVfMX2wCo9FxwSJbPdwKjy2uu/YPpU3wfHvIL4QHwVRp57OfGrDFeUJ8/8QdfBKIV12FTtLn00g==", "dev": true, "license": "MIT", "dependencies": { @@ -1259,13 +1246,13 @@ } }, "node_modules/@vitest/runner": { - "version": "4.1.4", - "resolved": "https://registry.npmjs.org/@vitest/runner/-/runner-4.1.4.tgz", - "integrity": "sha512-xTp7VZ5aXP5ZJrn15UtJUWlx6qXLnGtF6jNxHepdPHpMfz/aVPx+htHtgcAL2mDXJgKhpoo2e9/hVJsIeFbytQ==", + "version": "4.1.5", + "resolved": "https://registry.npmjs.org/@vitest/runner/-/runner-4.1.5.tgz", + "integrity": "sha512-2D+o7Pr82IEO46YPpoA/YU0neeyr6FTerQb5Ro7BUnBuv6NQtT/kmVnczngiMEBhzgqz2UZYl5gArejsyERDSQ==", "dev": true, "license": "MIT", "dependencies": { - "@vitest/utils": "4.1.4", + "@vitest/utils": "4.1.5", "pathe": "^2.0.3" }, "funding": { @@ -1273,14 +1260,14 @@ } }, "node_modules/@vitest/snapshot": { - "version": "4.1.4", - "resolved": "https://registry.npmjs.org/@vitest/snapshot/-/snapshot-4.1.4.tgz", - "integrity": "sha512-MCjCFgaS8aZz+m5nTcEcgk/xhWv0rEH4Yl53PPlMXOZ1/Ka2VcZU6CJ+MgYCZbcJvzGhQRjVrGQNZqkGPttIKw==", + "version": "4.1.5", + "resolved": "https://registry.npmjs.org/@vitest/snapshot/-/snapshot-4.1.5.tgz", + "integrity": "sha512-zypXEt4KH/XgKGPUz4eC2AvErYx0My5hfL8oDb1HzGFpEk1P62bxSohdyOmvz+d9UJwanI68MKwr2EquOaOgMQ==", "dev": true, "license": "MIT", "dependencies": { - "@vitest/pretty-format": "4.1.4", - "@vitest/utils": "4.1.4", + "@vitest/pretty-format": "4.1.5", + "@vitest/utils": "4.1.5", "magic-string": "^0.30.21", "pathe": "^2.0.3" }, @@ -1288,10 +1275,20 @@ "url": "https://opencollective.com/vitest" } }, + "node_modules/@vitest/snapshot/node_modules/magic-string": { + "version": "0.30.21", + "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.21.tgz", + "integrity": "sha512-vd2F4YUyEXKGcLHoq+TEyCjxueSeHnFxyyjNp80yg0XV4vUhnDer/lvvlqM/arB5bXQN5K2/3oinyCRyx8T2CQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jridgewell/sourcemap-codec": "^1.5.5" + } + }, "node_modules/@vitest/spy": { - "version": "4.1.4", - "resolved": "https://registry.npmjs.org/@vitest/spy/-/spy-4.1.4.tgz", - "integrity": "sha512-XxNdAsKW7C+FLydqFJLb5KhJtl3PGCMmYwFRfhvIgxJvLSXhhVI1zM8f1qD3Zg7RCjTSzDVyct6sghs9UEgBEQ==", + "version": "4.1.5", + "resolved": "https://registry.npmjs.org/@vitest/spy/-/spy-4.1.5.tgz", + "integrity": "sha512-2lNOsh6+R2Idnf1TCZqSwYlKN2E/iDlD8sgU59kYVl+OMDmvldO1VDk39smRfpUNwYpNRVn3w4YfuC7KfbBnkQ==", "dev": true, "license": "MIT", "funding": { @@ -1299,13 +1296,13 @@ } }, "node_modules/@vitest/utils": { - "version": "4.1.4", - "resolved": "https://registry.npmjs.org/@vitest/utils/-/utils-4.1.4.tgz", - "integrity": "sha512-13QMT+eysM5uVGa1rG4kegGYNp6cnQcsTc67ELFbhNLQO+vgsygtYJx2khvdt4gVQqSSpC/KT5FZZxUpP3Oatw==", + "version": "4.1.5", + "resolved": "https://registry.npmjs.org/@vitest/utils/-/utils-4.1.5.tgz", + "integrity": "sha512-76wdkrmfXfqGjueGgnb45ITPyUi1ycZ4IHgC2bhPDUfWHklY/q3MdLOAB+TF1e6xfl8NxNY0ZYaPCFNWSsw3Ug==", "dev": true, "license": "MIT", "dependencies": { - "@vitest/pretty-format": "4.1.4", + "@vitest/pretty-format": "4.1.5", "convert-source-map": "^2.0.0", "tinyrainbow": "^3.1.0" }, @@ -1379,19 +1376,6 @@ "node": ">= 8" } }, - "node_modules/anymatch/node_modules/picomatch": { - "version": "2.3.2", - "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.2.tgz", - "integrity": "sha512-V7+vQEJ06Z+c5tSye8S+nHUfI51xoXIXjHQ99cQtKUkQqqO1kO/KCJUfZXuB47h/YBlDhah2H3hdUGXn8ie0oA==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=8.6" - }, - "funding": { - "url": "https://github.com/sponsors/jonschlinkert" - } - }, "node_modules/assertion-error": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/assertion-error/-/assertion-error-2.0.1.tgz", @@ -1410,9 +1394,9 @@ "license": "MIT" }, "node_modules/baseline-browser-mapping": { - "version": "2.10.20", - "resolved": "https://registry.npmjs.org/baseline-browser-mapping/-/baseline-browser-mapping-2.10.20.tgz", - "integrity": "sha512-1AaXxEPfXT+GvTBJFuy4yXVHWJBXa4OdbIebGN/wX5DlsIkU0+wzGnd2lOzokSk51d5LUmqjgBLRLlypLUqInQ==", + "version": "2.10.21", + "resolved": "https://registry.npmjs.org/baseline-browser-mapping/-/baseline-browser-mapping-2.10.21.tgz", + "integrity": "sha512-Q+rUQ7Uz8AHM7DEaNdwvfFCTq7a43lNTzuS94eiWqwyxfV/wJv+oUivef51T91mmRY4d4A1u9rcSvkeufCVXlA==", "dev": true, "license": "Apache-2.0", "bin": { @@ -1503,9 +1487,9 @@ } }, "node_modules/caniuse-lite": { - "version": "1.0.30001788", - "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001788.tgz", - "integrity": "sha512-6q8HFp+lOQtcf7wBK+uEenxymVWkGKkjFpCvw5W25cmMwEDU45p1xQFBQv8JDlMMry7eNxyBaR+qxgmTUZkIRQ==", + "version": "1.0.30001790", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001790.tgz", + "integrity": "sha512-bOoxfJPyYo+ds6W0YfptaCWbFnJYjh2Y1Eow5lRv+vI2u8ganPZqNm1JwNh0t2ELQCqIWg4B3dWEusgAmsoyOw==", "dev": true, "funding": [ { @@ -1684,9 +1668,9 @@ "license": "MIT" }, "node_modules/electron-to-chromium": { - "version": "1.5.340", - "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.340.tgz", - "integrity": "sha512-908qahOGocRMinT2nM3ajCEM99H4iPdv84eagPP3FfZy/1ZGeOy2CZYzjhms81ckOPCXPlW7LkY4XpxD8r1DrA==", + "version": "1.5.343", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.343.tgz", + "integrity": "sha512-YHnQ3MXI08icvL9ZKnEBy05F2EQ8ob01UaMOuMbM8l+4UcAq6MPPbBTJBbsBUg3H8JeZNt+O4fjsoWth3p6IFg==", "dev": true, "license": "ISC" }, @@ -1747,24 +1731,6 @@ "node": ">=12.0.0" } }, - "node_modules/fdir": { - "version": "6.5.0", - "resolved": "https://registry.npmjs.org/fdir/-/fdir-6.5.0.tgz", - "integrity": "sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=12.0.0" - }, - "peerDependencies": { - "picomatch": "^3 || ^4" - }, - "peerDependenciesMeta": { - "picomatch": { - "optional": true - } - } - }, "node_modules/fill-range": { "version": "7.1.1", "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz", @@ -2033,6 +1999,16 @@ } } }, + "node_modules/jsdom/node_modules/lru-cache": { + "version": "11.3.5", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-11.3.5.tgz", + "integrity": "sha512-NxVFwLAnrd9i7KUBxC4DrUhmgjzOs+1Qm50D3oF1/oL+r1NpZ4gA7xvG0/zJ8evR7zIKn4vLf7qTNduWFtCrRw==", + "dev": true, + "license": "BlueOak-1.0.0", + "engines": { + "node": "20 || >=22" + } + }, "node_modules/jsesc": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-3.1.0.tgz", @@ -2349,23 +2325,26 @@ } }, "node_modules/lru-cache": { - "version": "11.3.5", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-11.3.5.tgz", - "integrity": "sha512-NxVFwLAnrd9i7KUBxC4DrUhmgjzOs+1Qm50D3oF1/oL+r1NpZ4gA7xvG0/zJ8evR7zIKn4vLf7qTNduWFtCrRw==", + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-5.1.1.tgz", + "integrity": "sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==", "dev": true, - "license": "BlueOak-1.0.0", - "engines": { - "node": "20 || >=22" + "license": "ISC", + "dependencies": { + "yallist": "^3.0.2" } }, "node_modules/magic-string": { - "version": "0.30.21", - "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.21.tgz", - "integrity": "sha512-vd2F4YUyEXKGcLHoq+TEyCjxueSeHnFxyyjNp80yg0XV4vUhnDer/lvvlqM/arB5bXQN5K2/3oinyCRyx8T2CQ==", + "version": "0.30.8", + "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.8.tgz", + "integrity": "sha512-ISQTe55T2ao7XtlAStud6qwYPZjE4GK1S/BeVPus4jrq6JuOnQ00YKQC581RWhR122W7msZV263KzVeLoqidyQ==", "dev": true, "license": "MIT", "dependencies": { - "@jridgewell/sourcemap-codec": "^1.5.5" + "@jridgewell/sourcemap-codec": "^1.4.15" + }, + "engines": { + "node": ">=12" } }, "node_modules/mdn-data": { @@ -2474,9 +2453,9 @@ } }, "node_modules/node-releases": { - "version": "2.0.37", - "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.37.tgz", - "integrity": "sha512-1h5gKZCF+pO/o3Iqt5Jp7wc9rH3eJJ0+nh/CIoiRwjRxde/hAHyLPXYN4V3CqKAbiZPSeJFSWHmJsbkicta0Eg==", + "version": "2.0.38", + "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.38.tgz", + "integrity": "sha512-3qT/88Y3FbH/Kx4szpQQ4HzUbVrHPKTLVpVocKiLfoYvw9XSGOX2FmD2d6DrXbVYyAQTF2HeF6My8jmzx7/CRw==", "dev": true, "license": "MIT" }, @@ -2618,13 +2597,13 @@ "license": "ISC" }, "node_modules/picomatch": { - "version": "4.0.4", - "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.4.tgz", - "integrity": "sha512-QP88BAKvMam/3NxH6vj2o21R6MjxZUAd6nlwAS/pnGvN9IVLocLHxGYIzFhg6fUQ+5th6P4dv4eW9jX3DSIj7A==", + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.2.tgz", + "integrity": "sha512-V7+vQEJ06Z+c5tSye8S+nHUfI51xoXIXjHQ99cQtKUkQqqO1kO/KCJUfZXuB47h/YBlDhah2H3hdUGXn8ie0oA==", "dev": true, "license": "MIT", "engines": { - "node": ">=12" + "node": ">=8.6" }, "funding": { "url": "https://github.com/sponsors/jonschlinkert" @@ -2699,19 +2678,6 @@ "node": ">=8.10.0" } }, - "node_modules/readdirp/node_modules/picomatch": { - "version": "2.3.2", - "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.2.tgz", - "integrity": "sha512-V7+vQEJ06Z+c5tSye8S+nHUfI51xoXIXjHQ99cQtKUkQqqO1kO/KCJUfZXuB47h/YBlDhah2H3hdUGXn8ie0oA==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=8.6" - }, - "funding": { - "url": "https://github.com/sponsors/jonschlinkert" - } - }, "node_modules/require-from-string": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/require-from-string/-/require-from-string-2.0.2.tgz", @@ -2991,6 +2957,37 @@ "url": "https://github.com/sponsors/SuperchupuDev" } }, + "node_modules/tinyglobby/node_modules/fdir": { + "version": "6.5.0", + "resolved": "https://registry.npmjs.org/fdir/-/fdir-6.5.0.tgz", + "integrity": "sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12.0.0" + }, + "peerDependencies": { + "picomatch": "^3 || ^4" + }, + "peerDependenciesMeta": { + "picomatch": { + "optional": true + } + } + }, + "node_modules/tinyglobby/node_modules/picomatch": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.4.tgz", + "integrity": "sha512-QP88BAKvMam/3NxH6vj2o21R6MjxZUAd6nlwAS/pnGvN9IVLocLHxGYIzFhg6fUQ+5th6P4dv4eW9jX3DSIj7A==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, "node_modules/tinyrainbow": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/tinyrainbow/-/tinyrainbow-3.1.0.tgz", @@ -3221,20 +3218,33 @@ } } }, + "node_modules/vite/node_modules/picomatch": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.4.tgz", + "integrity": "sha512-QP88BAKvMam/3NxH6vj2o21R6MjxZUAd6nlwAS/pnGvN9IVLocLHxGYIzFhg6fUQ+5th6P4dv4eW9jX3DSIj7A==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, "node_modules/vitest": { - "version": "4.1.4", - "resolved": "https://registry.npmjs.org/vitest/-/vitest-4.1.4.tgz", - "integrity": "sha512-tFuJqTxKb8AvfyqMfnavXdzfy3h3sWZRWwfluGbkeR7n0HUev+FmNgZ8SDrRBTVrVCjgH5cA21qGbCffMNtWvg==", + "version": "4.1.5", + "resolved": "https://registry.npmjs.org/vitest/-/vitest-4.1.5.tgz", + "integrity": "sha512-9Xx1v3/ih3m9hN+SbfkUyy0JAs72ap3r7joc87XL6jwF0jGg6mFBvQ1SrwaX+h8BlkX6Hz9shdd1uo6AF+ZGpg==", "dev": true, "license": "MIT", "dependencies": { - "@vitest/expect": "4.1.4", - "@vitest/mocker": "4.1.4", - "@vitest/pretty-format": "4.1.4", - "@vitest/runner": "4.1.4", - "@vitest/snapshot": "4.1.4", - "@vitest/spy": "4.1.4", - "@vitest/utils": "4.1.4", + "@vitest/expect": "4.1.5", + "@vitest/mocker": "4.1.5", + "@vitest/pretty-format": "4.1.5", + "@vitest/runner": "4.1.5", + "@vitest/snapshot": "4.1.5", + "@vitest/spy": "4.1.5", + "@vitest/utils": "4.1.5", "es-module-lexer": "^2.0.0", "expect-type": "^1.3.0", "magic-string": "^0.30.21", @@ -3262,12 +3272,12 @@ "@edge-runtime/vm": "*", "@opentelemetry/api": "^1.9.0", "@types/node": "^20.0.0 || ^22.0.0 || >=24.0.0", - "@vitest/browser-playwright": "4.1.4", - "@vitest/browser-preview": "4.1.4", - "@vitest/browser-webdriverio": "4.1.4", - "@vitest/coverage-istanbul": "4.1.4", - "@vitest/coverage-v8": "4.1.4", - "@vitest/ui": "4.1.4", + "@vitest/browser-playwright": "4.1.5", + "@vitest/browser-preview": "4.1.5", + "@vitest/browser-webdriverio": "4.1.5", + "@vitest/coverage-istanbul": "4.1.5", + "@vitest/coverage-v8": "4.1.5", + "@vitest/ui": "4.1.5", "happy-dom": "*", "jsdom": "*", "vite": "^6.0.0 || ^7.0.0 || ^8.0.0" @@ -3311,6 +3321,29 @@ } } }, + "node_modules/vitest/node_modules/magic-string": { + "version": "0.30.21", + "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.21.tgz", + "integrity": "sha512-vd2F4YUyEXKGcLHoq+TEyCjxueSeHnFxyyjNp80yg0XV4vUhnDer/lvvlqM/arB5bXQN5K2/3oinyCRyx8T2CQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jridgewell/sourcemap-codec": "^1.5.5" + } + }, + "node_modules/vitest/node_modules/picomatch": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.4.tgz", + "integrity": "sha512-QP88BAKvMam/3NxH6vj2o21R6MjxZUAd6nlwAS/pnGvN9IVLocLHxGYIzFhg6fUQ+5th6P4dv4eW9jX3DSIj7A==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, "node_modules/w3c-xmlserializer": { "version": "5.0.0", "resolved": "https://registry.npmjs.org/w3c-xmlserializer/-/w3c-xmlserializer-5.0.0.tgz", From 18473b3eb86b8e87b1f7214d12b493b0be5934da Mon Sep 17 00:00:00 2001 From: Jordon Date: Wed, 22 Apr 2026 19:00:21 +0100 Subject: [PATCH 29/37] Update Git plugin to follow latest commits --- openvcs.plugins.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/openvcs.plugins.json b/openvcs.plugins.json index 4dccff0e..9933becf 100644 --- a/openvcs.plugins.json +++ b/openvcs.plugins.json @@ -1,6 +1,6 @@ { "plugin": [ - "@openvcs/git-plugin@nightly", + "@openvcs/git-plugin@edge", "@openvcs/official-themes@nightly" ] } From a66135837053a4bf7d31601e9147f1f44db9ea3d Mon Sep 17 00:00:00 2001 From: Jordon Date: Wed, 22 Apr 2026 19:51:22 +0100 Subject: [PATCH 30/37] Implement fix for menus --- Backend/src/core/ui.rs | 12 ++++++++++++ Backend/src/tauri_commands/plugins.rs | 5 ++++- Frontend/src/scripts/features/settings.ts | 5 +++++ Frontend/src/scripts/ui/menubar.ts | 5 +++++ docs/plugin architecture.md | 7 +++++++ 5 files changed, 33 insertions(+), 1 deletion(-) diff --git a/Backend/src/core/ui.rs b/Backend/src/core/ui.rs index 163133e2..45ee53d2 100644 --- a/Backend/src/core/ui.rs +++ b/Backend/src/core/ui.rs @@ -5,6 +5,16 @@ use serde::{Deserialize, Serialize}; +/// Menu surface target for rendering. +#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)] +#[serde(rename_all = "kebab-case")] +pub enum MenuSurface { + /// Menu appears in the main menubar. + Menubar, + /// Menu appears in the settings modal. + Settings, +} + /// Menu descriptor contributed by a plugin. #[derive(Debug, Clone, Serialize, Deserialize)] pub struct Menu { @@ -15,6 +25,8 @@ pub struct Menu { /// Optional display ordering hint. #[serde(default, skip_serializing_if = "Option::is_none")] pub order: Option, + /// Required render target surface ('menubar' or 'settings'). + pub surface: MenuSurface, /// Renderable UI elements under the menu. pub elements: Vec, } diff --git a/Backend/src/tauri_commands/plugins.rs b/Backend/src/tauri_commands/plugins.rs index eb682ad7..0cc3bc73 100644 --- a/Backend/src/tauri_commands/plugins.rs +++ b/Backend/src/tauri_commands/plugins.rs @@ -1,7 +1,7 @@ // Copyright © 2025-2026 OpenVCS Contributors // SPDX-License-Identifier: GPL-3.0-or-later use crate::core::settings::{SettingKv, SettingValue}; -use crate::core::ui::{Menu, UiElement}; +use crate::core::ui::{Menu, MenuSurface, UiElement}; use crate::plugin_bundles::{InstalledPluginIndex, PluginBundleStore}; use crate::plugin_runtime::instance::PluginRuntimeInstance; use crate::plugin_runtime::settings_store; @@ -63,6 +63,8 @@ pub struct PluginMenuPayload { pub id: String, /// User-visible label. pub label: String, + /// Render target surface. + pub surface: MenuSurface, /// Renderable menu elements. pub elements: Vec, } @@ -420,6 +422,7 @@ fn menu_to_payload(plugin_id: &str, menu: Menu) -> PluginMenuPayload { plugin_id: plugin_id.to_string(), id: menu.id, label: menu.label, + surface: menu.surface, elements, } } diff --git a/Frontend/src/scripts/features/settings.ts b/Frontend/src/scripts/features/settings.ts index 64edf64a..71295b13 100644 --- a/Frontend/src/scripts/features/settings.ts +++ b/Frontend/src/scripts/features/settings.ts @@ -21,6 +21,7 @@ interface PluginMenuPayload { plugin_id: string; id: string; label: string; + surface: 'menubar' | 'settings'; elements: Array<{ type: 'text' | 'button' | string; id?: string; @@ -300,6 +301,10 @@ async function renderPluginMenus(modal: HTMLElement): Promise { }; for (const menu of menus) { + // Only render settings-surface menus in the settings modal. + const surface = String(menu.surface || 'menubar').toLowerCase(); + if (surface !== 'settings') continue; + const section = pluginSectionId(menu.plugin_id, menu.id); const navLi = document.createElement('li'); navLi.dataset.pluginMenu = 'true'; diff --git a/Frontend/src/scripts/ui/menubar.ts b/Frontend/src/scripts/ui/menubar.ts index 0bf34ddc..d748972f 100644 --- a/Frontend/src/scripts/ui/menubar.ts +++ b/Frontend/src/scripts/ui/menubar.ts @@ -11,6 +11,7 @@ interface PluginMenuPayload { plugin_id: string; id: string; label: string; + surface: 'menubar' | 'settings'; elements: Array<{ type: 'text' | 'button' | string; id?: string; @@ -57,6 +58,10 @@ export async function refreshPluginMenubarMenus(): Promise { } for (const menu of Array.isArray(menus) ? menus : []) { + // Only render menubar-surface menus in the menubar. + const surface = String(menu.surface || 'menubar').toLowerCase(); + if (surface !== 'menubar') continue; + const menuId = String(menu?.id || '').trim(); const list = getMenuList(menuId); if (!menuId || !list) continue; diff --git a/docs/plugin architecture.md b/docs/plugin architecture.md index 030266a4..9c25c528 100644 --- a/docs/plugin architecture.md +++ b/docs/plugin architecture.md @@ -48,6 +48,13 @@ match built-in top-level menus such as `repository` are projected into the main menubar. For VCS backend plugins, these items therefore appear only after the repository-scoped runtime has started. +Menu surfaces can be explicitly targeted using the `surface` option: + +- `getOrCreateMenu('repository', 'Repository', { surface: 'menubar' })` - renders in the top menubar +- `getOrCreateMenu('my-settings', 'My Settings', { surface: 'settings' })` - renders in the Settings modal + +The `surface` option is required. Plugin authors must explicitly specify where their menus should appear. + Core plugin-to-host notifications: - `host.log` From 336d8e8f63e4f03e2aa372f6da4790e719fab561 Mon Sep 17 00:00:00 2001 From: Jordon Date: Wed, 22 Apr 2026 20:23:48 +0100 Subject: [PATCH 31/37] Implement plugin update channels --- .github/workflows/development.yml | 1 + .gitignore | 1 + Backend/scripts/ensure-built-in-plugins.js | 73 ++++++++++++++++++++- Backend/scripts/run-tauri-before-command.js | 10 ++- README.md | 7 +- docs/plugin architecture.md | 26 +++++++- docs/plugins.md | 39 ++++++++++- openvcs.plugins.json | 10 ++- 8 files changed, 154 insertions(+), 13 deletions(-) diff --git a/.github/workflows/development.yml b/.github/workflows/development.yml index b41aa0c6..9ca9e435 100644 --- a/.github/workflows/development.yml +++ b/.github/workflows/development.yml @@ -35,6 +35,7 @@ jobs: RUSTC_WRAPPER: sccache SCCACHE_GHA_ENABLED: ${{ vars.SSCCACHE_GHA_ENABLED }} SCCACHE_CACHE_SIZE: ${{ vars.SSCCACHE_SIZE }} + OPENVCS_UPDATE_CHANNEL: dev timeout-minutes: 20 steps: diff --git a/.gitignore b/.gitignore index f8dfbef6..5cc6ebed 100644 --- a/.gitignore +++ b/.gitignore @@ -29,3 +29,4 @@ dist-ssr .env.tauri.local .env .opencode/ +/openvcs.plugins.local.json diff --git a/Backend/scripts/ensure-built-in-plugins.js b/Backend/scripts/ensure-built-in-plugins.js index 16822542..58a88169 100644 --- a/Backend/scripts/ensure-built-in-plugins.js +++ b/Backend/scripts/ensure-built-in-plugins.js @@ -9,6 +9,7 @@ const scriptDir = __dirname; const backendDir = path.resolve(scriptDir, '..'); const clientDir = path.resolve(backendDir, '..'); const builtInConfigPath = path.join(clientDir, 'openvcs.plugins.json'); +const localConfigPath = path.join(clientDir, 'openvcs.plugins.local.json'); const builtInOutputDir = path.join(clientDir, 'target', 'openvcs', 'built-in-plugins'); const nodeRuntimeDir = path.join(clientDir, 'target', 'openvcs', 'node-runtime'); const npmExecutable = process.platform === 'win32' ? 'npm.cmd' : 'npm'; @@ -79,13 +80,78 @@ function ensureBundledNodeRuntime() { console.log(`Bundled node runtime -> ${dest}`); } +/** + * Determines the active update channel from environment variable. + * Supports stable/beta/dev and maps nightly->dev. + * Defaults to stable when unset. + */ +function getActiveChannel() { + const channel = (process.env.OPENVCS_UPDATE_CHANNEL || '').trim().toLowerCase(); + if (channel === 'nightly') { + return 'dev'; + } + if (channel === 'stable' || channel === 'beta' || channel === 'dev') { + return channel; + } + return 'stable'; +} + +/** + * Reads the built-in plugin config and extracts specs for the active channel. + * Falls back to stable if channel array is missing. + */ function readBuiltInConfig() { const raw = fs.readFileSync(builtInConfigPath, 'utf8'); const parsed = JSON.parse(raw); - const entries = Array.isArray(parsed?.plugin) ? parsed.plugin : []; + const channel = getActiveChannel(); + + // Try the channel-specific array first, fall back to stable + let entries = []; + if (Array.isArray(parsed?.[channel])) { + entries = parsed[channel]; + } else if (Array.isArray(parsed?.stable)) { + console.warn(`Channel '${channel}' not found in config, falling back to 'stable'`); + entries = parsed.stable; + } + return entries.map((value) => String(value || '').trim()).filter(Boolean); } +/** + * Reads local override config and returns the channel-specific override when present. + * Returns null when no override applies for the active channel. + */ +function readLocalOverrideConfig() { + if (!fs.existsSync(localConfigPath)) { + return null; + } + + const raw = fs.readFileSync(localConfigPath, 'utf8'); + const parsed = JSON.parse(raw); + const channel = getActiveChannel(); + + if (!Object.prototype.hasOwnProperty.call(parsed || {}, channel)) { + return null; + } + + const entries = Array.isArray(parsed?.[channel]) ? parsed[channel] : []; + return entries.map((value) => String(value || '').trim()).filter(Boolean); +} + +/** + * Determines which plugin specs to use: local override takes priority + * when present for the active channel, otherwise uses main config. + */ +function resolvePluginSpecs() { + const localSpecs = readLocalOverrideConfig(); + if (localSpecs !== null) { + const channel = getActiveChannel(); + console.log(`Using local override for channel '${channel}' (${localSpecs.length} plugins)`); + return localSpecs; + } + return readBuiltInConfig(); +} + function resolveLocalSource(spec) { if (!spec) return null; let candidate = spec; @@ -224,8 +290,9 @@ function rebuildBuiltInPlugins() { fs.rmSync(builtInOutputDir, { recursive: true, force: true }); ensureDirectory(builtInOutputDir); - const specs = readBuiltInConfig(); - console.log(`Syncing ${specs.length} built-in plugins from ${builtInConfigPath}`); + const specs = resolvePluginSpecs(); + const channel = getActiveChannel(); + console.log(`Syncing ${specs.length} built-in plugins for channel '${channel}' from ${builtInConfigPath}`); for (const spec of specs) { const { tempRoot, packageDir, pluginId } = stageBuiltInPlugin(spec); diff --git a/Backend/scripts/run-tauri-before-command.js b/Backend/scripts/run-tauri-before-command.js index 0aab8422..164bb774 100644 --- a/Backend/scripts/run-tauri-before-command.js +++ b/Backend/scripts/run-tauri-before-command.js @@ -25,8 +25,11 @@ if (dryRun) { process.exit(0); } -function run(cmd, args, cwd) { +function run(cmd, args, cwd, env) { const spawnOpts = { cwd, stdio: 'inherit' }; + if (env) { + spawnOpts.env = { ...process.env, ...env }; + } if ( process.platform === 'win32' && (cmd === 'npm' || cmd.toLowerCase().endsWith('.cmd') || cmd.toLowerCase().endsWith('.bat')) @@ -44,7 +47,10 @@ function run(cmd, args, cwd) { } } -run(process.execPath, [ensureScript], backendDir); +const ensureEnv = mode === 'dev' && !process.env.OPENVCS_UPDATE_CHANNEL + ? { OPENVCS_UPDATE_CHANNEL: 'dev' } + : null; +run(process.execPath, [ensureScript], backendDir, ensureEnv); if (mode === 'build' && process.env.FRONTEND_SKIP_BUILD === '1') { console.log('FRONTEND_SKIP_BUILD=1; skipping Frontend build step.'); diff --git a/README.md b/README.md index ff1e881c..510340ec 100644 --- a/README.md +++ b/README.md @@ -174,9 +174,10 @@ use the same channel-aware Tauri build flow. The Tauri precommands in `Backend/tauri.conf.json` intentionally set an explicit hook `cwd` to `Backend/` so Tauri does not resolve them from nested -plugin directories, and built-in plugins are materialized from -`openvcs.plugins.json` into `target/openvcs/built-in-plugins/` before the app is -built. +plugin directories, and built-in plugins are materialized from the +channel-aware `openvcs.plugins.json` into `target/openvcs/built-in-plugins/` +before the app is built. Local development can optionally override the active +channel list with `openvcs.plugins.local.json`. ### Optional: Rust‑only build diff --git a/docs/plugin architecture.md b/docs/plugin architecture.md index 9c25c528..d25d00a8 100644 --- a/docs/plugin architecture.md +++ b/docs/plugin architecture.md @@ -71,9 +71,31 @@ system `node` executable. Instead, OpenVCS resolves config-declared plugin sources into the writable local plugin store before discovery runs: -- Built-in source list: `Client/openvcs.plugins.json` +- Built-in source list: `Client/openvcs.plugins.json` (channel-first) - User source list: top-level `plugin = [...]` in `openvcs.conf` +The built-in config uses a channel-first schema: + +```json +{ + "stable": ["@openvcs/git-plugin@latest", "@openvcs/official-themes@latest"], + "beta": ["@openvcs/git-plugin@beta", "@openvcs/official-themes@beta"], + "dev": ["@openvcs/git-plugin@edge", "@openvcs/official-themes@nightly"] +} +``` + +The active channel is determined by `OPENVCS_UPDATE_CHANNEL`: +- `stable` - production releases +- `beta` - beta builds +- `dev` - development builds +- `nightly` - alias for `dev` +- unset/unknown values default to `stable` + +For local development, create `openvcs.plugins.local.json` in the Client directory +to override the channel list (gitignored). If the file defines the active +channel key, that list fully replaces the committed channel list, including an +empty array. + The resolver accepts: - npm package specifiers such as `@scope/name` or `name@version` @@ -84,7 +106,7 @@ contents and then installs runtime dependencies into the local plugin root when needed. Local path plugins therefore behave like npm packages and should define their published files and `prepack` behavior accordingly. -## Installed Plugin Layout +## Installed Layout After sync, the backend operates only on local installed plugin directories: diff --git a/docs/plugins.md b/docs/plugins.md index c64361b6..faf65c54 100644 --- a/docs/plugins.md +++ b/docs/plugins.md @@ -8,11 +8,46 @@ directory under the app config directory. ## Source Of Truth -OpenVCS reads two plugin source lists with the same entry shape: +OpenVCS reads two plugin source lists: -- Built-in plugins: `Client/openvcs.plugins.json` +- Built-in plugins: `Client/openvcs.plugins.json` (channel-first) - User plugins: the top-level `plugin = [...]` array in `openvcs.conf` +## Channel-Based Built-in Config + +Built-in plugins use a channel-first schema that maps release channels to plugin +specifier arrays: + +```json +{ + "stable": ["@openvcs/git-plugin@latest", "@openvcs/official-themes@latest"], + "beta": ["@openvcs/git-plugin@beta", "@openvcs/official-themes@beta"], + "dev": ["@openvcs/git-plugin@edge", "@openvcs/official-themes@nightly"] +} +``` + +The active channel is determined by the `OPENVCS_UPDATE_CHANNEL` environment +variable: + +- `stable` - production releases +- `beta` - beta builds +- `dev` - development builds +- `nightly` - alias for `dev` +- unset/unknown values default to `stable` + +### Local Override + +For local development, create `openvcs.plugins.local.json` in the Client directory +with the same shape to override the channel-specific plugin list. This is useful +for testing different plugin versions without modifying the main config. + +If the local file defines the active channel key, that channel list fully +replaces the committed list, including an empty array. + +The local override file is ignored by git (see `.gitignore`). + +## User Plugin Config + Example user config: ```toml diff --git a/openvcs.plugins.json b/openvcs.plugins.json index 9933becf..0408ba46 100644 --- a/openvcs.plugins.json +++ b/openvcs.plugins.json @@ -1,5 +1,13 @@ { - "plugin": [ + "stable": [ + "@openvcs/git-plugin@latest", + "@openvcs/official-themes@latest" + ], + "beta": [ + "@openvcs/git-plugin@beta", + "@openvcs/official-themes@beta" + ], + "dev": [ "@openvcs/git-plugin@edge", "@openvcs/official-themes@nightly" ] From 835079e353205a75cb9b776cad855150712a7d74 Mon Sep 17 00:00:00 2001 From: "opencode-agent[bot]" Date: Wed, 22 Apr 2026 19:26:38 +0000 Subject: [PATCH 32/37] Add monitoring, plugin updates Co-authored-by: Jordonbc --- Frontend/package-lock.json | 30 ------------------------------ 1 file changed, 30 deletions(-) diff --git a/Frontend/package-lock.json b/Frontend/package-lock.json index 719bf283..8823ee7d 100644 --- a/Frontend/package-lock.json +++ b/Frontend/package-lock.json @@ -717,9 +717,6 @@ "arm64" ], "dev": true, - "libc": [ - "glibc" - ], "license": "MIT", "optional": true, "os": [ @@ -737,9 +734,6 @@ "arm64" ], "dev": true, - "libc": [ - "musl" - ], "license": "MIT", "optional": true, "os": [ @@ -757,9 +751,6 @@ "ppc64" ], "dev": true, - "libc": [ - "glibc" - ], "license": "MIT", "optional": true, "os": [ @@ -777,9 +768,6 @@ "s390x" ], "dev": true, - "libc": [ - "glibc" - ], "license": "MIT", "optional": true, "os": [ @@ -797,9 +785,6 @@ "x64" ], "dev": true, - "libc": [ - "glibc" - ], "license": "MIT", "optional": true, "os": [ @@ -817,9 +802,6 @@ "x64" ], "dev": true, - "libc": [ - "musl" - ], "license": "MIT", "optional": true, "os": [ @@ -2178,9 +2160,6 @@ "arm64" ], "dev": true, - "libc": [ - "glibc" - ], "license": "MPL-2.0", "optional": true, "os": [ @@ -2202,9 +2181,6 @@ "arm64" ], "dev": true, - "libc": [ - "musl" - ], "license": "MPL-2.0", "optional": true, "os": [ @@ -2226,9 +2202,6 @@ "x64" ], "dev": true, - "libc": [ - "glibc" - ], "license": "MPL-2.0", "optional": true, "os": [ @@ -2250,9 +2223,6 @@ "x64" ], "dev": true, - "libc": [ - "musl" - ], "license": "MPL-2.0", "optional": true, "os": [ From 53aa42c36b82aecf7151bb7814176d8f8e0cc905 Mon Sep 17 00:00:00 2001 From: Jordon Date: Thu, 23 Apr 2026 02:00:33 +0100 Subject: [PATCH 33/37] Fixed commit issues --- Backend/src/plugin_runtime/node_instance.rs | 6 +++++ Backend/src/plugin_runtime/protocol.rs | 2 ++ Backend/src/plugin_runtime/vcs_proxy.rs | 10 +++++++++ Backend/src/tauri_commands/commit.rs | 25 ++++++++++++++++----- docs/plugin architecture.md | 4 ++++ 5 files changed, 42 insertions(+), 5 deletions(-) diff --git a/Backend/src/plugin_runtime/node_instance.rs b/Backend/src/plugin_runtime/node_instance.rs index a5dca86e..60aa8153 100644 --- a/Backend/src/plugin_runtime/node_instance.rs +++ b/Backend/src/plugin_runtime/node_instance.rs @@ -732,6 +732,12 @@ impl NodePluginRuntimeInstance { self.rpc_call_unit(Methods::VCS_STAGE_PATCH, params) } + /// Calls `vcs.stage-paths`. + pub fn vcs_stage_paths(&self, paths: &[String]) -> Result<(), String> { + let params = self.session_params(json!({ "paths": paths }))?; + self.rpc_call_unit(Methods::VCS_STAGE_PATHS, params) + } + /// Calls `vcs.discard-paths`. pub fn vcs_discard_paths(&self, paths: &[String]) -> Result<(), String> { let params = self.session_params(json!({ "paths": paths }))?; diff --git a/Backend/src/plugin_runtime/protocol.rs b/Backend/src/plugin_runtime/protocol.rs index 3762eb07..9f1ce869 100644 --- a/Backend/src/plugin_runtime/protocol.rs +++ b/Backend/src/plugin_runtime/protocol.rs @@ -94,6 +94,8 @@ impl Methods { pub const VCS_WRITE_MERGE_RESULT: &'static str = "vcs.write_merge_result"; /// Stages a text patch. pub const VCS_STAGE_PATCH: &'static str = "vcs.stage_patch"; + /// Stages explicit paths to the index. + pub const VCS_STAGE_PATHS: &'static str = "vcs.stage_paths"; /// Discards path changes. pub const VCS_DISCARD_PATHS: &'static str = "vcs.discard_paths"; /// Applies reverse patch. diff --git a/Backend/src/plugin_runtime/vcs_proxy.rs b/Backend/src/plugin_runtime/vcs_proxy.rs index bce620fc..b1750818 100644 --- a/Backend/src/plugin_runtime/vcs_proxy.rs +++ b/Backend/src/plugin_runtime/vcs_proxy.rs @@ -241,6 +241,16 @@ impl Vcs for PluginVcsProxy { .map_err(|e| self.map_runtime_error(e)) } + fn stage_paths(&self, paths: &[PathBuf]) -> VcsResult<()> { + let paths = paths + .iter() + .map(|p| p.to_string_lossy().to_string()) + .collect::>(); + self.runtime + .vcs_stage_paths(&paths) + .map_err(|e| self.map_runtime_error(e)) + } + fn discard_paths(&self, paths: &[PathBuf]) -> VcsResult<()> { let paths = paths .iter() diff --git a/Backend/src/tauri_commands/commit.rs b/Backend/src/tauri_commands/commit.rs index 466672dd..60021199 100644 --- a/Backend/src/tauri_commands/commit.rs +++ b/Backend/src/tauri_commands/commit.rs @@ -125,10 +125,6 @@ pub async fn commit_selected( async_runtime::spawn_blocking(move || { let on = progress_bridge(app); - on(VcsEvent::Info { - msg: "Staging selected files…".into(), - }); - let (name, email) = repo .inner() .get_identity() @@ -146,6 +142,16 @@ pub async fn commit_selected( let paths: Vec = files.into_iter().map(PathBuf::from).collect(); + on(VcsEvent::Info { + msg: "Staging selected files…".into(), + }); + repo.inner() + .stage_paths(&paths) + .map_err(|e| { + error!("stage_paths failed: {e}"); + e.to_string() + })?; + on(VcsEvent::Info { msg: "Writing commit…".into(), }); @@ -312,7 +318,16 @@ pub async fn commit_patch_and_files( .commit_index(&message, &name, &email) .map_err(|e| e.to_string())? } else { - let paths: Vec = files.into_iter().map(PathBuf::from).collect(); + let paths: Vec = files.iter().map(PathBuf::from).collect(); + on(VcsEvent::Info { + msg: "Staging selected files…".into(), + }); + repo.inner() + .stage_paths(&paths) + .map_err(|e| { + error!("stage_paths failed: {e}"); + e.to_string() + })?; repo.inner() .commit(&message, &name, &email, &paths) .map_err(|e| e.to_string())? diff --git a/docs/plugin architecture.md b/docs/plugin architecture.md index d25d00a8..1585b608 100644 --- a/docs/plugin architecture.md +++ b/docs/plugin architecture.md @@ -63,6 +63,10 @@ Core plugin-to-host notifications: - `host.event_emit` - `vcs.event` +Selected-file commit flows stage repository-relative paths into the index with +`vcs.stage_paths` before issuing `vcs.commit`. Plugins implementing selected-path +commits should therefore support both RPCs consistently. + Plugin runtime requires the app-bundled Node binary; there is no fallback to a system `node` executable. From 2ec18d0be547df54c7398b9e0d3fcaaac577efbf Mon Sep 17 00:00:00 2001 From: Jordon Date: Thu, 23 Apr 2026 02:01:13 +0100 Subject: [PATCH 34/37] Fix mod.rs file --- Backend/src/core/mod.rs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Backend/src/core/mod.rs b/Backend/src/core/mod.rs index ceab45f1..2dd70b3b 100644 --- a/Backend/src/core/mod.rs +++ b/Backend/src/core/mod.rs @@ -97,6 +97,8 @@ pub trait Vcs: Send + Sync { /// Stages changes represented by a textual patch. fn stage_patch(&self, patch: &str) -> Result<()>; + /// Stages explicit paths to the index. + fn stage_paths(&self, paths: &[PathBuf]) -> Result<()>; /// Discards changes for the provided repository-relative paths. fn discard_paths(&self, paths: &[PathBuf]) -> Result<()>; /// Applies a patch in reverse to revert its changes. From ead22ff66c1b0cc440aaf917d0736f1a1fd456e6 Mon Sep 17 00:00:00 2001 From: Jordon Date: Thu, 23 Apr 2026 02:25:40 +0100 Subject: [PATCH 35/37] Fixed issues --- Backend/src/lib.rs | 16 +++++++++++++++- Backend/src/tauri_commands/commit.rs | 20 ++++++++------------ Backend/src/validate.rs | 15 +++++++++++---- Frontend/src/scripts/main.ts | 16 ++++++++++++---- 4 files changed, 46 insertions(+), 21 deletions(-) diff --git a/Backend/src/lib.rs b/Backend/src/lib.rs index 3be8f73c..5dc52c7b 100644 --- a/Backend/src/lib.rs +++ b/Backend/src/lib.rs @@ -38,9 +38,23 @@ mod validate; mod workarounds; /// Loads `Client/.env` for local development without overwriting existing env vars. +/// +/// Missing .env file is silently ignored. Malformed or unreadable .env files +/// are reported with context for debugging before structured logging is ready. fn load_local_dotenv() { let dotenv_path = std::path::Path::new(env!("CARGO_MANIFEST_DIR")).join("../.env"); - let _ = dotenvy::from_path(&dotenv_path); + + match dotenvy::from_path(&dotenv_path) { + Ok(_) => {} + Err(dotenvy::Error::Io(error)) if error.kind() == std::io::ErrorKind::NotFound => {} + Err(err) => { + eprintln!( + "warning: failed to load local .env from {}: {}", + dotenv_path.display(), + err + ); + } + } } /// Selects preferred backend from settings or first available plugin backend. diff --git a/Backend/src/tauri_commands/commit.rs b/Backend/src/tauri_commands/commit.rs index 60021199..93624399 100644 --- a/Backend/src/tauri_commands/commit.rs +++ b/Backend/src/tauri_commands/commit.rs @@ -145,12 +145,10 @@ pub async fn commit_selected( on(VcsEvent::Info { msg: "Staging selected files…".into(), }); - repo.inner() - .stage_paths(&paths) - .map_err(|e| { - error!("stage_paths failed: {e}"); - e.to_string() - })?; + repo.inner().stage_paths(&paths).map_err(|e| { + error!("stage_paths failed: {e}"); + e.to_string() + })?; on(VcsEvent::Info { msg: "Writing commit…".into(), @@ -322,12 +320,10 @@ pub async fn commit_patch_and_files( on(VcsEvent::Info { msg: "Staging selected files…".into(), }); - repo.inner() - .stage_paths(&paths) - .map_err(|e| { - error!("stage_paths failed: {e}"); - e.to_string() - })?; + repo.inner().stage_paths(&paths).map_err(|e| { + error!("stage_paths failed: {e}"); + e.to_string() + })?; repo.inner() .commit(&message, &name, &email, &paths) .map_err(|e| e.to_string())? diff --git a/Backend/src/validate.rs b/Backend/src/validate.rs index 32863a20..e49e2938 100644 --- a/Backend/src/validate.rs +++ b/Backend/src/validate.rs @@ -1,6 +1,15 @@ // Copyright © 2025-2026 OpenVCS Contributors // SPDX-License-Identifier: GPL-3.0-or-later use std::path::Path; +use std::sync::LazyLock; + +/// Regex pattern for scp-like Git URLs. +static SCP_LIKE_RE: LazyLock = + LazyLock::new(|| regex::Regex::new(r"^[\w.-]+@[\w.-]+:[\w./-]+\.git$").unwrap()); + +/// Regex pattern for Windows absolute paths. +static WIN_ABS_RE: LazyLock = + LazyLock::new(|| regex::Regex::new(r"^[A-Za-z]:[\\/]").unwrap()); #[derive(serde::Serialize)] pub struct Validation { @@ -51,8 +60,7 @@ fn is_probably_git_url(u: &str) -> bool { return true; } // scp-like: git@host:org/repo.git - let scp_like = regex::Regex::new(r"^[\w.-]+@[\w.-]+:[\w./-]+\.git$").unwrap(); - if scp_like.is_match(u) { + if SCP_LIKE_RE.is_match(u) { return true; } false @@ -76,8 +84,7 @@ fn looks_like_path(s: &str) -> bool { return true; } // Windows drive letter absolute, e.g. C:\... - let win_abs = regex::Regex::new(r"^[A-Za-z]:[\\/]").unwrap(); - win_abs.is_match(s) + WIN_ABS_RE.is_match(s) } /// Validates whether a string looks like a supported Git URL. diff --git a/Frontend/src/scripts/main.ts b/Frontend/src/scripts/main.ts index 0c131475..bdeb796f 100644 --- a/Frontend/src/scripts/main.ts +++ b/Frontend/src/scripts/main.ts @@ -390,14 +390,22 @@ async function boot() { break; case '__plugin_menu_action__': { if (!TAURI.has) { notify('Plugin actions are available in the desktop app'); break; } - const pluginId = String(payload?.pluginId || '').trim(); - const actionId = String(payload?.actionId || '').trim(); - if (!pluginId || !actionId) break; + const pluginId = typeof payload?.pluginId === 'string' ? payload.pluginId.trim() : ''; + const actionId = typeof payload?.actionId === 'string' ? payload.actionId.trim() : ''; + if (!pluginId || !actionId) { + console.warn(`Plugin menu action skipped: missing pluginId (${!!pluginId}) or actionId (${!!actionId})`); + notify(!pluginId && !actionId + ? 'Plugin action is missing plugin and action IDs' + : !pluginId + ? 'Plugin action missing plugin ID' + : `Plugin action missing action for "${pluginId}"`); + break; + } try { await invokePluginAction(pluginId, actionId); } catch (e) { console.error(`Plugin menu action failed: ${pluginId}/${actionId}`, e); - notify('Plugin action failed'); + notify(`Plugin action for "${pluginId}" failed`); } break; } From 6bc1973ded44523e165d85c3678ded6f1f5dfa31 Mon Sep 17 00:00:00 2001 From: Jordon Date: Thu, 23 Apr 2026 02:33:28 +0100 Subject: [PATCH 36/37] Update opencode-review.yml --- .github/workflows/opencode-review.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/opencode-review.yml b/.github/workflows/opencode-review.yml index 9cbdf8dc..6fabd629 100644 --- a/.github/workflows/opencode-review.yml +++ b/.github/workflows/opencode-review.yml @@ -29,7 +29,7 @@ jobs: #GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} with: model: ${{ vars.OPENCODE_REVIEW_MODEL }} - #use_github_token: true + use_github_token: false prompt: | Review this pull request: - Check for code quality issues @@ -45,7 +45,7 @@ jobs: #GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} with: model: ${{ vars.OPENCODE_REVIEW_MODEL_FALLBACK }} - #use_github_token: true + use_github_token: false prompt: | Review this pull request: - Check for code quality issues From 7cb6a0a6ba0f437508733a287d42076e19c0355c Mon Sep 17 00:00:00 2001 From: Jordon Date: Thu, 23 Apr 2026 02:40:41 +0100 Subject: [PATCH 37/37] Version Bump --- Backend/Cargo.toml | 2 +- Cargo.lock | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Backend/Cargo.toml b/Backend/Cargo.toml index 2511f518..96c99654 100644 --- a/Backend/Cargo.toml +++ b/Backend/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "openvcs" -version = "0.2.2" +version = "0.3.0" description = "OpenVCS: a lightweight, highly customizable Git GUI built on Rust & Tauri" authors = ["Jordon Brooks"] homepage = "https://bbgames.dev" diff --git a/Cargo.lock b/Cargo.lock index 8a7643a6..d142a79c 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2939,7 +2939,7 @@ checksum = "7c87def4c32ab89d880effc9e097653c8da5d6ef28e6b539d313baaacfbafcbe" [[package]] name = "openvcs" -version = "0.2.2" +version = "0.3.0" dependencies = [ "base64 0.22.1", "directories",