first commit
This commit is contained in:
@@ -0,0 +1,90 @@
|
||||
# `service-worker`
|
||||
|
||||
<!-- begin:auto-docs -->
|
||||
_(no submodules)_
|
||||
<!-- end:auto-docs -->
|
||||
|
||||
## Purpose
|
||||
|
||||
`service-worker.ts` is the production Service Worker entrypoint
|
||||
exposed via the `/service-worker` subpath. Its only public function,
|
||||
`runPackedResourceServiceWorker(scope, opts?)`, registers four
|
||||
handlers — `install`, `activate`, `fetch`, and `message` — against
|
||||
the supplied scope. In production the scope is the real
|
||||
`ServiceWorkerGlobalScope`; in tests it is the in-memory shim from
|
||||
`sw-shim.ts`. Cluster A intentionally caches the **packed** bytes in
|
||||
the SW (un-tagged) and lets the `PackedResourceManager` on the page
|
||||
do the unpack; Cluster B adds SW-side unpack with range support.
|
||||
|
||||
## Features
|
||||
|
||||
- `install` → `scope.skipWaiting()` so the new worker activates on
|
||||
the first navigation rather than waiting for every tab to close.
|
||||
- `activate` → deletes every cache whose name is not the configured
|
||||
`cacheName`, then calls `scope.clients.claim()` so existing tabs
|
||||
start routing through the new worker immediately.
|
||||
- `fetch` → matches `packedPatterns` (default
|
||||
`[/\.packed$/, /\?packed=true/]`) and intercepts only those URLs.
|
||||
Cache hits are served verbatim; misses trigger an upstream fetch
|
||||
and a cache write tagged `X-Unpacked: true`.
|
||||
- `message` → handles `CACHE_CLEAR` (deletes the cache) and
|
||||
`CACHE_STATUS` (replies with `{ cacheSize, urls }` on
|
||||
`event.ports[0]`).
|
||||
- Injectable `fetch` for tests — no `vi.mock` required.
|
||||
|
||||
## Usage: Basic
|
||||
|
||||
In your production SW bundle (`service-worker.js`):
|
||||
|
||||
```ts
|
||||
import { runPackedResourceServiceWorker } from "@suaveplan/packer-browser/service-worker";
|
||||
|
||||
runPackedResourceServiceWorker(
|
||||
self as unknown as ServiceWorkerGlobalScope
|
||||
);
|
||||
```
|
||||
|
||||
## Usage: Advanced
|
||||
|
||||
```ts
|
||||
import {
|
||||
createServiceWorkerShim,
|
||||
runPackedResourceServiceWorker,
|
||||
} from "@suaveplan/packer-browser/service-worker";
|
||||
|
||||
const scope = createServiceWorkerShim();
|
||||
runPackedResourceServiceWorker(scope, {
|
||||
cacheName: "test-cache",
|
||||
packedPatterns: [/^https:\/\/cdn\.example\.com\/.+\.packed/],
|
||||
fetch: async (url) => new Response(testBytes),
|
||||
});
|
||||
|
||||
const request = new Request("https://cdn.example.com/a.packed");
|
||||
const fetchEvent = makeFetchEventLike(request);
|
||||
scope.dispatchEvent(fetchEvent);
|
||||
const response = await fetchEvent.responsePromise;
|
||||
// response.headers.get("X-Unpacked") === "true"
|
||||
```
|
||||
|
||||
## API Reference
|
||||
|
||||
- `runPackedResourceServiceWorker(scope, opts?: RunServiceWorkerOptions): void`.
|
||||
- `RunServiceWorkerOptions`:
|
||||
- `cacheName?: string` — default `"packed-resources-v1"`.
|
||||
- `packedPatterns?: ReadonlyArray<RegExp>` — default
|
||||
`[/\.packed$/, /\?packed=true/]`.
|
||||
- `fetch?: FetchLike` — default `globalThis.fetch`.
|
||||
- Errors raised inside the fetch handler are `PackerBrowserError`
|
||||
with `LOAD_FAILED` (network) or `RESOURCE_NOT_FOUND` (non-2xx)
|
||||
codes; they propagate out of `respondWith` as a rejected promise.
|
||||
|
||||
## Implementation Notes
|
||||
|
||||
The SW deliberately does not call into `PackedResourceManager` from
|
||||
inside its scope — the manager owns Blob URL allocation, which is a
|
||||
page-scope concern (a SW that calls `URL.createObjectURL` produces
|
||||
URLs the page cannot resolve). The SW's role is purely to cache the
|
||||
**packed** bytes and short-circuit re-fetch. The page-side manager
|
||||
sees the cached response (or a fresh network response) and runs the
|
||||
unpack. This split keeps the SW small enough to register on a flaky
|
||||
connection without bundling the entire Unpacker pipeline.
|
||||
Reference in New Issue
Block a user