Stream utilities for JavaScript runtimes.
What is @rcompat/stream?#
A cross-runtime module providing utilities for working with Web Streams.
Convert ReadableStream to strings and other common stream operations.
Works consistently across Node, Deno, and Bun.
Installation#
bash
npm install @rcompat/streambash
pnpm add @rcompat/streambash
yarn add @rcompat/streambash
bun add @rcompat/streamUsage#
Convert stream to string#
js
import stream from "@rcompat/stream";
// From a ReadableStream
const readable = new ReadableStream({
start(controller) {
controller.enqueue(new TextEncoder().encode("Hello, "));
controller.enqueue(new TextEncoder().encode("World!"));
controller.close();
}
});
const text = await stream.stringify(readable);
console.log(text); // "Hello, World!"With fetch response#
js
import stream from "@rcompat/stream";
const response = await fetch("https://example.com/data.txt");
const text = await stream.stringify(response.body);
console.log(text);With file streams#
js
import stream from "@rcompat/stream";
import fs from "@rcompat/fs";
const file = fs.ref("./data.txt");
const content = await stream.stringify(file.stream());
console.log(content);API Reference#
stringify#
ts
import stream from "@rcompat/stream";
stream.stringify(readable: ReadableStream<Uint8Array>): Promise<string>;Reads all chunks from a byte ReadableStream, decodes them as streaming UTF-8
text, and concatenates them into a single string. Multibyte characters remain
intact when their bytes span chunks.
| Parameter | Type | Description |
|---|---|---|
readable |
ReadableStream<Uint8Array> |
The stream to read from |
Returns: Promise<string> — The complete stream content as a string.
Throws: If the input is not a ReadableStream instance.
How It Works#
The stringify function:
- Gets a reader from the stream via
getReader() - Reads chunks until
doneistrue - Decodes each chunk with a per-call streaming UTF-8 decoder
- Flushes the decoder and releases the reader lock
js
// Simplified implementation
const decoder = new TextDecoder();
async function stringify(stream) {
const reader = stream.getReader();
const decoder = new TextDecoder();
let output = "";
try {
for (;;) {
const { done, value } = await reader.read();
if (done) return output + decoder.decode();
output += decoder.decode(value, { stream: true });
}
} finally {
reader.releaseLock();
}
}Examples#
Process streaming API response#
js
import stream from "@rcompat/stream";
async function fetchJSON(url) {
const response = await fetch(url);
const text = await stream.stringify(response.body);
return JSON.parse(text);
}
const data = await fetchJSON("https://api.example.com/users");Read subprocess output#
js
import stream from "@rcompat/stream";
import io from "@rcompat/io";
const { stdout } = io.spawn("ls", ["-la"], { cwd: "." });
const output = await stream.stringify(stdout);
console.log(output);Collect streaming chunks#
js
import stream from "@rcompat/stream";
async function collectSSE(url) {
const response = await fetch(url);
// note: For actual SSE, you'd process chunks individually
// this example just collects everything
return await stream.stringify(response.body);
}Transform and stringify#
js
import stream from "@rcompat/stream";
const source = new ReadableStream({
start(controller) {
controller.enqueue(new TextEncoder().encode("line1\n"));
controller.enqueue(new TextEncoder().encode("line2\n"));
controller.close();
}
});
// transform stream (uppercase)
const transformed = source.pipeThrough(new TransformStream({
transform(chunk, controller) {
const text = new TextDecoder().decode(chunk);
controller.enqueue(new TextEncoder().encode(text.toUpperCase()));
}
}));
const result = await stream.stringify(transformed);
console.log(result); // "LINE1\nLINE2\n"Cross-Runtime Compatibility#
| Runtime | Supported |
|---|---|
| Node.js | ✓ |
| Deno | ✓ |
| Bun | ✓ |
No configuration required — just import and use.
License#
MIT
Contributing#
See CONTRIBUTING.md in the repository root.