Realtime streaming state · pre-alpha

Liveflux

Turn a live connection — WebSocket, Phoenix Channels, any push transport — into typed, reconnect-safe UI state. You describe the channel and how its events fold; Liveflux owns the sockets, cache glue, dedup, backpressure, and reconnect logic.

A live, keyed list of trades — the whole component, and it running:

Trades.tsx
import { useStream } from '@liveflux/react';

type Trade = { id: number; symbol: string; price: number };

export function Trades() {
  // upsert → Trade[]: a matching id updates in place, a new id is appended.
  const trades = useStream<Trade>({
    channel: 'trades',
    into: { strategy: 'upsert', key: 'id', cap: 50 },
  });

  return trades.map((t) => <Row key={t.id} symbol={t.symbol} price={t.price} />);
}
Live · running now

The wire subscription is multiplexed onto one connection, deduped, and re-sent after a reconnect — none of which you wrote.

The realtime plumbing it owns

A realtime feature looks small until you ship it. Liveflux is the layer that owns the parts you'd otherwise hand-roll every time — behind a small typed surface.

Reconnect-safe

On an unexpected close it backs off with jitter and replays every active subscription on the new connection — streams resume on their own.

One multiplexed connection

Many subscriptions share a single socket. Identical subscriptions fold once, ref-counted, and release only when the last subscriber leaves.

Cache-shaped state

Fold raw events into the shape your UI renders — append (log), upsert (keyed list), replace (latest), or your own reducer.

Backpressure

Adapters watch the send buffer and queue control frames past a high-water mark; oversized inbound frames are dropped before decoding.

Tear-free React

Reads go through useSyncExternalStore, so state is consistent under concurrent rendering. Pass a selector to re-render only on the slice you use.

Typed end-to-end

Generics flow from the channel through the fold strategy to the value your component receives — the return type follows the strategy.

Protocol- and framework-agnostic

One engine, swappable transports, per-framework bindings. Point it at a new backend by changing the adapter; the components don't move.

Binding · @liveflux/react
Engine · @liveflux/core
Adapter · ws / phoenix
Your backend

Packages

@liveflux/core

Framework-agnostic engine — connection, subscriptions, store, backpressure.

@liveflux/ws

Generic WebSocket adapter for any plain-WebSocket backend, in any language.

@liveflux/phoenix

Phoenix Channels (v2) adapter — joins, rejoin backoff, heartbeat topic.

@liveflux/react

React binding — the useStream hook + LivefluxProvider.

Wire up your first stream

Install three packages, drop in a provider, and call useStream. It's about a dozen lines.