SDK overview
NodalMerge provides JavaScript-first SDK surfaces for building local-first collaborative applications on top of deterministic room history. This page helps you choose an SDK surface and adopt a safe baseline integration pattern.SDK surfaces
NodalMerge currently exposes two practical JavaScript entry styles:- Document-style API (
createDoc) for map/text/list-centric collaboration - Runtime-oriented SDK (
createNodalMergeSdk) for room/sync/replay/offline/topology control
Which surface should you use?
Use document-style API when:- You want ergonomic map/text/list primitives
- You are building app-level collaborative UX quickly
- You prefer high-level handles and event hooks
- You need explicit control over sync/replay/query/projection flows
- You are building host/runtime integrations
- You want direct access to room, transport, and topology sub-APIs
Core integration flow
Most apps follow this sequence:- Initialize SDK with room and transport options
- Connect room/session
- Apply local writes
- Push/flush updates
- Subscribe to change/runtime events
- Reconcile speculative intent with canonical outcomes
Data-model alignment
Use SDK data primitives according to merge semantics:- Map for key/value winner semantics
- Text for collaborative text editing
- List for ordered item identity workflows
- Blob references for large binary payloads
Local-first and canonical refinement
SDK integrations should explicitly separate:- Fast speculative user intent
- Authoritative canonical outcomes
intent/**for optimistic writesworld/**for canonical accepted state
Connection, transport, and reconnect
The SDK handles transport lifecycle concerns including:- WebSocket session management
- Reconnect/backoff behavior
- Optional mesh/direct transport enhancements where available
Presence and ephemeral state
Presence APIs are for real-time ephemeral collaboration state:- Cursor positions
- Live participant context
- Typing/attention hints
Blob and file handling in SDK integrations
Blob/file transfer is not only a protocol concern. SDK integrations should model binary payload workflows explicitly. Use the SDK CAS surface when your app needs file-like payload behavior:sdk.cas.setBlob(key, bytes)to attach content-addressed bytes and receive a hash pointersdk.cas.getBlob(hashHex)to resolve bytes when available locallysdk.cas.requestMissingBlobs()to trigger retrieval of missing blob payloads
world/files/**) rather than embedding raw bytes in normal sync keys.
For wire-level transfer mechanics and direct I/O fallback behavior, see protocol/blob-flow.
Persistence strategy
For production local-first behavior, define and test persistence ownership explicitly:- What state is cached locally
- When it is flushed
- How hydration runs on app start
Host-exposed commands (SDK perspective)
The server runtime exposes a set of graph-level introspection and promotion commands beyond normal sync. As an SDK developer, you encounter these in two ways: the SDK wraps some automatically (e.g.,sdk.query.readReplayRange), and others are available via direct host-core embedding for custom server builds.
| Command | What it does | When an SDK developer cares |
|---|---|---|
GetFrontier | Returns the CRDT frontier (leaf node IDs) | Building sync-status UIs, detecting convergence between peers |
GetCausalParents | Returns a node’s causal parent IDs | Graph visualizers, debugging change history |
GetCanonicalResolution | Returns the conflict-resolved map state at the current canonical checkpoint | Conflict inspector UIs, verifying canonical state |
ComputeSyncDiff | Set difference between the room’s nodes and a peer’s claimed set | Custom sync progress displays, diagnosing gaps |
InspectPack | Decodes pack bytes to extract causal metadata without applying them | Debugging packs before import, validation tooling |
PromoteCheckpointToGraph | Promotes a canonical checkpoint snapshot into the CRDT graph as a synthetic origin | Controls where replay begins; affects getTextCanonical and projection behavior |
Checkpoint promotion and the canonical plane
NodalMerge maintains two views of room state:- Speculative (intent lane): the local optimistic view, including uncommitted ops
- Canonical (authoritative lane): the settled, policy-verified, conflict-resolved view
canonical_hash.
PromoteCheckpointToGraph bridges these two planes: it takes a canonical checkpoint (identified by seq, hash, or frontier) and materializes it as a synthetic origin node in the CRDT graph. After promotion:
- Replay always begins from the promoted node, not original genesis
sdk.sync.getTextCanonical()reflects post-promotion statesdk.query.buildProjection()with{ selector: "latest" }sees the promoted baseline
Rejections, conflicts, and guardrails
SDK surfaces expose rejection/conflict signals that should feed user-visible and operator-visible handling. Recommended baseline:- Handle typed rejection classes where available
- Record recent rejection/conflict context for diagnostics
- Avoid silent rollback behavior in UX
Recommended adoption path
Start with:- Single room end-to-end connect/write/read flow
- Deterministic primitive modeling (map/text/list)
- Reconnect and offline persistence validation
- Intent vs canonical refinement flow
- Capability-scoped auth integration (if needed)
Common mistakes
- Treating SDK transport success as canonical-state success
- Storing durable domain data in ephemeral presence channels
- Skipping local persistence drills until late
- Mixing intent and canonical writes in the same namespace
- Choosing map/list/text primitives based on convenience instead of merge semantics
- Treating large binary payloads as normal string/map state instead of using blob references + CAS