@statewalker/webrun-http-browser 0.10.0 → 0.12.2

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.
Files changed (62) hide show
  1. package/README.md +155 -10
  2. package/dist/core/index.d.ts +1 -0
  3. package/dist/core/index.d.ts.map +1 -1
  4. package/dist/core/service-worker-control.d.ts +2 -1
  5. package/dist/core/service-worker-control.d.ts.map +1 -1
  6. package/dist/core/sw-scope.d.ts +31 -0
  7. package/dist/core/sw-scope.d.ts.map +1 -0
  8. package/dist/index.js +834 -225
  9. package/dist/link/http-link.d.ts +16 -3
  10. package/dist/link/http-link.d.ts.map +1 -1
  11. package/dist/relay/index-sw.d.ts +8 -2
  12. package/dist/relay/index-sw.d.ts.map +1 -1
  13. package/dist/relay/index.d.ts +1 -1
  14. package/dist/relay/index.d.ts.map +1 -1
  15. package/dist/relay-sw.js +433 -83
  16. package/dist/relay-worker.d.ts +1 -0
  17. package/dist/relay-worker.d.ts.map +1 -1
  18. package/dist/relay-worker.js +433 -83
  19. package/dist/sw/handler-endpoint.d.ts +5 -2
  20. package/dist/sw/handler-endpoint.d.ts.map +1 -1
  21. package/dist/sw/http-sw-dispatcher.d.ts +114 -7
  22. package/dist/sw/http-sw-dispatcher.d.ts.map +1 -1
  23. package/dist/sw/index.d.ts +1 -0
  24. package/dist/sw/index.d.ts.map +1 -1
  25. package/dist/sw/protocol.d.ts +3 -0
  26. package/dist/sw/protocol.d.ts.map +1 -1
  27. package/dist/sw/sw-dispatcher.d.ts +5 -2
  28. package/dist/sw/sw-dispatcher.d.ts.map +1 -1
  29. package/dist/sw/sw-http-adapter.d.ts +19 -4
  30. package/dist/sw/sw-http-adapter.d.ts.map +1 -1
  31. package/dist/sw/worker-service.d.ts +5 -2
  32. package/dist/sw/worker-service.d.ts.map +1 -1
  33. package/dist/sw-worker.js +596 -132
  34. package/dist/sw.js +829 -223
  35. package/dist/worker.js +622 -120
  36. package/dist/ws/frames.d.ts +6 -1
  37. package/dist/ws/frames.d.ts.map +1 -1
  38. package/dist/ws/server.d.ts +50 -2
  39. package/dist/ws/server.d.ts.map +1 -1
  40. package/dist/ws/socket-core.d.ts +5 -2
  41. package/dist/ws/socket-core.d.ts.map +1 -1
  42. package/dist/ws/upgrade.d.ts +12 -1
  43. package/dist/ws/upgrade.d.ts.map +1 -1
  44. package/package.json +5 -4
  45. package/src/core/index.ts +1 -0
  46. package/src/core/service-worker-control.ts +5 -3
  47. package/src/core/sw-scope.ts +27 -0
  48. package/src/link/http-link.ts +20 -4
  49. package/src/relay/index-sw.ts +15 -2
  50. package/src/relay/index.ts +2 -2
  51. package/src/relay-worker.ts +1 -0
  52. package/src/sw/handler-endpoint.ts +17 -4
  53. package/src/sw/http-sw-dispatcher.ts +267 -67
  54. package/src/sw/index.ts +5 -0
  55. package/src/sw/protocol.ts +11 -1
  56. package/src/sw/sw-dispatcher.ts +17 -11
  57. package/src/sw/sw-http-adapter.ts +36 -10
  58. package/src/sw/worker-service.ts +11 -4
  59. package/src/ws/frames.ts +18 -12
  60. package/src/ws/server.ts +166 -11
  61. package/src/ws/socket-core.ts +7 -2
  62. package/src/ws/upgrade.ts +22 -4
@@ -63,6 +63,11 @@ export declare function readFrame(data: unknown): WsFrame | undefined;
63
63
  export declare function postFrame(port: MessagePort, frame: WsFrame): void;
64
64
  /** The size a message counts for in `bufferedAmount`: UTF-8 bytes, or the buffer's length. */
65
65
  export declare function messageSize(data: string | ArrayBuffer): number;
66
- /** The UTF-8 length of `text`, without encoding it. */
66
+ /**
67
+ * The UTF-8 length of `text`, as `TextEncoder` would encode it (a lone surrogate counts as the 3
68
+ * bytes of U+FFFD). Every message is measured on both ends (`bufferedAmount` and the byte acks), so
69
+ * this runs natively: `encodeInto` a reused buffer, a chunk at a time, never splitting a surrogate
70
+ * pair across two chunks. A loop over the characters in JavaScript took about 30 times as long.
71
+ */
67
72
  export declare function utf8Length(text: string): number;
