Getting started
Install
npm install fetchstream-jspnpm add fetchstream-jsyarn add fetchstream-jsRequires Node 18+ (global fetch) or any modern browser.
Your first stream
import { fetchStream } from "fetchstream-js";
await fetchStream("/api/users").on("$.users.*", (user) => {
console.log(user.name);
});That's it. Each user logs the moment its closing } arrives on the wire — long before the full response is downloaded.
Pick a pattern
A. Per-match callback
Use this when you want to handle items one at a time (e.g. append to a list, send each to a worker):
fetchStream("/api/products")
.on("$.products.*", (product) => renderProduct(product))
.on("$.total", (n) => setTotal(n));B. Async iteration
Same idea, but with backpressure — await render(product) blocks the parser until your handler finishes:
for await (const product of fetchStream("/api/products").iterate(
"$.products.*",
)) {
await renderProduct(product);
}C. Live mirror
When you want the whole document available to a UI as it streams in:
fetchStream("/api/data").live(({ data, chunks, done }) => {
// `data` is the same reference every call, growing in place.
// Shape matches your final JSON exactly — just incomplete until `done`.
render(data);
});In browsers the callback is automatically coalesced onto requestAnimationFrame (one delivery per frame). In Node/SSR every parser mutation produces a delivery. Override either with { throttle: 50 } or disable with { throttle: false }.
Common shapes
// flat objects
fetchStream(url).on("$.id", (id) => {
/* ... */
});
// flat arrays of primitives
fetchStream(url).on("$.tags.*", (tag) => {
/* ... */
});
// arrays of objects
fetchStream(url).on("$.users.*", (user) => {
/* ... */
});
// envelope + payload
fetchStream(url)
.on("$.status", (s) => {
/* ... */
})
.on("$.data.*", (item) => {
/* ... */
})
.on("$.errors.*", (e) => {
/* ... */
});
// deeply nested
fetchStream(url).on("$.report.sections.*.rows.*", (row) => {
/* ... */
});
// arrays at the root
fetchStream(url).on("$.*", (item) => {
/* ... */
});See Path syntax for the full specification.
Abort
fetchStream mirrors the WHATWG fetch() signature, including AbortSignal:
const ac = new AbortController();
fetchStream("/api/products", { signal: ac.signal }).on("$.products.*", render);
// Later — cancels the body reader and rejects the handle.
ac.abort();Next steps
- Why streaming? — the rationale + benchmarks
- Path syntax — what
$.users.*actually means - Live mirror mode — the React-friendly pattern
- React integration — full example with hooks