Atelier

Realtime

Channels for postgres changes, custom broadcast, and presence. Server pushes; the database and the realtime layer are co-located.

Three event types

  • postgres_changes — automatic notifications when tables change (INSERT, UPDATE, DELETE).
  • broadcast — custom events you publish from anywhere in your code.
  • presence — track who’s currently online, with optional state per user.

Subscribe

import { atelier } from '@atelier/sdk';
 
const channel = atelier.channel('room-42');
 
channel.on('postgres_changes', { table: 'todos' }, (change) => {
  // { op, row, old_row, user_id }
});
 
channel.on('broadcast', { event: 'cursor' }, (payload) => {
  // { x, y, color }
});
 
channel.on('presence', (state) => {
  // { joined, left, users }
});
 
await channel.subscribe();

postgres_changes

Every mutation that flows through Base fans out to subscribers of that table. Subject to RLS — a user only receives rows they’re allowed to see.

// All changes
channel.on('postgres_changes', { table: 'todos' }, handler);
 
// Specific operation
channel.on('postgres_changes', { table: 'todos', op: 'INSERT' }, handler);
 
// With a filter
channel.on('postgres_changes', {
  table: 'todos',
  filter: { user_id: me.id },
}, handler);

Broadcast

Send custom events to anyone subscribed to a channel. Useful for cursor positions, typing indicators, or game state — anything ephemeral that doesn’t belong in the database.

channel.send({ event: 'cursor', payload: { x: 120, y: 480, color: '#000' } });

Presence

Track who’s online in a channel. The server diffs join/leave automatically; you get current state and per-user updates.

channel.presence.track({ name: 'Ryan', cursor: { x: 0, y: 0 } });
 
channel.on('presence', (state) => {
  // state.users    — array of currently-online users
  // state.joined   — users since last event
  // state.left     — users since last event
});
 
channel.presence.untrack();
Transport

The SDK uses Server-Sent Events for server-push and HTTP for publish. One connection per project, multiple topics multiplexed. Behind the scenes the SDK upgrades to WebSockets when duplex is needed (cursor + chat + game state). You don’t manage connections.

Scaling

Single-replica setups run the emitter in-process — no Redis, no NATS, no Postgres LISTEN. Multi-replica clusters swap in a Postgres-backed emitter transparently — your code doesn’t change.