68
73
  //# sourceMappingURL=frames.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"frames.d.ts","sourceRoot":"","sources":["../../src/ws/frames.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;GAwBG;AAEH,0EAA0E;AAC1E,eAAO,MAAM,wBAAwB,IAAI,CAAC;AAE1C,qDAAqD;AACrD,eAAO,MAAM,oBAAoB,QAAS,CAAC;AAE3C,oEAAoE;AACpE,eAAO,MAAM,wBAAwB,OAAQ,CAAC;AAE9C,MAAM,MAAM,OAAO,GACf;IAAE,CAAC,EAAE,GAAG,CAAC;IAAC,CAAC,EAAE,MAAM,GAAG,WAAW,CAAA;CAAE,GACnC;IAAE,CAAC,EAAE,GAAG,CAAC;IAAC,IAAI,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CAAE,GACxC;IAAE,CAAC,EAAE,GAAG,CAAC;IAAC,EAAE,EAAE,MAAM,CAAA;CAAE,GACtB;IAAE,CAAC,EAAE,GAAG,CAAA;CAAE,GACV;IAAE,CAAC,EAAE,GAAG,CAAC;IAAC,CAAC,EAAE,MAAM,CAAA;CAAE,CAAC;AAE1B;;;;GAIG;AACH,MAAM,WAAW,QAAQ;IACvB,UAAU,CAAC,EAAE,EAAE,MAAM,IAAI,EAAE,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC;IAChD,YAAY,CAAC,EAAE,EAAE,OAAO,GAAG,IAAI,CAAC;IAChC,WAAW,CAAC,EAAE,EAAE,MAAM,IAAI,EAAE,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC;IACjD,aAAa,CAAC,EAAE,EAAE,OAAO,GAAG,IAAI,CAAC;CAClC;AAED,eAAO,MAAM,aAAa,EAAE,QAK3B,CAAC;AAEF,gFAAgF;AAChF,wBAAgB,SAAS,CAAC,IAAI,EAAE,OAAO,GAAG,OAAO,GAAG,SAAS,CA2B5D;AAED,6DAA6D;AAC7D,wBAAgB,SAAS,CAAC,IAAI,EAAE,WAAW,EAAE,KAAK,EAAE,OAAO,GAAG,IAAI,CAGjE;AAED,8FAA8F;AAC9F,wBAAgB,WAAW,CAAC,IAAI,EAAE,MAAM,GAAG,WAAW,GAAG,MAAM,CAE9D;AAED,uDAAuD;AACvD,wBAAgB,UAAU,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAe/C"}
