# `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`. ## 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.