rune-sync
v0.2.1
Published
<div align="center">
Downloads
142
Readme
rune-sync
A powerful and flexible Svelte 5 library for synchronizing reactive state across various storage backends, enabling seamless data persistence and real-time collaboration.
Quick Start
Installation
npm install rune-sync
# or
pnpm add rune-sync
# or
yarn add rune-syncUsage
import { createSyncState } from 'rune-sync';
import { lsSync } from 'rune-sync/localstorage';
// Create a reactive state that persists to localStorage
let userSettings = lsSync('user-settings', {
theme: 'dark',
language: 'en'
});
// State changes are automatically saved
userSettings.theme = 'light'; // Persisted immediatelyYes, that's all it takes to get started!
Limitation: Rune-Sync state must always be an object. You cannot use primitive values (like strings, numbers, or booleans) as the root state. Always wrap your data in an object.
Features
- Universal Storage Support: Can work with any storage solution via custom synchronizers. Build your own sync logic for servers, WebRTC, cloud storage, or any API
- Built-in Synchronizers: Ready-to-use synchronizers for localStorage and IndexedDB with cross-tab synchronization
- Real-time Updates: Automatic cross-tab synchronization for localStorage and localForage
- Performance Controls: Built-in debounce and throttle options for optimizing write performance
- Flexible Settings: Configurable options for subscription control and performance tuning
- TypeScript Support: Full type safety with generics
- Zero Dependencies: Lightweight and focused on Svelte's reactivity
Usage Examples
Basic Usage
import { createSyncState } from 'rune-sync';
import { lsSync } from 'rune-sync/localstorage';
// Create a reactive state that persists to localStorage
let userSettings = lsSync('user-settings', {
theme: 'dark',
language: 'en'
});
// State changes are automatically saved
userSettings.theme = 'light'; // Persisted immediatelyWith Performance Controls
import { lfSync } from 'rune-sync/localforage';
// Debounced writes (wait 500ms after changes before saving)
let searchResults = lfSync(
'search-results',
{
query: '',
results: []
},
{ debounce: 500 }
);
// Throttled writes (save at most once per 1000ms)
let realTimeData = lfSync(
'realtime-data',
{
value: 0
},
{ throttle: 1000 }
);
// Disable cross-tab synchronization
let localOnlyState = lsSync(
'local-only',
{
data: 'sensitive'
},
{ doNotSubscribe: true }
);Built-in Synchronizers
localStorageSync: Browser localStorage with cross-tab synchronization via Storage APIlocalForageSync: IndexedDB/localStorage via localForage with cross-tab synchronization via BroadcastChannel
Note: If you want to use the
localForagesynchronizer, you must also installlocalforage
Cross-tab Sync: Both built-in synchronizers automatically synchronize state changes across browser tabs/windows
Creating Custom Synchronizers
Implement the StateSynchronizer interface to create your own storage backend:
import type { StateSynchronizer } from 'rune-sync';
const myCustomSync: StateSynchronizer = {
read: async (key: string) => {
// Implement your read logic
const data = await myStorage.get(key);
return data ? JSON.parse(data) : null;
},
write: async (key: string, value: unknown) => {
// Implement your write logic
await myStorage.set(key, JSON.stringify(value));
},
// Optional: Enable real-time updates
subscribe: (key: string, write: (newValue: T) => void) => {
// Set up real-time listener
// Call write() with the new value when it changes (when event occurs)
const unsubscribe = myRealtimeService.subscribe(key, (data) => {
write(data.value);
});
return unsubscribe;
}
};
// Use your custom synchronizer
const syncState = createSyncState(myCustomSync);
let appState = syncState('app-state', { counter: 0 });API Reference
createSyncState(synchronizer: StateSynchronizer)
Creates a state factory function that uses the provided synchronizer.
Parameters:
synchronizer: Implementation of theStateSynchronizerinterface
Returns: A function that creates synchronized reactive state
State Factory Function
const syncState = createSyncState(synchronizer);
const state = syncState<T>(key: string, initialValue: T, settings?: SyncSettings): T;Parameters:
key: Storage key for the stateinitialValue: Initial state value (must be object or array)settings: Optional configuration object
Returns: Reactive Svelte state
SyncSettings Interface
interface SyncSettings {
// Disable cross-tab synchronization
doNotSubscribe?: boolean;
// Debounce writes by N milliseconds
debounce?: number;
// Throttle writes to at most once per N milliseconds
throttle?: number;
}StateSynchronizer Interface
interface StateSynchronizer {
read<T>(key: string): Promise<T | null> | T | null;
write<T>(key: string, value: T): Promise<void> | void;
subscribe?<T>(key: string, write: (newValue: T) => void): () => void;
}Contributing
We welcome contributions! Please see our contributing guidelines for details.
License
MIT License - see LICENSE for details.
Made for the Svelte community
