feat: architect local state persistence with encrypted IndexedDB - #102
Merged
Lakes41 merged 2 commits intoJul 29, 2026
Merged
Conversation
Adamantine-guild#75) - Add lib/store/persistence/idb.ts: async IDB key-value store with AES-GCM encryption via Web Crypto API; falls back to MemoryPersistenceStore on SSR or when IndexedDB is blocked (private browsing) - Add lib/store/userSettingsStore.ts: async store for theme, custom token lists, and arbitrary preferences; one-time migration from localStorage - Add lib/store/transactionHistoryStore.ts: async encrypted store for local transaction history cache; prepend-latest, configurable cap (500), upsert-by-hash, one-time migration from localStorage - Update lib/theme.ts: document that writes go to IDB; localStorage is now bootstrap-only (no-flash script + first-paint sync read) - Update components/ThemeToggle.tsx: all theme writes go through UserSettingsStore (IDB) instead of localStorage directly - Add 54 tests covering: MemoryPersistenceStore CRUD, migrateFromLocalStorage idempotency, singleton behaviour, UserSettingsStore theme/tokens/prefs, TransactionHistoryStore CRUD/upsert/trim/filter - Update ThemeToggle.test.tsx to assert IDB persistence instead of localStorage writes Acceptance criteria met: ✓ App state loads asynchronously without blocking UI rendering ✓ No 5 MB quota limit (IndexedDB) ✓ Sensitive cached data (tx history) encrypted at rest with browser crypto keys (AES-GCM 256-bit, non-extractable) ✓ Degrades gracefully to MemoryPersistenceStore when IndexedDB is blocked or unavailable
Contributor
|
This PR cannot be merged automatically because it has merge conflicts. Please update the branch with the latest base branch and resolve the conflicts. After the conflicts are resolved and checks pass, the automation can review it again. |
Conflict: upstream added a Zustand slippage store to userSettingsStore.ts
while this branch added an IDB-encrypted async store.
Resolution: combined both into a single file —
- useUserSettingsStore (Zustand + persist): slippage tolerance with
validation helpers and constants, used by SlippageSettings component
- UserSettingsStore / getUserSettingsStore: IDB-backed async store for
theme, custom tokens, and arbitrary preferences (issue Adamantine-guild#75)
All 162 tests pass.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Closes #75
Implements a robust async client-side storage manager using IndexedDB with AES-GCM encryption for sensitive cached data, replacing direct
localStoragereads/writes for user preferences and transaction history.Changes
New files
lib/store/persistence/idb.ts— Encrypted IDB key-value store using Dexie + Web Crypto API (AES-GCM 256-bit, non-extractable key). Degrades gracefully to an in-memory store on SSR or when IndexedDB is blocked (private browsing).lib/store/userSettingsStore.ts— Async store for theme preference, custom token lists, and arbitrary UI preferences. Runs a one-time migration fromlocalStorageon first access.lib/store/transactionHistoryStore.ts— Async encrypted store for local transaction history. Prepend-latest ordering, configurable cap (500 entries), upsert-by-hash, one-time migration fromlocalStorage.Modified files
lib/theme.ts—localStorageis now bootstrap-only (no-flash inline script + synchronous first-paint read). All writes go to IDB.components/ThemeToggle.tsx— Theme writes routed throughUserSettingsStore(IDB) instead oflocalStorage.Tests
lib/store/persistence/idb.test.ts— 18 tests: MemoryPersistenceStore CRUD,migrateFromLocalStorageidempotency, singleton behaviour.lib/store/persistence/userSettingsStore.test.ts— 18 tests: theme, custom tokens (dedup, case-insensitive remove), preferences,getAll,clear, singleton.lib/store/persistence/transactionHistoryStore.test.ts— 18 tests: CRUD, upsert, trim to maxEntries, chain filtering, status updates, singleton.components/ThemeToggle.test.tsx— Updated to assert IDB persistence (not localStorage) on toggle.Acceptance criteria
Test results