Skip to main content

Documentation Index

Fetch the complete documentation index at: https://mintlify.com/InsForge/InsForge/llms.txt

Use this file to discover all available pages before exploring further.

Overview

InsForge Real-time provides WebSocket-based pub/sub messaging for live updates, chat, notifications, and collaborative features.

Key Features

  • Channel-based Messaging - Organize messages with pattern matching
  • WebSocket Pub/Sub - Low-latency bidirectional communication
  • Webhook Integration - Forward messages to external services
  • Message History - Query past messages via API
  • Row Level Security - Database-level access control
  • Delivery Tracking - Monitor message delivery rates

Architecture

Channels

Channels use pattern matching to organize subscriptions.

Creating Channels

curl -X POST https://your-app.region.insforge.app/api/realtime/channels \
  -H "Authorization: Bearer YOUR_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "pattern": "chat:*",
    "description": "Chat room messages",
    "webhookUrls": ["https://example.com/webhook"],
    "enabled": true
  }'
Response:
{
  "id": "550e8400-e29b-41d4-a716-446655440000",
  "pattern": "chat:*",
  "description": "Chat room messages",
  "webhookUrls": ["https://example.com/webhook"],
  "enabled": true,
  "createdAt": "2024-01-15T10:30:00Z",
  "updatedAt": "2024-01-15T10:30:00Z"
}

Channel Patterns

Patterns support wildcard matching:
PatternMatchesUse Case
chat:*chat:room1, chat:room2Multiple chat rooms
order:*order:123, order:456Order-specific updates
user:*:notificationsuser:123:notificationsUser notifications
globalglobalBroadcast to all

List Channels

curl https://your-app.region.insforge.app/api/realtime/channels \
  -H "Authorization: Bearer YOUR_TOKEN"

WebSocket Connection

Connecting

import { createClient } from '@insforge/sdk';

const client = createClient({
  baseUrl: 'https://your-app.region.insforge.app',
  anonKey: 'your-anon-key'
});

// Connect with authentication
await client.realtime.connect({
  accessToken: 'your-access-token'
});

console.log('Connected to real-time server');

Connection States

client.realtime.on('connect', () => {
  console.log('Connected');
});

client.realtime.on('disconnect', () => {
  console.log('Disconnected');
});

client.realtime.on('error', (error) => {
  console.error('Error:', error);
});

Subscribing to Channels

const subscription = client.realtime
  .channel('chat:room1')
  .on('message', (payload) => {
    console.log('Message:', payload);
  })
  .subscribe();

Unsubscribing

subscription.unsubscribe();

Publishing Messages

// Publish to channel
const { error } = await client.realtime
  .channel('chat:room1')
  .send({
    type: 'message',
    event: 'message.new',
    payload: {
      text: 'Hello, world!',
      userId: '123',
      timestamp: Date.now()
    }
  });

if (error) {
  console.error('Failed to send:', error);
}

Message Structure

interface RealtimeMessage {
  type: 'message' | 'broadcast';
  event: string;           // e.g., "message.new"
  channel: string;         // e.g., "chat:room1"
  payload: any;           // Your custom data
  senderId?: string;      // User ID of sender
  timestamp: string;      // ISO 8601
}

Presence

Track who’s online in a channel:
const channel = client.realtime.channel('chat:room1');

// Set initial presence
await channel.track({
  user_id: '123',
  username: 'John',
  status: 'online'
});

// Listen to presence changes
channel.on('presence', (event) => {
  if (event.type === 'join') {
    console.log('User joined:', event.presence);
  } else if (event.type === 'leave') {
    console.log('User left:', event.presence);
  }
});

Webhooks

Forward messages to external services:

Webhook Payload

{
  "event": "message.new",
  "channelName": "chat:room1",
  "channelId": "550e8400-e29b-41d4-a716-446655440000",
  "payload": {
    "text": "Hello, world!",
    "userId": "123"
  },
  "senderId": "123e4567-e89b-12d3-a456-426614174000",
  "timestamp": "2024-01-15T10:30:00Z"
}

Webhook Endpoint

