BusWire
type BusWire = | { clientId: string; key: string; kind: PeerKind; scope: "state"; type: "patch"; v: 1; value: unknown; version: Version;} | { clientId: string; kind: PeerKind; scope: "state"; type: "hello"; v: 1;} | { clientId: string; kind: PeerKind; scope: "state"; state: Record<string, unknown>; type: "snapshot"; v: 1; versions: Record<string, Version>;} | { clientId: string; kind: PeerKind; metadata?: unknown; scope: "presence"; type: "hello" | "ping" | "bye"; v: 1;} | { clientId: string; kind: PeerKind; scope: "leader"; type: "hello"; v: 1;} | { clientId: string; kind: PeerKind; scope: "leader"; term: Version; type: "claim" | "heartbeat" | "resign"; v: 1;} | { clientId: string; key: string; kind: PeerKind; scope: "op"; type: "hello"; v: 1;} | { action: unknown; clientId: string; key: string; kind: PeerKind; opId: string; scope: "op"; type: "propose"; v: 1;} | { action: unknown; clientId: string; key: string; kind: PeerKind; opId: string; scope: "op"; seq: number; type: "commit"; v: 1;} | { clientId: string; key: string; kind: PeerKind; scope: "op"; seq: number; state: unknown; type: "snapshot"; v: 1;} | { clientId: string; kind: PeerKind; msgId: string; payload: unknown; replyTo?: string; scope: "event"; type: string; v: 1;};Everything on the same-origin bus, multiplexed by scope over one BroadcastChannel per name.
v is the wire protocol version, and changing it is a decision with rules —
see wire.ts for what may be added within a version and what must bump it.
Union Members
Section titled “Union Members”Type Literal
Section titled “Type Literal”{ clientId: string; key: string; kind: PeerKind; scope: "state"; type: "patch"; v: 1; value: unknown; version: Version;}Type Literal
Section titled “Type Literal”{ clientId: string; kind: PeerKind; scope: "state"; type: "hello"; v: 1;}Type Literal
Section titled “Type Literal”{ clientId: string; kind: PeerKind; scope: "state"; state: Record<string, unknown>; type: "snapshot"; v: 1; versions: Record<string, Version>;}Type Literal
Section titled “Type Literal”{ clientId: string; kind: PeerKind; metadata?: unknown; scope: "presence"; type: "hello" | "ping" | "bye"; v: 1;}clientId
Section titled “clientId”clientId: string;kind: PeerKind;metadata?
Section titled “metadata?”optional metadata?: unknown;Whatever this client wants peers to know about it — a display name, a tab title, a cursor.
Carried on hello only, never on a ping. A ping is a heartbeat and
arrives constantly; attaching metadata to it would re-announce
unchanged data forever and churn every subscriber’s roster. Additive
within wire v1: a build that predates it neither sets nor reads it.
scope: "presence";type: "hello" | "ping" | "bye";v: 1;Type Literal
Section titled “Type Literal”{ clientId: string; kind: PeerKind; scope: "leader"; type: "hello"; v: 1;}Type Literal
Section titled “Type Literal”{ clientId: string; kind: PeerKind; scope: "leader"; term: Version; type: "claim" | "heartbeat" | "resign"; v: 1;}clientId
Section titled “clientId”clientId: string;kind: PeerKind;scope: "leader";term: Version;The claimant’s term. Arbitrated with newer() — the same clock the store uses.
type: "claim" | "heartbeat" | "resign";v: 1;Type Literal
Section titled “Type Literal”{ clientId: string; key: string; kind: PeerKind; scope: "op"; type: "hello"; v: 1;}Type Literal
Section titled “Type Literal”{ action: unknown; clientId: string; key: string; kind: PeerKind; opId: string; scope: "op"; type: "propose"; v: 1;}action
Section titled “action”action: unknown;clientId
Section titled “clientId”clientId: string;key: string;kind: PeerKind;opId: string;Identifies this dispatch across its proposal and its commit, so a commit can be recognised as one’s own and applied once.
scope: "op";type: "propose";v: 1;Type Literal
Section titled “Type Literal”{ action: unknown; clientId: string; key: string; kind: PeerKind; opId: string; scope: "op"; seq: number; type: "commit"; v: 1;}action
Section titled “action”action: unknown;clientId
Section titled “clientId”clientId: string;key: string;kind: PeerKind;opId: string;scope: "op";seq: number;The leader’s ordering decision: a gapless counter every client replays in the same order.
type: "commit";v: 1;Type Literal
Section titled “Type Literal”{ clientId: string; key: string; kind: PeerKind; scope: "op"; seq: number; state: unknown; type: "snapshot"; v: 1;}Type Literal
Section titled “Type Literal”{ clientId: string; kind: PeerKind; msgId: string; payload: unknown; replyTo?: string; scope: "event"; type: string; v: 1;}clientId
Section titled “clientId”clientId: string;kind: PeerKind;msgId: string;payload
Section titled “payload”payload: unknown;replyTo?
Section titled “replyTo?”optional replyTo?: string;The msgId this is an answer to, when it is one.
Additive within wire v1: a build that predates ask never sets it and
never reads it, so the field is simply absent both ways — which is the
rule for new optional fields (see wire.ts).
scope: "event";type: string;v: 1;