@@ -10,7 +10,29 @@ import { ApiClient } from './api-client.js';
1010import { DomHelpers } from '../ui/dom-helpers.js' ;
1111import { MessageLogger } from '../ui/message-logger.js' ;
1212
13- const STORAGE_KEY = 'tbl_user_preferences' ;
13+ // Storage configuration with versioning
14+ const STORAGE_VERSION = 1 ;
15+ const STORAGE_KEY_PREFIX = 'tbl_user_preferences' ;
16+ const STORAGE_KEY = `${ STORAGE_KEY_PREFIX } _v${ STORAGE_VERSION } ` ;
17+
18+ /**
19+ * Validate user preferences structure
20+ * @param {any } data - Data to validate
21+ * @returns {boolean } True if valid
22+ */
23+ function validatePreferences ( data ) {
24+ if ( ! data || typeof data !== 'object' ) return false ;
25+
26+ // Check version
27+ if ( ! ( 'version' in data ) ) return false ;
28+
29+ // Validate types for known fields (non-exhaustive, just critical ones)
30+ if ( 'ttsEnabled' in data && typeof data . ttsEnabled !== 'boolean' ) return false ;
31+ if ( 'textCleanup' in data && typeof data . textCleanup !== 'boolean' ) return false ;
32+ if ( 'refineTranslation' in data && typeof data . refineTranslation !== 'boolean' ) return false ;
33+
34+ return true ;
35+ }
1436
1537/**
1638 * Flag to prevent localStorage from overriding .env default model
@@ -58,6 +80,9 @@ export const SettingsManager = {
5880 * Initialize settings manager - load saved preferences and setup auto-save
5981 */
6082 initialize ( ) {
83+ // Clean up old storage versions
84+ this . cleanupOldStorageVersions ( ) ;
85+
6186 this . loadLocalPreferences ( ) ;
6287 // Setup auto-save listeners after a short delay to avoid triggering during initial load
6388 setTimeout ( ( ) => {
@@ -66,6 +91,41 @@ export const SettingsManager = {
6691 } , 500 ) ;
6792 } ,
6893
94+ /**
95+ * Clean up old localStorage versions
96+ */
97+ cleanupOldStorageVersions ( ) {
98+ try {
99+ // Remove old non-versioned key
100+ const oldKey = 'tbl_user_preferences' ;
101+ if ( localStorage . getItem ( oldKey ) ) {
102+ // Migrate data from old key before removing
103+ const oldData = localStorage . getItem ( oldKey ) ;
104+ if ( oldData ) {
105+ try {
106+ const parsed = JSON . parse ( oldData ) ;
107+ // Add version and save to new key
108+ parsed . version = STORAGE_VERSION ;
109+ localStorage . setItem ( STORAGE_KEY , JSON . stringify ( parsed ) ) ;
110+ } catch ( e ) {
111+ console . warn ( 'Could not migrate old preferences:' , e ) ;
112+ }
113+ }
114+ localStorage . removeItem ( oldKey ) ;
115+ }
116+
117+ // Remove any other versions (future-proofing)
118+ for ( let i = 0 ; i < STORAGE_VERSION ; i ++ ) {
119+ const oldVersionKey = `${ STORAGE_KEY_PREFIX } _v${ i } ` ;
120+ if ( localStorage . getItem ( oldVersionKey ) ) {
121+ localStorage . removeItem ( oldVersionKey ) ;
122+ }
123+ }
124+ } catch ( error ) {
125+ console . warn ( 'Failed to cleanup old storage versions:' , error ) ;
126+ }
127+ } ,
128+
69129 /**
70130 * Setup event listeners for auto-save on all settings elements
71131 * @private
@@ -140,8 +200,30 @@ export const SettingsManager = {
140200 getLocalPreferences ( ) {
141201 try {
142202 const stored = localStorage . getItem ( STORAGE_KEY ) ;
143- return stored ? JSON . parse ( stored ) : { } ;
144- } catch {
203+
204+ if ( ! stored ) return { } ;
205+
206+ const parsed = JSON . parse ( stored ) ;
207+
208+ // Validate structure
209+ if ( ! validatePreferences ( parsed ) ) {
210+ console . warn ( 'Invalid preferences structure, resetting to defaults' ) ;
211+ localStorage . removeItem ( STORAGE_KEY ) ;
212+ return { } ;
213+ }
214+
215+ // Check version compatibility
216+ if ( parsed . version !== STORAGE_VERSION ) {
217+ console . warn ( `Preferences version mismatch (found ${ parsed . version } , expected ${ STORAGE_VERSION } )` ) ;
218+ // Could implement migration here in the future
219+ localStorage . removeItem ( STORAGE_KEY ) ;
220+ return { } ;
221+ }
222+
223+ return parsed ;
224+ } catch ( error ) {
225+ console . error ( 'Failed to load preferences from localStorage:' , error ) ;
226+ MessageLogger . addLog ( '⚠️ Could not load saved preferences' ) ;
145227 return { } ;
146228 }
147229 } ,
@@ -153,10 +235,23 @@ export const SettingsManager = {
153235 saveLocalPreferences ( prefs ) {
154236 try {
155237 const current = this . getLocalPreferences ( ) ;
156- const updated = { ...current , ...prefs } ;
238+ const updated = {
239+ ...current ,
240+ ...prefs ,
241+ version : STORAGE_VERSION ,
242+ timestamp : Date . now ( )
243+ } ;
244+
157245 localStorage . setItem ( STORAGE_KEY , JSON . stringify ( updated ) ) ;
158- } catch {
159- // Preference save failed silently
246+ } catch ( error ) {
247+ console . error ( 'Failed to save preferences to localStorage:' , error ) ;
248+
249+ // Check if it's a quota exceeded error
250+ if ( error . name === 'QuotaExceededError' ) {
251+ MessageLogger . addLog ( '⚠️ Browser storage full, could not save preferences' ) ;
252+ } else {
253+ MessageLogger . addLog ( '⚠️ Failed to save preferences' ) ;
254+ }
160255 }
161256 } ,
162257
0 commit comments