Initial Commit
This commit is contained in:
@@ -0,0 +1,91 @@
|
||||
# `cross-origin` — multi-origin Service Worker registration
|
||||
|
||||
## Purpose
|
||||
|
||||
`registerCrossOriginPackedResourceServiceWorker` lets an application
|
||||
register a packed-resource Service Worker hosted on a different origin
|
||||
(typically a CDN subdomain). Before any browser request is dispatched
|
||||
the helper validates the SW URL's origin against a caller-supplied
|
||||
allowlist, so attacker-controlled or misconfigured CDN origins cannot
|
||||
slip past. On success the helper returns both the new registration and
|
||||
the container's current registration list so multi-tenant apps can
|
||||
confirm the CDN-origin SW is actually controlling the page.
|
||||
|
||||
## Features
|
||||
|
||||
- Strict allowlist validation BEFORE `register()` fires
|
||||
- Parses `swUrl` via the `URL` constructor — malformed URLs reject with
|
||||
`PACKER_BROWSER.UNAUTHORIZED_ORIGIN`
|
||||
- Delegates to `registerPackedResourceServiceWorker` so all the
|
||||
underlying contract (AbortSignal, error wrapping, message resolution)
|
||||
remains intact
|
||||
- Returns the full registration list (parity with
|
||||
`clients.matchAll({ includeUncontrolled: true })`)
|
||||
|
||||
## Usage: Basic
|
||||
|
||||
```ts
|
||||
import { registerCrossOriginPackedResourceServiceWorker } from "@suaveplan/packer-browser/utils";
|
||||
|
||||
await registerCrossOriginPackedResourceServiceWorker({
|
||||
swUrl: "https://cdn.example.com/sw.js",
|
||||
scope: "/packed/",
|
||||
allowedOrigins: ["https://cdn.example.com"],
|
||||
});
|
||||
```
|
||||
|
||||
## Usage: Advanced
|
||||
|
||||
```ts
|
||||
import {
|
||||
PACKER_BROWSER_CODES,
|
||||
PackerBrowserError,
|
||||
registerCrossOriginPackedResourceServiceWorker,
|
||||
} from "@suaveplan/packer-browser";
|
||||
|
||||
try {
|
||||
const { registration, registrations } =
|
||||
await registerCrossOriginPackedResourceServiceWorker({
|
||||
swUrl: "https://cdn.example.com/sw.js",
|
||||
scope: "/",
|
||||
allowedOrigins: [
|
||||
"https://cdn.example.com",
|
||||
"https://cdn-fallback.example.com",
|
||||
],
|
||||
container: navigator.serviceWorker,
|
||||
signal: shutdownController.signal,
|
||||
});
|
||||
console.log("registered", registration.scope, "of", registrations.length);
|
||||
} catch (err) {
|
||||
if (
|
||||
err instanceof PackerBrowserError &&
|
||||
err.code === PACKER_BROWSER_CODES.UNAUTHORIZED_ORIGIN
|
||||
) {
|
||||
console.warn("Origin not allowed; falling back to first-party SW.");
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## API Reference
|
||||
|
||||
- `registerCrossOriginPackedResourceServiceWorker(opts: RegisterCrossOriginOptions): Promise<RegisterCrossOriginResult>`
|
||||
- `opts.swUrl: string` — absolute SW URL. Required.
|
||||
- `opts.scope: string` — registration scope. Required.
|
||||
- `opts.allowedOrigins: ReadonlyArray<string>` — exact-string match. Required.
|
||||
- `opts.container?` — injectable container. Default: `navigator.serviceWorker`.
|
||||
- `opts.messageResolver?` — i18n resolver.
|
||||
- `opts.signal?` — AbortSignal forwarded to `register()`.
|
||||
- Returns `{ registration, registrations }`.
|
||||
|
||||
## Implementation Notes
|
||||
|
||||
- Origin equality is exact-string — there is no host-suffix matching.
|
||||
Allowlisting both `https://cdn.example.com` and
|
||||
`https://cdn-fallback.example.com` is explicit by design.
|
||||
- Malformed `swUrl` strings (relative paths, plain identifiers) yield
|
||||
`UNAUTHORIZED_ORIGIN`, not `SW_REGISTRATION_FAILED`, because the
|
||||
helper deliberately rejects before consulting the container.
|
||||
- The `registrations` list is the full `container.getRegistrations()`
|
||||
return value when a container is supplied; without one (e.g. in a
|
||||
Node smoke harness) the underlying `register()` already rejects with
|
||||
`SW_REGISTRATION_FAILED` so the caller never sees a partial list.
|
||||
Reference in New Issue
Block a user