68 lines
2.1 KiB
Markdown
68 lines
2.1 KiB
Markdown
# `range/range-stream-parse.ts`
|
|
|
|
## Purpose
|
|
|
|
Streams an HTTP response body line-by-line through a `TextDecoderStream`
|
|
and a newline framer, yielding `{ suffix, count }` records as soon as
|
|
each line crosses a complete byte boundary. The parser deliberately
|
|
never calls `Response.text()` and never collects the body into a single
|
|
string buffer, so even a 30 KiB `Add-Padding` response is processed in
|
|
bounded memory. Mid-flight `AbortSignal` is honoured between chunks.
|
|
|
|
## Features
|
|
|
|
- Async generator interface — drop in to `for await` loops.
|
|
- CRLF and LF newlines both work; trailing line without newline is
|
|
emitted; empty lines are skipped.
|
|
- Per-line validation delegated to `parseRangeLine` so strict-mode
|
|
rejection happens at first-fault.
|
|
- AbortSignal threading: pre-aborted and mid-flight aborts both throw
|
|
`HIBP.ABORTED` and the underlying reader is released in a `finally`
|
|
guard.
|
|
|
|
## Usage: Basic Example
|
|
|
|
```ts
|
|
import { streamParseRangeBody } from "@suaveplan/hibp";
|
|
|
|
for await (const line of streamParseRangeBody(response.body!, { strict: true })) {
|
|
if (line.suffix === expected) /* ... */;
|
|
}
|
|
```
|
|
|
|
## Usage: Advanced Example
|
|
|
|
```ts
|
|
import { streamParseRangeBody } from "@suaveplan/hibp";
|
|
|
|
const ac = new AbortController();
|
|
const iter = streamParseRangeBody(response.body!, {
|
|
strict: false,
|
|
signal: ac.signal,
|
|
});
|
|
|
|
setTimeout(() => ac.abort(), 100);
|
|
|
|
try {
|
|
for await (const _line of iter) { /* ... */ }
|
|
} catch (err) {
|
|
if ((err as { code?: string }).code === "HIBP.ABORTED") {
|
|
// user cancelled
|
|
}
|
|
}
|
|
```
|
|
|
|
## API Reference
|
|
|
|
- `streamParseRangeBody(body, { strict, signal? }): AsyncGenerator<RangeLine>`.
|
|
|
|
## Implementation Notes
|
|
|
|
The `TextDecoderStream` typings model the writable side as
|
|
`BufferSource`, which trips the structural `pipeThrough` constraint, so
|
|
the parser casts at the boundary. Calls to `Response.text()` are
|
|
forbidden by the spec — the test suite asserts zero invocations. The
|
|
generator's `finally` clause releases the underlying reader even when
|
|
the consumer breaks out early, preventing leaked readable streams when
|
|
a caller chooses to short-circuit on the first match.
|