7.0 KiB
enhance-packer-browser-streaming — Cluster B §4 streaming enhancements
Package: @suaveplan/packer-browser
Status: PROPOSED
Type: feature
Design: not applicable (Cluster B; architecture captured inline in tasks.md and the spec delta, mirroring Cluster A).
Spec delta: ./specs/packer-browser/spec.md
Why
Cluster A (2026-05-19-add-packer-browser-core) landed the production-quality
core (PACKER-BROWSER-1..12, 153 tests, 100/100/100/100 coverage). The upstream
audit (../suaveplan/enterprise/packer-browser.md §4) enumerates ten
feature-rich enhancements; Cluster B picks up the four "streaming" items so
the package can serve real CDN-backed packed media: progressive (entry-by-
entry) unpack, Range-request support inside the Service Worker, encrypted
archives with a pluggable keyring, and content-addressed versioned archive
URLs with automatic SW cache invalidation. These four are foundational for
large media (audio/video) and multi-tenant deployments; remaining §4 items
(adaptive cache, <link rel=preload>, multi-origin SW, BackgroundFetch,
diagnostics overlay, additional subpath splits, full Playwright sweep) ship in
Cluster C.
What changes
Pure additions. Cluster A's public surface (PACKER-BROWSER-1..12) remains
intact. The Cluster A entrypoint (default . export) gains five new exports;
no removals.
- ADDED:
PackedResourceLoader.loadStream(inputs, opts?)— async iterator that yields eachLoadedResourceas soon as its packed bytes are decoded, honouringAbortSignalat every yield. - ADDED:
PackedResourceManager.loadStream(inputs, opts?)— thin pass-through that also writes each decoded entry into the cache as it arrives. - ADDED:
serveRangeResponse(request, body, opts?)— RFC 7233 §2.1 single-range helper returningResponsewith206/200/412/416semantics (Content-Range,Accept-Ranges: bytes,Content-Length,If-RangeETag handling). - ADDED:
RunServiceWorkerOptions.rangeThreshold(default262144— 256 KiB) — fetch handler emits a206for matching requests whose cached body exceeds the threshold; multi-range requests fall back to416. - ADDED:
KeyringProvidercontract —resolveKey(keyId): Promise<Uint8Array>with a defaultemptyKeyring()factory that rejects all key ids. - ADDED:
encodeEncryptedArchive(plaintext, keyId, key, nonce, opts?)/decodeEncryptedArchiveHeader(bytes)— wire format with stableSP-ENC1\x01magic prefix, framed JSON header, and AES-256-GCM ciphertext+tag. Header carries{ alg: "AES-256-GCM", keyId, nonce, aad? }. - ADDED:
PackedResourceLoaderOptions.keyring— when supplied, the loader detects theSP-ENC1prefix, resolves the key, AES-GCM decrypts, then proceeds with the standard verify+unpack pipeline. - ADDED:
PACKER_BROWSER_CODES.KEY_UNAVAILABLE(new error code) + matching i18n keys (packer-browser.error.KEY_UNAVAILABLE.no-key,packer-browser.error.KEY_UNAVAILABLE.decrypt-failed). - ADDED:
computeArchiveContentHash(entries, formatVersion)— BLAKE3 Merkle root over canonical entry digests with the format-version byte appended; reuses@suaveplan/packer'sentryDigestBlake3/merkleRootBlake3. - ADDED:
buildContentAddressedUrl(prefix, hash, ext?)— content-addressed URL builder; defaults to/packed/<hash>.bundle.asset. - ADDED:
RunServiceWorkerOptions.contentAddressed(defaulttrue) +RunServiceWorkerOptions.legacyUrlPattern— when content-addressed mode is on, SW caches under the hash; the legacy/packed/<name>pattern is still recognised whenlegacyUrlPatternis supplied. - ADDED:
cleanupOutdatedCaches(scope, prefix, keep)— SW helper that deletes every cache whose name starts withprefixand is not inkeep; invoked from theactivatehandler when content-addressed mode is on so a new manifest hash invalidates old cache entries. - ADDED:
PACKER_BROWSER_FLAGS.URL_CONTENT_ADDRESSED— registered against the manager's injectedFlagProviderso adopters can flip the URL form at runtime; default-on for new manifests, default-off honours legacy/packed/<name>requests transparently.
Out of scope
- Adaptive cache sizing via
navigator.storage.estimate()(§4.3) — Cluster C. <link rel="preload">generation (§4.5) — Cluster C.- Multi-origin SW helper (§4.7) — Cluster C.
- BackgroundFetch API integration (§4.8) — Cluster C.
- Diagnostics dev overlay (§4.9) — Cluster C.
- Subpath splits beyond Cluster A's five (
.,/manager,/service-worker,/utils,/singleton) (§4.10) — Cluster C. - Full Playwright E2E coverage across all features — Cluster C (Cluster A's Playwright stub remains; new tests are vitest unit only).
Source mapping
This change derives from ../suaveplan/enterprise/packer-browser.md.
| Requirement | Source lines | Notes |
|---|---|---|
| PACKER-BROWSER-13 — Progressive streaming unpack | L69-L69 | §4.1 progressive streaming; per-entry yield with AbortSignal honouring. |
| PACKER-BROWSER-14 — Range-request SW support | L70-L70 | §4.2 range requests; single-range 206 with Content-Range/Accept-Ranges/If-Range. |
| PACKER-BROWSER-15 — Encrypted archives with pluggable keyring | L72-L72 | §4.4 encrypted archives; pluggable KeyringProvider, AES-256-GCM via @suaveplan/crypto, new KEY_UNAVAILABLE error code. |
| PACKER-BROWSER-16 — Content-addressed versioned archive URLs | L74-L74 | §4.6 versioned archives; BLAKE3 hash over entry digests + format-version byte; cleanupOutdatedCaches from SW activate; flag-gated URL form. |
Verification approach
Every requirement carries **Verified by:** entries pointing at concrete
it(...) titles in the listed test files. Tests are co-located with
implementation (src/<feature>/<feature>.test.ts).
src/loader/loader-stream.test.ts— covers PACKER-BROWSER-13.src/manager/manager.test.ts— covers PACKER-BROWSER-13 (manager pass-through).src/range-response/range-response.test.ts— covers PACKER-BROWSER-14.src/service-worker/service-worker.test.ts— covers PACKER-BROWSER-14 (SW wiring).src/keyring/keyring.test.ts— covers PACKER-BROWSER-15.src/encrypted-archive/encrypted-archive.test.ts— covers PACKER-BROWSER-15 (wire format).src/loader/loader.test.ts— covers PACKER-BROWSER-15 (decrypt-then-unpack path).src/content-address/content-address.test.ts— covers PACKER-BROWSER-16.src/service-worker/service-worker.test.ts— covers PACKER-BROWSER-16 (cleanupOutdatedCaches).src/error-codes.test.ts— covers PACKER-BROWSER-15 (new code reachability).
Impact
Affected dependents
Run bunx turbo ls --filter=...@suaveplan/packer-browser to enumerate.
- No dependents (verified by
grep -rln "@suaveplan/packer-browser" packages/ apps/— the package is still pre-1.0 with no in-tree consumers, per Cluster A archive). All additions are additive; no consumer migration required.
Migration
Not applicable — additive changes only. Existing Cluster A consumers continue to work unchanged; the new APIs are opt-in via additional options.