Bundle / foldkit-bundle
Many of one: collections
A collection places a bundle once per key. The parent Model still owns every item; the collection routes by key:
Parent Model.rows = { a: Row.Model, b: Row.Model }
GotRowsMessage({ key: 'b', message }) -> Row.update on rows.b -> rows.b written back// Row is a bundle whose Model is { id: string, count: number }.
const RowsDeclared = Bundle.declareEach(Row, 'rows') // a record field and GotRowsMessage
const RowsPage = Bundle.parent({
Model: Schema.Struct({ ...RowsDeclared.fields }),
Message: defineMessageUnion({ ...RowsDeclared.cases }),
})
const Rows = RowsPage.each(RowsDeclared)
Rows.add('b', row => ({ ...row, id: 'b' })) // init, then prepare
Rows.remove('b')add(key, prepare?)writes the item frominitand lifts its Commands. An item cannot see its key, sopreparelets the parent store what only it knows, such as the id. Adding an existing key replaces the item.remove(key)deletes the item. A Message that arrives later for that key leaves the parent unchanged.update,helpers.name(key, ...input), andonOut(outMessage, key)work per item.argsare given once, for every item.view(parent, h, key)renders one item andviewAll(parent, h)renders all of them, each in its own slot.Page.placeEach(bundle, field, config)places without a declaration.placements.initialstarts a collection empty unlessrestgives it.
Typed keys and order
Pass a key Schema, such as a branded id, and the key type follows through add,
remove, helpers, views, and onOut. Store items in an array when order
matters: a record puts integer-like keys such as "2" first. Ids in an array
must be unique, and an item is stored under its own id: give add a prepare
that sets the id to the key, as below, and keep it through update. Writing an
item whose id is not its key throws, since it could never be read back.
const RowId = Schema.String.pipe(Schema.brand('RowId'))
const GotOrderedRowMessage = Link.keyedWrapper('GotOrderedRowMessage', RowMessage, RowId)
// OrderedRow is a bundle whose Model has `id: RowId`; OrderedPage's Model has `rows: Array<…>`.
const OrderedRows = OrderedRow.each(
OrderedPage.link.collectionById('rows', GotOrderedRowMessage, { id: row => row.id }),
)
OrderedRows.add(RowId.make('first'), row => ({ ...row, id: RowId.make('first') }))
OrderedRows.remove(RowId.make('first')) // a RowId, not a stringSubscriptions restart together. Each child Subscription becomes one parent
entry over every item. Adding or removing an item, or changing any item's
dependencies, restarts that entry's stream for every item. A child entry with
keepAliveEquivalence stays alive while the keys are unchanged, and each item
reads its own latest dependencies. A bundle with Managed Resources cannot be
placed per key; the type says why.