1
+ {"version":3,"file":"frames.d.ts","sourceRoot":"","sources":["../../src/ws/frames.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;GAwBG;AAEH,0EAA0E;AAC1E,eAAO,MAAM,wBAAwB,IAAI,CAAC;AAE1C,qDAAqD;AACrD,eAAO,MAAM,oBAAoB,QAAS,CAAC;AAE3C,oEAAoE;AACpE,eAAO,MAAM,wBAAwB,OAAQ,CAAC;AAE9C,MAAM,MAAM,OAAO,GACf;IAAE,CAAC,EAAE,GAAG,CAAC;IAAC,CAAC,EAAE,MAAM,GAAG,WAAW,CAAA;CAAE,GACnC;IAAE,CAAC,EAAE,GAAG,CAAC;IAAC,IAAI,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CAAE,GACxC;IAAE,CAAC,EAAE,GAAG,CAAC;IAAC,EAAE,EAAE,MAAM,CAAA;CAAE,GACtB;IAAE,CAAC,EAAE,GAAG,CAAA;CAAE,GACV;IAAE,CAAC,EAAE,GAAG,CAAC;IAAC,CAAC,EAAE,MAAM,CAAA;CAAE,CAAC;AAE1B;;;;GAIG;AACH,MAAM,WAAW,QAAQ;IACvB,UAAU,CAAC,EAAE,EAAE,MAAM,IAAI,EAAE,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC;IAChD,YAAY,CAAC,EAAE,EAAE,OAAO,GAAG,IAAI,CAAC;IAChC,WAAW,CAAC,EAAE,EAAE,MAAM,IAAI,EAAE,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC;IACjD,aAAa,CAAC,EAAE,EAAE,OAAO,GAAG,IAAI,CAAC;CAClC;AAED,eAAO,MAAM,aAAa,EAAE,QAK3B,CAAC;AAEF,gFAAgF;AAChF,wBAAgB,SAAS,CAAC,IAAI,EAAE,OAAO,GAAG,OAAO,GAAG,SAAS,CA2B5D;AAED,6DAA6D;AAC7D,wBAAgB,SAAS,CAAC,IAAI,EAAE,WAAW,EAAE,KAAK,EAAE,OAAO,GAAG,IAAI,CAGjE;AAED,8FAA8F;AAC9F,wBAAgB,WAAW,CAAC,IAAI,EAAE,MAAM,GAAG,WAAW,GAAG,MAAM,CAE9D;AAOD;;;;;GAKG;AACH,wBAAgB,UAAU,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAW/C"}
@@ -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;
@@ -1 +1 @@
1
- {"version":3,"file":"server.d.ts","sourceRoot":"","sources":["../../src/ws/server.ts"],"names":[],"mappings":"AAAA,OAAO,EAAoC,KAAK,OAAO,EAAE,KAAK,QAAQ,EAAE,MAAM,aAAa,CAAC;AAC5F,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,0EAA0E;IAC1E,cAAc,CAAC,EAAE,MAAM,CAAC;CACzB;AAED;;;;;;;;;;;;;GAaG;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,SAAS,CAAS;IAC1B,OAAO,CAAC,MAAM,CAAiD;IAC/D,OAAO,CAAC,YAAY,CAAwB;IAC5C,OAAO,CAAC,SAAS,CAAc;IAC/B,OAAO,CAAC,MAAM,CAAU;IAExB,YAAY,IAAI,EAAE,WAAW,EAAE,OAAO,GAAE,sBAA2B,EAOlE;IAED,qCAAqC;IACrC,IAAI,QAAQ,IAAI,OAAO,CAEtB;IAED,uDAAuD;IACvD,MAAM,IAAI,IAAI,CAIb;IAED,IAAI,CAAC,IAAI,EAAE,MAAM,GAAG,WAAW,GAAG,eAAe,GAAG,IAAI,CAKvD;IAED,KAAK,CAAC,IAAI,SAAO,EAAE,MAAM,SAAK,GAAG,IAAI,CAWpC;IAED,UAAmB,QAAQ,CAAC,KAAK,EAAE,OAAO,CAAC,OAAO,EAAE;QAAE,CAAC,EAAE,GAAG,GAAG,GAAG,CAAA;KAAE,CAAC,GAAG,IAAI,CAM3E;IAED,SAAS,CAAC,gBAAgB,CAAC,IAAI,EAAE,MAAM,GAAG,WAAW,GAAG,IAAI,CAE3D;IAED,UAAmB,OAAO,CAAC,EAAE,EAAE,MAAM,GAAG,IAAI,CAO3C;IAED,UAAmB,SAAS,IAAI,IAAI,CAGnC;IAED,OAAO,CAAC,eAAe;CAQxB"}
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"}
@@ -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
- /** How long to wait for the echo of a close frame before giving up with 1006. */
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
- private _wakeDrainWaiters;
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":"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"}
1
+ {"version":3,"file":"socket-core.d.ts","sourceRoot":"","sources":["../../src/ws/socket-core.ts"],"names":[],"mappings":"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"}
@@ -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
- /** More headers for the handler to see (cookies, origin, authorization...). */
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`.
@@ -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,+EAA+E;IAC/E,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,CAYT;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,CAelB;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"}
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.10.0",
3
+ "version": "0.12.2",
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-rpc": "^0.8.0",
62
- "@statewalker/webrun-streams": "^0.2.3",
63
- "@statewalker/webrun-http-streams": "^0.4.0"
61
+ "@statewalker/webrun-http-streams": "^0.4.0",
62
+ "@statewalker/webrun-rpc": "^0.10.0",
63
+ "@statewalker/webrun-streams": "^0.2.3"
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
@@ -8,3 +8,4 @@ export * from "./data-channels.js";
8
8
  export * from "./message-target.js";
9
9
  export * from "./registry.js";
10
10
  export * from "./service-worker-control.js";
11
+ export type { FetchEventLike, ServiceWorkerClientLike, ServiceWorkerScope } from "./sw-scope.js";
@@ -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: ServiceWorkerGlobalScope): () => void {
171
- return handleChannelCalls(self, CLAIM_CALL, (event) => {
172
- const claimed = self.clients.claim().then(() => true);
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
+ }
@@ -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 a one-chunk window in both
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(
@@ -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?: (client: Client, key: string, path?: string) => boolean | Promise<boolean>;
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
- self: ServiceWorkerGlobalScope,
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) {
@@ -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
  /**
@@ -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 { ControlMessage } from "./protocol.js";
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
- /** Opens a socket to the handler `url` routes to, through the ServiceWorker. */
146
- async connectWebSocket(url: string, protocols: string[] = []): Promise<WebSocketConnection> {
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({ t: "ws-open", id, url, protocols } satisfies ControlMessage);
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