first commit
This commit is contained in:
@@ -0,0 +1,67 @@
|
||||
# `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.
|
||||
Reference in New Issue
Block a user