transport-io 0.0.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.
Files changed (99) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +28 -0
  3. package/dist/adapter.d.ts +69 -0
  4. package/dist/adapter.d.ts.map +1 -0
  5. package/dist/adapter.js +51 -0
  6. package/dist/adapter.js.map +1 -0
  7. package/dist/client.d.ts +60 -0
  8. package/dist/client.d.ts.map +1 -0
  9. package/dist/client.js +162 -0
  10. package/dist/client.js.map +1 -0
  11. package/dist/codec.d.ts +5 -0
  12. package/dist/codec.d.ts.map +1 -0
  13. package/dist/codec.js +47 -0
  14. package/dist/codec.js.map +1 -0
  15. package/dist/contract.d.ts +79 -0
  16. package/dist/contract.d.ts.map +1 -0
  17. package/dist/contract.js +54 -0
  18. package/dist/contract.js.map +1 -0
  19. package/dist/datagram.d.ts +29 -0
  20. package/dist/datagram.d.ts.map +1 -0
  21. package/dist/datagram.js +92 -0
  22. package/dist/datagram.js.map +1 -0
  23. package/dist/errors.d.ts +8 -0
  24. package/dist/errors.d.ts.map +1 -0
  25. package/dist/errors.js +11 -0
  26. package/dist/errors.js.map +1 -0
  27. package/dist/framer.d.ts +21 -0
  28. package/dist/framer.d.ts.map +1 -0
  29. package/dist/framer.js +110 -0
  30. package/dist/framer.js.map +1 -0
  31. package/dist/handshake.d.ts +34 -0
  32. package/dist/handshake.d.ts.map +1 -0
  33. package/dist/handshake.js +79 -0
  34. package/dist/handshake.js.map +1 -0
  35. package/dist/hub.d.ts +43 -0
  36. package/dist/hub.d.ts.map +1 -0
  37. package/dist/hub.js +149 -0
  38. package/dist/hub.js.map +1 -0
  39. package/dist/index.d.ts +19 -0
  40. package/dist/index.d.ts.map +1 -0
  41. package/dist/index.js +18 -0
  42. package/dist/index.js.map +1 -0
  43. package/dist/origin.d.ts +18 -0
  44. package/dist/origin.d.ts.map +1 -0
  45. package/dist/origin.js +72 -0
  46. package/dist/origin.js.map +1 -0
  47. package/dist/protocol.d.ts +79 -0
  48. package/dist/protocol.d.ts.map +1 -0
  49. package/dist/protocol.js +76 -0
  50. package/dist/protocol.js.map +1 -0
  51. package/dist/queue.d.ts +45 -0
  52. package/dist/queue.d.ts.map +1 -0
  53. package/dist/queue.js +94 -0
  54. package/dist/queue.js.map +1 -0
  55. package/dist/server.d.ts +45 -0
  56. package/dist/server.d.ts.map +1 -0
  57. package/dist/server.js +127 -0
  58. package/dist/server.js.map +1 -0
  59. package/dist/session.d.ts +94 -0
  60. package/dist/session.d.ts.map +1 -0
  61. package/dist/session.js +645 -0
  62. package/dist/session.js.map +1 -0
  63. package/dist/testing/hostile-adapter.d.ts +44 -0
  64. package/dist/testing/hostile-adapter.d.ts.map +1 -0
  65. package/dist/testing/hostile-adapter.js +116 -0
  66. package/dist/testing/hostile-adapter.js.map +1 -0
  67. package/dist/testing/index.d.ts +8 -0
  68. package/dist/testing/index.d.ts.map +1 -0
  69. package/dist/testing/index.js +8 -0
  70. package/dist/testing/index.js.map +1 -0
  71. package/dist/transport/browser.d.ts +8 -0
  72. package/dist/transport/browser.d.ts.map +1 -0
  73. package/dist/transport/browser.js +89 -0
  74. package/dist/transport/browser.js.map +1 -0
  75. package/dist/transport/fails.node.d.ts +33 -0
  76. package/dist/transport/fails.node.d.ts.map +1 -0
  77. package/dist/transport/fails.node.js +184 -0
  78. package/dist/transport/fails.node.js.map +1 -0
  79. package/dist/transport/loopback.d.ts +11 -0
  80. package/dist/transport/loopback.d.ts.map +1 -0
  81. package/dist/transport/loopback.js +98 -0
  82. package/dist/transport/loopback.js.map +1 -0
  83. package/dist/transport/moq.node.d.ts +19 -0
  84. package/dist/transport/moq.node.d.ts.map +1 -0
  85. package/dist/transport/moq.node.js +211 -0
  86. package/dist/transport/moq.node.js.map +1 -0
  87. package/dist/transport/parity-suite.d.ts +40 -0
  88. package/dist/transport/parity-suite.d.ts.map +1 -0
  89. package/dist/transport/parity-suite.js +133 -0
  90. package/dist/transport/parity-suite.js.map +1 -0
  91. package/dist/transport/types.d.ts +36 -0
  92. package/dist/transport/types.d.ts.map +1 -0
  93. package/dist/transport/types.js +2 -0
  94. package/dist/transport/types.js.map +1 -0
  95. package/dist/transport/unreliable.d.ts +37 -0
  96. package/dist/transport/unreliable.d.ts.map +1 -0
  97. package/dist/transport/unreliable.js +59 -0
  98. package/dist/transport/unreliable.js.map +1 -0
  99. package/package.json +55 -0
