isomorphic-store
v0.0.5
Published
IsomorphicStore is a lightweight and flexible TypeScript storage library that provides a consistent data storage API for browser environments. Regardless of whether the underlying storage mechanism is localStorage, sessionStorage, history state, navigatio
Readme
IsomorphicStore 中文
1. Introduction
IsomorphicStore is a lightweight and flexible TypeScript storage library that provides a consistent data storage API for browser environments. Regardless of whether the underlying storage mechanism is localStorage, sessionStorage, history state, navigation state, or in-memory storage, you can access data through a unified interface without modifying business logic.
Key Features:
- Multiple Adapter Support — Five built-in storage strategies available out of the box for quick backend switching.
- Namespace Isolation — Prevents data conflicts between different modules or applications.
- Event System — Subscribe to data changes and respond in real-time.
- Version Management and Migration — Automatically transforms data during upgrades without manual compatibility code.
- Comprehensive Error Handling — Custom error classes for convenient debugging.
- Native TypeScript Support — Complete type safety.
2. Installation
Install using your preferred package manager:
npm install isomorphic-storeOr:
pnpm add isomorphic-store
yarn add isomorphic-store3. Usage
3.1 Basic Example
Create a simple store and perform basic CRUD operations:
import { IsomorphicStore, StorageStrategy } from 'isomorphic-store';
// Create an in-memory store
const store = new IsomorphicStore('my-app:state', StorageStrategy.MEMORY);
// Set data
store.set('username', 'Alice');
store.set('theme', 'dark');
// Read data
console.log(store.get('username')); // 'Alice'
// Remove a single item
store.remove('theme');
// Clear all data
store.clear();
// Destroy the store instance
store.destroy();3.2 Storage Strategies
IsomorphicStore provides five built-in storage strategies. Choose based on your requirements:
3.2.1 LOCAL (localStorage)
Data persists across browser sessions. Suitable for long-term configurations and user preferences.
const settings = new IsomorphicStore('settings', StorageStrategy.LOCAL);
settings.set('theme', 'dark');
// Data remains after browser reload3.2.2 SESSION (sessionStorage)
Session-scoped persistence. Data is cleared when the tab closes. Suitable for session-level temporary data.
const session = new IsomorphicStore('session', StorageStrategy.SESSION);
session.set('authToken', 'abc123');3.2.3 MEMORY
In-memory storage cleared when the process terminates. Suitable for application runtime-only temporary state.
const cache = new IsomorphicStore('cache', StorageStrategy.MEMORY);
cache.set('cachedList', [1, 2, 3]);3.2.4 HISTORY (history.state)
Uses the browser History API, integrated with routing. Suitable for intermediate workflow states.
const flow = new IsomorphicStore('flow', StorageStrategy.HISTORY);
flow.set('currentStep', 2);3.2.5 NAVIGATION (navigation.state)
Asynchronous Navigation API for cross-tab navigation context.
const nav = new IsomorphicStore('nav', StorageStrategy.NAVIGATION);
nav.set('destination', '/home');3.3 Event Subscription
Monitor data changes and respond in real-time:
const store = new IsomorphicStore('app', StorageStrategy.MEMORY);
// Subscribe to all changes
const unsubscribe = store.subscribe(event => {
console.log(`Event: ${event.type}`);
console.log(`Key: ${event.key}`);
console.log(`Old Value: ${event.oldValue}`);
console.log(`New Value: ${event.newValue}`);
console.log(`Timestamp: ${event.timestamp}`);
});
store.set('count', 1); // Trigger subscription
// Output: Event: set, Key: count, New Value: 1
// Unsubscribe
unsubscribe();3.4 Versioning and Migration
Automatically migrate existing data when the data structure is upgraded—no manual transformation required:
// Version 1 data
const storeV1 = new IsomorphicStore('user', StorageStrategy.LOCAL, { version: 1 });
storeV1.set('profile', { name: 'Alice', age: 25 });
storeV1.destroy();
// Upgrade to version 2 with migration rules
const storeV2 = new IsomorphicStore('user', StorageStrategy.LOCAL, {
version: 2,
migrations: [
{
from: 1,
to: 2,
migrate: (data) => ({
name: data.name,
age: data.age,
joinedAt: Date.now() // New field
})
}
]
});
// Data is automatically migrated on read
const profile = storeV2.get('profile');
console.log(profile); // { name: 'Alice', age: 25, joinedAt: 1709... }Multi-level migration:
const store = new IsomorphicStore('data', StorageStrategy.LOCAL, {
version: 3,
migrations: [
{
from: 1,
to: 2,
migrate: data => ({ ...data, v2: true })
},
{
from: 2,
to: 3,
migrate: data => ({ ...data, timestamp: Date.now() })
}
]
});3.5 Namespacing
Each IsomorphicStore instance isolates data through namespaces, preventing conflicts:
// User module
const userStore = new IsomorphicStore('user:profile', StorageStrategy.LOCAL);
userStore.set('name', 'Alice');
// Settings module
const settingsStore = new IsomorphicStore('app:settings', StorageStrategy.LOCAL);
settingsStore.set('theme', 'dark');
// Each operates independently
console.log(userStore.get('name')); // 'Alice'
console.log(settingsStore.get('theme')); // 'dark'
console.log(userStore.get('theme')); // null3.6 Custom Adapters
Extend storage capabilities by registering custom adapters:
import { globalNamespaceRegistry } from 'isomorphic-store';
class IndexedDBAdapter {
get(key) { /* implementation */ }
set(key, value) { /* implementation */ }
remove(key) { /* implementation */ }
clear() { /* implementation */ }
hasKey(key) { /* implementation */ }
}
// Register custom adapter
globalNamespaceRegistry.register('indexeddb', new IndexedDBAdapter());
// Use it
const db = new IsomorphicStore('myapp', 'indexeddb');3.7 TypeScript Usage
IsomorphicStore supports two TypeScript usage patterns:
- Schema mode (recommended): pass a mapping type that maps each key to its value type. TypeScript will infer exact types per key.
- Single-type mode (backward compatible): pass a single type
Tand all keys must conform toT.
Example — Schema mode:
type AppSchema = {
user: { id: number; name: string };
theme: 'light' | 'dark';
isLoggedIn: boolean;
};
const store = new IsomorphicStore<AppSchema>('app', StorageStrategy.LOCAL);
store.set('user', { id: 1, name: 'Alice' }); // ✅ type-safe
store.set('theme', 'dark'); // ✅
// store.set('theme', 'invalid'); // ❌ compile error
const user = store.get('user'); // { id: number; name: string } | nullExample — Single-type mode (backward compatible):
const store = new IsomorphicStore<string>('strings', StorageStrategy.MEMORY);
store.set('k1', 'value');
const v = store.get('k1'); // string | nullMigration notes:
- If you currently use a single-type store and want to migrate to Schema mode, first define the Schema type and then gradually update
set/getusages per key. Schema is compile-time only and has no runtime overhead. - For dynamic or unknown keys, keep using a single-type (e.g.
anyorunknown), or include a more general entry in your Schema (e.g. an index signature).
4. API Reference
IsomorphicStore Class
Constructor
constructor(
namespace: string,
strategy: StorageStrategy | string,
options?: IsomorphicStoreOptions<T>
)namespace(string): Namespace identifier. Stores with the same namespace share data.strategy(StorageStrategy | string): Storage strategy or custom adapter name.options(IsomorphicStoreOptions):version(number): Data version, defaults to 1.migrations(MigrationRule[]): Version migration rules.
Methods
set(key: string, value: T): void
Sets or updates a data item.
store.set('key', 'value');get(key: string): T | null
Retrieves a data item. Executes version migration if needed.
const value = store.get('key');remove(key: string): void
Removes a specific data item.
store.remove('key');clear(): void
Clears all data within the namespace.
store.clear();hasKey(key: string): boolean
Checks if a data item exists.
if (store.hasKey('key')) {
// ...
}subscribe(listener: EventListener): Unsubscribe
Subscribes to data change events. Returns an unsubscribe function.
const unsubscribe = store.subscribe(event => {
console.log(event);
});
unsubscribe();destroy(): void
Destroys the store instance and unloads all listeners.
store.destroy();Event Object
interface IsomorphicStoreEvent<T> {
type: IsomorphicStoreEventType; // 'set' | 'remove' | 'clear'
key?: string; // Key being operated on
oldValue?: T | null | undefined; // Previous value
newValue?: T | null | undefined; // New value
namespace: string; // Namespace
timestamp: number; // Event timestamp in milliseconds
source: IsomorphicStore<T>; // Event source (IsomorphicStore instance)
}Error Types
// Base error class
class IsomorphicStoreError extends Error { }
// Namespace conflict error
class NamespaceConflictError extends IsomorphicStoreError { }
// Migration error
class MigrationError extends IsomorphicStoreError { }
// Adapter error
class AdapterError extends IsomorphicStoreError { }
// Not initialized error
class NotInitializedError extends IsomorphicStoreError { }
// Invalid argument error
class InvalidArgumentError extends IsomorphicStoreError { }Usage example:
import { MigrationError } from 'isomorphic-store';
try {
const store = new IsomorphicStore('app', StorageStrategy.LOCAL, {
version: 3,
migrations: [
{ from: 1, to: 2, migrate: d => d }
// Missing migration rule for 2->3
]
});
store.get('data'); // Throws MigrationError
} catch (err) {
if (err instanceof MigrationError) {
console.error('Migration failed:', err.message);
}
}Exported Types
import {
IsomorphicStore,
StorageStrategy,
IsomorphicStoreEvent,
IsomorphicStoreEventType,
IsomorphicStoreOptions,
MigrationRule,
EventListener,
Unsubscribe,
IStorageAdapter,
globalNamespaceRegistry
} from 'isomorphic-store';5. License
MIT License
Copyright (c) 2025
This project is licensed under the MIT License, allowing free use, modification, and distribution. See the LICENSE file for details.
Core Mechanisms Summary
| Mechanism | Description | Use Case | |-----------|-------------|----------| | Storage Strategy | Five available built-in storage backends | Select persistent or temporary storage based on requirements | | Namespace | Data isolation and organization | Prevent data conflicts in multi-module applications | | Event System | Subscribe to data changes | Real-time UI updates or trigger business logic | | Migration Mechanism | Automatic data upgrade and transformation | Maintain data compatibility during application evolution | | Error Handling | Custom error classes | Precisely capture and locate issues |
For more information and examples, visit the GitHub repository.
