diff --git a/documentation/TODO__Agents.md b/documentation/TODO__Agents.md index 6b7b5e6c..62d2a05f 100644 --- a/documentation/TODO__Agents.md +++ b/documentation/TODO__Agents.md @@ -7,6 +7,15 @@ ## 🚧 Upcoming High Priority +### [Stores] Refactor — ae_stores.ts and ae_events_stores.ts cleanup +Both files have grown organically and are messy. Refactor goals: +- Split into focused files per domain (core, user/auth, files, module-specific) +- Remove dead/commented-out code and stale `ver`/`ver_idb` constants from data structs (replaced by `__version` in store_versions.ts) +- Standardize field naming conventions +- Move sponsorships/stripe Stripe button IDs out of session store and into config +- Keep `ae_stores.ts` and `ae_events_stores.ts` as barrel re-exports for backwards compatibility +Related: `src/lib/stores/store_versions.ts` is the new home for version constants. + ### [Launcher] Active features (identified 2026-03-06) - [x] **Font size cycler (Launcher sidebar):** Font size cycler and light/dark toggle added to new `menu_launcher_controls.svelte` component; wired into `launcher_menu.svelte`. Visibility toggles (All Files / All Sessions) moved to same component and restyled to `preset-tonal-tertiary`. (2026-03-11) diff --git a/src/lib/stores/ae_events_stores.ts b/src/lib/stores/ae_events_stores.ts index a1b61ae2..8d4a7f16 100644 --- a/src/lib/stores/ae_events_stores.ts +++ b/src/lib/stores/ae_events_stores.ts @@ -1,3 +1,7 @@ +// store_versions MUST be first import — its side-effect wipes stale localStorage +// before svelte-persisted-store hydrates from it. +import { AE_EVENTS_LOC_VERSION } from '$lib/stores/store_versions'; + import { persisted } from 'svelte-persisted-store'; import { writable } from 'svelte/store'; import type { Writable } from 'svelte/store'; @@ -12,6 +16,7 @@ const ver_idb = '2025-10-16_2139'; // Longer-term app data. This should be stored to *local* storage. // Updated 2024-03-06 const events_local_data_struct: key_val = { + __version: AE_EVENTS_LOC_VERSION, // Schema version gate — see store_versions.ts ver: ver, ver_idb: ver_idb, diff --git a/src/lib/stores/ae_stores.ts b/src/lib/stores/ae_stores.ts index 51e45c8a..8f100460 100644 --- a/src/lib/stores/ae_stores.ts +++ b/src/lib/stores/ae_stores.ts @@ -1,3 +1,7 @@ +// store_versions MUST be first import — its side-effect wipes stale localStorage +// before svelte-persisted-store hydrates from it. +import { AE_LOC_VERSION } from '$lib/stores/store_versions'; + import { persisted } from 'svelte-persisted-store'; import { readable, writable } from 'svelte/store'; @@ -62,6 +66,7 @@ const ver_idb = '2025-05-01_1445'; // Not currently used // *** BEGIN *** Longer-term app data. This should be stored to local storage. const ae_app_local_data_defaults: key_val = { + __version: AE_LOC_VERSION, // Schema version gate — see store_versions.ts last_page_reload: null, // last_idb_reload: null, // last_cache_refresh: null, // Date.now() diff --git a/src/lib/stores/store_versions.ts b/src/lib/stores/store_versions.ts new file mode 100644 index 00000000..081f5500 --- /dev/null +++ b/src/lib/stores/store_versions.ts @@ -0,0 +1,60 @@ +/** + * store_versions.ts + * + * Single source of truth for persisted store schema versions. + * + * HOW IT WORKS: + * This file is imported at the top of ae_stores.ts and ae_events_stores.ts. + * ES modules resolve imports before running the importing module's body, + * so the version check + localStorage wipe here runs BEFORE persisted() is + * called — meaning stale data is cleared before svelte-persisted-store + * can hydrate from it. + * + * HOW TO USE: + * When a store schema changes in a breaking way (type change, required + * restructure, field rename that code depends on), bump the relevant version + * by 1. Any client with an older version will have that store silently wiped + * on next page load. They re-initialize from the new defaults. + * + * WHAT COUNTS AS BREAKING: + * - Changing a field's type (e.g. string → object, or null → required object) + * - Renaming a field that code reads directly (not just a display label) + * - Restructuring a nested object that breaks existing property access + * DOES NOT require a bump: + * - Adding a new optional field (svelte-persisted-store deep-merges defaults) + * - Removing a field (old value is ignored, no error) + * - Changing a default value when the stored value being stale is acceptable + * + * localStorage keys: + * 'ae_loc' → AE_LOC_VERSION + * 'ae_events_loc' → AE_EVENTS_LOC_VERSION + */ + +export const AE_LOC_VERSION = 1; +export const AE_EVENTS_LOC_VERSION = 1; + +// Version check side-effect: runs on import, before any persisted() call. +// Guards typeof localStorage for safety (SSR environments, test runners). +if (typeof localStorage !== 'undefined') { + _check_and_wipe('ae_loc', AE_LOC_VERSION); + _check_and_wipe('ae_events_loc', AE_EVENTS_LOC_VERSION); +} + +function _check_and_wipe(key: string, expected_version: number): void { + try { + const raw = localStorage.getItem(key); + if (!raw) return; // No stored value — nothing to wipe. + + const parsed = JSON.parse(raw); + if (parsed?.__version !== expected_version) { + localStorage.removeItem(key); + console.info( + `[store_versions] '${key}' wiped — schema v${parsed?.__version ?? 'none'} → v${expected_version}` + ); + } + } catch { + // Corrupt JSON — wipe unconditionally. + localStorage.removeItem(key); + console.warn(`[store_versions] '${key}' wiped — corrupt JSON in localStorage`); + } +}