package/dist/server.js ADDED
@@ -0,0 +1,127 @@
1
+ /** Server surface. Transport-agnostic: it accepts a Connection from the seam. */
2
+ import { MemoryAdapter } from './adapter.js';
3
+ import { buildEventTable, } from './contract.js';
4
+ import { Hub } from './hub.js';
5
+ import { OriginAllocator } from './origin.js';
6
+ import { CloseCode } from './protocol.js';
7
+ import { Session } from './session.js';
8
+ export class Server {
9
+ #opts;
10
+ #nodeId;
11
+ #origins;
12
+ #peers = new Map();
13
+ #onPeer = [];
14
+ #table;
15
+ #hub;
16
+ #adapter;
17
+ #nextPeer = 0;
18
+ #serverOrigin = 0;
19
+ #callHandlers = new Map();
20
+ constructor(opts) {
21
+ this.#opts = opts;
22
+ this.#nodeId = opts.nodeId ?? `node-${Math.trunc(performance.now())}`;
23
+ this.#origins = new OriginAllocator(opts.hostOrdinal ?? 0);
24
+ }
25
+ /** Builds the event table once. Async because event ids are a SHA-256 of the name. */
26
+ async listen() {
27
+ this.#table = await buildEventTable(this.#opts.contract);
28
+ this.#adapter = this.#opts.adapter ?? new MemoryAdapter(this.#nodeId);
29
+ this.#hub = new Hub(this.#adapter, this.#table);
30
+ // The server broadcasts on the datagram lane too, so it needs its own origin.
31
+ // Origin 0 is reserved, so it cannot simply be left unset.
32
+ this.#serverOrigin = this.#origins.allocate(Date.now());
33
+ }
34
+ /** Register a responder for a callable event. */
35
+ handle(event, handler) {
36
+ this.#callHandlers.set(event, handler);
37
+ for (const { session } of this.#peers.values()) {
38
+ session.handle(event, handler);
39
+ }
40
+ return () => {
41
+ this.#callHandlers.delete(event);
42
+ // Sweeping current peers rather than the ones present at registration: a session
43
+ // accepted in between picked the handler up from `#callHandlers`, so it has to be
44
+ // revoked too. Deleting from the map alone left every already-connected peer still
45
+ // being answered — revoking a privileged responder did nothing for anyone connected.
46
+ for (const { session } of this.#peers.values())
47
+ session.unhandle(event);
48
+ };
49
+ }
50
+ onSession(cb) {
51
+ this.#onPeer.push(cb);
52
+ return () => {
53
+ const i = this.#onPeer.indexOf(cb);
54
+ if (i >= 0)
55
+ this.#onPeer.splice(i, 1);
56
+ };
57
+ }
58
+ memberCount(room) {
59
+ return this.#requireHub().memberCount(room);
60
+ }
61
+ async accept(conn) {
62
+ const table = this.#requireTable();
63
+ const hub = this.#requireHub();
64
+ const id = `${this.#nodeId}:${this.#nextPeer++}`;
65
+ const origin = this.#origins.allocate(Date.now());
66
+ const session = new Session(conn, {
67
+ table,
68
+ origin,
69
+ ...(this.#opts.validateInbound === undefined
70
+ ? {}
71
+ : { validateInbound: this.#opts.validateInbound }),
72
+ });
73
+ const peer = {
74
+ id,
75
+ origin,
76
+ get rooms() {
77
+ return hub.rooms(id);
78
+ },
79
+ join: (room) => hub.join(room, id, session),
80
+ leave: (room) => hub.leave(room, id),
81
+ on: (event, handler) => session.on(event, (payload) => handler(payload)),
82
+ emit: (event, payload) => session.emit(event, payload),
83
+ stats: () => session.stats(),
84
+ close: (code = CloseCode.WT_NO_ERROR, reason = '') => session.close(code, reason),
85
+ };
86
+ for (const [event, handler] of this.#callHandlers)
87
+ session.handle(event, handler);
88
+ this.#peers.set(id, { peer, session });
89
+ void conn.closed
90
+ .then(async () => {
91
+ this.#peers.delete(id);
92
+ this.#origins.free(origin, Date.now());
93
+ session.dispose();
94
+ await hub.removePeer(id);
95
+ })
96
+ // Teardown is the last thing that runs for this peer; there is no caller left to
97
+ // hand a rejection to. Without this it was an unhandled rejection, which ends the
98
+ // process under Node's default — the opposite of what ADR/0005 and D40 promise.
99
+ .catch(() => undefined);
100
+ await session.start();
101
+ for (const cb of this.#onPeer)
102
+ cb(peer);
103
+ return peer;
104
+ }
105
+ to(room) {
106
+ const hub = this.#requireHub();
107
+ const make = (except) => ({
108
+ emit: (event, payload) => hub.broadcast(room, event, payload, { origin: this.#serverOrigin, except }),
109
+ except: (...peers) => make([...except, ...peers]),
110
+ });
111
+ return make([]);
112
+ }
113
+ #requireTable() {
114
+ if (this.#table === undefined)
115
+ throw new Error('call listen() before accept()');
116
+ return this.#table;
117
+ }
118
+ #requireHub() {
119
+ if (this.#hub === undefined)
120
+ throw new Error('call listen() before use');
121
+ return this.#hub;
122
+ }
123
+ }
124
+ export function createServer(opts) {
125
+ return new Server(opts);
126
+ }
127
+ //# sourceMappingURL=server.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"server.js","sourceRoot":"","sources":["../src/server.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,94 @@
1
+ import type { EventTable } from './contract.ts';
2
+ import { type Frame } from './framer.ts';
3
+ import { type Negotiated } from './handshake.ts';
4
+ import { type QueueStats } from './queue.ts';
5
+ import type { Connection } from './transport/types.ts';
6
+ export interface SessionStats extends QueueStats {
7
+ readonly staleReceived: number;
8
+ }
9
+ export type EventHandler = (payload: unknown, meta: {
10
+ readonly from: number;
11
+ }) => void;
12
+ export type CallHandler = (payload: unknown, ctx: {
13
+ readonly signal: AbortSignal;
14
+ }) => Promise<unknown>;
15
+ export interface SessionOptions {
16
+ readonly table: EventTable;
17
+ readonly origin: number;
18
+ readonly validateInbound?: boolean;
19
+ readonly now?: () => number;
20
+ readonly handshakeDeadlineMs?: number;
21
+ /**
22
+ * How a queued datagram flush is deferred. Defaults to a microtask, which is what makes
23
+ * the bounded ring and the TTL reachable at all: a synchronous drain on every push
24
+ * would mean a burst never queues and neither policy ever applies. Tests inject a
25
+ * manual scheduler to exercise both deterministically.
26
+ */
27
+ readonly scheduleFlush?: (flush: () => void) => void;
28
+ }
29
+ export declare class Session {
30
+ #private;
31
+ /** Resolves when both sides have exchanged a valid handshake. */
32
+ readonly ready: Promise<Negotiated>;
33
+ constructor(conn: Connection, opts: SessionOptions);
34
+ get origin(): number;
35
+ start(): Promise<Negotiated>;
36
+ /** JOIN and LEAVE are server-to-client notifications, so a client can keep an accurate
37
+ * view of its own membership. Rooms are server-authoritative; this is not a request. */
38
+ onControl(cb: (type: number, body: unknown) => void): () => void;
39
+ on(event: string, handler: EventHandler): () => void;
40
+ /** Fire and forget on whichever lane the contract declared. The call site never chooses. */
41
+ emit(event: string, payload: unknown): void;
42
+ /** Register a responder. Only events declaring `returns` are callable. */
43
+ handle(event: string, handler: CallHandler): () => void;
44
+ /** Revoke a responder on this session. `Server.handle`'s disposer needs it. */
45
+ unhandle(event: string): void;
46
+ /** True once the connection has closed and everything it held has been released. */
47
+ get disposed(): boolean;
48
+ /**
49
+ * Each call opens its own bidirectional stream, so the stream IS the correlation: no
50
+ * identifiers, no pending map, and a stalled call blocks nothing else.
51
+ *
52
+ * There is no default timeout. A dead peer is detected by the QUIC idle timeout, which
53
+ * closes the session and rejects every pending call — the case a timeout is usually
54
+ * reached for is already handled. Pass `AbortSignal.timeout(ms)` for a slow but live
55
+ * responder.
56
+ */
57
+ call(event: string, payload: unknown, opts?: {
58
+ readonly signal?: AbortSignal;
59
+ }): Promise<unknown>;
60
+ get openCalls(): number;
61
+ get inboundCalls(): number;
62
+ /** Used by the hub to forward an already-encoded frame without re-encoding per peer. */
63
+ sendFrame(frame: Frame): void;
64
+ /** Forward an already-encoded frame. The hub encodes once and fans the same bytes out. */
65
+ sendEncodedFrame(bytes: Uint8Array): void;
66
+ sendDatagramBytes(bytes: Uint8Array): void;
67
+ stats(): SessionStats;
68
+ /**
69
+ * The only door out of a session, and every internal path now uses it.
70
+ *
71
+ * Guarding this method alone was not enough: four call sites reached `#conn.close()`
72
+ * directly — the handshake deadline, the peer-too-slow bound, an emit write failure and a
73
+ * protocol error on the read loop — so the guard covered the one path that already had
74
+ * the fewest duplicates. A soak still produced 619,422 `close sent twice` complaints from
75
+ * quiche after the first fix, which is what a partial guard looks like from the outside.
76
+ */
77
+ close(code: number, reason: string): void;
78
+ /**
79
+ * Idempotent, and wired to `conn.closed` in `start()` so it cannot be forgotten.
80
+ *
81
+ * It was forgotten. `clearInterval` appeared in exactly one place — `close()` — and
82
+ * neither teardown path called it: the server's `conn.closed` continuation freed the
83
+ * origin and removed the peer, and the client's patched a snapshot. Whichever side did
84
+ * not *initiate* the close kept a live interval whose callback closes over `this`,
85
+ * retaining the Session, its Connection, the frame decoder, both queues, the sequence
86
+ * gate and every handler set. At 100 sessions a second that is 360,000 unreclaimable
87
+ * Sessions an hour, and `unref()` does nothing about it — it stops a timer holding the
88
+ * event loop open, not holding memory.
89
+ */
90
+ dispose(): void;
91
+ /** Frames written to the contract but not yet accepted by the transport. */
92
+ get emitQueueDepth(): number;
93
+ }
94
+ //# sourceMappingURL=session.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"session.d.ts","sourceRoot":"","sources":["../src/session.ts"],"names":[],"mappings":"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"}