feat: add store_versions.ts — localStorage schema versioning for ae_loc and ae_events_loc
Persistent stores grow and change over time. svelte-persisted-store deep-merges old localStorage values with new defaults, so stale values (e.g. hash_prefix_length: 1) silently survive schema changes and cause subtle bugs. - src/lib/stores/store_versions.ts: Single source of truth for AE_LOC_VERSION / AE_EVENTS_LOC_VERSION. Side-effect on import: reads raw localStorage and wipes if __version mismatches. Must be imported first in ae_stores.ts and ae_events_stores.ts so the wipe happens before persisted() hydrates from localStorage. - ae_stores.ts + ae_events_stores.ts: Import store_versions as first import; add __version to persisted store defaults. - documentation/TODO__Agents.md: Added stores refactor task — both store files need a cleanup pass. Bump AE_LOC_VERSION or AE_EVENTS_LOC_VERSION by 1 on breaking schema changes. Non-breaking changes (new optional fields, default value tweaks) do not need a bump. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -7,6 +7,15 @@
|
|||||||
|
|
||||||
## 🚧 Upcoming High Priority
|
## 🚧 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)
|
### [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)
|
- [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)
|
||||||
|
|||||||
@@ -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 { persisted } from 'svelte-persisted-store';
|
||||||
import { writable } from 'svelte/store';
|
import { writable } from 'svelte/store';
|
||||||
import type { 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.
|
// Longer-term app data. This should be stored to *local* storage.
|
||||||
// Updated 2024-03-06
|
// Updated 2024-03-06
|
||||||
const events_local_data_struct: key_val = {
|
const events_local_data_struct: key_val = {
|
||||||
|
__version: AE_EVENTS_LOC_VERSION, // Schema version gate — see store_versions.ts
|
||||||
ver: ver,
|
ver: ver,
|
||||||
ver_idb: ver_idb,
|
ver_idb: ver_idb,
|
||||||
|
|
||||||
|
|||||||
@@ -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 { persisted } from 'svelte-persisted-store';
|
||||||
|
|
||||||
import { readable, writable } from 'svelte/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.
|
// *** BEGIN *** Longer-term app data. This should be stored to local storage.
|
||||||
const ae_app_local_data_defaults: key_val = {
|
const ae_app_local_data_defaults: key_val = {
|
||||||
|
__version: AE_LOC_VERSION, // Schema version gate — see store_versions.ts
|
||||||
last_page_reload: null,
|
last_page_reload: null,
|
||||||
// last_idb_reload: null,
|
// last_idb_reload: null,
|
||||||
// last_cache_refresh: null, // Date.now()
|
// last_cache_refresh: null, // Date.now()
|
||||||
|
|||||||
60
src/lib/stores/store_versions.ts
Normal file
60
src/lib/stores/store_versions.ts
Normal file
@@ -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`);
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user