/** * Storage Library for Financial Insight System * Provides a unified interface for data storage with potential for external storage integration */ // Define storage keys for better type safety and avoid string duplication export const STORAGE_KEYS = { CHATS: 'fis-chats', SETTINGS: 'fis-settings', API_ENDPOINT: 'apiEndpoint', THEME: 'fis-theme', SOURCES: 'fis-sources', PROFILE_STORAGE_KEY: 'fis-profile' } as const; // Types for our storage export interface StorageOptions { ttl?: number; // Time to live in milliseconds } export type StorageValue = string | object | number | boolean | null | undefined; /** * Storage service that provides unified interface for storing and retrieving data * Currently uses localStorage, but can be extended to use external storage in the future */ class StorageService { private defaults: Partial> = {}; // Set default values for storage keys setDefaults(defaults: Partial>) { this.defaults = defaults; } // Get item from storage with automatic parsing and default fallback get(key: string): T | null { try { const item = localStorage.getItem(key); if (!item) { // Return default if available if (key in this.defaults) { return this.defaults[key] as T; } return null; } const { value, expires } = JSON.parse(item); if (expires && expires < Date.now()) { this.remove(key); // Return default if available if (key in this.defaults) { return this.defaults[key] as T; } return null; } return value as T; } catch (error) { console.error(`Error getting item from storage: ${key}`, error); // Return default if available if (key in this.defaults) { return this.defaults[key] as T; } return null; } } // Set item in storage with optional TTL set(key: string, value: StorageValue, options: StorageOptions = {}): boolean { try { const storageItem = { value, expires: options.ttl ? Date.now() + options.ttl : null }; localStorage.setItem(key, JSON.stringify(storageItem)); return true; } catch (error) { console.error(`Error setting item in storage: ${key}`, error); return false; } } // Remove item from storage remove(key: string): boolean { try { localStorage.removeItem(key); return true; } catch (error) { console.error(`Error removing item from storage: ${key}`, error); return false; } } // Check if key exists in storage has(key: string): boolean { return localStorage.getItem(key) !== null; } // Clear all storage for the application clear(): boolean { try { // Only clear keys that start with our application prefix (fis-) Object.keys(localStorage).forEach(key => { if (key.startsWith('fis-')) { localStorage.removeItem(key); } }); return true; } catch (error) { console.error('Error clearing storage', error); return false; } } /** * Export all application data for keys defined in STORAGE_KEYS as a JSON object. * Returns an object with key-value pairs. */ export(): Record { const exported: Record = {}; Object.values(STORAGE_KEYS).forEach(key => { try { const item = localStorage.getItem(key); if (item) { exported[key] = JSON.parse(item); } } catch (error) { console.error(`Error exporting key: ${key}`, error); } }); return exported; } /** * Import data from an external source into local storage. * Accepts an object with key-value pairs (as produced by export()). * Overwrites existing keys, but only those defined in STORAGE_KEYS. */ import(data: Record): boolean { try { Object.entries(data).forEach(([key, value]) => { if (Object.values(STORAGE_KEYS).includes(key as any)) { localStorage.setItem(key, JSON.stringify(value)); } }); return true; } catch (error) { console.error('Error importing data into storage', error); return false; } } // Reset all keys to their default values resetToDefaults(): boolean { try { Object.entries(this.defaults).forEach(([key, value]) => { this.set(key, value); }); return true; } catch (error) { console.error('Error resetting storage to defaults', error); return false; } } } // Create and export a singleton instance export const storage = new StorageService(); storage.setDefaults({ [STORAGE_KEYS.CHATS]: [], [STORAGE_KEYS.SETTINGS]: {}, [STORAGE_KEYS.API_ENDPOINT]: "https://insight-ai-api.hf.space", [STORAGE_KEYS.THEME]: "dark", [STORAGE_KEYS.SOURCES]: [], });