A pure-Go library for the Loro CRDT wire format.
loro-go reads and writes the Loro Fast wire format (FastUpdates and FastSnapshot) byte-for-byte, and reconstructs document state for Map, List, Text, MovableList and Tree containers. No cgo, single Go toolchain build.
Bytes are verified against two independent ground truths: real loro-crdt@1.12.5 exports, and the serde_columnar@0.3.14 crate (golden column vectors emitted by a small Rust harness). A blob produced by loro-go imports cleanly into the canonical loro-crdt JavaScript package with matching toJSON(). Upstream minors are re-checked against the committed fixtures; see COMPAT.md (1.13.1: byte-identical).
Not affiliated with loro-dev. Loro is a separate project; this is an independent Go reading of its wire format.
Mirror. Primary repository is github.com/Deln0r/loro-go; an EU-hosted mirror auto-synced on every push lives at codeberg.org/Deln0r/loro-go.
go get github.com/Deln0r/loro-go
package main
import (
"fmt"
"github.com/Deln0r/loro-go/loro"
)
func main() {
// Decode a FastUpdates blob exported by loro-crdt and reconstruct state.
u, err := loro.DecodeUpdates(blob) // blob = doc.export({mode:"update"})
if err != nil {
panic(err)
}
state, _ := loro.MergeState(u)
fmt.Println(state) // map[string]any matching doc.toJSON()
// Or build a document in Go and export bytes loro-crdt can import.
d := loro.NewDoc(1)
d.TextInsert("title", 0, "hello")
d.MapSet("meta", "n", int64(7))
out := d.ExportUpdates()
_ = out
}loro.DecodeSnapshot reads the FastSnapshot format (oplog SSTable) the same way.
- Header + checksum (xxh32),
FastUpdatesandFastSnapshotframing serde_columnarstrategies: Rle, BoolRle, DeltaRle, DeltaOfDelta (decode and encode, byte-verified)- Change blocks: all eight blobs decode and re-encode byte-identically
- Containers: Map (LWW), List and Text (Fugue ordering, concurrent + multi-peer merge), MovableList (moves), Tree (nested state with fractional index)
- Deletes: text/list id-span tombstones (DeleteSeq), map key deletion (DeleteOnce), including deletes targeting another peer's elements
- Blocks carrying multiple changes (per-change ids, lamports, timestamps recovered)
- LZ4-compressed SSTable blocks (decompression, checksums verified)
- Rich-text
toDelta: styled runs reconstructed via the mark anchor model (loro.TextDelta) - Encode from scratch: build a document and export
FastUpdatesbyte-identical to loro-crdt - KV/SSTable reader for the snapshot oplog section, with block and meta checksum verification
- Mark anchoring under concurrent edits (expand rules), and marks interacting with deletes in the same range
- Tree node
metasub-containers and deep trees - Counter container
testdata/gen drives loro-crdt (npm) to emit binary + JSON fixtures, testdata/rustgen emits serde_columnar golden column vectors, and testdata/gen/validate_go.mjs imports a loro-go-produced blob back into loro-crdt. The Go tests assert byte-identity and state equality against these. Regenerate with:
cd testdata/gen && npm install && node gen.mjs
cd ../rustgen && cargo run > ../columnar_golden.txt
MIT. See LICENSE.