first commit

This commit is contained in:
2026-05-29 08:20:56 +01:00
commit 949299f58d
6368 changed files with 527176 additions and 0 deletions

View File

@@ -0,0 +1,81 @@
# `sw-shim`
## Purpose
`sw-shim.ts` provides `createServiceWorkerShim()`, a hand-rolled
in-memory implementation of `ServiceWorkerGlobalScope` sufficient to
register and exercise the production SW handlers in a Node test
process. The shim is a **real implementation** — every method does
the work it claims to do, no `vi.mock` is permitted by CLAUDE.md rule
2. Tests register the production `runPackedResourceServiceWorker`
against the shim and dispatch `FetchEvent` / `ExtendableEvent` /
`MessageEvent` instances built from `globalThis` constructors.
## Features
- `addEventListener(type, handler)` registers the handler against a
type-keyed `Map<string, Set<EventListener>>`.
- `dispatchEvent(event)` walks the matching set and invokes each
handler synchronously, returning the standard `boolean`.
- `caches` is a real `Map<string, Map<url, Response>>`-backed
`CacheStorage`; `open` / `match` / `put` / `keys` / `delete` all
behave like the platform API.
- `clients.claim()` and `skipWaiting()` resolve immediately and
record their call counts on `record` so tests can assert lifecycle
invariants like "skipWaiting was called once".
- No `vi.fn` / `vi.mock` anywhere — the entire test surface
observes real method behaviour via the `record` snapshot or the
cache state.
## Usage: Basic
```ts
import {
createServiceWorkerShim,
runPackedResourceServiceWorker,
} from "@suaveplan/packer-browser";
const scope = createServiceWorkerShim();
runPackedResourceServiceWorker(scope);
scope.dispatchEvent(new Event("install"));
// scope.record.skipWaitingCalls === 1
```
## Usage: Advanced
```ts
import { createServiceWorkerShim } from "@suaveplan/packer-browser";
const scope = createServiceWorkerShim();
const cache = await scope.caches.open("ephemeral");
await cache.put("/a", new Response("payload"));
const hit = await cache.match("/a");
const text = await hit?.text();
// text === "payload"
// Dispatch into a custom listener
scope.addEventListener("custom", (ev) => observed.push(ev.type));
scope.dispatchEvent(new Event("custom"));
```
## API Reference
- `createServiceWorkerShim(): ServiceWorkerShim`.
- `ServiceWorkerShim`:
- `addEventListener(type, handler)` / `dispatchEvent(event)`.
- `skipWaiting(): Promise<void>` (records call).
- `clients: { claim(): Promise<void> }` (records call).
- `caches: ShimCacheStorage`.
- `record: ShimRecord` — `{ skipWaitingCalls, clientsClaimCalls }`.
## Implementation Notes
The shim deliberately does NOT reproduce browser quirks like Cache
Storage partitioning by origin, the FetchEvent network fall-through,
or the per-message-port `start()` requirement. Those behaviours are
covered by the Playwright E2E suite, not the unit tests; the unit
tests are concerned with the SW handler logic ("a packed URL
intercepted by the production code path produces a cache write")
which the shim faithfully exposes. Tests construct `Event`, `Request`,
and `Response` objects via `globalThis` (happy-dom in vitest) rather
than reinventing them inside the shim.