Skip to content

Installation

bash
npm install @statesync/svelte @statesync/core

Purpose

@statesync/svelte applies snapshots to Svelte state containers. It supports two targets:

  • 'store' (default) — Svelte 4 writable() stores. Always produces a new object reference (required for store reactivity).
  • 'state' — Svelte 5 $state runes. Mutates the reactive proxy in-place (how $state tracks changes).

API

createSvelteSnapshotApplier(storeOrState, options?)

OptionTypeDefaultDescription
target'store' | 'state''store''store' for writable(), 'state' for $state runes
mode'patch' | 'replace''patch'Apply strategy (see below)
pickKeysReadonlyArray<keyof State>Only update these keys (mutually exclusive with omitKeys)
omitKeysReadonlyArray<keyof State>Protect these keys from updates
toState(data, ctx) => Partial<State>identityMap snapshot data to state shape. ctx contains { store } or { state } depending on target
strictbooleantrueThrow if toState returns a non-object

Store interface

For target: 'store', the adapter uses a structural interface — no svelte import required:

ts
interface SvelteStoreLike<State> {
  set(value: State): void;
  update(updater: (current: State) => State): void;
}

Any Svelte writable() store satisfies this interface automatically.

For target: 'state', pass any plain $state object directly.

Apply semantics

target: 'store' (Svelte 4)

ModeBehavior
'patch' (default)store.update(current => ({ ...current, ...patch })) — new reference
'replace'store.update(_ => rebuiltState) — new reference, preserving omitted keys

target: 'state' (Svelte 5)

ModeBehavior
'patch' (default)state[key] = value for each key — in-place mutation, identity preserved
'replace'delete state[key] for stale keys + state[key] = value for new — identity preserved

Examples

Svelte 4 — writable store

ts
import { createRevisionSync } from '@statesync/core';
import { createSvelteSnapshotApplier } from '@statesync/svelte';
import { writable } from 'svelte/store';

const store = writable({
  theme: 'light',
  locale: 'en',
  sidebarOpen: false,
});

const applier = createSvelteSnapshotApplier(store, {
  mode: 'patch',
  omitKeys: ['sidebarOpen'],
});

const sync = createRevisionSync({
  topic: 'user-prefs',
  subscriber,
  provider,
  applier,
});

await sync.start();

Svelte 5 — $state rune

ts
import { createRevisionSync } from '@statesync/core';
import { createSvelteSnapshotApplier } from '@statesync/svelte';

let settings = $state({
  theme: 'light',
  locale: 'en',
  sidebarOpen: false,
});

const applier = createSvelteSnapshotApplier(settings, {
  target: 'state', 
  mode: 'patch',
  omitKeys: ['sidebarOpen'],
});

const sync = createRevisionSync({
  topic: 'user-prefs',
  subscriber,
  provider,
  applier,
});

await sync.start();

Using in a Svelte 4 component

svelte
<script>
  import { onMount, onDestroy } from 'svelte';
  import { writable } from 'svelte/store';
  import { createRevisionSync } from '@statesync/core';
  import { createSvelteSnapshotApplier } from '@statesync/svelte';

  const settings = writable({ theme: 'light', locale: 'en' });

  const applier = createSvelteSnapshotApplier(settings, { mode: 'patch' });
  const sync = createRevisionSync({ topic: 'settings', subscriber, provider, applier });

  onMount(() => sync.start());
  onDestroy(() => sync.stop());
</script>

<p>Theme: {$settings.theme}</p>

See also

Released under the MIT License.