Initial Commit
This commit is contained in:
@@ -0,0 +1,127 @@
|
||||
# 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 each `LoadedResource` as soon as its packed bytes are
|
||||
decoded, honouring `AbortSignal` at 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 returning `Response` with `206`/`200`/`412`/`416`
|
||||
semantics (`Content-Range`, `Accept-Ranges: bytes`, `Content-Length`,
|
||||
`If-Range` ETag handling).
|
||||
- ADDED: `RunServiceWorkerOptions.rangeThreshold` (default `262144` —
|
||||
256 KiB) — fetch handler emits a `206` for matching requests whose cached
|
||||
body exceeds the threshold; multi-range requests fall back to `416`.
|
||||
- ADDED: `KeyringProvider` contract — `resolveKey(keyId): Promise<Uint8Array>`
|
||||
with a default `emptyKeyring()` factory that rejects all key ids.
|
||||
- ADDED: `encodeEncryptedArchive(plaintext, keyId, key, nonce, opts?)` /
|
||||
`decodeEncryptedArchiveHeader(bytes)` — wire format with stable
|
||||
`SP-ENC1\x01` magic 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 the `SP-ENC1` prefix, 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`'s
|
||||
`entryDigestBlake3`/`merkleRootBlake3`.
|
||||
- ADDED: `buildContentAddressedUrl(prefix, hash, ext?)` — content-addressed
|
||||
URL builder; defaults to `/packed/<hash>.bundle.asset`.
|
||||
- ADDED: `RunServiceWorkerOptions.contentAddressed` (default `true`) +
|
||||
`RunServiceWorkerOptions.legacyUrlPattern` — when content-addressed mode
|
||||
is on, SW caches under the hash; the legacy `/packed/<name>` pattern is
|
||||
still recognised when `legacyUrlPattern` is supplied.
|
||||
- ADDED: `cleanupOutdatedCaches(scope, prefix, keep)` — SW helper that
|
||||
deletes every cache whose name starts with `prefix` and is not in `keep`;
|
||||
invoked from the `activate` handler 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 injected `FlagProvider` so 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.
|
||||
Reference in New Issue
Block a user