@statewalker/webrun-http-browser 0.6.4 → 0.7.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +319 -65
- package/dist/core/data-calls.d.ts +17 -0
- package/dist/core/data-calls.d.ts.map +1 -1
- package/dist/core/service-worker-control.d.ts +3 -1
- package/dist/core/service-worker-control.d.ts.map +1 -1
- package/dist/index.d.ts +3 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +3907 -266
- package/dist/link/errors.d.ts +2 -0
- package/dist/link/errors.d.ts.map +1 -0
- package/dist/link/http-link.d.ts +58 -0
- package/dist/link/http-link.d.ts.map +1 -0
- package/dist/link/index.d.ts +4 -0
- package/dist/link/index.d.ts.map +1 -0
- package/dist/link/locks.d.ts +39 -0
- package/dist/link/locks.d.ts.map +1 -0
- package/dist/link/rendezvous.d.ts +21 -0
- package/dist/link/rendezvous.d.ts.map +1 -0
- package/dist/relay/index-sw.d.ts +12 -2
- package/dist/relay/index-sw.d.ts.map +1 -1
- package/dist/relay/index.d.ts +66 -8
- package/dist/relay/index.d.ts.map +1 -1
- package/dist/relay-sw.js +1160 -55
- package/dist/relay-worker.js +1161 -55
- package/dist/sw/handler-endpoint.d.ts +81 -0
- package/dist/sw/handler-endpoint.d.ts.map +1 -0
- package/dist/sw/handler-table.d.ts +53 -0
- package/dist/sw/handler-table.d.ts.map +1 -0
- package/dist/sw/http-sw-dispatcher.d.ts +162 -21
- package/dist/sw/http-sw-dispatcher.d.ts.map +1 -1
- package/dist/sw/index.d.ts +5 -0
- package/dist/sw/index.d.ts.map +1 -1
- package/dist/sw/protocol.d.ts +115 -0
- package/dist/sw/protocol.d.ts.map +1 -0
- package/dist/sw/sw-dispatcher.d.ts +2 -1
- package/dist/sw/sw-dispatcher.d.ts.map +1 -1
- package/dist/sw/sw-http-adapter.d.ts +199 -0
- package/dist/sw/sw-http-adapter.d.ts.map +1 -0
- package/dist/sw/sw-websocket.d.ts +16 -0
- package/dist/sw/sw-websocket.d.ts.map +1 -0
- package/dist/sw/worker-service.d.ts +45 -0
- package/dist/sw/worker-service.d.ts.map +1 -0
- package/dist/sw/worker-url.d.ts +9 -0
- package/dist/sw/worker-url.d.ts.map +1 -0
- package/dist/sw-worker.js +2075 -210
- package/dist/sw.d.ts +2 -0
- package/dist/sw.d.ts.map +1 -1
- package/dist/sw.js +3853 -480
- package/dist/worker.d.ts +10 -0
- package/dist/worker.d.ts.map +1 -0
- package/dist/worker.js +3507 -0
- package/dist/ws/client.d.ts +73 -0
- package/dist/ws/client.d.ts.map +1 -0
- package/dist/ws/frames.d.ts +68 -0
- package/dist/ws/frames.d.ts.map +1 -0
- package/dist/ws/index.d.ts +6 -0
- package/dist/ws/index.d.ts.map +1 -0
- package/dist/ws/server.d.ts +53 -0
- package/dist/ws/server.d.ts.map +1 -0
- package/dist/ws/socket-core.d.ts +91 -0
- package/dist/ws/socket-core.d.ts.map +1 -0
- package/dist/ws/upgrade.d.ts +93 -0
- package/dist/ws/upgrade.d.ts.map +1 -0
- package/package.json +10 -5
- package/src/core/data-calls.ts +52 -2
- package/src/core/service-worker-control.ts +7 -1
- package/src/index.ts +3 -0
- package/src/link/errors.ts +3 -0
- package/src/link/http-link.ts +222 -0
- package/src/link/index.ts +3 -0
- package/src/link/locks.ts +97 -0
- package/src/link/rendezvous.ts +60 -0
- package/src/relay/index-sw.ts +84 -12
- package/src/relay/index.ts +205 -29
- package/src/sw/handler-endpoint.ts +278 -0
- package/src/sw/handler-table.ts +130 -0
- package/src/sw/http-sw-dispatcher.ts +649 -90
- package/src/sw/index.ts +5 -0
- package/src/sw/protocol.ts +103 -0
- package/src/sw/sw-dispatcher.ts +12 -30
- package/src/sw/sw-http-adapter.ts +613 -0
- package/src/sw/sw-websocket.ts +43 -0
- package/src/sw/worker-service.ts +133 -0
- package/src/sw/worker-url.ts +19 -0
- package/src/sw-worker.ts +8 -3
- package/src/sw.ts +2 -0
- package/src/worker.ts +9 -0
- package/src/ws/client.ts +346 -0
- package/src/ws/frames.ts +119 -0
- package/src/ws/index.ts +11 -0
- package/src/ws/server.ts +132 -0
- package/src/ws/socket-core.ts +251 -0
- package/src/ws/upgrade.ts +200 -0
package/README.md
CHANGED
|
@@ -2,17 +2,24 @@
|
|
|
2
2
|
|
|
3
3
|
## What it is
|
|
4
4
|
|
|
5
|
-
A ServiceWorker-based HTTP server for the browser. You write
|
|
6
|
-
`(Request) => Response` handlers in page
|
|
7
|
-
`fetch()` calls and routes them to those handlers over
|
|
8
|
-
network round-trip and no external server.
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
5
|
+
A ServiceWorker-based HTTP and WebSocket server for the browser. You write
|
|
6
|
+
ordinary `(Request) => Response` handlers in a page or in a Dedicated Worker; a
|
|
7
|
+
ServiceWorker intercepts `fetch()` calls and routes them to those handlers over
|
|
8
|
+
`MessagePort`s, with no network round-trip and no external server. Bodies
|
|
9
|
+
stream with backpressure in both directions, and an aborted `fetch` reaches the
|
|
10
|
+
handler as a cancellation. It has two modes:
|
|
11
|
+
|
|
12
|
+
- **Same-origin** (`./sw` + `./sw-worker`, and `./worker` in Dedicated
|
|
13
|
+
Workers): your app registers its own worker next to its pages and mounts
|
|
14
|
+
handlers under URL prefixes, in the page itself or in workers the page
|
|
15
|
+
attaches.
|
|
12
16
|
- **Relay** (`.` + `./relay-sw` or `./relay-worker`): a worker hosted on a relay
|
|
13
17
|
origin serves requests for any page that embeds a hidden relay iframe. The
|
|
14
18
|
page never registers a worker of its own.
|
|
15
19
|
|
|
20
|
+
In both modes a handler can also accept WebSockets: a socket is carried by a
|
|
21
|
+
`MessagePort`, and the caller gets a class with the browser's `WebSocket` API.
|
|
22
|
+
|
|
16
23
|
## Why it exists
|
|
17
24
|
|
|
18
25
|
The browser already has `Request`, `Response`, `ReadableStream` and
|
|
@@ -42,9 +49,10 @@ pnpm add @statewalker/webrun-http-browser
|
|
|
42
49
|
|
|
43
50
|
| Subpath | Format | Runs in | What it gives |
|
|
44
51
|
| --- | --- | --- | --- |
|
|
45
|
-
| `.` | ESM, `dist/index.js` + `.d.ts` | page, relay iframe | Relay page API (`newRemoteRelayChannel`, `initHttpService`, `callHttpService`, `getRelayWindowMessageHandler`, `splitServiceUrl`), ServiceWorker lifecycle helpers (`initServiceWorker`, `newServiceWorkerPort`, `awaitActiveServiceWorker`, `awaitServiceWorkerControl`, `handleClaimRequests`, `ServiceWorkerControlError`), the `MessagePort` call primitives, and everything re-exported from `@statewalker/webrun-streams` and `@statewalker/webrun-http-streams`. |
|
|
46
|
-
| `./sw` | ESM, `dist/sw.js` + `.d.ts` | page and worker | Same-origin classes: `SwHttpAdapter` (page), `SwHttpDispatcher` and `startHttpDispatcher` (worker), and
|
|
47
|
-
| `./
|
|
52
|
+
| `.` | ESM, `dist/index.js` + `.d.ts` | page, relay iframe | Relay page API (`newRemoteRelayChannel`, `initHttpService`, `callHttpService`, `callWebSocketService`, `relayWebSocketClass`, `getRelayWindowMessageHandler`, `splitServiceUrl`), ServiceWorker lifecycle helpers (`initServiceWorker`, `newServiceWorkerPort`, `awaitActiveServiceWorker`, `awaitServiceWorkerControl`, `handleClaimRequests`, `ServiceWorkerControlError`), everything `./sw` exports, the `MessagePort` call primitives, and everything re-exported from `@statewalker/webrun-streams` and `@statewalker/webrun-http-streams`. |
|
|
53
|
+
| `./sw` | ESM, `dist/sw.js` + `.d.ts` | page and worker | Same-origin classes: `SwHttpAdapter` (page), `SwHttpDispatcher` and `startHttpDispatcher` (worker), the WebSocket module (`createWebSocketClass`, `upgradeWebSocket`, ...), `serviceWorkerWebSocketClass`, the HTTP link layer (`connectHttpLink`, `serveHttpLink`), and the version-1 bases `SwPortHandler` / `SwPortDispatcher`. |
|
|
54
|
+
| `./worker` | ESM, `dist/worker.js` + `.d.ts` | Dedicated Worker | `serveHttpInWorker(handler)`, and the WebSocket helpers a handler needs (`upgradeWebSocket`, `isWebSocketUpgrade`, `requestedProtocols`, `createWebSocketClass`). |
|
|
55
|
+
| `./sw-worker` | IIFE, `dist/sw-worker.js`, no types | ServiceWorker | Prebuilt same-origin worker: calls `startHttpDispatcher({ self, log: console.log, ...self.HTTP_DISPATCHER_OPTIONS })`. Load it with `importScripts`. |
|
|
48
56
|
| `./relay-sw` | IIFE, `dist/relay-sw.js`, no types | ServiceWorker | Prebuilt relay worker: calls `startRelayServiceWorker(self, self.RELAY_OPTIONS ?? {})`. Load it with `importScripts`. |
|
|
49
57
|
| `./relay-worker` | ESM, `dist/relay-worker.js` + `.d.ts` | ServiceWorker | The relay worker runtime as a typed module, for a host that bundles its own worker: `startRelayServiceWorker`, `RelayServiceWorkerOptions`, `MountSpec`. Not re-exported from `.`, because it only runs inside a worker. |
|
|
50
58
|
|
|
@@ -80,7 +88,8 @@ const connection = await newRemoteRelayChannel({
|
|
|
80
88
|
url: new URL("https://my-relay.example/relay.html"),
|
|
81
89
|
});
|
|
82
90
|
|
|
83
|
-
// 2. Register a handler for service "FS".
|
|
91
|
+
// 2. Register a handler for service "FS". Resolves a function that unregisters
|
|
92
|
+
// it; that function's promise settles once the relay has dropped the service.
|
|
84
93
|
const unregister = await initHttpService(
|
|
85
94
|
async (request) => new Response(`Hello ${new URL(request.url).pathname}`),
|
|
86
95
|
{ key: "FS", port: connection.port },
|
|
@@ -120,6 +129,28 @@ prefix is not stripped: a handler mounted at `/peers/` receives
|
|
|
120
129
|
`/peers/12D3Koo/llm`. A handler that routes relative to its mount strips the
|
|
121
130
|
prefix itself.
|
|
122
131
|
|
|
132
|
+
### Relay mode: WebSockets
|
|
133
|
+
|
|
134
|
+
The same handler accepts sockets: on a `GET` with `Upgrade: websocket` it
|
|
135
|
+
answers with `upgradeWebSocket` (see [WebSockets](#websockets)). A caller on
|
|
136
|
+
any origin opens one through the relay connection:
|
|
137
|
+
|
|
138
|
+
```ts
|
|
139
|
+
import { relayWebSocketClass } from "@statewalker/webrun-http-browser";
|
|
140
|
+
|
|
141
|
+
const WS = relayWebSocketClass({ key: "FS", port: connection.port });
|
|
142
|
+
const ws = new WS("https://my-relay.example/~FS/chat", ["v1"]);
|
|
143
|
+
ws.onmessage = (event) => console.log(event.data);
|
|
144
|
+
```
|
|
145
|
+
|
|
146
|
+
`callWebSocketService(url, protocols, { key, port })` is the lower level: it
|
|
147
|
+
resolves `{ port, protocol }` once the service accepted. The relay worker only
|
|
148
|
+
brokers the port; after that the socket runs between the caller and the
|
|
149
|
+
serving page directly. Content served on the relay origin itself opens sockets
|
|
150
|
+
through the relay worker with `serviceWorkerWebSocketClass()`, routed by its url
|
|
151
|
+
like a fetch. The relay's `canRegister` and `takeover` rules apply to sockets
|
|
152
|
+
as to requests, since both go to the service that holds the key.
|
|
153
|
+
|
|
123
154
|
### Relay mode: build your own relay worker
|
|
124
155
|
|
|
125
156
|
```ts
|
|
@@ -134,7 +165,8 @@ const stop = startRelayServiceWorker(self, {
|
|
|
134
165
|
url.pathname === "/relay.html" ||
|
|
135
166
|
url.pathname === "/relay-sw.js",
|
|
136
167
|
takeover: "first-wins",
|
|
137
|
-
canRegister: (client, _key) =>
|
|
168
|
+
canRegister: (client, _key, path) =>
|
|
169
|
+
new URL(client.url).pathname === "/relay.html" && path !== "/index.html",
|
|
138
170
|
decorateResponse: (response) => response,
|
|
139
171
|
});
|
|
140
172
|
```
|
|
@@ -143,9 +175,15 @@ const stop = startRelayServiceWorker(self, {
|
|
|
143
175
|
| --- | --- | --- |
|
|
144
176
|
| `mounts` | none | Fixed table `Array<{ key, path?, match? }>`, for a host that knows its services at build time. A key declared here belongs to the host: a page's `REGISTER` or `UNREGISTER` for it never replaces or removes the mount, so the page can register with no `path`. |
|
|
145
177
|
| `exclude` | none | `(url) => boolean`. Paths the relay never claims, through the table or through `/~<key>/`. Checked first. |
|
|
146
|
-
| `canRegister` | everyone | `(client, key) => boolean \| Promise<boolean>`.
|
|
178
|
+
| `canRegister` | everyone | `(client, key, path?) => boolean \| Promise<boolean>`. `path` is where the registrant asks to be mounted (`undefined` for `/~<key>/`), so a host can vet where a key lands, not only who takes it. Refuses with `this client may not register "<key>"` (`... at "<path>"`). Also consulted for `UNREGISTER`, with the key's current path. |
|
|
147
179
|
| `takeover` | `"last-wins"` | `"first-wins"` keeps a live holder's key; a second page gets `"<key>" is already served by another client`. A holder that reloaded is no longer live, so it can always re-register. |
|
|
148
180
|
| `decorateResponse` | none | `(response, request) => Response`. Stamps headers on responses the relay makes, including its error responses. Not applied to requests the worker leaves to the network. |
|
|
181
|
+
| `streamTimeout` | none | Per-stream inactivity timeout, in ms, of the links to services. |
|
|
182
|
+
|
|
183
|
+
`UNREGISTER` is accepted only from the client that holds the key, or, once
|
|
184
|
+
that client is gone, from any client `canRegister` allows: any page of the
|
|
185
|
+
relay origin can post to the worker, including foreign content the host serves
|
|
186
|
+
there.
|
|
149
187
|
|
|
150
188
|
`startRelayServiceWorker` returns a function that removes its listeners.
|
|
151
189
|
|
|
@@ -191,9 +229,11 @@ declare const self: ServiceWorkerGlobalScope & { RELAY_OPTIONS?: RelayServiceWor
|
|
|
191
229
|
</script>
|
|
192
230
|
```
|
|
193
231
|
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
232
|
+
Without `swUrl` the handler registers the bundle's own `dist/relay-sw.js`,
|
|
233
|
+
and without `scopeUrl` the scope is that worker's directory, `dist/`: the
|
|
234
|
+
widest scope a script there may claim without a `Service-Worker-Allowed`
|
|
235
|
+
header. A relay page that serves services anywhere else passes both, as above.
|
|
236
|
+
`timeout` bounds the wait for the worker to activate. If the worker cannot start, every call the parent makes on the port
|
|
197
237
|
is answered with that error, so the parent's `initHttpService` /
|
|
198
238
|
`callHttpService` reject instead of hanging.
|
|
199
239
|
|
|
@@ -229,14 +269,176 @@ importScripts("/path/to/@statewalker/webrun-http-browser/dist/sw-worker.js");
|
|
|
229
269
|
| Option | Default | Meaning |
|
|
230
270
|
| --- | --- | --- |
|
|
231
271
|
| `key` | required | First URL segment under the scope that the worker routes to this page. |
|
|
232
|
-
| `serviceWorkerUrl` |
|
|
272
|
+
| `serviceWorkerUrl` | `sw-worker.js` at the scope | Resolved against `location.href`. An unresolvable value throws `Invalid serviceWorkerUrl: "<value>" (relative to <href>)`. |
|
|
233
273
|
| `scope` | directory of `serviceWorkerUrl` | Registration scope. |
|
|
234
274
|
| `timeout` | `30_000` | Upper bound, in ms, for activation, control and the adapter's handshake. Past it `start()` rejects with a `ServiceWorkerControlError`. |
|
|
235
275
|
| `reloadIfUncontrolled` | `false` | Reload the page once instead of rejecting when it stays uncontrolled. |
|
|
276
|
+
| `streamTimeout` | none | Per-stream inactivity timeout of the links, in ms. Unset, a slow reader is throttled, never failed. |
|
|
277
|
+
| `id`, `meta` | a fresh id, none | The handler slot of this page's handlers, and what a `route` function sees of them. |
|
|
278
|
+
| `webSocket` | defaults | Options of `adapter.WebSocket` (`heartbeatMs`, `timers`, `closeTimeoutMs`). |
|
|
236
279
|
|
|
237
280
|
`register(prefix, handler)` resolves `{ baseUrl, prefix, remove() }`. The
|
|
238
281
|
prefix must start with the adapter's `key`.
|
|
239
282
|
|
|
283
|
+
### Same-origin mode: handlers in Dedicated Workers
|
|
284
|
+
|
|
285
|
+
A handler that does heavy work (SQLite on OPFS, WASM, a build) belongs in a
|
|
286
|
+
worker. Attached with `attachWorker`, the worker talks to the ServiceWorker
|
|
287
|
+
directly: the page makes the channels, hands one end of each to the worker and
|
|
288
|
+
the other to the ServiceWorker, and carries nothing afterwards, so a busy or
|
|
289
|
+
background-throttled page does not slow the requests down.
|
|
290
|
+
|
|
291
|
+
```ts
|
|
292
|
+
// page
|
|
293
|
+
const adapter = new SwHttpAdapter({ key: "app", serviceWorkerUrl: "/sw-worker.js" });
|
|
294
|
+
await adapter.start();
|
|
295
|
+
const worker = new Worker(new URL("./site-worker.js", import.meta.url), { type: "module" });
|
|
296
|
+
const link = await adapter.attachWorker(worker, { key: "site", id: "shard-0" });
|
|
297
|
+
|
|
298
|
+
// site-worker.js
|
|
299
|
+
import { serveHttpInWorker } from "@statewalker/webrun-http-browser/worker";
|
|
300
|
+
|
|
301
|
+
const service = serveHttpInWorker(async (request) => new Response("from a worker"));
|
|
302
|
+
// Requests through the ServiceWorker's router, to other handlers:
|
|
303
|
+
const other = await service.fetch("/app/api/x");
|
|
304
|
+
```
|
|
305
|
+
|
|
306
|
+
`attachWorker(worker, { key?, id?, meta? })` resolves a `WorkerLink`
|
|
307
|
+
`{ key, id, owner, drain({ ms }), detach() }`. Several workers may serve one key;
|
|
308
|
+
the ServiceWorker picks one per request (see below). Attaching an `id` the key
|
|
309
|
+
already has replaces that handler: the old one finishes its requests in flight
|
|
310
|
+
and gets no new ones.
|
|
311
|
+
|
|
312
|
+
`serveHttpInWorker(handler, options?)` returns `{ fetch, connectWebSocket,
|
|
313
|
+
WebSocket, linked, close() }`. Its `fetch` goes through the router without a
|
|
314
|
+
`fetch` event, so it works whether or not the worker is controlled.
|
|
315
|
+
|
|
316
|
+
### Same-origin mode: routing and hand-over
|
|
317
|
+
|
|
318
|
+
The ServiceWorker keeps a table of handlers per key and asks a `route`
|
|
319
|
+
function which one answers a request:
|
|
320
|
+
|
|
321
|
+
```js
|
|
322
|
+
// sw-worker.js, served next to your pages
|
|
323
|
+
self.HTTP_DISPATCHER_OPTIONS = {
|
|
324
|
+
route: (request, key, handlers) =>
|
|
325
|
+
handlers.find((h) => h.id === request.headers.get("x-shard")) ?? handlers[0],
|
|
326
|
+
};
|
|
327
|
+
importScripts("/path/to/@statewalker/webrun-http-browser/dist/sw-worker.js");
|
|
328
|
+
```
|
|
329
|
+
|
|
330
|
+
`handlers` are the live (not draining) handlers of the key, each a
|
|
331
|
+
`HandlerInfo` `{ id, key, owner, inflight, meta, attachedAt, draining }`. The
|
|
332
|
+
default, `leastInflightRoute`, takes the one with the fewest requests in flight,
|
|
333
|
+
the oldest on a tie: with one tab per key, the same page as before. A worker of
|
|
334
|
+
your own passes the options to `startHttpDispatcher({ self, ...options })`.
|
|
335
|
+
|
|
336
|
+
| Option | Default | What it does |
|
|
337
|
+
| --- | --- | --- |
|
|
338
|
+
| `route` | `leastInflightRoute` | Picks the handler. `undefined` makes the request wait for another to attach. |
|
|
339
|
+
| `attachTimeoutMs` | `15_000` | How long a request waits for a handler during a hand-over. Past it, `503`. |
|
|
340
|
+
| `relinkTimeoutMs` | `3_000` | How long a request waits for the pages to attach again after a restart. |
|
|
341
|
+
| `handoverMs` | `5_000` | How long a replaced handler may finish its requests. |
|
|
342
|
+
| `wsConnectTimeoutMs` | `15_000` | How long a socket waits for its handler's answer. |
|
|
343
|
+
| `streamTimeout` | none | Per-stream inactivity timeout of the links. |
|
|
344
|
+
| `livenessCheckMs` | `5_000` | Period of the backup liveness check (`navigator.locks.query()`); `0` turns it off. |
|
|
345
|
+
|
|
346
|
+
`link.drain({ ms })` hands a slot over: no new requests reach the handler (they
|
|
347
|
+
wait for the next owner of the key, up to `attachTimeoutMs`), and those in
|
|
348
|
+
flight may finish for up to `ms`. Then the link is closed. A drain or detach
|
|
349
|
+
names the attachment's `owner` token, so a late one from a previous owner never
|
|
350
|
+
touches the current one.
|
|
351
|
+
|
|
352
|
+
### Same-origin mode: restarts and liveness
|
|
353
|
+
|
|
354
|
+
The browser stops an idle ServiceWorker (Chromium after about 30 s), and every
|
|
355
|
+
port it held dies with it. Nothing reports that on the other end, so:
|
|
356
|
+
|
|
357
|
+
- **Re-linking.** The ServiceWorker keeps its table in memory only. The first
|
|
358
|
+
request after a restart, for a key it served before, asks every window to
|
|
359
|
+
attach its links again (`NEED_LINKS`) and waits for them. Pages answer by
|
|
360
|
+
attaching their own handlers and their workers.
|
|
361
|
+
- **Handler liveness.** Each handler holds a Web Lock while it lives; the
|
|
362
|
+
ServiceWorker watches it. When a tab closes or a worker is terminated, its
|
|
363
|
+
requests in flight fail at once with `502` and
|
|
364
|
+
`The handler was lost while this request was in flight; it may or may not
|
|
365
|
+
have been applied.`
|
|
366
|
+
- **ServiceWorker liveness.** The ServiceWorker holds a Web Lock too, and the
|
|
367
|
+
handlers watch it. When it dies, a worker's calls in flight over
|
|
368
|
+
`service.fetch` fail with `LinkLostError` (`The ServiceWorker was lost while
|
|
369
|
+
this call was in flight; ...`) instead of hanging, and new calls wait: the
|
|
370
|
+
worker asks its page to attach it again, and that message wakes the
|
|
371
|
+
ServiceWorker.
|
|
372
|
+
- **Keep-alive.** Port messages are not events, so a long call over
|
|
373
|
+
`service.fetch` would not keep the ServiceWorker awake. While such calls are
|
|
374
|
+
in flight, the worker asks its page every 20 s to post a keep-alive message
|
|
375
|
+
to the ServiceWorker.
|
|
376
|
+
|
|
377
|
+
Measured in Chromium with a ServiceWorker that may idle out
|
|
378
|
+
(`tests/browser/lifetime.browser.ts`, which drives Chromium over raw CDP:
|
|
379
|
+
Playwright keeps every ServiceWorker running):
|
|
380
|
+
|
|
381
|
+
- without the keep-alive, a 45 s call over `service.fetch` fails at about 30 s
|
|
382
|
+
with the loss error; with it, the call completes;
|
|
383
|
+
- a response streaming through the ServiceWorker keeps it alive by itself: a
|
|
384
|
+
60 s event stream arrives whole in the test, and a 6-minute one did in a
|
|
385
|
+
one-off run.
|
|
386
|
+
|
|
387
|
+
Without Web Locks, a page handler's liveness falls back to `clients.get()`, and
|
|
388
|
+
worker deaths are not noticed until a request times out.
|
|
389
|
+
|
|
390
|
+
### WebSockets
|
|
391
|
+
|
|
392
|
+
A ServiceWorker never sees WebSocket connections, so a socket is opened
|
|
393
|
+
explicitly and carried by a `MessagePort`. The handler side is an HTTP upgrade:
|
|
394
|
+
|
|
395
|
+
```ts
|
|
396
|
+
import { isWebSocketUpgrade, upgradeWebSocket } from "@statewalker/webrun-http-browser/worker";
|
|
397
|
+
|
|
398
|
+
async function handler(request: Request): Promise<Response> {
|
|
399
|
+
if (isWebSocketUpgrade(request)) {
|
|
400
|
+
const { socket, response } = upgradeWebSocket(request, { protocol: "v1" });
|
|
401
|
+
socket.accept();
|
|
402
|
+
socket.addEventListener("message", (event) => socket.send(event.data));
|
|
403
|
+
return response; // status 101
|
|
404
|
+
}
|
|
405
|
+
return new Response("not a socket", { status: 426 });
|
|
406
|
+
}
|
|
407
|
+
```
|
|
408
|
+
|
|
409
|
+
The caller gets a class with the browser's `WebSocket` API, which leaves the
|
|
410
|
+
global `WebSocket` alone:
|
|
411
|
+
|
|
412
|
+
```ts
|
|
413
|
+
const ws = new adapter.WebSocket(`${baseUrl}chat`, ["v1"]); // page with an adapter
|
|
414
|
+
const WS = serviceWorkerWebSocketClass(); // any controlled page
|
|
415
|
+
const WS2 = service.WebSocket; // in a worker, via the router
|
|
416
|
+
```
|
|
417
|
+
|
|
418
|
+
The ServiceWorker only brokers the port: it routes the url like a fetch, asks
|
|
419
|
+
the handler, and hands the accepted port to the caller. The socket then runs
|
|
420
|
+
between the two directly, so it survives a ServiceWorker restart. A socket to
|
|
421
|
+
a handler in the same page needs no ServiceWorker at all.
|
|
422
|
+
|
|
423
|
+
- **Upgrade request.** A browser drops `Upgrade` and `Sec-*` headers from every
|
|
424
|
+
`new Request()`, so the upgrade request carries them as its own `headers`
|
|
425
|
+
property. `requestedProtocols(request)` reads the subprotocols.
|
|
426
|
+
- **Server end.** `ServerWebSocket` delivers events only after `accept()`
|
|
427
|
+
(frames that arrive earlier are queued), answers pings before it, and has
|
|
428
|
+
`send`, `close`, `bufferedAmount` and `whenDrained(limit)` for
|
|
429
|
+
backpressure.
|
|
430
|
+
- **Client.** `createWebSocketClass(connect, options)` validates as the
|
|
431
|
+
standard does (url, scheme, fragment, subprotocol tokens, close codes and
|
|
432
|
+
reasons), has `binaryType`, the `on*` handlers and the close handshake.
|
|
433
|
+
`bufferedAmount` is real: the other end acknowledges what it consumed.
|
|
434
|
+
- **Heartbeat.** A port never reports that its other side died. The client
|
|
435
|
+
pings every `heartbeatMs` (default 10 s) and closes with 1006 when pongs stop
|
|
436
|
+
for twice that; the server closes with 1006 when pings stop for three times
|
|
437
|
+
that. On a page's main thread, pass unthrottled `timers`.
|
|
438
|
+
- **Wire protocol.** Frames `m` (message), `c` (close), `p`/`q` (ping/pong) and
|
|
439
|
+
`a` (bytes consumed), version `WS_PORT_PROTOCOL_VERSION`; see
|
|
440
|
+
`src/ws/frames.ts`.
|
|
441
|
+
|
|
240
442
|
### Same-origin mode: a page that is not controlled
|
|
241
443
|
|
|
242
444
|
```ts
|
|
@@ -283,22 +485,30 @@ callHttpService(req, {key, port}) ──port──► relay iframe ──► rel
|
|
|
283
485
|
Same-origin mode:
|
|
284
486
|
|
|
285
487
|
```
|
|
286
|
-
page fetch(<scope>/KEY/...) ──► same-origin worker ── first path segment
|
|
287
|
-
|
|
288
|
-
|
|
488
|
+
page fetch(<scope>/KEY/...) ──► same-origin worker ── KEY = first path segment
|
|
489
|
+
route(request, KEY, handlers) ──down──► page handler (SwHttpAdapter.register)
|
|
490
|
+
──down──► worker handler (serveHttpInWorker)
|
|
491
|
+
worker service.fetch(url) ──up──► same-origin worker ── same routing
|
|
492
|
+
new WebSocket(...) ──WS_CONNECT──► same-origin worker ──ctl──► handler ── port ──► caller
|
|
289
493
|
```
|
|
290
494
|
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
by
|
|
294
|
-
|
|
495
|
+
Every link is one `MessagePort` (`down`: requests a handler serves; `up`:
|
|
496
|
+
requests a worker sends; `ctl`: socket hand-over). Calls on a link are
|
|
497
|
+
multiplexed by `@statewalker/webrun-rpc` (`connect` / `serve` over `overPipe`),
|
|
498
|
+
each a stream with a one-chunk window in both directions, and HTTP runs over
|
|
499
|
+
them with `fetchOverDuplex` / `serveFetchOverDuplex` from
|
|
500
|
+
`@statewalker/webrun-http-streams`. The relay uses the same links, one per
|
|
501
|
+
`CONNECT`. Every hand-shake carries `HTTP_LINK_PROTOCOL`: a peer of version 1
|
|
502
|
+
(this package's own stream transport) is still served over that transport, and
|
|
503
|
+
a page whose worker runs an older version gets a `ServiceWorkerControlError`
|
|
504
|
+
with `reason: "incompatible"`.
|
|
295
505
|
|
|
296
506
|
### Every bundle is self-contained
|
|
297
507
|
|
|
298
508
|
This package does not externalise its dependencies. Its own HTML loads
|
|
299
509
|
`../dist/index.js` from a static host with no import map, and the two IIFE
|
|
300
510
|
workers are loaded with `importScripts`, which cannot resolve a bare
|
|
301
|
-
specifier. So each of the
|
|
511
|
+
specifier. So each of the six outputs is one file with `idb-keyval`,
|
|
302
512
|
`@statewalker/webrun-streams` and `@statewalker/webrun-http-streams` inlined,
|
|
303
513
|
built from its own rolldown config so no chunks are shared. The cost is
|
|
304
514
|
duplicated code across bundles, and that `instanceof` does not hold across this
|
|
@@ -378,22 +588,28 @@ When the relay worker cannot hand a request to a service, it answers with JSON
|
|
|
378
588
|
|
|
379
589
|
### Same-origin routing
|
|
380
590
|
|
|
381
|
-
The worker takes the first path segment under its scope as the key and
|
|
382
|
-
the request to
|
|
383
|
-
|
|
591
|
+
The worker takes the first path segment under its scope as the key and routes
|
|
592
|
+
the request to one of the key's handlers. A key that was served at some point
|
|
593
|
+
but has no live handler answers `404 Not Found (no active handler)` rather
|
|
384
594
|
than falling through to the network: a dev server's SPA fallback would
|
|
385
|
-
otherwise serve the app shell for every site URL.
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
595
|
+
otherwise serve the app shell for every site URL. (After a restart, the first
|
|
596
|
+
such request first asks the pages to link again; see above.) A URL outside the
|
|
597
|
+
scope, or of a key never served, is not answered at all: the worker does not
|
|
598
|
+
call `respondWith`, so the browser performs the request as without a worker.
|
|
599
|
+
Navigations under the scope are the exception: they are passed through with
|
|
600
|
+
`fetch(request)`, because Firefox can leave a page uncontrolled when its worker
|
|
601
|
+
did not answer the navigation. On
|
|
602
|
+
the page, a request matching no registered prefix gets
|
|
603
|
+
`404 Error 404: Not found`.
|
|
604
|
+
|
|
605
|
+
The worker keeps only the served keys in IndexedDB (`claimedKeys`); the
|
|
606
|
+
handlers are attached again after a restart. The relay keeps its registry
|
|
607
|
+
under `clientsIds` as `{ clientId, path }` entries and still reads the older
|
|
608
|
+
bare-client-id shape.
|
|
609
|
+
|
|
610
|
+
`SwPortHandler.stop()` unregisters only the registration its own `start()`
|
|
611
|
+
made; other workers on the origin stay registered. After a `start()` that
|
|
612
|
+
rejected, `stop()` unregisters nothing, since that attempt kept the worker.
|
|
397
613
|
|
|
398
614
|
### A page can load uncontrolled although its worker is active
|
|
399
615
|
|
|
@@ -424,26 +640,38 @@ answered by the worker and can load uncontrolled in Firefox; call
|
|
|
424
640
|
(`ServiceWorker "<url>" (scope <scope>) did not activate within <n> ms …`);
|
|
425
641
|
- `uncontrolled`: active, but the page is not controlled;
|
|
426
642
|
- `unresponsive`: controls the page but did not answer the adapter's
|
|
427
|
-
`UPDATE_COMMUNICATION_PORT` handshake in time
|
|
428
|
-
|
|
429
|
-
|
|
643
|
+
`UPDATE_COMMUNICATION_PORT` handshake in time;
|
|
644
|
+
- `incompatible`: answered the handshake but runs an older version of this
|
|
645
|
+
package (reload the page once the updated worker is active).
|
|
646
|
+
|
|
647
|
+
### Backpressure, and where the browser buffers
|
|
648
|
+
|
|
649
|
+
Both modes move requests over webrun-rpc links: a handler producing a body is
|
|
650
|
+
never more than a few chunks ahead of whoever reads it through this package's
|
|
651
|
+
links, and a reader that stops (an aborted `fetch`, a cancelled body) releases
|
|
652
|
+
the producer. Between a ServiceWorker's `respondWith` and the page, though,
|
|
653
|
+
Chromium buffers by itself, tens of megabytes of a fast stream: a page reading
|
|
654
|
+
slowly sees the handler run that far ahead before backpressure reaches it
|
|
655
|
+
(about 55 MiB, the same for a plain ServiceWorker with no library). Firefox
|
|
656
|
+
sets no such bound: it keeps reading a ServiceWorker's response while the page
|
|
657
|
+
does not, so there a handler streaming to a page that stopped reading keeps
|
|
658
|
+
producing (this package still holds only a few chunks of it). A worker
|
|
659
|
+
reading through `service.fetch` has no such buffer. `links.browser.ts` pins
|
|
660
|
+
the split: once a page stops reading, the handler is never more than a few
|
|
661
|
+
chunks ahead of what the ServiceWorker handed to Chromium, and stops.
|
|
430
662
|
|
|
431
663
|
`sendStream` / `handleStreams`, and the `sendHttpRequest` /
|
|
432
|
-
`handleHttpRequests` pair built on them,
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
`getRelayWindowMessageHandler`'s default `swUrl` and `SwPortHandler`'s default
|
|
445
|
-
worker URL both resolve to `index-sw.js` next to the module. No such file is
|
|
446
|
-
built. Pass `swUrl` / `serviceWorkerUrl` explicitly. Constructing a
|
|
664
|
+
`handleHttpRequests` pair built on them, are version 1's transport, kept for
|
|
665
|
+
peers that still speak it. They have no backpressure (a fast producer over a
|
|
666
|
+
slow consumer accumulates without bound), no per-stream timeout and no
|
|
667
|
+
chunking, and are `@deprecated`.
|
|
668
|
+
|
|
669
|
+
### The adapter's default worker url follows the scope
|
|
670
|
+
|
|
671
|
+
Without `serviceWorkerUrl`, `SwPortHandler` (and so `SwHttpAdapter`) uses
|
|
672
|
+
`sw-worker.js` at its scope, the scope resolved against the bundle's url. With
|
|
673
|
+
`scope: "/dist/"` that is the shipped `dist/sw-worker.js`; with `scope: "/"` it
|
|
674
|
+
is `/sw-worker.js`, a loader the host must serve there. Constructing a
|
|
447
675
|
`SwHttpAdapter` with neither `serviceWorkerUrl` nor `scope` fails with
|
|
448
676
|
`RangeError: Maximum call stack size exceeded`, because each default is
|
|
449
677
|
computed from the other.
|
|
@@ -460,6 +688,11 @@ computed from the other.
|
|
|
460
688
|
relay origin cannot use it.
|
|
461
689
|
- **Plain `fetch()` works only from pages under the worker's scope.** A caller
|
|
462
690
|
on another origin uses `callHttpService`.
|
|
691
|
+
- **`Set-Cookie` does not reach a page through a ServiceWorker.** A
|
|
692
|
+
browser-built `Response` drops it; carry state another way.
|
|
693
|
+
- **Liveness needs Web Locks** (`navigator.locks`, in every current browser).
|
|
694
|
+
Without it, handler deaths are noticed late and ServiceWorker deaths not at
|
|
695
|
+
all.
|
|
463
696
|
|
|
464
697
|
### Exports of the root entry
|
|
465
698
|
|
|
@@ -468,12 +701,14 @@ Relay, page side:
|
|
|
468
701
|
| Export | Purpose |
|
|
469
702
|
| --- | --- |
|
|
470
703
|
| `newRemoteRelayChannel(opts?)` / `RemoteRelayChannel`, `RemoteRelayChannelOptions` | Embed the relay iframe; resolves `{ baseUrl, port, close() }`. |
|
|
471
|
-
| `initHttpService(handler, { key, path?, port })` | Register a service; resolves a
|
|
704
|
+
| `initHttpService(handler, { key, path?, port, streamTimeout? })` | Register a service (HTTP and sockets); resolves a function that unregisters it, whose promise settles once the relay acknowledged. |
|
|
472
705
|
| `callHttpService(request, { key, port })` | Call a service through the port. |
|
|
473
|
-
| `
|
|
706
|
+
| `callWebSocketService(url, protocols, { key, port })` / `relayWebSocketClass({ key, port }, options?)` | Open a socket to a service through the port. |
|
|
707
|
+
| `answerConnect(handler, data, port)`, `sendOverConnection(port, reply, request)` | The two ends of one `CONNECT`, for a host with its own registration. |
|
|
708
|
+
| `ServiceOptions`, `ConnectReply`, `WebSocketConnectParams` | `{ key, path?, port, streamTimeout? }`, and the `CONNECT` shapes. |
|
|
474
709
|
| `getRelayWindowMessageHandler(opts?)` / `RelayWindowHandlerOptions` | The relay iframe's `window.onmessage`; options `swUrl`, `scopeUrl`, `timeout`. |
|
|
475
710
|
| `initializeConnection(opts)` / `InitializeConnectionOptions` | Send `CONNECT` for a key; resolves a `MessagePort`, or `null` if refused. Extra fields ride in the payload. |
|
|
476
|
-
| `registerConnectionsHandler(opts)` / `RegisterConnectionsHandlerOptions` | Register a key (and optional `path`) and answer its `CONNECT`s; resolves
|
|
711
|
+
| `registerConnectionsHandler(opts)` / `RegisterConnectionsHandlerOptions` | Register a key (and optional `path`) and answer its `CONNECT`s; resolves an awaitable cleanup. |
|
|
477
712
|
| `splitServiceUrl(url, separator = "~")` / `SplitServiceUrl` | Parse `<origin>/~<key>/<path>` into `{ url, key, baseUrl, path }`. |
|
|
478
713
|
|
|
479
714
|
ServiceWorker lifecycle:
|
|
@@ -500,6 +735,21 @@ Messaging primitives:
|
|
|
500
735
|
| `newRegistry(onError?)` / `Registry`, `NewRegistryResult`, `CleanupAction` | Cleanup registry. |
|
|
501
736
|
| `MessageTarget`, `MessageSource`, `MessageSink`, `MessageListener` | Port view types, re-exported from `@statewalker/webrun-rpc`. |
|
|
502
737
|
|
|
738
|
+
Same-origin, links and WebSockets (also on `./sw`):
|
|
739
|
+
|
|
740
|
+
| Export | Purpose |
|
|
741
|
+
| --- | --- |
|
|
742
|
+
| `SwHttpAdapter`, `SwHttpAdapterOptions`, `SwHttpRegistration`, `AttachWorkerOptions`, `WorkerLink` | The page side. |
|
|
743
|
+
| `SwHttpDispatcher`, `startHttpDispatcher`, `SwHttpDispatcherOptions` | The ServiceWorker side. |
|
|
744
|
+
| `HandlerTable`, `HandlerInfo`, `RouteFunction`, `leastInflightRoute` | Routing. |
|
|
745
|
+
| `serveHttpInWorker`, `WorkerHttpService`, `HandlerEndpoint` | The handler side (also on `./worker`). |
|
|
746
|
+
| `connectHttpLink`, `serveHttpLink`, `trackedLink`, `HttpLink`, `LinkLostError`, `HTTP_LINK_PROTOCOL` | HTTP over one `MessagePort`. |
|
|
747
|
+
| `holdLock`, `watchLock`, `newLockName`, `locksAvailable`, `PortRendezvous` | Liveness and reply-matching helpers. |
|
|
748
|
+
| `createWebSocketClass`, `PortWebSocket`, `WebSocketConnector`, `WebSocketConnection` | The client. |
|
|
749
|
+
| `upgradeWebSocket`, `ServerWebSocket`, `takePort`, `takeUpgrade`, `serveWebSocketUpgrade`, `newWebSocketUpgradeRequest`, `isWebSocketUpgrade`, `requestedProtocols`, `withHeaders` | The server end and the upgrade. |
|
|
750
|
+
| `serviceWorkerWebSocketClass`, `connectWebSocketThroughServiceWorker` | Sockets from any page a ServiceWorker of this package controls. |
|
|
751
|
+
| `SwPortHandler`, `SwPortDispatcher` | Version 1's bases, kept for subclasses. |
|
|
752
|
+
|
|
503
753
|
The root entry also re-exports all of `@statewalker/webrun-streams` and
|
|
504
754
|
`@statewalker/webrun-http-streams`.
|
|
505
755
|
|
|
@@ -507,10 +757,12 @@ The root entry also re-exports all of `@statewalker/webrun-streams` and
|
|
|
507
757
|
|
|
508
758
|
All four runtime dependencies are bundled into `dist/`:
|
|
509
759
|
|
|
510
|
-
- `@statewalker/webrun-
|
|
511
|
-
|
|
760
|
+
- `@statewalker/webrun-rpc`: the link transport (`connect` / `serve` over
|
|
761
|
+
`overPipe`), and the `MessageTarget` types.
|
|
762
|
+
- `@statewalker/webrun-http-streams`: HTTP over those streams
|
|
763
|
+
(`fetchOverDuplex` / `serveFetchOverDuplex`), version 1's stubs, and
|
|
764
|
+
`HttpError`.
|
|
512
765
|
- `@statewalker/webrun-streams`: iterator helpers and error serialisation.
|
|
513
|
-
- `@statewalker/webrun-rpc`: only the `MessageTarget` types.
|
|
514
766
|
- `idb-keyval`: a small IndexedDB key-value store that keeps registrations
|
|
515
767
|
across worker restarts.
|
|
516
768
|
|
|
@@ -520,7 +772,9 @@ All four runtime dependencies are bundled into `dist/`:
|
|
|
520
772
|
- `pnpm run test:browser`: builds, then runs `tests/browser/` in Chromium and
|
|
521
773
|
Firefox through Playwright against the built bundles, plus
|
|
522
774
|
`tests/packaging/`, which checks the published exports map. Needs the
|
|
523
|
-
browsers: `pnpm exec playwright install chromium firefox`.
|
|
775
|
+
browsers: `pnpm exec playwright install chromium firefox`. `links.browser.ts`
|
|
776
|
+
(workers, routing, restarts, sockets) and `relay-links.browser.ts` run in
|
|
777
|
+
Chromium only: they stop the ServiceWorker through CDP and use two origins.
|
|
524
778
|
|
|
525
779
|
## License
|
|
526
780
|
|
|
@@ -1,5 +1,22 @@
|
|
|
1
1
|
import type { MessageSink, MessageSource } from "./message-target.js";
|
|
2
2
|
export type ChannelCallHandler = (event: MessageEvent, params: unknown, ...transfers: MessagePort[]) => unknown;
|
|
3
|
+
/**
|
|
4
|
+
* A channel call's result that carries transferables, a `MessagePort` say:
|
|
5
|
+
* return `withTransfer({ port }, [port])` from a `handleChannelCalls` handler
|
|
6
|
+
* and `callChannel` resolves with `{ port }`.
|
|
7
|
+
*/
|
|
8
|
+
export declare function withTransfer<T>(value: T, transfer: Transferable[]): T;
|
|
9
|
+
/** Splits a handler's result into the value to post and its transfer list. */
|
|
10
|
+
export declare function unwrapTransfer(result: unknown): {
|
|
11
|
+
value: unknown;
|
|
12
|
+
transfer: Transferable[];
|
|
13
|
+
};
|
|
3
14
|
export declare function callChannel<T = unknown>(target: MessageSink, callType: string, params: unknown, ...transfers: Transferable[]): Promise<T>;
|
|
4
15
|
export declare function handleChannelCalls(target: MessageSource, callType: string, handler: ChannelCallHandler): () => void;
|
|
16
|
+
/**
|
|
17
|
+
* `callChannel`, failing after `ms` instead of waiting for ever: a peer that
|
|
18
|
+
* died (a ServiceWorker stopped mid-call) or that does not know `callType` (an
|
|
19
|
+
* older version) never answers.
|
|
20
|
+
*/
|
|
21
|
+
export declare function callChannelWithin<T = unknown>(ms: number, target: MessageSink, callType: string, params: unknown, ...transfers: Transferable[]): Promise<T>;
|
|
5
22
|
//# sourceMappingURL=data-calls.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"data-calls.d.ts","sourceRoot":"","sources":["../../src/core/data-calls.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"data-calls.d.ts","sourceRoot":"","sources":["../../src/core/data-calls.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,WAAW,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAC;AAEtE,MAAM,MAAM,kBAAkB,GAAG,CAC/B,KAAK,EAAE,YAAY,EACnB,MAAM,EAAE,OAAO,EACf,GAAG,SAAS,EAAE,WAAW,EAAE,KACxB,OAAO,CAAC;AAUb;;;;GAIG;AACH,wBAAgB,YAAY,CAAC,CAAC,EAAE,KAAK,EAAE,CAAC,EAAE,QAAQ,EAAE,YAAY,EAAE,GAAG,CAAC,CAErE;AAMD,8EAA8E;AAC9E,wBAAgB,cAAc,CAAC,MAAM,EAAE,OAAO,GAAG;IAAE,KAAK,EAAE,OAAO,CAAC;IAAC,QAAQ,EAAE,YAAY,EAAE,CAAA;CAAE,CAI5F;AAED,wBAAgB,WAAW,CAAC,CAAC,GAAG,OAAO,EACrC,MAAM,EAAE,WAAW,EACnB,QAAQ,EAAE,MAAM,EAChB,MAAM,EAAE,OAAO,EACf,GAAG,SAAS,EAAE,YAAY,EAAE,GAC3B,OAAO,CAAC,CAAC,CAAC,CAUZ;AAED,wBAAgB,kBAAkB,CAChC,MAAM,EAAE,aAAa,EACrB,QAAQ,EAAE,MAAM,EAChB,OAAO,EAAE,kBAAkB,GAC1B,MAAM,IAAI,CAiBZ;AAED;;;;GAIG;AACH,wBAAgB,iBAAiB,CAAC,CAAC,GAAG,OAAO,EAC3C,EAAE,EAAE,MAAM,EACV,MAAM,EAAE,WAAW,EACnB,QAAQ,EAAE,MAAM,EAChB,MAAM,EAAE,OAAO,EACf,GAAG,SAAS,EAAE,YAAY,EAAE,GAC3B,OAAO,CAAC,CAAC,CAAC,CAMZ"}
|
|
@@ -11,8 +11,10 @@ export declare const CLAIM_CALL = "CLAIM";
|
|
|
11
11
|
* - `uncontrolled`: the worker is active but the page is not controlled by it.
|
|
12
12
|
* - `unresponsive`: the page is controlled, but the worker did not answer the
|
|
13
13
|
* adapter's handshake in time.
|
|
14
|
+
* - `incompatible`: the worker answered, but runs another version of this
|
|
15
|
+
* package's link protocol.
|
|
14
16
|
*/
|
|
15
|
-
export type ServiceWorkerControlFailure = "activation-timeout" | "uncontrolled" | "unresponsive";
|
|
17
|
+
export type ServiceWorkerControlFailure = "activation-timeout" | "uncontrolled" | "unresponsive" | "incompatible";
|
|
16
18
|
/**
|
|
17
19
|
* Why a page could not get a working ServiceWorker. `reason` says which wait
|
|
18
20
|
* failed; check it (or `name`) rather than `instanceof`, because each of this
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"service-worker-control.d.ts","sourceRoot":"","sources":["../../src/core/service-worker-control.ts"],"names":[],"mappings":"AAKA;;;;GAIG;AACH,eAAO,MAAM,8BAA8B,QAAS,CAAC;AAUrD,kFAAkF;AAClF,eAAO,MAAM,UAAU,UAAU,CAAC;AAElC
|
|
1
|
+
{"version":3,"file":"service-worker-control.d.ts","sourceRoot":"","sources":["../../src/core/service-worker-control.ts"],"names":[],"mappings":"AAKA;;;;GAIG;AACH,eAAO,MAAM,8BAA8B,QAAS,CAAC;AAUrD,kFAAkF;AAClF,eAAO,MAAM,UAAU,UAAU,CAAC;AAElC;;;;;;;GAOG;AACH,MAAM,MAAM,2BAA2B,GACnC,oBAAoB,GACpB,cAAc,GACd,cAAc,GACd,cAAc,CAAC;AAEnB;;;;GAIG;AACH,qBAAa,yBAA0B,SAAQ,KAAK;IAClD,QAAQ,CAAC,MAAM,EAAE,2BAA2B,CAAC;IAC7C,YAAY,MAAM,EAAE,2BAA2B,EAAE,OAAO,EAAE,MAAM,EAI/D;CACF;AAED,MAAM,WAAW,yBAAyB;IACxC,uFAAuF;IACvF,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB;AAED,MAAM,WAAW,gCAAiC,SAAQ,yBAAyB;IACjF;;;;;;OAMG;IACH,oBAAoB,CAAC,EAAE,OAAO,CAAC;IAC/B,oDAAoD;IACpD,SAAS,CAAC,EAAE,sBAAsB,CAAC;CACpC;AAED;;;;;GAKG;AACH,wBAAsB,wBAAwB,CAC5C,YAAY,EAAE,yBAAyB,EACvC,EAAE,OAAwC,EAAE,GAAE,yBAA8B,GAC3E,OAAO,CAAC,aAAa,CAAC,CAaxB;AAED;;;;;;;;;;;;;;;;GAgBG;AACH,wBAAsB,yBAAyB,CAC7C,YAAY,EAAE,yBAAyB,EACvC,EACE,OAAwC,EACxC,oBAA4B,EAC5B,SAAmC,GACpC,GAAE,gCAAqC,GACvC,OAAO,CAAC,aAAa,CAAC,CA6CxB;AAED;;;;GAIG;AACH,wBAAgB,mBAAmB,CAAC,IAAI,EAAE,wBAAwB,GAAG,MAAM,IAAI,CAM9E"}
|
package/dist/index.d.ts
CHANGED
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,iBAAiB,CAAC;AAChC,cAAc,iBAAiB,CAAC;AAChC,cAAc,kBAAkB,CAAC"}
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,iBAAiB,CAAC;AAChC,cAAc,iBAAiB,CAAC;AAChC,cAAc,iBAAiB,CAAC;AAChC,cAAc,kBAAkB,CAAC;AACjC,cAAc,eAAe,CAAC;AAC9B,cAAc,eAAe,CAAC"}
|