Mirror / Mirrored state
How it fits together
mermaid
flowchart LR
subgraph app["application"]
direction TB
model["Model — the only truth"]
slice["slice: a writable projection<br/>encoded with defaults elided"]
model --> slice
end
subgraph stores["stores"]
direction TB
url["URL<br/>?filter=active&page=2"]
kv["KeyValueStore<br/>one JSON document per key"]
end
slice -- "entry writes what changed" --> url
slice -- "entry writes what changed" --> kv
url -. "reduce(model, url) on navigation and load" .-> model
kv -. "reduce(model, MirrorRestored) from restore" .-> modelDeclared from the application:
ts
const Filters = Mirror.url(App, {
fields: [App.model.filter, App.model.page, App.model.q],
keys: { q: { history: 'replace' } },
})
const Prefs = Mirror.kv(App, { key: 'todo/prefs', scope: userId, fields: [App.model.sidebar, App.model.draft] })Wired into update, the URL hook the runtime already has, and one
Subscription entry per mirror:
ts
const update = (model, message) => {
if (Mirror.reduces(message)) return { model: Prefs.reduce(model, message) }
if (message._tag === 'UrlChanged') return { model: Filters.reduce(model, message.url) }
…
}
const subscriptions = Subscription.make<Model, Message, KeyValueStore>()(() => ({
...Filters.subscriptions,
...Prefs.subscriptions,
}))Under Sync.mount, the url option is where a URL mirror plugs in
(init: (model, url) => Filters.reduce(model, url), onUrlChange), and
subscriptions and resources carry the entries and the store layer.