@web_of_trust/adapter-automerge
v0.2.9
Published
Automerge CRDT adapter for Web of Trust — Rust/WASM-based replication and personal document management
Readme
@web_of_trust/adapter-automerge
Alternative CRDT adapter for Web of Trust — Rust compiled to WebAssembly.
Implements the ReplicationAdapter and personal document interfaces from @web_of_trust/core using Automerge. Available as a drop-in alternative to @web_of_trust/adapter-yjs. The Yjs adapter is the default; use this one when Automerge semantics or tooling are specifically required.
Note: Automerge's Rust→WASM runtime (1.7 MB) blocks the main thread on mobile devices. Measured: ~6.4 s initialisation on Android vs ~85 ms for Yjs. Only use this adapter on desktop-only deployments or when you need Automerge's specific merge semantics.
Installation
pnpm add @web_of_trust/adapter-automergeRequires @web_of_trust/core as a peer dependency.
Key Features
- AutomergeReplicationAdapter — encrypted shared spaces using
automerge-repoDocHandles - PersonalDocManager — personal data stored in an Automerge document with
Automerge.save()snapshots - CompactionService — two-phase compaction with yield points to reduce UI freeze on WASM-constrained devices
- PersonalNetworkAdapter — multi-device sync for the personal document via the Relay
- SyncOnlyStorageAdapter — stores automerge-repo sync states without the full document binary
API Overview
Personal Document
import {
initPersonalDoc,
getPersonalDoc,
changePersonalDoc,
onPersonalDocChange,
flushPersonalDoc,
} from '@web_of_trust/adapter-automerge'
// Initialise (loads snapshot from CompactStore / Vault)
await initPersonalDoc({ identity, compactStore, vaultClient })
// Read
const doc = getPersonalDoc()
const contact = doc.contacts['did:key:z6Mk...']
// Mutate
changePersonalDoc((doc) => {
doc.profile.name = 'Alice'
})
// Subscribe to changes
const unsub = onPersonalDocChange(() => {
const latest = getPersonalDoc()
})
// Persist immediately (normally automatic)
await flushPersonalDoc()Replication Adapter (Shared Spaces)
import { AutomergeReplicationAdapter } from '@web_of_trust/adapter-automerge'
const replication = new AutomergeReplicationAdapter({
identity, // PublicIdentitySession
messaging, // MessagingAdapter
keyManagement, // KeyManagementPort (optional, defaults to InMemoryKeyManagementAdapter)
metadataStorage, // SpaceMetadataStorage (optional)
compactStore, // CompactStore (optional, IDB-backed)
vaultUrl, // string (optional)
})
// Open a space
const handle = await replication.openSpace<{ notes: string }>(spaceInfo)
// Read
const doc = handle.getDoc()
// Mutate
await handle.transact((doc) => {
doc.notes = 'Hello from Alice'
})
// React to remote updates
handle.onRemoteUpdate(() => {
console.log('Remote change:', handle.getDoc())
})
handle.close()Compaction Service
The CompactionService strips Automerge history to keep snapshots small. It runs in the background with yield points to avoid long WASM freezes:
import { CompactionService } from '@web_of_trust/adapter-automerge'
const compaction = new CompactionService()
const compact = await compaction.compact(automergeDoc)
// compact is a fresh Automerge.Doc with history strippedHow to Run
# Build (watch mode during development)
pnpm dev
# Build once
pnpm build
# Run tests
pnpm test
# Run tests in watch mode
pnpm test:watchCRDT Switch
# Use Automerge in the demo app
VITE_CRDT=automerge pnpm dev:demo
# Default is Yjs (no variable needed)
pnpm dev:demoVite config must mark @automerge/automerge as external to avoid bundling the WASM twice:
// vite.config.ts
build: {
rollupOptions: {
external: ['@automerge/automerge'],
},
}