Files
2026-05-27 23:29:53 +01:00

5.7 KiB

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<Blob> — 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/.