Initial Commit
This commit is contained in:
102
packages/foundation/data/packer-browser/src/loader/loader.md
Normal file
102
packages/foundation/data/packer-browser/src/loader/loader.md
Normal file
@@ -0,0 +1,102 @@
|
||||
# `loader`
|
||||
|
||||
<!-- begin:auto-docs -->
|
||||
_(no submodules)_
|
||||
<!-- end:auto-docs -->
|
||||
|
||||
## Purpose
|
||||
|
||||
`loader.ts` is the fetch → verify → unpack → Blob-URL pipeline for
|
||||
packed resources. It is the only place in the package that issues a
|
||||
network request, the only place that runs `Unpacker.unpack`, and the
|
||||
only place that allocates a Blob URL. Splitting it out from
|
||||
`PackedResourceManager` keeps every concern testable in isolation —
|
||||
fetch retry, signature failure, abort propagation, and OTel histogram
|
||||
emission can each be exercised without instantiating a cache.
|
||||
|
||||
## Features
|
||||
|
||||
- `fetch` routed through `@suaveplan/retry`'s `withRetry` with a
|
||||
single-attempt default policy; callers opt in to retry by passing
|
||||
`retryConfig`.
|
||||
- `AbortSignal` honoured at every yield point — pre-fetch, post-fetch,
|
||||
post-buffer, post-verify, and pre-unpack.
|
||||
- Optional Ed25519 signature verification when `verifyKey` is supplied
|
||||
and the response carries an `X-Archive-Signature` header.
|
||||
- OTel emission: increments `packed_resource_fetch_total` on every
|
||||
attempt; records `packed_resource_decode_ms` on every successful
|
||||
pipeline run.
|
||||
- Typed error surface: every failure produces `PackerBrowserError`
|
||||
with a `PACKER_BROWSER.*` code and an i18n-resolved message.
|
||||
- Injectable `fetch` for tests — no `vi.mock` required.
|
||||
|
||||
## Usage: Basic
|
||||
|
||||
```ts
|
||||
import {
|
||||
createPackerBrowserObservability,
|
||||
PackedResourceLoader,
|
||||
resolveRuntime,
|
||||
} from "@suaveplan/packer-browser";
|
||||
|
||||
const loader = new PackedResourceLoader({
|
||||
runtime: resolveRuntime(),
|
||||
observability: createPackerBrowserObservability(),
|
||||
});
|
||||
|
||||
const { url, metadata } = await loader.load("/banner.packed");
|
||||
img.src = url;
|
||||
```
|
||||
|
||||
## Usage: Advanced
|
||||
|
||||
```ts
|
||||
import { createConstantBackoff } from "@suaveplan/retry";
|
||||
import { PackedResourceLoader } from "@suaveplan/packer-browser";
|
||||
|
||||
const controller = new AbortController();
|
||||
const loader = new PackedResourceLoader({
|
||||
runtime: resolveRuntime(),
|
||||
observability,
|
||||
fetch: async (url) => recordedFetch(url),
|
||||
});
|
||||
|
||||
const out = await loader.load("/banner.packed", {
|
||||
verifyKey: trustAnchorPublicKey,
|
||||
signal: controller.signal,
|
||||
retryConfig: {
|
||||
maxAttempts: 3,
|
||||
delay: createConstantBackoff({ delay: 250 }),
|
||||
},
|
||||
});
|
||||
```
|
||||
|
||||
## API Reference
|
||||
|
||||
- `new PackedResourceLoader(opts: PackedResourceLoaderOptions)`.
|
||||
- `loader.load(url: string, opts?: PackedResourceLoadOptions):
|
||||
Promise<LoadedResource>`.
|
||||
- Throws `RESOURCE_NOT_FOUND` for non-2xx.
|
||||
- Throws `ARCHIVE_SIGNATURE_INVALID` for a non-verifying signature
|
||||
when `verifyKey` is supplied.
|
||||
- Throws `LOAD_FAILED` when `Unpacker.unpack` rejects.
|
||||
- Throws `ABORTED` when the supplied signal fires.
|
||||
- `PackedResourceLoadOptions`:
|
||||
- `verifyChecksum?: boolean` — default `false`.
|
||||
- `verifyKey?: Uint8Array` — optional Ed25519 public key.
|
||||
- `signal?: AbortSignal` — checked at every yield.
|
||||
- `retryConfig?: RetryConfig` — default: single attempt.
|
||||
- `messageResolver?: MessageResolver` — overrides the constructor's
|
||||
resolver for this call.
|
||||
|
||||
## Implementation Notes
|
||||
|
||||
Cluster A's loader treats every fetched payload as a raw `PackedData`
|
||||
whose metadata is reconstructed from the bytes; signature verification
|
||||
covers the **archive transport** layer, while integrity verification
|
||||
is delegated to the `Unpacker` and currently skipped
|
||||
(`verifyIntegrity: false`) because Cluster A archives do not carry the
|
||||
BLAKE3 integrity bundle. Cluster B introduces the formal manifest
|
||||
decoder and re-enables integrity. The `X-Archive-Signature` header
|
||||
contract is unchanged across clusters — switching to a separate
|
||||
signature manifest is a Cluster B concern only.
|
||||
Reference in New Issue
Block a user