Spaces:
Sleeping
Sleeping
| /** | |
| * LocalStorage wrapper with safe JSON serialization. | |
| * | |
| * All read/write operations are wrapped in try/catch to handle | |
| * environments where localStorage is unavailable (SSR, privacy | |
| * mode, storage quota exceeded, etc.). | |
| */ | |
| // --------------------------------------------------------------------------- | |
| // Availability Check | |
| // --------------------------------------------------------------------------- | |
| /** | |
| * Determine whether localStorage is available and writable. | |
| * | |
| * @returns {boolean} | |
| */ | |
| function isStorageAvailable() { | |
| try { | |
| const testKey = "__storage_test__"; | |
| window.localStorage.setItem(testKey, "1"); | |
| window.localStorage.removeItem(testKey); | |
| return true; | |
| } catch { | |
| return false; | |
| } | |
| } | |
| const storageAvailable = isStorageAvailable(); | |
| // --------------------------------------------------------------------------- | |
| // Core Operations | |
| // --------------------------------------------------------------------------- | |
| /** | |
| * Retrieve a value from localStorage. | |
| * | |
| * @param {string} key - Storage key. | |
| * @param {*} defaultValue - Fallback when the key is absent or unreadable. | |
| * @returns {*} Parsed value or defaultValue. | |
| */ | |
| export function getItem(key, defaultValue = null) { | |
| if (!storageAvailable) { | |
| return defaultValue; | |
| } | |
| try { | |
| const raw = window.localStorage.getItem(key); | |
| if (raw === null) { | |
| return defaultValue; | |
| } | |
| return JSON.parse(raw); | |
| } catch { | |
| return defaultValue; | |
| } | |
| } | |
| /** | |
| * Persist a value to localStorage. | |
| * | |
| * @param {string} key - Storage key. | |
| * @param {*} value - Value to store (will be JSON-serialized). | |
| * @returns {boolean} Whether the write succeeded. | |
| */ | |
| export function setItem(key, value) { | |
| if (!storageAvailable) { | |
| return false; | |
| } | |
| try { | |
| window.localStorage.setItem(key, JSON.stringify(value)); | |
| return true; | |
| } catch (err) { | |
| console.error(`[storage] Failed to write key "${key}":`, err); | |
| return false; | |
| } | |
| } | |
| /** | |
| * Remove a key from localStorage. | |
| * | |
| * @param {string} key - Storage key. | |
| * @returns {boolean} Whether the removal succeeded. | |
| */ | |
| export function removeItem(key) { | |
| if (!storageAvailable) { | |
| return false; | |
| } | |
| try { | |
| window.localStorage.removeItem(key); | |
| return true; | |
| } catch { | |
| return false; | |
| } | |
| } | |
| /** | |
| * Clear all FarmHelp-related entries from localStorage. | |
| * Only removes keys that start with "farmhelp_". | |
| * | |
| * @returns {boolean} Whether the operation succeeded. | |
| */ | |
| export function clearAll() { | |
| if (!storageAvailable) { | |
| return false; | |
| } | |
| try { | |
| const keysToRemove = []; | |
| for (let i = 0; i < window.localStorage.length; i++) { | |
| const key = window.localStorage.key(i); | |
| if (key && key.startsWith("farmhelp_")) { | |
| keysToRemove.push(key); | |
| } | |
| } | |
| keysToRemove.forEach((key) => window.localStorage.removeItem(key)); | |
| return true; | |
| } catch { | |
| return false; | |
| } | |
| } | |
| // --------------------------------------------------------------------------- | |
| // TTL-Based Cache Operations | |
| // --------------------------------------------------------------------------- | |
| /** | |
| * Store a value with an expiration timestamp. | |
| * | |
| * @param {string} key - Storage key. | |
| * @param {*} value - Value to cache. | |
| * @param {number} ttlMs - Time-to-live in milliseconds. | |
| * @returns {boolean} Whether the write succeeded. | |
| */ | |
| export function setWithTTL(key, value, ttlMs) { | |
| const record = { | |
| value, | |
| expiry: Date.now() + ttlMs, | |
| }; | |
| return setItem(key, record); | |
| } | |
| /** | |
| * Retrieve a cached value, returning defaultValue if expired or absent. | |
| * | |
| * @param {string} key - Storage key. | |
| * @param {*} defaultValue - Fallback when expired or absent. | |
| * @returns {*} The cached value or defaultValue. | |
| */ | |
| export function getWithTTL(key, defaultValue = null) { | |
| const record = getItem(key, null); | |
| if (!record || typeof record !== "object" || !record.expiry) { | |
| return defaultValue; | |
| } | |
| if (Date.now() > record.expiry) { | |
| removeItem(key); | |
| return defaultValue; | |
| } | |
| return record.value; | |
| } | |
| // --------------------------------------------------------------------------- | |
| // Convenience Export | |
| // --------------------------------------------------------------------------- | |
| const storage = { | |
| get: getItem, | |
| set: setItem, | |
| remove: removeItem, | |
| clearAll, | |
| setWithTTL, | |
| getWithTTL, | |
| }; | |
| export default storage; | |