Mirror / foldkit-mirror

What the Model being the truth gives you

Because Mirror derives its representation from application fields, several behaviors fall out automatically.

Defaults

App.initial is the default source. A field equal to its initial value is omitted from the representation by default:

initial: { filter: 'all', page: 1 }
Model:   { filter: 'all', page: 1 }
URL:     /todos

Changing only the filter yields:

/todos?filter=active

A key that should remain explicit can opt in:

ts
keys: {
  page: { keep: true },
}

An application created without initial passes the initial Model in the mirror config instead.

Codecs

Mirror derives a key's text representation from the field's encoded type:

string  -> text
number  -> parsed number
boolean -> true / false
other   -> JSON

Override a field when a friendlier representation is useful:

ts
keys: {
  tags: {
    codec: TagsAsCommaSeparatedText,
  },
}

mirror.decode(keys) returns both the successfully decoded values and any issues when a caller wants to surface invalid input.

Batching and loop avoidance

Subscriptions depend on the encoded slice, not every Model transition. One transition that changes several mirrored fields still produces at most one write, and a change that encodes to the same key set produces none.

That also prevents URL feedback loops:

popstate
  -> reduce URL into Model
  -> subscription sees same encoded keys
  -> no second navigation write

How state changes here

Ordinary edits use Message/update/modifyFields like anywhere else; the mirror observes and represents. Restoration runs the other direction: the declared writable projection installs the URL/KV value into the Model on startup. The projection is declared up front, so restoration can only ever write the fields the application already linked.