# Capability Spec Delta: react-packer (add-react-packer) **Package**: `@suaveplan/react-packer` **Status**: PROPOSED > Every requirement below carries a `**Verified by:**` line at authoring time. ## ADDED Requirements ### Requirement: REACT-PACKER-1 — `usePackedResource` lifecycle The package SHALL export `usePackedResource(packedUrl, options?)`, a React hook that resolves a `PackedResourceManager` from context (or the singleton fallback), invokes `manager.load(url, opts)`, and returns `{ url, loading, error, status, reload }`. The hook MUST honour `AbortSignal`: it merges any caller-supplied signal with its own internal `AbortController`, aborts on unmount, aborts on `packedUrl` change, and aborts on `reload()`. On a `null`/`undefined` `packedUrl` the hook MUST settle on `status = "idle"` without invoking the manager. #### Scenario: nullable packed URL produces idle state - **WHEN** the hook is mounted with `packedUrl = null` - **THEN** `status === "idle"`, `url === null`, `loading === false`, and `manager.load` is never called #### Scenario: success transitions loading → success - **WHEN** the manager resolves a real Blob URL for the given packed URL - **THEN** the hook transitions `loading` (true) → `success`, exposes the Blob `url`, and clears any prior `error` #### Scenario: pre-aborted signal short-circuits with REACT_PACKER_ABORTED - **WHEN** the caller passes a pre-aborted `AbortSignal` - **THEN** the hook surfaces `status = "error"` with `error.code === "REACT_PACKER_ABORTED"` and never calls the manager #### Scenario: unmount releases the cached resource - **WHEN** a successful load completes and the component unmounts - **THEN** `manager.release(url, opts.verifyKey)` runs exactly once and no `setState` warning fires **Verified by:** `src/hooks/use-packed-resource/use-packed-resource.test.tsx::"is idle when packedUrl is null"` AND `src/hooks/use-packed-resource/use-packed-resource.test.tsx::"transitions loading then success on a real manager"` AND `src/hooks/use-packed-resource/use-packed-resource.test.tsx::"surfaces REACT_PACKER_ABORTED on a pre-aborted signal"` AND `src/hooks/use-packed-resource/use-packed-resource.test.tsx::"releases the cached entry on unmount"` AND `src/hooks/use-packed-resource/use-packed-resource.test.tsx::"reload() re-runs the loader and resets state"` AND `src/hooks/use-packed-resource/use-packed-resource.test.tsx::"changing packedUrl aborts the prior in-flight load"` AND `src/hooks/use-packed-resource/use-packed-resource.test.tsx::"wraps a manager failure as REACT_PACKER_LOAD_FAILED"` --- ### Requirement: REACT-PACKER-2 — `usePackedImage` with image-tuned defaults The package SHALL export `usePackedImage(packedUrl, options?)` which delegates to `usePackedResource` with `cache: true` and `allowedMimePrefixes: ["image/"]` unless the caller overrides them. The hook MUST preserve the full `UsePackedResourceReturn` shape. #### Scenario: image hook applies image MIME allow-list - **WHEN** the hook is mounted and the underlying manager call inspects options - **THEN** the call includes `allowedMimePrefixes: ["image/"]` and `cache: true` #### Scenario: caller override wins over defaults - **WHEN** the caller passes `{ cache: false }` - **THEN** the manager call receives `cache: false` **Verified by:** `src/hooks/use-packed-image/use-packed-image.test.tsx::"loads an image-tuned packed resource"` AND `src/hooks/use-packed-image/use-packed-image.test.tsx::"caller can override the cache default"` --- ### Requirement: REACT-PACKER-3 — `usePackedAudio` with audio-tuned defaults The package SHALL export `usePackedAudio(packedUrl, options?)` which delegates to `usePackedResource` with `cache: true` and `allowedMimePrefixes: ["audio/"]` unless overridden. #### Scenario: audio hook applies audio MIME allow-list - **WHEN** the hook resolves a packed URL - **THEN** the manager receives `allowedMimePrefixes: ["audio/"]` and `cache: true` **Verified by:** `src/hooks/use-packed-audio/use-packed-audio.test.tsx::"loads an audio-tuned packed resource"` AND `src/hooks/use-packed-audio/use-packed-audio.test.tsx::"forwards caller-supplied verifyKey to the manager"` --- ### Requirement: REACT-PACKER-4 — `usePackedVideo` with video-tuned defaults The package SHALL export `usePackedVideo(packedUrl, options?)` which delegates to `usePackedResource` with `cache: false` (videos are large and dominate cache budgets) and `allowedMimePrefixes: ["video/"]` unless overridden. #### Scenario: video hook opts out of caching by default - **WHEN** the hook resolves a packed URL with no caller options - **THEN** the manager receives `cache: false` and `allowedMimePrefixes: ["video/"]` **Verified by:** `src/hooks/use-packed-video/use-packed-video.test.tsx::"loads a video-tuned packed resource without caching"` AND `src/hooks/use-packed-video/use-packed-video.test.tsx::"caller can opt back into caching"` --- ### Requirement: REACT-PACKER-5 — `usePackedFont` injects @font-face The package SHALL export `usePackedFont(packedUrl, fontFamily?, options?)` which delegates to `usePackedResource` with font-tuned defaults, injects a `@font-face` stylesheet (`