@statewalker/webrun-http-browser 0.9.0 → 0.12.1
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 +155 -10
- package/dist/core/index.d.ts +1 -0
- package/dist/core/index.d.ts.map +1 -1
- package/dist/core/service-worker-control.d.ts +2 -1
- package/dist/core/service-worker-control.d.ts.map +1 -1
- package/dist/core/sw-scope.d.ts +31 -0
- package/dist/core/sw-scope.d.ts.map +1 -0
- package/dist/index.js +908 -221
- package/dist/link/http-link.d.ts +16 -3
- package/dist/link/http-link.d.ts.map +1 -1
- package/dist/relay/index-sw.d.ts +8 -2
- package/dist/relay/index-sw.d.ts.map +1 -1
- package/dist/relay/index.d.ts +1 -1
- package/dist/relay/index.d.ts.map +1 -1
- package/dist/relay-sw.js +470 -81
- package/dist/relay-worker.d.ts +1 -0
- package/dist/relay-worker.d.ts.map +1 -1
- package/dist/relay-worker.js +470 -81
- package/dist/sw/handler-endpoint.d.ts +5 -2
- package/dist/sw/handler-endpoint.d.ts.map +1 -1
- package/dist/sw/http-sw-dispatcher.d.ts +114 -7
- package/dist/sw/http-sw-dispatcher.d.ts.map +1 -1
- package/dist/sw/index.d.ts +1 -0
- package/dist/sw/index.d.ts.map +1 -1
- package/dist/sw/protocol.d.ts +3 -0
- package/dist/sw/protocol.d.ts.map +1 -1
- package/dist/sw/sw-dispatcher.d.ts +5 -2
- package/dist/sw/sw-dispatcher.d.ts.map +1 -1
- package/dist/sw/sw-http-adapter.d.ts +19 -4
- package/dist/sw/sw-http-adapter.d.ts.map +1 -1
- package/dist/sw/worker-service.d.ts +5 -2
- package/dist/sw/worker-service.d.ts.map +1 -1
- package/dist/sw-worker.js +681 -141
- package/dist/sw.js +896 -218
- package/dist/worker.js +689 -115
- package/dist/ws/server.d.ts +50 -2
- package/dist/ws/server.d.ts.map +1 -1
- package/dist/ws/socket-core.d.ts +5 -2
- package/dist/ws/socket-core.d.ts.map +1 -1
- package/dist/ws/upgrade.d.ts +12 -1
- package/dist/ws/upgrade.d.ts.map +1 -1
- package/package.json +4 -3
- package/src/core/index.ts +1 -0
- package/src/core/service-worker-control.ts +5 -3
- package/src/core/sw-scope.ts +27 -0
- package/src/link/http-link.ts +20 -4
- package/src/relay/index-sw.ts +15 -2
- package/src/relay/index.ts +2 -2
- package/src/relay-worker.ts +1 -0
- package/src/sw/handler-endpoint.ts +17 -4
- package/src/sw/http-sw-dispatcher.ts +267 -67
- package/src/sw/index.ts +5 -0
- package/src/sw/protocol.ts +11 -1
- package/src/sw/sw-dispatcher.ts +17 -11
- package/src/sw/sw-http-adapter.ts +36 -10
- package/src/sw/worker-service.ts +11 -4
- package/src/ws/server.ts +166 -11
- package/src/ws/socket-core.ts +7 -2
- package/src/ws/upgrade.ts +22 -4
package/dist/ws/server.d.ts
CHANGED
|
@@ -6,8 +6,35 @@ export interface ServerWebSocketOptions {
|
|
|
6
6
|
/** The subprotocol the server picked, `""` for none. */
|
|
7
7
|
protocol?: string;
|
|
8
8
|
timers?: WsTimers;
|
|
9
|
-
/** How long `close()` waits for the client's echo, in ms. Default 5 s. */
|
|
9
|
+
/** How long `close()` waits for the client's echo, in ms. Default 5 s; `Infinity` for ever. */
|
|
10
10
|
closeTimeoutMs?: number;
|
|
11
|
+
/**
|
|
12
|
+
* When the heartbeat watch starts: `"open"` (the default) at once, so a client that never
|
|
13
|
+
* pings is closed with 1006 after three default periods; `"first-ping"` with the client's
|
|
14
|
+
* first ping, so a peer that does not ping at all (the other end of a pair kept in the same
|
|
15
|
+
* realm, say) is never closed for it. Once pings have started, both close a socket whose
|
|
16
|
+
* pings stop. Under `"first-ping"` a peer that never pings is never found dead.
|
|
17
|
+
*/
|
|
18
|
+
watch?: "open" | "first-ping";
|
|
19
|
+
/**
|
|
20
|
+
* Which heartbeat period the watch keeps: `"follow"` (the default) the one each ping
|
|
21
|
+
* announces, `"first"` the first ping's. A client announces a longer period when its page
|
|
22
|
+
* turns hidden (browsers throttle hidden pages' timers), and a closing tab turns hidden on its
|
|
23
|
+
* way out: following it notices a dead tab only after three of the longer periods.
|
|
24
|
+
*/
|
|
25
|
+
heartbeatPeriod?: "follow" | "first";
|
|
26
|
+
/** Lets `send()` before `accept()`; the frames wait in the port until the peer reads. */
|
|
27
|
+
sendBeforeAccept?: boolean;
|
|
28
|
+
/**
|
|
29
|
+
* Delivers the messages that arrive after `close()` until the peer's close frame does (they
|
|
30
|
+
* were in flight), as workerd does. By default they are dropped, as browsers do.
|
|
31
|
+
*/
|
|
32
|
+
deliverWhileClosing?: boolean;
|
|
33
|
+
/**
|
|
34
|
+
* The code `close()` sends when given none. Default 1000. 1005 ("no status code") is what a
|
|
35
|
+
* close frame without a code reads as on the other end, as `close()` does on workerd.
|
|
36
|
+
*/
|
|
37
|
+
defaultCloseCode?: number;
|
|
11
38
|
}
|
|
12
39
|
/**
|
|
13
40
|
* The server end of a socket over a `MessagePort`: what a handler gets from
|
|
@@ -21,7 +48,8 @@ export interface ServerWebSocketOptions {
|
|
|
21
48
|
* `whenDrained(limit)` waits for it to fall: the backpressure a producer
|
|
22
49
|
* applies.
|
|
23
50
|
* - When the client's pings stop for three heartbeat periods (a closed tab, a
|
|
24
|
-
* terminated worker), the socket closes with 1006.
|
|
51
|
+
* terminated worker), the socket closes with 1006. With `watch: "first-ping"`
|
|
52
|
+
* the watch starts only once the client pings.
|
|
25
53
|
*/
|
|
26
54
|
export declare class ServerWebSocket extends PortSocketCore {
|
|
27
55
|
static readonly CONNECTING = 0;
|
|
@@ -30,18 +58,38 @@ export declare class ServerWebSocket extends PortSocketCore {
|
|
|
30
58
|
static readonly CLOSED = 3;
|
|
31
59
|
readonly url: string;
|
|
32
60
|
readonly protocol: string;
|
|
61
|
+
private _binaryType;
|
|
62
|
+
private readonly _options;
|
|
33
63
|
private _accepted;
|
|
64
|
+
private _detached;
|
|
34
65
|
private _queue;
|
|
35
66
|
private _heartbeatMs;
|
|
36
67
|
private _lastPing;
|
|
68
|
+
/** Whether a ping (with a period a timer takes) arrived already. */
|
|
69
|
+
private _pinged;
|
|
37
70
|
private _watch;
|
|
38
71
|
constructor(port: MessagePort, options?: ServerWebSocketOptions);
|
|
39
72
|
/** Whether `accept()` was called. */
|
|
40
73
|
get accepted(): boolean;
|
|
74
|
+
/** How binary messages arrive: `ArrayBuffer`s (the default) or `Blob`s. Other values are ignored. */
|
|
75
|
+
get binaryType(): "blob" | "arraybuffer";
|
|
76
|
+
set binaryType(value: "blob" | "arraybuffer");
|
|
77
|
+
/**
|
|
78
|
+
* Hands this end's transport to another holder before it was accepted: the port to give the
|
|
79
|
+
* client (a pair's end returned in a 101, say), with the frames that reached this end first
|
|
80
|
+
* delivered ahead of the rest. This end is closed then, with no event, and answers nothing.
|
|
81
|
+
*/
|
|
82
|
+
detach(): MessagePort;
|
|
41
83
|
/** Starts delivering events, the queued ones first. */
|
|
42
84
|
accept(): void;
|
|
43
85
|
send(data: string | ArrayBuffer | ArrayBufferView): void;
|
|
44
86
|
close(code?: number, reason?: string): void;
|
|
87
|
+
/**
|
|
88
|
+
* Refuses a `close()` the endpoint may not make: by default a code outside RFC 6455 §7.4's
|
|
89
|
+
* sendable ones, or a reason over 123 bytes. A subclass with another platform's rules
|
|
90
|
+
* overrides it.
|
|
91
|
+
*/
|
|
92
|
+
protected checkClose(code: number | undefined, reason: string): void;
|
|
45
93
|
protected _deliver(frame: Extract<WsFrame, {
|
|
46
94
|
t: "m" | "c";
|
|
47
95
|
}>): void;
|
package/dist/ws/server.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"server.d.ts","sourceRoot":"","sources":["../../src/ws/server.ts"],"names":[],"mappings":"AAAA,OAAO,
|
|
1
|
+
{"version":3,"file":"server.d.ts","sourceRoot":"","sources":["../../src/ws/server.ts"],"names":[],"mappings":"AAAA,OAAO,EAKL,KAAK,OAAO,EACZ,KAAK,QAAQ,EACd,MAAM,aAAa,CAAC;AACrB,OAAO,EAML,cAAc,EAEf,MAAM,kBAAkB,CAAC;AAE1B,MAAM,WAAW,sBAAsB;IACrC,oCAAoC;IACpC,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,wDAAwD;IACxD,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,MAAM,CAAC,EAAE,QAAQ,CAAC;IAClB,+FAA+F;IAC/F,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB;;;;;;OAMG;IACH,KAAK,CAAC,EAAE,MAAM,GAAG,YAAY,CAAC;IAC9B;;;;;OAKG;IACH,eAAe,CAAC,EAAE,QAAQ,GAAG,OAAO,CAAC;IACrC,yFAAyF;IACzF,gBAAgB,CAAC,EAAE,OAAO,CAAC;IAC3B;;;OAGG;IACH,mBAAmB,CAAC,EAAE,OAAO,CAAC;IAC9B;;;OAGG;IACH,gBAAgB,CAAC,EAAE,MAAM,CAAC;CAC3B;AAED;;;;;;;;;;;;;;GAcG;AACH,qBAAa,eAAgB,SAAQ,cAAc;IACjD,MAAM,CAAC,QAAQ,CAAC,UAAU,KAAc;IACxC,MAAM,CAAC,QAAQ,CAAC,IAAI,KAAQ;IAC5B,MAAM,CAAC,QAAQ,CAAC,OAAO,KAAW;IAClC,MAAM,CAAC,QAAQ,CAAC,MAAM,KAAU;IAEhC,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAC;IACrB,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;IAC1B,OAAO,CAAC,WAAW,CAAyC;IAC5D,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAyB;IAClD,OAAO,CAAC,SAAS,CAAS;IAC1B,OAAO,CAAC,SAAS,CAAS;IAC1B,OAAO,CAAC,MAAM,CAAiD;IAC/D,OAAO,CAAC,YAAY,CAAwB;IAC5C,OAAO,CAAC,SAAS,CAAc;IAC/B,oEAAoE;IACpE,OAAO,CAAC,OAAO,CAAS;IACxB,OAAO,CAAC,MAAM,CAAU;IAExB,YAAY,IAAI,EAAE,WAAW,EAAE,OAAO,GAAE,sBAA2B,EAQlE;IAED,qCAAqC;IACrC,IAAI,QAAQ,IAAI,OAAO,CAEtB;IAED,qGAAqG;IACrG,IAAI,UAAU,IAAI,MAAM,GAAG,aAAa,CAEvC;IACD,IAAI,UAAU,CAAC,KAAK,EAAE,MAAM,GAAG,aAAa,EAE3C;IAED;;;;OAIG;IACH,MAAM,IAAI,WAAW,CA0DpB;IAED,uDAAuD;IACvD,MAAM,IAAI,IAAI,CAOb;IAED,IAAI,CAAC,IAAI,EAAE,MAAM,GAAG,WAAW,GAAG,eAAe,GAAG,IAAI,CAQvD;IAED,KAAK,CAAC,IAAI,CAAC,EAAE,MAAM,EAAE,MAAM,SAAK,GAAG,IAAI,CAGtC;IAED;;;;OAIG;IACH,SAAS,CAAC,UAAU,CAAC,IAAI,EAAE,MAAM,GAAG,SAAS,EAAE,MAAM,EAAE,MAAM,GAAG,IAAI,CAUnE;IAED,UAAmB,QAAQ,CAAC,KAAK,EAAE,OAAO,CAAC,OAAO,EAAE;QAAE,CAAC,EAAE,GAAG,GAAG,GAAG,CAAA;KAAE,CAAC,GAAG,IAAI,CAW3E;IAED,SAAS,CAAC,gBAAgB,CAAC,IAAI,EAAE,MAAM,GAAG,WAAW,GAAG,IAAI,CAI3D;IAED,UAAmB,OAAO,CAAC,EAAE,EAAE,MAAM,GAAG,IAAI,CAoB3C;IAED,UAAmB,SAAS,IAAI,IAAI,CAGnC;IAED,OAAO,CAAC,eAAe;CAQxB"}
|
package/dist/ws/socket-core.d.ts
CHANGED
|
@@ -22,7 +22,10 @@ export declare class WsCloseEvent extends Event {
|
|
|
22
22
|
export declare function newCloseEvent(init: WsCloseEventInit): Event;
|
|
23
23
|
export interface PortSocketOptions {
|
|
24
24
|
timers?: WsTimers;
|
|
25
|
-
/**
|
|
25
|
+
/**
|
|
26
|
+
* How long to wait for the echo of a close frame before giving up with 1006. `Infinity` waits
|
|
27
|
+
* for as long as it takes.
|
|
28
|
+
*/
|
|
26
29
|
closeTimeoutMs?: number;
|
|
27
30
|
}
|
|
28
31
|
/**
|
|
@@ -80,7 +83,7 @@ export declare abstract class PortSocketCore extends EventTarget {
|
|
|
80
83
|
protected _onCloseFrame(code: number, reason: string): void;
|
|
81
84
|
/** The socket is closed: release the port and tell the listeners. */
|
|
82
85
|
protected _finish(code: number, reason: string, wasClean: boolean, error?: boolean): void;
|
|
83
|
-
|
|
86
|
+
protected _wakeDrainWaiters(): void;
|
|
84
87
|
}
|
|
85
88
|
/** Copies `data` into a fresh `ArrayBuffer`: `send()` must never detach the caller's buffer. */
|
|
86
89
|
export declare function toArrayBuffer(data: ArrayBuffer | ArrayBufferView): ArrayBuffer;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"socket-core.d.ts","sourceRoot":"","sources":["../../src/ws/socket-core.ts"],"names":[],"mappings":"AAAA,OAAO,EAML,KAAK,OAAO,EACZ,KAAK,QAAQ,EACd,MAAM,aAAa,CAAC;AAErB,eAAO,MAAM,UAAU,IAAI,CAAC;AAC5B,eAAO,MAAM,IAAI,IAAI,CAAC;AACtB,eAAO,MAAM,OAAO,IAAI,CAAC;AACzB,eAAO,MAAM,MAAM,IAAI,CAAC;AAExB,MAAM,WAAW,gBAAiB,SAAQ,SAAS;IACjD,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,QAAQ,CAAC,EAAE,OAAO,CAAC;CACpB;AAED;;;GAGG;AACH,qBAAa,YAAa,SAAQ,KAAK;IACrC,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,QAAQ,CAAC,QAAQ,EAAE,OAAO,CAAC;IAC3B,YAAY,IAAI,EAAE,MAAM,EAAE,IAAI,GAAE,gBAAqB,EAKpD;CACF;AAED,uEAAuE;AACvE,wBAAgB,aAAa,CAAC,IAAI,EAAE,gBAAgB,GAAG,KAAK,CAG3D;AAED,MAAM,WAAW,iBAAiB;IAChC,MAAM,CAAC,EAAE,QAAQ,CAAC;IAClB
|
|
1
|
+
{"version":3,"file":"socket-core.d.ts","sourceRoot":"","sources":["../../src/ws/socket-core.ts"],"names":[],"mappings":"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"}
|
package/dist/ws/upgrade.d.ts
CHANGED
|
@@ -18,7 +18,11 @@ export declare const WS_VERSION_HEADER = "x-webrun-ws-version";
|
|
|
18
18
|
export interface WebSocketUpgradeInit {
|
|
19
19
|
/** Requested subprotocols, in order of preference. */
|
|
20
20
|
protocols?: string[];
|
|
21
|
-
/**
|
|
21
|
+
/**
|
|
22
|
+
* More headers for the handler to see (what a `route` function picks by, origin...). They are
|
|
23
|
+
* the caller's word: nothing checks them, so a handler trusts a `cookie` or an `authorization`
|
|
24
|
+
* here no more than its caller. `sec-websocket-protocol` comes from `protocols` only.
|
|
25
|
+
*/
|
|
22
26
|
headers?: HeadersInit;
|
|
23
27
|
}
|
|
24
28
|
/**
|
|
@@ -63,6 +67,13 @@ interface PendingUpgrade {
|
|
|
63
67
|
* hands it to the caller.
|
|
64
68
|
*/
|
|
65
69
|
export declare function upgradeWebSocket(request: Request, options?: UpgradeWebSocketOptions): WebSocketUpgrade;
|
|
70
|
+
/**
|
|
71
|
+
* A 101 for a socket whose server end the handler runs itself, on the other end of `port`
|
|
72
|
+
* (a server of its own over this package's frames, say): what `upgradeWebSocket` returns, minus
|
|
73
|
+
* the `ServerWebSocket`. The host hands `port` to the caller as it would for `upgradeWebSocket`
|
|
74
|
+
* (`takePort`), and `protocol` (`""` for none) is the subprotocol picked.
|
|
75
|
+
*/
|
|
76
|
+
export declare function webSocketUpgradeResponse(port: MessagePort, protocol?: string): Response;
|
|
66
77
|
/**
|
|
67
78
|
* The port to hand to the caller, for a response from `upgradeWebSocket`.
|
|
68
79
|
* Taken once: a second call returns `undefined`.
|
package/dist/ws/upgrade.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"upgrade.d.ts","sourceRoot":"","sources":["../../src/ws/upgrade.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,eAAe,EAAE,KAAK,sBAAsB,EAAE,MAAM,aAAa,CAAC;AAE3E;;;;;;;;;;;;;GAaG;AAEH,8EAA8E;AAC9E,eAAO,MAAM,iBAAiB,wBAAwB,CAAC;AAEvD,MAAM,WAAW,oBAAoB;IACnC,sDAAsD;IACtD,SAAS,CAAC,EAAE,MAAM,EAAE,CAAC;IACrB
|
|
1
|
+
{"version":3,"file":"upgrade.d.ts","sourceRoot":"","sources":["../../src/ws/upgrade.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,eAAe,EAAE,KAAK,sBAAsB,EAAE,MAAM,aAAa,CAAC;AAE3E;;;;;;;;;;;;;GAaG;AAEH,8EAA8E;AAC9E,eAAO,MAAM,iBAAiB,wBAAwB,CAAC;AAEvD,MAAM,WAAW,oBAAoB;IACnC,sDAAsD;IACtD,SAAS,CAAC,EAAE,MAAM,EAAE,CAAC;IACrB;;;;OAIG;IACH,OAAO,CAAC,EAAE,WAAW,CAAC;CACvB;AAED;;;GAGG;AACH,wBAAgB,0BAA0B,CACxC,GAAG,EAAE,MAAM,GAAG,GAAG,EACjB,EAAE,SAAc,EAAE,OAAO,EAAE,GAAE,oBAAyB,GACrD,OAAO,CAeT;AAED;;;GAGG;AACH,wBAAgB,WAAW,CAAC,OAAO,EAAE,OAAO,EAAE,OAAO,EAAE,OAAO,GAAG,OAAO,CAGvE;AAED,8CAA8C;AAC9C,wBAAgB,kBAAkB,CAAC,OAAO,EAAE,OAAO,GAAG,OAAO,CAE5D;AAED,mEAAmE;AACnE,wBAAgB,kBAAkB,CAAC,OAAO,EAAE,OAAO,GAAG,MAAM,EAAE,CAO7D;AAED,MAAM,WAAW,uBAAwB,SAAQ,IAAI,CAAC,sBAAsB,EAAE,KAAK,CAAC;CAAG;AAEvF,MAAM,WAAW,gBAAgB;IAC/B,6DAA6D;IAC7D,MAAM,EAAE,eAAe,CAAC;IACxB,8CAA8C;IAC9C,QAAQ,EAAE,QAAQ,CAAC;CACpB;AAED,UAAU,cAAc;IACtB,IAAI,EAAE,WAAW,CAAC;IAClB,QAAQ,EAAE,MAAM,CAAC;CAClB;AAWD;;;;;;;;;;;;;;GAcG;AACH,wBAAgB,gBAAgB,CAC9B,OAAO,EAAE,OAAO,EAChB,OAAO,GAAE,uBAA4B,GACpC,gBAAgB,CAOlB;AAED;;;;;GAKG;AACH,wBAAgB,wBAAwB,CAAC,IAAI,EAAE,WAAW,EAAE,QAAQ,SAAK,GAAG,QAAQ,CAWnF;AAED;;;GAGG;AACH,wBAAgB,QAAQ,CAAC,QAAQ,EAAE,QAAQ,GAAG,WAAW,GAAG,SAAS,CAEpE;AAED,0DAA0D;AAC1D,wBAAgB,WAAW,CAAC,QAAQ,EAAE,QAAQ,GAAG,cAAc,GAAG,SAAS,CAK1E;AAED,MAAM,MAAM,sBAAsB,GAC9B;IAAE,EAAE,EAAE,IAAI,CAAC;IAAC,IAAI,EAAE,WAAW,CAAC;IAAC,QAAQ,EAAE,MAAM,CAAA;CAAE,GACjD;IAAE,EAAE,EAAE,KAAK,CAAC;IAAC,MAAM,EAAE,MAAM,CAAC;IAAC,OAAO,EAAE,MAAM,CAAA;CAAE,CAAC;AAEnD,MAAM,WAAW,yBAA0B,SAAQ,oBAAoB;IACrE,GAAG,EAAE,MAAM,CAAC;CACb;AAED;;;;;GAKG;AACH,wBAAsB,qBAAqB,CACzC,OAAO,EAAE,CAAC,OAAO,EAAE,OAAO,KAAK,QAAQ,GAAG,OAAO,CAAC,QAAQ,CAAC,EAC3D,EAAE,GAAG,EAAE,SAAc,EAAE,OAAO,EAAE,EAAE,yBAAyB,GAC1D,OAAO,CAAC,sBAAsB,CAAC,CA4BjC"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@statewalker/webrun-http-browser",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.12.1",
|
|
4
4
|
"private": false,
|
|
5
5
|
"type": "module",
|
|
6
6
|
"description": "ServiceWorker-based HTTP and WebSocket server for browsers: handlers in pages and Dedicated Workers, same-origin and relay modes, streams with backpressure",
|
|
@@ -58,9 +58,9 @@
|
|
|
58
58
|
],
|
|
59
59
|
"dependencies": {
|
|
60
60
|
"idb-keyval": "^6.3.0",
|
|
61
|
-
"@statewalker/webrun-http-streams": "^0.3.2",
|
|
62
61
|
"@statewalker/webrun-streams": "^0.2.3",
|
|
63
|
-
"@statewalker/webrun-rpc": "^0.
|
|
62
|
+
"@statewalker/webrun-rpc": "^0.10.0",
|
|
63
|
+
"@statewalker/webrun-http-streams": "^0.4.0"
|
|
64
64
|
},
|
|
65
65
|
"devDependencies": {
|
|
66
66
|
"@biomejs/biome": "^2.5.15",
|
|
@@ -80,6 +80,7 @@
|
|
|
80
80
|
"scripts": {
|
|
81
81
|
"build": "rimraf dist && rolldown -c && tsc --emitDeclarationOnly --declaration",
|
|
82
82
|
"test": "vitest run",
|
|
83
|
+
"bench": "vitest run --config vitest.bench.config.ts && echo \"all benchmarks passed\"",
|
|
83
84
|
"test:browser": "pnpm run build && vitest run --config vitest.browser.config.ts",
|
|
84
85
|
"lint": "biome check src tests",
|
|
85
86
|
"serve": "http-server -p 5173 -c-1 -s .",
|
package/src/core/index.ts
CHANGED
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
import { callChannel, handleChannelCalls } from "./data-calls.js";
|
|
4
4
|
import { withDeadline } from "./deadline.js";
|
|
5
|
+
import type { ServiceWorkerScope } from "./sw-scope.js";
|
|
5
6
|
|
|
6
7
|
/**
|
|
7
8
|
* How long, by default, the page waits for its ServiceWorker to activate and
|
|
@@ -167,9 +168,10 @@ export async function awaitServiceWorkerControl(
|
|
|
167
168
|
* `clients.claim()`, which takes over every uncontrolled client in scope.
|
|
168
169
|
* Returns a function that stops answering.
|
|
169
170
|
*/
|
|
170
|
-
export function handleClaimRequests(self:
|
|
171
|
-
|
|
172
|
-
|
|
171
|
+
export function handleClaimRequests(self: ServiceWorkerScope): () => void {
|
|
172
|
+
const sw = self as unknown as ServiceWorkerGlobalScope;
|
|
173
|
+
return handleChannelCalls(sw, CLAIM_CALL, (event) => {
|
|
174
|
+
const claimed = sw.clients.claim().then(() => true);
|
|
173
175
|
(event as unknown as Partial<ExtendableMessageEvent>).waitUntil?.(claimed);
|
|
174
176
|
return claimed;
|
|
175
177
|
});
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* A ServiceWorker's global scope, as this package's API takes it: structurally, so that code
|
|
3
|
+
* importing the package's declarations compiles with the DOM lib alone. TypeScript's
|
|
4
|
+
* `ServiceWorkerGlobalScope` is in the WebWorker lib, which a page's or a library's
|
|
5
|
+
* compilation does not load. A ServiceWorker's `self` is one.
|
|
6
|
+
*/
|
|
7
|
+
export interface ServiceWorkerScope extends EventTarget {
|
|
8
|
+
readonly location: { readonly href: string; readonly origin: string };
|
|
9
|
+
readonly registration?: { readonly scope: string };
|
|
10
|
+
readonly clients: unknown;
|
|
11
|
+
skipWaiting(): Promise<void>;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
/** A ServiceWorker's `fetch` event, structurally (see `ServiceWorkerScope`). */
|
|
15
|
+
export interface FetchEventLike extends Event {
|
|
16
|
+
readonly request: Request;
|
|
17
|
+
respondWith(response: Response | PromiseLike<Response>): void;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
/**
|
|
21
|
+
* A ServiceWorker's client (a page or a worker it controls), structurally (see
|
|
22
|
+
* `ServiceWorkerScope`). A `Client` is one.
|
|
23
|
+
*/
|
|
24
|
+
export interface ServiceWorkerClientLike {
|
|
25
|
+
readonly id: string;
|
|
26
|
+
readonly url: string;
|
|
27
|
+
}
|
package/src/link/http-link.ts
CHANGED
|
@@ -8,8 +8,11 @@ import { asyncDisposable } from "./async-dispose.js";
|
|
|
8
8
|
* own `handleStreams` / `sendStream` (no backpressure); version 2 is
|
|
9
9
|
* webrun-rpc's `connect` / `serve` over `overPipe` with webrun-http-streams'
|
|
10
10
|
* `fetchOverDuplex` / `serveFetchOverDuplex`: one port per link, calls
|
|
11
|
-
* multiplexed on it, each call a stream with
|
|
12
|
-
* directions, and cancellation that reaches the handler.
|
|
11
|
+
* multiplexed on it, each call a stream with backpressure in both
|
|
12
|
+
* directions, and cancellation that reaches the handler. A call's port with a
|
|
13
|
+
* window (`HttpLinkOptions.window`) pipelines its chunks where both ends speak
|
|
14
|
+
* it, and goes one confirmed chunk at a time otherwise, so the window needs
|
|
15
|
+
* no new version.
|
|
13
16
|
*/
|
|
14
17
|
export const HTTP_LINK_PROTOCOL = "webrun-http-link/2";
|
|
15
18
|
|
|
@@ -34,8 +37,21 @@ export interface HttpLinkOptions {
|
|
|
34
37
|
* reads the upload afterwards keeps it as long as it keeps reading.
|
|
35
38
|
*/
|
|
36
39
|
requestIdleMs?: number;
|
|
40
|
+
/**
|
|
41
|
+
* The calling end only: the flow-control window, in bytes, that every
|
|
42
|
+
* request's port asks for (webrun-rpc's `window`; default 256 KiB). On it,
|
|
43
|
+
* request and response bodies are pipelined: chunks leave without waiting
|
|
44
|
+
* for a confirmation each, and a reader that stops holds about one window
|
|
45
|
+
* of them. `0` turns the window off: one confirmed chunk at a time, the
|
|
46
|
+
* envelopes of a link with no window. An answering end of an older version
|
|
47
|
+
* falls back to that by itself.
|
|
48
|
+
*/
|
|
49
|
+
window?: number;
|
|
37
50
|
}
|
|
38
51
|
|
|
52
|
+
/** The calling end's default `HttpLinkOptions.window`: 256 KiB. */
|
|
53
|
+
const DEFAULT_HTTP_LINK_WINDOW = 256 * 1024;
|
|
54
|
+
|
|
39
55
|
/** The calling end of a link: sends requests, gets responses. */
|
|
40
56
|
export interface HttpLink {
|
|
41
57
|
/** Sends `request` and resolves with the response, whose body streams. */
|
|
@@ -77,10 +93,10 @@ const LINK_CLOSE = "webrun-http:link-close";
|
|
|
77
93
|
/** Opens the calling end of a link on `port` (one port per link). */
|
|
78
94
|
export async function connectHttpLink(
|
|
79
95
|
port: MessagePort,
|
|
80
|
-
{ streamTimeout, maxPorts }: HttpLinkOptions = {},
|
|
96
|
+
{ streamTimeout, maxPorts, window = DEFAULT_HTTP_LINK_WINDOW }: HttpLinkOptions = {},
|
|
81
97
|
): Promise<HttpLink> {
|
|
82
98
|
const { call, close } = await connect({
|
|
83
|
-
mux: overPipe(port, { codec: structuredCodec, side: "initiator", maxPorts }),
|
|
99
|
+
mux: overPipe(port, { codec: structuredCodec, side: "initiator", maxPorts, window }),
|
|
84
100
|
timeout: streamTimeout,
|
|
85
101
|
});
|
|
86
102
|
return trackedLink(
|
package/src/relay/index-sw.ts
CHANGED
|
@@ -3,6 +3,7 @@ import { get, set } from "idb-keyval";
|
|
|
3
3
|
import { callChannel, handleChannelCalls, withTransfer } from "../core/data-calls.js";
|
|
4
4
|
import { newRegistry } from "../core/registry.js";
|
|
5
5
|
import { handleClaimRequests } from "../core/service-worker-control.js";
|
|
6
|
+
import type { ServiceWorkerClientLike, ServiceWorkerScope } from "../core/sw-scope.js";
|
|
6
7
|
import { HTTP_LINK_PROTOCOL } from "../link/http-link.js";
|
|
7
8
|
import { WS_CONNECT_CALL } from "../sw/protocol.js";
|
|
8
9
|
import type { WebSocketConnection } from "../ws/client.js";
|
|
@@ -137,9 +138,18 @@ export interface RelayServiceWorkerOptions {
|
|
|
137
138
|
* mount an allowed key at `/index.html` and outrank `/` on longest-prefix.
|
|
138
139
|
* Also consulted for `UNREGISTER`, with the path the key is mounted at.
|
|
139
140
|
*/
|
|
140
|
-
canRegister?: (
|
|
141
|
+
canRegister?: (
|
|
142
|
+
client: ServiceWorkerClientLike,
|
|
143
|
+
key: string,
|
|
144
|
+
path?: string,
|
|
145
|
+
) => boolean | Promise<boolean>;
|
|
141
146
|
/** Per-stream inactivity timeout of the links to services, in ms. Default none. */
|
|
142
147
|
streamTimeout?: number;
|
|
148
|
+
/**
|
|
149
|
+
* The window, in bytes, of the links to services: `HttpLinkOptions.window`.
|
|
150
|
+
* Default 256 KiB; 0 turns it off.
|
|
151
|
+
*/
|
|
152
|
+
window?: number;
|
|
143
153
|
/** Default `"last-wins"`, the behaviour before this option existed. */
|
|
144
154
|
takeover?: "first-wins" | "last-wins";
|
|
145
155
|
/** Stamp headers on responses the relay makes. Not applied to network fetches. */
|
|
@@ -171,9 +181,11 @@ export function mayRegister(args: {
|
|
|
171
181
|
* channel calls used by the page-side relay client.
|
|
172
182
|
*/
|
|
173
183
|
export function startRelayServiceWorker(
|
|
174
|
-
|
|
184
|
+
scope: ServiceWorkerScope,
|
|
175
185
|
options: RelayServiceWorkerOptions = {},
|
|
176
186
|
): () => void {
|
|
187
|
+
// Typed structurally in the signature so the declarations need no WebWorker lib.
|
|
188
|
+
const self = scope as unknown as ServiceWorkerGlobalScope;
|
|
177
189
|
const [register, clear] = newRegistry();
|
|
178
190
|
const mounts = newMountTable({ exclude: options.exclude });
|
|
179
191
|
// The keys the HOST declared. Kept so a page's REGISTER/UNREGISTER cannot
|
|
@@ -339,6 +351,7 @@ export function startRelayServiceWorker(
|
|
|
339
351
|
if (!reply) throw HttpError.errorForbidden(params);
|
|
340
352
|
const response = await sendOverConnection(channel.port1, reply, request, {
|
|
341
353
|
streamTimeout: options.streamTimeout,
|
|
354
|
+
window: options.window,
|
|
342
355
|
});
|
|
343
356
|
return options.decorateResponse?.(response, request) ?? response;
|
|
344
357
|
} catch (error) {
|
package/src/relay/index.ts
CHANGED
|
@@ -180,7 +180,7 @@ export async function initHttpService(
|
|
|
180
180
|
*/
|
|
181
181
|
export async function callHttpService(
|
|
182
182
|
request: Request,
|
|
183
|
-
{ key, port, streamTimeout }: ServiceOptions,
|
|
183
|
+
{ key, port, streamTimeout, window }: ServiceOptions,
|
|
184
184
|
): Promise<Response> {
|
|
185
185
|
const channel = new MessageChannel();
|
|
186
186
|
const reply = await callChannel<boolean | ConnectReply>(
|
|
@@ -193,7 +193,7 @@ export async function callHttpService(
|
|
|
193
193
|
channel.port1.close();
|
|
194
194
|
throw new Error(`No service with key "${key}"`);
|
|
195
195
|
}
|
|
196
|
-
return await sendOverConnection(channel.port1, reply, request, { streamTimeout });
|
|
196
|
+
return await sendOverConnection(channel.port1, reply, request, { streamTimeout, window });
|
|
197
197
|
}
|
|
198
198
|
|
|
199
199
|
/**
|
package/src/relay-worker.ts
CHANGED
|
@@ -15,6 +15,7 @@
|
|
|
15
15
|
* import.
|
|
16
16
|
*/
|
|
17
17
|
|
|
18
|
+
export type { ServiceWorkerClientLike, ServiceWorkerScope } from "./core/sw-scope.js";
|
|
18
19
|
export type { RelayServiceWorkerOptions } from "./relay/index-sw.js";
|
|
19
20
|
export { startRelayServiceWorker } from "./relay/index-sw.js";
|
|
20
21
|
export type { MountSpec } from "./relay/mount-table.js";
|
|
@@ -10,7 +10,7 @@ import { watchLock } from "../link/locks.js";
|
|
|
10
10
|
import { PortRendezvous } from "../link/rendezvous.js";
|
|
11
11
|
import type { WebSocketConnection } from "../ws/client.js";
|
|
12
12
|
import { serveWebSocketUpgrade } from "../ws/upgrade.js";
|
|
13
|
-
import type
|
|
13
|
+
import { type ControlMessage, headerPairs } from "./protocol.js";
|
|
14
14
|
|
|
15
15
|
export type FetchHandler = (request: Request) => Response | Promise<Response>;
|
|
16
16
|
|
|
@@ -142,8 +142,15 @@ export class HandlerEndpoint {
|
|
|
142
142
|
return await (link.up as HttpLink).send(request);
|
|
143
143
|
}
|
|
144
144
|
|
|
145
|
-
/**
|
|
146
|
-
|
|
145
|
+
/**
|
|
146
|
+
* Opens a socket to the handler `url` routes to, through the ServiceWorker. The handler sees
|
|
147
|
+
* `headers` on the upgrade request, and so does a `route` function choosing it.
|
|
148
|
+
*/
|
|
149
|
+
async connectWebSocket(
|
|
150
|
+
url: string,
|
|
151
|
+
protocols: string[] = [],
|
|
152
|
+
headers?: HeadersInit,
|
|
153
|
+
): Promise<WebSocketConnection> {
|
|
147
154
|
const link = await this._linkWith("ctl");
|
|
148
155
|
const id = this._sockets.newId();
|
|
149
156
|
const answer = this._sockets.wait(
|
|
@@ -151,7 +158,13 @@ export class HandlerEndpoint {
|
|
|
151
158
|
this.options.wsConnectTimeoutMs ?? 15_000,
|
|
152
159
|
`the socket request for ${url}`,
|
|
153
160
|
);
|
|
154
|
-
link.ctl?.postMessage({
|
|
161
|
+
link.ctl?.postMessage({
|
|
162
|
+
t: "ws-open",
|
|
163
|
+
id,
|
|
164
|
+
url,
|
|
165
|
+
protocols,
|
|
166
|
+
headers: headerPairs(headers),
|
|
167
|
+
} satisfies ControlMessage);
|
|
155
168
|
return await answer;
|
|
156
169
|
}
|
|
157
170
|
|