app.post('/webhook', express.json(), (req, res) => {
  const { event, channelName, payload } = req.body;
  
  console.log(`Received ${event} on ${channelName}:`, payload);
  
  // Process message
  if (event === 'message.new') {
    // Send notification, log to analytics, etc.
  }
  
  res.status(200).json({ received: true });
});

Message History

Query Messages

curl "https://your-app.region.insforge.app/api/realtime/messages?channelId=550e8400&limit=50" \
  -H "Authorization: Bearer YOUR_TOKEN"
Response:
[
  {
    "id": "660e8400-e29b-41d4-a716-446655440000",
    "eventName": "message.new",
    "channelId": "550e8400-e29b-41d4-a716-446655440000",
    "channelName": "chat:room1",
    "payload": {
      "text": "Hello!",
      "userId": "123"
    },
    "senderType": "user",
    "senderId": "770e8400-e29b-41d4-a716-446655440000",
    "wsAudienceCount": 5,
    "whAudienceCount": 1,
    "whDeliveredCount": 1,
    "createdAt": "2024-01-15T10:30:00Z"
  }
]

Message Statistics

curl "https://your-app.region.insforge.app/api/realtime/messages/stats?channelId=550e8400" \
  -H "Authorization: Bearer YOUR_TOKEN"
Response:
{
  "totalMessages": 1250,
  "whDeliveryRate": 0.98,
  "topEvents": [
    { "eventName": "message.new", "count": 450 },
    { "eventName": "message.edit", "count": 120 }
  ]
}

Row Level Security

Control access with RLS policies:

Subscribe Permissions

-- Users can only subscribe to channels they have access to
CREATE POLICY "Users can subscribe to public channels"
ON realtime_channels FOR SELECT
USING (enabled = true AND is_public = true);

CREATE POLICY "Users can subscribe to their own channels"
ON realtime_channels FOR SELECT
USING (owner_id = auth.user_id());

Publish Permissions

-- Users can only publish to channels they're members of
CREATE POLICY "Users can publish to their channels"
ON realtime_messages FOR INSERT
WITH CHECK (
  EXISTS (
    SELECT 1 FROM channel_members
    WHERE channel_id = realtime_messages.channel_id
    AND user_id = auth.user_id()
  )
);

Get RLS Policies

curl https://your-app.region.insforge.app/api/realtime/permissions \
  -H "Authorization: Bearer YOUR_TOKEN"

Use Cases

Chat Application

1

Create Chat Channel

await createChannel({
  pattern: 'chat:*',
  description: 'Chat rooms'
});
2

Subscribe to Room

const sub = client.realtime
  .channel(`chat:${roomId}`)
  .on('message', handleMessage)
  .subscribe();
3

Send Messages

await client.realtime
  .channel(`chat:${roomId}`)
  .send({
    type: 'message',
    event: 'message.new',
    payload: { text, userId }
  });

Live Notifications

// Subscribe to user notifications
client.realtime
  .channel(`user:${userId}:notifications`)
  .on('notification', (payload) => {
    showNotification(payload);
  })
  .subscribe();

// Send notification
await client.realtime
  .channel(`user:${userId}:notifications`)
  .send({
    type: 'broadcast',
    event: 'notification',
    payload: {
      title: 'New message',
      body: 'You have a new message',
      type: 'info'
    }
  });

Live Cursors

// Track cursor position
const channel = client.realtime.channel('document:123');

document.addEventListener('mousemove', (e) => {
  channel.track({
    user_id: userId,
    cursor: { x: e.clientX, y: e.clientY }
  });
});

// Render other users' cursors
channel.on('presence', () => {
  const users = channel.presenceState();
  renderCursors(users);
});

Best Practices

Use Channel Patterns

Organize channels with patterns like resource:id for scalability

Implement Reconnection

Handle disconnections and reconnect automatically

Debounce Presence Updates

Don’t send presence updates too frequently (max 1/sec)

Clean Up Subscriptions

Always unsubscribe when components unmount

Use RLS for Security

Protect channels with Row Level Security policies

Next Steps

Database

Store message history and user data

Authentication

Secure WebSocket connections

Functions

Process messages server-side

AI Integration

Build AI-powered chat