@s2-dev/resumable-stream/tanstack-ai entrypoint.
The server helper stores TanStack StreamChunk events in S2. The client helper
builds a TanStack SubscribeConnectionAdapter so useChat can send messages
normally while reading assistant chunks from an S2 replay stream.
Install
Server Setup
lib/s2.ts
Start A Turn
app/api/chat/route.ts
Replay Route
app/api/chat/replay/route.ts
live: true for session-mode chat UIs so the replay connection stays open
at the tail and receives future turns.
Client
app/page.tsx
id: cursor. createConnection remembers
the most recent cursor inside that connection instance and sends it back as
from on the next subscribe request, so a dropped subscription can continue
after the chunks already delivered instead of rendering them twice. For a full
page refresh, pass the saved history cursor as shown below.
Completed History
TanStackuseChat expects completed messages as app state, so keep transcript
loading in your app:
- Fetch history before mounting
useChat. - Pass it as
initialMessages. - Start replay from the history cursor so old chunks are not rendered again.
/history route. That history behavior is intentionally
example code, not package API.
Options
createResumableChat accepts:
| option | default | description |
|---|---|---|
mode | "single-use" | "single-use" uses one stream per generation. "shared" reuses one active-generation stream. "session" appends generations to one durable stream. |
endpoints | S2 defaults | Optional endpoint overrides, commonly used with S2 Lite. |
batchSize | 10 | Maximum number of chunks per append batch. |
lingerDuration | 50 | Maximum batching delay in milliseconds. |
leaseDurationMs | 5000 | shared mode takeover window for stale active generations. |
onError | generic message | Maps upstream errors to a TanStack RUN_ERROR chunk. |
createConnection accepts:
| option | description |
|---|---|
sendUrl | POST endpoint that starts generation. |
subscribeUrl | GET endpoint that returns replay SSE. String URLs get ?from=<cursor> appended after chunks have been seen; function URLs receive the cursor. |
body | Extra fields merged into the POST body, usually { id: chatId }. |
headers | Static or lazy headers sent on every request. |
credentials | Fetch credentials mode. Defaults to same-origin. |
fetch | Custom fetch implementation for tests or framework integrations. |
reconnectBackoffMs | Millisecond backoff schedule. Defaults to [], so TanStack owns subscription lifecycle. |
Example
A complete TanStack Start chat app is available here:examples/tanstack-ai-chat.
