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

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.