@sitharaj08/react-unified-storage
v1.0.1
Published
One unified, secure, and modern storage solution for React.
Maintainers
Readme
@sitharaj08/react-unified-storage
React bindings for unified storage - One unified, secure, and modern storage solution for React applications.
✨ Features
- ⚡ React hooks with automatic re-rendering
- 🚀 TypeScript-first with strict typing and generics
- 🔒 End-to-end encryption with AES-GCM and PBKDF2
- 📦 Automatic compression with gzip
- 🔄 Cross-tab synchronization via BroadcastChannel API
- 💾 Multiple storage drivers (IndexedDB, localStorage, sessionStorage, memory)
- 🛡️ SSR-safe with automatic fallback to in-memory storage
- 📋 Schema validation with Zod integration
- ⏰ TTL support for automatic data expiration
- 🔄 Versioning & migrations for data evolution
- 📊 Metadata tracking (timestamps, driver info, versions)
- 🎯 Tiny bundle (<10KB gzipped)
- 🧪 Comprehensive testing with Vitest
📦 Installation
# React package (includes everything)
npm install @sitharaj08/react-unified-storage
# Peer dependencies
npm install react@^16.8.0🚀 Quick Start
import { StorageProvider, useStore } from '@sitharaj08/react-unified-storage';
function App() {
return (
<StorageProvider config={{ driver: 'auto' }}>
<UserProfile />
</StorageProvider>
);
}
function UserProfile() {
const [user, setUser] = useStore('user', {
defaultValue: { name: 'Anonymous', theme: 'light' }
});
return (
<div>
<h1>Welcome, {user.name}!</h1>
<button onClick={() => setUser({ ...user, theme: 'dark' })}>
Toggle Theme
</button>
</div>
);
}🏗️ Architecture
This package provides React bindings for the core storage functionality. It includes:
StorageProvider- Context provider for configurationuseStore- Hook for individual key-value storageuseStoreSuspense- Suspense-enabled version of useStoreuseCollection- Hook for collection-based storage
📚 API Reference
StorageProvider
<StorageProvider config={config}>
<App />
</StorageProvider>Configuration Options:
interface StorageConfig {
driver?: StorageDriver;
namespace?: string;
broadcast?: boolean;
encryption?: {
key: string;
salt?: string;
};
compression?: boolean;
errorHandler?: (error: Error) => void;
}useStore
const [value, setValue, meta] = useStore<T>(key, options?);Parameters:
key: string- Storage keyoptions?: UseStoreOptions<T>
Returns:
value: T- Current stored valuesetValue: (value: T) => Promise<void>- Update functionmeta?: StorageMeta- Metadata (whenmetadata: true)
Options:
interface UseStoreOptions<T> {
defaultValue?: T;
schema?: z.ZodSchema<T>;
version?: number;
metadata?: boolean;
ttlMs?: number;
}useStoreSuspense
Suspense-enabled version of useStore:
const [value, setValue] = useStoreSuspense<T>(key, options);useCollection
const collection = useCollection<T>(name, options?);Returns a collection instance with CRUD operations:
await collection.add({ id: 1, name: 'Item' });
const items = await collection.list();
await collection.update(1, { name: 'Updated' });
await collection.remove(1);🏗️ Storage Drivers
| Driver | Description | SSR Safe | Persistence | Size Limit | Best For |
|--------|-------------|----------|-------------|------------|----------|
| auto | Auto-selects best available | ✅ | ✅ | Varies | General use |
| idb | IndexedDB | ❌ | ✅ | ~50MB+ | Large datasets |
| local | localStorage | ❌ | ✅ | ~5-10MB | Small data |
| session | sessionStorage | ❌ | Tab-only | ~5-10MB | Temporary data |
| memory | In-memory | ✅ | Tab-only | Unlimited | SSR/Caching |
🔧 Advanced Usage
Encryption Setup
<StorageProvider config={{
encryption: {
key: 'your-32-character-secret-key-here!',
salt: 'optional-salt-for-key-derivation'
}
}}>
<App />
</StorageProvider>Schema Validation & Migrations
import { z } from 'zod';
const userSchemaV1 = z.object({
name: z.string(),
email: z.string()
});
const userSchemaV2 = z.object({
name: z.string(),
email: z.string(),
avatar: z.string().optional()
});
const [user, setUser] = useStore('user', {
schema: userSchemaV2,
version: 2,
// Migration function (if needed)
migrate: (oldData, oldVersion) => {
if (oldVersion === 1) {
return { ...oldData, avatar: undefined };
}
return oldData;
}
});Cross-Tab Synchronization
// Automatic synchronization (enabled by default with broadcast: true)
<StorageProvider config={{ broadcast: true }}>
<App />
</StorageProvider>TTL (Time To Live)
// Expires in 1 hour
const [data, setData] = useStore('temp-token', {
ttlMs: 60 * 60 * 1000
});Error Handling
<StorageProvider config={{
errorHandler: (error) => {
console.error('Storage error:', error);
// Send to error reporting service
}
}}>
<App />
</StorageProvider>🌐 SSR & Server-Side Rendering
The library automatically detects SSR environments and falls back to memory storage:
// This works in both SSR and client environments
<StorageProvider config={{ driver: 'auto' }}>
<App />
</StorageProvider>SSR Behavior:
- Server: Uses memory storage (no persistence)
- Client: Hydrates to chosen driver (IndexedDB/localStorage)
- Data consistency: Server and client data are isolated
🧪 Testing
import { setup, read, write } from '@sitharaj08/react-unified-storage-core';
import { MemoryDriver } from '@sitharaj08/react-unified-storage-core';
// Use memory driver for testing
setup({ driver: 'memory' });
// Your tests here
test('should store and retrieve data', async () => {
await write('test', { value: 42 });
const result = await read('test');
expect(result).toEqual({ value: 42 });
});📊 Performance
- Bundle Size: <10KB gzipped (includes core functionality)
- Operations: ~1-2ms for localStorage, ~5-10ms for IndexedDB
- Memory Usage: Minimal overhead, efficient data structures
- Compression: Up to 70% size reduction for text data
🤝 Contributing
We welcome contributions! Please see our Contributing Guide for details.
📄 License
Apache License 2.0 © Sitharaj Seenivasan
