State & syncing
The store, optimistic writes, and merge-patch sync.
connect() returns a store over your view model. Reads are synchronous;
writes apply optimistically and sync to the host.
import { connect } from '@rectsh/rect';
const rect = await connect();Reading
rect.get(); // the whole view model
rect.get('items.0.done'); // a dot path — numeric segments index arrays
rect.subscribe((state) => render(state)); // fires on connect + every change
rect.revision; // optimistic-concurrency token (a number)subscribe returns an unsubscribe function. In React you never call these
directly — the hooks do (see React).
Writing
Three write ops, all of which apply locally at once (optimistic), then sync:
rect.set('title', 'Hi'); // set one path
rect.update((draft) => draft.items.push(x)); // mutate a draft
rect.patch({ completion: { approved: true } }); // shallow mergeHow syncing works
- A write mutates a local copy immediately, so the UI updates with no round trip.
- The store diffs the change into an RFC 7386 JSON Merge Patch and sends it to the host.
- The host applies the patch to the authoritative store, bumps the revision, and returns the authoritative snapshot.
- The store rebases any still-unsynced local edits onto that snapshot.
The same channel delivers changes made by someone else — most importantly an
agent calling rect_patch or rect_dispatch. Those arrive as authoritative
snapshots and your subscribers fire, so the view stays live without any
polling.
Merge-patch semantics
Because sync is a JSON Merge Patch: objects deep-merge, null deletes a key, and
arrays replace wholesale (there's no per-index array merge over the wire). To
change one array element, write the whole array — or model the collection as an
object keyed by id if you want granular updates.