first commit
This commit is contained in:
@@ -0,0 +1,91 @@
|
||||
# round-trip (streamToUint8Array / uint8ArrayToStream)
|
||||
|
||||
<!-- begin:auto-docs -->
|
||||
_(no submodules)_
|
||||
<!-- end:auto-docs -->
|
||||
## 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 `AbortSignal` both before and during read; cancels the reader.
|
||||
- Pure WHATWG Streams API — no Node-only or DOM-only deps.
|
||||
|
||||
## Usage: Basic Example
|
||||
|
||||
```ts
|
||||
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
|
||||
|
||||
```ts
|
||||
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
|
||||
with `StreamAbortedError` and cancels the reader.
|
||||
- **Returns** — `Promise<Uint8Array>` of the concatenated bytes.
|
||||
- **Throws** — `StreamAbortedError` on cancellation.
|
||||
|
||||
## Implementation Notes
|
||||
|
||||
- The drain pre-collects chunks and sums lengths so the final `Uint8Array` is
|
||||
allocated exactly once — avoids the quadratic-copy trap of repeatedly
|
||||
appending into a growing buffer.
|
||||
- Each emission of `uint8ArrayToStream` is a copy via `data.slice`, so the
|
||||
source `Uint8Array` may be mutated independently after the stream is built.
|
||||
- The abort listener is removed in `finally` to keep the signal listener count
|
||||
bounded across long-lived signals.
|
||||
Reference in New Issue
Block a user