Local Storage Adapter
The LocalStorageAdapter
extends the abstract StorageAdapter
class, providing a concrete implementation for persisting data to browser's
localStorage
. It offers enhanced capabilities including
encryption, expiration management, metadata tracking, and optional
cross-tab synchronization.
1. Getting Started
Initialize the adapter with the desired options:
import { LocalStorageAdapter } from "storagefy";
const adapter = new LocalStorageAdapter({
dbName: "my-app", // required - creates namespace for your keys
encrypt: true, // optional, default false
version: 1, // optional, default 1
expireCheckInterval: 2000, // optional, default 1000ms
description: "Main app store", // optional
channelName: "main-channel" // optional - used for sync between tabs
enableSyncTabs: false, // optional, default false - Whether to enable sync automatically on change key value
});
The channelName
enables automatic synchronization of data across
open tabs using the CrossTabChannel
communication system, even
for sessionStorage
or when using other adapters that support
channels.
2. Core Concepts
Storage Namespacing
All keys are automatically namespaced using the format {dbName}__
to avoid conflicts with other applications using localStorage. When encryption
is enabled, keys are additionally obfuscated using a simple algorithm.
Encryption
When the encrypt: true
option is set, all values are encrypted
before storage and decrypted when retrieved using the cryptoHelper
module. Keys are also obfuscated to enhance security.
Cross-Tab Communication
When a channelName
is provided, changes to data are broadcast
across browser tabs using the CrossTabChannel
mechanism. This
enables real-time synchronization of state across multiple open instances
of your application.
Expiration Management
The adapter includes a built-in expiration system that automatically
removes expired items at regular intervals (configurable via expireCheckInterval
). This helps manage temporary data without manual cleanup.
3. Test It
wait the animation to finish before go to another tab!
LocalStorage Content:
4. API Reference
await adapter.get(key)
Retrieves a value. Returns null
if not found or expired.
Handles decryption automatically if encryption is enabled.
await adapter.set("theme", "dark");
const value = await adapter.get("theme"); // "dark"
await adapter.set(key, value, expire?)
Stores a value. Optional expire
is in milliseconds from
now. Handles encryption automatically if enabled and broadcasts changes
to other tabs if using a channel.
// Save a theme that expires in 5 seconds
await adapter.set("theme", "dark", 5000);
await adapter.delete(key)
Removes a key and its expiration metadata. Also broadcasts deletion to other tabs if using a channel.
await adapter.delete("theme");
await adapter.list(prefix?)
Returns all keys/values matching the prefix (defaults to all in namespace). Decrypts values if encryption is enabled.
await adapter.set("a", 1);
await adapter.set("b", 2);
const list = await adapter.list();
// [{ key: "a", value: 1 }, { key: "b", value: 2 }]
await adapter.has(key)
Returns true
if the key exists and has not expired.
await adapter.has("a"); // true or false
await adapter.clear()
Clears all data, including metadata and expirations, within this adapter's namespace.
await adapter.clear();
await adapter.reset()
Removes only data keys related to the namespace, not metadata. Useful for clearing user data while preserving system configuration.
await adapter.reset();
await adapter.setExpire(key, timestamp)
Set a custom expiration time (timestamp in ms) for a specific key.
const future = Date.now() + 10000;
await adapter.setExpire("token", future);
await adapter.getExpire(key)
Returns the expiration timestamp for a key, or null
if no
expiration is set.
const expireTime = await adapter.getExpire("token");
// Returns timestamp or null
await adapter.deleteExpire(key)
Removes the expiration for the given key, making it permanent.
await adapter.deleteExpire("token");
await adapter.clearExpire()
Deletes all keys that have expired based on their timestamps.
await adapter.clearExpire();
adapter.destroy()
Cleans up resources, stops the expiration timer, and removes event listeners.
adapter.destroy(); // Clean up before unmounting
adapter.emitDataChange(key, value, origin)
Explicitly broadcasts a data change event to other tabs (usually called automatically by set/delete).
adapter.emitDataChange("settings", newSettings, "tab-123");
adapter.onDataChanged(callback)
Registers a callback function to handle data changes from other tabs or contexts.
adapter.onDataChanged(({ key, value, origin }) => {
console.log(`Data for ${key} changed in tab ${origin}`);
// Update UI or app state accordingly
});
5. Advanced Usage
State Management Integration
The adapter can be used to persist and synchronize state management libraries like Vuex, Pinia, Redux, or Zustand across tabs:
// With Pinia store
const userStore = useUserStore();
// Listen for external changes
adapter.onDataChanged(({ key, value }) => {
if (key === "user-data") {
userStore.updateUser(value);
}
});
// Save changes from this tab
watch(() => userStore.user, (newValue) => {
adapter.set("user-data", newValue);
});
Session Expiration
Managing authentication tokens with automatic expiration:
// Store auth token with expiration
const tokenExpiry = Date.now() + (60 * 60 * 1000); // 1 hour
await adapter.set("auth-token", token, tokenExpiry);
// Check if session is valid
const isLoggedIn = await adapter.has("auth-token");
6. Notes
-
Keys are namespaced under
{dbName}__
to avoid conflicts. - Expirations are automatically checked and removed in intervals (default 1s).
-
Encryption only applies if enabled via
encrypt: true
option. -
Use
channelName
to sync updates across tabs (e.g. for state management libraries). - The adapter handles browser storage limits gracefully with error logging.
- Destroyed adapters should be re-initialized if needed again.