import { createDefu } from 'defu' /** * Abstraction for preferences storage * Currently uses localStorage, designed for future user prefs API */ const STORAGE_KEY = 'npmx-list-prefs' interface StorageProvider { get: () => T | null set: (value: T) => void remove: () => void } const defu = createDefu((object, key, value) => { if (Array.isArray(object[key]) && Array.isArray(value)) { object[key] = value return true } }) /** * Creates a localStorage-based storage provider */ function createLocalStorageProvider(key: string): StorageProvider { return { get: () => { if (import.meta.server) return null try { const stored = localStorage.getItem(key) if (stored) { return JSON.parse(stored) as T } } catch { // Corrupted data, remove it localStorage.removeItem(key) } return null }, set: (value: T) => { if (import.meta.server) return try { localStorage.setItem(key, JSON.stringify(value)) } catch { // Storage full or other error, fail silently } }, remove: () => { if (import.meta.server) return localStorage.removeItem(key) }, } } // Future: API-based provider would look like this: // function createApiStorageProvider(endpoint: string): StorageProvider { // return { // get: async () => { /* fetch from API */ }, // set: async (value) => { /* POST to API */ }, // remove: async () => { /* DELETE from API */ }, // } // } /** * Composable for managing preferences storage * Abstracts the storage mechanism to allow future migration to API-based storage * */ export function usePreferencesProvider(defaultValue: T) { const provider = createLocalStorageProvider(STORAGE_KEY) const data = ref(defaultValue) const isHydrated = shallowRef(false) // Load from storage on client onMounted(() => { const stored = provider.get() if (stored) { // Merge stored values with defaults to handle schema evolution data.value = defu(stored, defaultValue) } isHydrated.value = true }) // Persist changes function save() { provider.set(data.value) } // Reset to defaults function reset() { data.value = { ...defaultValue } provider.remove() } // Update specific keys function update(key: K, value: T[K]) { data.value[key] = value save() } return { data, isHydrated, save, reset, update, } }