Composition / foldkit-composition

The Document, and its two schemas

A Document is normalized: roots and each Region hold ids, and nodes holds each node once, under its id. A node does not store its own id, so an id and its key cannot disagree, and a node is in exactly one place.

There are two schemas, on purpose:

ts
Composition.Document                                 // tolerant: what is stored and read
Composition.Document.check(Composition.valid(Site))  // strict: what may be published

The tolerant codec accepts any well-formed Document, whatever Block names it uses and with props as JSON. So a stored page always reads, an old revision always restores, and content the deployment no longer knows survives. The strict check runs validate and fails with every finding at its path. Store the first in the Entity, and ask the second of the operation that publishes:

ts
const Page = Entity.define('Page', Schema.Struct({
  id: Schema.String,
  title: Schema.String,
  document: Composition.Document,
}))

const PublishPage = Entity.input(Page, Schema.Struct({
  title: Page.fields.title.schema,
  document: Composition.Document.check(Composition.valid(Site)),
}))

appearance holds a node's look as names, such as { tone: 'accent' }, checked against the axes its Block offers (Appearance). when lists the conditions a node shows under (Conditions), and actions what its events run (Actions), as names and literal input.