rune-sync Svelte Themes

Rune Sync

Svelte 5 library for synchronizing reactive state across various storage backends

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-sync

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 immediately

Yes, that's all it takes to get started!

Limitation: Rune-Sync state must always be an object or array. You cannot use primitive values (like strings, numbers, or booleans) as the root state. Always wrap your data in an object or array.

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 immediately

With 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 API
  • localForageSync: IndexedDB/localStorage via localForage with cross-tab synchronization via BroadcastChannel

Note: If you want to use the localForage synchronizer, you must also install localforage

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 the StateSynchronizer interface

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 state
  • initialValue: 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

Top categories

Loading Svelte Themes