From ad740986fea58f7da82636af370f141ed307d1d5 Mon Sep 17 00:00:00 2001 From: phantomptr Date: Fri, 26 Jun 2026 22:29:09 +0800 Subject: [PATCH 1/5] fix(install): keep a rejected patch staged so the DPI fallback can install it MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit On FW 11/12 the in-process InstallByPackage rejects a PS4 update with 0x80b21106 (an authid gate) — the EXPECTED first step before the client retries through the standalone DPI daemon, which lands patches the in-process path can't. But the engine's 2.2.55 register-reject staging cleanup deleted the staged .pkg the instant that first register was rejected, so the DPI fallback had nothing left to install (HW bug bundle, FW 12.70: register-reject staging cleaned fired right after 0x80b21106, register_path=none, update failed). Add the pure predicate preserve_staging_on_reject(package_type) (ends_with DP) and skip the auto-clean for a guarded patch, logging staging PRESERVED for DPI fallback. The client owns cleanup of its transient copy after the FULL cascade (USB path fs_deletes unconditionally; the queue keeps-for-retry on fail / deletes on success), so no leak. Base/DLC keep the existing idempotent cleanup. --- .../crates/ps5upload-core/src/pkg_install.rs | 33 +++++++++++++++++++ .../ps5upload-engine/src/pkg_install.rs | 30 ++++++++++++++++- 2 files changed, 62 insertions(+), 1 deletion(-) diff --git a/engine/crates/ps5upload-core/src/pkg_install.rs b/engine/crates/ps5upload-core/src/pkg_install.rs index 2c6b95f3..91301a4c 100644 --- a/engine/crates/ps5upload-core/src/pkg_install.rs +++ b/engine/crates/ps5upload-core/src/pkg_install.rs @@ -273,6 +273,22 @@ pub fn install_may_not_launch(register_path: &str) -> bool { register_path == "appinst-local" } +/// Whether to PRESERVE the staged .pkg after an in-process register-reject, +/// instead of auto-deleting it. +/// +/// A guarded patch ("…DP") that the in-process `InstallByPackage` rejects +/// (typically `0x80B21106`, the FW 11/12 authid gate) is the EXPECTED first +/// step: the client then retries the SAME staged file through the standalone +/// DPI daemon — a separate, properly-authid'd loader process that is HW-proven +/// to land patches the in-process path can't. Deleting the file on reject pulls +/// it out from under that fallback and the update can never apply (HW bug +/// bundle, FW 12.70). For every other type the auto-clean stands: it keeps a +/// failed register idempotent and stops a stale pkg polluting Sony's installer +/// queue. The client owns cleanup of its transient copy after the full cascade. +pub fn preserve_staging_on_reject(package_type: &str) -> bool { + package_type.ends_with("DP") +} + /// Whether `s` has the shape of a PS5 title_id: four uppercase letters /// (CUSA / PPSA / NPXS / …) followed by five digits, e.g. "CUSA12345". /// Mirrors `looks_like_title_id` in the payload's register.c so the two @@ -683,6 +699,23 @@ mod tests { assert!(!install_may_not_launch("")); } + #[test] + fn preserve_staging_on_reject_only_for_patches() { + // A patch (…DP) must KEEP its staged pkg on a register-reject so the + // client's DPI-daemon fallback can install the same file. Both PS4 and + // PS5 patch types end in "DP" (PS4DP / the PS5 patch category). + assert!(preserve_staging_on_reject("PS4DP")); + assert!(preserve_staging_on_reject("PS5DP")); + // Base games and DLC auto-clean as before (idempotent retry, no + // installer-queue pollution). A DLC ("…AC") carries its OWN content_id, + // so a stale staged copy is exactly the residue the cleanup prevents. + assert!(!preserve_staging_on_reject("PS4GD")); + assert!(!preserve_staging_on_reject("PS5GD")); + assert!(!preserve_staging_on_reject("PS4AC")); + assert!(!preserve_staging_on_reject("PS5AC")); + assert!(!preserve_staging_on_reject("")); + } + #[test] fn newly_added_err_codes_have_messages() { // Codes added in v2.16.1 after audit found we were leaving these diff --git a/engine/crates/ps5upload-engine/src/pkg_install.rs b/engine/crates/ps5upload-engine/src/pkg_install.rs index 3d80267a..b0dfb30a 100644 --- a/engine/crates/ps5upload-engine/src/pkg_install.rs +++ b/engine/crates/ps5upload-engine/src/pkg_install.rs @@ -665,12 +665,40 @@ async fn install_start_handler( // residue. Take() so we don't double-delete if status // somehow runs later. Spawn-blocking because fs_delete // does sync I/O over the mgmt socket. - let path_to_clean = { + // + // EXCEPTION — a guarded patch ("…DP"). The in-process + // InstallByPackage hitting 0x80B21106 is the EXPECTED first + // step for a PS4 update on FW 11/12: the client then retries + // through the standalone DPI daemon (a separate, properly- + // authid'd loader process — HW-proven to land patches the + // in-process path can't). That fallback installs the SAME + // staged pkg by its on-disk path, so deleting it here pulls + // the file out from under DPI and the update can never apply + // (HW bug bundle, FW 12.70: "register-reject staging cleaned" + // fired right after 0x80B21106, leaving DPI nothing to install). + // The client owns cleanup of its transient copy after the FULL + // cascade (the USB path fs_deletes it unconditionally; the + // queue keeps it for retry on failure / deletes on success), + // so skipping the auto-clean for a patch doesn't leak. + let is_guarded_patch = + ps5upload_core::pkg_install::preserve_staging_on_reject(&package_type); + let path_to_clean = if is_guarded_patch { + // Leave staging_path in the session ref untouched — the client's + // DPI fallback needs the file. Don't auto-delete. + None + } else { let mut sessions = state.sessions.lock().unwrap_or_else(|e| e.into_inner()); sessions .get_mut(&session_id) .and_then(|s| s.staging_path.take()) }; + if is_guarded_patch { + crate::log_info!( + "register-reject staging PRESERVED for DPI fallback: session={} package_type={}", + session_id, + package_type, + ); + } if let Some(path) = path_to_clean { let addr = req.ps5_addr.clone(); let sid = session_id.clone(); From ea5b2bae217df22b7ea1bbbe9b42871d7b39c228 Mon Sep 17 00:00:00 2001 From: phantomptr Date: Fri, 26 Jun 2026 22:29:21 +0800 Subject: [PATCH 2/5] fix(installed): Close game now works when Sony's app-kill is rejected (FW 12.20) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit handleStop did `ack = appKill(...)` then `if (!ack.ok) processKill(...)`, but appKill never resolves ok=false — the engine bails when the payload returns ok=false, so the invoke promise REJECTS. On FW 12.20 sceApplicationKill rejects the app id, appKill throws, and we jumped straight to the outer catch — the SIGKILL fallback (which runs with the payload's elevated ucred and does work) never ran, so the button "did nothing". Wrap each kill in its own try/catch so a throw falls THROUGH to the pid SIGKILL instead of aborting. Detection is fine (the badge+button appear, so app_id is valid) — only the kill API fails on 12.20. --- client/src/screens/InstalledApps/index.tsx | 39 ++++++++++++++++++---- 1 file changed, 33 insertions(+), 6 deletions(-) diff --git a/client/src/screens/InstalledApps/index.tsx b/client/src/screens/InstalledApps/index.tsx index 1fe6f540..f815ea1c 100644 --- a/client/src/screens/InstalledApps/index.tsx +++ b/client/src/screens/InstalledApps/index.tsx @@ -51,6 +51,7 @@ import { pushNotification } from "../../state/notifications"; import { withConsolePrefix } from "../../state/roster"; import { useTr } from "../../state/lang"; import { transferAddr, mgmtAddr, hostOf } from "../../lib/addr"; +import { transferScreenBusy } from "../../lib/ps5Transfers"; import { useStaleHostGuard } from "../../lib/staleHostGuard"; // ── Classification helpers ─────────────────────────────────────────────────── @@ -483,6 +484,14 @@ export default function InstalledAppsScreen() { let cancelled = false; const addr = mgmtAddr(host); const tick = async () => { + // Don't add mgmt-port load while an upload to THIS console is running. + // A folder reconcile (e.g. a many-chunk exfat.ffpfsc game) fires a + // per-file connection burst at the payload's mgmt port; injecting a + // process-list poll every 3s onto that contends with each file's + // finalize round-trip and can collapse effective throughput on a + // many-file upload (a single .pkg is one finalize, so it's immune). + // The running-game badge can wait until the upload finishes. + if (transferScreenBusy(host)) return; try { const r = await fetchRunningGames(addr); if (!cancelled) setRunning(r); @@ -587,14 +596,32 @@ export default function InstalledAppsScreen() { if (!ok || probe.isStale()) return; setStoppingId(t.titleId); try { - // Prefer Sony's clean app-kill (by app id); fall back to SIGKILL of a - // pid for the title when no app id was reported. + // Prefer Sony's clean app-kill (by app id); fall back to a SIGKILL of + // the title's pid. CRUCIAL: appKill can *throw* (the engine bails when + // the payload returns ok=false — observed on FW 12.20, where + // sceApplicationKill rejects the app id), so the fallback must run on a + // throw too, not only on a resolved ok=false. Treating both the same + // way is what makes the SIGKILL path actually reachable — previously a + // 12.20 appKill threw straight to the outer catch and the pid fallback + // (which runs with the payload's elevated ucred) never fired, so the + // Close button "did nothing". const addr = mgmtAddr(probe.host); - let ack = game.appId ? await appKill(addr, game.appId) : { ok: false }; - if (!ack.ok && game.pid) { - const k = await processKill(addr, game.pid); - ack = { ok: k.ok }; + let killed = false; + if (game.appId) { + try { + killed = (await appKill(addr, game.appId)).ok; + } catch { + /* Sony's app-kill failed/threw — fall through to SIGKILL. */ + } + } + if (!killed && game.pid) { + try { + killed = (await processKill(addr, game.pid)).ok; + } catch { + /* SIGKILL also failed — reported as "couldn't close" below. */ + } } + const ack = { ok: killed }; if (probe.isStale()) return; if (ack.ok) { // Drop it from the running set immediately so the card flips back to From 3fe35e222f06ef440ec3b596233c34f3a10b03fc Mon Sep 17 00:00:00 2001 From: phantomptr Date: Fri, 26 Jun 2026 22:29:32 +0800 Subject: [PATCH 3/5] perf(upload): pause running-game pollers while an upload to that console runs MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit InstalledApps (every 3s) and Library's RunningAppsPanel (every 5s) poll the PS5 mgmt port for what's running. A folder reconcile (a many-chunk exfat.ffpfsc dump) already bursts that same mgmt port with per-file finalize round-trips; the extra poll contends and can collapse a many-file upload's effective throughput (a single .pkg is one finalize, so it's immune) — the likeliest cause of the reported 120→10 MB/s exfat regression. Both pollers now skip a tick when transferScreenBusy(host) and resume the moment the upload ends. Safe regardless of whether it's THE cause; needs a HW repro (slow upload with only the Upload screen open) to confirm. --- client/src/screens/Library/RunningAppsPanel.tsx | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/client/src/screens/Library/RunningAppsPanel.tsx b/client/src/screens/Library/RunningAppsPanel.tsx index 92adfeb4..f61578d3 100644 --- a/client/src/screens/Library/RunningAppsPanel.tsx +++ b/client/src/screens/Library/RunningAppsPanel.tsx @@ -25,6 +25,7 @@ import { pushNotification } from "../../state/notifications"; import { withConsolePrefix } from "../../state/roster"; import { useRunningAppsStore } from "../../state/runningApps"; import { useDocumentVisible } from "../../lib/visibility"; +import { transferScreenBusy } from "../../lib/ps5Transfers"; interface RunningJoined { app_id: number; @@ -146,9 +147,16 @@ export default function RunningAppsPanel({ mgmtAddr }: { mgmtAddr: string }) { useEffect(() => { if (!visible) return; refresh(); - const id = window.setInterval(refresh, 5000); + const id = window.setInterval(() => { + // Skip the auto-poll while an upload to this console is running: the 5s + // appListRunning + appdb query hit the same mgmt port a folder reconcile + // is bursting per-file finalize calls on, and the contention can collapse + // a many-file upload's throughput. Resumes the moment the upload ends. + if (transferScreenBusy(mgmtAddr)) return; + refresh(); + }, 5000); return () => window.clearInterval(id); - }, [refresh, visible]); + }, [refresh, visible, mgmtAddr]); async function doAction( appId: number, From 082446f8d0ba07f79fe533600935805fada971e1 Mon Sep 17 00:00:00 2001 From: phantomptr Date: Fri, 26 Jun 2026 22:29:46 +0800 Subject: [PATCH 4/5] chore(deps): bump frontend, tauri-shell, tower-http and actions groups MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Folds in the four open dependabot PRs (#146–#149), reapplied on current main so the lockfiles regenerate cleanly: - engine: tower-http 0.6 -> 0.7 (cors feature; CorsLayer unchanged, builds clean) - desktop: tauri 2.11.3 / tauri-build 2.6.3 / tauri-utils 2.9.3 / tray-icon 0.24.1 - client: @tauri-apps/api 2.11.1, lucide-react 1.21.0, react-router-dom 7.18.0, @vitest/coverage-v8 4.1.9, typescript-eslint 8.61.1 - CI: actions/checkout v7, docker/setup-buildx v4, build-push v7, login v4, metadata v6 Verified: engine clippy+tests, desktop cargo check, client typecheck/lint/743 tests/vite build, i18n gate — all green. --- .github/workflows/docker-engine.yml | 22 +- .github/workflows/engine-ci.yml | 18 +- .github/workflows/publish.yml | 8 +- client/package-lock.json | 268 +++++++++++----------- client/package.json | 12 +- client/src-tauri/Cargo.lock | 63 +++-- client/src-tauri/Cargo.toml | 2 +- engine/Cargo.lock | 19 +- engine/Cargo.toml | 2 +- engine/crates/ps5upload-engine/Cargo.toml | 2 +- 10 files changed, 216 insertions(+), 200 deletions(-) diff --git a/.github/workflows/docker-engine.yml b/.github/workflows/docker-engine.yml index c38c6c12..67342e2a 100644 --- a/.github/workflows/docker-engine.yml +++ b/.github/workflows/docker-engine.yml @@ -33,11 +33,11 @@ jobs: if: github.event_name == 'pull_request' runs-on: ubuntu-24.04 steps: - - uses: actions/checkout@v6 + - uses: actions/checkout@v7 - - uses: docker/setup-buildx-action@v3 + - uses: docker/setup-buildx-action@v4 - - uses: docker/build-push-action@v6 + - uses: docker/build-push-action@v7 with: context: engine file: engine/Dockerfile @@ -97,7 +97,7 @@ jobs: env: IMAGE: ${{ needs.resolve.outputs.image }} steps: - - uses: actions/checkout@v6 + - uses: actions/checkout@v7 with: ref: ${{ needs.resolve.outputs.tag }} @@ -106,22 +106,22 @@ jobs: PLATFORM: ${{ matrix.platform }} run: echo "PLATFORM_PAIR=$(printf '%s' "$PLATFORM" | tr '/' '-')" >> "$GITHUB_ENV" - - uses: docker/setup-buildx-action@v3 + - uses: docker/setup-buildx-action@v4 - - uses: docker/login-action@v3 + - uses: docker/login-action@v4 with: registry: ghcr.io username: ${{ github.actor }} password: ${{ secrets.GITHUB_TOKEN }} - - uses: docker/metadata-action@v5 + - uses: docker/metadata-action@v6 id: meta with: images: ${{ env.IMAGE }} - name: Build and push by digest id: push - uses: docker/build-push-action@v6 + uses: docker/build-push-action@v7 with: context: engine file: engine/Dockerfile @@ -164,15 +164,15 @@ jobs: pattern: digests-* merge-multiple: true - - uses: docker/setup-buildx-action@v3 + - uses: docker/setup-buildx-action@v4 - - uses: docker/login-action@v3 + - uses: docker/login-action@v4 with: registry: ghcr.io username: ${{ github.actor }} password: ${{ secrets.GITHUB_TOKEN }} - - uses: docker/metadata-action@v5 + - uses: docker/metadata-action@v6 id: meta with: images: ${{ env.IMAGE }} diff --git a/.github/workflows/engine-ci.yml b/.github/workflows/engine-ci.yml index 213ac2c1..91b1ff4c 100644 --- a/.github/workflows/engine-ci.yml +++ b/.github/workflows/engine-ci.yml @@ -42,7 +42,7 @@ jobs: name: version sync (VERSION is canonical) runs-on: ubuntu-24.04 steps: - - uses: actions/checkout@v6 + - uses: actions/checkout@v7 - uses: actions/setup-node@v6 with: node-version: 22 @@ -57,7 +57,7 @@ jobs: name: rust (engine workspace) runs-on: ubuntu-24.04 steps: - - uses: actions/checkout@v6 + - uses: actions/checkout@v7 - name: Install Rust stable uses: dtolnay/rust-toolchain@stable @@ -119,7 +119,7 @@ jobs: target: aarch64-pc-windows-msvc runs-on: ${{ matrix.os }} steps: - - uses: actions/checkout@v6 + - uses: actions/checkout@v7 - name: Install Rust stable uses: dtolnay/rust-toolchain@stable @@ -147,7 +147,7 @@ jobs: os: [ubuntu-24.04, macos-14, windows-2022] runs-on: ${{ matrix.os }} steps: - - uses: actions/checkout@v6 + - uses: actions/checkout@v7 - name: Install Rust stable uses: dtolnay/rust-toolchain@stable @@ -227,7 +227,7 @@ jobs: name: client (ts + vite) runs-on: ubuntu-24.04 steps: - - uses: actions/checkout@v6 + - uses: actions/checkout@v7 - uses: actions/setup-node@v6 with: @@ -274,7 +274,7 @@ jobs: os: [ubuntu-24.04, macos-14, windows-2022] runs-on: ${{ matrix.os }} steps: - - uses: actions/checkout@v6 + - uses: actions/checkout@v7 - uses: actions/setup-node@v6 with: node-version: 22 @@ -306,7 +306,7 @@ jobs: # inspection, not enforcement. continue-on-error: true steps: - - uses: actions/checkout@v6 + - uses: actions/checkout@v7 - uses: actions/setup-node@v6 with: @@ -346,7 +346,7 @@ jobs: name: payload (ELF) runs-on: ubuntu-24.04 steps: - - uses: actions/checkout@v6 + - uses: actions/checkout@v7 - name: Install payload toolchain run: | @@ -400,7 +400,7 @@ jobs: name: android (apk build) runs-on: ubuntu-24.04 steps: - - uses: actions/checkout@v6 + - uses: actions/checkout@v7 - uses: actions/setup-node@v6 with: diff --git a/.github/workflows/publish.yml b/.github/workflows/publish.yml index 4537be3f..fd0166e2 100644 --- a/.github/workflows/publish.yml +++ b/.github/workflows/publish.yml @@ -59,7 +59,7 @@ jobs: name: build-payload runs-on: ubuntu-24.04 steps: - - uses: actions/checkout@v6 + - uses: actions/checkout@v7 with: ref: ${{ github.event.inputs.tag || github.ref_name }} @@ -142,7 +142,7 @@ jobs: rust_target: aarch64-pc-windows-msvc steps: - - uses: actions/checkout@v6 + - uses: actions/checkout@v7 with: ref: ${{ github.event.inputs.tag || github.ref_name }} @@ -411,7 +411,7 @@ jobs: # release", not a failed release. continue-on-error: true steps: - - uses: actions/checkout@v6 + - uses: actions/checkout@v7 with: ref: ${{ github.event.inputs.tag || github.ref_name }} @@ -507,7 +507,7 @@ jobs: - build-android runs-on: ubuntu-24.04 steps: - - uses: actions/checkout@v6 + - uses: actions/checkout@v7 with: ref: ${{ github.event.inputs.tag || github.ref_name }} diff --git a/client/package-lock.json b/client/package-lock.json index 9973b481..a589a5be 100644 --- a/client/package-lock.json +++ b/client/package-lock.json @@ -1,14 +1,14 @@ { "name": "ps5upload-client", - "version": "3.3.22", + "version": "3.3.23", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "ps5upload-client", - "version": "3.3.22", + "version": "3.3.23", "dependencies": { - "@tauri-apps/api": "^2.11.0", + "@tauri-apps/api": "^2.11.1", "@tauri-apps/plugin-dialog": "^2.7.1", "@tauri-apps/plugin-fs": "^2.5.1", "@tauri-apps/plugin-notification": "^2.3.1", @@ -16,10 +16,10 @@ "@tauri-apps/plugin-shell": "^2.3.5", "clsx": "^2.1.1", "html-to-image": "^1.11.13", - "lucide-react": "^1.18.0", + "lucide-react": "^1.21.0", "react": "^19.2.7", "react-dom": "^19.2.7", - "react-router-dom": "^7.17.0", + "react-router-dom": "^7.18.0", "zustand": "^5.0.14" }, "devDependencies": { @@ -29,12 +29,12 @@ "@types/react": "^19.2.17", "@types/react-dom": "^19.2.3", "@vitejs/plugin-react": "^6.0.2", - "@vitest/coverage-v8": "^4.1.8", + "@vitest/coverage-v8": "^4.1.9", "eslint": "^10.5.0", "eslint-plugin-react-hooks": "^7.1.1", "tailwindcss": "^4.0.0", "typescript": "^6.0.3", - "typescript-eslint": "^8.61.0", + "typescript-eslint": "^8.61.1", "vite": "^8.0.16", "vitest": "^4.1.4" } @@ -1206,9 +1206,9 @@ } }, "node_modules/@tauri-apps/api": { - "version": "2.11.0", - "resolved": "https://registry.npmjs.org/@tauri-apps/api/-/api-2.11.0.tgz", - "integrity": "sha512-7CinYODhky9lmO23xHnUFv0Xt43fbtWMyxZcLcRBlFkcgXKuEirBvHpmtJ89YMhyeGcq20Wuc47Fa4XjyniywA==", + "version": "2.11.1", + "resolved": "https://registry.npmjs.org/@tauri-apps/api/-/api-2.11.1.tgz", + "integrity": "sha512-M2FPuYND2m+wh5hfW9ZpSdxMPdEJovPBWwoHJmwUpysTYNHaOkVFN419m/K0LIgjb/7KU2vBgsUepJWugQCvAA==", "license": "Apache-2.0 OR MIT", "funding": { "type": "opencollective", @@ -1548,17 +1548,17 @@ } }, "node_modules/@typescript-eslint/eslint-plugin": { - "version": "8.61.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-8.61.0.tgz", - "integrity": "sha512-bFNvl9ZczlVb+wR2Akszf3gHfKVj/8WanXaGJ3UstTA7brNKg0cNdk6X1Psu5V7MZ2oQtzZKOEzIUehaoxbDGw==", + "version": "8.62.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-8.62.0.tgz", + "integrity": "sha512-o+mpz7EYiMzXoySXiKmzlabIvTVqUuK5yLrAedRPRDA0IpPFMUV1IXt6OqljIxX/kumN6EjUYp41Hqelh6p/Dw==", "dev": true, "license": "MIT", "dependencies": { "@eslint-community/regexpp": "^4.12.2", - "@typescript-eslint/scope-manager": "8.61.0", - "@typescript-eslint/type-utils": "8.61.0", - "@typescript-eslint/utils": "8.61.0", - "@typescript-eslint/visitor-keys": "8.61.0", + "@typescript-eslint/scope-manager": "8.62.0", + "@typescript-eslint/type-utils": "8.62.0", + "@typescript-eslint/utils": "8.62.0", + "@typescript-eslint/visitor-keys": "8.62.0", "ignore": "^7.0.5", "natural-compare": "^1.4.0", "ts-api-utils": "^2.5.0" @@ -1571,7 +1571,7 @@ "url": "https://opencollective.com/typescript-eslint" }, "peerDependencies": { - "@typescript-eslint/parser": "^8.61.0", + "@typescript-eslint/parser": "^8.62.0", "eslint": "^8.57.0 || ^9.0.0 || ^10.0.0", "typescript": ">=4.8.4 <6.1.0" } @@ -1587,16 +1587,16 @@ } }, "node_modules/@typescript-eslint/parser": { - "version": "8.61.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-8.61.0.tgz", - "integrity": "sha512-5B7PfA2e1NQGCnDHd/0lW7W3gvp3d59Ryw54FYO8Uswxo9f6ikw3AZV+Xj/TvpImmpsiYyUqAfhC6kJID1jF6w==", + "version": "8.62.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-8.62.0.tgz", + "integrity": "sha512-dzHeT2gySzZtLDsuqxU9AkYgIsQoHAHtRBpOqM+Ofzx1Bwrd2RcCjQJ+6iQbsHOIR6NS33bF2W1k3blN1zLDrA==", "dev": true, "license": "MIT", "dependencies": { - "@typescript-eslint/scope-manager": "8.61.0", - "@typescript-eslint/types": "8.61.0", - "@typescript-eslint/typescript-estree": "8.61.0", - "@typescript-eslint/visitor-keys": "8.61.0", + "@typescript-eslint/scope-manager": "8.62.0", + "@typescript-eslint/types": "8.62.0", + "@typescript-eslint/typescript-estree": "8.62.0", + "@typescript-eslint/visitor-keys": "8.62.0", "debug": "^4.4.3" }, "engines": { @@ -1612,14 +1612,14 @@ } }, "node_modules/@typescript-eslint/project-service": { - "version": "8.61.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/project-service/-/project-service-8.61.0.tgz", - "integrity": "sha512-DV42F7MLJO6Rax7SK1yg43tcnEfGUrurSpSxKuVX+a3RCTzBlH3fuxprrOJXKCJGAaw82xXocikJ0uQaqwXgGA==", + "version": "8.62.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/project-service/-/project-service-8.62.0.tgz", + "integrity": "sha512-wexnCqiTg7BOGtbLDftYpRWlmLq4xfoMd7BKFR6Y75sZS3QmRKLdN3yWLhmIYgqMmP/OXWpj3H8odkb5nGURCQ==", "dev": true, "license": "MIT", "dependencies": { - "@typescript-eslint/tsconfig-utils": "^8.61.0", - "@typescript-eslint/types": "^8.61.0", + "@typescript-eslint/tsconfig-utils": "^8.62.0", + "@typescript-eslint/types": "^8.62.0", "debug": "^4.4.3" }, "engines": { @@ -1634,14 +1634,14 @@ } }, "node_modules/@typescript-eslint/scope-manager": { - "version": "8.61.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-8.61.0.tgz", - "integrity": "sha512-IWdXFHFSb6mlC3HPc7QsLDm5zYEbUla6trDEHf32D3/dnuUyXd87plScSNXSbm0/RxMvObpI17sv/EDTGrGZkA==", + "version": "8.62.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-8.62.0.tgz", + "integrity": "sha512-1lX38kNxXIRb8mEc3lbq5mdHq1Pf2+U0nFU65KfT18mtPxxl0fvjuEE92mHuXPuCtElJhOrddOpyMlM3Z0umEA==", "dev": true, "license": "MIT", "dependencies": { - "@typescript-eslint/types": "8.61.0", - "@typescript-eslint/visitor-keys": "8.61.0" + "@typescript-eslint/types": "8.62.0", + "@typescript-eslint/visitor-keys": "8.62.0" }, "engines": { "node": "^18.18.0 || ^20.9.0 || >=21.1.0" @@ -1652,9 +1652,9 @@ } }, "node_modules/@typescript-eslint/tsconfig-utils": { - "version": "8.61.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/tsconfig-utils/-/tsconfig-utils-8.61.0.tgz", - "integrity": "sha512-O5Amvdv9ztMpxpf+vmFULGG78IE6Qwdr3bCGvqwG4nwc9H2qXkOYJJnRbRHyMkQTjv1d03olqwwwzHLMqpFePQ==", + "version": "8.62.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/tsconfig-utils/-/tsconfig-utils-8.62.0.tgz", + "integrity": "sha512-y2GAdB6ykaXUvuspbYnizQc4oDDz0Tz/Yc7iWrXf9mx8vm/L/0vLHCe0tS2boG96Zy+DivnVDQ9ZUEWoHqqx1g==", "dev": true, "license": "MIT", "engines": { @@ -1669,15 +1669,15 @@ } }, "node_modules/@typescript-eslint/type-utils": { - "version": "8.61.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-8.61.0.tgz", - "integrity": "sha512-TuBiQYIkd97yBfInHCTKVYMbX4kvEmpOEuixIuzCU9p8BGT1SfyyO0d0IfDMbPIHcjn/hWnusUX5e8v5Xg+X8A==", + "version": "8.62.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-8.62.0.tgz", + "integrity": "sha512-+g5O3j0w2ldzC86Pv6fvbO/xhAonbJFIdf/MKQ1d30gndlsVzUOE83ldfSE15Qrl9fhFjK6AovHs5Wpp6vx86w==", "dev": true, "license": "MIT", "dependencies": { - "@typescript-eslint/types": "8.61.0", - "@typescript-eslint/typescript-estree": "8.61.0", - "@typescript-eslint/utils": "8.61.0", + "@typescript-eslint/types": "8.62.0", + "@typescript-eslint/typescript-estree": "8.62.0", + "@typescript-eslint/utils": "8.62.0", "debug": "^4.4.3", "ts-api-utils": "^2.5.0" }, @@ -1694,9 +1694,9 @@ } }, "node_modules/@typescript-eslint/types": { - "version": "8.61.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-8.61.0.tgz", - "integrity": "sha512-9QTQpZ5Iin4CdIodfbDQFSeiSJKidgYJYug1P9CC2xWgUTvlmixViqDZNciMjwLBZyJnG4tGmPl97rVAFb1AJg==", + "version": "8.62.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-8.62.0.tgz", + "integrity": "sha512-KvAclkktORPvM54TgLgA4z9HIV1M8zOgw9ZVNXl9f/8dLYfXYX1wkMXP7qmabpijQRV5bHJLOmoyGQbLMaUYeg==", "dev": true, "license": "MIT", "engines": { @@ -1708,16 +1708,16 @@ } }, "node_modules/@typescript-eslint/typescript-estree": { - "version": "8.61.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-8.61.0.tgz", - "integrity": "sha512-42zatd5qSvvcV1JdDBCLxYRznvP4eIHpPoZXdkPFnAmanA4FuZ5dibSnCBggY8hQnqajPpoGjXFdZ7fIJKQnlA==", + "version": "8.62.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-8.62.0.tgz", + "integrity": "sha512-+hVbNxtW64pIcZWDPGbyaKF7vp2IBTVY5ma1blwwksrjdsbdqqEKvJWMGbBofei4F6Dovx1M0RJgoFeNu2279A==", "dev": true, "license": "MIT", "dependencies": { - "@typescript-eslint/project-service": "8.61.0", - "@typescript-eslint/tsconfig-utils": "8.61.0", - "@typescript-eslint/types": "8.61.0", - "@typescript-eslint/visitor-keys": "8.61.0", + "@typescript-eslint/project-service": "8.62.0", + "@typescript-eslint/tsconfig-utils": "8.62.0", + "@typescript-eslint/types": "8.62.0", + "@typescript-eslint/visitor-keys": "8.62.0", "debug": "^4.4.3", "minimatch": "^10.2.2", "semver": "^7.7.3", @@ -1736,9 +1736,9 @@ } }, "node_modules/@typescript-eslint/typescript-estree/node_modules/semver": { - "version": "7.8.4", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.8.4.tgz", - "integrity": "sha512-rUCObTnP32Q08R2uuIrt7r9PlEonuTmtuXYcW6s5kjdlj3xbnwe+21yXptAUYcMAABLkYYTtnmzb3w3EDZfueA==", + "version": "7.8.5", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.8.5.tgz", + "integrity": "sha512-Y7/KDsb8LjooZpwaqGyulO6DQlksgCncchHGk+sZIY4SBvUocMBEFH5Ur1fI4dV+Jvl0w6cjvucaIi40puRioA==", "dev": true, "license": "ISC", "bin": { @@ -1749,16 +1749,16 @@ } }, "node_modules/@typescript-eslint/utils": { - "version": "8.61.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-8.61.0.tgz", - "integrity": "sha512-3bzFt7ImFMW/jVYwJamDoe/dMOdFLSC6pom6rRjdh4SZJEYupyMzem8e7vKZLclLfpHjlwSAXOUxtKxGXUiLqA==", + "version": "8.62.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-8.62.0.tgz", + "integrity": "sha512-82r66fi9zYwZ+mTq3vKgwjbZ1PVk/DJzrXFLpG6RnBbdvH8TEGVHIs9H4d2drhkOzf0syZuD/OZvvlu6GDbP4g==", "dev": true, "license": "MIT", "dependencies": { "@eslint-community/eslint-utils": "^4.9.1", - "@typescript-eslint/scope-manager": "8.61.0", - "@typescript-eslint/types": "8.61.0", - "@typescript-eslint/typescript-estree": "8.61.0" + "@typescript-eslint/scope-manager": "8.62.0", + "@typescript-eslint/types": "8.62.0", + "@typescript-eslint/typescript-estree": "8.62.0" }, "engines": { "node": "^18.18.0 || ^20.9.0 || >=21.1.0" @@ -1773,13 +1773,13 @@ } }, "node_modules/@typescript-eslint/visitor-keys": { - "version": "8.61.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-8.61.0.tgz", - "integrity": "sha512-QVLZu3ZPQEE+HICQyAMZ2yLQhxf0meY/wx6Hx14YcTNj13JB3qHlX3lJ02L3fLGHgERRH71kvYDwiXIguT3AjQ==", + "version": "8.62.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-8.62.0.tgz", + "integrity": "sha512-CY3uyFSRbcQv3nnSv8S0+lDftMVz6P963PoRlxrV7ew/Md564g9ut60PYzdLM5qW4jFn93GBF+Soi90ISAN+GQ==", "dev": true, "license": "MIT", "dependencies": { - "@typescript-eslint/types": "8.61.0", + "@typescript-eslint/types": "8.62.0", "eslint-visitor-keys": "^5.0.0" }, "engines": { @@ -1817,14 +1817,14 @@ } }, "node_modules/@vitest/coverage-v8": { - "version": "4.1.8", - "resolved": "https://registry.npmjs.org/@vitest/coverage-v8/-/coverage-v8-4.1.8.tgz", - "integrity": "sha512-lt3kovsyHwYe00wq4D1ti0Z974fWj4NLp6siqiyEufUpyFwK9Yhi7rBhac9JL5aA0zoMrJqc4vYPZRUnI7l7nw==", + "version": "4.1.9", + "resolved": "https://registry.npmjs.org/@vitest/coverage-v8/-/coverage-v8-4.1.9.tgz", + "integrity": "sha512-G9/lgqibheLVBDRuya45EbsEXTYcWoSG+TLg7i2axuzx0Eq62eXn+aWXyaVdV5vKvFSWd6ywcX8hA7la9Pvu8g==", "dev": true, "license": "MIT", "dependencies": { "@bcoe/v8-coverage": "^1.0.2", - "@vitest/utils": "4.1.8", + "@vitest/utils": "4.1.9", "ast-v8-to-istanbul": "^1.0.0", "istanbul-lib-coverage": "^3.2.2", "istanbul-lib-report": "^3.0.1", @@ -1838,8 +1838,8 @@ "url": "https://opencollective.com/vitest" }, "peerDependencies": { - "@vitest/browser": "4.1.8", - "vitest": "4.1.8" + "@vitest/browser": "4.1.9", + "vitest": "4.1.9" }, "peerDependenciesMeta": { "@vitest/browser": { @@ -1848,16 +1848,16 @@ } }, "node_modules/@vitest/expect": { - "version": "4.1.8", - "resolved": "https://registry.npmjs.org/@vitest/expect/-/expect-4.1.8.tgz", - "integrity": "sha512-h3nDO677RDLEGlBxyQ5CW8RlMThSKSRLUePLOx09gNIWRL40edgA1GCZSZgf1W55MFAG6/Sw14KeaAnqv0NKdQ==", + "version": "4.1.9", + "resolved": "https://registry.npmjs.org/@vitest/expect/-/expect-4.1.9.tgz", + "integrity": "sha512-vl/rYsUKcBr3SnQn166+XR5ZQcgMx3DQhFWdfli/cWpLnLUmbxZvyrJZotLFUryib+LtArYMSTJ5RbQ57ZqrlA==", "dev": true, "license": "MIT", "dependencies": { "@standard-schema/spec": "^1.1.0", "@types/chai": "^5.2.2", - "@vitest/spy": "4.1.8", - "@vitest/utils": "4.1.8", + "@vitest/spy": "4.1.9", + "@vitest/utils": "4.1.9", "chai": "^6.2.2", "tinyrainbow": "^3.1.0" }, @@ -1866,13 +1866,13 @@ } }, "node_modules/@vitest/mocker": { - "version": "4.1.8", - "resolved": "https://registry.npmjs.org/@vitest/mocker/-/mocker-4.1.8.tgz", - "integrity": "sha512-LEiN/xe4OSIbKe9HQIp5OC24agGD9J5CnmMgsLohVVoOPWL9a2sBoR6VBx43jQZb7Kr1l4RCuyCJzcAa0+dojw==", + "version": "4.1.9", + "resolved": "https://registry.npmjs.org/@vitest/mocker/-/mocker-4.1.9.tgz", + "integrity": "sha512-EVkXzBjrPGM+cK8/ANWgBrkUCfJfb38/EfTSO8h7pWvKkyPkpWxvR7BkD2MyItMF62C97zAEoqdpUixwR/e+Rw==", "dev": true, "license": "MIT", "dependencies": { - "@vitest/spy": "4.1.8", + "@vitest/spy": "4.1.9", "estree-walker": "^3.0.3", "magic-string": "^0.30.21" }, @@ -1893,9 +1893,9 @@ } }, "node_modules/@vitest/pretty-format": { - "version": "4.1.8", - "resolved": "https://registry.npmjs.org/@vitest/pretty-format/-/pretty-format-4.1.8.tgz", - "integrity": "sha512-9GasEBxpZ1VYIpqHf/0+YGg121uSNwCKOJqIrTwWP/TB7DmFCiaBpNl3aPZzoLWfWkuqhbH8vJIVobZkvdo2cA==", + "version": "4.1.9", + "resolved": "https://registry.npmjs.org/@vitest/pretty-format/-/pretty-format-4.1.9.tgz", + "integrity": "sha512-s0iufns3iIFitdgm+YR7g1whCAaGtXz459VS9/PqyKDEEFgYIhsHOQmXgIgDuYCt7DeQmiZT0Qe2OA2p4ZPu5A==", "dev": true, "license": "MIT", "dependencies": { @@ -1906,13 +1906,13 @@ } }, "node_modules/@vitest/runner": { - "version": "4.1.8", - "resolved": "https://registry.npmjs.org/@vitest/runner/-/runner-4.1.8.tgz", - "integrity": "sha512-EmVxeBAfMJvycdjd6Hm+RbFBbA9fKvo0Kx37hNpBYoYeavH3RNsBXWDooR1mgD52dCrxIIuP7UotpfiwOikvcg==", + "version": "4.1.9", + "resolved": "https://registry.npmjs.org/@vitest/runner/-/runner-4.1.9.tgz", + "integrity": "sha512-KXLMDtc7oe70+3mJfGrPUWPesswH+3sTxAMAMl8DG7I8IUQT4XW718dY5ID3vPUcmlu27CcKfY4P3h3I29SLJg==", "dev": true, "license": "MIT", "dependencies": { - "@vitest/utils": "4.1.8", + "@vitest/utils": "4.1.9", "pathe": "^2.0.3" }, "funding": { @@ -1920,14 +1920,14 @@ } }, "node_modules/@vitest/snapshot": { - "version": "4.1.8", - "resolved": "https://registry.npmjs.org/@vitest/snapshot/-/snapshot-4.1.8.tgz", - "integrity": "sha512-acfZboRmAIf05DEKcBQy33VXojFJjtUdLyo7oOmV9kebb2xdU01UknNiPuPZoJZQyO7DF0gZdTGTpeAzET9QPQ==", + "version": "4.1.9", + "resolved": "https://registry.npmjs.org/@vitest/snapshot/-/snapshot-4.1.9.tgz", + "integrity": "sha512-Jc7RKGNBo8Z28WYIm0Niej4xdSPByRf6mU58VpHQkd6Zh05rlnA+twjbK5HyeIGHxrzsc3mJgS43uM0CZKzaIA==", "dev": true, "license": "MIT", "dependencies": { - "@vitest/pretty-format": "4.1.8", - "@vitest/utils": "4.1.8", + "@vitest/pretty-format": "4.1.9", + "@vitest/utils": "4.1.9", "magic-string": "^0.30.21", "pathe": "^2.0.3" }, @@ -1936,9 +1936,9 @@ } }, "node_modules/@vitest/spy": { - "version": "4.1.8", - "resolved": "https://registry.npmjs.org/@vitest/spy/-/spy-4.1.8.tgz", - "integrity": "sha512-6EevtBp6OZOPF7bmz36HrGMeP3txgVSrgebWxHOafDXGkhIzfXK14f8KF6MuFfgXXUeHxmpD3BQxkV00/3s5mA==", + "version": "4.1.9", + "resolved": "https://registry.npmjs.org/@vitest/spy/-/spy-4.1.9.tgz", + "integrity": "sha512-fHpsS6mIi+PiEW+vcRVOMkX1oSaPKne3VOclSFICPcGOmfKgXPU5iAah+wcNcj2xPrCCmfq99IDGf+EojhhvhA==", "dev": true, "license": "MIT", "funding": { @@ -1946,13 +1946,13 @@ } }, "node_modules/@vitest/utils": { - "version": "4.1.8", - "resolved": "https://registry.npmjs.org/@vitest/utils/-/utils-4.1.8.tgz", - "integrity": "sha512-uOJamYALNhfJ6iolExyQM40yIQwDqYnkKtQ5VCiSe17E33H0aQ/u+1GlRuz4LZBk6Mm3sg90G9hEbmEt37C1Zg==", + "version": "4.1.9", + "resolved": "https://registry.npmjs.org/@vitest/utils/-/utils-4.1.9.tgz", + "integrity": "sha512-A51o8ymO5PpqlWNnBP9ZHPXDIpuMtTLlGSjN7la4US+LJzoUMyhwjA5QXlm39JexgwHKW4Xjs8Z2d3dLCXOeuA==", "dev": true, "license": "MIT", "dependencies": { - "@vitest/pretty-format": "4.1.8", + "@vitest/pretty-format": "4.1.9", "convert-source-map": "^2.0.0", "tinyrainbow": "^3.1.0" }, @@ -3102,9 +3102,9 @@ } }, "node_modules/lucide-react": { - "version": "1.18.0", - "resolved": "https://registry.npmjs.org/lucide-react/-/lucide-react-1.18.0.tgz", - "integrity": "sha512-LZDb7H/0YfM+RJncD0hDQRCAu+vSGODqpe35TuVI8EuXaRjkczbsx7p8dY4J87F/MUSj6bpYqeI8nw8qXaAdmA==", + "version": "1.21.0", + "resolved": "https://registry.npmjs.org/lucide-react/-/lucide-react-1.21.0.tgz", + "integrity": "sha512-reEZMXq8Qdd5jg5XYkQ5TR1fB/GiQ7ih4vcrthYDtgjSDwh0i6/YLiGjsWsIwgN49gpAnd4J2elSNzncMEEUUQ==", "license": "ISC", "peerDependencies": { "react": "^16.5.1 || ^17.0.0 || ^18.0.0 || ^19.0.0" @@ -3396,9 +3396,9 @@ } }, "node_modules/react-router": { - "version": "7.17.0", - "resolved": "https://registry.npmjs.org/react-router/-/react-router-7.17.0.tgz", - "integrity": "sha512-FDELK7rTMlCHO5+reyXsPlmfr7N1F91lPHsWYfMEGQm/KQ+F4JFM8jGoeQDmDvdTs93Fw9aSilH+uKRb4/jXvQ==", + "version": "7.18.0", + "resolved": "https://registry.npmjs.org/react-router/-/react-router-7.18.0.tgz", + "integrity": "sha512-pTTGt8J+ji1NOmYnjzT+bAJy/1zD+Jp4ziO6cL7T3ZLvXKtusO7BpFqlRXitqpcPVqllsIXFHRMt+2/k3Xn6HQ==", "license": "MIT", "dependencies": { "cookie": "^1.0.1", @@ -3418,12 +3418,12 @@ } }, "node_modules/react-router-dom": { - "version": "7.17.0", - "resolved": "https://registry.npmjs.org/react-router-dom/-/react-router-dom-7.17.0.tgz", - "integrity": "sha512-fyU2yjGups/hE6Xz0I5ZYbVL8Gx29eCjgpHaRaTaVU+OOAdfRX05KsvyRm0GO8YQwOkhpU3MurW1jyMUJn+zSw==", + "version": "7.18.0", + "resolved": "https://registry.npmjs.org/react-router-dom/-/react-router-dom-7.18.0.tgz", + "integrity": "sha512-Fi0yY6kgtKae/Th2xibdWK0KSdYZ4B53Gyf6wRtomOKWgpNm7H7+DyfDhncdz9FKbpS+1jmDhg3F4WoGJ+yFOA==", "license": "MIT", "dependencies": { - "react-router": "7.17.0" + "react-router": "7.18.0" }, "engines": { "node": ">=20.0.0" @@ -3670,16 +3670,16 @@ } }, "node_modules/typescript-eslint": { - "version": "8.61.0", - "resolved": "https://registry.npmjs.org/typescript-eslint/-/typescript-eslint-8.61.0.tgz", - "integrity": "sha512-8y31Rd0eGTrDKqhy6vT0HtzhN+YLjQizwX3aA3hPXP/ynSfnrBXcQY5IzsP9/DM7+klX4IUncZZjkchP0z+rUw==", + "version": "8.62.0", + "resolved": "https://registry.npmjs.org/typescript-eslint/-/typescript-eslint-8.62.0.tgz", + "integrity": "sha512-8QxXi+ZACKX0kaqO4gY8kn0RSD9gFfaHDWwjqtEN48aWCBkX4MJaufWN+c3BzlrXLOxfywDL8CaoqUwcRq4j4Q==", "dev": true, "license": "MIT", "dependencies": { - "@typescript-eslint/eslint-plugin": "8.61.0", - "@typescript-eslint/parser": "8.61.0", - "@typescript-eslint/typescript-estree": "8.61.0", - "@typescript-eslint/utils": "8.61.0" + "@typescript-eslint/eslint-plugin": "8.62.0", + "@typescript-eslint/parser": "8.62.0", + "@typescript-eslint/typescript-estree": "8.62.0", + "@typescript-eslint/utils": "8.62.0" }, "engines": { "node": "^18.18.0 || ^20.9.0 || >=21.1.0" @@ -3813,19 +3813,19 @@ } }, "node_modules/vitest": { - "version": "4.1.8", - "resolved": "https://registry.npmjs.org/vitest/-/vitest-4.1.8.tgz", - "integrity": "sha512-flY6ScbCIt9HThs+C5HS7jvGOB560DJtk/Z15IQROTA6zEy49Nh8T/dofWTQL+n3vswqn87sbJNiuqw1SDp5Ig==", + "version": "4.1.9", + "resolved": "https://registry.npmjs.org/vitest/-/vitest-4.1.9.tgz", + "integrity": "sha512-nE3/LEyc0z87uHYLZebqCUOaJr2hdtuPp7BQ4BosVFnfltxgAvMG08NyrSGlPpOUWvR27c5flSmYFTNr78L9GQ==", "dev": true, "license": "MIT", "dependencies": { - "@vitest/expect": "4.1.8", - "@vitest/mocker": "4.1.8", - "@vitest/pretty-format": "4.1.8", - "@vitest/runner": "4.1.8", - "@vitest/snapshot": "4.1.8", - "@vitest/spy": "4.1.8", - "@vitest/utils": "4.1.8", + "@vitest/expect": "4.1.9", + "@vitest/mocker": "4.1.9", + "@vitest/pretty-format": "4.1.9", + "@vitest/runner": "4.1.9", + "@vitest/snapshot": "4.1.9", + "@vitest/spy": "4.1.9", + "@vitest/utils": "4.1.9", "es-module-lexer": "^2.0.0", "expect-type": "^1.3.0", "magic-string": "^0.30.21", @@ -3853,12 +3853,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.8", - "@vitest/browser-preview": "4.1.8", - "@vitest/browser-webdriverio": "4.1.8", - "@vitest/coverage-istanbul": "4.1.8", - "@vitest/coverage-v8": "4.1.8", - "@vitest/ui": "4.1.8", + "@vitest/browser-playwright": "4.1.9", + "@vitest/browser-preview": "4.1.9", + "@vitest/browser-webdriverio": "4.1.9", + "@vitest/coverage-istanbul": "4.1.9", + "@vitest/coverage-v8": "4.1.9", + "@vitest/ui": "4.1.9", "happy-dom": "*", "jsdom": "*", "vite": "^6.0.0 || ^7.0.0 || ^8.0.0" diff --git a/client/package.json b/client/package.json index 4385f0e0..a9244753 100644 --- a/client/package.json +++ b/client/package.json @@ -1,7 +1,7 @@ { "name": "ps5upload-client", "private": true, - "version": "3.3.22", + "version": "3.3.23", "description": "The all-in-one PS5 companion app.", "homepage": "https://github.com/phantomptr/ps5upload", "author": "PhantomPtr ", @@ -26,7 +26,7 @@ "dist:linux-arm": "tauri build --target aarch64-unknown-linux-gnu" }, "dependencies": { - "@tauri-apps/api": "^2.11.0", + "@tauri-apps/api": "^2.11.1", "@tauri-apps/plugin-dialog": "^2.7.1", "@tauri-apps/plugin-fs": "^2.5.1", "@tauri-apps/plugin-notification": "^2.3.1", @@ -34,10 +34,10 @@ "@tauri-apps/plugin-shell": "^2.3.5", "clsx": "^2.1.1", "html-to-image": "^1.11.13", - "lucide-react": "^1.18.0", + "lucide-react": "^1.21.0", "react": "^19.2.7", "react-dom": "^19.2.7", - "react-router-dom": "^7.17.0", + "react-router-dom": "^7.18.0", "zustand": "^5.0.14" }, "devDependencies": { @@ -47,12 +47,12 @@ "@types/react": "^19.2.17", "@types/react-dom": "^19.2.3", "@vitejs/plugin-react": "^6.0.2", - "@vitest/coverage-v8": "^4.1.8", + "@vitest/coverage-v8": "^4.1.9", "eslint": "^10.5.0", "eslint-plugin-react-hooks": "^7.1.1", "tailwindcss": "^4.0.0", "typescript": "^6.0.3", - "typescript-eslint": "^8.61.0", + "typescript-eslint": "^8.61.1", "vite": "^8.0.16", "vitest": "^4.1.4" }, diff --git a/client/src-tauri/Cargo.lock b/client/src-tauri/Cargo.lock index e3b17f85..f8b2c6c4 100644 --- a/client/src-tauri/Cargo.lock +++ b/client/src-tauri/Cargo.lock @@ -1237,7 +1237,7 @@ dependencies = [ [[package]] name = "ftx2-proto" -version = "3.3.21" +version = "3.3.23" dependencies = [ "serde", "thiserror 2.0.18", @@ -3319,7 +3319,7 @@ dependencies = [ [[package]] name = "ps5upload-core" -version = "3.3.21" +version = "3.3.23" dependencies = [ "anyhow", "base64 0.22.1", @@ -3336,7 +3336,7 @@ dependencies = [ [[package]] name = "ps5upload-desktop" -version = "3.3.21" +version = "3.3.23" dependencies = [ "anyhow", "base64 0.22.1", @@ -3369,7 +3369,7 @@ dependencies = [ [[package]] name = "ps5upload-engine" -version = "3.3.21" +version = "3.3.23" dependencies = [ "anyhow", "axum", @@ -3381,13 +3381,13 @@ dependencies = [ "serde_json", "tokio", "tokio-stream", - "tower-http", + "tower-http 0.7.0", "uuid", ] [[package]] name = "ps5upload-pkg" -version = "3.3.21" +version = "3.3.23" dependencies = [ "serde", "thiserror 2.0.18", @@ -3715,7 +3715,7 @@ dependencies = [ "tokio-rustls", "tokio-util", "tower", - "tower-http", + "tower-http 0.6.8", "tower-service", "url", "wasm-bindgen", @@ -3750,7 +3750,7 @@ dependencies = [ "tokio", "tokio-util", "tower", - "tower-http", + "tower-http 0.6.8", "tower-service", "url", "wasm-bindgen", @@ -4565,9 +4565,9 @@ checksum = "61c41af27dd6d1e27b1b16b489db798443478cef1f06a660c96db617ba5de3b1" [[package]] name = "tauri" -version = "2.11.2" +version = "2.11.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "437404997acf375d85f1177afa7e11bb971f274ed6a7b83a2a3e339015f4cc28" +checksum = "c2616f96cb644bf2c5c456d9de4d5d5100e592d7424c74d8b55c5cb96e359e93" dependencies = [ "anyhow", "bytes", @@ -4617,9 +4617,9 @@ dependencies = [ [[package]] name = "tauri-build" -version = "2.6.2" +version = "2.6.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4aa1f9055fc23919a54e4e125052bed16ed04aef0487086e758fe01a67b451c7" +checksum = "bc9ce40b16101cb6ea63d3e221567affd1c3a9205f95d7bc574941a10636b632" dependencies = [ "anyhow", "cargo_toml", @@ -4638,9 +4638,9 @@ dependencies = [ [[package]] name = "tauri-codegen" -version = "2.6.2" +version = "2.6.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e4a0319528a025a38c4078e7dae2c446f4e63620ddb0659a643ede1cb38f90e9" +checksum = "08279169ff42f8fc45a1dbc9dcae888893ba95288142e5880c59b93a26d2cfc5" dependencies = [ "base64 0.22.1", "brotli", @@ -4665,9 +4665,9 @@ dependencies = [ [[package]] name = "tauri-macros" -version = "2.6.2" +version = "2.6.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ae6cb4e3896c21d2f6da5b31251d2faea0153bba56ed0e970f918115dbee4924" +checksum = "e8b394794f399a421811d06966343e7933fcae92d59f5180b9388d1174497a45" dependencies = [ "heck 0.5.0", "proc-macro2", @@ -4815,9 +4815,9 @@ dependencies = [ [[package]] name = "tauri-runtime" -version = "2.11.2" +version = "2.11.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "48222d7116c8807eaa6fe2f372e023fae125084e61e6eca6d70b7961cdf129ef" +checksum = "b0b4bc95aed361b0019067d189a1174a603d460d0f6c72606512d59fc9c12ec8" dependencies = [ "cookie", "dpi", @@ -4840,9 +4840,9 @@ dependencies = [ [[package]] name = "tauri-runtime-wry" -version = "2.11.2" +version = "2.11.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b83849ee63ecb27a8e8d0fe51915ca215076914aca43f96db1179f0f415f6cd9" +checksum = "fe41e015bf8fc4d6477ff4926a0ef769dc64ff34c7b0038b6f7cacae892acb5c" dependencies = [ "gtk", "http", @@ -4866,9 +4866,9 @@ dependencies = [ [[package]] name = "tauri-utils" -version = "2.9.2" +version = "2.9.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "092379df9a707631978e6c56b1bc2401d387f01e2d4a3c123360d167bbb9aa95" +checksum = "3e176a18e67764923c4f1ce66f25ae4abe5f688384d5eb1a0fa6c77f3d90f887" dependencies = [ "anyhow", "brotli", @@ -5273,6 +5273,21 @@ dependencies = [ "tower-service", ] +[[package]] +name = "tower-http" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b11f75e912b0c2be01b63d8cf8057b8c3f97cf34abb3d431a3a4c8675498e233" +dependencies = [ + "bitflags 2.11.1", + "bytes", + "http", + "percent-encoding", + "pin-project-lite", + "tower-layer", + "tower-service", +] + [[package]] name = "tower-layer" version = "0.3.3" @@ -5319,9 +5334,9 @@ dependencies = [ [[package]] name = "tray-icon" -version = "0.23.1" +version = "0.24.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "15edbb0d80583e85ee8df283410038e17314df5cba30da2087a54a85216c0773" +checksum = "65ba1e5f6b9ef9fd87e21b9c6f351554dbd717960089168fcfdef854686961dc" dependencies = [ "crossbeam-channel", "dirs", diff --git a/client/src-tauri/Cargo.toml b/client/src-tauri/Cargo.toml index 1f10fb1a..3069c8d4 100644 --- a/client/src-tauri/Cargo.toml +++ b/client/src-tauri/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "ps5upload-desktop" -version = "3.3.22" +version = "3.3.23" description = "The all-in-one PS5 companion app." edition = "2021" rust-version = "1.77" diff --git a/engine/Cargo.lock b/engine/Cargo.lock index bcab459e..ad3e0f24 100644 --- a/engine/Cargo.lock +++ b/engine/Cargo.lock @@ -494,7 +494,7 @@ dependencies = [ [[package]] name = "ftx2-proto" -version = "3.3.22" +version = "3.3.23" dependencies = [ "serde", "thiserror", @@ -954,7 +954,7 @@ dependencies = [ [[package]] name = "ps5upload-bench" -version = "3.3.22" +version = "3.3.23" dependencies = [ "criterion", "ftx2-proto", @@ -964,7 +964,7 @@ dependencies = [ [[package]] name = "ps5upload-core" -version = "3.3.22" +version = "3.3.23" dependencies = [ "anyhow", "base64", @@ -981,7 +981,7 @@ dependencies = [ [[package]] name = "ps5upload-engine" -version = "3.3.22" +version = "3.3.23" dependencies = [ "anyhow", "axum", @@ -999,7 +999,7 @@ dependencies = [ [[package]] name = "ps5upload-lab" -version = "3.3.22" +version = "3.3.23" dependencies = [ "anyhow", "ftx2-proto", @@ -1008,7 +1008,7 @@ dependencies = [ [[package]] name = "ps5upload-pkg" -version = "3.3.22" +version = "3.3.23" dependencies = [ "serde", "serde_json", @@ -1017,7 +1017,7 @@ dependencies = [ [[package]] name = "ps5upload-tests" -version = "3.3.22" +version = "3.3.23" dependencies = [ "anyhow", "ftx2-proto", @@ -1386,13 +1386,14 @@ dependencies = [ [[package]] name = "tower-http" -version = "0.6.11" +version = "0.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4cfcf7e2740e6fc6d4d688b4ef00650406bb94adf4731e43c096c3a19fe40840" +checksum = "b11f75e912b0c2be01b63d8cf8057b8c3f97cf34abb3d431a3a4c8675498e233" dependencies = [ "bitflags", "bytes", "http", + "percent-encoding", "pin-project-lite", "tower-layer", "tower-service", diff --git a/engine/Cargo.toml b/engine/Cargo.toml index 5c539a8b..61dc8181 100644 --- a/engine/Cargo.toml +++ b/engine/Cargo.toml @@ -13,7 +13,7 @@ resolver = "2" [workspace.package] edition = "2021" license = "GPL-3.0-or-later" -version = "3.3.22" +version = "3.3.23" [workspace.dependencies] anyhow = "1.0" diff --git a/engine/crates/ps5upload-engine/Cargo.toml b/engine/crates/ps5upload-engine/Cargo.toml index e88cd988..3ac132b0 100644 --- a/engine/crates/ps5upload-engine/Cargo.toml +++ b/engine/crates/ps5upload-engine/Cargo.toml @@ -23,5 +23,5 @@ serde.workspace = true serde_json.workspace = true tokio.workspace = true tokio-stream.workspace = true -tower-http = { version = "0.6", features = ["cors"] } +tower-http = { version = "0.7", features = ["cors"] } uuid.workspace = true From e594af6c41f08da1c42ccef15881d01941cfc4cd Mon Sep 17 00:00:00 2001 From: phantomptr Date: Fri, 26 Jun 2026 22:29:56 +0800 Subject: [PATCH 5/5] chore(release): 3.3.23 - Fixed FW11/12 update installs (preserve the staged patch for the DPI fallback) - Fixed Close game on FW 12.20 (reach the SIGKILL fallback) - Pause running-game pollers during an upload (exfat speed regression) - Dependency + CI bumps --- CHANGELOG.md | 20 ++++++++++++++++++++ VERSION | 2 +- client/src-tauri/tauri.conf.json | 2 +- payload/include/config.h | 2 +- 4 files changed, 23 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index f56a5679..760b8e76 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,26 @@ What's new in ps5upload, written for humans. --- +## 3.3.23 + +- **Fixed: game updates that couldn't install on newer firmware.** When the PS5's + in-app installer turned an update away (a common first step on firmware 11/12), + the tool was deleting the staged update file a split second too early — so the + fallback installer (the one that actually lands updates) had nothing left to + install. The update file is now kept until the whole install cascade has had its + turn, so updates can fall through to the path that works. Your base game is never + touched either way. *(Needs a final confirmation on real firmware-12 hardware.)* +- **Fixed: the "Close game" button did nothing on some firmware.** On firmware + 12.20, the PS5's clean "close app" call is rejected, and the tool was giving up + there instead of trying its backup way of stopping the game. It now falls through + to the backup stop so the button actually closes the game. +- **Faster uploads while the app is open.** The Installed Apps and Library screens + quietly check what's running on your PS5 every few seconds. That check shares a + channel with uploads, and on big multi-part games (exfat/ShadowMount dumps) it + could drag transfer speed down. Those checks now pause while an upload to that + console is running, and resume the moment it finishes. +- Routine dependency and CI updates. + ## 3.3.22 - **See what's playing, and stop it.** Installed Apps now shows a "Playing" badge diff --git a/VERSION b/VERSION index c21e5b4e..d244a1e7 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -3.3.22 +3.3.23 diff --git a/client/src-tauri/tauri.conf.json b/client/src-tauri/tauri.conf.json index f87f1b98..77f3ec6c 100644 --- a/client/src-tauri/tauri.conf.json +++ b/client/src-tauri/tauri.conf.json @@ -1,7 +1,7 @@ { "$schema": "https://schema.tauri.app/config/2", "productName": "PS5Upload", - "version": "3.3.22", + "version": "3.3.23", "identifier": "com.phantomptr.ps5upload", "build": { "beforeDevCommand": "npm run dev:vite", diff --git a/payload/include/config.h b/payload/include/config.h index 493089e0..0aa814eb 100644 --- a/payload/include/config.h +++ b/payload/include/config.h @@ -5,7 +5,7 @@ * UI tell apart an old payload still running from a build that includes * a particular fix, without having to boot the console. Keep in sync * with the desktop app's package.json during releases. */ -#define PS5UPLOAD2_VERSION "3.3.22" +#define PS5UPLOAD2_VERSION "3.3.23" /* Author credit — embedded in the startup toast so anyone looking at * the console screen knows who wrote the software that just loaded. * Kept separate from VERSION so release scripts can bump the version