> ## Documentation Index
> Fetch the complete documentation index at: https://docs.nodalmerge.com/llms.txt
> Use this file to discover all available pages before exploring further.

# SDK overview

> Choose the right NodalMerge SDK surface, connect to rooms, and adopt local-first patterns that converge under authority controls.

# 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

Both sit on top of the same core convergence model and wire protocol.

## 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

Use runtime-oriented SDK when:

* 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

You can start with the higher-level surface and move deeper only where needed.

## Core integration flow

Most apps follow this sequence:

1. Initialize SDK with room and transport options
2. Connect room/session
3. Apply local writes
4. Push/flush updates
5. Subscribe to change/runtime events
6. Reconcile speculative intent with canonical outcomes

This sequence supports both local-first UX and policy-governed canonical correctness.

## 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

Choosing the right primitive is more important than convenience wrappers.

## Local-first and canonical refinement

SDK integrations should explicitly separate:

* Fast speculative user intent
* Authoritative canonical outcomes

A common namespace pattern:

* `intent/**` for optimistic writes
* `world/**` for canonical accepted state

This prevents mixing transient intent with durable truth.

## Connection, transport, and reconnect

The SDK handles transport lifecycle concerns including:

* WebSocket session management
* Reconnect/backoff behavior
* Optional mesh/direct transport enhancements where available

Build UI states that tolerate reconnect and eventual refinement rather than assuming continuous connectivity.

## Presence and ephemeral state

Presence APIs are for real-time ephemeral collaboration state:

* Cursor positions
* Live participant context
* Typing/attention hints

Do not model durable business state in presence channels.

## 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 pointer
* `sdk.cas.getBlob(hashHex)` to resolve bytes when available locally
* `sdk.cas.requestMissingBlobs()` to trigger retrieval of missing blob payloads

Keep app state as hash references (for example in `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

Validate reconnect and hydration behavior with real offline/restart drills, not only unit tests.

## 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 |

See [api-reference/websocket-commands#graph-introspection-host-core-direct](/api-reference/websocket-commands#graph-introspection-host-core-direct) for full request/response schemas.

## 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

The canonical lane is managed through the Canonical Checkpoint plane — a separate compute path that resolves conflicts and produces a deterministic `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 state
* `sdk.query.buildProjection()` with `{ selector: "latest" }` sees the promoted baseline

As an SDK developer this matters when you are building history panes, undo stacks, or audit views that must distinguish pre- and post-promotion state. Promotion is idempotent — re-promoting the same checkpoint returns the existing node.

## 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:

1. Single room end-to-end connect/write/read flow
2. Deterministic primitive modeling (map/text/list)
3. Reconnect and offline persistence validation
4. Intent vs canonical refinement flow
5. Capability-scoped auth integration (if needed)

Then layer advanced query/projection/topology behavior.

## 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

## Related pages

* [sdk/javascript](/sdk/javascript)
* [sdk/react](/sdk/react)
* [sdk/presence](/sdk/presence)
* [sdk/undo-and-conflicts](/sdk/undo-and-conflicts)
* [sdk/subscriptions](/sdk/subscriptions)
* [protocol/blob-flow](/protocol/blob-flow)
* [api-reference/websocket-commands](/api-reference/websocket-commands)
