3.4 KiB
3.4 KiB
loader-stream
Purpose
Progressive entry-by-entry unpack helper that powers
PackedResourceLoader.loadStream. Callers pass a list of packed-archive
URLs (or StreamLoadEntry records with per-entry options) and consume
the returned AsyncIterableIterator<StreamedLoadedResource>. Each entry
is dispatched through the standard load pipeline (fetch → maybe-decrypt
→ verify → unpack) in parallel; the iterator yields each result in
completion order so a slow fetch can't block a fast neighbour.
Features
- Completion-order yielding —
Promise.raceover outstanding entries so the consumer'sfor-awaitloop wakes up as soon as any entry finishes. - Per-entry options merge —
entry.optionsoverrides the iterator-leveloptsso a single stream can mix unencrypted and encrypted entries, differentverifyKeys, or different mime allow-lists. AbortSignalhonoured at every yield. Pre-aborted signal short- circuits the iterator without issuing a fetch; a signal that fires mid-stream throws on the nextnext()call.- Coexists with the batch
loadpath — both call into the same loader pipeline so behaviour (signature verification, retry policy, OTel metrics) is identical.
Usage: Basic Example
import { createPackedResourceManager } from "@suaveplan/packer-browser";
const manager = createPackedResourceManager();
const urls = ["/a.packed", "/b.packed", "/c.packed"];
for await (const entry of manager.getLoader().loadStream(urls)) {
console.info("decoded", entry.inputUrl, "→", entry.url);
}
Usage: Advanced Example
import { MemoryKeyring, createPackedResourceManager } from "@suaveplan/packer-browser";
const keyring = new MemoryKeyring({ "tenant-a": new Uint8Array(32).fill(0x11) });
const ac = new AbortController();
const manager = createPackedResourceManager();
const stream = manager.getLoader().loadStream(
[
{ url: "/asset-a.packed" },
{ url: "/asset-b.packed", options: { keyring } },
{ url: "/asset-c.packed", options: { allowedMimePrefixes: ["image/"] } },
],
{ signal: ac.signal }
);
setTimeout(() => ac.abort(), 5000);
for await (const entry of stream) {
consume(entry);
}
API Reference
loadStream(loader, inputs, opts?)— free function used byPackedResourceLoader.loadStream. Not part of the package's public barrel.StreamLoadEntry—{ url: string; options?: PackedResourceLoadOptions }.StreamedLoadedResource—LoadedResource & { inputUrl: string }.
Implementation Notes
- The
Promise.racestrategy is bounded — N outstanding fetches at all times — so callers that want a sliding-window concurrency limit should chunk their input list externally. A built-in concurrency cap is intentionally out of scope; the loader'swithRetryalready smooths transient failures and@suaveplan/streamscarries the general windowing primitives for callers that need them. - A pending entry's
.promiseis created eagerly whenloadStreamis invoked, not lazily onnext(). That matches the audit's "stream sub-resources as bytes arrive" requirement: by starting every fetch immediately, the iterator yields the first completer with the lowest possible latency. - The signal check inside the
whileloop runs before everyawait Promise.race(...)so a mid-stream abort terminates cleanly without leaving the iterator suspended on an indefinite race.