Using SafeMesh in your code — main (unreleased)
This guide uses main (unreleased) source. These are local build paths, not registry installation promises. The Lean proof applies to the models; bindings, bytes and transport are TESTED engineering surfaces. Maintainer support is UNKNOWN for all four surfaces. Evidence: install matrix and status.
You bring the transport
Section titled “You bring the transport”SafeMesh supplies CRDT state, deltas, canonical bytes and event-log operations. Your application supplies the schema and moves records between replicas. TransportAdapter describes subscription, connectivity, sending batches and draining incoming envelopes; InMemoryTransport implements a deterministic test environment. Neither proves real delivery. Evidence: transport interfaces.
For an event-log integration, follow this sequence:
- Create local state and its log. Use consistent counter arity and your chosen replica identities. The Rust walkthrough’s
Replicacombines a CRDT with anEventLog. - Record and apply a local edit.
append_withassigns a record sequence and applies its delta through the supplied callback. - Exchange canonical bytes. Encode with
Record::to_wire_bytes, move the bytes through your transport, then decode withRecord::from_wire_bytesusing the agreed delta type. - Admit before applying.
admit_withapplies an accepted record through its callback. Duplicate and collision outcomes leave state unchanged; do not separately apply a rejected payload. - Repair gaps. Exchange versions and use
EventLog::sinceoranti_entropyto send missing records after connectivity returns. - Restore deliberately. Rebuild state by replaying accepted history; decoding bytes alone does not choose your application’s empty-state shape or supply durable storage.
Evidence for this sequence: the public-API m2slice.rs walkthrough, its explanation, and EventLog implementation.
After the first-result example, create your own Cargo application and add a path dependency on your local checkout:
[dependencies]safemesh-crdt = { path = "/absolute/path/to/safemesh/rust/crates/safemesh-crdt" }Replace the path with your checkout location. The crate exposes GCounter, checked coordinate updates, and checked full-state merge:
use safemesh_crdt::GCounter;
fn main() { let mut left = GCounter::new(2); let mut right = GCounter::new(2); left.try_apply_bump(0, 3).unwrap(); right.try_apply_bump(1, 2).unwrap(); left.try_merge(&right).unwrap(); right.try_merge(&left).unwrap(); assert_eq!(left.value(), 5); assert_eq!(left.state(), right.state()); println!("counter={}", left.value());}This is an in-process state merge. Tallies are cumulative, so resending the same bump does not increment again. try_apply_bump rejects an out-of-range coordinate; try_merge rejects incompatible replica counts. Handle these errors at your input boundary rather than copying the example’s unwrap into an untrusted-input path. Evidence: GCounter API and counter model.
For record exchange, persistence, a child-process exit and restart, follow the durable Rust walkthrough. It uses local::DurableReplica with local-writer on Linux and requires filesystem locks and file/directory sync. Preserve its fence and transaction files; use restart for an existing store, not a fresh constructor. This engineering evidence does not prove storage durability. The generated reference covers the Rust API present in this build.
From the repository root, build the local library:
(cd rust && cargo build -p safemesh-ffi --release)Include rust/crates/safemesh-ffi/include/safemesh.h in your C project and link the built library from rust/target/release using your platform’s linker configuration. The header exposes opaque handles, status results, and matching release functions. This function illustrates ownership of a counter:
#include "safemesh.h"
uint64_t example_counter(void) { SafeMeshGCounter *counter = safemesh_gcounter_new(2); SafeMeshStatus status = safemesh_gcounter_try_apply_bump(counter, 0, 3); uint64_t value = status == 0 ? safemesh_gcounter_value(counter) : 0; safemesh_gcounter_free(counter); return value;}Check status values: Ok is 0, NullPointer is 1, and ReplicaOutOfRange is 2 for this checked bump function. Release each owned handle once. OR-Set queries return owned SafeMeshU64s arrays, released with safemesh_u64s_free; sets use safemesh_orset_free. The caller supplies fresh set tokens. Evidence: FFI contract and header.
The C ABI has carrier operations and a G-Counter delta-to-wire helper, no replica/event-log surface. Do not assume the Python or WASM record-exchange examples translate directly to C. The documented repository checks call ABI functions from Rust and check header drift; those checks do not contain an external C compile/link/run test. Evidence: root surface description and FFI assurance scope.
WASM / TypeScript
Section titled “WASM / TypeScript”Use the Rust/WASM and Node prerequisites from the browser example. For a Node integration, build a Node-target package from the repository root:
wasm-pack build rust/crates/safemesh-wasm --target nodejs --out-dir pkg-node --releasenode rust/crates/safemesh-wasm/examples/node-convergence.mjs rust/crates/safemesh-wasm/pkg-nodeFor a bundler application, use --target bundler instead. The generated bundler package exports named classes and initializes WASM on import; it has no init export. Match the import style to the wasm-pack target. Evidence: WASM build and quickstart.
For a Node-target package, the exchange at the center of an application looks like this (save beside pkg-node as an .mjs file):
import { createRequire } from "node:module";const require = createRequire(import.meta.url);const { SafeMeshGCounterReplica } = require("./pkg-node/safemesh_wasm.js");
const left = new SafeMeshGCounterReplica(1n, 3);const right = new SafeMeshGCounterReplica(2n, 3);const bytes = left.appendBump(1, 5n);right.mergeRecordBytes(bytes); // Your transport carries these bytes.left.mergeLogBytes(right.logBytes());console.log(left.value(), right.value()); // 5n 5nleft.free();right.free();The integer values represented as u64 use JavaScript bigint. SafeMeshStringOrSetReplica additionally exposes UTF-8 set record/log exchange; SafeMeshOrSet exposes whole-state merge over numeric elements. Fresh token allocation remains the caller’s responsibility. Evidence: WASM wrapper guide.
For the complete TypeScript/Node file persistence and restore path, read PERSIST.md. The Linux CI package smoke runs Node; that is not a browser/version/OS support matrix. Evidence: package smoke and WASM assurance scope.
Python
Section titled “Python”First build and install the local wheel in a virtual environment. Run your application with that environment’s Python. The module exposes the same Rust-backed counter record/log exchange:
import safemesh_python as sm
left = sm.GCounterReplica(1, 3)right = sm.GCounterReplica(2, 3)right.merge_record_bytes(left.append_bump(1, 5))left.merge_log_bytes(right.log_bytes())print(left.value(), right.value()) # 5 5Here the Python calls hand bytes directly between two in-process objects; your application must move those bytes across its actual transport. GCounter.try_apply_bump raises IndexError for an invalid coordinate without changing state. Numeric OrSet operations take unsigned 64-bit elements and tokens; allocate fresh replica-unique tokens for adds. Evidence: Python quickstart and token contract.
The CI distribution check installs a local wheel on Linux x64 with CPython 3.11. The abi3-py38 setting describes artifact reach, not evidence that every Python version or platform was tested. The documented data-mule demo is an in-memory partition-and-heal walk; a Python disk/process restore walk is not documented in the root surface map. Evidence: Python distribution scope and root walkthrough map.
Before committing to an integration, compare the limits with your requirements and read the proof boundary.