LumenJS deep dive — Socket
This article is part of the LumenJS deep dive series a series about the architectural decisions behind LumenJS, an open-source full-stack web framework designed for agent-driven development.
subscribe() solved one direction. Server pushes, client listens. But some features need both sides talking. Chat, collaborative editing, presence, games. For that we added socket().
Socket
Same pattern, different primitive. Each page can export a socket() function. It runs on the server, sets up event listeners, and gives you a two-way channel — the client can send, the server can respond or broadcast.
The server listens with on(). It pushes back with push(). It broadcasts to a room with room.broadcast(). The cleanup function runs when the client disconnects.
On the component side, the framework injects an emit() method automatically, no wiring, no import.
That's the full loop. Client emits, server receives, server broadcasts, components update.
Recommended by LinkedIn
Rooms
Rooms are first-class. Join on connect, leave on disconnect, broadcast to everyone or everyone except the sender.
broadcast() excludes the sender. broadcastAll() includes everyone. Pick what fits.
When to use subscribe vs socket
The decision is simple. If the data only flows one way, server to client, use subscribe(). It uses native SSE, zero dependencies. If the client needs to send events too, use socket(). It uses Socket.IO, installed separately with lumenjs add socketio.
No overhead either way. Socket.IO client is only loaded on pages that export a socket() function.
When socket grows
Same rule as loaders and subscribe. Move the handler out to _socket.ts in the page folder. LumenJS picks it up automatically.
Conclusion
Three primitives. loader() for initial data. subscribe() for server push. socket() for bidirectional communication. Each one follows the same convention, a named export, collocated with the component, stripped from the client bundle.
The tradeoff here is infrastructure. Socket.IO needs a stateful server with sticky sessions. Traditional serverless functions don't fit. Plan for it before you reach for it.