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

@rootlodge/reality-server

v1.2.2

Published

Socketless Real-Time Infrastructure - Server components with mesh awareness and storage adapters

Readme

@rootlodge/reality-server

Server package for Reality - Socketless Real-Time Infrastructure

Stateless HTTP handlers with mesh-aware coordination.

Reality Does NOT Own Your Data

┌─────────────────────────────────────────────────────────────────────────┐
│                                                                         │
│  ❌ Reality does NOT store your payloads                               │
│  ❌ Reality does NOT require a database                                │
│  ❌ Reality is NOT a data layer                                        │
│                                                                         │
│  ✅ Reality tracks change METADATA (version, hash)                     │
│  ✅ Reality propagates INVALIDATION signals                            │
│  ✅ Reality coordinates MESH of servers                                │
│                                                                         │
│  Your app stores data. Reality tells clients when to refetch.          │
│                                                                         │
└─────────────────────────────────────────────────────────────────────────┘

Installation

npm install @rootlodge/reality-server

Quick Start (No Database Required!)

import { RealityServer } from '@rootlodge/reality-server';

// That's it! No database needed.
const server = new RealityServer({
  serverId: 'server-1',
});

// When your data changes, invalidate the key
await server.invalidate('chat:room:123');

// Or invalidate multiple keys at once
await server.invalidateMany(['user:42', 'feed:global']);

// Mount the handler on your framework
const handler = server.getFetchHandler();
app.post('/reality/sync', handler);

Execution Modes

Reality supports three execution modes:

┌─────────────────────────────────────────────────────────────────────────┐
│                          EXECUTION MODES                               │
├─────────────────────────────────────────────────────────────────────────┤
│                                                                         │
│  SERVER-EXTERNAL (Default)        SSR-EMBEDDED                         │
│  ────────────────────────         ────────────                         │
│  ┌────────────────┐               ┌────────────────┐                   │
│  │ Reality Server │               │ Your SSR App   │                   │
│  │ ┌────────────┐ │               │ ┌────────────┐ │                   │
│  │ │   HTTP     │ │◄── Requests   │ │  Embedded  │ │                   │
│  │ │  Handler   │ │               │ │  Reality   │ │ ◄── In-process    │
│  │ └────────────┘ │               │ └────────────┘ │                   │
│  └────────────────┘               └────────────────┘                   │
│                                                                         │
│  Use for: Production, scaling     Use for: TanStack, Vite, Next.js    │
│                                                                         │
└─────────────────────────────────────────────────────────────────────────┘

Embedded Server for SSR

import { createEmbeddedRealityServer } from '@rootlodge/reality-server';

// Create embedded server for SSR
const embedded = createEmbeddedRealityServer({
  serverId: 'ssr-server',
});

// Handle sync requests directly (no HTTP)
const response = await embedded.handleSync(request);

// Invalidate when data changes
await embedded.invalidate(['chat:room:123']);

Optional Storage Adapters

Storage is OPTIONAL. Use it only if you need to:

  • Persist metadata across restarts
  • Share state between multiple server instances

Memory Storage (Default)

import { MemoryStorage } from '@rootlodge/reality-server';

const storage = new MemoryStorage();

SQL Storage (PostgreSQL, MySQL, SQLite)

import { SQLStorage } from '@rootlodge/reality-server';
import { Pool } from 'pg';

const pool = new Pool({ connectionString: process.env.DATABASE_URL });
const storage = new SQLStorage({
  query: (sql, params) => pool.query(sql, params).then(r => r.rows),
  dialect: 'postgres', // 'postgres' | 'mysql' | 'sqlite'
});

Drizzle Adapter

import { createDrizzleAdapter } from '@rootlodge/reality-server';
import { drizzle } from 'drizzle-orm/postgres-js';
import postgres from 'postgres';

const client = postgres(process.env.DATABASE_URL);
const db = drizzle(client);

const storage = createDrizzleAdapter(db, {
  tableName: 'reality_nodes',
});

Prisma Adapter

import { createPrismaAdapter } from '@rootlodge/reality-server';
import { PrismaClient } from '@prisma/client';

const prisma = new PrismaClient();
const storage = createPrismaAdapter(prisma, {
  modelName: 'RealityNode',
});

DynamoDB Adapter

import { DynamoDBStorage } from '@rootlodge/reality-server';
import { DynamoDB } from '@aws-sdk/client-dynamodb';

const dynamodb = new DynamoDB({ region: 'us-east-1' });
const storage = new DynamoDBStorage({
  client: dynamodb,
  tableName: 'reality-nodes',
});

Server Options

const server = new RealityServer({
  // Required
  storage: Storage,              // Storage adapter instance
  
  // Optional
  serverId: string,              // Unique server ID (auto-generated if not provided)
  meshPeers: string[],           // URLs of other servers for mesh coordination
  redis: {                       // Optional Redis for pub/sub acceleration
    publisher: RedisClient,
    subscriber: RedisClient,
    channel: 'reality:updates',
  },
  onError: (error) => void,      // Error handler
});

Updating Nodes

When your application data changes, update the corresponding Reality node:

// After adding a message
room.messages.push(newMessage);

// Update the Reality node with a hash of the current state
const hash = createHash(JSON.stringify(room.messages.map(m => m.id)));
await server.updateNode('chat:room:general', hash);

// Clients subscribed to 'chat:room:general' will detect the change on next sync

Hash Strategy

The hash should change whenever the underlying data changes. Options:

