156 lines
5.3 KiB
Markdown
156 lines
5.3 KiB
Markdown
# 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<Blob>
|
|
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<ServiceWorkerRegistration>
|
|
function unregisterPackedResourceServiceWorker(): Promise<boolean>
|
|
function clearServiceWorkerCache(): Promise<void>
|
|
function getServiceWorkerCacheStatus(): Promise<SwCacheStatus>
|
|
|
|
// 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.
|