Skip to content

Realtime

Channels, tickets, presence and live logs.

View as Markdown

Create a channel

A channel belongs to exactly one project. A channel with the same name in another project is a different channel.

bash
veltic realtime channels create PROJECT_ID orders "Order status"

Test in two terminals

Start the listener first, then publish from a second terminal.

bash
veltic realtime listen PROJECT_ID orders
veltic realtime publish PROJECT_ID orders created '{"id":1}'

Connect a browser client

Request a short-lived ticket from the dashboard and connect directly to the realtime endpoint with it. The dashboard cannot terminate the WebSocket itself, because serverless functions cannot hold a persistent connection. Grant only the publish or subscribe permissions the client needs.

typescript
const ticket = await fetch('/api/realtime/ticket', {
  method: 'POST',
  body: JSON.stringify({ channels: ['orders'], mode: 'subscribe' })
}).then(response => response.json());

const socket = new WebSocket(`${ticket.endpoint}?ticket=${ticket.token}`);

Live logs

logs:app:<name> and logs:function:<name> are a reserved namespace. Nobody creates them: the ticket grants them through a prefix after checking app.read or function.read and that the resource exists, and it grants subscribe only, so no client can forge a log line. Payloads are raw excerpts batched every 250 milliseconds; anything over 32 KB is dropped and flagged as truncated.

Realtime is not an archive

Messages reach whoever is connected at the time. Store anything that matters in PostgreSQL and resynchronize state after a reconnect.