Quickstart Decision Guide

Choose the right approach for your real-time application with Erebus

Quickstart Decision Guide

Welcome to Erebus! This guide helps you choose the right SDK and approach for your real-time application. Whether you're building a chat app, collaborative editor, or notification system, we'll get you started quickly.

🚀 Quick Decision Tree

Choose your path based on your project type:

I'm building a React/Next.js app

React SDK Quickstart (Experimental)

  • Hooks-based API: useChannel, usePresence
  • Declarative subscriptions with React patterns
  • Built-in state management

I'm building any other app (Node.js, Vue, Vanilla JS, etc.)

Core SDK Quickstart (Stable)

  • Framework-agnostic TypeScript/JavaScript SDK
  • Direct WebSocket connection management
  • Full control over connection lifecycle

I want maximum type safety

Schema Facade Guide

  • Runtime validation with Zod schemas
  • Compile-time type checking
  • Prevents payload mismatches

🏗️ Architecture Overview

Understanding how Erebus fits into your application:

Client-Server Flow

graph TB
    Client[Your App] --> Auth[Auth Server]
    Auth --> Grant[Grant Token]
    Client --> |Grant Token| Gateway[Erebus Gateway]
    Gateway --> Channel[Channel/Topic]
    Channel --> Subscribers[All Subscribers]

Key Components

ComponentPurposeYour Responsibility
Client SDKReal-time messagingImport and configure
Auth ServerIssue grant tokensImplement authorization logic
Erebus GatewayMessage routingNothing (managed service)
Channels/TopicsMessage organizationDesign topic structure

🎯 Use Case Examples

Real-time Chat

Best SDK: Core SDK or React SDK Key Features: Messages, presence, history

// Subscribe to chat messages
await client.subscribe("chat:room-123", (msg) => {
  addMessageToUI(msg.senderId, msg.payload);
});

// Track who's online  
await client.onPresence("chat:room-123", (presence) => {
  updateUserList(presence.clientId, presence.status);
});

// Send messages
await client.publish("chat:room-123", "Hello everyone! 👋");

Live Notifications

Best SDK: Core SDK Key Features: Targeted publishing, acknowledgments

// Subscribe to user-specific notifications
await client.subscribe(`user-${currentUserId}`, (msg) => {
  showNotification(JSON.parse(msg.payload));
});

// Send notification with delivery confirmation
await client.publishWithAck(
  `user-${targetUserId}`,
  JSON.stringify({ title: "New Message", body: "Alice sent you a message" }),
  (ack) => console.log("Notification delivered:", ack.success)
);

Collaborative Editing

Best SDK: Schema Facade (for type safety) Key Features: Operational transforms, conflict resolution

// Define schema for edit operations
const editSchema = z.object({
  type: z.enum(["insert", "delete", "format"]),
  position: z.number(),
  content: z.string(),
  author: z.string()
});

const typedClient = new ErebusPubSubSchemas(client, { edit: editSchema });

// Subscribe to document changes
await typedClient.subscribe("edit", `doc-${documentId}`, (msg) => {
  applyOperation(msg.payload); // Fully typed payload
});

// Broadcast changes
typedClient.publish("edit", `doc-${documentId}`, {
  type: "insert",
  position: cursorPosition,
  content: "new text",
  author: currentUserId
});

Live Dashboard

Best SDK: Core SDK Key Features: High-frequency updates, multiple data streams

// Subscribe to multiple data streams
const topics = ["metrics", "alerts", "user-activity"];

for (const topic of topics) {
  await client.subscribe(topic, (msg) => {
    updateDashboard(topic, JSON.parse(msg.payload));
  });
}

// Real-time metrics publishing
setInterval(() => {
  const metrics = collectMetrics();
  client.publish("metrics", JSON.stringify(metrics));
}, 1000);

🔧 Environment Setup

Development Setup

  1. Install Erebus SDK

    npm install @erebus-sh/sdk
  2. Create environment configuration

    .env.local
    SECRET_API_KEY=your_api_key_here
    EREBUS_AUTH_URL=http://localhost:4919
    EREBUS_WS_URL=ws://localhost:8787
  3. Set up TypeScript (recommended)

    tsconfig.json
    {
      "compilerOptions": {
        "target": "ES2022",
        "module": "ESNext",
        "moduleResolution": "bundler",
        "strict": true
      }
    }

