Transports
SSE Transport
Server-Sent Events for real-time streaming
Installation
npm install @spoosh/transport-sseSetup
import { Spoosh } from "@spoosh/core";
import { create } from "@spoosh/react";
import { sse } from "@spoosh/transport-sse";
const spoosh = new Spoosh<ApiSchema, Error>("/api").withTransports([sse()]);
export const { useSSE } = create(spoosh);Define SSE Endpoints
SSE endpoints have an events field defining the event types:
type ApiSchema = {
notifications: {
GET: {
query: { userId: string };
events: {
message: { data: { id: string; text: string } };
alert: { data: { priority: "low" | "high"; text: string } };
};
};
};
};message is the default SSE event type. If your server sends data without an
event: field, it will be received as message.
Basic Usage
function Notifications() {
const { data, isConnected } = useSSE(
(api) => api("notifications").GET({ query: { userId: "123" } })
);
return (
<div>
<p>{isConnected ? "Listening..." : "Not connected"}</p>
{data?.message && <p>{data.message.text}</p>}
{data?.alert && <p>Alert: {data.alert.text}</p>}
</div>
);
}Parse Strategies
| Strategy | What it does | Example input → output |
|---|---|---|
"auto" | Smart detection (default) | "123" → 123, "true" → true, '{"a":1}' → {a:1} |
"json-done" | Parse JSON, ignore [DONE] | '{"text":"hi"}' → {text:"hi"}, "[DONE]" → ignored |
"json" | Always JSON | '{"a":1}' → {a:1} |
"text" | Keep as string | "hello" → "hello" |
"number" | Convert to number | "42" → 42 |
"boolean" | Convert to boolean | "true" → true |
Usage
// One strategy for all events
useSSE((api) => api("stream").GET(), { parse: "json" });
// Different strategy per event
useSSE((api) => api("stream").GET(), {
parse: {
chunk: "text", // Keep chunks as strings
metadata: "json", // Parse metadata as JSON
},
});
// Custom function
useSSE((api) => api("stream").GET(), {
parse: (data) => data.toUpperCase(),
});Accumulate Strategies
| Strategy | What it does | Example |
|---|---|---|
"replace" | New replaces old (default) | "a" then "b" → "b" |
"merge" | Smart merge based on type | "a" then "b" → "ab" |
Merge Behavior
The "merge" strategy automatically handles different types:
| prev | next | result |
|---|---|---|
string | string | concat |
number | number | replace |
string | number | replace |
number | string | replace |
object | object | shallow merge |
array | array | concat |
object | array | replace |
array | object | replace |
Usage
// One strategy for all events
useSSE((api) => api("stream").GET(), { accumulate: "merge" });
// Different strategy per event
useSSE((api) => api("stream").GET(), {
accumulate: {
chunk: "merge", // Build up text/objects
status: "replace", // Only keep latest status
},
});
// Field-specific config (merge only specific fields)
useSSE((api) => api("chat").POST(), {
accumulate: {
chunk: { text: "merge" }, // Concat text field, replace others
},
});
// Example: Field-specific accumulation in action
// Schema: events: { chunk: { data: { id: string; text: string; tokens: number } } }
//
// Event 1: { id: "1", text: "Hello", tokens: 5 }
// Event 2: { id: "2", text: " World", tokens: 6 }
//
// With { chunk: "merge" }: { id: "2", text: " World", tokens: 6 } (shallow merge)
// With { chunk: { text: "merge" } }: { id: "2", text: "Hello World", tokens: 6 } (concat text only)
// Same result using custom function:
useSSE((api) => api("chat").POST(), {
accumulate: {
chunk: (prev, curr) => ({
...curr,
text: (prev?.text || "") + curr.text,
}),
},
});Transport Options
sse({
disconnectDelay: 100,
throttle: true,
openWhenHidden: true,
});| Option | Type | Default | Description |
|---|---|---|---|
disconnectDelay | number | 100 | Delay before closing idle connections |
throttle | boolean | number | false | Batch updates |
openWhenHidden | boolean | true | Keep connection in background tabs |
Connection Options
useSSE(
(api) =>
api("notifications").GET({
headers: { Authorization: "Bearer token" },
credentials: "include",
}),
{
maxRetries: 5,
retryDelay: 2000,
}
);| Option | Type | Default | Description |
|---|---|---|---|
headers | HeadersInit | - | Request headers |
credentials | RequestCredentials | - | Include cookies ("include", "same-origin") |
maxRetries | number | 3 | How many times to retry on failure |
retryDelay | number | 1000 | Ms between retries |
Features
- Connection Pooling - Multiple components share one connection to the same URL
- Automatic Reconnection - Retries on failure with configurable
maxRetriesandretryDelay - React Strict Mode - Handles double-mount gracefully with
disconnectDelay - Background Tab Support - Keeps connection alive when tab is hidden (configurable)