Wire protocol reference¶
This reference describes the logical wire data before a connection codec turns it into a text or binary frame.
Value¶
A model value is an externally tagged enum.
Variant |
Shape |
Notes |
|---|---|---|
Null |
|
Null value. |
Bool |
|
Boolean. |
Int |
|
Signed integer. |
Float |
|
Floating-point number. |
Str |
|
String. |
List |
|
Ordered values. |
Map |
|
String-keyed map. |
Submodel |
|
Core model reference. Current Python and JavaScript bridges inline nested models as maps. |
Example:
{"Map": {"name": {"Str": "lamp"}, "on": {"Bool": true}}}
Path segments¶
Patch operations address values by paths from the model root.
Segment |
Shape |
|---|---|
Map key |
|
List index |
|
An empty path addresses the whole model value.
Patch¶
A patch contains the model revision reached by applying the patch and an ordered list of operations.
{"rev": 1, "ops": []}
Operations¶
Set¶
Sets or replaces the value at path. An empty path replaces the whole model.
{"Set": {"path": [{"Key": "on"}], "value": {"Bool": true}}}
Remove¶
Removes a map entry. The last path segment is a Key.
{"Remove": {"path": [{"Key": "name"}]}}
Insert¶
Inserts a value into the list at path.
{"Insert": {"path": [{"Key": "items"}], "index": 0, "value": {"Str": "first"}}}
RemoveAt¶
Removes an element from the list at path.
{"RemoveAt": {"path": [{"Key": "items"}], "index": 0}}
Malformed paths, wrong container types, and out-of-bounds list indexes are rejected by the core apply path.
Protocol messages¶
Connections carry one logical message per frame.
Snapshot¶
A snapshot initializes a client mirror for one model.
{
"t": "snapshot",
"id": 1,
"type": "Device",
"rev": 0,
"value": {"Map": {"name": {"Str": "lamp"}, "on": {"Bool": false}}}
}
Patch¶
A patch advances an existing mirror.
{
"t": "patch",
"id": 1,
"patch": {
"rev": 1,
"ops": [
{"Set": {"path": [{"Key": "on"}], "value": {"Bool": true}}}
]
}
}
Clients ignore patch messages whose revision is less than or equal to the revision already seen for that model.
Client.recv() (Python and JavaScript alike) returns {t: "snapshot", id, rev} for an accepted
snapshot, the decoded patch message for an accepted patch, and None/undefined for an ignored
revision or an unrecognized message type — unknown types are ignored, not errors, so a newer server
can add message types without breaking older clients. Reactive adapters can consume the returned
patch paths without reading and decoding the complete mirror, either from the recv() return value
or via Client.on_change / Client.onChange, which fires with the same accepted change under the
managed connect/run/SSE paths. The returned change and Client.value() share immutable branches
with the mirror and must not be mutated. A patch before its snapshot, an unknown patch operation, or
an invalid path raises; failed frames leave the mirror and its accepted revision unchanged.
Reject¶
The server refuses a proposed edit that fails validation — or a write to a shared model the tenant
cannot write — by sending the proposer (and only the proposer) the authoritative revert followed by a
typed reject saying why. rev is the server’s current revision for the model, and error carries
the model’s validation message where available (e.g. pydantic’s).
{
"t": "reject",
"id": 1,
"rev": 4,
"error": "1 validation error for Device\nbrightness\n Input should be a valid integer ..."
}
A reject never changes the mirror (the revert snapshot alongside does); clients surface it through
Client.on_reject / Client.onReject so an app can show why the edit died instead of a silent
revert.
Model ids¶
Session model ids start at 1 inside each store. Tenant-local ids in a Hub are isolated per
tenant. Shared hub model ids start at 1099511627776 (1 << 40) so they do not collide with
session-local ids.
Built-in codecs¶
Name accepted |
Canonical codec |
Frame type |
|---|---|---|
|
|
Text frame. |
|
|
Binary frame. |
A WebSocket connection selects a codec with the codec query parameter. Server and Hub encode
each outbound message for the target connection’s codec.
SSE, Jupyter comm, and anywidget adapters use JSON text only.
Custom codecs¶
A custom codec is registered under a content type and provides two functions:
Function |
Input |
Output |
|---|---|---|
|
JSON-able protocol message or |
|
|
|
JSON-able protocol message or |
Built-in codec names cannot be overridden. Custom codecs are binding-local; register matching implementations in every Python or JavaScript process that uses the content type.