Skip to main content

Envelope

Every message in either direction has the same outer shape.

interface WaylocateMessage {
/** Namespace guard and protocol version. */
waylocate: 1;
kind: "command" | "result" | "event";
/** Dot-namespaced, such as "camera.flyTo" or "selection.changed". */
name: string;
/** Correlation identifier. On commands and results; absent on events. */
id?: string;
payload?: unknown;
/** Events only. Who caused this. */
source?: "user" | "host" | "system";
}

The waylocate field

This field is a namespace guard first and a version number second. Any message arriving without it is dropped without a reply and without a log entry.

That is not defensive excess. A page's window receives constant traffic from development tooling, browser extensions, and other embedded content, none of which is addressed to the map. A guard field is the only reliable way to separate protocol traffic from noise, and a version number that also serves as the guard costs nothing extra.

Commands and results

A command carries an id. The result echoes it, which is what pairs the two.

{
"waylocate": 1,
"kind": "command",
"name": "selection.setRoom",
"id": "c7",
"payload": { "ref": "muntz-hall/170" }
}

Results add an ok field.

{ "waylocate": 1, "kind": "result", "name": "selection.setRoom", "id": "c7", "ok": true }
{
"waylocate": 1,
"kind": "result",
"name": "selection.setRoom",
"id": "c7",
"ok": false,
"error": { "code": "REF_NOT_FOUND", "message": "No room matching 'room-999'" }
}

Commands that return data carry it in payload on the successful result. camera.get and map.getState are the two that do.

Every command is answered exactly once, including malformed ones and commands the map does not recognise.

Events

Events have no id, because nothing is waiting for them. They carry source instead.

{
"waylocate": 1,
"kind": "event",
"name": "selection.changed",
"source": "user",
"payload": { "building": "muntz-hall", "floor": "1", "room": "170" }
}

Forward compatibility

A host should ignore fields it does not recognise rather than rejecting the message, and should ignore events it does not know rather than treating them as errors. Both are how an implementation written today keeps working against a map that has since gained capabilities.

The SDK does both. A host implemented by hand should too.

Next