fleury_wire library
Fleury's explicitly unstable, platform-neutral remote wire.
This library exposes the frame protocol, codecs, and transport contracts used by first-party browser and agent peers that ship in lockstep with Fleury. It is correctness-tested, but it is not a semver-stable integration surface: frame shapes and negotiation rules may change between releases.
Most platform hosts should use fleury_host.dart. A peer that deliberately
speaks this wire must follow docs/implementation/wire-protocol.md and use a
matching Fleury build.
Classes
- ByeFrame
- Either side signals a clean shutdown. Empty payload.
- CaretFrame
- The focused editable's caret rectangle in cell space, or absent when nothing editable is focused. The peer positions its hidden IME capture element there so composition candidate windows appear at the caret. App → peer, sent when the rect changes.
- ClipboardResultFrame
- The peer's answer to a ClipboardWriteFrame. Peer → app.
- ClipboardWriteFrame
- The app asks the peer to place text on the PEER's clipboard — the machine the user is actually sitting at. Sequenced so the app can match the peer's ClipboardResultFrame. App → peer. Without this, copy in a served session lands on the server's clipboard (or nowhere).
- DebugRequestFrame
- A pull-style debug query from the peer (agent bridge, future browser DevTools): "send me your recent kind records". Peer → app. seq correlates the DebugResponseFrame; limit bounds how many records the app returns (newest last). Kinds are strings so the set can grow without a protocol change; unknown kinds get an empty response.
- DebugResponseFrame
-
The app's answer to a DebugRequestFrame: the seq and kind echoed
back with a JSON document of records (shape is per-kind; see
DebugFrameLog.toJson/ runApp's error serialization). App → peer. - FrameDecoder
- Streaming frame decoder. Feed bytes as they arrive from the transport; pull out complete frames with drain. The decoder holds partial-frame state across calls so a fragmented socket read or websocket message boundary doesn't lose data.
- ImagePlacement
-
Where an inline image sits: its content-hash id, visible cell window, and
original fit box. Bytes travel out-of-band (an
InlineImageFrame), shipped once per id. - InitFrame
- The handshake. The peer sends one before any InputFrame, carrying the remote display's size and the capabilities the app should plan against (color mode, image protocol, multiplexer wrapping), and the protocol it speaks. The app answers with one of its own (see protocolVersion and terminalInput).
- InlineImageCacheLedger
- Insertion-ordered inline-image cache accounting.
- InlineImageCachePolicy
- Shared cache accounting for remote inline-image hosts.
- InlineImageFrame
-
The bytes of one inline image (browser surface), keyed by content-hash
id. App → peer, sent once before the first PlanFrame that places it; the
client caches it by id and renders an
<img>overlay wherever a plan'splacementsreference it. Decoupling bytes from placement keeps the image off the cell-grid wire and ships it a single time. - InputEventFrame
- A structured input event from the peer — keystroke, mouse, paste, resize, composition — dispatched server-side as a TuiEvent. Replaces the raw InputFrame byte stream on the structured path. Peer → app.
- InputFrame
- Raw input bytes from the remote display — keystrokes, escape sequences, paste contents. Routed through the same InputParser pipeline as a local POSIX driver.
- OutputFrame
- Outbound ANSI bytes — the app's diff render. Only ever flows app → peer. Legacy host; the structured serve host emits PlanFrame.
- PlanFrame
- A presentation plan — the structured serve host's per-frame output, driving a visual surface on the peer instead of ANSI. App → peer.
- RemoteFrame
- One decoded frame off the wire. Sealed so callers exhaustively switch in dispatch.
- RemoteFrameTransport
- Bidirectional frame channel between the app and a peer (a local shell terminal, a browser, a test harness). Frames flow in both directions; lifetime is owned by the caller (typically the driver).
- RemotePatchRun
- A run of same-style cells within a patch.
- RemotePlan
- A frame reduced to its changed cells for the wire: the grid size, repaint/scroll flags, a per-frame style table, and the changed column-range patches. The client applies the patches to a CellBuffer mirror and rebuilds the dirty rows from it (reusing the span builder), so only changed cells travel — the efficiency ANSI gets implicitly.
- RemoteRowPatch
- One contiguous changed column range in a row.
- ResizeFrame
-
The remote display resized. Surfaced as a
ResizeEventon the driver's event stream. - SemanticActionFrame
- The peer activated a node in its accessible DOM (a screen reader or agent driving the semantics, not the visual grid). The host invokes action on the live node id. Peer → app; the structured counterpart to the app → peer SemanticsFrame.
- SemanticActionResultFrame
- The app's answer to a SemanticActionFrame: the node id and action echoed back with the invocation status, so the peer (browser AT mirror, agent bridge) can distinguish "handler ran", "disabled", "not found", "unsupported", and "handler threw" instead of guessing from tree diffs. App → peer.
- SemanticsFrame
- A semantic snapshot (UTF-8 JSON, the SemanticInspectionSnapshot shape) for the just-rendered frame. App → peer; lets a served session stay agent-drivable and accessible.
- SemanticsWireDecoder
- Client side: replays the encoder's frames, holding the flat node state and rebuilding a SemanticTree after each. One instance per session.
- SemanticsWireEncoder
- Server side: turns semantic frames into compact wire payloads, emitting a full frame once per connection and patches thereafter. One instance per served session (it holds the last-sent state). Two entry points share that state: encodeTree (the serve render loop's path — redacts only the changed nodes on demand, O(changed)) and encode (for consumers that already hold a pre-redacted SemanticInspectionSnapshot, e.g. inspection/agent bridges).
- SemanticWireDelta
-
The set of node ids whose wire form may have changed since the last
present, in WIRE-id space (already sanitized). Derived from
SemanticsOwner's per-frame diff: changed is added ∪ updated, removed is removed. The owner's node equality compares exactly the fields the wire serializes — includingboundsand child order — so a node lands in changed iff its wire form could differ. Passing this lets the encoder re-serialize only the changed nodes instead of re-flattening the whole tree every frame. - TerminalInputModes
- The input half of a TerminalMode: which reports the terminal sends (mouse, pastes, focus changes) and how much of the Kitty keyboard protocol encodes keys.
Enums
- FrameType
- Frame type discriminator.
- RemoteClipboardStatus
- How a peer handled an app-requested clipboard write.
- RemoteWireProtocol
- The two protocols the remote wire carries. They share the frame envelope and the INIT handshake and version independently; an INIT declares exactly one, and the session speaks it throughout.
Mixins
- SynchronousSendTransport
- Mixin for transports whose send hands bytes off synchronously (an in-memory pair, a test fake): they can never back up.
Constants
- defaultInlineImageCachePolicy → const InlineImageCachePolicy
- The production cache policy shared by the remote sender and browser host.
- defaultMaxRemoteFramePayloadLength → const int
- Default remote frame payload cap.
- maxRemoteControlFramePayloadLength → const int
- Small handshake/control frames should never carry document-sized payloads.
- maxRemoteDocumentFramePayloadLength → const int
- Structured plans, semantic snapshots, debug records, and ANSI output.
- maxRemoteImageFramePayloadLength → const int
- One encoded inline image. Images remain the only frame allowed up to the global cap.
- maxRemoteInputFramePayloadLength → const int
- Text, paste, clipboard, and semantic-action input accepted in one event.
- maxRemoteSemanticNodeIdBytes → const int
- Maximum UTF-8 byte length of a semantic node id on the remote wire.
- maxSemanticTreeDepth → const int
-
Maximum tree depth the decoder will reconstruct. The frame payload cap
already bounds total bytes (and thus node count), but a hostile or corrupt
patch could still encode a very deep
childIdschain; capping recursion depth turns that into a pruned subtree instead of a stack overflow. Far beyond any real UI nesting. - maxSemanticWireEdges → const int
- Maximum child references in one decoded semantic mirror.
- maxSemanticWireNodes → const int
- Maximum retained nodes in one decoded semantic mirror.
- remoteProtocolVersion → const int
-
The structured wire protocol version (RemoteWireProtocol.structured).
Bumped on any change to a frame the structured protocol uses; declared in
INIT as
v=<n>and answered app → peer. The protocol is lockstep: a structured peer and the app must speak exactly this version. - semanticsWireVersion → const int
- Wire envelope schema version. Bumped only on a breaking shape change; the decoder rejects an unknown version rather than misreading it.
- serveSessionBusyCloseCode → const int
-
WebSocket close code
fleury serve(bridge mode) turns a second browser away with while a session is live: bridge mode pairs one browser with the one app it does not own. Private-use range, same reasoning as serveSessionLimitCloseCode; the reason names--spawnas the way to get a session per tab. - serveSessionLimitCloseCode → const int
-
WebSocket close code
fleury serveturns a browser away with when the admission cap (--max-sessions) is already full. - shellProtocolVersion → const int
-
The version of the protocol
fleury shellspeaks (RemoteWireProtocol.shell), declared in INIT asshell=<n>.
Functions
-
applyRemotePlanToBuffer(
RemotePlan plan, CellBuffer mirror) → Set< int> -
Applies a decoded
planto a CellBuffer mirror, reproducing the server's frame. The client rebuilds the dirty DOM rows from the mirror afterward. Returns the row indices the plan touched. -
buildRemotePlan(
CellBuffer prev, CellBuffer next, {required bool fullRepaint, TuiDirtyRows? dirtyRows}) → RemotePlan -
Builds a RemotePlan from the rendered
prev/nextbuffers — the changed column ranges only, grouped into same-style runs with a per-frame style table. OnfullRepaint(or a size change) every row is treated as changed. -
decodeInputEvent(
Uint8List bytes) → TuiEvent - Decodes a TuiEvent from wire bytes.
-
decodeRemotePlan(
Uint8List bytes) → RemotePlan - Decodes a RemotePlan from wire bytes.
-
decodeSemanticAction(
Uint8List bytes) → ({SemanticAction action, SemanticNodeId id, String? targetToken, Object? value}) - Decodes a semantic-action request. Throws RemoteCodecException on an unrecognized action name or a malformed payload so the caller rejects it rather than misinterpreting it.
-
encodeFrame(
RemoteFrame frame) → Uint8List - Encodes a frame into wire bytes ready for the transport.
-
encodeInputEvent(
TuiEvent event) → Uint8List - Encodes a TuiEvent to wire bytes. Throws RemoteCodecException for an event kind not carried by the serve protocol.
-
encodeRemotePlan(
RemotePlan plan) → Uint8List - Encodes a RemotePlan to wire bytes.
-
encodeSemanticAction(
SemanticNodeId id, SemanticAction action, {Object? value, String? targetToken}) → Uint8List -
Encodes a peer's semantic-action request — the browser or an agent
activating a node in its accessible DOM — as the node id, the action name,
and an optional JSON-encoded payload (carried only by
setValue). -
maxRemoteDebugResponseJsonLength(
String kind) → int -
Maximum raw JSON bytes that fit in a DebugResponseFrame for
kind. -
remoteFramePayloadLimit(
FrameType? type) → int -
The maximum payload accepted for
typeby the default remote wire.
Exceptions / Errors
- RemoteCodecException
- Thrown when a structured frame payload is malformed.
- RemoteProtocolException
- A malformed frame or payload was received from a remote peer.