Local-first offline sync engine, optimized for low-bandwidth environments
δΈζη | English
A complete offline sync solution using Local-First architecture. Apps run fully offline with local storage as the primary data source, while automatically syncing with the server in the background. Optimized for unstable network conditions (like 2G/3G networks in Africa), with data compression, resumable uploads, and intelligent conflict resolution.
- π Full Offline Support - Works completely offline with IndexedDB local storage
- π Auto Sync - Automatically syncs when network is detected
- β‘ Incremental Sync - Transmits only changed data to save bandwidth
- ποΈ Outbox Pattern - Intercepts writes, queues them locally, reliable sync
- π§ Smart Conflict Resolution - Last-Write-Wins (LWW) + Vector Clocks
- π± Cross-Platform - Works on Web and mobile (based on RxDB)
- π¦ Data Compression - MessagePack + DEFLATE, reduces data by 40-60%
- π€ Resumable Uploads - Full TUS protocol implementation for large files
- β‘ Performance Optimized - Batch operations, indexing, query caching
- π Real-time Push - WebSocket server push notifications
- π‘οΈ Type-Safe - End-to-end TypeScript support
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β Client App β
β ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ β
β β UI Layer (React) β β
β ββββββββββββββββββββββββ¬ββββββββββββββββββββββββββββββββββ β
β β β
β ββββββββββββββββββββββββΌββββββββββββββββββββββββββββββββββ β
β β Offline SDK (@offline-sync/sdk) β β
β β βββββββββββ βββββββββββ βββββββββββ ββββββββββ β β
β β β Storage β β Network β β Outbox β β Sync β β β
β β β (RxDB) β βManager β β (Queue) β βManager β β β
β β ββββββ¬βββββ ββββββ¬βββββ ββββββ¬βββββ βββββ¬βββββ β β
β β β β β β β β
β β βββββΌβββββββββββββΌβββββββββββββΌβββββββββββββΌββββ β β
β β β IndexedDB (Browser Local Storage) β β β
β β ββββββββββββββββββββββββββββββββββββββββββββββββββββ β β
β ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ β
ββββββββββββββββββββββββββββββββ¬βββββββββββββββββββββββββββββββ
β HTTPS (Compressed)
βΌ
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β Sync Gateway Server β
β ββββββββββββββββ ββββββββββββ βββββββββββ ββββββββββ β
β β Gateway β β Applier β β Arbiter β β TUS β β
β β (Routing) β β(Apply β β(Conflictβ β(Resumableβ β
β β β βActions) β βResolution)β βUploads) β β
β ββββββββ¬ββββββββ ββββββ¬ββββββ ββββββ¬ββββββ ββββββ¬ββββ β
β β β β β β
β ββββββββΌβββββββββββββββΌββββββββββββββΌββββββββββββββΌβββββ β
β β CouchDB (Main Database) β β
β β - todos, products, customers, orders β β
β β - _changes feed for incremental sync β β
β β - Mango Query support β β
β ββββββββββββββββββββββββββββββββββββββββββββββββββββββββ β
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
# Clone repository
git clone https://github.com/iannil/offline-sync-engine.git
cd offline-sync-engine
# Install dependencies
pnpm install# Start server (port 3000)
pnpm dev:server
# Start client demo (port 5173)
pnpm dev:client# Build SDK
pnpm --filter @offline-sync/sdk build
# Build server
pnpm --filter @offline-sync/server build
# Build demo
pnpm --filter @offline-sync/client-demo buildimport { OfflineClient } from '@offline-sync/sdk';
// Initialize client
const client = new OfflineClient({
database: { name: 'my-app' },
sync: {
enabled: true,
url: 'https://api.example.com/sync',
interval: 30000, // sync every 30s
enableCompression: true,
},
});
// Wait for client to be ready
await client.initialize();
// Get database
const db = client.getDatabase();
// Create a todo (offline + auto sync)
const todo = await db.todos.insert({
id: 'todo-1',
text: 'Learn Offline Sync Engine',
completed: false,
createdAt: new Date().toISOString(),
updatedAt: new Date().toISOString(),
});
// Manually trigger sync
await client.getSyncManager().triggerSync();
// Monitor sync state
client.getSyncManager().onStateChange((state) => {
console.log('Syncing:', state.isSyncing);
console.log('Pending:', state.pendingCount);
});import { createTusUpload } from '@offline-sync/sdk/storage';
// Create file upload
const uploader = createTusUpload({
endpoint: 'https://api.example.com/api/tus',
data: file,
metadata: {
filename: file.name,
type: file.type,
},
chunkSize: 5 * 1024 * 1024, // 5MB chunks
onProgress: (sent, total) => {
console.log(`Progress: ${(sent / total * 100).toFixed(1)}%`);
},
});
// Start upload
const uploadUrl = await uploader.start();
// Pause upload
uploader.pause();
// Resume upload (supports resumable uploads)
await uploader.resume();# Push local operations to server
curl -X POST https://api.example.com/api/sync/push \
-H "Content-Type: application/msgpack+deflate" \
-H "Accept: application/msgpack+deflate" \
--data-binary '@payload.bin'
# Pull server changes
curl "https://api.example.com/api/sync/pull?since=1234567890" \
-H "Accept: application/msgpack+deflate"
# TUS create upload
curl -X POST https://api.example.com/api/tus \
-H "Tus-Resumable: 1.0.0" \
-H "Upload-Length: 1024000" \
-H "Upload-Metadata: filename dGVzdC5qcGc="offline-sync-engine/
βββ packages/
β βββ sdk/ # Client SDK
β β βββ src/
β β β βββ storage/ # Storage modules
β β β βββ network/ # Network management
β β β βββ outbox/ # Offline queue
β β β βββ sync/ # Sync management
β β β βββ client/ # Client entry
β β βββ package.json
β β
β βββ server/ # Sync gateway server
β β βββ src/
β β β βββ gateway/ # Sync gateway
β β β βββ applier/ # Operation applier
β β β βββ arbiter/ # Conflict arbiter
β β β βββ database/ # Database layer
β β β βββ tus/ # TUS protocol
β β βββ package.json
β β
β βββ client-demo/ # Demo application
β βββ src/
β β βββ components/
β β βββ db/
β βββ package.json
β
βββ docs/ # Documentation
βββ pnpm-workspace.yaml # Monorepo configuration
βββ package.json
interface OfflineClientConfig {
// Database configuration
database: {
name: string; // Database name
};
// Sync configuration
sync?: {
enabled: boolean; // Enable sync
url: string; // Sync server URL
interval?: number; // Sync interval (ms)
batchSize?: number; // Batch size
enableCompression?: boolean; // Enable compression
enableWebSocket?: boolean; // Enable WebSocket
};
// Outbox configuration
outbox?: {
maxRetries?: number; // Max retry attempts
initialDelay?: number; // Initial retry delay (ms)
maxDelay?: number; // Max retry delay (ms)
};
}# Environment variables
COUCHDB_URL=http://localhost:5984
COUCHDB_USERNAME=admin
COUCHDB_PASSWORD=password
COUCHDB_DB_PREFIX=offline-sync
PORT=3000
HOST=0.0.0.0// Client
import { OfflineClient } from '@offline-sync/sdk/client';
// Storage
import {
createDatabase,
getDatabase,
todoSchema,
productSchema,
} from '@offline-sync/sdk/storage';
// Query
import {
findAll,
findById,
findWhere,
paginate,
count,
QueryBuilder,
} from '@offline-sync/sdk/storage';
// Compression
import {
CompressionService,
compress,
decompress,
} from '@offline-sync/sdk/storage';
// TUS Protocol
import {
createTusUpload,
uploadFile,
TusUploader,
} from '@offline-sync/sdk/storage';
// Testing
import {
benchmarkWrite,
benchmarkRead,
benchmarkQuery,
testCapacity,
} from '@offline-sync/sdk/testing';
// Types
import type { Todo, Product, OutboxAction, NetworkStatus } from '@offline-sync/sdk';| Endpoint | Method | Description |
|---|---|---|
/health |
GET | Health check |
/api/sync/push |
POST | Push local operations |
/api/sync/pull |
GET | Pull remote changes |
/api/sync/:collection |
GET | Get collection data |
/api/sync/:collection/:id |
GET | Get single document |
/api/applier/apply |
POST | Apply single operation |
/api/applier/batch |
POST | Batch apply operations |
/api/arbiter/check |
POST | Conflict detection |
/api/arbiter/resolve |
POST | LWW conflict resolution |
/api/arbiter/resolve/merge |
POST | Field-level merge |
/api/tus |
POST | Create upload |
/api/tus/:id |
PATCH | Upload chunk |
/api/stream |
WS | Real-time push |
- Node.js >= 18
- pnpm >= 8
- CouchDB >= 3.0 (optional, for production)
# Install dependencies
pnpm install
# Start dev servers
pnpm dev:server # Server
pnpm dev:client # Client
# Run tests
pnpm test
# Lint code
pnpm lint
pnpm format# Start CouchDB with Docker
docker run -d \
--name couchdb \
-p 5984:5984 \
-e COUCHDB_USER=admin \
-e COUCHDB_PASSWORD=password \
couchdb:3| Document | Description |
|---|---|
| Architecture Overview | Local-First architecture design |
| API Documentation | Client/Server API definitions |
| Verification Report | Feature verification checklist |
| Development Progress | Development roadmap |
Contributions are welcome! Please follow these steps:
- Fork this repository
- Create a feature branch (
git checkout -b feature/amazing-feature) - Commit your changes (
git commit -m 'Add amazing feature') - Push to the branch (
git push origin feature/amazing-feature) - Create a Pull Request
- Write code in TypeScript
- Follow ESLint rules
- Add unit tests for new features
- Update relevant documentation
β
Phase 1: Basic Offline [ββββββββββββββββββββββββββββ] 100%
ββ RxDB integration, schemas, offline queue, LWW conflict resolution
β
Phase 2: Optimization [ββββββββββββββββββββββββββββ] 100%
ββ Incremental sync, MessagePack + DEFLATE compression
β
Phase 3: Advanced Features [ββββββββββββββββββββββββββββ] 100%
ββ TUS resumable uploads, WebSocket push, batch operations, indexing
π Phase 4: Production Ready [ββββββββββββββββββββββββββββ] 0%
ββ Security hardening, monitoring, Docker deployment, documentation
| Category | Tasks | Status |
|---|---|---|
| Security | Request validation, CORS, rate limiting, API auth | β³ Pending |
| Monitoring | Structured logging, error tracking, performance metrics | β³ Pending |
| Deployment | Docker containerization, env management, health checks | β³ Pending |
| Documentation | API docs generation, usage guides, example code | β³ Pending |
See Development Progress for details.
| Category | Technology |
|---|---|
| Frontend Framework | React + TypeScript |
| Local Database | RxDB + Dexie (IndexedDB) |
| Backend Framework | Fastify (Node.js) |
| Main Database | CouchDB |
| Data Serialization | MessagePack |
| Data Compression | DEFLATE (pako) |
| Resumable Upload | TUS Protocol v1.0.0 |
| Real-time Communication | WebSocket |
| Package Manager | pnpm workspaces |
| Build Tools | tsup (libraries) + Vite (apps) |
| Testing Framework | Vitest |
MIT License - see LICENSE file
This project is built on top of excellent open source projects:
- RxDB - JavaScript NoSQL database
- Fastify - High-performance Node.js web framework
- Nano - CouchDB client
- MessagePack - Efficient binary serialization
- TUS Protocol - Resumable upload protocol
- Pako | zlib interface
Built with β€οΈ for offline-first applications in low-bandwidth environments