TypeScript Types Reference
Complete reference for all exported TypeScript types in Vuer-RTC.
Core Message Types
CRDTMessage
The envelope containing CRDT metadata and a batch of operations. This is the fundamental unit of communication in Vuer-RTC.
interface CRDTMessage {
// CRDT Metadata (wrapper)
id: string; // Message ID (UUID)
sessionId: string; // Session that created this message
clock: VectorClock; // Vector clock for causal ordering
lamportTime: number; // Lamport timestamp for total ordering
timestamp: number; // Wall-clock time (seconds since epoch)
// Operations (batch)
ops: Operation[]; // One or more operations
}Example:
const message: CRDTMessage = {
id: 'msg-uuid-123',
sessionId: 'session-abc',
clock: { 'session-abc': 5, 'session-xyz': 3 },
lamportTime: 42,
timestamp: 1708989600,
ops: [
{ otype: 'vector3.set', key: 'cube', path: 'position', value: [1, 2, 3] }
]
};Operation
Union type of all operation types. Every operation extends BaseOp.
type Operation =
| NumberSetOp | NumberAddOp | NumberMultiplyOp | NumberMinOp | NumberMaxOp
| StringSetOp | StringConcatOp
| TextInitOp | TextInsertOp | TextDeleteOp | TextReplaceOp
| BooleanSetOp | BooleanOrOp | BooleanAndOp
| Vector3SetOp | Vector3AddOp | Vector3MultiplyOp | Vector3ApplyEulerOp | Vector3ApplyQuaternionOp
| EulerSetOp | EulerAddOp
| QuaternionSetOp | QuaternionMultiplyOp
| ColorSetOp | ColorBlendOp
| ArraySetOp | ArrayPushOp | ArrayUnionOp | ArrayRemoveOp
| ObjectSetOp | ObjectMergeOp
| NodeInsertOp | NodeRemoveOp | NodeMoveOp
| MetaUndoOp | MetaRedoOp;BaseOp
Base interface extended by all operations.
interface BaseOp {
key: string; // Node key (human-friendly, e.g., 'cube-1', 'player', 'scene')
otype: string; // dtype operation: 'number.set', 'vector3.add', etc.
path: string; // Property path: 'color', 'transform.position', etc.
}Number Operations
NumberSetOp
interface NumberSetOp extends BaseOp {
otype: 'number.set';
value: number;
}Example:
{ otype: 'number.set', key: 'light-1', path: 'intensity', value: 0.8 }NumberAddOp
interface NumberAddOp extends BaseOp {
otype: 'number.add';
value: number;
}Example:
{ otype: 'number.add', key: 'player', path: 'score', value: 100 }NumberMultiplyOp
interface NumberMultiplyOp extends BaseOp {
otype: 'number.multiply';
value: number;
}NumberMinOp
interface NumberMinOp extends BaseOp {
otype: 'number.min';
value: number;
}NumberMaxOp
interface NumberMaxOp extends BaseOp {
otype: 'number.max';
value: number;
}String Operations
StringSetOp
interface StringSetOp extends BaseOp {
otype: 'string.set';
value: string;
}StringConcatOp
interface StringConcatOp extends BaseOp {
otype: 'string.concat';
value: string;
separator?: string; // Optional separator (default: '')
}Text CRDT Operations
Text operations support collaborative character-level editing using a CRDT.
TextInitOp
Initialize a CRDT-backed text property. Must be called before using text operations.
interface TextInitOp extends BaseOp {
otype: 'text.init';
value?: string; // Optional initial content
}Example:
{ otype: 'text.init', key: 'doc', path: 'content', value: 'Hello world' }TextInsertOp
Insert text at a position. Supports two formats:
- Position-based (local operations):
{ position, value } - CRDT metadata (network sync):
{ id, content, parentId, seq }
interface TextInsertOp extends BaseOp {
otype: 'text.insert';
// Position-based format (local convenience)
position?: number;
value?: string;
// CRDT metadata format (network sync)
id?: { agent: string; seq: number };
content?: string;
parentId?: { agent: string; seq: number } | null;
seq?: number; // Lamport timestamp
}Examples:
// Local format
{ otype: 'text.insert', key: 'doc', path: 'content', position: 5, value: 'world' }
// CRDT format (generated internally)
{
otype: 'text.insert',
key: 'doc',
path: 'content',
id: { agent: 'session-abc', seq: 10 },
content: 'world',
parentId: { agent: 'session-abc', seq: 9 },
seq: 42
}TextDeleteOp
Delete text at a position. Supports two formats:
- Position-based:
{ position, length } - CRDT metadata:
{ deletions }
interface TextDeleteOp extends BaseOp {
otype: 'text.delete';
// Position-based format
position?: number;
length?: number;
// CRDT metadata format
deletions?: Array<{ id: { agent: string; seq: number }; length: number }>;
}Examples:
// Local format
{ otype: 'text.delete', key: 'doc', path: 'content', position: 5, length: 3 }
// CRDT format
{
otype: 'text.delete',
key: 'doc',
path: 'content',
deletions: [
{ id: { agent: 'session-abc', seq: 10 }, length: 3 }
]
}TextReplaceOp
Atomic delete + insert (for select-and-type).
interface TextReplaceOp extends BaseOp {
otype: 'text.replace';
// Position-based format
position?: number;
length?: number; // chars to delete
value?: string; // chars to insert
// CRDT metadata format
deletions?: Array<{ id: { agent: string; seq: number }; length: number }>;
id?: { agent: string; seq: number };
content?: string;
parentId?: { agent: string; seq: number } | null;
seq?: number;
}Boolean Operations
BooleanSetOp
interface BooleanSetOp extends BaseOp {
otype: 'boolean.set';
value: boolean;
}BooleanOrOp
interface BooleanOrOp extends BaseOp {
otype: 'boolean.or';
value: boolean;
}BooleanAndOp
interface BooleanAndOp extends BaseOp {
otype: 'boolean.and';
value: boolean;
}Vector3 Operations
Vector3SetOp
interface Vector3SetOp extends BaseOp {
otype: 'vector3.set';
value: [number, number, number];
}Example:
{ otype: 'vector3.set', key: 'cube', path: 'position', value: [1, 2, 3] }Vector3AddOp
interface Vector3AddOp extends BaseOp {
otype: 'vector3.add';
value: [number, number, number];
}Vector3MultiplyOp
interface Vector3MultiplyOp extends BaseOp {
otype: 'vector3.multiply';
value: [number, number, number];
}Vector3ApplyEulerOp
Rotate a vector by euler angles.
type EulerOrder = 'XYZ' | 'XZY' | 'YXZ' | 'YZX' | 'ZXY' | 'ZYX';
interface Vector3ApplyEulerOp extends BaseOp {
otype: 'vector3.applyEuler';
value: [number, number, number]; // [x, y, z] rotation angles in radians
order?: EulerOrder; // Default: 'XYZ'
intrinsic?: boolean; // Default: true (axes move with body)
}Example:
// Intrinsic YXZ rotation (common for FPS cameras)
{
otype: 'vector3.applyEuler',
key: 'camera',
path: 'direction',
value: [0, Math.PI/2, 0],
order: 'YXZ'
}Vector3ApplyQuaternionOp
interface Vector3ApplyQuaternionOp extends BaseOp {
otype: 'vector3.applyQuaternion';
value: [number, number, number, number]; // [x, y, z, w]
}Euler Operations
EulerSetOp
interface EulerSetOp extends BaseOp {
otype: 'euler.set';
value: [number, number, number]; // [x, y, z] in radians
}EulerAddOp
interface EulerAddOp extends BaseOp {
otype: 'euler.add';
value: [number, number, number]; // [x, y, z] in radians
}Quaternion Operations
QuaternionSetOp
interface QuaternionSetOp extends BaseOp {
otype: 'quaternion.set';
value: [number, number, number, number]; // [x, y, z, w]
}QuaternionMultiplyOp
interface QuaternionMultiplyOp extends BaseOp {
otype: 'quaternion.multiply';
value: [number, number, number, number]; // [x, y, z, w]
}Color Operations
ColorSetOp
interface ColorSetOp extends BaseOp {
otype: 'color.set';
value: string; // Hex color (e.g., '#ff0000')
}ColorBlendOp
interface ColorBlendOp extends BaseOp {
otype: 'color.blend';
value: string; // Hex color to blend towards
}Array Operations
ArraySetOp
interface ArraySetOp extends BaseOp {
otype: 'array.set';
value: any[];
}ArrayPushOp
interface ArrayPushOp extends BaseOp {
otype: 'array.push';
value: any;
}ArrayUnionOp
interface ArrayUnionOp extends BaseOp {
otype: 'array.union';
value: any[]; // Add unique items
}ArrayRemoveOp
interface ArrayRemoveOp extends BaseOp {
otype: 'array.remove';
value: any;
}Object Operations
ObjectSetOp
interface ObjectSetOp extends BaseOp {
otype: 'object.set';
value: Record<string, any>;
}ObjectMergeOp
interface ObjectMergeOp extends BaseOp {
otype: 'object.merge';
value: Record<string, any>;
}Scene Graph Operations
NodeInsertOp
Create a new node as a child of parent.
interface NodeInsertOp extends BaseOp {
key: string; // Parent node's key
otype: 'node.insert';
path: 'children';
value: {
key: string; // New node's key (also used as id)
tag: string; // 'Scene' | 'Mesh' | 'Group' | ...
name: string; // Display name
[key: string]: any; // Initial properties
};
}Example:
{
otype: 'node.insert',
key: 'scene',
path: 'children',
value: {
key: 'cube-1',
tag: 'Mesh',
name: 'Red Cube',
position: [0, 0, 0],
color: '#ff0000'
}
}NodeRemoveOp
Remove a node from parent (tombstone).
interface NodeRemoveOp extends BaseOp {
key: string; // Parent node's key
otype: 'node.remove';
path: 'children';
value: string; // Node key to remove
}NodeMoveOp
Move a node from one parent to another (reparent).
interface NodeMoveOp extends BaseOp {
key: string; // Old parent node's key
otype: 'node.move';
path: 'children';
value: {
nodeKey: string; // Node key to move
newParent: string; // New parent node key
};
}Meta Operations (Undo/Redo)
MetaUndoOp
Mark a message as undone.
interface MetaUndoOp {
key: '_meta';
otype: 'meta.undo';
path: '_meta';
targetMsgId: string; // Message ID to undo
}MetaRedoOp
Unmark a message as undone.
interface MetaRedoOp {
key: '_meta';
otype: 'meta.redo';
path: '_meta';
targetMsgId: string; // Message ID to redo
}Scene Graph State
SceneNode
A node in the flattened scene graph. Properties are stored directly with dot-notation paths.
interface SceneNode {
// Identity
key: string; // Unique key in scene (human-friendly)
tag: string; // Node type
name: string; // Display name
// Tree structure
children: string[]; // Child node keys
// CRDT metadata envelope
_crdt: CRDTEnvelope;
// Dynamic properties (flat with dot-notation paths)
// e.g., 'transform.position', 'color', 'opacity'
[path: string]: unknown;
}Example:
const node: SceneNode = {
key: 'cube-1',
tag: 'Mesh',
name: 'Red Cube',
children: [],
_crdt: {
clock: { 'session-abc': 5 },
lamportTime: 42,
createdAt: 1708989600,
updatedAt: 1708989650,
lww: {
'position': { lamportTime: 42, sessionId: 'session-abc' },
'color': { lamportTime: 43, sessionId: 'session-abc' }
}
},
'position': [1, 2, 3],
'color': '#ff0000',
'opacity': 0.8
};CRDTEnvelope
All CRDT metadata for a SceneNode, stored under _crdt.
interface CRDTEnvelope {
clock: VectorClock;
lamportTime: number;
createdAt: number; // Timestamp when node was created
updatedAt: number; // Last update timestamp
deletedAt?: number; // Tombstone for soft delete
lww: Record<string, PropertyLWW>; // Per-property LWW metadata
}PropertyLWW
Per-property Last-Write-Wins metadata.
interface PropertyLWW {
lamportTime: number;
sessionId: string;
}SceneGraph
Complete scene representation.
interface SceneGraph {
nodes: Record<string, SceneNode>; // Flattened map by key
rootKey: string; // Root node key
}Example:
const graph: SceneGraph = {
rootKey: 'scene',
nodes: {
'scene': {
key: 'scene',
tag: 'Scene',
name: 'Root',
children: ['cube-1', 'light-1'],
_crdt: { /* ... */ }
},
'cube-1': {
key: 'cube-1',
tag: 'Mesh',
name: 'Red Cube',
children: [],
_crdt: { /* ... */ },
'position': [1, 2, 3]
}
}
};Client State
ClientState
Complete client-side state.
interface ClientState {
// Current computed value (derived from snapshot + journal + edits)
graph: SceneGraph;
// Committed edits (sent or pending acknowledgement)
journal: JournalEntry[];
// Uncommitted operations (in-progress edits)
edits: EditBuffer;
// Checkpoint for fast replay
snapshot: Snapshot;
// Clocks
lamportTime: number;
vectorClock: VectorClock;
sessionId: string;
}JournalEntry
A committed message with metadata.
interface JournalEntry {
msg: CRDTMessage;
ack: boolean; // Has server acknowledged?
deletedAt?: number; // If set, message is "undone"
}EditBuffer
Uncommitted operations.
interface EditBuffer {
ops: Operation[]; // Pending operations (merged)
baseGraph: SceneGraph | null; // Graph state when edits started
}Snapshot
Checkpoint for fast replay.
interface Snapshot {
graph: SceneGraph;
vectorClock: VectorClock;
lamportTime: number; // Max lamport time baked in
journalIndex: number; // How many entries are baked in
}GraphStore
The public API for the graph store.
interface GraphStore {
// State access
getState: () => ClientState;
subscribe: (listener: () => void) => () => void;
// Edit operations
edit: (op: Operation) => void;
commit: (description?: string) => CRDTMessage | null;
// Server communication
receive: (msg: CRDTMessage) => void;
ack: (msgId: string) => void;
loadServerState: (snapshot: Snapshot, journal: CRDTMessage[]) => void;
// Undo/redo
undo: () => { msg: CRDTMessage | null };
redo: () => { msg: CRDTMessage | null };
// Maintenance
compact: () => void;
compactToWatermark: (watermark: VectorClock) => void;
}CreateGraphOptions
Options for creating a graph store.
interface CreateGraphOptions {
sessionId: string;
initialSnapshot?: Snapshot;
onSend?: (msg: CRDTMessage) => void;
onStateChange?: (state: ClientState) => void;
}Vector Clock
VectorClock
CRDT-inspired vector clock for causal ordering.
type VectorClock = Record<string, number>;Example:
const clock: VectorClock = {
'session-abc': 5,
'session-xyz': 3,
'session-123': 7
};Vector clocks track causality:
- Each session has a counter
- Counters increment with each operation
- Clocks are merged to detect concurrent operations
TextRope Types
Types for the collaborative text editing CRDT.
ItemId
Identifier for a text item.
interface ItemId {
agent: string; // Session ID
seq: number; // Sequence number
}Item
A text item in the rope.
interface Item {
id: ItemId;
content: string;
isDeleted: boolean;
parentId: ItemId | null;
seq: number; // Lamport timestamp
}InsertOp
Insert operation for text rope.
interface InsertOp {
id: ItemId;
content: string;
parentId: ItemId | null;
seq: number;
}DeleteOp
Delete operation for text rope.
interface DeleteOp {
deletions: Array<{ id: ItemId; length: number }>;
}ReplaceOp
Replace operation (atomic delete + insert).
interface ReplaceOp {
delete: DeleteOp;
insert: InsertOp;
}MoveOp
Move operation (delete + insert at new position).
interface MoveOp {
delete: DeleteOp;
insert: InsertOp;
}TextRope
High-performance text CRDT based on RGA/YATA.
class TextRope {
_tree: ItemTree;
_agentIndex: Map<string, SpanEntry[]>;
agentId: string;
clock: number;
maxSeq: number;
}Sync Types
SyncDigest
Bloom filter digest for sync reconciliation.
interface SyncDigest {
mtype: 'sync';
vectorClock: VectorClock; // Covers compacted (snapshot) entries
filter: Uint8Array; // Bloom filter bytes (covers journal entries)
count: number; // Journal length (diagnostics)
}Usage:
import { buildSyncDigest } from 'vuer-rtc';
const digest = buildSyncDigest(clientState);
// Send to server for efficient syncType Usage Examples
Creating a CRDTMessage
import { createGraph } from 'vuer-rtc';
import type { CRDTMessage, Operation } from 'vuer-rtc';
const store = createGraph({
sessionId: 'session-abc',
onSend: (msg: CRDTMessage) => {
// Send to server
console.log(`Sending ${msg.ops.length} operations`);
}
});
// Edit operations are batched
store.edit({ otype: 'vector3.set', key: 'cube', path: 'position', value: [1, 2, 3] });
store.edit({ otype: 'color.set', key: 'cube', path: 'color', value: '#ff0000' });
// Commit creates a CRDTMessage with both ops
const msg = store.commit('Update cube');Working with SceneGraph
import type { SceneGraph, SceneNode } from 'vuer-rtc';
const graph: SceneGraph = store.getState().graph;
// Access nodes
const cube: SceneNode | undefined = graph.nodes['cube-1'];
// Traverse children
const rootNode = graph.nodes[graph.rootKey];
rootNode.children.forEach(childKey => {
const child = graph.nodes[childKey];
console.log(`Child: ${child.name}`);
});
// Access properties with type safety
if (cube) {
const position = cube['position'] as [number, number, number];
const color = cube['color'] as string;
}Implementing Custom Operations
import type { Operation, Vector3SetOp, ColorSetOp } from 'vuer-rtc';
function updateCubeColor(store: GraphStore, key: string, color: string) {
const op: ColorSetOp = {
otype: 'color.set',
key,
path: 'color',
value: color
};
store.edit(op);
}
function moveCube(store: GraphStore, key: string, delta: [number, number, number]) {
const op: Vector3AddOp = {
otype: 'vector3.add',
key,
path: 'position',
value: delta
};
store.edit(op);
}Handling Text CRDT
import type { TextInitOp, TextInsertOp, TextDeleteOp } from 'vuer-rtc';
// Initialize text property
const initOp: TextInitOp = {
otype: 'text.init',
key: 'doc',
path: 'content',
value: 'Hello world'
};
store.edit(initOp);
// Insert text
const insertOp: TextInsertOp = {
otype: 'text.insert',
key: 'doc',
path: 'content',
position: 6,
value: 'beautiful '
};
store.edit(insertOp);
// Delete text
const deleteOp: TextDeleteOp = {
otype: 'text.delete',
key: 'doc',
path: 'content',
position: 0,
length: 5
};
store.edit(deleteOp);