release: v0.3.0-alpha.24
add car.streamBlocks + BlockIterator for zero-alloc CAR iteration over
large repos. strictly additive — read/readWithOptions/Car/findBlock are
unchanged. shares parser helpers (readUvarint, cidLength, verifyBlockHash)
and the CarError set with the existing path, so future CAR fixes benefit
both.
motivated by ken (semantic search over a PDS) which trips the 200k block
guard on repos like pfrazee.com (~72 MB, 248k blocks). the existing
read() path eagerly builds a StringHashMapUnmanaged indexing every CID —
~12 MB of auxiliary metadata on top of whatever the caller is doing.
streamBlocks skips the hashmap and Block[] entirely; iterator is O(1)
space beyond the input buffer, and offset() lets callers build a CID →
byte-offset index that's strictly smaller.
tests:
- round-trip equivalence against read (same block ordering + bytes)
- corruption test confirms BadBlockHash still fires through the iterator
- ZAT_STRESS=1 gated test against cached /tmp/pfrazee.car (72 MB, 248k
blocks) — asserts stream + read see identical block count, total bytes,
and cid xor. not in CI.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>