Usage
React
Effect stream
Node IDs
addNode() returns the new node’s ID as a string ("wall_ms:logical:node_id"). Pass this ID to moveNode(), updateNode(), and deleteNode().
Sibling ordering
Siblings are ordered lexicographically by theirposition string, with ties broken by author ID descending. Use a fractional indexing scheme (e.g. "a0", "a0V", "b0") to insert between existing siblings without rewriting all positions.
API
Conflict semantics
- Concurrent adds to the same parent converge — siblings are ordered by
(position, id desc) - Concurrent moves: both moves apply in HLC order. The last move (highest
op_id) wins for each node’s parent pointer - Cycle prevention: a move that would place a node under its own descendant is silently discarded
- Tombstones: deleted nodes are never GC’d — children are preserved and restored if a concurrent move targets a deleted parent
- Value updates: last-write-wins via the
updated_atHLC timestamp
Encryption
Tree node values support end-to-end encryption. Pass anencryption map to MeridianClient.create():
addNode and updateNode encrypt the value argument before sending. deleteNode and moveNode do not involve a value and are unaffected. The decrypted value is transparent via value(), onChange(), and stream(). See Encryption for key generation and distribution patterns.
CRDT key prefix
Use thetr: prefix by convention: