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
npm install @nolag/sync @nolag/js-sdk
Quick Start
import { NoLagSync } from'@nolag/sync'const sync = newNoLagSync('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 collectionconst all = await collection.getAllDocuments()
console.log(`${all.length} documents in collection`)
// Delete a documentawait 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.