Skip to content

Getting started

The @insession SDK is three small packages pulled out of a production realtime app. They are independent enough that you can adopt one and ignore the rest.

PackageWhat it doesRuntime dependencies
@insession/ws-resilient-transportKeeps a WebSocket connected across deploys: fast reconnect on service restart, jittered backoff otherwise, terminal close codes that stop retrying.none
@insession/space-stateHolds the state of a shared room — members, chat, presence, typing, plugins — as a pure reducer over inbound messages.none
@insession/space-state-reactBinds the store to React via useSyncExternalStore. One hook.@insession/space-state (+ react as a peer)

The only edge between them is space-state-reactspace-state. The transport does not depend on the store, and the store does not depend on the transport:

your app
├── @insession/space-state-react ──> @insession/space-state
│ │
│ store.onSend(msg) ──┐
│ store.receive(msg) <┘
│ │
└── @insession/ws-resilient-transport ─────┘
(you wire these two together)

That gap is deliberate. The store never opens a socket: it hands outbound messages to whatever you registered with onSend, and you feed inbound messages back in with receive. Wiring them together is three lines, and in exchange the store stays testable with no server and no browser at all.

  • You have a WebSocket that drops on every deploy. Take ws-resilient-transport alone. It knows nothing about rooms or state.
  • You are modelling a shared room and want the state logic testable. Take space-state alone, and keep your existing transport.
  • Both, in a React app. Take all three.
Terminal window
npm install @insession/space-state @insession/space-state-react @insession/ws-resilient-transport

Every package ships as built ESM (dist/index.js + dist/index.d.ts) with TypeScript types included. Node 22.18+ or any modern bundler.

import { createSpaceStore } from '@insession/space-state';
import { createResilientWebSocket } from '@insession/ws-resilient-transport';
const store = createSpaceStore({
selfName: 'alice',
t: (key) => key,
getPresence: () => 'active',
});
const transport = createResilientWebSocket({
url: 'wss://example.com/ws',
buildOpenMessage: async ({ resumedFromServiceRestart }) => ({
type: 'join',
resume: resumedFromServiceRestart,
}),
onMessage: (msg) => store.receive(msg), // inbound: socket → store
serviceRestartCode: 1012,
});
store.onSend((msg) => transport.send(msg)); // outbound: store → socket
transport.connect();

Side effects the store asks for (a sound, a notification, a timer) arrive separately through store.onEffect — the store describes them, your app decides what they mean.