3.2 KiB
3.2 KiB
round-trip (streamToUint8Array / uint8ArrayToStream)
(no submodules)
Purpose
The round-trip module provides the two halves of byte ↔ stream conversion that
underpin most file/network adapters in @suaveplan/streams. uint8ArrayToStream
turns an in-memory buffer into a backpressure-respecting ReadableStream, and
streamToUint8Array drains an arbitrary readable stream back into a single
Uint8Array. They are deliberately co-located because most consumers reach for
both in the same call path (e.g. test fixtures that load a buffer, push it
through a transform pipeline, then re-collect the output for assertion).
The drain side is AbortSignal-aware and rejects with StreamAbortedError
when cancellation is requested, cancelling the underlying reader so upstream
producers can release resources promptly.
Features
uint8ArrayToStream: configurable chunk size; defaults to a single emission.- Per-chunk copy emission so consumers can safely retain references.
streamToUint8Array: total-length pre-sum, single allocation for output.- Honours
AbortSignalboth before and during read; cancels the reader. - Pure WHATWG Streams API — no Node-only or DOM-only deps.
Usage: Basic Example
import {
streamToUint8Array,
uint8ArrayToStream,
} from "@suaveplan/streams/utils/stream/round-trip/round-trip";
const original = new Uint8Array([1, 2, 3, 4]);
const drained = await streamToUint8Array(uint8ArrayToStream(original));
// drained equals original
Usage: Advanced Example
import {
streamToUint8Array,
uint8ArrayToStream,
} from "@suaveplan/streams/utils/stream/round-trip/round-trip";
async function pipeWithTimeout(
data: Uint8Array,
transform: TransformStream<Uint8Array, Uint8Array>,
ms: number
): Promise<Uint8Array> {
const ac = new AbortController();
const timer = setTimeout(() => ac.abort(new Error("timeout")), ms);
try {
const piped = uint8ArrayToStream(data, { chunkSize: 4096 }).pipeThrough(
transform
);
return await streamToUint8Array(piped, ac.signal);
} finally {
clearTimeout(timer);
}
}
API Reference
uint8ArrayToStream(data, options?)
data: Uint8Array— bytes to emit.options.chunkSize?: number— bytes per chunk; defaults to entire array.- Returns —
ReadableStream<Uint8Array>that closes after the last chunk.
streamToUint8Array(stream, signal?)
stream: ReadableStream<Uint8Array>— source stream.signal?: AbortSignal— cancellation token; cancelling rejects the call withStreamAbortedErrorand cancels the reader.- Returns —
Promise<Uint8Array>of the concatenated bytes. - Throws —
StreamAbortedErroron cancellation.
Implementation Notes
- The drain pre-collects chunks and sums lengths so the final
Uint8Arrayis allocated exactly once — avoids the quadratic-copy trap of repeatedly appending into a growing buffer. - Each emission of
uint8ArrayToStreamis a copy viadata.slice, so the sourceUint8Arraymay be mutated independently after the stream is built. - The abort listener is removed in
finallyto keep the signal listener count bounded across long-lived signals.