4.0 KiB
4.0 KiB
content-address
(no submodules)
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 extbundle.assetmatches the Cluster A SW pattern).cleanupOutdatedCaches(caches, prefix, keep)— Service Worker helper that deletes every cache name with a given prefix not inkeep.PACKER_BROWSER_FLAGS.URL_CONTENT_ADDRESSED— stable feature-flag string registered against the manager'sFlagProvider.
Usage: Basic Example
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
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): Uint8ArrayThrowsRangeErrorifformatVersionis not an integer in [0, 255].contentHashHex(hash: Uint8Array): stringThrowsRangeErroron non-32-byte input.buildContentAddressedUrl(prefix: string, hash: string, ext?: string): stringcleanupOutdatedCaches(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+merkleRootBlake3primitives. cleanupOutdatedCachesaccepts any object withkeys()anddelete()methods; both the productionglobalThis.cachesand the in-memoryShimCacheStoragesatisfy the contract, which keeps the SW unit tests honest.buildContentAddressedUrltrims a trailing slash from the prefix so callers can pass/packedor/packed/interchangeably.- The Cluster A SW pattern
/\.packed$/continues to match the canonical content-addressed form; the Cluster BRunServiceWorkerOptions.legacyUrlPatternslot accepts any other RegExp callers need for backwards compatibility (e.g. legacy named-archive URLs).