Mirror / Mirrored state

One owner per datum

A mirror is not an owner. It observes fields and owns nothing, which is what separates it from the two packages that do own state:

StateOwnerStore
Filter, sort, page, search text, an open panelthe local Modelthe URL, via Mirror.url
Preferences, a draft, a collapsed sidebarthe local ModelKeyValueStore, via Mirror.kv
Client-authored state that must converge across devicesfoldkit-synca durable ordered log
A cache of another owner's factsfoldkit-remotethe server

mirror.contract is of kind mirror, so Module.manifest shows a mirrored field as local with the mirror beside it, and Module.validate reports a key-value mirror whose MirrorRestored the union does not declare. A URL key belongs to one mirror per application.

Recovery

A mirror holds no unsent user edits, so its policy is Remote's, not Sync's: a key-value document of another version or scope, or a malformed one, is removed rather than restored; a store failure is absorbed and never fails the application; a slice back at its defaults removes the document. Outside a browser the URL store writes nothing, so a server render is safe.

When not to use a mirror

  • Two tabs must agree. A mirror is last-write-wins with no log; use foldkit-sync.
  • The value is a server fact. Use foldkit-remote; the URL should carry the identity (?projectId=p1), not the entity.
  • The key is a route. A Foldkit router owns the path; a mirror touches only its own query keys and composes with route.query(schema) when they differ.

See it working

examples/todo-app keeps the filter in the URL (/?filter=active, linkable and read back on navigation) and the composer's draft in Web Storage; pnpm demo prints both in section 12 of the transcript, and test/runtime.test.ts round-trips the URL. The package README documents the API.