# Tasks: enterprise-browser-packer-browser **Change ID**: enterprise-browser-packer-browser **Package**: `@suaveplan/packer-browser` **Target path**: `browser/storage/packer-browser` **Prerequisite packages on Verdaccio**: `@suaveplan/packer`, `@suaveplan/crypto`, `@suaveplan/events`, `@suaveplan/error`, `@suaveplan/logger` --- ## 0. Pre-flight (non-negotiable) - [ ] 0.1 Confirm clean working tree (`git status` reports nothing) and no in-flight worktrees with uncommitted work (`git worktree list` then `git status` in each) - [ ] 0.2 If any worktrees exist under `.claude/worktrees/`, account for each one: still-active agent, work-pending-merge, or stale-and-prune. Stale worktrees MUST be removed (`git worktree remove`) before opening a new one — code that has been lost twice on main is the failure mode this guards against. - [ ] 0.3 Confirm the package set in `MANIFEST.md` matches `find packages -maxdepth 3 -name package.json` count. Drift here means a prior change archived without regenerating the manifest. ## 1. Scaffold - [ ] Create directory tree per `proposal.md`. - [ ] `package.json` v0.0.0, `"sideEffects": false`. - `dependencies`: `@suaveplan/packer workspace:^`, `@suaveplan/crypto workspace:^`, `@suaveplan/events workspace:^`, `@suaveplan/error workspace:^`, `@suaveplan/types workspace:^`, `@suaveplan/logger workspace:^`, `@suaveplan/schema-registry workspace:^`, `zod catalog:forms`, `@opentelemetry/api catalog:observability`, `tslib catalog:build` - `devDependencies`: `vitest catalog:testing`, `@vitest/coverage-istanbul catalog:testing`, `@playwright/test catalog:testing`, `@suaveplan/testing workspace:^` - Subpath exports: `"."`, `"./manager"`, `"./service-worker"`, `"./utils"`, `"./singleton"` - [ ] `tsconfig.json`, `vitest.config.ts` (pool: forks, `fileParallelism: false`). --- ## 2. Error codes - [ ] `PACKED_RESOURCE_NOT_FOUND`, `SW_REGISTRATION_FAILED`, `PACKED_ARCHIVE_SIGNATURE_INVALID`. - [ ] `registerPackerBrowserErrorCodes()` — call eagerly in `src/index.ts`. --- ## 3. Types (`src/types/types/`) - [ ] `PackedResource { path: string; mimeType: string; size: number; blob: Blob }`. - [ ] `PackedResourceType = 'image' | 'audio' | 'font' | 'video' | 'other'`. - [ ] `ManagerOptions`, `SwOptions`, `SwCacheStatus`, `PackedResourceManagerMetrics`. - [ ] Write `types.md`. --- ## 4. Cache module (`src/manager/cache/`) - [ ] `cache.ts` — LRU blob cache: `get(path)`, `set(path, blob)`, `evict()`, `clear()`, `metrics()`. - [ ] Configurable `maxEntries` and `maxBytes`; eviction on exceed. - [ ] Write `cache.test.ts` (CRUD, LRU eviction order, byte-limit eviction). Write `cache.md`. --- ## 5. Loader module (`src/manager/loader/`) - [ ] `loader.ts` — fetch archive URL, decode via `@suaveplan/packer`, verify manifest signature when `manifestSignature` provided. - [ ] On invalid signature throw `PACKED_ARCHIVE_SIGNATURE_INVALID` via `@suaveplan/crypto` ed25519 verify. - [ ] Write `loader.test.ts` (fetch success, decode, signature valid, signature invalid). Write `loader.md`. --- ## 6. Manager module (`src/manager/manager/`) - [ ] `manager.ts` — LRU orchestrator composing `cache.ts` + `loader.ts`. - [ ] `fetch(assetPath): Promise` — cache hit fast path; cache miss → loader → cache insert. - [ ] `release(assetPath)`, `clear()`, `getMetrics(): PackedResourceManagerMetrics`. - [ ] Wire OTel counters: `packer.resource_fetch_total`, `packer.cache_hits_total`, `packer.cache_miss_total`; histogram `packer.decode_ms`. - [ ] Write `manager.test.ts` (fetch hit, fetch miss, release, clear, metrics). Write `manager.md`. --- ## 7. `createPackedResourceManager` factory (`src/manager/`) - [ ] `index.ts` re-exporting `createPackedResourceManager(options: ManagerOptions): PackedResourceManager`. - [ ] Factory validates options with Zod; throws typed error on invalid config. --- ## 8. Service Worker (`src/service-worker/service-worker/`) - [ ] `service-worker.ts` — `ServiceWorkerGlobalScope` handler: intercept fetch, match against packed archive cache, respond or pass through. - [ ] Write `service-worker.test.ts` via a `ServiceWorkerGlobalScope` shim (no `vi.stubGlobal`). - [ ] Write `service-worker.md`. --- ## 9. SW utilities (`src/utils/register-service-worker/`) - [ ] `register-service-worker.ts` — `registerPackedResourceServiceWorker(options?)`, `unregisterPackedResourceServiceWorker()`, `clearServiceWorkerCache()`, `getServiceWorkerCacheStatus()`. - [ ] Throw `SW_REGISTRATION_FAILED` on registration failure. - [ ] Write `register-service-worker.test.ts`. Write `register-service-worker.md`. --- ## 10. Singleton subpath (`src/singleton/`) - [ ] `index.ts` — `export const packedResourceManager = createPackedResourceManager(defaultOptions)` for backward compat. --- ## 11. Integration test (`tests/integration.test.ts`) - [ ] Fetch multiple assets from a packed archive. - [ ] Verify LRU eviction under quota pressure. - [ ] Verify signature rejection path. --- ## 12. Playwright E2E (`e2e/packer-browser.spec.ts`) - [ ] Chromium, Firefox, WebKit browser contexts. - [ ] Assert SW intercepts packed asset requests and serves blobs. - [ ] Assert SW cache invalidation after `clearServiceWorkerCache()`. --- ## 13. Docs + verify - [ ] Write `.md` per module (≥200 words, API reference, examples). - [ ] Write `README.md` with subpath table, manifest-verification guide, SW setup. - [ ] `bunx turbo lint typecheck test --filter=@suaveplan/packer-browser` — green. - [ ] `bunx turbo test:coverage` — 100%. - [ ] No `@ts-expect-error` in `src/` or tests. No `vi.stubGlobal`. - [ ] Playwright E2E green on Chromium, WebKit, Firefox. - [ ] `bun scripts/publish.ts --package @suaveplan/packer-browser`. - [ ] Archive to `openspec/archive/2026-04-24-enterprise-browser-packer-browser/`.