Surface / foldkit-surface
Projections
A Projection<Root, Value> is a Model codec for Value, a pure
read(root) => Value, its dependencies (Model paths), and its metadata:
facts other packages attach and interpret, such as the server data a
foldkit-remote selection needs. Reading never performs I/O.
Projection.struct({ todos: model.todos, selectedTodoId: model.selectedTodoId })
Projection.of(Model)({ todos: true, selectedTodoId: true }) // from the Schema
Projection.array(projection) // Projection<ReadonlyArray<Root>, ReadonlyArray<Value>>
Projection.option(projection) // Projection<Option<Root>, Option<Value>>
Projection.fromReader(codec, read) // escape hatch for a non-ModelRef valueProjection.struct accepts ModelRefs and nested Projections, so a Surface can
mix local fields with remote or replicated values. A nested projection
contributes its dependencies and metadata to the parent.
Metadata
Metadata is foldkit-metadata, re-exported so an
application needs one import. A package declares its own slot once and reads back only its own entries:
const Flags = Metadata.key<string>('flags', {
merge: flags => [...new Set(flags)],
summarize: flag => flag,
})
const beta = Projection.fromReader(Schema.Boolean, readBeta, { metadata: Flags.of('beta') })
Flags.get(Projection.struct({ beta, todos: model.todos }).metadata) // ['beta']Entries are combined per key with that key's merge as projections compose, and
looked up by the key object, never by its name, so two packages cannot collide.
The flip side: two copies of one package (a duplicated install, a reloaded
module) declare two keys and do not see each other's entries. Metadata is
opaque and its entries frozen; only a key's of and composition make one.
Surface never interprets them; Surface.inspect and Module show them through
summarize.