local-village-server
v0.1.2
Published
Server package for local-village with REST API, WebSocket support, and storage adapters
Maintainers
Readme
local-village-server
Server package for local-village with REST API, WebSocket support, and storage adapters.
Features
- REST API: Express router with sync endpoints
- WebSocket Server: Real-time updates and presence
- Storage Adapters: Memory (dev) and SurrealDB (production)
- Conflict Detection: Server-side conflict detection
- Fastify Support: Optional Fastify plugin
- TypeScript: Full type safety
Installation
npm install local-village-server
# or
yarn add local-village-server
# or
pnpm add local-village-serverRequirements
- Node.js 18+
Quick Start
Express Server
import express from 'express'
import { createServer } from 'http'
import {
createLocalVillageServer,
MemoryAdapter,
RealtimeServer,
} from 'local-village-server'
const app = express()
const httpServer = createServer(app)
// Create storage adapter
const storage = new MemoryAdapter()
// Create Local Village server
const localVillage = createLocalVillageServer({
storage,
collections: ['todos', 'users'],
})
// Mount routes
app.use('/api', localVillage.router)
// Add real-time support (optional)
const realtime = new RealtimeServer({ path: '/ws' })
realtime.attach(httpServer)
httpServer.listen(3000, () => {
console.log('Server running on http://localhost:3000')
})Fastify Server
import Fastify from 'fastify'
import {
createLocalVillageFastifyPlugin,
MemoryAdapter,
} from 'local-village-server'
const fastify = Fastify()
const storage = new MemoryAdapter()
fastify.register(createLocalVillageFastifyPlugin, {
storage,
collections: ['todos', 'users'],
prefix: '/api',
})
fastify.listen({ port: 3000 })Storage Adapters
MemoryAdapter
For development and testing:
import { MemoryAdapter } from 'local-village-server'
const storage = new MemoryAdapter()SurrealDBAdapter
For production with SurrealDB:
import { SurrealDBAdapter } from 'local-village-server'
const storage = new SurrealDBAdapter({
url: 'http://localhost:8000/rpc',
namespace: 'myapp',
database: 'production',
username: 'root',
password: 'root',
})
await storage.connect()API Endpoints
The server exposes these endpoints:
| Method | Endpoint | Description |
|--------|----------|-------------|
| POST | /sync | Sync operations from client |
| GET | /changes | Get changes since token |
| GET | /health | Health check |
Sync Request
POST /api/sync
{
"clientId": "client-123",
"operations": [
{
"id": "op-1",
"type": "create",
"collection": "todos",
"documentId": "todo-1",
"data": { "title": "Buy milk", "completed": false },
"timestamp": 1699999999999
}
],
"syncToken": "token-abc"
}Changes Request
GET /api/changes?token=token-abc&collections=todos,usersReal-time Server
Basic Setup
import { RealtimeServer } from 'local-village-server'
const realtime = new RealtimeServer({
path: '/ws',
heartbeatInterval: 30000,
})
realtime.attach(httpServer)Events
realtime.on('connection', (client) => {
console.log('Client connected:', client.id)
})
realtime.on('subscribe', (client, collection) => {
console.log(`${client.id} subscribed to ${collection}`)
})
realtime.on('disconnect', (client) => {
console.log('Client disconnected:', client.id)
})Broadcasting Changes
// Broadcast to all subscribers of a collection
realtime.broadcast('todos', {
type: 'change',
collection: 'todos',
documentId: 'todo-1',
data: { title: 'Updated', completed: true },
})Presence
Enable presence tracking for real-time collaboration:
const realtime = new RealtimeServer({
path: '/ws',
presence: {
enabled: true,
timeout: 60000, // Remove inactive users after 60s
},
})
// Client joins a room
// { type: 'presence:join', room: 'document-123', data: { name: 'Alice' } }
// Get presence for a room
const users = realtime.getPresence('document-123')Authentication Middleware
import { createAuthMiddleware } from 'local-village-server'
const authMiddleware = createAuthMiddleware({
verify: async (token) => {
// Verify JWT or session token
const user = await verifyToken(token)
return user ? { userId: user.id } : null
},
exclude: ['/health'], // Paths to skip auth
})
app.use('/api', authMiddleware, localVillage.router)Configuration
const localVillage = createLocalVillageServer({
storage,
collections: ['todos', 'users'],
// Optional settings
conflictResolution: 'server-wins', // or 'client-wins', 'last-write-wins'
maxBatchSize: 100,
syncTokenTTL: 86400000, // 24 hours
// Hooks
onSync: async (operations, clientId) => {
console.log(`Syncing ${operations.length} ops from ${clientId}`)
},
onConflict: async (conflict) => {
console.log('Conflict detected:', conflict)
},
})Client Package
For the React client library, install local-village:
npm install local-villageDocumentation
License
MIT
