The page side — what a page writes
The socket connects by itself when the install has realtime.enabled in main.json and a user is signed in. A page asks for the rooms its app declared (node/apps/<app>/api/realtime.js) and listens for the events the server pushes (realtime.emit(room, event, payload)).
// route.php: 'vendors' => ['socketio'], 'libs' => ['realtime']
const ack = await g.realtime.join('bsp:project:12'); // { ok } | { ok: false, reason }
const off = g.realtime.on('project-changed', (payload) => {
lister.reload(); // a thin reference — fetch the rest through the API
});
// later: off(); g.realtime.leave('bsp:project:12');
Live state — g.realtime.state()
…
This site is anonymous by design, so the lib stays idle here (reason: "anonymous"). The signed-in proof lives on the app site: /realtime-test.
The rules
- One socket per page, opened by the lib — never call
io()yourself. Rooms are re-joined after every reconnection; the server forgets them with the socket, the page must not notice. - A session ended anywhere (logout, revoke, expiry) ENDS the lib for this page:
realtime:endedon document, no reconnection. A new sign-in is a new page load. - Events reach
g.realtime.on(event, fn)AND document asrealtime:event(detail.event,detail.payload). Keep payloads thin references — the page fetches the data through the API, exactly like pub/sub. - The server side (rooms, allow(),
realtime.emit) is api.md "Realtime — socket.io"; docs:templates/app/docs/libs/realtime.md.