S2 integrates with TanStack AI through theDocumentation Index
Fetch the complete documentation index at: https://s2.dev/docs/llms.txt
Use this file to discover all available pages before exploring further.
@s2-dev/resumable-stream package. The integration persists TanStack
StreamChunk events to S2 and replays them through a useChat connection
adapter.
Prerequisites
- Sign up here, generate an access token, and set
it as
S2_ACCESS_TOKENin your env. - Create a basin from the Basins tab with Create Stream on Append and
Create Stream on Read enabled, and set it as
S2_BASINin your env.
Import paths
The integration has separate server and client entrypoints.Setup
Create one chat helper and share it across your routes:lib/s2.ts
lib/stream-name.ts
Server: POST route
In session mode, the POST route starts generation and returns quickly. Chunk delivery happens through the replay route, not the POST response.src/routes/api.chat.ts
makeSessionResponse treats S2 as the source of truth. It reads the durable
chat stream, appends the latest submitted user message if it is not already
stored, then starts your source function with the S2-derived messages. The
POST route returns 202; the replay route delivers the stored user chunk and
model chunks.
The example omits waitUntil because TanStack Start route handlers do not have
a Next.js-style after API. If your deployment runtime can stop background
work after a response is returned, pass that runtime’s background-task hook as
waitUntil.
Server: replay route
The replay route owns all session delivery.src/routes/api.chat.replay.ts
fromSeqNum is omitted, chat.replay first emits a TanStack
MESSAGES_SNAPSHOT, then tails from the snapshot cursor. When fromSeqNum is
present, replay starts from that cursor. Replay responses include SSE id
fields, and the client adapter stores those ids as the next reconnect cursor.
Client
Pass the send and replay endpoints to the TanStack connection.app/page.tsx
subscribeUrlis both the initial snapshot read and the live replay stream.live: truetells TanStackuseChatto callconnection.subscribe()on mount.body: { id: chatId }includes the chat id on send requests.
live: true because makeSessionResponse returns 202
and chunks arrive through the replay subscription.
Flow
- The browser mounts and calls
connection.subscribe(). chat.replayreads the current S2 stream and emitsMESSAGES_SNAPSHOT.- The same replay response keeps tailing new chunks.
- The browser sends a message with the normal TanStack
messagesarray. makeSessionResponserereads S2, stores only the latest missing user message, then starts the model.- Model chunks are written to S2 and delivered through the open replay response.
- Reconnects continue from the last SSE
id.
Modes
mode controls how generations map to S2 streams.
| mode | use when | refresh behavior |
|---|---|---|
single-use | Each assistant turn has its own stream name. | Replays only the active turn. |
shared | One stream name should hold the active generation only. | Replays the active generation after lease/fence coordination. |
session | You are building a full chat session. | Replay bootstraps a snapshot, then tails later chunks. |
single-use and shared, you can omit subscribeUrl and stream chunks
directly on the POST response. If you pass subscribeUrl, the client can
recover an active generation on mount.
Configuration
Relevant options oncreateResumableChat:
| option | default | what it controls |
|---|---|---|
mode | "single-use" | "single-use" uses one stream per generation. "shared" reuses one active-generation stream. "session" stores a durable chat session log. |
endpoints | S2 defaults | Optional endpoint overrides, for example when using S2 Lite. |
leaseDurationMs | 5000 | Only for shared and session. Max pause within an active generation before a new claim can take it over. |
onError | generic message | Maps upstream errors to the RUN_ERROR chunk shown to the client. |
batchSize / lingerDuration | 10 / 50ms | S2 append batching knobs. |
createS2Connection:
| option | what it controls |
|---|---|
mode | Must match the server mode. Use "session" for chat sessions. |
sendUrl | POST endpoint that starts generation. |
subscribeUrl | GET endpoint that streams chunks. Required for session; optional for single-use and shared. |
headers / credentials | Auth and fetch options for both send and subscribe requests. |
body | Extra fields merged into the POST request body. |
fetch | Custom fetch implementation for tests or framework integrations. |
Example
A runnable TanStack Start chat app demonstrating session replay is available in the SDK repo:examples/tanstack-ai-chat.
