Stacks Documentation
⌘ K
Changelog

TypeScript Realtime Package

A powerful and flexible realtime communication library for TypeScript that provides multiple drivers (Pusher, Socket.IO, and Bun WebSocket) for handling realtime events and broadcasting.

Installation

# Using bun
bun add @stacksjs/realtime

# Using npm
npm install @stacksjs/realtime

# Using yarn
yarn add @stacksjs/realtime

# Using pnpm
pnpm add @stacksjs/realtime

Basic Usage

import { broadcast, channel } from'@stacksjs/realtime' '@stacksjs/realtime'

// Broadcasting an event
const orderData = {
  orderId:'12345' '12345',
  userId:'user_123' 'user_123',
  products: [
    { id:'prod_1' 'prod_1', name:'Widget' 'Widget', quantity: 2 },
    { id:'prod_2' 'prod_2', name:'Gadget' 'Gadget', quantity: 1 },
  ],
  totalAmount: 99.99,
  shippingAddress: {
    street:'123 Main St' '123 Main St',
    city:'Anytown' 'Anytown',
    country:'USA' 'USA',
    postalCode:'12345' '12345',
  },
}

// Trigger the broadcast
await broadcast('OrderShipped''OrderShipped', orderData)

Creating Broadcast Events

Create a broadcast event by defining a handler in your broadcasts directory:

// app/Broadcasts/OrderShipped.ts
import type { RealtimeOptions } from'@stacksjs/types' '@stacksjs/types'
import { channel } from'@stacksjs/realtime' '@stacksjs/realtime'

interface OrderData {
  orderId: string
  userId: string
  products: Array<{
    id: string
    name: string
    quantity: number
  }>
  totalAmount: number
  shippingAddress: {
    street: string
    city: string
    country: string
    postalCode: string
  }
  shippedAt?: string
}

export default {
  /**
   * The event name.
   */
  event:'OrderShipped' 'OrderShipped',

  /**
   * Handle the broadcast event.
   * This method is called when the event is triggered.
   */
  async handle(data: OrderData): Promise<void> {
    await channel(`orders.${data.orderId}`).private(this.event, data)
  },
} satisfies RealtimeOptions

Channel Types

The package supports three types of channels:

1. Public Channels

  • Accessible to all clients
  • No authentication required
  • Example: channel('notifications').public(event, data)

2. Private Channels

  • Require authentication
  • Prefixed with private-
  • Example: channel('user-123').private(event, data)

3. Presence Channels

  • Require authentication
  • Support user presence features
  • Prefixed with presence-
  • Example: channel('chat-room').presence(event, data)

Broadcasting Methods

Basic Broadcasting

// Broadcast to a public channel
await channel('notifications''notifications').public('new-message''new-message', { message:'Hello!' 'Hello!' })

// Broadcast to a private channel
await channel('user-123''user-123').private('status-update''status-update', { status:'online' 'online' })

// Broadcast to a presence channel
await channel('chat-room''chat-room').presence('user-joined''user-joined', { user:'John' 'John' })

Broadcasting with Events

// Define your event data interface
interface MessageData {
  content: string
  sender: string
  timestamp: string
}

// Create a broadcast event
// app/Broadcasts/NewMessage.ts
export default {
  event:'NewMessage' 'NewMessage',
  async handle(data: MessageData): Promise<void> {
    await channel(`chat.${data.sender}`).private(this.event, data)
  },
} satisfies RealtimeOptions

// Trigger the broadcast
await broadcast('NewMessage''NewMessage', {
  content:'Hello!' 'Hello!',
  sender:'user_123' 'user_123',
  timestamp: new Date().toISOString(),
})

Configuration

The package can be configured through the application's configuration file:

// config/realtime.ts
export default {
  driver:'pusher' 'pusher',// or 'socket' or 'bun' // or 'socket' or 'bun'
  
  // Pusher configuration
  pusher: {
    appId:'your-app-id' 'your-app-id',
    key:'your-key' 'your-key',
    secret:'your-secret' 'your-secret',
    cluster:'mt1' 'mt1',
    useTLS: true,
  },
  
  // Socket.IO configuration
  socket: {
    host:'localhost' 'localhost',
    port: 3000,
  },
}

Best Practices

1. Channel Naming

  • Use descriptive names for channels
  • Follow the naming convention: {type}.{identifier}
  • Example: orders.12345, chat.user_123

2. Event Naming

  • Use PascalCase for event names
  • Be specific and descriptive
  • Example: OrderShipped, MessageReceived

3. Type Safety

  • Define interfaces for your event data
  • Use TypeScript to ensure type safety
  • Export types for reuse across your application

4. Security

  • Use private channels for sensitive data
  • Implement proper authentication for private and presence channels
  • Validate data before broadcasting

5. Organization

  • Keep broadcast events in a dedicated directory
  • Group related events together
  • Use consistent naming conventions