Files
skills/docs/persistence/storage/storage-http/src/range/range.md
2026-05-29 08:20:56 +01:00

3.5 KiB

range

(no submodules)

Purpose

Encodes HTTP Range semantics for HttpStorage.getPartial. Builds the request header from (offset, length) and interprets the response in the three documented shapes: 206 Partial Content (happy path — body returned verbatim), 200 OK (origin ignored the Range — body sliced client-side and the fallback is flagged so the caller can emit a counter), and 416 Range Not Satisfiable (request beyond EOF — mapped to STORAGE_HTTP.NOT_FOUND).

Without this module, every adapter consumer would have to re-implement the same disambiguation. Keeping it isolated also lets tests pin range behaviour without spinning up the full HttpStorage.

Features

  • buildRangeHeader(offset, length) — validates integer non-negativity / positivity, returns bytes=<o>-<o+l-1>.
  • consumeRangeResponse(response, offset, length, url) — distinguishes 206 / 200 / 416 / other, returns { bytes, fellBack }.
  • Programmer-error inputs throw STORAGE_HTTP.INVALID_OPTIONS so they surface in development, not as cryptic upstream failures.

Usage: Basic

import { buildRangeHeader, consumeRangeResponse } from "@suaveplan/storage-http";

const header = buildRangeHeader(0, 1024); // "bytes=0-1023"
const response = await fetch(url, { headers: { Range: header } });
const { bytes, fellBack } = await consumeRangeResponse(response, 0, 1024, url);

Usage: Advanced

import { buildRangeHeader, consumeRangeResponse } from "@suaveplan/storage-http";

async function readSlice(url: string, offset: number, length: number) {
    const response = await fetch(url, { headers: { Range: buildRangeHeader(offset, length) } });
    const { bytes, fellBack } = await consumeRangeResponse(response, offset, length, url);
    if (fellBack) operatorLog.warn({ url }, "origin ignored Range — full body returned");
    return bytes;
}

API Reference

buildRangeHeader(offset: number, length: number): string

Returns "bytes=<offset>-<offset+length-1>". Throws StorageHttpError(INVALID_OPTIONS) when offset is not a non-negative integer or length is not a positive integer.

interface RangeOutcome

{ bytes: Uint8Array; fellBack: boolean } — fellBack is true only when the origin returned 200 OK to a Range request and the slice was performed client-side.

consumeRangeResponse(response, offset, length, url): Promise<RangeOutcome>

  • 206 → returns the body verbatim with fellBack = false.
  • 200 → consumes the full body, slices [offset, offset + length), returns with fellBack = true.
  • 416 → throws StorageHttpError(NOT_FOUND) with httpStatus: 416.
  • other → throws StorageHttpError(UPSTREAM_ERROR) with the observed status.

Implementation Notes

  • The Content-Range response header is intentionally NOT parsed here — it carries the total object size, which is useful for cache metadata but not required to decode the body. HttpStorage parses it in the metadata path when needed.
  • Client-side slicing on 200 uses Math.min clamps so out-of-bounds requests never throw RangeError on slice; the resulting array is simply empty if offset >= body.byteLength. The caller decides whether to treat that as "object shorter than expected" or pass it through.
  • 416 mapping to NOT_FOUND is a deliberate simplification: distinguishing "object missing" from "range past EOF on an existing object" requires a HEAD round-trip the caller already has cheaper alternatives for (e.g. exists() or attaching If-Range to disambiguate cache vs miss).