# OpenSpec Change: enterprise-browser-packer-browser - **Change ID**: enterprise-browser-packer-browser - **Package**: `@suaveplan/packer-browser` - **Category**: browser - **Target path**: `browser/storage/packer-browser` - **Status**: IN PROGRESS - **Date**: 2026-04-24 - **Reference spec**: `/mnt/s/web/suaveplan/enterprise/packer-browser.md` --- ## Summary Deliver `@suaveplan/packer-browser` on the genesis branch at enterprise quality. The package provides the browser-side runtime for `@suaveplan/packer` packed media archives: a Service Worker interceptor, a `PackedResourceManager` with fetch + LRU cache, signed-manifest verification via `@suaveplan/crypto`, and SW lifecycle utilities. React hooks (`usePackedResource` etc.) move to a separate `@suaveplan/react-packer` companion. No `react` runtime dep in this package. --- ## Current-state audit (genesis) Fresh build — does not exist on genesis yet. --- ## Available workspace deps on genesis | Package | Role | |---|---| | `@suaveplan/packer` (`workspace:^`) | Pack/unpack, archive format, manifest | | `@suaveplan/crypto` (`workspace:^`) | Signed-manifest verification | | `@suaveplan/events` (`workspace:^`) | Resource lifecycle events | | `@suaveplan/error` (`workspace:^`) | Typed errors | | `@suaveplan/types` (`workspace:^`) | `LoggerLike` | | `@suaveplan/logger` (`workspace:^`) | Structured logging in SW + manager | | `@suaveplan/schema-registry` (`workspace:^`) | Manifest schema registration | | `zod` (`catalog:forms`) | Manifest Zod schema | | `@opentelemetry/api` (`catalog:observability`) | Fetch/cache/decode metrics | | `tslib` (`catalog:build`) | Runtime helpers | No `react` in runtime deps. Dev: `vitest`, `@vitest/coverage-istanbul`, `@playwright/test`, `@suaveplan/testing`. --- ## Preserved public API surface ```ts // Manager (no React dep) class PackedResourceManager { fetch(assetPath: string): Promise release(assetPath: string): void getMetrics(): PackedResourceManagerMetrics clear(): void } function createPackedResourceManager(options: ManagerOptions): PackedResourceManager // Singleton (backward compat at ./singleton subpath) // import { packedResourceManager } from '@suaveplan/packer-browser/singleton' // SW utilities function registerPackedResourceServiceWorker(options?: SwOptions): Promise function unregisterPackedResourceServiceWorker(): Promise function clearServiceWorkerCache(): Promise function getServiceWorkerCacheStatus(): Promise // Types interface PackedResource { path: string; mimeType: string; size: number; blob: Blob } type PackedResourceType = 'image' | 'audio' | 'font' | 'video' | 'other' ``` Subpath exports: `./manager`, `./service-worker`, `./utils`, `./singleton`. --- ## New additions for genesis ### 1. React hooks removed → `@suaveplan/react-packer` `usePackedResource`, `usePackedImage`, `usePackedFont`, `usePackedVideo`, `usePackedAudio` all move to a companion package. This package has zero React runtime dep. ### 2. Signed-manifest verification `PackedResourceManager` accepts `manifestSignature` in `ManagerOptions`. Before trusting packed resources, verifies signature with `@suaveplan/crypto` ed25519; throws `PACKED_ARCHIVE_SIGNATURE_INVALID` on failure. ### 3. Split `PackedResourceManager` Into `manager.ts` (orchestration, LRU accounting), `cache.ts` (blob cache, hit/miss, eviction), `loader.ts` (fetch + decode + verify) — each ≤300 lines. ### 4. Service worker unit test `service-worker/service-worker.ts` unit-tested via a `ServiceWorkerGlobalScope` shim; no coverage gap. ### 5. `createPackedResourceManager` factory Replaces module-singleton; explicit factory. Singleton available at `./singleton` backward-compat subpath. ### 6. Error codes `PACKED_RESOURCE_NOT_FOUND`, `SW_REGISTRATION_FAILED`, `PACKED_ARCHIVE_SIGNATURE_INVALID`. ### 7. OTel metrics Counter `packer.resource_fetch_total`, counter `packer.cache_hits_total`, counter `packer.cache_miss_total`, histogram `packer.decode_ms`. --- ## File layout ```text browser/storage/packer-browser/ package.json tsconfig.json vitest.config.ts src/ index.ts error-codes.ts manager/ manager/ (manager.ts — LRU orchestrator, manager.test.ts, manager.md) cache/ (cache.ts — blob cache, cache.test.ts, cache.md) loader/ (loader.ts — fetch + decode + manifest verify, loader.test.ts, loader.md) service-worker/ service-worker/ service-worker.ts service-worker.md service-worker.test.ts (real SW scope shim) index.ts utils/ register-service-worker/ register-service-worker.ts register-service-worker.md register-service-worker.test.ts index.ts singleton/ index.ts (re-exports packedResourceManager singleton) types/ types/ types.ts types.md index.ts tests/ integration.test.ts e2e/ packer-browser.spec.ts (Chromium/Firefox/WebKit SW interception) ``` --- ## Impact **Downstream**: any browser app consuming packed media archives; `@suaveplan/react-packer` (new companion). **Breaking changes**: `usePackedResource` hooks removed from this package (relocated to companion). **Prerequisites**: `@suaveplan/packer`, `@suaveplan/crypto`, `@suaveplan/events`, `@suaveplan/error`, `@suaveplan/logger` on Verdaccio.