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();
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.