Initial Commit

This commit is contained in:
2026-05-27 23:47:53 +01:00
parent fbc70f96e6
commit 9b28db724f
18103 changed files with 1600554 additions and 0 deletions

View File

@@ -0,0 +1,94 @@
# range-response
<!-- begin:auto-docs -->
_(no submodules)_
<!-- end:auto-docs -->
## Purpose
RFC 7233 §2.1 single-range `Response` builder for packed-resource
delivery from the Service Worker. Browsers ask for ranges when streaming
audio, scrubbing video, or resuming a download — this module is the
helper the SW invokes to serve those ranges out of the already-decoded
bytes it cached. The helper keeps SW code small: parse, branch, build
`Response`. No state, no allocations beyond the response body slice.
## Features
- Single-range `bytes=<start>-<end>` parsing with normalised
open-ended (`bytes=100-`) and suffix (`bytes=-100`) forms.
- `206 Partial Content` with `Content-Range`, `Accept-Ranges: bytes`,
and `Content-Length` headers when the request is a valid single
range above the configured threshold.
- `200 OK` with `Accept-Ranges: bytes` for unranged requests or bodies
below the threshold (default 256 KiB).
- `416 Range Not Satisfiable` for multi-range or malformed ranges, with
a `Content-Range: bytes */<total>` header per spec.
- `412 Precondition Failed` for `If-Range` ETag mismatches.
- `Accept-Ranges: bytes` advertised on every successful response so
clients know the resource supports ranges going forward.
## Usage: Basic Example
```ts
import { serveRangeResponse } from "@suaveplan/packer-browser";
self.addEventListener("fetch", (event) => {
const req = (event as FetchEvent).request;
const body = getCachedBody(req); // application-specific
(event as FetchEvent).respondWith(
serveRangeResponse(req, body, { contentType: "audio/mpeg" })
);
});
```
## Usage: Advanced Example
```ts
import {
serveRangeResponse,
DEFAULT_RANGE_THRESHOLD_BYTES,
} from "@suaveplan/packer-browser";
function buildResponse(req: Request, body: Uint8Array, etag: string) {
return serveRangeResponse(req, body, {
contentType: "video/mp4",
etag,
// Lower the threshold for small clips that benefit from range
// hopping (e.g. sprite-sheet image maps).
rangeThreshold: DEFAULT_RANGE_THRESHOLD_BYTES / 8,
});
}
```
## API Reference
- `parseRange(header: string | null, totalBytes: number): ParseRangeResult`
- Returns `null` when header is absent or non-bytes unit.
- Returns `"multi-range"` when the header carries more than one range.
- Returns `"invalid"` when malformed or out-of-bounds.
- Returns `ParsedByteRange { start, end }` otherwise.
- `serveRangeResponse(request: Request, body: Uint8Array, opts?: ServeRangeResponseOptions): Response`
- `opts.contentType` — defaults to `application/octet-stream`.
- `opts.etag` — when present, enables `If-Range` evaluation.
- `opts.rangeThreshold` — minimum body size to enable 206 (default
`262144`).
- `DEFAULT_RANGE_THRESHOLD_BYTES: number` — `262144`.
## Implementation Notes
- The 256 KiB default threshold is chosen empirically: below this size
the cost of slicing + emitting a 206 outweighs the saving for typical
consumers (a single round-trip with the full body is cheaper). The
threshold is fully configurable via `RunServiceWorkerOptions.rangeThreshold`.
- The helper does NOT support multi-range responses (`multipart/byteranges`).
RFC 7233 explicitly permits servers to return either 416 or fall back
to 200; this implementation chooses 416 to surface the limit
immediately so clients can issue single-range follow-ups.
- `If-Range` is interpreted as strong ETag equality. Date-based
`If-Range` values are treated as etags and will mismatch any
configured etag; callers that want HTTP-date semantics should set
`opts.etag` to the date string they expect.
- Every successful response advertises `Accept-Ranges: bytes`, even the
below-threshold 200, so the next client request can choose to issue a
ranged follow-up.