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 returns the supplied board unchanged —
the core apply path (block / link / stack mutation, block UI
insertion / removal) is not routed through this generic. Subclass
methods receive a plain board snapshot (no reactive surface) and
return a board, which the final observer assigns back to
rv$board. For piecemeal customization of the core apply path
itself, override the relevant sub-generic
(modify_board_links(), insert_block_ui(), etc.) instead.
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.
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.