Main To Worker Communication Protocol
Main to Worker Communication Protocol
Written for AI agents. See Log Methodology Note below for details.
This document tries to capture the challenges in defining and creating the communication protocol between the main window (running elements and component bridges) and the sandbox (running components and element bridges).
The protocol
On secure context initial creation:

The main window sends a JPMRootComponentProps message with the ViewState of the element
opting in to use a secure component. The worker root is using this ViewState to start
the rendering process in the sandbox environment.
As the rending of components continues within the sandbox environment, each element bridge
records the input ViewState it gets and sends a JPMRender message to it's corresponding
component bridge.
Two important things to remember here -
- for performance, we do not compute component props on the main window, rather, we compute
props in the sandbox. We render all the tree in the sandbox, recording all the
JPMRendermessages. - again for performance, while the protocol models multiple
JPMRendermessages, the underlying channel only sends a single low level message that batches all the protocol messages.

When registering events, the element bridge sends a JPMAddEventListener message to the
component bridge, with the refName of the sub-element to add the event for, and eventType
to listen for.
When an event is triggered, the component bridge captures the event. For regular events,
it only sends the coordinate and eventType of the actual event. For events registered
using $onX, it also adds the computed eventData. The data is sent as a JPMDomEvent
message to the element bridge, who triggers the event on the original component
The addressing challenge
As we can see above, one of the challenges is directing messages between the pair of component and
element bridges at the same place in the tree. Because the tree structure, forEach and if
statements, the tree structure cannot be statically determined.
We denote CompId as a number value that facilitates the communication between the bridges - that is,
component bridge CompId: 2 communicates with element bridge CompId: 2.

The derive the relationships between element bridge and component bridge, we need to look
at the parent component and the coordinate within the parent component's element.
That is, we compute CompId based on (parent CompId, coordinate in parent).
CompId:2 ~~ CompId:1 + Coordinate: a
We also need to think of the order of components and elements creation - the main point of
which is that a child is always created after the parent, and has the creation context
internally in the runtime package. It terms of CompId allocation - who allocates between the
main and sandbox, there is no one clear answer - for static elements and components, the
main window will be first. For dynamic elements and components, the sandbox will be first.
For the element bridge CompId: 2 to generate the CompId, it needs to look up the stack
for the element bridge CompId: 1 and to the coordinate: a of a sub-element of CompId: 1.
For the component bridge CompId: 2 to generate the CompId, it needs to look up the stack
for the component bridge CompId: 1 and to the coordinate: a of a sub-element of CompId: 1.
Both imply a context API for Jay that can be used by the secure package to access the parent
CompId and coordinate. See 16 - Context API
The formal communication protocol
export interface JayPort {
getRootEndpoint(): JayEndpoint;
getEndpoint(parentCompId: number, parentCoordinate: string): JayEndpoint;
batch(handler: () => void);
flush();
}
export interface JayEndpoint {
post(outMessage: JayPortMessage);
onUpdate(handler: JayPortInMessageHandler);
get compId(): number;
}
JayPort- the connection to the protocol. Each side, the main and the sandbox, have one port to facilitate the communicationgetRootEndpoint- gets an endpoint that represents the tree root, that is, does not have a parent componentgetEndpoint- gets an endpoint that represents a specific bridge communication with it's partner bridge. the call togetEndpointalso triggers the generation of theCompIdbased of the provided parametersbatch- record all messages send via the endpoints during the handler run, and flush all messages as one batch when the handler completesflush- flushes all messages, if messages are added withoutbatch
JayEndpoint- the actual interface bridges are usingpost- send a message to the partner bridgeonUpdate- listen to messages from the partner bridgecompId- get the compId.
Log Methodology Note
Note: These design logs are written primarily for AI agents as part of the Design Log methodology and made accessible here for human readers. The language and structure are optimized for machine consumption — expect precise, specification-style prose rather than narrative documentation.