GitHub

API Reference

Complete reference for all exported functions, types, and hooks in Vuer-RTC.

Core Exports

Graph Factory

createGraph

Create a graph store for managing CRDT-based scene graph state.

function createGraph(options: CreateGraphOptions): GraphStore

Parameters:

ParameterTypeDescription
options.sessionIdstringUnique session identifier
options.onSend(msg: CRDTMessage) => voidCallback invoked when a message is ready to send to the server
options.onStateChange(state: ClientState) => voidOptional callback invoked on every state change
options.initialSnapshotSnapshotOptional initial snapshot to restore from

Returns: GraphStore - A store with methods to edit, commit, undo/redo, and sync state.

Example:

const store = createGraph({
  sessionId: 'user-123',
  onSend: (msg) => websocket.send(JSON.stringify(msg)),
});

store.edit({ otype: 'vector3.add', key: 'cube', path: 'position', value: [1, 0, 0] });
store.commit('Move cube');

createGraphFromServer

Create a graph store initialized from server state (snapshot + journal).

function createGraphFromServer(
  sessionId: string,
  snapshot: Snapshot,
  journal: CRDTMessage[],
  onSend?: (msg: CRDTMessage) => void
): GraphStore

Parameters:

ParameterTypeDescription
sessionIdstringUnique session identifier
snapshotSnapshotServer snapshot containing graph state and metadata
journalCRDTMessage[]Array of uncompacted messages from server
onSend(msg: CRDTMessage) => voidOptional callback for outgoing messages

Returns: GraphStore


Client Actions

Low-level state manipulation functions. Most users should use createGraph or React hooks instead.

State Initialization

createInitialState

Create initial client state.

function createInitialState(sessionId: string, initialSnapshot?: Snapshot): ClientState

initFromServer

Initialize client state from server snapshot and journal.

function initFromServer(
  sessionId: string,
  snapshot: Snapshot,
  journal: CRDTMessage[]
): ClientState

Edit Buffer Operations

onEdit

Add an operation to the edit buffer (uncommitted).

function onEdit(state: ClientState, op: Operation): ClientState

commitEdits

Commit pending edits as a single message.

function commitEdits(
  state: ClientState,
  description?: string
): { state: ClientState; msg: CRDTMessage | null }

Returns: New state and the message to send (or null if no edits).

cancelEdits

Discard all uncommitted edits.

function cancelEdits(state: ClientState): ClientState

Server Communication

onRemoteMessage

Process an incoming message from another client or server.

function onRemoteMessage(state: ClientState, msg: CRDTMessage): ClientState

onServerAck

Mark a message as acknowledged by the server.

function onServerAck(state: ClientState, msgId: string): ClientState

Undo/Redo

undo

Undo the last committed message.

function undo(state: ClientState): { state: ClientState; undoMsg: CRDTMessage | null }

redo

Redo the last undone message.

function redo(state: ClientState): { state: ClientState; redoMsg: CRDTMessage | null }

Compaction

compact

Compact the journal by creating a new snapshot at the current watermark.

function compact(state: ClientState): ClientState

Removes all acknowledged messages from the journal and updates the snapshot.

compactToWatermark

Compact to a specific watermark (lamport timestamp).

function compactToWatermark(state: ClientState, watermark: number): ClientState

Utilities

generateUUID

Generate a compact session ID (12-character nanoid).

function generateUUID(): string

getUnackedMessages

Get all messages that have not been acknowledged by the server.

function getUnackedMessages(state: ClientState): CRDTMessage[]

hasPendingMessages

Check if there are any unacknowledged messages.

function hasPendingMessages(state: ClientState): boolean

getPendingCount

Get the count of unacknowledged messages.

function getPendingCount(state: ClientState): number

React Hooks

Available from @vuer-ai/vuer-rtc/hooks subpath.

Provider

GraphProvider

Wrap your app to provide graph context.

function GraphProvider(props: GraphProviderProps): JSX.Element

Props:

PropTypeDescription
sessionIdstringUnique session identifier
onSend(msg: CRDTMessage) => voidCallback for outgoing messages
childrenReactNodeChild components

Example:

<GraphProvider sessionId="user-123" onSend={sendToServer}>
  <Scene />
</GraphProvider>

State Access Hooks

useGraphStore

Access the underlying graph store.

function useGraphStore(): GraphStore

useGraph

Get the current graph state. Re-renders on any graph change.

function useGraph(): SceneGraph

useNode

Subscribe to a specific node. Re-renders only when that node changes.

function useNode(key: string): SceneNode | undefined

useNodeProperty

Subscribe to a specific property of a node. Re-renders only when that property changes.

function useNodeProperty<T>(key: string, path: string): T | undefined

Example:

const position = useNodeProperty<[number, number, number]>('cube-1', 'position');

Action Hooks

useGraphActions

Get actions to modify the graph.