Production Checklist

  • Environment variables configured
  • Auth server deployed and accessible
  • Error handling implemented
  • Connection retry logic added
  • Graceful shutdown handling
  • Monitoring and logging set up

📦 Deployment Examples

Vercel (Next.js)

vercel.json
{
  "functions": {
    "app/api/erebus/[...all]/route.ts": {
      "maxDuration": 30
    }
  },
  "env": {
    "SECRET_API_KEY": "@secret_api_key",
    "EREBUS_AUTH_URL": "https://your-app.vercel.app"
  }
}

Netlify

netlify.toml
[build]
  functions = "netlify/functions"

[[env]]
  SECRET_API_KEY = "your_api_key_here"
  EREBUS_AUTH_URL = "https://your-app.netlify.app"

Docker

Dockerfile
FROM node:18-alpine

WORKDIR /app
COPY package*.json ./
RUN npm ci --only=production

COPY . .

ENV NODE_ENV=production
ENV SECRET_API_KEY=${SECRET_API_KEY}
ENV EREBUS_AUTH_URL=${EREBUS_AUTH_URL}

EXPOSE 3000
CMD ["npm", "start"]

Railway

railway.yml
deploy:
  startCommand: npm start
  healthcheckPath: /health

env:
  SECRET_API_KEY: ${{ SECRET_API_KEY }}
  EREBUS_AUTH_URL: https://${{ RAILWAY_PUBLIC_DOMAIN }}

⚡ Performance Considerations

When to Use Core SDK vs React SDK

FactorCore SDKReact SDK
Performance✅ Maximum control⚠️ React overhead
Bundle Size✅ Minimal⚠️ React dependencies
Developer Experience⚠️ Manual state management✅ React patterns
Stability✅ Stable API⚠️ Experimental
Framework✅ Any framework❌ React only

Message Volume Guidelines

VolumeRecommended PatternNotes
Low (< 10/sec)Direct publish/subscribeSimple and straightforward
Medium (10-100/sec)Message batchingReduce network overhead
High (> 100/sec)Buffering + debouncingConsider rate limiting

🛠️ Common Patterns

Event-Driven Architecture

// Central event manager
class EventManager {
  constructor(private client: ErebusPubSubClient) {}
  
  // Emit events
  async emit(event: string, data: unknown) {
    await this.client.publish(`events:${event}`, JSON.stringify(data));
  }
  
  // Listen for events
  async on(event: string, handler: (data: unknown) => void) {
    await this.client.subscribe(`events:${event}`, (msg) => {
      handler(JSON.parse(msg.payload));
    });
  }
}

Request-Response Pattern

// Request-response over pub/sub
async function makeRequest(requestId: string, data: unknown): Promise<unknown> {
  const responsePromise = new Promise((resolve) => {
    const handler = (msg: MessageBody) => {
      const response = JSON.parse(msg.payload);
      if (response.requestId === requestId) {
        client.unsubscribe(`response:${requestId}`);
        resolve(response.data);
      }
    };
    
    client.subscribe(`response:${requestId}`, handler);
  });
  
  // Send request
  await client.publish(`request:service`, JSON.stringify({
    requestId,
    data
  }));
  
  return responsePromise;
}

Fan-out Notifications

// Send to multiple users efficiently
async function notifyUsers(userIds: string[], notification: unknown) {
  // Option 1: Individual topics
  await Promise.all(
    userIds.map(userId => 
      client.publish(`user:${userId}`, JSON.stringify(notification))
    )
  );
  
  // Option 2: Broadcast topic with filtering
  await client.publish("broadcast:notifications", JSON.stringify({
    targetUsers: userIds,
    ...notification
  }));
}

🚦 Getting Started Paths

Path 1: Simple Integration (5 minutes)

  1. Install SDK - Basic installation
  2. Core Quickstart - Working example
  3. Deploy - Push to production

Path 2: Type-Safe Development (15 minutes)

  1. Install SDK - Basic installation
  2. Schema Facade - Type-safe messaging
  3. Advanced Patterns - Production patterns

Path 3: React Integration (3 minutes)

  1. Install SDK - Basic installation
  2. React Quickstart - Next.js example
  3. Hooks Reference - Coming soon

ResourceDescription
Complete API ReferenceAll methods and types
Examples RepositoryWorking code examples
Schema ValidationType-safe messaging
Message HistoryHistorical message retrieval
Error HandlingRobust error patterns