Variable storageConst

storage: {
    getItem: (key: string) => null | string;
    setItem: (key: string, value: string) => void;
    removeItem: (key: string) => void;
    clear: () => void;
    setItemAsync: (key: string, value: string) => Promise<void>;
    getItemAsync: (key: string) => Promise<null | string>;
} = ...

Unified storage abstraction across cache, localStorage, and electron-store.

Type declaration

  • getItem: (key: string) => null | string

    Retrieves a value from cache or localStorage.

      getItem: (key: string): string | null => {
    try {
    // Check cache first to avoid redundant reads
    if (key in storageCache) {
    return storageCache[key];
    }

    // Return from localStorage synchronously
    // NOTE: For most accurate data, use getItemAsync() which checks electron-store first
    const value = readLocalStorageValue(key);

    // Cache the value
    if (value !== null) {
    storageCache[key] = value;
    }

    return value;
    } catch (error) {
    captureError(
    ErrorType.STORAGE,
    `Error reading from storage key: ${key}`,
    error instanceof Error ? error : new Error(String(error)),
    { key, operation: "read" },
    );
    return null;
    }
    },
  • setItem: (key: string, value: string) => void

    Stores a value across all storage layers (cache, localStorage, electron-store). Skips writes if the value hasn't changed in the cache.

      setItem: (key: string, value: string): void => {
    try {
    // Redundancy check: skip write if value hasn't changed in cache
    // This prevents unnecessary I/O, but can cause drift if layers get out of sync
    if (storageCache[key] === value) {
    console.debug(`[Storage] 🔍 Skipping redundant write for key: ${key}`);
    return;
    }

    console.debug(
    `[Storage] 🔍 Setting item: ${key} (${value.length} bytes)`,
    );

    // Update cache
    storageCache[key] = value;

    // Store in localStorage for compatibility
    writeLocalStorageValue(key, value);

    // Also store in electronStore if available
    if (globalThis.electronStore) {
    globalThis.electronStore.setItem(key, value).catch((error) => {
    captureError(
    ErrorType.SYSTEM,
    `Error writing to electron-store: ${key}`,
    error instanceof Error ? error : new Error(String(error)),
    { key, operation: "write", target: "electron-store" },
    );
    });
    }
    } catch (error) {
    captureError(
    ErrorType.STORAGE,
    `Error writing to storage key: ${key}`,
    error instanceof Error ? error : new Error(String(error)),
    { key, operation: "write", valueSize: value.length },
    );
    }
    },
  • removeItem: (key: string) => void

    Removes a value from all storage layers.

      removeItem: (key: string): void => {
    try {
    console.debug(`[Storage] 🔍 Removing item: ${key}`);

    // Remove from cache
    delete storageCache[key];

    // Remove from localStorage for compatibility
    removeLocalStorageValue(key);

    // Also remove from electronStore if available
    if (globalThis.electronStore) {
    globalThis.electronStore.removeItem(key).catch((error) => {
    captureError(
    ErrorType.SYSTEM,
    `Error deleting from electron-store: ${key}`,
    error instanceof Error ? error : new Error(String(error)),
    { key, operation: "delete", target: "electron-store" },
    );
    });
    }
    } catch (error) {
    captureError(
    ErrorType.STORAGE,
    `Error deleting storage key: ${key}`,
    error instanceof Error ? error : new Error(String(error)),
    { key, operation: "delete" },
    );
    }
    },
  • clear: () => void

    Clears all storage layers.

      clear: (): void => {
    try {
    console.info("[Storage] 🗑️ Clearing all storage...");

    // Clear cache
    const keyCount = Object.keys(storageCache).length;
    for (const key of Object.keys(storageCache)) {
    delete storageCache[key];
    }

    // Clear localStorage for compatibility
    clearLocalStorageValues();

    // Also clear electronStore if available
    if (globalThis.electronStore) {
    globalThis.electronStore.clear().catch((error) => {
    console.warn("[Storage] ❌ Error clearing electron-store:", error);
    });
    }

    console.info(`[Storage] ✅ Cleared ${keyCount} keys from storage`);
    } catch (error) {
    captureError(
    ErrorType.STORAGE,
    "Error clearing all storage layers",
    error instanceof Error ? error : new Error(String(error)),
    { operation: "clear" },
    );
    }
    },
  • setItemAsync: (key: string, value: string) => Promise<void>

    Stores a value to electron-store (authoritative), then syncs to localStorage.

      setItemAsync: async (key: string, value: string): Promise<void> => {
    if (!globalThis.electronStore) {
    // Fallback to sync method if no electron store
    console.debug(
    `[Storage] 🔍 No electron-store available, using sync setItem for ${key}`,
    );
    storage.setItem(key, value);
    return;
    }

    try {
    console.debug(
    `[Storage] 🔍 Async setting item: ${key} (${value.length} bytes)`,
    );

    // Write to electron-store first (authoritative source)
    await globalThis.electronStore.setItem(key, value);

    // Update cache
    storageCache[key] = value;

    // Sync to localStorage
    writeLocalStorageValue(key, value);

    console.debug(`[Storage] ✅ Async set complete: ${key}`);
    } catch (error) {
    captureError(
    ErrorType.STORAGE,
    `Error async setting item: ${key}`,
    error instanceof Error ? error : new Error(String(error)),
    { key, operation: "write-async", valueSize: value.length },
    );
    throw error;
    }
    },
  • getItemAsync: (key: string) => Promise<null | string>

    Retrieves a value, preferring electron-store (authoritative) over localStorage.

      getItemAsync: async (key: string): Promise<string | null> => {
    if (globalThis.electronStore) {
    try {
    console.debug(`[Storage] 🔍 Async getting item: ${key}`);
    const value = await globalThis.electronStore.getItem(key);
    if (value === null) {
    console.debug(`[Storage] 🔍 Item not found: ${key}`);
    } else {
    console.debug(
    `[Storage] ✅ Found item: ${key} (${value.length} bytes)`,
    );
    writeLocalStorageValue(key, value); // keep localStorage in sync
    storageCache[key] = value;
    }
    return value;
    } catch (error) {
    captureError(
    ErrorType.SYSTEM,
    `Error reading from electron-store: ${key}`,
    error instanceof Error ? error : new Error(String(error)),
    { key, operation: "read-async", target: "electron-store" },
    );
    console.debug(`[Storage] 🔍 Falling back to localStorage for: ${key}`);
    // fallback to localStorage
    return readLocalStorageValue(key);
    }
    }
    // fallback if no electronStore
    console.debug(
    `[Storage] 🔍 No electron-store available, using localStorage for ${key}`,
    );
    return readLocalStorageValue(key);
    },
