---
title: Sync SDK
description: Real-time data sync with document CRUD, version tracking, and conflict resolution across clients.
---

# @nolag/sync

Real-time data sync with document CRUD, version tracking, and conflict resolution.

## Overview

Sync structured data across clients in real time. Documents within a collection carry monotonically increasing version numbers and are merged using a last-writer-wins (LWW) strategy applied per field, so concurrent edits to different fields of the same document are automatically reconciled. When two clients update the same field simultaneously, a `conflict` event is emitted so your application can apply custom resolution logic if the default LWW behaviour is not appropriate. Collections group related documents and behave like lightweight database tables.

### Key Features

- Real-time document create, update, and delete broadcast to all collection subscribers
- Per-field last-writer-wins merge with no full-document overwrites
- Automatic conflict detection with a `conflict` event for custom resolution
- Ephemeral change channel with no server-side retention
- Collaborator online/offline presence via lobby
- Local cache: `getDocument()` and `getAllDocuments()` are synchronous reads

## How It Works

`NoLagSync` wraps the `@nolag/js-sdk` client and manages a lobby that tracks which collaborators are online. Calling `joinCollection(name)` returns a `SyncRoom` that subscribes to the `changes` topic. Every create, update, and delete operation is published to that topic so all subscribers receive it and update their local document cache. The SDK maintains a version counter per document and detects conflicts when an incoming update has a base version lower than the current local version.

| Topic | Purpose | Replay |
| --- | --- | --- |
| `changes` | Document create, update, and delete operations with version metadata | Ephemeral |

## Installation

```bash [Terminal]
npm install @nolag/sync @nolag/js-sdk
```

## Quick Start

```typescript [TypeScript]
import { NoLagSync } from '@nolag/sync'

const sync = new NoLagSync('your-access-token')
await sync.connect()

// Join a collection (analogous to a database table or folder)
const collection = await sync.joinCollection('tasks')

// Create a document (all collaborators see it instantly)
await collection.createDocument('task-001', {
  title: 'Design new homepage',
  status: 'todo',
  assignee: 'alice',
  priority: 1,
})

// Update specific fields (version is incremented automatically)
await collection.updateDocument('task-001', {
  status: 'in-progress',
  assignee: 'bob',
})

// Read a document from local cache (no network call)
const task = await collection.getDocument('task-001')
console.log(task?.version) // e.g. 2

// Read all documents in the collection
const all = await collection.getAllDocuments()
console.log(`${all.length} documents in collection`)

// Delete a document
await collection.deleteDocument('task-001')

// React to changes from other collaborators
collection.on('documentCreated', ({ id, data, version }) => {
  console.log('New document:', id, data)
})

collection.on('documentUpdated', ({ id, fields, version }) => {
  console.log('Updated:', id, fields)
})

collection.on('documentDeleted', ({ id }) => {
  console.log('Deleted:', id)
})

// Handle conflicts (last-writer-wins per field, conflict emitted for custom resolution)
collection.on('conflict', ({ id, localVersion, remoteVersion, fields }) => {
  console.warn('Conflict on', id, '- remote version wins unless resolved manually')
})

// Know when the local state is fully in sync with the server
collection.on('synced', () => {
  console.log('Collection fully synced')
})
```

## API Reference

### NoLagSync

| Method | Returns | Description |
| --- | --- | --- |
| `connect()` | `Promise<void>` | Establish the WebSocket connection and join the lobby. |
| `disconnect()` | `void` | Close the connection and leave the lobby. |
| `joinCollection(name)` | `Promise<SyncRoom>` | Subscribe to a collection. Returns the room instance with a pre-populated local cache. |
| `leaveCollection(name)` | `Promise<void>` | Unsubscribe from a collection and release its local cache. |
| `getCollaborators()` | `Collaborator[]` | Return all collaborators currently online in the lobby. |

### NoLagSync Events

| Event | Payload | Description |
| --- | --- | --- |
| `connected` | none | WebSocket connection established. |
| `disconnected` | `reason: string` | Connection closed. |
| `reconnected` | none | Connection restored; collection membership and presence are restored automatically. |
| `error` | `error: Error` | A transport or protocol error occurred. |
| `collaboratorOnline` | `collaborator: Collaborator` | A collaborator joined the lobby. |
| `collaboratorOffline` | `collaborator: Collaborator` | A collaborator left the lobby. |

### SyncRoom

| Method | Returns | Description |
| --- | --- | --- |
| `createDocument(id, data)` | `Promise<Document>` | Create a new document with an explicit ID and initial field values. Version starts at 1. |
| `updateDocument(id, fields)` | `Promise<Document>` | Apply a partial field update. Merges with existing data; increments version. |
| `deleteDocument(id)` | `Promise<void>` | Delete a document from the collection. Propagated to all subscribers. |
| `getDocument(id)` | `Document \| undefined` | Read a document from the local cache. Returns `undefined` if not found. |
| `getAllDocuments()` | `Document[]` | Return all documents currently in the local cache for this collection. |

### SyncRoom Events

| Event | Payload | Description |
| --- | --- | --- |
| `documentCreated` | `{ id, data, version, authorId }` | A new document was created by any collaborator. |
| `documentUpdated` | `{ id, fields, version, authorId }` | A document's fields were updated by any collaborator. |
| `documentDeleted` | `{ id, authorId }` | A document was deleted by any collaborator. |
| `localChange` | `{ id, type, data }` | Fired when the local client applies a change (before server acknowledgment). |
| `conflict` | `{ id, localVersion, remoteVersion, fields }` | Concurrent write conflict detected. Remote version is applied; use this event to override. |
| `synced` | none | The local cache is fully reconciled with the server state. |
| `collaboratorJoined` | `collaborator: Collaborator` | A collaborator joined this collection. |
| `collaboratorLeft` | `collaborator: Collaborator` | A collaborator left this collection. |
