Initial Commit

This commit is contained in:
2026-05-27 23:29:53 +01:00
commit fbc70f96e6
10000 changed files with 1102152 additions and 0 deletions

View File

@@ -0,0 +1,128 @@
# Add `@suaveplan/react-packer` — React 19 companion for `@suaveplan/packer-browser`
**Package**: `@suaveplan/react-packer`
**Status**: PROPOSED
**Type**: new-package
- **Design**: ./design.md
- **Spec delta**: ./specs/react-packer/spec.md
## Why
`@suaveplan/packer-browser` (genesis Cluster A) ships the manager, cache,
loader, signature verification, and Service-Worker interceptor with **no
React runtime dep**. Upstream `packer-browser@1.0.17` carried the React
hooks (`usePackedResource`, `usePackedImage`, `usePackedAudio`,
`usePackedVideo`, `usePackedFont`) inside the same package, forcing every
non-React consumer (server bundles, R3F apps that do their own loading,
Web-Worker scripts) to ship React via transitive dependency. Upstream
`enterprise/packer-browser.md` §3.3 specifically calls for splitting the
hooks into a React companion package; that split has been deferred to
`@suaveplan/react-packer`, this change.
This package provides the hooks at genesis quality — `AbortSignal` on
every action, `MessageResolver` plumbed through, `PackedResourceProvider`
React context for explicit dependency injection of a
`PackedResourceManager`, sensible fallback to the
`@suaveplan/packer-browser/singleton` for adopters that want zero-config,
and 100/100/100/100 coverage against a real (non-mock) manager backed by
real `Response` + `Blob` fixtures.
## What changes
This is a brand-new package — every export is additive. No changes to
`@suaveplan/packer-browser`'s surface.
- ADDED: `usePackedResource(packedUrl, opts?)` — generic hook returning
`{ url, blob, loading, error, status, reload }`.
- ADDED: `usePackedImage(packedUrl, opts?)` — image-tuned defaults (cache
on, `allowedMimePrefixes = ["image/"]`).
- ADDED: `usePackedAudio(packedUrl, opts?)` — audio-tuned defaults.
- ADDED: `usePackedVideo(packedUrl, opts?)` — video-tuned defaults (cache
off — videos are large).
- ADDED: `usePackedFont(packedUrl, fontFamily?, opts?)` — injects a
`@font-face` rule and waits for `document.fonts.load`. Returns the
generic shape plus `fontLoaded: boolean`.
- ADDED: `PackedResourceProvider` — React context that supplies a
`PackedResourceManager` and (optionally) a `MessageResolver` to every
hook in its subtree.
- ADDED: `usePackedResourceManager()` — internal hook that resolves the
manager from context with a documented fallback to
`@suaveplan/packer-browser/singleton`.
- ADDED: `REACT_PACKER_CODES` + `ReactPackerError` — stable error code
registry (`LOAD_FAILED`, `FONT_LOAD_FAILED`, `ABORTED`).
## Out of scope
- Service-Worker registration UI — adopters use
`@suaveplan/packer-browser`'s lifecycle helpers directly.
- A `<PackedImage>` / `<PackedVideo>` / `<PackedAudio>` React component
wrapper. The hooks are the public surface; consumers compose their own
presentational components. This keeps the package focused on the carve
upstream `enterprise/packer-browser.md` §3.3 explicitly asked for.
## Source mapping
This change derives from upstream
`../suaveplan/packages/browser/packer-browser/src/hooks/usePackedResource.ts`
and `../suaveplan/enterprise/packer-browser.md` §3.3 ("Move React hooks
into a new React companion package"). The genesis rewrite preserves the
upstream public symbol names and per-variant defaults while bringing
every requirement to enterprise quality (no module singleton, real
`AbortSignal`, real `MessageResolver`, real error hierarchy).
| Requirement | Source lines | Notes |
|---|---|---|
| REACT-PACKER-1 (`usePackedResource`) | upstream `usePackedResource.ts` L22-L87 | Rewritten to consume injected manager; adds AbortSignal + error-code wrapping. |
| REACT-PACKER-2 (`usePackedImage`) | upstream L89-L101 | Same defaults (cache on); adds `allowedMimePrefixes`. |
| REACT-PACKER-3 (`usePackedAudio`) | upstream L103-L115 | Same defaults (cache on). |
| REACT-PACKER-4 (`usePackedVideo`) | upstream L117-L129 | Same defaults (cache off). |
| REACT-PACKER-5 (`usePackedFont`) | upstream L131-L198 | Preserves `@font-face` injection + cleanup. |
| REACT-PACKER-6 (`PackedResourceProvider`) | enterprise/packer-browser.md L42-L51 ("Move React hooks…") | Adds explicit DI surface that upstream did not have (module singleton only). |
| REACT-PACKER-7 (error hierarchy) | enterprise/packer-browser.md §63 | Standard genesis bar; upstream raised plain `Error`. |
| REACT-PACKER-8 (singleton fallback) | enterprise/packer-browser.md L51 | Adopters who omit `<PackedResourceProvider>` fall back to `@suaveplan/packer-browser/singleton`. |
### Requirements with no source line
None — every requirement either ports an upstream behaviour or implements
an enterprise gap explicitly named in `enterprise/packer-browser.md`.
## Verification approach
Every requirement carries a `**Verified by:**` line pointing at a concrete
`it(...)` title in the planned test files.
- `src/hooks/use-packed-resource/use-packed-resource.test.tsx` — covers
REACT-PACKER-1 (loading, success, error, reload, abort on unmount,
abort on URL change, signal propagation).
- `src/hooks/use-packed-image/use-packed-image.test.tsx` — covers
REACT-PACKER-2 (`allowedMimePrefixes` enforcement, image defaults).
- `src/hooks/use-packed-audio/use-packed-audio.test.tsx` — covers
REACT-PACKER-3 (audio defaults).
- `src/hooks/use-packed-video/use-packed-video.test.tsx` — covers
REACT-PACKER-4 (video defaults including cache off).
- `src/hooks/use-packed-font/use-packed-font.test.tsx` — covers
REACT-PACKER-5 (`@font-face` injection, cleanup, `fontLoaded` flag,
`document.fonts.load` failure path).
- `src/provider/packed-resource-provider/packed-resource-provider.test.tsx`
— covers REACT-PACKER-6 + REACT-PACKER-8 (context wiring, singleton
fallback when no provider, `MessageResolver` propagation).
- `src/error-codes/error-codes.test.ts` — covers REACT-PACKER-7 (code
registry, `ReactPackerError.is(...)` brand check).
## Migration impact
None — additive only. `@suaveplan/packer-browser` is not modified.
Consumers that previously imported hooks from upstream `packer-browser`
(none on genesis — packer-browser shipped without hooks per its own
proposal) migrate by adding `@suaveplan/react-packer` as a dep and
importing from there.
## Impact
### Affected dependents
Run `bunx turbo ls --filter=...@suaveplan/react-packer` to enumerate.
This is a new package with zero existing dependents on genesis:
- No dependents (verified by `grep -rln "@suaveplan/react-packer" packages/ apps/ 2>/dev/null` returning no matches at proposal time).