npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

rune-sync

v0.2.1

Published

<div align="center">

Downloads

142

Readme

rune-sync

npm version License: MIT Svelte Types

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