Collaboration Protocol
Typed WebSocket messages for realtime collaboration
The collaboration protocol defines all Socket.IO messages exchanged between client and server. All message types are exported from @hfu.digital/boardkit-core and used by both @hfu.digital/boardkit-nestjs (server) and @hfu.digital/boardkit-react (client).
import { PROTOCOL_VERSION } from '@hfu.digital/boardkit-core';
// PROTOCOL_VERSION = 1Client Messages (Client → Server)
type ClientMessage =
| JoinMessage
| LeaveMessage
| MutateMessage
| CursorMessage
| PageSwitchMessage
| PingMessage;JoinMessage
Sent when a client connects to a board session.
interface JoinMessage {
type: 'join';
boardId: string;
token: string;
lastSequence?: number; // for reconnection delta sync
}LeaveMessage
interface LeaveMessage {
type: 'leave';
}MutateMessage
Sends element mutations to the server.
interface MutateMessage {
type: 'mutate';
mutations: ElementMutation[];
requestId: string; // for matching ack responses
}CursorMessage
Broadcasts cursor position to other participants.
interface CursorMessage {
type: 'cursor';
position: Point;
pageId: string;
}PageSwitchMessage
interface PageSwitchMessage {
type: 'pageSwitch';
pageId: string;
}PingMessage
interface PingMessage {
type: 'ping';
timestamp: number;
}Server Messages (Server → Client)
type ServerMessage =
| JoinedMessage
| SyncDeltaMessage
| SyncFullMessage
| MutationAckMessage
| MutationBroadcastMessage
| CursorBroadcastMessage
| ParticipantJoinedMessage
| ParticipantLeftMessage
| RateLimitedMessage
| ErrorMessage
| PongMessage;JoinedMessage
Confirms successful join with the current participant list.
interface JoinedMessage {
type: 'joined';
userId: string;
boardId: string;
participants: Array<{
userId: string;
displayName: string;
color: string;
}>;
currentSequence: number;
}SyncDeltaMessage
Delivers missed mutations since the client's lastSequence (used for reconnection).
interface SyncDeltaMessage {
type: 'sync:delta';
mutations: ElementMutation[];
fromSequence: number;
toSequence: number;
}SyncFullMessage
Delivers the complete board state (used when delta sync is not possible or on first join).
interface SyncFullMessage {
type: 'sync:full';
boardData: Record<string, unknown>;
currentSequence: number;
}MutationAckMessage
Acknowledges a client's mutation request.
interface MutationAckMessage {
type: 'mutation:ack';
requestId: string;
sequence: number;
}MutationBroadcastMessage
Broadcasts another client's mutations to all other participants.
interface MutationBroadcastMessage {
type: 'mutation:broadcast';
userId: string;
mutations: ElementMutation[];
sequence: number;
}CursorBroadcastMessage
interface CursorBroadcastMessage {
type: 'cursor:broadcast';
userId: string;
position: Point;
pageId: string;
}ParticipantJoinedMessage / ParticipantLeftMessage
interface ParticipantJoinedMessage {
type: 'participant:joined';
userId: string;
displayName: string;
color: string;
}
interface ParticipantLeftMessage {
type: 'participant:left';
userId: string;
}RateLimitedMessage
interface RateLimitedMessage {
type: 'rate-limited';
retryAfterMs: number;
}ErrorMessage
interface ErrorMessage {
type: 'error';
code: string;
message: string;
}Common error codes: AUTH_FAILED, FORBIDDEN, SESSION_MISMATCH.
PongMessage
interface PongMessage {
type: 'pong';
timestamp: number;
serverTime: number;
}Message Flow Diagram
Client A Server Client B
│ │ │
├── join ────────────────► │
│ ├── joined ──────────────►
◄── joined ──────────────┤ │
◄── sync:full ───────────┤ │
│ │ │
├── mutate ──────────────► │
◄── mutation:ack ────────┤ │
│ ├── mutation:broadcast ──►
│ │ │
├── cursor ──────────────► │
│ ├── cursor:broadcast ────►
│ │ │