function useGraphActions(): {
  edit: (op: Operation) => void;
  commit: (description?: string) => CRDTMessage | null;
  cancelEdits: () => void;
  undo: () => void;
  redo: () => void;
  receive: (msg: CRDTMessage) => void;
  compact: () => void;
  compactToWatermark: (watermark: number) => void;
}

Example:

const { edit, commit, undo, redo } = useGraphActions();

const onDrag = (delta: [number, number, number]) => {
  edit({ otype: 'vector3.add', key: 'cube', path: 'position', value: delta });
};

const onDragEnd = () => {
  commit('Move cube');
};

useDrag

Helper hook for drag operations with automatic edit buffering.

function useDrag(
  key: string,
  path: string,
  description: string
): {
  onDragStart: () => void;
  onDrag: (delta: [number, number, number]) => void;
  onDragEnd: () => void;
}

Example:

const { onDragStart, onDrag, onDragEnd } = useDrag('cube-1', 'position', 'Move cube');

useUndoRedoShortcuts

Enable keyboard shortcuts for undo/redo (Cmd/Ctrl+Z, Cmd/Ctrl+Shift+Z).

function useUndoRedoShortcuts(): void

Operations

High-level operation dispatcher and validator.

Dispatcher

applyOperation

Apply a single operation to the graph.

function applyOperation(graph: SceneGraph, op: Operation): SceneGraph

applyMessage

Apply all operations in a message to the graph.

function applyMessage(graph: SceneGraph, msg: CRDTMessage): SceneGraph

applyMessages

Apply multiple messages to the graph.

function applyMessages(graph: SceneGraph, messages: CRDTMessage[]): SceneGraph

createEmptyGraph

Create an empty scene graph with root node.

function createEmptyGraph(): SceneGraph

Validation

OperationValidator

Validator for operation schemas.

class OperationValidator {
  validate(op: Operation): ValidationResult;
}

Example:

const validator = new OperationValidator();
const result = validator.validate({ otype: 'vector3.set', key: 'cube', path: 'position', value: [1, 2, 3] });
if (!result.valid) {
  console.error(result.errors);
}

Text CRDT Utilities

getTextDocument

Get the TextRope instance from a node property.

function getTextDocument(graph: SceneGraph, key: string, path: string): TextRope | null

CRDT - TextRope

High-performance text CRDT with B-tree storage. Available from @vuer-ai/vuer-rtc/crdt.

Factory

create

Create a new TextRope instance.

function create(agentId: string): TextRope

Queries

getText

Get the visible text content.

function getText(rope: TextRope): string

getLength

Get the visible character count.

function getLength(rope: TextRope): number

getItems

Get all items (including deleted).

function getItems(rope: TextRope): Item[]

getStats

Get statistics about the rope structure.

function getStats(rope: TextRope): {
  items: number;
  visibleChars: number;
  deletedChars: number;
  agents: number;
  maxSeq: number;
}

Local Edits

insert

Insert text at a position.

function insert(rope: TextRope, pos: number, content: string): TextRope

remove

Remove text range.

function remove(rope: TextRope, from: number, to: number): DeleteOp

replace

Replace text range.

function replace(rope: TextRope, from: number, to: number, content: string): ReplaceOp

move

Move text range to a new position.

function move(rope: TextRope, from: number, to: number, targetPos: number): MoveOp

Remote Operations

apply

Apply a remote insert operation.

function apply(rope: TextRope, op: InsertOp): TextRope

applyDelete

Apply a remote delete operation.

function applyDelete(rope: TextRope, op: DeleteOp): TextRope

applyReplace

Apply a remote replace operation.

function applyReplace(rope: TextRope, op: ReplaceOp): TextRope

applyMove

Apply a remote move operation.

function applyMove(rope: TextRope, op: MoveOp): TextRope

Merging & Snapshots

merge

Merge two ropes (used for reconciliation).

function merge(rope1: TextRope, rope2: TextRope): TextRope

snapshot

Create a deep copy of the rope.

function snapshot(rope: TextRope): TextRope

compact

Remove tombstones (deleted items) from the rope.

function compact(rope: TextRope): TextRope

Serialization

toRaw

Serialize to plain object.

function toRaw(rope: TextRope): RawTextRope

fromRaw

Deserialize from plain object.

function fromRaw(raw: RawTextRope): TextRope

fromSnapshot

Create from a snapshot object.

function fromSnapshot(snapshot: RawTextRope): TextRope

Item Utilities

findItemById

Find an item by its ID.

function findItemById(rope: TextRope, id: ItemId): Item | null

itemIdEquals

Compare two item IDs for equality.

function itemIdEquals(a: ItemId | null, b: ItemId | null): boolean

itemIdCompare

Compare two item IDs for ordering.

function itemIdCompare(a: ItemId, b: ItemId): number

RangeTree (B-tree)

Low-level B-tree implementation used by TextRope.

class RangeTree {
  constructor(order?: number);
  insert(item: Item, ord: number): void;
  splitAt(ord: number): void;
  getAt(ord: number): Item | null;
  totalVisible(): number;
  totalItems(): number;
  // ... additional methods
}

