Events & rooms
An event is a server→client push where the server picks the recipients. Declare it under serverToClient (no subscribe flag):
serverToClient: {
message: { payload: z.object({ room: z.string(), text: z.string(), from: z.string() }) },
}The client listens with on, which returns an unsubscribe function:
const off = client.on('message', (m) => render(m)) // m is typed
off() // stop listeningSending to one connection
Inside a handler, push to just that connection with conn.emit. It's scoped to the connection's role events:
user: {
notify: async (_input, _ctx, conn) => {
conn.emit('message', { room: 'lobby', text: 'hi', from: 'system' })
return { ok: true }
},
}conn.emit is node-local — it only reaches that specific socket on this node. To reach a connection or user wherever they're connected (across nodes), use srv.toConn(id).emit(...) / srv.toUser(uid).emit(...) — see Introspection & presence.
Rooms
A room is a server-controlled group of connections. Add members, then broadcast:
srv.room('room:42').add(conn) // server-controlled membership
srv.room('room:42').broadcast('message', { ... }) // delivered to every member
srv.room('room:42').remove(conn)
srv.room('room:42').size // member count on THIS nodeRooms are mixed-role — a user and an agent can be in the same room. Because of that, broadcast only accepts shared events (the vocabulary every member provably understands). So put events you broadcast to rooms in shared.serverToClient:
shared: {
serverToClient: { message: { payload: z.object({ room: z.string(), text: z.string(), from: z.string() }) } },
}Role-specific fan-out
To push a role-specific event to a group, use a topic (forRole(r).publish) or iterate and conn.emit. room.broadcast is deliberately shared-only.
Event vs topic
Use an event when the server decides who receives it (notifications, room broadcasts, targeted pushes). Use a topic when the client opts into a stream. Both are serverToClient; the only difference is the subscribe: true flag and who initiates.
Delivery
Events are at-most-once — a client that's offline misses them (no replay). Design for it: see Reconnection & delivery.
Next: Topics.