npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

local-village-server

v0.1.2

Published

Server package for local-village with REST API, WebSocket support, and storage adapters

Readme

local-village-server

Server package for local-village with REST API, WebSocket support, and storage adapters.

npm version TypeScript License: MIT

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

Requirements

  • 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,users

Real-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-village

Documentation

License

MIT