State Management

VectorClockManager

Causal ordering utilities.

class VectorClockManager {
  create(sessionId: string): VectorClock;
  increment(clock: VectorClock, sessionId: string): VectorClock;
  merge(clock1: VectorClock, clock2: VectorClock): VectorClock;
  compare(clock1: VectorClock, clock2: VectorClock): number;
}

Example:

const manager = new VectorClockManager();
const clock = manager.create('session-1');
const newClock = manager.increment(clock, 'session-1');
const merged = manager.merge(clock, remoteClock);

DType

Data type registry for server-side conflict resolution.

class DType {
  static register<T>(
    dtype: string,
    defaultValue: T,
    mergeFn: MergeFn<T>
  ): void;

  static getDefault(dtype: string): unknown;
  static merge<T>(dtype: string, a: ValueWithMeta<T>, b: ValueWithMeta<T>): ValueWithMeta<T>;
}

ConflictResolver

Server-side conflict resolution.

class ConflictResolver {
  resolve(existing: PropertyLWW, incoming: PropertyLWW, otype: string): PropertyLWW;
}

function parseOtype(otype: string): { dtype: string; verb: string }

Sync Utilities

Efficient message reconciliation using bloom filters.

BloomFilter

Probabilistic set for message ID reconciliation.

class BloomFilter {
  constructor(numBits: number, numHashes: number);

  static create(expectedItems: number, falsePositiveRate?: number): BloomFilter;

  add(key: string): void;
  has(key: string): boolean;

  toBytes(): Uint8Array;
  static fromBytes(bytes: Uint8Array): BloomFilter;
}

Example:

const filter = BloomFilter.create(1000, 0.01); // 1000 items, 1% false positive rate
filter.add('msg-123');
filter.add('msg-456');

if (filter.has('msg-123')) {
  console.log('Message probably in set');
}

Sync Digest

buildSyncDigest

Build a sync digest from client state for reconciliation.

function buildSyncDigest(state: ClientState): SyncDigest

Returns: SyncDigest object containing:

  • vectorClock: Covers all compacted messages
  • filter: Bloom filter covering uncompacted journal
  • count: Journal length

Example:

const digest = buildSyncDigest(state);
websocket.send(JSON.stringify(digest));

Types

Core Types

interface CRDTMessage {
  id: string;
  sessionId: string;
  clock: VectorClock;
  lamportTime: number;
  timestamp: number;
  ops: Operation[];
}

interface SceneGraph {
  nodes: Record<string, SceneNode>;
  rootKey: string;
}

interface SceneNode {
  key: string;
  tag?: string;
  children?: string[];
  _crdt: CRDTEnvelope;
  [key: string]: unknown; // Dynamic properties
}

interface ClientState {
  graph: SceneGraph;
  journal: JournalEntry[];
  edits: EditBuffer;
  snapshot: Snapshot;
  lamportTime: number;
  vectorClock: VectorClock;
  sessionId: string;
}

interface Snapshot {
  graph: SceneGraph;
  vectorClock: VectorClock;
  lamportTime: number;
  journalIndex: number;
}

TextRope Types

interface ItemId {
  agent: string;
  seq: number;
}

interface Item {
  id: ItemId;
  content: string;
  isDeleted: boolean;
  parentId: ItemId | null;
  seq: number;
}

interface InsertOp {
  id: ItemId;
  content: string;
  parentId: ItemId | null;
  seq: number;
}

interface DeleteOp {
  deletions: Array<{ id: ItemId; length: number }>;
}

Operation Types

All operations extend BaseOp:

interface BaseOp {
  otype: string;  // e.g., 'vector3.add', 'string.set'
  key?: string;   // Target node key ('.' = root)
  path?: string;  // Property path ('.' = node root)
  value?: unknown;
  // Additional fields per operation type
}

See the Operations page for the complete list of operation types.


Wire Serialization

encode

Serialize a message using msgpack.

function encode(msg: CRDTMessage | SyncDigest): Uint8Array

decode

Deserialize a message from msgpack.

function decode(bytes: Uint8Array): CRDTMessage | SyncDigest

Example:

import { encode, decode } from '@vuer-ai/vuer-rtc';

const msg: CRDTMessage = { /* ... */ };
const bytes = encode(msg);
websocket.send(bytes);

// On receive:
const received = decode(new Uint8Array(event.data));

Advanced Usage

Edit Buffer Utilities

isAdditiveOp

Check if an operation is additive (can be merged).

function isAdditiveOp(op: Operation): boolean

mergeValues

Merge two operation values for the same key+path.

function mergeValues(otype: string, prev: unknown, next: unknown): unknown

Graph Rebuilding

rebuildGraph

Rebuild the graph from snapshot + journal (used internally after undo/redo).

function rebuildGraph(state: ClientState): ClientState

Related Pages