// Option 1: Hash of IDs (fast, detects additions/deletions)
const hash = createHash(items.map(i => i.id).join(','));

// Option 2: Hash of content (detects all changes)
const hash = createHash(JSON.stringify(items));

// Option 3: Timestamp (simple, always changes)
const hash = String(Date.now());

// Option 4: Version counter (from database)
const hash = String(record.version);

HTTP Protocol

Request

POST /reality/sync HTTP/1.1
Content-Type: application/json

{
  "known": {
    "chat:room:general": 5,
    "user:profile:123": 2
  }
}

Response

HTTP/1.1 200 OK
Content-Type: application/json

{
  "changed": {
    "chat:room:general": {
      "key": "chat:room:general",
      "version": 6,
      "hash": "abc123",
      "updatedAt": 1699876543210
    }
  },
  "mesh": {
    "peers": ["server-2", "server-3"],
    "serverVersion": 1
  }
}

Mesh Coordination

For multi-server deployments, servers gossip peer information:

const server1 = new RealityServer({
  serverId: 'server-1',
  peers: ['http://server-2:3000', 'http://server-3:3000'],
});

const server2 = new RealityServer({
  serverId: 'server-2',
  peers: ['http://server-1:3000', 'http://server-3:3000'],
});

Mesh info is piggybacked on normal requests - no additional connections needed.

Optional Invalidation Adapters

Automatically invalidate Reality keys when your database changes:

Drizzle Auto-Invalidation

import { 
  RealityServer, 
  createDrizzleInvalidationAdapter 
} from '@rootlodge/reality-server';

const reality = new RealityServer({ serverId: 'server-1' });

const adapter = createDrizzleInvalidationAdapter({
  db,
  keyExtractor: (table, operation, data) => {
    if (table === 'messages') {
      return [`chat:room:${data.roomId}`];
    }
    return [];
  },
});

reality.setInvalidationAdapter(adapter);

Prisma Auto-Invalidation

import { createPrismaInvalidationAdapter } from '@rootlodge/reality-server';

const adapter = createPrismaInvalidationAdapter({
  prisma,
  keyExtractor: (model, operation, data) => {
    if (model === 'Message') {
      return [`chat:room:${data.roomId}`];
    }
    return [];
  },
});

reality.setInvalidationAdapter(adapter);

Callback Adapter

import { createCallbackInvalidationAdapter } from '@rootlodge/reality-server';

const adapter = createCallbackInvalidationAdapter({
  onInvalidate: async (keys) => {
    console.log('Invalidated:', keys);
    // Custom logic: notify external systems, etc.
  },
});

Redis Acceleration (Optional)

For faster cross-server propagation:

import Redis from 'ioredis';

const publisher = new Redis(process.env.REDIS_URL);
const subscriber = new Redis(process.env.REDIS_URL);

const server = new RealityServer({
  storage,
  serverId: 'server-1',
  redis: {
    publisher,
    subscriber,
    channel: 'reality:updates',
  },
});

Important: Redis is for acceleration only. The system MUST work correctly without it.

Framework Adapters

Fetch API (Bun, Deno, Workers)

import { createFetchHandler } from '@rootlodge/reality-server';

const handler = createFetchHandler(server);

// Bun
Bun.serve({
  fetch(req) {
    if (new URL(req.url).pathname === '/reality/sync') {
      return handler(req);
    }
    return new Response('Not Found', { status: 404 });
  },
});

Express

import { createExpressAdapter } from '@rootlodge/reality-server';
import express from 'express';

const app = express();
app.use(express.json());
app.post('/reality/sync', createExpressAdapter(server));

Fastify

import { createFetchHandler } from '@rootlodge/reality-server';

fastify.post('/reality/sync', async (request, reply) => {
  const response = await createFetchHandler(server)(
    new Request('http://localhost/reality/sync', {
      method: 'POST',
      headers: { 'content-type': 'application/json' },
      body: JSON.stringify(request.body),
    })
  );
  reply.status(response.status).send(await response.json());
});

SSE Compatibility

For gradual migration from SSE:

// Server-side SSE compatibility endpoint
app.get('/events', async (req, res) => {
  const response = await server.handleSSECompat(req, {
    keys: ['notifications:all'],
    heartbeatInterval: 30000,
  });
  // Stream response to client
});

API Reference

RealityServer

class RealityServer {
  constructor(options: RealityServerOptions);
  
  // Update a node's version
  updateNode(key: string, hash: string): Promise<void>;
  
  // Get node metadata
  getNode(key: string): Promise<RealityNodeMeta | null>;
  
  // Handle sync request
  handleSync(request: SyncRequest): Promise<SyncResponse>;
  
  // Get mesh peers
  getMeshPeers(): Promise<string[]>;
  
  // Get server stats
  getStats(): Promise<ServerStats>;
  
  // SSE compatibility handler
  handleSSECompat(request: Request, options: SSEOptions): Promise<Response>;
}

Storage Interface

All storage adapters implement:

interface RealityStorage {
  getNode(key: string): Promise<RealityNodeMeta | null>;
  setNode(key: string, meta: RealityNodeMeta): Promise<void>;
  incrementVersion(key: string): Promise<number>;
  listChangedSince(version: number): Promise<RealityNodeMeta[]>;
  getNodes(keys: string[]): Promise<Map<string, RealityNodeMeta>>;
  getMaxVersion(): Promise<number>;
  deleteNode(key: string): Promise<void>;
  isHealthy(): Promise<boolean>;
}

License

MIT