Files
skills/docs/foundation/data/packer-browser/src/content-address/content-address.md
2026-05-29 08:20:56 +01:00

104 lines
4.0 KiB
Markdown

# content-address
<!-- begin:auto-docs -->
_(no submodules)_
<!-- end:auto-docs -->
## Purpose
Content-addressed URL builder and cache-invalidation helpers for packed
archives. Each archive's canonical URL is derived from a BLAKE3 Merkle
root over its entries plus the format-version byte, so any payload or
wire-format change produces a different URL and the Service Worker can
cleanly invalidate the prior version on next install. This module is
the foundation for the `/packed/<hash>.bundle.asset` URL form and the
SW `activate`-time cache pruning.
## Features
- `computeArchiveContentHash(entries, formatVersion)` — deterministic
32-byte BLAKE3 root that mixes the format-version byte into the leaf
set so a wire-format bump is reflected in the URL.
- `contentHashHex(hash)` — lowercase-hex serialiser used by URL builders
and cache-key emitters.
- `buildContentAddressedUrl(prefix, hash, ext?)` — emits the canonical
`<prefix>/<hash>.<ext>` URL (default ext `bundle.asset` matches the
Cluster A SW pattern).
- `cleanupOutdatedCaches(caches, prefix, keep)` — Service Worker helper
that deletes every cache name with a given prefix not in `keep`.
- `PACKER_BROWSER_FLAGS.URL_CONTENT_ADDRESSED` — stable feature-flag
string registered against the manager's `FlagProvider`.
## Usage: Basic Example
```ts
import {
buildContentAddressedUrl,
computeArchiveContentHash,
contentHashHex,
} from "@suaveplan/packer-browser";
const entries = [new Uint8Array([1, 2, 3]), new Uint8Array([4, 5, 6])];
const hash = computeArchiveContentHash(entries, /* formatVersion */ 1);
const url = buildContentAddressedUrl("/packed", contentHashHex(hash));
// → "/packed/<64-hex>.bundle.asset"
```
## Usage: Advanced Example
```ts
import {
cleanupOutdatedCaches,
runPackedResourceServiceWorker,
} from "@suaveplan/packer-browser";
// Inside the Service Worker bootstrap:
runPackedResourceServiceWorker(self as unknown as ServiceWorkerGlobalScope, {
cacheName: `packed-resources-${currentHash}`,
contentAddressed: true,
});
// `cleanupOutdatedCaches` is invoked by the SW's activate handler
// automatically when `contentAddressed` is on. You can also call it
// from a maintenance message handler:
self.addEventListener("message", async (ev) => {
if ((ev as MessageEvent).data?.type === "GC") {
const deleted = await cleanupOutdatedCaches(
self.caches,
"packed-resources-",
[`packed-resources-${currentHash}`]
);
console.info("Pruned", deleted);
}
});
```
## API Reference
- `computeArchiveContentHash(entries: ReadonlyArray<Uint8Array>, formatVersion: number): Uint8Array`
Throws `RangeError` if `formatVersion` is not an integer in [0, 255].
- `contentHashHex(hash: Uint8Array): string` Throws `RangeError` on
non-32-byte input.
- `buildContentAddressedUrl(prefix: string, hash: string, ext?: string): string`
- `cleanupOutdatedCaches(caches: CacheStorageLike, prefix: string, keep: ReadonlyArray<string>): Promise<string[]>`
Returns the list of cache names that were deleted.
- `PACKER_BROWSER_FLAGS.URL_CONTENT_ADDRESSED: string` — `"packer-browser.url.content-addressed"`.
## Implementation Notes
- The format-version byte is appended as a synthetic trailing entry
rather than mixed via HKDF so the implementation stays simple and
every transformation is auditable via the existing
`entryDigestBlake3` + `merkleRootBlake3` primitives.
- `cleanupOutdatedCaches` accepts any object with `keys()` and
`delete()` methods; both the production `globalThis.caches` and the
in-memory `ShimCacheStorage` satisfy the contract, which keeps the SW
unit tests honest.
- `buildContentAddressedUrl` trims a trailing slash from the prefix so
callers can pass `/packed` or `/packed/` interchangeably.
- The Cluster A SW pattern `/\.packed$/` continues to match the
canonical content-addressed form; the Cluster B
`RunServiceWorkerOptions.legacyUrlPattern` slot accepts any other
RegExp callers need for backwards compatibility (e.g. legacy
named-archive URLs).