Subduction runs its peer-to-peer sync layer as a Cloudflare Durable Object — one object per document, each with its own SQLite. Clients exchange signed commits over a single WebSocket; the object evicts itself between bursts of activity and rehydrates from storage on the next message. You pay for work, not for waiting.
wss://subduct.io/sync/<document-id>
Every client that names the same <document-id>
is routed to the same Durable Object — that is the whole coordination
primitive.
The sync engine is Rust compiled to WebAssembly, running inside the Durable Object next to its storage.
The document id maps to a stable Durable Object id, so load and storage spread across the fleet instead of a single hot instance.
Sockets stay open while the isolate is evicted from memory. Identity and connections rebuild from persisted state on the next frame.
Every peer proves an Ed25519 identity through a challenge/response handshake before it can read or write a document.
Accepted handshake nonces are persisted to SQLite, so a captured challenge can't be replayed after the object hibernates.
An alarm fires only when there's work — expiring nonces and compacting redundant commits once they're covered by a fragment.
Commits, fragments, and subscriptions live in the object's SQLite, so nothing is lost across evictions or restarts.
Point a Subduction client at the endpoint, complete the handshake, and subscribe to a document.
/sync/<document-id> — the worker routes it to that document's object.subduction-do; both sides derive the same audience from it.Open demo: this deployment runs a permissive policy — anyone who knows a document id can read and write it, storage is uncapped, and data may be reset at any time. It's for evaluation only; don't put anything private or durable here. Self-host with your own auth policy for real use.
// Browser client, via the subduction_wasm bundle.
import init, { Subduction, MemorySigner, MemoryStorage, SedimentreeId }
from "./pkg/subduction_wasm.js";
await init();
const sync = new Subduction({
signer: MemorySigner.generate(),
storage: new MemoryStorage(),
onRemoteHeads: () => render(),
});
const doc = SedimentreeId.fromBytes(docIdBytes);
const url = new URL(`wss://${host}/sync/${docIdHex}`);
// Handshake + identify the server peer.
await sync.connectDiscover(url, "subduction-do");
await sync.syncWithAllPeers(doc, true, 5000);
The lifecycle is designed so no work is lost when the isolate is evicted.
id_from_name(doc) — a dedicated, individually-hibernatable object with its own SQLite.