| 52 | // On fresh installs (no localStorage data) this is a no-op that just writes |
| 53 | // the migration flag so future upgrades can safely clear WebKit. |
| 54 | export async function runStoreMigrationIfNeeded() { |
| 55 | if (!window.__TAURI__?.core?.invoke) return; |
| 56 | try { |
| 57 | // Check if any critical key is absent from the store but present in localStorage. |
| 58 | const needs = await Promise.all( |
| 59 | _MIGRATE_KEYS.map(async (k) => { |
| 60 | const inStore = await window.__TAURI__.core.invoke("store_get", { key: k }); |
| 61 | return inStore === null && localStorage.getItem(k) !== null; |
| 62 | }) |
| 63 | ).then((r) => r.some(Boolean)); |
| 64 | |
| 65 | if (needs) { |
| 66 | // Migrate fixed keys. |
| 67 | for (const k of _MIGRATE_KEYS) { |
| 68 | try { |
| 69 | const raw = localStorage.getItem(k); |
| 70 | if (raw !== null) { |
| 71 | await window.__TAURI__.core.invoke("store_set", { key: k, value: JSON.parse(raw) }); |
| 72 | } |
| 73 | } catch (e) { console.warn("[store] migration failed for key", k, e); } |
| 74 | } |
| 75 | // Migrate per-job mix keys (stemdeck:mix:<jobId>). |
| 76 | for (let i = 0; i < localStorage.length; i++) { |
| 77 | const k = localStorage.key(i); |
| 78 | if (k?.startsWith("stemdeck:mix:")) { |
| 79 | try { |
| 80 | const raw = localStorage.getItem(k); |
| 81 | if (raw !== null) { |
| 82 | await window.__TAURI__.core.invoke("store_set", { key: k, value: JSON.parse(raw) }); |
| 83 | } |
| 84 | } catch (e) { console.warn("[store] migration failed for key", k, e); } |
| 85 | } |
| 86 | } |
| 87 | } |
| 88 | |
| 89 | // Write the flag regardless of whether migration was needed. This covers |
| 90 | // fresh installs (no localStorage data) so future upgrades clear WebKit. |
| 91 | await window.__TAURI__.core.invoke("mark_store_migration_done").catch((e) => |
| 92 | console.warn("[store] mark_store_migration_done failed:", e) |
| 93 | ); |
| 94 | } catch (e) { console.warn("[store] migration error:", e); } |
| 95 | } |
| 96 | |
| 97 | export function fmtTime(s) { |
| 98 | if (!isFinite(s) || s < 0) return "00:00"; |