Files
skills/docs/foundation/data/packer-browser/src/utils/register-service-worker.md
2026-05-29 08:20:56 +01:00

3.4 KiB

register-service-worker

Purpose

register-service-worker.ts collects four lifecycle helpers exposed via the /utils subpath: registerPackedResourceServiceWorker, unregisterPackedResourceServiceWorker, clearServiceWorkerCache, and getServiceWorkerCacheStatus. They wrap the navigator.serviceWorker API with typed errors, injectable container support (for tests), and AbortSignal honoured at every yield. Every boundary error uses MessageResolver-keyed messages rather than hard-coded English literals.

Features

  • Injectable container: ServiceWorkerContainerLike — tests pass an in-memory implementation; production defaults to navigator.serviceWorker.
  • AbortSignal honoured pre-call (synchronous reject with PackerBrowserError(ABORTED)) and mid-call (channel teardown + reject) on both clearServiceWorkerCache and getServiceWorkerCacheStatus.
  • getServiceWorkerCacheStatus includes a hard 5-second timeout so a hung controller cannot leak a pending Promise.
  • Boundary errors: SW_REGISTRATION_FAILED (no SW support, register rejected, no controller attached), LOAD_FAILED (timeout / negative reply), ABORTED (signal fires).
  • Returns typed shapes: ServiceWorkerRegistration, boolean, void, CacheStatusReply.

Usage: Basic

import {
    clearServiceWorkerCache,
    getServiceWorkerCacheStatus,
    registerPackedResourceServiceWorker,
} from "@suaveplan/packer-browser/utils";

await registerPackedResourceServiceWorker();
const status = await getServiceWorkerCacheStatus();
console.log(status.cacheSize, status.urls);

await clearServiceWorkerCache();

Usage: Advanced

import type { ServiceWorkerContainerLike } from "@suaveplan/packer-browser/utils";

const ac = new AbortController();
const recorded: string[] = [];
const container: ServiceWorkerContainerLike = {
    controller: createMockController(recorded),
    register: async () => fakeRegistration(),
    getRegistrations: async () => [],
    ready: Promise.resolve(fakeRegistration()),
};

await registerPackedResourceServiceWorker({
    container,
    scriptUrl: "/custom.js",
    signal: ac.signal,
});

API Reference

  • registerPackedResourceServiceWorker(opts?: RegisterOptions): Promise<ServiceWorkerRegistration> —
    • throws SW_REGISTRATION_FAILED for no SW support / rejected register().
    • throws ABORTED on a pre-aborted signal.
  • unregisterPackedResourceServiceWorker(opts?): Promise<boolean> — resolves false when no container is available.
  • clearServiceWorkerCache(opts?): Promise<void> — throws SW_REGISTRATION_FAILED if no controller is attached; throws ABORTED if the signal fires.
  • getServiceWorkerCacheStatus(opts?): Promise<CacheStatusReply> — throws LOAD_FAILED on 5 s timeout; throws ABORTED on signal.
  • ServiceWorkerContainerLike / RegisterOptions / ServiceWorkerLifecycleOptions — type-only injection points.

Implementation Notes

The helpers route every controller.postMessage through a MessageChannel and listen on port1 for the reply. The AbortSignal integration closes port1 before rejecting so the underlying SW does not see a half-open channel. The 5-second getServiceWorkerCacheStatus timeout is hard-coded because the upstream form had the same value; Cluster B will widen this once the SW gains range-request support and a single status query can take arbitrarily long under load.