Repository navigation
v0.6.0
This release adds into: read a download — or a cache hit — straight into a buffer you allocated and get a prefix view of it back, so a sequential loop over dozens of large shards reuses one buffer instead of allocating one per call. It is additive: no API is removed or changed and no migration is needed. One caveat: the JavaScript floor moves up to Baseline 2024 (see below).
✨ Features
into— caller-owned buffers (FetchBytesOptions.into, and per file asHfFileSpec.intoforfetchHfFile/fetchHfFiles— one buffer per spec, sincefetchHfFilesruns in parallel). A network download is written into your buffer instead of a freshly allocated one, and a cache hit is read out of Cache Storage through its body stream into it instead of being materialized witharrayBuffer(). The return value isinto.subarray(0, n); the buffer stays yours, so the view (and the raw bytes handed tovalidate/decode) is only valid until the next write into the same buffer. Withdecode, the buffer holds the stored form and the decoded form is returned separately. Withinto,expectedBytesis no longer an allocation hint: what remains is the pre-check that rejects a declared length the buffer cannot hold.prefetchUrl/prefetchHfFilehave no use forinto(they never hold the bytes).- Too-small buffers fail loud instead of degrading. A network download is cancelled at the chunk that overflows and nothing is cached; a cache hit throws but keeps the entry (it is neither corruption nor a cache I/O failure, so it neither self-heals nor falls back to the network); an
expectedByteslarger than the buffer throws before any request is made — in the HuggingFace layer that includes the revision-resolution request. The error is a plainErrorwithname === "IntoCapacityError"; after any throw the buffer's contents are undefined. - Concurrent use of one buffer is rejected at the entrance. Passing the same buffer to two in-flight calls (for example the same
intoon severalHfFileSpecs of a parallelfetchHfFiles) throws at the cache layer's entry point, before that call's own download starts, because interleaved writes could otherwise store bytes that do not match the recorded hash. Reuse a buffer sequentially; aSharedArrayBuffer-backed view is rejected at the same point. - Single-flight keeps caller-owned buffers private. A caller that joins an in-flight download never receives the leader's
intobuffer: when the leader usedintoand someone has joined, the leader copies the stored bytes once before sharing them — so that flight peaks at twice the size, and a failure to allocate that copy throws even though the download, verification and cache write all succeeded (the retry is a cache hit). A joiner with its ownintogets the bytes copied into it. Nothing is copied for sharing when nobody joins. Note that a capacity failure on the leader's buffer fails the whole flight, joiners withoutintoincluded. - sha256 verification of materialized bytes now hands partial views straight to WebCrypto (only a
SharedArrayBuffer-backed view is copied first), so anintoprefix view is hashed without a JS-level copy. WebCrypto still takes its own copy internally, as the spec requires.
⚡ Runtime floor
- Baseline 2024 JavaScript. The single-flight path now uses
Promise.withResolvers(Safari 17.4, Chrome 119, Firefox 121, Deno 1.38, Node.js 22 and later); 0.5.0 did not use it anywhere in the library, so on a runtime below that line calls that worked in 0.5.0 will now throw. The TypeScript floor is unchanged (5.7 or later, whereUint8Arraytakes a type argument) but is now visible in the public API:intois typedUint8Array<ArrayBuffer>.
📝 Docs
- README gains a Reusing one buffer across many reads (
into) section stating whatintodoes and does not save (a joined flight's copy,body-less runtimes, Cache implementations that do not stream, WebCrypto's own copy); the design is recorded in ADR 0009 and the contract in limitations. Runtime support now records the JavaScript and TypeScript floors above.
Full Changelog: v0.5.0...v0.6.0