From 83ea6178595cc3f9ae934afc07bc61dd1fc98683 Mon Sep 17 00:00:00 2001 From: Twice6804 <260297042+Twice6804@users.noreply.github.com> Date: Wed, 17 Jun 2026 21:20:48 -0700 Subject: [PATCH 1/4] feat(saves): back up a save directly to a USB drive on the PS5 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Adds a configurable PS5-side save path (Settings, default /mnt/usb0/savedata) and a "Save to USB" action (per-row + bulk) on the Saves screen that pulls a save off the console, zips it, then pushes it back to ///.zip on a USB/extended-storage drive plugged into the PS5 itself — no host PC round-trip needed. Reuses the existing download/finalize/zip pipeline and single-file transfer (transfer_file); no payload/engine changes required. Pre-flights the USB mount via the existing checkDestinationFreeSpace helper and re-checks for a stale host before uploading, mirroring the Restore flow's safety guards. Co-Authored-By: Claude Sonnet 4.6 --- client/src/i18n/locales/en.ts | 12 ++ client/src/lib/backupTimestamp.test.ts | 24 +++ client/src/lib/backupTimestamp.ts | 19 +++ client/src/screens/Saves/index.tsx | 220 ++++++++++++++++++++++++- client/src/screens/Settings/index.tsx | 55 +++++++ client/src/state/saveSettings.test.ts | 91 ++++++++++ client/src/state/saveSettings.ts | 48 ++++++ client/src/state/userConfig.ts | 14 ++ scripts/i18n-known-missing.json | 187 +++++++++++++++++++++ 9 files changed, 661 insertions(+), 9 deletions(-) create mode 100644 client/src/lib/backupTimestamp.test.ts create mode 100644 client/src/lib/backupTimestamp.ts create mode 100644 client/src/state/saveSettings.test.ts create mode 100644 client/src/state/saveSettings.ts diff --git a/client/src/i18n/locales/en.ts b/client/src/i18n/locales/en.ts index 2e92e24c..13df2ac6 100644 --- a/client/src/i18n/locales/en.ts +++ b/client/src/i18n/locales/en.ts @@ -1017,6 +1017,13 @@ saves_restore_confirm_title: "Restore {title} from a .zip backup?", saves_restore_picker: "Pick the .zip backup to restore from", saves_restore_tooltip: "Pick a .zip backup and upload its contents back to this save's PS5 path. Overwrites the live save.", saves_title: "Save data", +saves_backup_usb: "Save to USB", +saves_backup_usb_tooltip: "Back this save up to the USB save path configured in Settings, without leaving the PS5.", +saves_backup_usb_all: "Back up all to USB", +saves_backup_usb_no_volume: "No writable USB/external drive found at {path}. Plug it into the PS5 and try again.", +saves_backup_usb_low_space: "Not enough free space at {path} for this backup.", +saves_backup_usb_summary: "Backed up {ok}/{total} to USB", +saves_backup_usb_summary_failed: "Backed up {ok}/{total} to USB; {failed} failed", schedules_add: "Add daily", schedules_caveat: "Schedules fire only while ps5upload is open. For true overnight automation, set a system cron job that hits the engine HTTP API instead.", schedules_remove: "remove", @@ -1057,6 +1064,11 @@ engine_url_label: "Engine URL", engine_url_reset: "Reset", engine_url_hint: "Where the app reaches the ps5upload-engine. Leave as the default local sidecar, or point at a remote/self-hosted engine. Restart the app after switching between local and remote.", +settings_card_save_path: "Save backups", +save_path_label: "USB save path", +save_path_reset: "Reset", +save_path_hint: + "PS5-side base folder for \"Save to USB storage\" backups (e.g. a USB stick plugged into the console). Each backup lands at //<timestamp>/<title id>.zip.", settings_group_updates: "Updates", settings_group_data: "Data & reset", settings_group_automation: "Automation", diff --git a/client/src/lib/backupTimestamp.test.ts b/client/src/lib/backupTimestamp.test.ts new file mode 100644 index 00000000..243d0d8f --- /dev/null +++ b/client/src/lib/backupTimestamp.test.ts @@ -0,0 +1,24 @@ +import { describe, expect, it } from "vitest"; +import { backupTimestamp } from "./backupTimestamp"; + +describe("backupTimestamp", () => { + it("formats as YYYY-MM-DD_HHMMSS in local time", () => { + const d = new Date(2026, 5, 17, 14, 25, 30); // June 17 2026, 14:25:30 local + expect(backupTimestamp(d)).toBe("2026-06-17_142530"); + }); + + it("zero-pads single-digit month/day/hour/minute/second", () => { + const d = new Date(2026, 0, 2, 3, 4, 5); // Jan 2 2026, 03:04:05 local + expect(backupTimestamp(d)).toBe("2026-01-02_030405"); + }); + + it("defaults to the current time when no argument is given", () => { + const before = new Date(); + const ts = backupTimestamp(); + const after = new Date(); + // Sanity check the shape and that it falls within [before, after]. + expect(ts).toMatch(/^\d{4}-\d{2}-\d{2}_\d{6}$/); + expect(backupTimestamp(before) <= ts).toBe(true); + expect(ts <= backupTimestamp(after)).toBe(true); + }); +}); diff --git a/client/src/lib/backupTimestamp.ts b/client/src/lib/backupTimestamp.ts new file mode 100644 index 00000000..2e9e302a --- /dev/null +++ b/client/src/lib/backupTimestamp.ts @@ -0,0 +1,19 @@ +// Timestamp string used to name a "Save to USB storage" backup folder: +// `<savePath>/<title_id>/<timestamp>/<title_id>.zip`. Sortable lexically +// and filesystem-safe on every target (PS5 exFAT/FAT32/UFS, host OSes). +// +// Pure function — `d` is passed in so tests don't depend on the wall +// clock (mirrors the `nowMs`-injection convention in pkgStagingPath.ts). + +function pad(n: number, width = 2): string { + return String(n).padStart(width, "0"); +} + +/** Local-time `YYYY-MM-DD_HHMMSS`, e.g. `2026-06-17_142530`. Local time + * (not UTC) so the folder name matches what the user would expect to + * see if they browse the USB drive themselves. */ +export function backupTimestamp(d: Date = new Date()): string { + const date = `${d.getFullYear()}-${pad(d.getMonth() + 1)}-${pad(d.getDate())}`; + const time = `${pad(d.getHours())}${pad(d.getMinutes())}${pad(d.getSeconds())}`; + return `${date}_${time}`; +} diff --git a/client/src/screens/Saves/index.tsx b/client/src/screens/Saves/index.tsx index 0ca8e4d8..9cfb5baa 100644 --- a/client/src/screens/Saves/index.tsx +++ b/client/src/screens/Saves/index.tsx @@ -8,11 +8,14 @@ import { Download, Upload as UploadIcon, FolderOpen, + HardDrive, } from "lucide-react"; import { openInFileSystem } from "../../state/fsNavigation"; import { savesList, startTransferDir, + startTransferFile, + checkDestinationFreeSpace, fsDelete, fsListDir, waitForJob, @@ -24,7 +27,10 @@ import { saveArchiveRestorePrepare, type SaveEntry, } from "../../api/ps5"; +import { localFs } from "../../api/localFs"; import { useConnectionStore, PS5_PAYLOAD_PORT } from "../../state/connection"; +import { getSavePath } from "../../state/saveSettings"; +import { backupTimestamp } from "../../lib/backupTimestamp"; import { PageHeader, Button, @@ -73,6 +79,9 @@ export default function SavesScreen() { // two ops over the same PS5 save path (which would deletes-and- // uploads in undefined order and leave the live save corrupt). const [busy, setBusy] = useState<Set<string>>(() => new Set()); + // "Back up all to USB" is a single sequential run across every save, so + // its busy flag is global rather than per-path like `busy` above. + const [bulkBackupBusy, setBulkBackupBusy] = useState(false); const isBusy = useCallback((path: string) => busy.has(path), [busy]); const markBusy = useCallback((path: string, on: boolean) => { setBusy((prev) => { @@ -322,6 +331,161 @@ export default function SavesScreen() { } } + /** + * Core "Save to USB storage" flow: pull the save off the PS5 (same + * download/finalize/zip steps as handleDownload), but instead of a + * host file-save dialog, push the resulting zip BACK onto the PS5 at + * `<savePath>/<title_id>/<timestamp>/<title_id>.zip` — typically a USB + * stick or extended-storage drive plugged into the console itself. + * + * `skipPreflight` lets the bulk "Back up all to USB" button validate + * the USB mount once up front instead of once per title. + */ + async function backupOneToUsb( + entry: SaveEntry, + opts?: { skipPreflight?: boolean }, + ) { + if (!host?.trim()) return; + if (isBusy(entry.path)) return; + const backupHost = host.trim(); + const addr = `${backupHost}:${PS5_PAYLOAD_PORT}`; + const base = getSavePath(); + markBusy(entry.path, true); + let tempDir: string | null = null; + try { + if (!opts?.skipPreflight) { + const preflight = await checkDestinationFreeSpace(addr, base, 0); + if (!preflight.volume || !preflight.volume.writable || preflight.volume.is_placeholder) { + throw new Error( + tr( + "saves_backup_usb_no_volume", + { path: base }, + `No writable USB/external drive found at ${base}. Plug it into the PS5 and try again.`, + ), + ); + } + } + // 1) Scratch dir + pull the PS5 save folder, same as handleDownload. + tempDir = await saveArchiveMakeTemp(entry.title_id); + const jobId = await startTransferDownload(entry.path, tempDir, addr, "folder"); + await waitForJob(jobId); + // 2) Format-aware cleanup (strip sdimg_ prefix, drop emulator + // bookkeeping subdirs) — identical to handleDownload. + await saveArchiveBackupFinalize(tempDir, entry.title_id); + // 3) Zip into the scratch dir itself (no host file-save dialog — + // the zip never needs to leave the temp dir before it's uploaded). + const zipName = `${entry.title_id}.zip`; + const hostZip = `${tempDir}/${zipName}`; + await saveArchiveZip(tempDir, entry.title_id, hostZip, zipName); + // 4) Size the zip (via the scratch dir listing) and confirm the USB + // target has room for it. Best-effort: an unreadable size or an + // unmatched volume just skips the check rather than blocking. + const remoteDir = `${base}/${entry.title_id}/${backupTimestamp()}`; + const remoteZip = `${remoteDir}/${zipName}`; + const tempEntries = await localFs.listDir(tempDir).catch(() => []); + const zipSize = tempEntries.find((e) => e.name === zipName)?.size ?? 0; + if (zipSize > 0) { + const spaceCheck = await checkDestinationFreeSpace(addr, remoteZip, zipSize); + if (spaceCheck.insufficient) { + throw new Error( + tr( + "saves_backup_usb_low_space", + { path: base }, + `Not enough free space at ${base} for this backup.`, + ), + ); + } + } + // 5) Stale-host re-check, same reasoning as handleRestore: the + // download+zip steps above can run for many seconds, and the user + // may have switched PS5 in the roster sidebar meanwhile. Refuse to + // upload to the wrong console. + const currentHost = useConnectionStore.getState().host?.trim(); + if (currentHost !== backupHost) { + throw new Error( + `Host changed during backup (was ${backupHost}, now ${currentHost || "(none)"}). ` + + "Aborted before upload — your other console's USB drive is untouched.", + ); + } + // 6) Upload the zip to the PS5's USB path. The payload's + // ensure_parent_dir auto-creates <title_id>/<timestamp>/ — no + // manual mkdir needed. + const jobId2 = await startTransferFile(hostZip, remoteZip, addr, null); + await waitForJob(jobId2); + pushNotification( + "success", + withConsolePrefix(backupHost, `Backed up ${entry.title_id} to USB`), + { body: `Saved to ${remoteZip}` }, + ); + } catch (e) { + const msg = e instanceof Error ? e.message : String(e); + setError(msg); + pushNotification( + "error", + withConsolePrefix(backupHost, `USB backup failed: ${entry.title_id}`), + { body: msg }, + ); + throw e; // let the bulk handler count this as a failure + } finally { + if (tempDir) await saveArchiveCleanupTemp(tempDir).catch(() => {}); + markBusy(entry.path, false); + } + } + + function handleBackupToUsb(entry: SaveEntry) { + backupOneToUsb(entry).catch(() => { + // Already surfaced via setError + pushNotification above. + }); + } + + async function handleBackupAllToUsb() { + if (!host?.trim() || !saves || saves.length === 0 || bulkBackupBusy) return; + const backupHost = host.trim(); + const addr = `${backupHost}:${PS5_PAYLOAD_PORT}`; + const base = getSavePath(); + setBulkBackupBusy(true); + try { + const preflight = await checkDestinationFreeSpace(addr, base, 0); + if (!preflight.volume || !preflight.volume.writable || preflight.volume.is_placeholder) { + const msg = tr( + "saves_backup_usb_no_volume", + { path: base }, + `No writable USB/external drive found at ${base}. Plug it into the PS5 and try again.`, + ); + setError(msg); + pushNotification("error", withConsolePrefix(backupHost, "USB backup failed"), { + body: msg, + }); + return; + } + let ok = 0; + let failed = 0; + for (const entry of saves) { + try { + await backupOneToUsb(entry, { skipPreflight: true }); + ok++; + } catch { + failed++; + } + } + pushNotification( + failed === 0 ? "success" : "error", + withConsolePrefix( + backupHost, + failed === 0 + ? tr("saves_backup_usb_summary", { ok, total: saves.length }, `Backed up ${ok}/${saves.length} to USB`) + : tr( + "saves_backup_usb_summary_failed", + { ok, total: saves.length, failed }, + `Backed up ${ok}/${saves.length} to USB; ${failed} failed`, + ), + ), + ); + } finally { + setBulkBackupBusy(false); + } + } + return ( <div className="p-6"> {confirmDialogNode} @@ -336,15 +500,39 @@ export default function SavesScreen() { "Per-game save folders on the PS5. PS5 saves under savedata_prospero/, PS4 legacy saves under savedata/. Backup writes a portable <title-id>.zip; restore expects the same shape.", )} right={ - <Button - variant="secondary" - size="sm" - leftIcon={<RefreshCw size={12} />} - onClick={refresh} - disabled={loading || !host?.trim() || payloadStatus !== "up"} - > - {tr("refresh", undefined, "Refresh")} - </Button> + <div className="flex items-center gap-2"> + <Button + variant="secondary" + size="sm" + leftIcon={ + bulkBackupBusy ? ( + <Loader2 size={12} className="animate-spin" /> + ) : ( + <HardDrive size={12} /> + ) + } + onClick={handleBackupAllToUsb} + disabled={ + bulkBackupBusy || + loading || + !host?.trim() || + payloadStatus !== "up" || + !saves || + saves.length === 0 + } + > + {tr("saves_backup_usb_all", undefined, "Back up all to USB")} + </Button> + <Button + variant="secondary" + size="sm" + leftIcon={<RefreshCw size={12} />} + onClick={refresh} + disabled={loading || !host?.trim() || payloadStatus !== "up"} + > + {tr("refresh", undefined, "Refresh")} + </Button> + </div> } /> @@ -414,6 +602,20 @@ export default function SavesScreen() { > {tr("saves_download", undefined, "Backup")} </Button> + <Button + variant="ghost" + size="sm" + leftIcon={<HardDrive size={11} />} + onClick={() => handleBackupToUsb(e)} + disabled={isBusy(e.path) || bulkBackupBusy} + title={tr( + "saves_backup_usb_tooltip", + undefined, + "Back this save up to the USB save path configured in Settings, without leaving the PS5.", + )} + > + {tr("saves_backup_usb", undefined, "Save to USB")} + </Button> {/* danger (red-bordered), NOT ghost like Backup: Restore overwrites — wipes — the live PS5 save. It sat visually identical to the harmless Backup button next to it, diff --git a/client/src/screens/Settings/index.tsx b/client/src/screens/Settings/index.tsx index b13b5b2a..7fc4f8b1 100644 --- a/client/src/screens/Settings/index.tsx +++ b/client/src/screens/Settings/index.tsx @@ -42,6 +42,7 @@ import { } from "../../state/uploadSettings"; import { useConnectionStore } from "../../state/connection"; import { useEngineStore, DEFAULT_ENGINE_URL } from "../../state/engine"; +import { useSaveSettingsStore, DEFAULT_SAVE_PATH } from "../../state/saveSettings"; import { userConfigPath, resetAllAppData } from "../../state/userConfig"; import { useUpdateStore, type UpdatePhase } from "../../state/update"; import { isMobile } from "../../lib/platform"; @@ -149,6 +150,58 @@ function EngineUrlSection() { ); } +/** Save-to-USB base path field. Where the Saves screen's "Save to USB + * storage" button writes backups on the PS5 itself (e.g. a USB stick + * plugged into the console) — full layout is `<path>/<title_id>/ + * <timestamp>/<title_id>.zip`. Edits commit on blur, same as the + * Engine URL field above. */ +function SavePathSection() { + const tr = useTr(); + const savePath = useSaveSettingsStore((s) => s.savePath); + const setSavePath = useSaveSettingsStore((s) => s.setSavePath); + const [draft, setDraft] = useState(savePath); + + return ( + <Section title={tr("settings_card_save_path", undefined, "Save backups")}> + <label className="grid gap-1.5 text-sm"> + <span className="font-medium"> + {tr("save_path_label", undefined, "USB save path")} + </span> + <div className="flex items-center gap-2"> + <input + type="text" + value={draft} + onChange={(e) => setDraft(e.target.value)} + onBlur={() => setSavePath(draft)} + placeholder={DEFAULT_SAVE_PATH} + spellCheck={false} + className="flex-1 rounded-md border border-[var(--color-border)] bg-[var(--color-surface)] px-3 py-1.5 text-sm" + /> + {savePath !== DEFAULT_SAVE_PATH && ( + <button + type="button" + onClick={() => { + setDraft(DEFAULT_SAVE_PATH); + setSavePath(DEFAULT_SAVE_PATH); + }} + className="text-xs text-[var(--color-muted)] hover:text-[var(--color-text)]" + > + {tr("save_path_reset", undefined, "Reset")} + </button> + )} + </div> + <span className="text-xs text-[var(--color-muted)]"> + {tr( + "save_path_hint", + undefined, + "PS5-side base folder for \"Save to USB storage\" backups (e.g. a USB stick plugged into the console). Each backup lands at <path>/<title id>/<timestamp>/<title id>.zip.", + )} + </span> + </label> + </Section> + ); +} + export default function SettingsScreen() { const { enabled, supported, lastError, setEnabled, syncFromBackend } = useKeepAwakeStore(); @@ -312,6 +365,8 @@ export default function SettingsScreen() { <EngineUrlSection /> + <SavePathSection /> + <GroupHeading> {tr("settings_group_uploads", undefined, "Uploads")} </GroupHeading> diff --git a/client/src/state/saveSettings.test.ts b/client/src/state/saveSettings.test.ts new file mode 100644 index 00000000..9c62eaa2 --- /dev/null +++ b/client/src/state/saveSettings.test.ts @@ -0,0 +1,91 @@ +import { describe, expect, it, beforeEach, afterEach, vi } from "vitest"; +import { useSaveSettingsStore, normalizeSavePath, DEFAULT_SAVE_PATH } from "./saveSettings"; + +// vitest's default node env has no `window`; the store reads +// `window.localStorage`. Install a tiny in-memory stub (same pattern as +// installSettings.test.ts) so the real persist branches run. +function installWindowStub(seed?: Record<string, string>) { + const store = new globalThis.Map<string, string>( + seed ? Object.entries(seed) : [], + ); + const localStorage = { + getItem: (k: string) => (store.has(k) ? (store.get(k) as string) : null), + setItem: (k: string, v: string) => void store.set(k, String(v)), + removeItem: (k: string) => void store.delete(k), + clear: () => store.clear(), + }; + (globalThis as { window?: unknown }).window = { localStorage }; +} + +const KEY = "ps5upload.save_path"; + +describe("normalizeSavePath", () => { + it("trims whitespace", () => { + expect(normalizeSavePath(" /mnt/usb0/savedata ")).toBe( + "/mnt/usb0/savedata", + ); + }); + + it("strips trailing slashes", () => { + expect(normalizeSavePath("/mnt/usb0/savedata/")).toBe( + "/mnt/usb0/savedata", + ); + expect(normalizeSavePath("/mnt/usb0/savedata///")).toBe( + "/mnt/usb0/savedata", + ); + }); + + it("falls back to the default when empty or whitespace-only", () => { + expect(normalizeSavePath("")).toBe(DEFAULT_SAVE_PATH); + expect(normalizeSavePath(" ")).toBe(DEFAULT_SAVE_PATH); + }); + + it("leaves an already-normalized custom path untouched", () => { + expect(normalizeSavePath("/mnt/ext0/backups")).toBe("/mnt/ext0/backups"); + }); +}); + +describe("saveSettings — savePath", () => { + beforeEach(() => { + installWindowStub(); + }); + + afterEach(() => { + delete (globalThis as { window?: unknown }).window; + vi.resetModules(); + }); + + it("defaults to DEFAULT_SAVE_PATH when the key is absent", async () => { + installWindowStub(); + vi.resetModules(); + const mod = await import("./saveSettings"); + expect(mod.useSaveSettingsStore.getState().savePath).toBe( + DEFAULT_SAVE_PATH, + ); + }); + + it("loads and normalizes a previously stored value", async () => { + installWindowStub({ [KEY]: "/mnt/usb1/savedata/" }); + vi.resetModules(); + const mod = await import("./saveSettings"); + expect(mod.useSaveSettingsStore.getState().savePath).toBe( + "/mnt/usb1/savedata", + ); + }); + + it("setter persists the normalized value and mirrors state", () => { + const s = useSaveSettingsStore.getState(); + s.setSavePath("/mnt/ext0/backups/"); + expect(window.localStorage.getItem(KEY)).toBe("/mnt/ext0/backups"); + expect(useSaveSettingsStore.getState().savePath).toBe( + "/mnt/ext0/backups", + ); + }); + + it("setter falls back to the default for an empty value", () => { + const s = useSaveSettingsStore.getState(); + s.setSavePath(" "); + expect(window.localStorage.getItem(KEY)).toBe(DEFAULT_SAVE_PATH); + expect(useSaveSettingsStore.getState().savePath).toBe(DEFAULT_SAVE_PATH); + }); +}); diff --git a/client/src/state/saveSettings.ts b/client/src/state/saveSettings.ts new file mode 100644 index 00000000..4fe22202 --- /dev/null +++ b/client/src/state/saveSettings.ts @@ -0,0 +1,48 @@ +import { create } from "zustand"; + +/** + * Where "Save to USB storage" writes save backups on the PS5 itself — + * e.g. a USB stick or extended-storage drive plugged into the console, + * NOT the host PC (that's the existing Saves screen's Backup-to-file + * flow). Defaults to the first USB mount slot the payload exposes. + * + * Persisted to localStorage and mirrored to ~/.ps5upload/settings.json, + * same as engineUrl (state/engine.ts). + */ + +export const DEFAULT_SAVE_PATH = "/mnt/usb0/savedata"; +const KEY_SAVE_PATH = "ps5upload.save_path"; + +/** Trim and drop trailing slashes so callers can `${savePath}/<title_id>/...` + * without doubling up. Falls back to the default when empty. */ +export function normalizeSavePath(raw: string): string { + const v = raw.trim().replace(/\/+$/, ""); + return v || DEFAULT_SAVE_PATH; +} + +function loadSavePath(): string { + if (typeof window === "undefined") return DEFAULT_SAVE_PATH; + const v = window.localStorage.getItem(KEY_SAVE_PATH); + return v ? normalizeSavePath(v) : DEFAULT_SAVE_PATH; +} + +interface SaveSettingsState { + savePath: string; + setSavePath: (path: string) => void; +} + +export const useSaveSettingsStore = create<SaveSettingsState>((set) => ({ + savePath: loadSavePath(), + setSavePath: (path) => { + const savePath = normalizeSavePath(path); + if (typeof window !== "undefined") { + window.localStorage.setItem(KEY_SAVE_PATH, savePath); + } + set({ savePath }); + }, +})); + +/** Non-hook accessor for module-scope callers (Saves screen handlers). */ +export function getSavePath(): string { + return useSaveSettingsStore.getState().savePath; +} diff --git a/client/src/state/userConfig.ts b/client/src/state/userConfig.ts index 38a61d33..25a0702f 100644 --- a/client/src/state/userConfig.ts +++ b/client/src/state/userConfig.ts @@ -7,6 +7,7 @@ import { useKeepAwakeStore } from "./keepAwake"; import { useUploadSettingsStore } from "./uploadSettings"; import { useConnectionStore } from "./connection"; import { useEngineStore, normalizeEngineUrl } from "./engine"; +import { useSaveSettingsStore, normalizeSavePath } from "./saveSettings"; /** * Mirror all persisted user settings to `~/.ps5upload/settings.json`. @@ -36,6 +37,9 @@ interface SettingsSnapshot { /** Base URL of the engine the UI talks to. Default is the local * sidecar; can point at a remote/self-hosted engine. */ engine_url?: string; + /** PS5-side base directory "Save to USB storage" backs up into — + * e.g. a USB stick plugged into the console. Default /mnt/usb0/savedata. */ + save_path?: string; keep_awake?: boolean; upload?: { always_overwrite?: boolean; @@ -51,6 +55,7 @@ function snapshotCurrent(): SettingsSnapshot { lang: useLangStore.getState().lang, ps5_host: useConnectionStore.getState().host, engine_url: useEngineStore.getState().engineUrl, + save_path: useSaveSettingsStore.getState().savePath, keep_awake: useKeepAwakeStore.getState().enabled, upload: { always_overwrite: useUploadSettingsStore.getState().alwaysOverwrite, @@ -111,6 +116,7 @@ export function installUserConfigMirror() { schedulePersist(); pushEngineUrl(s.engineUrl); }); + useSaveSettingsStore.subscribe(schedulePersist); } /** Tell the Rust shell which engine URL its proxies should hit. */ @@ -198,6 +204,14 @@ export async function hydrateFromUserConfig(): Promise<void> { // it changed here — the shell read settings.json at startup, but a // localStorage-only value (no file) wouldn't have reached it. pushEngineUrl(useEngineStore.getState().engineUrl); + const liveSavePath = useSaveSettingsStore.getState().savePath; + if ( + typeof data.save_path === "string" && + data.save_path.trim() && + normalizeSavePath(data.save_path) !== liveSavePath + ) { + useSaveSettingsStore.getState().setSavePath(data.save_path); + } const liveKeepAwake = useKeepAwakeStore.getState().enabled; if (typeof data.keep_awake === "boolean" && data.keep_awake !== liveKeepAwake) { await useKeepAwakeStore.getState().setEnabled(data.keep_awake); diff --git a/scripts/i18n-known-missing.json b/scripts/i18n-known-missing.json index 92cdc455..b797cbc1 100644 --- a/scripts/i18n-known-missing.json +++ b/scripts/i18n-known-missing.json @@ -144,12 +144,23 @@ "queue_installed", "queue_installed_warn", "queue_will_install", + "save_path_hint", + "save_path_label", + "save_path_reset", + "saves_backup_usb", + "saves_backup_usb_all", + "saves_backup_usb_low_space", + "saves_backup_usb_no_volume", + "saves_backup_usb_summary", + "saves_backup_usb_summary_failed", + "saves_backup_usb_tooltip", "saves_open_folder", "saves_open_folder_hint", "screenshots_bulk_partial", "search_scope_all", "search_scope_tooltip", "settings_card_engine", + "settings_card_save_path", "shortcuts_activate", "shortcuts_close", "shortcuts_cmd_palette", @@ -340,12 +351,23 @@ "queue_installed", "queue_installed_warn", "queue_will_install", + "save_path_hint", + "save_path_label", + "save_path_reset", + "saves_backup_usb", + "saves_backup_usb_all", + "saves_backup_usb_low_space", + "saves_backup_usb_no_volume", + "saves_backup_usb_summary", + "saves_backup_usb_summary_failed", + "saves_backup_usb_tooltip", "saves_open_folder", "saves_open_folder_hint", "screenshots_bulk_partial", "search_scope_all", "search_scope_tooltip", "settings_card_engine", + "settings_card_save_path", "shortcuts_activate", "shortcuts_close", "shortcuts_cmd_palette", @@ -536,12 +558,23 @@ "queue_installed", "queue_installed_warn", "queue_will_install", + "save_path_hint", + "save_path_label", + "save_path_reset", + "saves_backup_usb", + "saves_backup_usb_all", + "saves_backup_usb_low_space", + "saves_backup_usb_no_volume", + "saves_backup_usb_summary", + "saves_backup_usb_summary_failed", + "saves_backup_usb_tooltip", "saves_open_folder", "saves_open_folder_hint", "screenshots_bulk_partial", "search_scope_all", "search_scope_tooltip", "settings_card_engine", + "settings_card_save_path", "shortcuts_activate", "shortcuts_close", "shortcuts_cmd_palette", @@ -732,12 +765,23 @@ "queue_installed", "queue_installed_warn", "queue_will_install", + "save_path_hint", + "save_path_label", + "save_path_reset", + "saves_backup_usb", + "saves_backup_usb_all", + "saves_backup_usb_low_space", + "saves_backup_usb_no_volume", + "saves_backup_usb_summary", + "saves_backup_usb_summary_failed", + "saves_backup_usb_tooltip", "saves_open_folder", "saves_open_folder_hint", "screenshots_bulk_partial", "search_scope_all", "search_scope_tooltip", "settings_card_engine", + "settings_card_save_path", "shortcuts_activate", "shortcuts_close", "shortcuts_cmd_palette", @@ -928,12 +972,23 @@ "queue_installed", "queue_installed_warn", "queue_will_install", + "save_path_hint", + "save_path_label", + "save_path_reset", + "saves_backup_usb", + "saves_backup_usb_all", + "saves_backup_usb_low_space", + "saves_backup_usb_no_volume", + "saves_backup_usb_summary", + "saves_backup_usb_summary_failed", + "saves_backup_usb_tooltip", "saves_open_folder", "saves_open_folder_hint", "screenshots_bulk_partial", "search_scope_all", "search_scope_tooltip", "settings_card_engine", + "settings_card_save_path", "shortcuts_activate", "shortcuts_close", "shortcuts_cmd_palette", @@ -1124,12 +1179,23 @@ "queue_installed", "queue_installed_warn", "queue_will_install", + "save_path_hint", + "save_path_label", + "save_path_reset", + "saves_backup_usb", + "saves_backup_usb_all", + "saves_backup_usb_low_space", + "saves_backup_usb_no_volume", + "saves_backup_usb_summary", + "saves_backup_usb_summary_failed", + "saves_backup_usb_tooltip", "saves_open_folder", "saves_open_folder_hint", "screenshots_bulk_partial", "search_scope_all", "search_scope_tooltip", "settings_card_engine", + "settings_card_save_path", "shortcuts_activate", "shortcuts_close", "shortcuts_cmd_palette", @@ -1320,12 +1386,23 @@ "queue_installed", "queue_installed_warn", "queue_will_install", + "save_path_hint", + "save_path_label", + "save_path_reset", + "saves_backup_usb", + "saves_backup_usb_all", + "saves_backup_usb_low_space", + "saves_backup_usb_no_volume", + "saves_backup_usb_summary", + "saves_backup_usb_summary_failed", + "saves_backup_usb_tooltip", "saves_open_folder", "saves_open_folder_hint", "screenshots_bulk_partial", "search_scope_all", "search_scope_tooltip", "settings_card_engine", + "settings_card_save_path", "shortcuts_activate", "shortcuts_close", "shortcuts_cmd_palette", @@ -1516,12 +1593,23 @@ "queue_installed", "queue_installed_warn", "queue_will_install", + "save_path_hint", + "save_path_label", + "save_path_reset", + "saves_backup_usb", + "saves_backup_usb_all", + "saves_backup_usb_low_space", + "saves_backup_usb_no_volume", + "saves_backup_usb_summary", + "saves_backup_usb_summary_failed", + "saves_backup_usb_tooltip", "saves_open_folder", "saves_open_folder_hint", "screenshots_bulk_partial", "search_scope_all", "search_scope_tooltip", "settings_card_engine", + "settings_card_save_path", "shortcuts_activate", "shortcuts_close", "shortcuts_cmd_palette", @@ -1712,12 +1800,23 @@ "queue_installed", "queue_installed_warn", "queue_will_install", + "save_path_hint", + "save_path_label", + "save_path_reset", + "saves_backup_usb", + "saves_backup_usb_all", + "saves_backup_usb_low_space", + "saves_backup_usb_no_volume", + "saves_backup_usb_summary", + "saves_backup_usb_summary_failed", + "saves_backup_usb_tooltip", "saves_open_folder", "saves_open_folder_hint", "screenshots_bulk_partial", "search_scope_all", "search_scope_tooltip", "settings_card_engine", + "settings_card_save_path", "shortcuts_activate", "shortcuts_close", "shortcuts_cmd_palette", @@ -1908,12 +2007,23 @@ "queue_installed", "queue_installed_warn", "queue_will_install", + "save_path_hint", + "save_path_label", + "save_path_reset", + "saves_backup_usb", + "saves_backup_usb_all", + "saves_backup_usb_low_space", + "saves_backup_usb_no_volume", + "saves_backup_usb_summary", + "saves_backup_usb_summary_failed", + "saves_backup_usb_tooltip", "saves_open_folder", "saves_open_folder_hint", "screenshots_bulk_partial", "search_scope_all", "search_scope_tooltip", "settings_card_engine", + "settings_card_save_path", "shortcuts_activate", "shortcuts_close", "shortcuts_cmd_palette", @@ -2104,12 +2214,23 @@ "queue_installed", "queue_installed_warn", "queue_will_install", + "save_path_hint", + "save_path_label", + "save_path_reset", + "saves_backup_usb", + "saves_backup_usb_all", + "saves_backup_usb_low_space", + "saves_backup_usb_no_volume", + "saves_backup_usb_summary", + "saves_backup_usb_summary_failed", + "saves_backup_usb_tooltip", "saves_open_folder", "saves_open_folder_hint", "screenshots_bulk_partial", "search_scope_all", "search_scope_tooltip", "settings_card_engine", + "settings_card_save_path", "shortcuts_activate", "shortcuts_close", "shortcuts_cmd_palette", @@ -2300,12 +2421,23 @@ "queue_installed", "queue_installed_warn", "queue_will_install", + "save_path_hint", + "save_path_label", + "save_path_reset", + "saves_backup_usb", + "saves_backup_usb_all", + "saves_backup_usb_low_space", + "saves_backup_usb_no_volume", + "saves_backup_usb_summary", + "saves_backup_usb_summary_failed", + "saves_backup_usb_tooltip", "saves_open_folder", "saves_open_folder_hint", "screenshots_bulk_partial", "search_scope_all", "search_scope_tooltip", "settings_card_engine", + "settings_card_save_path", "shortcuts_activate", "shortcuts_close", "shortcuts_cmd_palette", @@ -2496,12 +2628,23 @@ "queue_installed", "queue_installed_warn", "queue_will_install", + "save_path_hint", + "save_path_label", + "save_path_reset", + "saves_backup_usb", + "saves_backup_usb_all", + "saves_backup_usb_low_space", + "saves_backup_usb_no_volume", + "saves_backup_usb_summary", + "saves_backup_usb_summary_failed", + "saves_backup_usb_tooltip", "saves_open_folder", "saves_open_folder_hint", "screenshots_bulk_partial", "search_scope_all", "search_scope_tooltip", "settings_card_engine", + "settings_card_save_path", "shortcuts_activate", "shortcuts_close", "shortcuts_cmd_palette", @@ -2692,12 +2835,23 @@ "queue_installed", "queue_installed_warn", "queue_will_install", + "save_path_hint", + "save_path_label", + "save_path_reset", + "saves_backup_usb", + "saves_backup_usb_all", + "saves_backup_usb_low_space", + "saves_backup_usb_no_volume", + "saves_backup_usb_summary", + "saves_backup_usb_summary_failed", + "saves_backup_usb_tooltip", "saves_open_folder", "saves_open_folder_hint", "screenshots_bulk_partial", "search_scope_all", "search_scope_tooltip", "settings_card_engine", + "settings_card_save_path", "shortcuts_activate", "shortcuts_close", "shortcuts_cmd_palette", @@ -2888,12 +3042,23 @@ "queue_installed", "queue_installed_warn", "queue_will_install", + "save_path_hint", + "save_path_label", + "save_path_reset", + "saves_backup_usb", + "saves_backup_usb_all", + "saves_backup_usb_low_space", + "saves_backup_usb_no_volume", + "saves_backup_usb_summary", + "saves_backup_usb_summary_failed", + "saves_backup_usb_tooltip", "saves_open_folder", "saves_open_folder_hint", "screenshots_bulk_partial", "search_scope_all", "search_scope_tooltip", "settings_card_engine", + "settings_card_save_path", "shortcuts_activate", "shortcuts_close", "shortcuts_cmd_palette", @@ -3084,12 +3249,23 @@ "queue_installed", "queue_installed_warn", "queue_will_install", + "save_path_hint", + "save_path_label", + "save_path_reset", + "saves_backup_usb", + "saves_backup_usb_all", + "saves_backup_usb_low_space", + "saves_backup_usb_no_volume", + "saves_backup_usb_summary", + "saves_backup_usb_summary_failed", + "saves_backup_usb_tooltip", "saves_open_folder", "saves_open_folder_hint", "screenshots_bulk_partial", "search_scope_all", "search_scope_tooltip", "settings_card_engine", + "settings_card_save_path", "shortcuts_activate", "shortcuts_close", "shortcuts_cmd_palette", @@ -3280,12 +3456,23 @@ "queue_installed", "queue_installed_warn", "queue_will_install", + "save_path_hint", + "save_path_label", + "save_path_reset", + "saves_backup_usb", + "saves_backup_usb_all", + "saves_backup_usb_low_space", + "saves_backup_usb_no_volume", + "saves_backup_usb_summary", + "saves_backup_usb_summary_failed", + "saves_backup_usb_tooltip", "saves_open_folder", "saves_open_folder_hint", "screenshots_bulk_partial", "search_scope_all", "search_scope_tooltip", "settings_card_engine", + "settings_card_save_path", "shortcuts_activate", "shortcuts_close", "shortcuts_cmd_palette", From c01f88173e84b1fffdd2986026c81011e4220694 Mon Sep 17 00:00:00 2001 From: phantomptr <phantomptr@gmail.com> Date: Sun, 28 Jun 2026 22:56:08 +0800 Subject: [PATCH 2/4] chore(deps): bump engine, tauri-shell, frontend and actions groups MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Folds in dependabot #153, #158, #159, #160, reapplied on current main so the lockfiles regenerate cleanly: - engine: anyhow 1.0.103, sevenz-rust2 0.21.1, uuid 1.23.4 - desktop: anyhow 1.0.103, flume 0.12.0, mdns-sd 0.20.1, socket-pktinfo 0.4.0, uuid 1.23.4 - client (dev): @tauri-apps/cli 2.11.3, @vitejs/plugin-react 6.0.3, eslint 10.6.0, vite 8.1.0 - CI: actions/cache v5 -> v6 Verified: engine workspace tests, desktop cargo check, client typecheck/lint/754 tests/vite build, i18n gate — all green. --- .github/workflows/engine-ci.yml | 6 +- .github/workflows/publish.yml | 2 +- client/package-lock.json | 300 ++++++++++++++++---------------- client/package.json | 8 +- client/src-tauri/Cargo.lock | 46 ++--- engine/Cargo.lock | 12 +- 6 files changed, 187 insertions(+), 187 deletions(-) diff --git a/.github/workflows/engine-ci.yml b/.github/workflows/engine-ci.yml index 91b1ff4c..e30f03b3 100644 --- a/.github/workflows/engine-ci.yml +++ b/.github/workflows/engine-ci.yml @@ -65,7 +65,7 @@ jobs: components: rustfmt, clippy - name: Cache cargo registry + target - uses: actions/cache@v5 + uses: actions/cache@v6 with: path: | ~/.cargo/registry @@ -171,7 +171,7 @@ jobs: libclang-dev - name: Cache cargo target - uses: actions/cache@v5 + uses: actions/cache@v6 with: path: | ~/.cargo/registry @@ -420,7 +420,7 @@ jobs: targets: aarch64-linux-android - name: Cache cargo target - uses: actions/cache@v5 + uses: actions/cache@v6 with: path: | ~/.cargo/registry diff --git a/.github/workflows/publish.yml b/.github/workflows/publish.yml index fd0166e2..915fc4ca 100644 --- a/.github/workflows/publish.yml +++ b/.github/workflows/publish.yml @@ -162,7 +162,7 @@ jobs: targets: ${{ matrix.rust_target }} - name: Cache cargo target - uses: actions/cache@v5 + uses: actions/cache@v6 with: path: | ~/.cargo/registry diff --git a/client/package-lock.json b/client/package-lock.json index a589a5be..9bc06c60 100644 --- a/client/package-lock.json +++ b/client/package-lock.json @@ -25,17 +25,17 @@ "devDependencies": { "@eslint/js": "^10.0.1", "@tailwindcss/vite": "^4.3.1", - "@tauri-apps/cli": "^2.11.2", + "@tauri-apps/cli": "^2.11.3", "@types/react": "^19.2.17", "@types/react-dom": "^19.2.3", - "@vitejs/plugin-react": "^6.0.2", + "@vitejs/plugin-react": "^6.0.3", "@vitest/coverage-v8": "^4.1.9", - "eslint": "^10.5.0", + "eslint": "^10.6.0", "eslint-plugin-react-hooks": "^7.1.1", "tailwindcss": "^4.0.0", "typescript": "^6.0.3", "typescript-eslint": "^8.61.1", - "vite": "^8.0.16", + "vite": "^8.1.0", "vitest": "^4.1.4" } }, @@ -290,21 +290,21 @@ } }, "node_modules/@emnapi/core": { - "version": "1.10.0", - "resolved": "https://registry.npmjs.org/@emnapi/core/-/core-1.10.0.tgz", - "integrity": "sha512-yq6OkJ4p82CAfPl0u9mQebQHKPJkY7WrIuk205cTYnYe+k2Z8YBh11FrbRG/H6ihirqcacOgl2BIO8oyMQLeXw==", + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@emnapi/core/-/core-1.11.1.tgz", + "integrity": "sha512-RSvbQmHzdKzNsLYa/wHrbc3KN4sYLKAdPZxqiM2HATqv/SBk2/ENSHpvXGaLOMcsAyz0poEGqkmmKYG3OWiJEQ==", "dev": true, "license": "MIT", "optional": true, "dependencies": { - "@emnapi/wasi-threads": "1.2.1", + "@emnapi/wasi-threads": "1.2.2", "tslib": "^2.4.0" } }, "node_modules/@emnapi/runtime": { - "version": "1.10.0", - "resolved": "https://registry.npmjs.org/@emnapi/runtime/-/runtime-1.10.0.tgz", - "integrity": "sha512-ewvYlk86xUoGI0zQRNq/mC+16R1QeDlKQy21Ki3oSYXNgLb45GV1P6A0M+/s6nyCuNDqe5VpaY84BzXGwVbwFA==", + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@emnapi/runtime/-/runtime-1.11.1.tgz", + "integrity": "sha512-vgj7R3y3Wgx24IQaGPA/R6YFXLHVMOZ0uVEyIQPaWs+rd1AzfEMXlAC22FYwO1XkKR6NPsq7mUandH8oIRdZFw==", "dev": true, "license": "MIT", "optional": true, @@ -313,9 +313,9 @@ } }, "node_modules/@emnapi/wasi-threads": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/@emnapi/wasi-threads/-/wasi-threads-1.2.1.tgz", - "integrity": "sha512-uTII7OYF+/Mes/MrcIOYp5yOtSMLBWSIoLPpcgwipoiKbli6k322tcoFsxoIIxPDqW01SQGAgko4EzZi2BNv2w==", + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/@emnapi/wasi-threads/-/wasi-threads-1.2.2.tgz", + "integrity": "sha512-c95qOXkHdydNKhscBTebqEC1CVAZpyqOfVfBzQ1qgzyl3gfeldUjIggDbIZgDKsHLgnsM+igH7TJ/eAasaVuMA==", "dev": true, "license": "MIT", "optional": true, @@ -568,14 +568,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", - "integrity": "sha512-3NQNNgA1YSlJb/kMH1ildASP9HW7/7kYnRI2szWJaofaS1hWmbGI4H+d3+22aGzXXN9IJ+n+GiFVcGipJP18ow==", + "version": "1.1.6", + "resolved": "https://registry.npmjs.org/@napi-rs/wasm-runtime/-/wasm-runtime-1.1.6.tgz", + "integrity": "sha512-ZLv/JdUfkvOy9eCnnBaGfiO+XimbjebAeO+MRQqD/B+FR1tnRN0tpKSJHRbE8sFfS6aqsXZ67TQjfwfsxULVbg==", "dev": true, "license": "MIT", "optional": true, "dependencies": { - "@tybys/wasm-util": "^0.10.1" + "@tybys/wasm-util": "^0.10.3" }, "funding": { "type": "github", @@ -587,9 +587,9 @@ } }, "node_modules/@oxc-project/types": { - "version": "0.133.0", - "resolved": "https://registry.npmjs.org/@oxc-project/types/-/types-0.133.0.tgz", - "integrity": "sha512-KzkdCd6Uxqnf6l3HOw1xfatAlUURA0g14cvBYFyJ5SaNOQbOUvBr9PKArcPcrNIeRsBdgcUzOGrhKveVpvOIGA==", + "version": "0.137.0", + "resolved": "https://registry.npmjs.org/@oxc-project/types/-/types-0.137.0.tgz", + "integrity": "sha512-WT+Gb24i8hmvo85AIv2oEYouEXkRlKAlT9WaCa3TfLgNCN+GhrJOGZuIlMouAh38Qe4QOx26eUOVsq70qXrywA==", "dev": true, "license": "MIT", "funding": { @@ -597,9 +597,9 @@ } }, "node_modules/@rolldown/binding-android-arm64": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/@rolldown/binding-android-arm64/-/binding-android-arm64-1.0.3.tgz", - "integrity": "sha512-454rs7jHngixp/NMxd5srYD57OnzSlZ/eFTETjORQHLwJG1lRtmNOJcBerZlfu4GjKqeq8aCCIQrMdHyhI51Hw==", + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/@rolldown/binding-android-arm64/-/binding-android-arm64-1.1.3.tgz", + "integrity": "sha512-DT6Z3PhvioeHMvxo+xHc3KtqggrI7CCTXCmC2h/5zUlp5jVitv7XEy+9q5/7v8IolhlioawpMo8Kg0EEBy7J0g==", "cpu": [ "arm64" ], @@ -614,9 +614,9 @@ } }, "node_modules/@rolldown/binding-darwin-arm64": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/@rolldown/binding-darwin-arm64/-/binding-darwin-arm64-1.0.3.tgz", - "integrity": "sha512-PcAhP+ynjURNyy8SKGl5DQP94aGuB/7JrXJb/t7P+hanXvQVMWzUvRRhBAcg/lNRadBhoUPqSoP4xw5tR/KBEA==", + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/@rolldown/binding-darwin-arm64/-/binding-darwin-arm64-1.1.3.tgz", + "integrity": "sha512-0NwgwsjM7LrsuVnXMK3koTpagBNOhloc/BNjKqZjv4V5zI5r13qx69uVhRx+o5Z0yy4Hzq+lpy7TAgUG/ocvrw==", "cpu": [ "arm64" ], @@ -631,9 +631,9 @@ } }, "node_modules/@rolldown/binding-darwin-x64": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/@rolldown/binding-darwin-x64/-/binding-darwin-x64-1.0.3.tgz", - "integrity": "sha512-9YpfeUvSE2RS7wysJ81uOZkXJz7f7Q55H2Gvp3VEw/EsahqDtrphrZ0EwDLK5vvKOzaCrBsjF8JmnMLcUt78Gg==", + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/@rolldown/binding-darwin-x64/-/binding-darwin-x64-1.1.3.tgz", + "integrity": "sha512-YtiBp4disu6V560loT6PjMdiRaWmVvDNrUunAalbiFx2ggeJwxdAsgZMcoGP17uyAsTwAj5V1niksxlHnVQ1Sw==", "cpu": [ "x64" ], @@ -648,9 +648,9 @@ } }, "node_modules/@rolldown/binding-freebsd-x64": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/@rolldown/binding-freebsd-x64/-/binding-freebsd-x64-1.0.3.tgz", - "integrity": "sha512-yB1IlAsSNHncV6SCTL27/MVGR5htvQsoGxIv5KMGXALp+Ll1wYsn+x98M9MW7qa+NdSbvrrY7ANI4wLJ0n1e6g==", + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/@rolldown/binding-freebsd-x64/-/binding-freebsd-x64-1.1.3.tgz", + "integrity": "sha512-yD3EkEdXk2LypPxnf/kSZHirarsI8gcPzc62SukhR9VJTyvV+F9Q/GxWNuCojc7sXyuVC4DxRGhdDK4X8VSsbw==", "cpu": [ "x64" ], @@ -665,9 +665,9 @@ } }, "node_modules/@rolldown/binding-linux-arm-gnueabihf": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-arm-gnueabihf/-/binding-linux-arm-gnueabihf-1.0.3.tgz", - "integrity": "sha512-Yi30IVAAfLUCy2MseFjbB1jAMDl1VMCAas5StnYp8da9+CKvMd2H2cbEjWcw5NPaPqzvYkVIaF1nNUG+b7u/sw==", + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-arm-gnueabihf/-/binding-linux-arm-gnueabihf-1.1.3.tgz", + "integrity": "sha512-c+8vieQbsD7HNAHKIA34w0GJ9FedFFuJGD+7E6vz7Q3uqAIugL5p45fhlsj4UaAsHpcmlqugBWMhA0/j7o0sIg==", "cpu": [ "arm" ], @@ -682,9 +682,9 @@ } }, "node_modules/@rolldown/binding-linux-arm64-gnu": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-arm64-gnu/-/binding-linux-arm64-gnu-1.0.3.tgz", - "integrity": "sha512-jsO7R8To+AdlYgUmN5sHSCZbfhtMBkO0WUx8iORQnPcMMdgr7qM2DQmMwgabs3GhNztdmoKkMKQFHD6DTMCIQw==", + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-arm64-gnu/-/binding-linux-arm64-gnu-1.1.3.tgz", + "integrity": "sha512-50jD0uUwLvur7Zz9LHz17kaAdTPjn5wN93hEgjvmYFRZwiR7ZJYovTd5ipyWJDAnXKvZ+wgc+/Ika6dwSF5OcA==", "cpu": [ "arm64" ], @@ -699,9 +699,9 @@ } }, "node_modules/@rolldown/binding-linux-arm64-musl": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-arm64-musl/-/binding-linux-arm64-musl-1.0.3.tgz", - "integrity": "sha512-VWkUHwWriDciit80wleYwKILoR/KMvxh/IdwS/paX+ZgpuRpCrKLUdadJbc0NpBEiyhpYawsJ73j9aCvOH+f7Q==", + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-arm64-musl/-/binding-linux-arm64-musl-1.1.3.tgz", + "integrity": "sha512-BO9+oPL8K9poZJBfYPsXNtYjPE5uM3qeehT3aFcW4LITOl+iSqhp0abzjR2nWBUNjIZeKXjAEWBZ64WjNoHd6w==", "cpu": [ "arm64" ], @@ -716,9 +716,9 @@ } }, "node_modules/@rolldown/binding-linux-ppc64-gnu": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-ppc64-gnu/-/binding-linux-ppc64-gnu-1.0.3.tgz", - "integrity": "sha512-5f1laC0SlIR0yDbFCd8acUhvJIag6N3zC5P7oUPN6wX0aOma+uKJ0wBDH5aq7I1PVI2ttTlhJwzwRIBnLiSGEg==", + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-ppc64-gnu/-/binding-linux-ppc64-gnu-1.1.3.tgz", + "integrity": "sha512-f3VpLB1vQ0Eo6ecr/6cekLnvYMFF4YBFoVGkfkvPLq1bAkbAwHYQPZKoAmG6OJyTcxxoC+AvezGx/S1obNC0Mw==", "cpu": [ "ppc64" ], @@ -733,9 +733,9 @@ } }, "node_modules/@rolldown/binding-linux-s390x-gnu": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-s390x-gnu/-/binding-linux-s390x-gnu-1.0.3.tgz", - "integrity": "sha512-Iq4ko0r4XsgbrF/LunNgHtAGLRRVE2kXonAXQ/MV0mC6jQpMOhW1SvtZja2EhC/kd05++bP78dsqBeIQyYJ6Yg==", + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-s390x-gnu/-/binding-linux-s390x-gnu-1.1.3.tgz", + "integrity": "sha512-AmurZ26Pqx/RI9N1gzEOCklkKXl927yjfXWUUS0O7Puh8ARM/Ob8qfrD3qnWksScdw6cSrW5PSHE9DyLu7+PtA==", "cpu": [ "s390x" ], @@ -750,9 +750,9 @@ } }, "node_modules/@rolldown/binding-linux-x64-gnu": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-x64-gnu/-/binding-linux-x64-gnu-1.0.3.tgz", - "integrity": "sha512-B8m6tD5+/N5FeNQFbKlLA/2yVq9ycQP1SeedyEYYKWBNR3ZQbkvIUcNnDNM03lO1l5F2roiiFJGgvoLLyZXtSg==", + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-x64-gnu/-/binding-linux-x64-gnu-1.1.3.tgz", + "integrity": "sha512-JJpqs8bRGITDOdbkNKnlojzBabbOHrqjSvDr0IVsZObE1lBcPjxItUEY9eWIDbxaJ3cGrXPWGfGkIxFijg/URg==", "cpu": [ "x64" ], @@ -767,9 +767,9 @@ } }, "node_modules/@rolldown/binding-linux-x64-musl": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-x64-musl/-/binding-linux-x64-musl-1.0.3.tgz", - "integrity": "sha512-pSdpdUJHkuCxun9LE7jvgUB9qsRgaiyNNCX7m/AvHTcq67AiT/Yhoxvw5zPfhrM8k/BfP8ce/hMOpthKDpEUow==", + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-x64-musl/-/binding-linux-x64-musl-1.1.3.tgz", + "integrity": "sha512-rSJcdjPxzA/by/6/rYs+v+bXU7UjvnbUWz8MJb6kh6+knqB1dCrtHg0uu7C/4haqJvqdkYHQ5IGn+tCH9GLW/g==", "cpu": [ "x64" ], @@ -784,9 +784,9 @@ } }, "node_modules/@rolldown/binding-openharmony-arm64": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/@rolldown/binding-openharmony-arm64/-/binding-openharmony-arm64-1.0.3.tgz", - "integrity": "sha512-OXXS3RKJgX2uLwM+gYyuH5omcH8fL1LJs96pZGgtetVCahON57+d4SJHzTgZiOjxgGkSnpXpOsWuPDGAKAigEg==", + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/@rolldown/binding-openharmony-arm64/-/binding-openharmony-arm64-1.1.3.tgz", + "integrity": "sha512-hQ3/PYkDJICgevvyNcVrihVeqq7k1Pp3VZ9lY+dauAYUJKO+auqApvANhvR1An9BhmqYKvW2Mu1F9u4DXSMLxQ==", "cpu": [ "arm64" ], @@ -801,9 +801,9 @@ } }, "node_modules/@rolldown/binding-wasm32-wasi": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/@rolldown/binding-wasm32-wasi/-/binding-wasm32-wasi-1.0.3.tgz", - "integrity": "sha512-JTtb8BWFynicNSoPrehsCzBtOKjZ6jhMiPFEmOiuXg1Fl8dn2KHQob+GuPSGR0dryQa1PQJbzjF3dqO/whhjLg==", + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/@rolldown/binding-wasm32-wasi/-/binding-wasm32-wasi-1.1.3.tgz", + "integrity": "sha512-Elcv/BtML9lXrV6JuKITc/grN2kYV9gjsQpW8Jfw4ioK0TOkjBjye0nnyqQNy9STNaI20lXNaQBRrD5gSgR0Yg==", "cpu": [ "wasm32" ], @@ -811,18 +811,18 @@ "license": "MIT", "optional": true, "dependencies": { - "@emnapi/core": "1.10.0", - "@emnapi/runtime": "1.10.0", - "@napi-rs/wasm-runtime": "^1.1.4" + "@emnapi/core": "1.11.1", + "@emnapi/runtime": "1.11.1", + "@napi-rs/wasm-runtime": "^1.1.6" }, "engines": { "node": "^20.19.0 || >=22.12.0" } }, "node_modules/@rolldown/binding-win32-arm64-msvc": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/@rolldown/binding-win32-arm64-msvc/-/binding-win32-arm64-msvc-1.0.3.tgz", - "integrity": "sha512-gEdFFEN70A/jxb2svrWsN3aDL7OUtmvlOy+6fa2jxG8K0wQ1ZbdeLGnidov6Yu5/733dI5ySfzFlQ/cb0bSz1g==", + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/@rolldown/binding-win32-arm64-msvc/-/binding-win32-arm64-msvc-1.1.3.tgz", + "integrity": "sha512-2DrEfhluH9yhiaFApmsjsjwrSYbNcY1oFTzYSP1a535jDbV98zCFanA/96TBUd0iDFcxGmw9QRExwGCXz3U+/g==", "cpu": [ "arm64" ], @@ -837,9 +837,9 @@ } }, "node_modules/@rolldown/binding-win32-x64-msvc": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/@rolldown/binding-win32-x64-msvc/-/binding-win32-x64-msvc-1.0.3.tgz", - "integrity": "sha512-eXB7CHuaQdqmJcc3koCNtNPmT/bj2gc999kUFgBxG8Ac0NdgXc4rkCHhqrgrhN3zddvvvrgzj1e90SuSfmyIXA==", + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/@rolldown/binding-win32-x64-msvc/-/binding-win32-x64-msvc-1.1.3.tgz", + "integrity": "sha512-OL4OMk7UPXOeVGGd3qo5zJyPIljf4AFgk5QAkPPS+OoLuOOozhuaQGC18MxVTnw/06q93gShAJzlwnSCY9YtqA==", "cpu": [ "x64" ], @@ -1216,9 +1216,9 @@ } }, "node_modules/@tauri-apps/cli": { - "version": "2.11.2", - "resolved": "https://registry.npmjs.org/@tauri-apps/cli/-/cli-2.11.2.tgz", - "integrity": "sha512-bk3HemqvGRoy+5D/dVMUQHKMYLglD0jVnMm/0iGMH6ufZ+p8r14m6BpIixwij3PBvZdvORUp1YifTD8QxVZ1Nw==", + "version": "2.11.3", + "resolved": "https://registry.npmjs.org/@tauri-apps/cli/-/cli-2.11.3.tgz", + "integrity": "sha512-EElQe8z8uD7Pi5++tJ/UfEwWuK08rd3oCDYdeIbJAb6pZRrxlqmoF5gh5H5YvzmUPhS4IRCaLSsQhvWkrfK+GQ==", "dev": true, "license": "Apache-2.0 OR MIT", "bin": { @@ -1232,23 +1232,23 @@ "url": "https://opencollective.com/tauri" }, "optionalDependencies": { - "@tauri-apps/cli-darwin-arm64": "2.11.2", - "@tauri-apps/cli-darwin-x64": "2.11.2", - "@tauri-apps/cli-linux-arm-gnueabihf": "2.11.2", - "@tauri-apps/cli-linux-arm64-gnu": "2.11.2", - "@tauri-apps/cli-linux-arm64-musl": "2.11.2", - "@tauri-apps/cli-linux-riscv64-gnu": "2.11.2", - "@tauri-apps/cli-linux-x64-gnu": "2.11.2", - "@tauri-apps/cli-linux-x64-musl": "2.11.2", - "@tauri-apps/cli-win32-arm64-msvc": "2.11.2", - "@tauri-apps/cli-win32-ia32-msvc": "2.11.2", - "@tauri-apps/cli-win32-x64-msvc": "2.11.2" + "@tauri-apps/cli-darwin-arm64": "2.11.3", + "@tauri-apps/cli-darwin-x64": "2.11.3", + "@tauri-apps/cli-linux-arm-gnueabihf": "2.11.3", + "@tauri-apps/cli-linux-arm64-gnu": "2.11.3", + "@tauri-apps/cli-linux-arm64-musl": "2.11.3", + "@tauri-apps/cli-linux-riscv64-gnu": "2.11.3", + "@tauri-apps/cli-linux-x64-gnu": "2.11.3", + "@tauri-apps/cli-linux-x64-musl": "2.11.3", + "@tauri-apps/cli-win32-arm64-msvc": "2.11.3", + "@tauri-apps/cli-win32-ia32-msvc": "2.11.3", + "@tauri-apps/cli-win32-x64-msvc": "2.11.3" } }, "node_modules/@tauri-apps/cli-darwin-arm64": { - "version": "2.11.2", - "resolved": "https://registry.npmjs.org/@tauri-apps/cli-darwin-arm64/-/cli-darwin-arm64-2.11.2.tgz", - "integrity": "sha512-+4UZzLt+eOAEQCwgd+TqKgyUJMrvx+BgdXLLaqJYmPqzP+nE6YZr/hY6CWLYGQb8jFn99jEkmC6uA3tNvamA1w==", + "version": "2.11.3", + "resolved": "https://registry.npmjs.org/@tauri-apps/cli-darwin-arm64/-/cli-darwin-arm64-2.11.3.tgz", + "integrity": "sha512-BxpaM8bsCoXs3wd4WKYhas/G1gs7+r7B+e4WnyRk2GEoVOouJB1hoL6E6YLXZDXbYci6VFdrNnobQwd2uVL4ew==", "cpu": [ "arm64" ], @@ -1263,9 +1263,9 @@ } }, "node_modules/@tauri-apps/cli-darwin-x64": { - "version": "2.11.2", - "resolved": "https://registry.npmjs.org/@tauri-apps/cli-darwin-x64/-/cli-darwin-x64-2.11.2.tgz", - "integrity": "sha512-VjYYtZUPqDMLutSfJEyxFE3Bz+DPi7c8wC3imckgvciLDZLq4qwKJxBicg0BXGhXjJsl8vKWgWRFNMPELQ+Xyg==", + "version": "2.11.3", + "resolved": "https://registry.npmjs.org/@tauri-apps/cli-darwin-x64/-/cli-darwin-x64-2.11.3.tgz", + "integrity": "sha512-DbZYuPB1ZEzcAHYeyCvo3ltzM27+aXwPloCrtexPnmgPgulYJm3TOq6aC4S+wPhSXteddg8zImtNkvx/gQzmwg==", "cpu": [ "x64" ], @@ -1280,9 +1280,9 @@ } }, "node_modules/@tauri-apps/cli-linux-arm-gnueabihf": { - "version": "2.11.2", - "resolved": "https://registry.npmjs.org/@tauri-apps/cli-linux-arm-gnueabihf/-/cli-linux-arm-gnueabihf-2.11.2.tgz", - "integrity": "sha512-yMemD6f4i95AQriS8EazyOFzbE34yjnP16i3IOzpHGQvBoy2DjypFMFBq0NtPuITURv/cOGguRtHR5d79/9CSA==", + "version": "2.11.3", + "resolved": "https://registry.npmjs.org/@tauri-apps/cli-linux-arm-gnueabihf/-/cli-linux-arm-gnueabihf-2.11.3.tgz", + "integrity": "sha512-741NduqBmz1XkdU8yz3OI/kBZtqHbvxo9F9ytIeWYU69/Ba9dcZEbqOU++Dp0G/XU8vAI0TfTywEl+p+BbLvaA==", "cpu": [ "arm" ], @@ -1297,9 +1297,9 @@ } }, "node_modules/@tauri-apps/cli-linux-arm64-gnu": { - "version": "2.11.2", - "resolved": "https://registry.npmjs.org/@tauri-apps/cli-linux-arm64-gnu/-/cli-linux-arm64-gnu-2.11.2.tgz", - "integrity": "sha512-cgI91D2wL8GSgoWwZXDqt+DwnuZCP2/bz03QAE4TrhgAKIsrB4hX26W/H1EONPUUNkqrsgeCD0wU6pcNjV/5kw==", + "version": "2.11.3", + "resolved": "https://registry.npmjs.org/@tauri-apps/cli-linux-arm64-gnu/-/cli-linux-arm64-gnu-2.11.3.tgz", + "integrity": "sha512-RWAXT8pTqIczXcoic+LXlo6uEbAXGB0cgh6Pg7Y9xVnEbzryQ1JHtRGj9SxzrKSemBIDBH6Qc24kK2G69i8ofA==", "cpu": [ "arm64" ], @@ -1314,9 +1314,9 @@ } }, "node_modules/@tauri-apps/cli-linux-arm64-musl": { - "version": "2.11.2", - "resolved": "https://registry.npmjs.org/@tauri-apps/cli-linux-arm64-musl/-/cli-linux-arm64-musl-2.11.2.tgz", - "integrity": "sha512-X1rm0BERqAAggtYTESSgXrS3sz4Sb/OiPiz54UqISlXW+GkR3vNIGnsy/lejNmoXGVqri3Q53BCfQiclOIyRPw==", + "version": "2.11.3", + "resolved": "https://registry.npmjs.org/@tauri-apps/cli-linux-arm64-musl/-/cli-linux-arm64-musl-2.11.3.tgz", + "integrity": "sha512-qomqYS+yAkd0gXMRmhguWXc7RfVN+XKKXaEwbf5QmKURwydLFOTldd6F8/WoZDSsBMrV8dpNxz0YneGLmobiSA==", "cpu": [ "arm64" ], @@ -1331,9 +1331,9 @@ } }, "node_modules/@tauri-apps/cli-linux-riscv64-gnu": { - "version": "2.11.2", - "resolved": "https://registry.npmjs.org/@tauri-apps/cli-linux-riscv64-gnu/-/cli-linux-riscv64-gnu-2.11.2.tgz", - "integrity": "sha512-usbMLJbT3KtkOrBMDVeGYNM35aTHXx38SJSzTMSqqjeUIOQ+iVPjb2yAGNAE+KqmBbAx4FOFIyMeKXx2M/JKGQ==", + "version": "2.11.3", + "resolved": "https://registry.npmjs.org/@tauri-apps/cli-linux-riscv64-gnu/-/cli-linux-riscv64-gnu-2.11.3.tgz", + "integrity": "sha512-jOCXbDqeDj5XcclsOBAaXjtTgwZCVg8zEZ+dbPUCoADOgljFgL0rOkYTc96vUYgOrYEfuHYihWMxIDGaD6GwJw==", "cpu": [ "riscv64" ], @@ -1348,9 +1348,9 @@ } }, "node_modules/@tauri-apps/cli-linux-x64-gnu": { - "version": "2.11.2", - "resolved": "https://registry.npmjs.org/@tauri-apps/cli-linux-x64-gnu/-/cli-linux-x64-gnu-2.11.2.tgz", - "integrity": "sha512-Ru4gwJKPG0ctVGchRGpRup4Y4lW2SSfFnrbQcyHhCliKy4g8Qz97TrUgCur4CbWyAgKxvGh3SjrkA0LDYzDGiw==", + "version": "2.11.3", + "resolved": "https://registry.npmjs.org/@tauri-apps/cli-linux-x64-gnu/-/cli-linux-x64-gnu-2.11.3.tgz", + "integrity": "sha512-+u3HO/F3gHwL48t9gWN/urqZvpaEJzBFmTaq5eSIhvy8TOvnhb+LgJr3Q3BG+5JxuBrCUjqtOEz6gMttdJFSBA==", "cpu": [ "x64" ], @@ -1365,9 +1365,9 @@ } }, "node_modules/@tauri-apps/cli-linux-x64-musl": { - "version": "2.11.2", - "resolved": "https://registry.npmjs.org/@tauri-apps/cli-linux-x64-musl/-/cli-linux-x64-musl-2.11.2.tgz", - "integrity": "sha512-eUm7T6clN1MMmNSRQ9gaWsQdyehQx2Gmn5hht/QUlqZQI/qcP2OJK5dnaxqwFzCr2HdsEo9ydxaqcS1oJzMvUw==", + "version": "2.11.3", + "resolved": "https://registry.npmjs.org/@tauri-apps/cli-linux-x64-musl/-/cli-linux-x64-musl-2.11.3.tgz", + "integrity": "sha512-spr5Jpr6KF/vehkLwJ0YmdGv8QwpWU+uw7J8bgijO0sox6ZCYsSNMbcsQjTqPi4xl+p0woIYpWXgChgHYpAc8g==", "cpu": [ "x64" ], @@ -1382,9 +1382,9 @@ } }, "node_modules/@tauri-apps/cli-win32-arm64-msvc": { - "version": "2.11.2", - "resolved": "https://registry.npmjs.org/@tauri-apps/cli-win32-arm64-msvc/-/cli-win32-arm64-msvc-2.11.2.tgz", - "integrity": "sha512-HeeZW80jU+gVTOEX4X/hC6NVSAdDVXajwP5fxIZ/3z9WvUC7qrudX2GMTilYq6Dg0e0sk0XgsAJD1hZ5wPBXUA==", + "version": "2.11.3", + "resolved": "https://registry.npmjs.org/@tauri-apps/cli-win32-arm64-msvc/-/cli-win32-arm64-msvc-2.11.3.tgz", + "integrity": "sha512-abkoRQih5xBa3vz2spWaex0kP/MzVzVPQHom2f8jnCq46R/luOD6Uy85EMU9/bfzf6ZzdorWJsgO+OMX90Fx2w==", "cpu": [ "arm64" ], @@ -1399,9 +1399,9 @@ } }, "node_modules/@tauri-apps/cli-win32-ia32-msvc": { - "version": "2.11.2", - "resolved": "https://registry.npmjs.org/@tauri-apps/cli-win32-ia32-msvc/-/cli-win32-ia32-msvc-2.11.2.tgz", - "integrity": "sha512-YhjQNZcXfbkCLyazSv1nPnJ9iRFE1wm6kc51FDbU10/Dk09io+6PAGMLjkxnX2GdM0qMnDmTjstY8mTDVvtKeA==", + "version": "2.11.3", + "resolved": "https://registry.npmjs.org/@tauri-apps/cli-win32-ia32-msvc/-/cli-win32-ia32-msvc-2.11.3.tgz", + "integrity": "sha512-Vy6AvzFm1G40hg3r+OYDB3jkuu7R4wnMzbQBKuun9v6Cgg8IierpLL7toMzrZKs/8NlG8Sg4x1iLFR52oknyHg==", "cpu": [ "ia32" ], @@ -1416,9 +1416,9 @@ } }, "node_modules/@tauri-apps/cli-win32-x64-msvc": { - "version": "2.11.2", - "resolved": "https://registry.npmjs.org/@tauri-apps/cli-win32-x64-msvc/-/cli-win32-x64-msvc-2.11.2.tgz", - "integrity": "sha512-d2JchlFIpZevZVReyqhQOekJmb1UH3rhZ5VX6sH3ty9ETE0TKQavpihvoScUXfKKpW6HZC0MrFGRU0ZtD+w3gA==", + "version": "2.11.3", + "resolved": "https://registry.npmjs.org/@tauri-apps/cli-win32-x64-msvc/-/cli-win32-x64-msvc-2.11.3.tgz", + "integrity": "sha512-GlciF75GdbseajOyib2aCHwE3BXIqZ1liGKWLFRvCdN5wm8h8hFssEVKQ/6E+2jsMLg9v7LCTb983YFnn0QSww==", "cpu": [ "x64" ], @@ -1478,9 +1478,9 @@ } }, "node_modules/@tybys/wasm-util": { - "version": "0.10.2", - "resolved": "https://registry.npmjs.org/@tybys/wasm-util/-/wasm-util-0.10.2.tgz", - "integrity": "sha512-RoBvJ2X0wuKlWFIjrwffGw1IqZHKQqzIchKaadZZfnNpsAYp2mM0h36JtPCjNDAHGgYez/15uMBpfGwchhiMgg==", + "version": "0.10.3", + "resolved": "https://registry.npmjs.org/@tybys/wasm-util/-/wasm-util-0.10.3.tgz", + "integrity": "sha512-F3fo1MYrRJYL3zER0OUOmkutjr1Vp23m7OsSgp7nq4SP6OqX6C/56XFIPAl5bt3zaBRjmW7SGz3u/6LwFpYcOg==", "dev": true, "license": "MIT", "optional": true, @@ -1791,13 +1791,13 @@ } }, "node_modules/@vitejs/plugin-react": { - "version": "6.0.2", - "resolved": "https://registry.npmjs.org/@vitejs/plugin-react/-/plugin-react-6.0.2.tgz", - "integrity": "sha512-DlSMqo4WhThw4vB8Mpn0Woe9J+Jfq1geJ61AKW0QEgLzGMNwtIMdxbDUzLxcun8W7NbJO0e2Jg/Nxm3cCSVzzg==", + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/@vitejs/plugin-react/-/plugin-react-6.0.3.tgz", + "integrity": "sha512-vmFvco5/QuC2f9Oj+wTk0+9XeDFkHxSamwZKYc7MxYwKICfvUvlMhqKI0VuICPltGqh1neqBKDvO4kes1ya8vg==", "dev": true, "license": "MIT", "dependencies": { - "@rolldown/pluginutils": "^1.0.0" + "@rolldown/pluginutils": "^1.0.1" }, "engines": { "node": "^20.19.0 || >=22.12.0" @@ -2268,9 +2268,9 @@ } }, "node_modules/eslint": { - "version": "10.5.0", - "resolved": "https://registry.npmjs.org/eslint/-/eslint-10.5.0.tgz", - "integrity": "sha512-1y+7C+vi12bUK1IpZeaV3gsH9fHLBmPvYmPx42pvT/E9yG0IC8g3PUZZgp0+JLJl7ZDK0flc2gc+Aw9dpCvIsQ==", + "version": "10.6.0", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-10.6.0.tgz", + "integrity": "sha512-6lVbcqSodALYo+4ELD0heG6lFiFxnLMuLkiMi2qV8LMp54N8tE8FT1GMH+ev4Ti00nFjNze2+Su6DsV5OQW3Dg==", "dev": true, "license": "MIT", "workspaces": [ @@ -3434,13 +3434,13 @@ } }, "node_modules/rolldown": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/rolldown/-/rolldown-1.0.3.tgz", - "integrity": "sha512-i00lAJ2ks1BYr7rjNjKC7BcqAS7nVfiT3QX1SI5aY+AFHblCmaUf9OE9dbdzDvW6dJxbi2ZCZiy9v3CcwOiX3g==", + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/rolldown/-/rolldown-1.1.3.tgz", + "integrity": "sha512-1F1eEtUBtFvcGm1HQ9TiUIUHPQG7mSAODrhIzjxoUEFuo8OcbrGLiVLkevNgj84TE4lnHvnumwFjhJO5Eu135g==", "dev": true, "license": "MIT", "dependencies": { - "@oxc-project/types": "=0.133.0", + "@oxc-project/types": "=0.137.0", "@rolldown/pluginutils": "^1.0.0" }, "bin": { @@ -3450,21 +3450,21 @@ "node": "^20.19.0 || >=22.12.0" }, "optionalDependencies": { - "@rolldown/binding-android-arm64": "1.0.3", - "@rolldown/binding-darwin-arm64": "1.0.3", - "@rolldown/binding-darwin-x64": "1.0.3", - "@rolldown/binding-freebsd-x64": "1.0.3", - "@rolldown/binding-linux-arm-gnueabihf": "1.0.3", - "@rolldown/binding-linux-arm64-gnu": "1.0.3", - "@rolldown/binding-linux-arm64-musl": "1.0.3", - "@rolldown/binding-linux-ppc64-gnu": "1.0.3", - "@rolldown/binding-linux-s390x-gnu": "1.0.3", - "@rolldown/binding-linux-x64-gnu": "1.0.3", - "@rolldown/binding-linux-x64-musl": "1.0.3", - "@rolldown/binding-openharmony-arm64": "1.0.3", - "@rolldown/binding-wasm32-wasi": "1.0.3", - "@rolldown/binding-win32-arm64-msvc": "1.0.3", - "@rolldown/binding-win32-x64-msvc": "1.0.3" + "@rolldown/binding-android-arm64": "1.1.3", + "@rolldown/binding-darwin-arm64": "1.1.3", + "@rolldown/binding-darwin-x64": "1.1.3", + "@rolldown/binding-freebsd-x64": "1.1.3", + "@rolldown/binding-linux-arm-gnueabihf": "1.1.3", + "@rolldown/binding-linux-arm64-gnu": "1.1.3", + "@rolldown/binding-linux-arm64-musl": "1.1.3", + "@rolldown/binding-linux-ppc64-gnu": "1.1.3", + "@rolldown/binding-linux-s390x-gnu": "1.1.3", + "@rolldown/binding-linux-x64-gnu": "1.1.3", + "@rolldown/binding-linux-x64-musl": "1.1.3", + "@rolldown/binding-openharmony-arm64": "1.1.3", + "@rolldown/binding-wasm32-wasi": "1.1.3", + "@rolldown/binding-win32-arm64-msvc": "1.1.3", + "@rolldown/binding-win32-x64-msvc": "1.1.3" } }, "node_modules/scheduler": { @@ -3735,16 +3735,16 @@ } }, "node_modules/vite": { - "version": "8.0.16", - "resolved": "https://registry.npmjs.org/vite/-/vite-8.0.16.tgz", - "integrity": "sha512-h9bXPmJichP5fLmVQo3PyaGSDE2n3aPuomeAlVRm0JLmt4rY6zmPKd59HYI4LNW8oTK7tlTsuC7l/m7awx9Jcw==", + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/vite/-/vite-8.1.0.tgz", + "integrity": "sha512-BuJcQK/56NQTWDGn4ABea3q4SSBdNPWwNZKTkkUpcMPnLoquSYH8llRtSUIgoL1KSCpHt5eghLShn50mH36y7Q==", "dev": true, "license": "MIT", "dependencies": { "lightningcss": "^1.32.0", "picomatch": "^4.0.4", "postcss": "^8.5.15", - "rolldown": "1.0.3", + "rolldown": "~1.1.2", "tinyglobby": "^0.2.17" }, "bin": { @@ -3761,7 +3761,7 @@ }, "peerDependencies": { "@types/node": "^20.19.0 || >=22.12.0", - "@vitejs/devtools": "^0.1.18", + "@vitejs/devtools": "^0.3.0", "esbuild": "^0.27.0 || ^0.28.0", "jiti": ">=1.21.0", "less": "^4.0.0", diff --git a/client/package.json b/client/package.json index a9244753..083701bf 100644 --- a/client/package.json +++ b/client/package.json @@ -43,17 +43,17 @@ "devDependencies": { "@eslint/js": "^10.0.1", "@tailwindcss/vite": "^4.3.1", - "@tauri-apps/cli": "^2.11.2", + "@tauri-apps/cli": "^2.11.3", "@types/react": "^19.2.17", "@types/react-dom": "^19.2.3", - "@vitejs/plugin-react": "^6.0.2", + "@vitejs/plugin-react": "^6.0.3", "@vitest/coverage-v8": "^4.1.9", - "eslint": "^10.5.0", + "eslint": "^10.6.0", "eslint-plugin-react-hooks": "^7.1.1", "tailwindcss": "^4.0.0", "typescript": "^6.0.3", "typescript-eslint": "^8.61.1", - "vite": "^8.0.16", + "vite": "^8.1.0", "vitest": "^4.1.4" }, "overrides": { diff --git a/client/src-tauri/Cargo.lock b/client/src-tauri/Cargo.lock index f8b2c6c4..655d7476 100644 --- a/client/src-tauri/Cargo.lock +++ b/client/src-tauri/Cargo.lock @@ -43,9 +43,9 @@ dependencies = [ [[package]] name = "anyhow" -version = "1.0.102" +version = "1.0.103" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7f202df86484c868dbad7eaa557ef785d5c66295e41b460ef922eca0723b842c" +checksum = "2a4385e2e34eb35d6b3efe798b9eb88096925d87726c0798709bf56d9ed84af3" [[package]] name = "arrayref" @@ -903,7 +903,7 @@ dependencies = [ "libc", "option-ext", "redox_users", - "windows-sys 0.61.2", + "windows-sys 0.59.0", ] [[package]] @@ -1104,7 +1104,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "39cab71617ae0d63f51a36d69f866391735b51691dbda63cf6f96d042b63efeb" dependencies = [ "libc", - "windows-sys 0.61.2", + "windows-sys 0.52.0", ] [[package]] @@ -1172,9 +1172,9 @@ dependencies = [ [[package]] name = "flume" -version = "0.11.1" +version = "0.12.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "da0e4dd2a88388a1f4ccc7c9ce104604dab68d9f408dc34cd45823d5a9069095" +checksum = "5e139bc46ca777eb5efaf62df0ab8cc5fd400866427e56c68b22e414e53bd3be" dependencies = [ "futures-core", "futures-sink", @@ -2465,9 +2465,9 @@ checksum = "47e1ffaa40ddd1f3ed91f717a33c8c0ee23fff369e3aa8772b9605cc1d22f4c3" [[package]] name = "mdns-sd" -version = "0.20.0" +version = "0.20.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "892f96f6d2ebe1ea641279f986ac52a2a6bac71e8f743bb258315cfe2bd7e88e" +checksum = "fb75febbe5fa1837a52fdbd1c735e168286c5c645fc2ddd31526f65c49941c2e" dependencies = [ "fastrand", "flume", @@ -2554,7 +2554,7 @@ dependencies = [ "png 0.18.1", "serde", "thiserror 2.0.18", - "windows-sys 0.61.2", + "windows-sys 0.60.2", ] [[package]] @@ -2891,7 +2891,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7d8fae84b431384b68627d0f9b3b1245fcf9f46f6c0e3dc902e9dce64edd1967" dependencies = [ "libc", - "windows-sys 0.61.2", + "windows-sys 0.45.0", ] [[package]] @@ -3475,7 +3475,7 @@ dependencies = [ "once_cell", "socket2", "tracing", - "windows-sys 0.60.2", + "windows-sys 0.52.0", ] [[package]] @@ -3841,7 +3841,7 @@ dependencies = [ "errno", "libc", "linux-raw-sys 0.12.1", - "windows-sys 0.61.2", + "windows-sys 0.52.0", ] [[package]] @@ -4297,13 +4297,13 @@ checksum = "67b1b7a3b5fe4f1376887184045fcf45c69e92af734b7aaddc05fb777b6fbd03" [[package]] name = "socket-pktinfo" -version = "0.3.2" +version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "927136cc2ae6a1b0e66ac6b1210902b75c3f726db004a73bc18686dcd0dcd22f" +checksum = "3e8e43b4bdce7cff8a4d3f8025ee38fce5ca138fab868ebbf9529c81328fbf9d" dependencies = [ "libc", "socket2", - "windows-sys 0.60.2", + "windows-sys 0.61.2", ] [[package]] @@ -4313,7 +4313,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3a766e1110788c36f4fa1c2b71b387a7815aa65f88ce0229841826633d93723e" dependencies = [ "libc", - "windows-sys 0.61.2", + "windows-sys 0.60.2", ] [[package]] @@ -4934,10 +4934,10 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "32497e9a4c7b38532efcdebeef879707aa9f794296a4f0244f6f69e9bc8574bd" dependencies = [ "fastrand", - "getrandom 0.4.2", + "getrandom 0.3.4", "once_cell", "rustix 1.1.4", - "windows-sys 0.61.2", + "windows-sys 0.52.0", ] [[package]] @@ -5351,7 +5351,7 @@ dependencies = [ "png 0.18.1", "serde", "thiserror 2.0.18", - "windows-sys 0.61.2", + "windows-sys 0.60.2", ] [[package]] @@ -5386,7 +5386,7 @@ checksum = "f2f6fb2847f6742cd76af783a2a2c49e9375d0a111c7bef6f71cd9e738c72d6e" dependencies = [ "memoffset", "tempfile", - "windows-sys 0.61.2", + "windows-sys 0.60.2", ] [[package]] @@ -5516,9 +5516,9 @@ checksum = "b6c140620e7ffbb22c2dee59cafe6084a59b5ffc27a8859a5f0d494b5d52b6be" [[package]] name = "uuid" -version = "1.23.3" +version = "1.23.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "144d6b123cef80b301b8f72a9e2ca4370ddec21950d0a103dd22c437006d2db7" +checksum = "bf80a72845275afea99e7f2b434723d3bc7e38470fcd1c7ed39a599c73319a53" dependencies = [ "getrandom 0.4.2", "js-sys", @@ -5889,7 +5889,7 @@ version = "0.1.11" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c2a7b1c03c876122aa43f3020e6c3c3ee5c05081c9a00739faf7503aeba10d22" dependencies = [ - "windows-sys 0.61.2", + "windows-sys 0.52.0", ] [[package]] diff --git a/engine/Cargo.lock b/engine/Cargo.lock index ad3e0f24..50789877 100644 --- a/engine/Cargo.lock +++ b/engine/Cargo.lock @@ -51,9 +51,9 @@ checksum = "940b3a0ca603d1eade50a4846a2afffd5ef57a9feac2c0e2ec2e14f9ead76000" [[package]] name = "anyhow" -version = "1.0.102" +version = "1.0.103" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7f202df86484c868dbad7eaa557ef785d5c66295e41b460ef922eca0723b842c" +checksum = "2a4385e2e34eb35d6b3efe798b9eb88096925d87726c0798709bf56d9ed84af3" [[package]] name = "arrayref" @@ -1199,9 +1199,9 @@ dependencies = [ [[package]] name = "sevenz-rust2" -version = "0.21.0" +version = "0.21.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dbbd24232798280d6bc896e3429a3469174de008ec8b1b591a96618b46664195" +checksum = "081a399c6762c4a9bda9233f502aca74b6ca6a0caaff4d218b12887eac4b6adc" dependencies = [ "aes", "bzip2", @@ -1480,9 +1480,9 @@ dependencies = [ [[package]] name = "uuid" -version = "1.23.3" +version = "1.23.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "144d6b123cef80b301b8f72a9e2ca4370ddec21950d0a103dd22c437006d2db7" +checksum = "bf80a72845275afea99e7f2b434723d3bc7e38470fcd1c7ed39a599c73319a53" dependencies = [ "getrandom", "js-sys", From 4da8bd57b8ff88971e04f1e3e1996c22e999e0f5 Mon Sep 17 00:00:00 2001 From: phantomptr <phantomptr@gmail.com> Date: Sun, 28 Jun 2026 23:03:51 +0800 Subject: [PATCH 3/4] fix(payloads): correct the ps5-app-dumper and Itemzflow catalogue repos (#82) Both 404'd in the Payloads catalogue because their GitHub repos moved: - ps5-app-dumper: ps5-payload-dev -> EchoStretch (ships ps5-app-dumper.elf) - Itemzflow: LightningMods/itemzflow_PS5 -> LightningMods/Itemzflow Resolving the repos replaces the hard 404 with the real release list. (Itemzflow is distributed as a .pkg app, so its releases may not always carry a payload asset, but the repo now resolves.) The dead git.etawen.dev lapy-jb-daemon entry is left as-is pending a decision on the community GitHub fork. --- client/src-tauri/src/commands/payloads.rs | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/client/src-tauri/src/commands/payloads.rs b/client/src-tauri/src/commands/payloads.rs index 59eb5e76..5d52097d 100644 --- a/client/src-tauri/src/commands/payloads.rs +++ b/client/src-tauri/src/commands/payloads.rs @@ -308,7 +308,10 @@ const CATALOGUE: &[CatalogueEntry] = &[ role: "Dump installed apps to USB", description: "Dumps installed PS5 apps to USB or internal storage in fakepkg/folder format. Reads config from /data/ps5-app-dumper/config.ini.", repo_host: "github.com", - repo_owner: "ps5-payload-dev", + // The releases live under EchoStretch, not ps5-payload-dev (the old + // owner 404s — GitHub issue #82). EchoStretch/ps5-app-dumper ships + // ps5-app-dumper.elf on each tag. + repo_owner: "EchoStretch", repo_name: "ps5-app-dumper", asset_name_hint: "dumper", on_console_marker_path: None, @@ -316,7 +319,7 @@ const CATALOGUE: &[CatalogueEntry] = &[ ports: &[], autoload_priority: 4, autoload_delay_ms: 200, - homepage: "https://github.com/ps5-payload-dev/ps5-app-dumper", + homepage: "https://github.com/EchoStretch/ps5-app-dumper", }, CatalogueEntry { id: "itemzflow", @@ -324,15 +327,19 @@ const CATALOGUE: &[CatalogueEntry] = &[ role: "PS5 native homebrew launcher UI", description: "Full-screen native PS5 launcher for homebrew, fpkg games, and FTP browsing. Heavyweight (~50 MB) but the most polished launcher in the scene.", repo_host: "github.com", + // The repo is LightningMods/Itemzflow — "itemzflow_PS5" 404s (GitHub + // issue #82). Note Itemzflow is distributed as a .pkg app, so its GitHub + // releases may not always carry a downloadable payload asset; resolving + // the repo at least replaces the hard 404 with the real release list. repo_owner: "LightningMods", - repo_name: "itemzflow_PS5", + repo_name: "Itemzflow", asset_name_hint: "itemzflow", on_console_marker_path: None, process_name_hint: Some("itemzflow"), ports: &[], autoload_priority: 5, autoload_delay_ms: 200, - homepage: "https://github.com/LightningMods/itemzflow_PS5", + homepage: "https://github.com/LightningMods/Itemzflow", }, CatalogueEntry { // Requested by users. Loads game cheats on-console; pairs with From 364d165f5a6e1bd370ef3949487d2d1f305f6261 Mon Sep 17 00:00:00 2001 From: phantomptr <phantomptr@gmail.com> Date: Sun, 28 Jun 2026 23:03:51 +0800 Subject: [PATCH 4/4] chore(release): 3.3.24 - New: back up a PS5 save directly to a USB drive (thanks @Twice6804) - Fixed: ps5-app-dumper / Itemzflow catalogue 404s (#82) - Dependency + CI bumps (engine, tauri-shell, frontend, actions groups) --- CHANGELOG.md | 12 ++++++++++++ VERSION | 2 +- client/package-lock.json | 4 ++-- client/package.json | 2 +- client/src-tauri/Cargo.lock | 10 +++++----- client/src-tauri/Cargo.toml | 2 +- client/src-tauri/tauri.conf.json | 2 +- engine/Cargo.lock | 14 +++++++------- engine/Cargo.toml | 2 +- payload/include/config.h | 2 +- 10 files changed, 32 insertions(+), 20 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 760b8e76..3bd0c750 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,18 @@ What's new in ps5upload, written for humans. --- +## 3.3.24 + +- **New: back up a PS5 save straight to a USB drive.** From the Saves screen you + can now copy a save (or all of them) to a USB drive plugged into the PS5 — each + backup lands in its own timestamped folder so nothing gets overwritten. There's + a configurable save path in Settings too. *(Thanks to @Twice6804 for the + contribution.)* +- **Fixed: a few payloads in the catalogue showed "Not Found."** ps5-app-dumper + and Itemzflow had moved to different repos and were 404ing in the Payloads + catalogue — both now point at their current homes. +- Routine dependency and CI updates. + ## 3.3.23 - **Fixed: game updates that couldn't install on newer firmware.** When the PS5's diff --git a/VERSION b/VERSION index d244a1e7..894c9158 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -3.3.23 +3.3.24 diff --git a/client/package-lock.json b/client/package-lock.json index 9bc06c60..5989758c 100644 --- a/client/package-lock.json +++ b/client/package-lock.json @@ -1,12 +1,12 @@ { "name": "ps5upload-client", - "version": "3.3.23", + "version": "3.3.24", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "ps5upload-client", - "version": "3.3.23", + "version": "3.3.24", "dependencies": { "@tauri-apps/api": "^2.11.1", "@tauri-apps/plugin-dialog": "^2.7.1", diff --git a/client/package.json b/client/package.json index 083701bf..f914cde7 100644 --- a/client/package.json +++ b/client/package.json @@ -1,7 +1,7 @@ { "name": "ps5upload-client", "private": true, - "version": "3.3.23", + "version": "3.3.24", "description": "The all-in-one PS5 companion app.", "homepage": "https://github.com/phantomptr/ps5upload", "author": "PhantomPtr <phantomptr@gmail.com>", diff --git a/client/src-tauri/Cargo.lock b/client/src-tauri/Cargo.lock index 655d7476..ead1eb9f 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.23" +version = "3.3.24" dependencies = [ "serde", "thiserror 2.0.18", @@ -3319,7 +3319,7 @@ dependencies = [ [[package]] name = "ps5upload-core" -version = "3.3.23" +version = "3.3.24" dependencies = [ "anyhow", "base64 0.22.1", @@ -3336,7 +3336,7 @@ dependencies = [ [[package]] name = "ps5upload-desktop" -version = "3.3.23" +version = "3.3.24" dependencies = [ "anyhow", "base64 0.22.1", @@ -3369,7 +3369,7 @@ dependencies = [ [[package]] name = "ps5upload-engine" -version = "3.3.23" +version = "3.3.24" dependencies = [ "anyhow", "axum", @@ -3387,7 +3387,7 @@ dependencies = [ [[package]] name = "ps5upload-pkg" -version = "3.3.23" +version = "3.3.24" dependencies = [ "serde", "thiserror 2.0.18", diff --git a/client/src-tauri/Cargo.toml b/client/src-tauri/Cargo.toml index 3069c8d4..cdce9cd1 100644 --- a/client/src-tauri/Cargo.toml +++ b/client/src-tauri/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "ps5upload-desktop" -version = "3.3.23" +version = "3.3.24" description = "The all-in-one PS5 companion app." edition = "2021" rust-version = "1.77" diff --git a/client/src-tauri/tauri.conf.json b/client/src-tauri/tauri.conf.json index 77f3ec6c..9e4e8a94 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.23", + "version": "3.3.24", "identifier": "com.phantomptr.ps5upload", "build": { "beforeDevCommand": "npm run dev:vite", diff --git a/engine/Cargo.lock b/engine/Cargo.lock index 50789877..f736cf97 100644 --- a/engine/Cargo.lock +++ b/engine/Cargo.lock @@ -494,7 +494,7 @@ dependencies = [ [[package]] name = "ftx2-proto" -version = "3.3.23" +version = "3.3.24" dependencies = [ "serde", "thiserror", @@ -954,7 +954,7 @@ dependencies = [ [[package]] name = "ps5upload-bench" -version = "3.3.23" +version = "3.3.24" dependencies = [ "criterion", "ftx2-proto", @@ -964,7 +964,7 @@ dependencies = [ [[package]] name = "ps5upload-core" -version = "3.3.23" +version = "3.3.24" dependencies = [ "anyhow", "base64", @@ -981,7 +981,7 @@ dependencies = [ [[package]] name = "ps5upload-engine" -version = "3.3.23" +version = "3.3.24" dependencies = [ "anyhow", "axum", @@ -999,7 +999,7 @@ dependencies = [ [[package]] name = "ps5upload-lab" -version = "3.3.23" +version = "3.3.24" dependencies = [ "anyhow", "ftx2-proto", @@ -1008,7 +1008,7 @@ dependencies = [ [[package]] name = "ps5upload-pkg" -version = "3.3.23" +version = "3.3.24" dependencies = [ "serde", "serde_json", @@ -1017,7 +1017,7 @@ dependencies = [ [[package]] name = "ps5upload-tests" -version = "3.3.23" +version = "3.3.24" dependencies = [ "anyhow", "ftx2-proto", diff --git a/engine/Cargo.toml b/engine/Cargo.toml index 61dc8181..ef960af8 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.23" +version = "3.3.24" [workspace.dependencies] anyhow = "1.0" diff --git a/payload/include/config.h b/payload/include/config.h index 0aa814eb..e77f3d13 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.23" +#define PS5UPLOAD2_VERSION "3.3.24" /* 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