WebSockets
WebSockets are a first-class core transport in Slingshot.
They are not interchangeable with SSE. Use WebSockets when clients need to send messages back, subscribe to rooms, or participate in presence and recovery flows.
These examples extend the starter app with a blog collaboration endpoint.
A copyable endpoint
Section titled “A copyable endpoint”// @skip-typecheckimport { defineApp } from '@lastshotlabs/slingshot';import { blogPackage } from './blog/package';
export default defineApp({ packages: [blogPackage], ws: { endpoints: { '/ws/blog': { presence: true, heartbeat: true, rateLimit: { windowMs: 10_000, maxMessages: 50, onExceeded: 'close' }, onRoomSubscribe: async (ws, room) => room === `post:${ws.data.actor.id}:drafts` || room.startsWith('post:public:'), incoming: { 'post:typing': { auth: 'userAuth', handler: (_ws, payload, ctx) => { const room = `post:${ctx.actor.id}:drafts`; ctx.publish(room, { type: 'post:typing', payload }); return { delivered: true }; }, }, 'post:subscribePublic': { auth: 'none', handler: (_ws, payload, ctx) => { const postId = (payload as { postId: string }).postId; ctx.subscribe(`post:public:${postId}`); return { subscribed: postId }; }, }, }, }, }, },});The endpoint surface
Section titled “The endpoint surface”Each endpoint can configure:
on.open,on.message,on.close,on.drainonRoomSubscribeincomingnamed event handlersmiddlewarefor incoming eventspresenceheartbeatpersistencerecoveryrateLimit
That is a real runtime surface, not just a thin socket wrapper.
Rooms and publish
Section titled “Rooms and publish”Incoming event handlers get a WsEventContext with:
publish(room, data)subscribe(room)unsubscribe(room)socketIdactorIdendpoint
That is the canonical room-level API for framework-managed WebSocket behavior.
Presence and recovery
Section titled “Presence and recovery”Presence and recovery are separate concerns:
presencetracks connected actors and room membershiprecoverylets clients reconnect and resume within a configured window
Recovery requires persistence. Slingshot will reject invalid recovery configuration at startup instead of failing later at runtime.
Transport and scaling
Section titled “Transport and scaling”Single-instance room publish works without extra setup. Multi-instance delivery requires a shared WebSocket transport:
import { defineApp } from '@lastshotlabs/slingshot';
declare const myWsTransport: import('@lastshotlabs/slingshot').WsConfig['transport'];
export default defineApp({ ws: { transport: myWsTransport, endpoints: { '/ws': { presence: true }, }, },});This is separate from the event bus. The event bus handles app events. The WebSocket transport handles cross-instance room fan-out.
Progression
Section titled “Progression”- default: one endpoint with
incoming,onRoomSubscribe, and room publish - customize: add
middleware,persistence, andrecovery - escape hatch: supply a shared
transportand let packages self-wire endpoint behavior through the bootstrap endpoint map
Package self-wiring
Section titled “Package self-wiring”Packages can bootstrap endpoint hooks through the root ws config. createApp() exposes the
bootstrap endpoint map on context so packages can attach incoming handlers or subscribe guards
before the runtime starts the live transport.
That is how package-owned realtime behavior can remain package-owned instead of leaking into the app root.
Use WebSockets for
Section titled “Use WebSockets for”- chat and collaborative editing
- room subscriptions
- presence
- low-latency bidirectional workflows
Use Server-Sent Events when the stream is server-to-client only.