Inside board_server() every state change flows through one
board_update reactive. Core registers two observers framing the
change: an initial one that validates the payload and runs
augment_board_update() for auto-fixups, and a final one that runs
apply_board_update() and resets the reactive. Plugins or
callbacks may register their own observers in between, provided they
use a finite priority — the highest and lowest reactive priorities
are reserved for core.
Usage
validate_board_update(payload, board, ..., session = get_session())
augment_board_update(upd, board, ..., session = get_session())
apply_board_update(board, upd, ..., session = get_session())Arguments
- payload, upd
A board update payload — see Validation above for the accepted shape.
- board
A
boardobject.- ...
Forwarded between methods. For
apply_board_update(), the final observer also splicesboard_server()'s...in here.- session
A shiny session, default
get_session().
Value
validate_board_update() returns invisible(payload) (or
throws a blockr_abort() error). augment_board_update() returns
the (possibly extended) payload. apply_board_update() returns a
board.
Details
All three functions dispatch on the board class. Subclasses
override to validate, augment, or react to their own payload slots,
typically composing with NextMethod(). validate_board_update()
is also a caller-facing entry point: it mirrors the initial
observer's checks against a caller-supplied payload, useful for
staging layers (e.g. accumulating LLM-proposed updates) that need
to fail loudly before publishing.
Validation
The default .board method runs a structural check on the payload
(block / link / stack per-slot rules) and a cross-reference check
that link endpoints and stack members resolve in the post-update
merged view. Unknown top-level keys are passed through, so subclass
payload slots reach subclass augment / apply methods.
Augment
The default .board method inserts implied link removals and stack
updates that follow from block removals, plus link-input
completion. Subclass methods may extend the payload with their own
fixups; an error thrown here aborts the update before apply runs.
Apply
The default .board method applies the core delta to the supplied
board and returns it: added blocks are appended, link and stack
deltas are folded in through modify_board_links() /
modify_board_stacks(), and removed blocks are dropped last (once
the earlier steps have freed them of every link and stack). Subclass
methods compose with NextMethod() to layer their own payload slots
on top of the core-updated board (blockr.dock, for instance,
cascades view membership), so a single apply_board_update() call
yields the full board for any subclass. The board handed in is a
plain board snapshot with no reactive surface; the returned
board is what the final observer assigns back to rv$board. The
reactive side effects that mirror the delta — block UI insertion /
removal, server construction / teardown, link and stack wiring — run
around this single reduce.
Errors thrown from either augment or apply are caught by the
observer, reported via notify(), and the reactive is reset so the
app keeps running.
Outcome
Alongside the human-facing notify() toast, every update cycle
records a machine-readable result into board$last_update (the
read-only board handed to plugins and callbacks). It is a list with
a monotonically increasing seq, a logical ok, the phase it
ended in ("validate" or "apply"), and a message
(conditionMessage() on failure, NA on success); it is NULL
before the first update. The seq advances on every write so that
two consecutive identical outcomes still invalidate a downstream
observer. A programmatic caller can watch this field to learn
whether a dispatched update was rejected, failed to apply, or landed.
See also
On a locked board (see is_board_locked()) the update is
dropped rather than applied.
Examples
brd <- new_board(
blocks = c(a = new_dataset_block("iris"), b = new_subset_block()),
links = links(ab = new_link(from = "a", to = "b"))
)
validate_board_update(
list(links = list(rm = "ab")),
brd
)
try(
validate_board_update(
list(links = list(add = links(xy = new_link(from = "x", to = "y")))),
brd
)
)
#> Error in blockr_abort("Expecting all links to refer to known block IDs.", :
#> Expecting all links to refer to known block IDs.