export const storage = {
/**
* Retrieves a value from cache or localStorage.
* @param key - Storage key.
* @returns The stored value, or null if not found.
* @source
*/
getItem: (key: string): string | null => {
try {
// Check cache first to avoid redundant reads
if (key in storageCache) {
return storageCache[key];
}

// Return from localStorage synchronously
// NOTE: For most accurate data, use getItemAsync() which checks electron-store first
const value = readLocalStorageValue(key);

// Cache the value
if (value !== null) {
storageCache[key] = value;
}

return value;
} catch (error) {
captureError(
ErrorType.STORAGE,
`Error reading from storage key: ${key}`,
error instanceof Error ? error : new Error(String(error)),
{ key, operation: "read" },
);
return null;
}
},

/**
* Stores a value across all storage layers (cache, localStorage, electron-store).
* Skips writes if the value hasn't changed in the cache.
* @param key - Storage key.
* @param value - Value to store.
* @source
*/
setItem: (key: string, value: string): void => {
try {
// Redundancy check: skip write if value hasn't changed in cache
// This prevents unnecessary I/O, but can cause drift if layers get out of sync
if (storageCache[key] === value) {
console.debug(`[Storage] 🔍 Skipping redundant write for key: ${key}`);
return;
}

console.debug(
`[Storage] 🔍 Setting item: ${key} (${value.length} bytes)`,
);

// Update cache
storageCache[key] = value;

// Store in localStorage for compatibility
writeLocalStorageValue(key, value);

// Also store in electronStore if available
if (globalThis.electronStore) {
globalThis.electronStore.setItem(key, value).catch((error) => {
captureError(
ErrorType.SYSTEM,
`Error writing to electron-store: ${key}`,
error instanceof Error ? error : new Error(String(error)),
{ key, operation: "write", target: "electron-store" },
);
});
}
} catch (error) {
captureError(
ErrorType.STORAGE,
`Error writing to storage key: ${key}`,
error instanceof Error ? error : new Error(String(error)),
{ key, operation: "write", valueSize: value.length },
);
}
},

/**
* Removes a value from all storage layers.
* @param key - Storage key to remove.
* @source
*/
removeItem: (key: string): void => {
try {
console.debug(`[Storage] 🔍 Removing item: ${key}`);

// Remove from cache
delete storageCache[key];

// Remove from localStorage for compatibility
removeLocalStorageValue(key);

// Also remove from electronStore if available
if (globalThis.electronStore) {
globalThis.electronStore.removeItem(key).catch((error) => {
captureError(
ErrorType.SYSTEM,
`Error deleting from electron-store: ${key}`,
error instanceof Error ? error : new Error(String(error)),
{ key, operation: "delete", target: "electron-store" },
);
});
}
} catch (error) {
captureError(
ErrorType.STORAGE,
`Error deleting storage key: ${key}`,
error instanceof Error ? error : new Error(String(error)),
{ key, operation: "delete" },
);
}
},

/**
* Clears all storage layers.
* @source
*/
clear: (): void => {
try {
console.info("[Storage] 🗑️ Clearing all storage...");

// Clear cache
const keyCount = Object.keys(storageCache).length;
for (const key of Object.keys(storageCache)) {
delete storageCache[key];
}

// Clear localStorage for compatibility
clearLocalStorageValues();

// Also clear electronStore if available
if (globalThis.electronStore) {
globalThis.electronStore.clear().catch((error) => {
console.warn("[Storage] ❌ Error clearing electron-store:", error);
});
}

console.info(`[Storage] ✅ Cleared ${keyCount} keys from storage`);
} catch (error) {
captureError(
ErrorType.STORAGE,
"Error clearing all storage layers",
error instanceof Error ? error : new Error(String(error)),
{ operation: "clear" },
);
}
},

/**
* Stores a value to electron-store (authoritative), then syncs to localStorage.
* @param key - Storage key.
* @param value - Value to store.
* @returns Promise that resolves when complete.
* @source
*/
setItemAsync: async (key: string, value: string): Promise<void> => {
if (!globalThis.electronStore) {
// Fallback to sync method if no electron store
console.debug(
`[Storage] 🔍 No electron-store available, using sync setItem for ${key}`,
);
storage.setItem(key, value);
return;
}

try {
console.debug(
`[Storage] 🔍 Async setting item: ${key} (${value.length} bytes)`,
);

// Write to electron-store first (authoritative source)
await globalThis.electronStore.setItem(key, value);

// Update cache
storageCache[key] = value;

// Sync to localStorage
writeLocalStorageValue(key, value);

console.debug(`[Storage] ✅ Async set complete: ${key}`);
} catch (error) {
captureError(
ErrorType.STORAGE,
`Error async setting item: ${key}`,
error instanceof Error ? error : new Error(String(error)),
{ key, operation: "write-async", valueSize: value.length },
);
throw error;
}
},
/**
* Retrieves a value, preferring electron-store (authoritative) over localStorage.
* @param key - Storage key.
* @returns Promise resolving to the stored value or null.
* @source
*/
getItemAsync: async (key: string): Promise<string | null> => {
if (globalThis.electronStore) {
try {
console.debug(`[Storage] 🔍 Async getting item: ${key}`);
const value = await globalThis.electronStore.getItem(key);
if (value === null) {
console.debug(`[Storage] 🔍 Item not found: ${key}`);
} else {
console.debug(
`[Storage] ✅ Found item: ${key} (${value.length} bytes)`,
);
writeLocalStorageValue(key, value); // keep localStorage in sync
storageCache[key] = value;
}
return value;
} catch (error) {
captureError(
ErrorType.SYSTEM,
`Error reading from electron-store: ${key}`,
error instanceof Error ? error : new Error(String(error)),
{ key, operation: "read-async", target: "electron-store" },
);
console.debug(`[Storage] 🔍 Falling back to localStorage for: ${key}`);
// fallback to localStorage
return readLocalStorageValue(key);
}
}
// fallback if no electronStore
console.debug(
`[Storage] 🔍 No electron-store available, using localStorage for ${key}`,
);
return readLocalStorageValue(key);
},
};