transport-io 0.0.1 → 0.2.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 +17 -9
- package/dist/adapter.d.ts +3 -3
- package/dist/adapter.d.ts.map +1 -1
- package/dist/adapter.js +1 -1
- package/dist/client.d.ts +11 -3
- package/dist/client.d.ts.map +1 -1
- package/dist/client.js +12 -4
- package/dist/client.js.map +1 -1
- package/dist/codec.js +1 -1
- package/dist/contract.d.ts +33 -9
- package/dist/contract.d.ts.map +1 -1
- package/dist/contract.js +1 -1
- package/dist/contract.js.map +1 -1
- package/dist/datagram.d.ts +2 -0
- package/dist/datagram.d.ts.map +1 -1
- package/dist/datagram.js +8 -4
- package/dist/datagram.js.map +1 -1
- package/dist/errors.js +1 -1
- package/dist/framer.d.ts +3 -3
- package/dist/framer.js +6 -6
- package/dist/handshake.d.ts +1 -1
- package/dist/handshake.js +2 -2
- package/dist/handshake.js.map +1 -1
- package/dist/hub.d.ts +1 -1
- package/dist/hub.js +6 -6
- package/dist/hub.js.map +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.js +2 -2
- package/dist/origin.d.ts +1 -1
- package/dist/origin.js +3 -3
- package/dist/protocol.d.ts +25 -12
- package/dist/protocol.d.ts.map +1 -1
- package/dist/protocol.js +25 -12
- package/dist/protocol.js.map +1 -1
- package/dist/queue.d.ts +7 -3
- package/dist/queue.d.ts.map +1 -1
- package/dist/queue.js +12 -4
- package/dist/queue.js.map +1 -1
- package/dist/server.d.ts +7 -1
- package/dist/server.d.ts.map +1 -1
- package/dist/server.js +3 -4
- package/dist/server.js.map +1 -1
- package/dist/session.d.ts +54 -7
- package/dist/session.d.ts.map +1 -1
- package/dist/session.js +364 -33
- package/dist/session.js.map +1 -1
- package/dist/transport/browser.js +2 -2
- package/dist/transport/browser.js.map +1 -1
- package/dist/transport/fails.node.js +3 -3
- package/dist/transport/moq.node.js +1 -1
- package/dist/transport/parity-suite.d.ts +3 -3
- package/dist/transport/parity-suite.js +8 -8
- package/dist/transport/parity-suite.js.map +1 -1
- package/dist/transport/types.d.ts +2 -2
- package/dist/transport/unreliable.d.ts +1 -1
- package/package.json +2 -2
package/README.md
CHANGED
|
@@ -1,19 +1,27 @@
|
|
|
1
|
-
|
|
1
|
+
<p align="center">
|
|
2
|
+
<picture>
|
|
3
|
+
<source media="(prefers-color-scheme: dark)" srcset="https://raw.githubusercontent.com/transport-io/transport-io/main/assets/brand/transport-io-lockup-bone.svg">
|
|
4
|
+
<img alt="transport-io" src="https://raw.githubusercontent.com/transport-io/transport-io/main/assets/brand/transport-io-lockup-ink.svg" width="340">
|
|
5
|
+
</picture>
|
|
6
|
+
</p>
|
|
2
7
|
|
|
3
8
|
Real-time apps over WebTransport. Socket.IO's shape, on a transport with multiple streams
|
|
4
9
|
and datagrams, without Socket.IO's mistakes.
|
|
5
10
|
|
|
6
11
|
Framing, length prefixes, buffer accumulation, stream lifecycle and backpressure queues are
|
|
7
|
-
hidden. Reliability is not: an event declares `
|
|
8
|
-
"this message may be dropped" is a property of your data that lives in the type system.
|
|
12
|
+
hidden. Reliability is not: an event declares `reliable` or `unreliable` in the contract, and
|
|
13
|
+
"this message may be dropped" is a property of your data that lives in the type system. The
|
|
14
|
+
reliable lane is carried on QUIC streams, the unreliable lane on QUIC datagrams.
|
|
9
15
|
|
|
10
|
-
**
|
|
11
|
-
|
|
16
|
+
**Read [KNOWN-ISSUES.md](https://github.com/transport-io/transport-io/blob/main/KNOWN-ISSUES.md)
|
|
17
|
+
before you start.** It is what this library refuses to do and will not change, plus the one
|
|
18
|
+
measured defect. Full documentation is in the
|
|
19
|
+
[repository README](https://github.com/transport-io/transport-io#readme). The short version:
|
|
12
20
|
|
|
13
|
-
- **WebTransport only.** No WebSocket fallback, deliberately
|
|
14
|
-
make the
|
|
21
|
+
- **WebTransport only.** No WebSocket fallback, deliberately - a fallback would silently
|
|
22
|
+
make the unreliable lane reliable and ordered, which is a lie about your data.
|
|
15
23
|
- **Chrome and Firefox.** Safari cannot talk to a quiche-backed server and is unsupported.
|
|
16
|
-
- **The server needs a separate native install**, and its Linux prebuild needs glibc 2.38
|
|
24
|
+
- **The server needs a separate native install**, and its Linux prebuild needs glibc 2.38 -
|
|
17
25
|
no default Node `-slim` image has it, and Alpine has no prebuild at all.
|
|
18
26
|
- **Each `call()` leaks ~5.95 KB of server memory**, upstream in the QUIC binding, not in
|
|
19
27
|
this library. `emit` and datagrams are flat.
|
|
@@ -23,6 +31,6 @@ hidden. Reliability is not: an event declares `stream` or `datagram` in the cont
|
|
|
23
31
|
npm install transport-io
|
|
24
32
|
```
|
|
25
33
|
|
|
26
|
-
A git install does not work
|
|
34
|
+
A git install does not work - the repository root is a private monorepo package.
|
|
27
35
|
|
|
28
36
|
MIT © #V0ID
|
package/dist/adapter.d.ts
CHANGED
|
@@ -5,12 +5,12 @@
|
|
|
5
5
|
* Rules core obeys (D40): every method is async even in memory, frames cross as bytes and
|
|
6
6
|
* never as live objects, `PeerId` is a stable cross-process string, no node assumes it
|
|
7
7
|
* knows a room's full membership, a frame for a room with no local members is dropped
|
|
8
|
-
* silently rather than erroring, and any method may reject
|
|
8
|
+
* silently rather than erroring, and any method may reject - core degrades rather than
|
|
9
9
|
* crashing.
|
|
10
10
|
*/
|
|
11
11
|
export type PeerId = string;
|
|
12
12
|
export type Frame = Uint8Array;
|
|
13
|
-
export type Lane = '
|
|
13
|
+
export type Lane = 'reliable' | 'unreliable';
|
|
14
14
|
/** The envelope carries the origin node. The frame the peer receives is not these bytes. */
|
|
15
15
|
export interface RemoteEnvelope {
|
|
16
16
|
readonly room: string;
|
|
@@ -51,7 +51,7 @@ export interface Publisher {
|
|
|
51
51
|
/**
|
|
52
52
|
* A bus two or more `MemoryAdapter`s can share, so a single process can model several
|
|
53
53
|
* nodes. Without it `MemoryAdapter` is per-instance and two of them cannot hear each
|
|
54
|
-
* other, which is
|
|
54
|
+
* other, which is why the cross-node delivery path had never executed a line.
|
|
55
55
|
*/
|
|
56
56
|
export declare function memoryBus(): MemoryBus;
|
|
57
57
|
export interface MemoryBus {
|
package/dist/adapter.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"adapter.d.ts","sourceRoot":"","sources":["../src/adapter.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AACH,MAAM,MAAM,MAAM,GAAG,MAAM,CAAA;AAC3B,MAAM,MAAM,KAAK,GAAG,UAAU,CAAA;AAC9B,MAAM,MAAM,IAAI,GAAG,
|
|
1
|
+
{"version":3,"file":"adapter.d.ts","sourceRoot":"","sources":["../src/adapter.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AACH,MAAM,MAAM,MAAM,GAAG,MAAM,CAAA;AAC3B,MAAM,MAAM,KAAK,GAAG,UAAU,CAAA;AAC9B,MAAM,MAAM,IAAI,GAAG,UAAU,GAAG,YAAY,CAAA;AAE5C,4FAA4F;AAC5F,MAAM,WAAW,cAAc;IAC7B,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAA;IACrB,QAAQ,CAAC,KAAK,EAAE,KAAK,CAAA;IACrB,QAAQ,CAAC,IAAI,EAAE,IAAI,CAAA;IACnB,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAA;IACvB,QAAQ,CAAC,MAAM,CAAC,EAAE,SAAS,MAAM,EAAE,CAAA;CACpC;AAED,MAAM,WAAW,gBAAgB;IAC/B,QAAQ,CAAC,IAAI,EAAE,IAAI,CAAA;IACnB,QAAQ,CAAC,MAAM,CAAC,EAAE,SAAS,MAAM,EAAE,CAAA;CACpC;AAED,MAAM,WAAW,OAAO;IACtB;;;;;;;;OAQG;IACH,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAA;IACvB,IAAI,CAAC,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAAA;IAC/C,KAAK,CAAC,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAAA;IAChD,SAAS,CAAC,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,KAAK,EAAE,IAAI,EAAE,gBAAgB,GAAG,OAAO,CAAC,IAAI,CAAC,CAAA;IAC5E,QAAQ,CAAC,EAAE,EAAE,CAAC,QAAQ,EAAE,cAAc,KAAK,IAAI,GAAG,IAAI,CAAA;CACvD;AAED;;;;GAIG;AACH,MAAM,WAAW,SAAS;IACxB,SAAS,CAAC,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,KAAK,EAAE,IAAI,EAAE,gBAAgB,GAAG,OAAO,CAAC,IAAI,CAAC,CAAA;CAC7E;AAED,4FAA4F;AAC5F;;;;GAIG;AACH,wBAAgB,SAAS,IAAI,SAAS,CAErC;AAED,MAAM,WAAW,SAAS;IACxB,QAAQ,CAAC,SAAS,EAAE,CAAC,CAAC,CAAC,EAAE,cAAc,KAAK,IAAI,CAAC,EAAE,CAAA;CACpD;AAED,qBAAa,aAAc,YAAW,OAAO;;IAG3C,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAA;IAEvB,YAAY,MAAM,EAAE,MAAM,EAAE,GAAG,GAAE,SAAuB,EAGvD;IAEK,IAAI,CAAC,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAOpD;IAEK,KAAK,CAAC,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAKrD;IAEK,SAAS,CAAC,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,KAAK,EAAE,IAAI,EAAE,gBAAgB,GAAG,OAAO,CAAC,IAAI,CAAC,CAWjF;IAED,QAAQ,CAAC,EAAE,EAAE,CAAC,CAAC,EAAE,cAAc,KAAK,IAAI,GAAG,IAAI,CAE9C;CACF"}
|
package/dist/adapter.js
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
/**
|
|
3
3
|
* A bus two or more `MemoryAdapter`s can share, so a single process can model several
|
|
4
4
|
* nodes. Without it `MemoryAdapter` is per-instance and two of them cannot hear each
|
|
5
|
-
* other, which is
|
|
5
|
+
* other, which is why the cross-node delivery path had never executed a line.
|
|
6
6
|
*/
|
|
7
7
|
export function memoryBus() {
|
|
8
8
|
return { listeners: [] };
|
package/dist/client.d.ts
CHANGED
|
@@ -2,12 +2,12 @@
|
|
|
2
2
|
* Client surface.
|
|
3
3
|
*
|
|
4
4
|
* Constructible without I/O: nothing here touches `window` or `WebTransport` at module
|
|
5
|
-
* scope, so importing this on a server
|
|
5
|
+
* scope, so importing this on a server - which Next.js will do - is safe. Feature
|
|
6
6
|
* detection happens inside connect().
|
|
7
7
|
*/
|
|
8
|
-
import { type AnyMap, type CallableOf, type Contract } from './contract.ts';
|
|
8
|
+
import { type AnyMap, type CallableOf, type Contract, type StreamableOf } from './contract.ts';
|
|
9
9
|
import { TransportError } from './errors.ts';
|
|
10
|
-
import { type SessionStats } from './session.ts';
|
|
10
|
+
import { type SessionStats, type StreamResult } from './session.ts';
|
|
11
11
|
import type { Connection } from './transport/types.ts';
|
|
12
12
|
export type Status = 'idle' | 'connecting' | 'connected' | 'closing' | 'closed';
|
|
13
13
|
export interface ClientState {
|
|
@@ -55,6 +55,14 @@ export declare class Client<M extends AnyMap = AnyMap> {
|
|
|
55
55
|
call<K extends CallableOf<M> & string>(event: K, payload: M[K]['payload'], options?: {
|
|
56
56
|
readonly signal?: AbortSignal;
|
|
57
57
|
}): Promise<M[K]['returns']>;
|
|
58
|
+
/**
|
|
59
|
+
* Available only on events declaring `yields`. Iterate it, or `.collect()` the whole
|
|
60
|
+
* sequence. Leaving the loop with `break` resets the QUIC stream, which is what reaches
|
|
61
|
+
* the responder's `ctx.signal`; there is no separate cancel call and none is needed.
|
|
62
|
+
*/
|
|
63
|
+
stream<K extends StreamableOf<M> & string>(event: K, payload: M[K]['payload'], options?: {
|
|
64
|
+
readonly signal?: AbortSignal;
|
|
65
|
+
}): StreamResult<M[K]['yields']>;
|
|
58
66
|
stats(): SessionStats | undefined;
|
|
59
67
|
}
|
|
60
68
|
//# sourceMappingURL=client.d.ts.map
|
package/dist/client.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"client.d.ts","sourceRoot":"","sources":["../src/client.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AACH,OAAO,
|
|
1
|
+
{"version":3,"file":"client.d.ts","sourceRoot":"","sources":["../src/client.ts"],"names":[],"mappings":"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"}
|
package/dist/client.js
CHANGED
|
@@ -2,10 +2,10 @@
|
|
|
2
2
|
* Client surface.
|
|
3
3
|
*
|
|
4
4
|
* Constructible without I/O: nothing here touches `window` or `WebTransport` at module
|
|
5
|
-
* scope, so importing this on a server
|
|
5
|
+
* scope, so importing this on a server - which Next.js will do - is safe. Feature
|
|
6
6
|
* detection happens inside connect().
|
|
7
7
|
*/
|
|
8
|
-
import { buildEventTable } from './contract.js';
|
|
8
|
+
import { buildEventTable, } from './contract.js';
|
|
9
9
|
import { TransportError } from './errors.js';
|
|
10
10
|
import { CloseCode, FrameType } from './protocol.js';
|
|
11
11
|
import { Session } from './session.js';
|
|
@@ -84,6 +84,14 @@ export class Client {
|
|
|
84
84
|
async call(event, payload, options) {
|
|
85
85
|
return (await this.#requireSession().call(event, payload, options));
|
|
86
86
|
}
|
|
87
|
+
/**
|
|
88
|
+
* Available only on events declaring `yields`. Iterate it, or `.collect()` the whole
|
|
89
|
+
* sequence. Leaving the loop with `break` resets the QUIC stream, which is what reaches
|
|
90
|
+
* the responder's `ctx.signal`; there is no separate cancel call and none is needed.
|
|
91
|
+
*/
|
|
92
|
+
stream(event, payload, options) {
|
|
93
|
+
return this.#requireSession().stream(event, payload, options);
|
|
94
|
+
}
|
|
87
95
|
stats() {
|
|
88
96
|
return this.#session?.stats();
|
|
89
97
|
}
|
|
@@ -94,12 +102,12 @@ export class Client {
|
|
|
94
102
|
const conn = await this.#opts.connect();
|
|
95
103
|
// Chrome implements neither `requireUnreliable` nor `reliability`, so `undefined`
|
|
96
104
|
// must pass or every session on the dominant browser would be refused. Only an
|
|
97
|
-
// explicit reliable-only is a lie about the
|
|
105
|
+
// explicit reliable-only is a lie about the unreliable lane.
|
|
98
106
|
if (conn.reliability() === 'reliable-only') {
|
|
99
107
|
// §10.2 code 1006. Throwing without closing left the peer holding a session this
|
|
100
108
|
// side had already abandoned, with nothing on the wire to say why.
|
|
101
109
|
conn.close(CloseCode.WT_RELIABILITY_REFUSED, 'reliable-only transport refused');
|
|
102
|
-
throw new TransportError('WT_RELIABILITY_REFUSED', 'the session negotiated reliable-only transport', 'The
|
|
110
|
+
throw new TransportError('WT_RELIABILITY_REFUSED', 'the session negotiated reliable-only transport', 'The unreliable lane would silently become reliable and ordered. This library refuses rather than lie about your data.');
|
|
103
111
|
}
|
|
104
112
|
const session = new Session(conn, {
|
|
105
113
|
table,
|
package/dist/client.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"client.js","sourceRoot":"","sources":["../src/client.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AACH,OAAO,
|
|
1
|
+
{"version":3,"file":"client.js","sourceRoot":"","sources":["../src/client.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AACH,OAAO,EAEL,eAAe,GAIhB,MAAM,eAAe,CAAA;AACtB,OAAO,EAAE,cAAc,EAAE,MAAM,aAAa,CAAA;AAC5C,OAAO,EAAE,SAAS,EAAE,SAAS,EAAE,MAAM,eAAe,CAAA;AACpD,OAAO,EAAE,OAAO,EAAwC,MAAM,cAAc,CAAA;AAgC5E,MAAM,OAAO,MAAM;IACR,KAAK,CAAe;IACpB,UAAU,GAAG,IAAI,GAAG,EAAc,CAAA;IAClC,SAAS,GAAG,IAAI,GAAG,EAA2C,CAAA;IACvE,QAAQ,CAAqB;IAC7B,SAAS,GAAgB,MAAM,CAAC,MAAM,CAAC;QACrC,MAAM,EAAE,MAAM;QACd,SAAS,EAAE,IAAI;QACf,KAAK,EAAE,EAAE;QACT,SAAS,EAAE,IAAI;KAChB,CAAC,CAAA;IACF,KAAK,GAAG,CAAC,CAAA;IACT,WAAW,CAA2B;IAEtC,YAAY,IAAmB;QAC7B,IAAI,CAAC,KAAK,GAAG,IAAI,CAAA;IACnB,CAAC;IAED;;;;OAIG;IACH,WAAW;QACT,OAAO,IAAI,CAAC,SAAS,CAAA;IACvB,CAAC;IAED,SAAS,CAAC,QAAoB;QAC5B,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAA;QAC7B,OAAO,GAAG,EAAE;YACV,IAAI,CAAC,UAAU,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAA;QAClC,CAAC,CAAA;IACH,CAAC;IAED;oFACgF;IAChF,KAAK,CAAC,OAAO;QACX,IAAI,CAAC,KAAK,EAAE,CAAA;QACZ,IAAI,IAAI,CAAC,WAAW,KAAK,SAAS;YAAE,IAAI,CAAC,WAAW,GAAG,IAAI,CAAC,UAAU,EAAE,CAAA;QACxE,IAAI,CAAC;YACH,MAAM,IAAI,CAAC,WAAW,CAAA;QACxB,CAAC;QAAC,OAAO,CAAC,EAAE,CAAC;YACX,IAAI,CAAC,WAAW,GAAG,SAAS,CAAA;YAC5B,MAAM,CAAC,CAAA;QACT,CAAC;IACH,CAAC;IAED,UAAU;QACR,IAAI,CAAC,KAAK,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,IAAI,CAAC,KAAK,GAAG,CAAC,CAAC,CAAA;QACxC,IAAI,IAAI,CAAC,KAAK,GAAG,CAAC;YAAE,OAAM;QAC1B,IAAI,CAAC,MAAM,CAAC,EAAE,MAAM,EAAE,SAAS,EAAE,CAAC,CAAA;QAClC,IAAI,CAAC,QAAQ,EAAE,KAAK,CAAC,SAAS,CAAC,WAAW,EAAE,mBAAmB,CAAC,CAAA;QAChE,IAAI,CAAC,QAAQ,GAAG,SAAS,CAAA;QACzB,IAAI,CAAC,WAAW,GAAG,SAAS,CAAA;QAC5B,IAAI,CAAC,MAAM,CAAC,EAAE,MAAM,EAAE,QAAQ,EAAE,SAAS,EAAE,IAAI,EAAE,KAAK,EAAE,EAAE,EAAE,CAAC,CAAA;IAC/D,CAAC;IAED,mEAAmE;IACnE,IAAI,CAA6B,KAAQ,EAAE,OAAwB;QACjE,IAAI,CAAC,eAAe,EAAE,CAAC,IAAI,CAAC,KAAK,EAAE,OAAO,CAAC,CAAA;IAC7C,CAAC;IAED,EAAE,CACA,KAAQ,EACR,OAA2C;QAE3C,IAAI,GAAG,GAAG,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,KAAK,CAAC,CAAA;QACnC,IAAI,GAAG,KAAK,SAAS,EAAE,CAAC;YACtB,GAAG,GAAG,IAAI,GAAG,EAAE,CAAA;YACf,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,KAAK,EAAE,GAAG,CAAC,CAAA;QAChC,CAAC;QACD,GAAG,CAAC,GAAG,CAAC,OAA+B,CAAC,CAAA;QACxC,MAAM,GAAG,GAAG,IAAI,CAAC,QAAQ,EAAE,EAAE,CAAC,KAAK,EAAE,CAAC,CAAC,EAAE,EAAE,CAAC,OAAO,CAAC,CAAoB,CAAC,CAAC,CAAA;QAC1E,OAAO,GAAG,EAAE;YACV,GAAG,CAAC,MAAM,CAAC,OAA+B,CAAC,CAAA;YAC3C,GAAG,EAAE,EAAE,CAAA;QACT,CAAC,CAAA;IACH,CAAC;IAED,qFAAqF;IACrF,KAAK,CAAC,IAAI,CACR,KAAQ,EACR,OAAwB,EACxB,OAA2C;QAE3C,OAAO,CAAC,MAAM,IAAI,CAAC,eAAe,EAAE,CAAC,IAAI,CAAC,KAAK,EAAE,OAAO,EAAE,OAAO,CAAC,CAAoB,CAAA;IACxF,CAAC;IAED;;;;OAIG;IACH,MAAM,CACJ,KAAQ,EACR,OAAwB,EACxB,OAA2C;QAE3C,OAAO,IAAI,CAAC,eAAe,EAAE,CAAC,MAAM,CAAC,KAAK,EAAE,OAAO,EAAE,OAAO,CAE3D,CAAA;IACH,CAAC;IAED,KAAK;QACH,OAAO,IAAI,CAAC,QAAQ,EAAE,KAAK,EAAE,CAAA;IAC/B,CAAC;IAED,KAAK,CAAC,UAAU;QACd,IAAI,CAAC,MAAM,CAAC,EAAE,MAAM,EAAE,YAAY,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAA;QACtD,IAAI,CAAC;YACH,MAAM,KAAK,GAAG,MAAM,eAAe,CAAC,IAAI,CAAC,KAAK,CAAC,QAAQ,CAAC,CAAA;YACxD,MAAM,IAAI,GAAG,MAAM,IAAI,CAAC,KAAK,CAAC,OAAO,EAAE,CAAA;YAEvC,kFAAkF;YAClF,+EAA+E;YAC/E,6DAA6D;YAC7D,IAAI,IAAI,CAAC,WAAW,EAAE,KAAK,eAAe,EAAE,CAAC;gBAC3C,iFAAiF;gBACjF,mEAAmE;gBACnE,IAAI,CAAC,KAAK,CAAC,SAAS,CAAC,sBAAsB,EAAE,iCAAiC,CAAC,CAAA;gBAC/E,MAAM,IAAI,cAAc,CACtB,wBAAwB,EACxB,gDAAgD,EAChD,uHAAuH,CACxH,CAAA;YACH,CAAC;YAED,MAAM,OAAO,GAAG,IAAI,OAAO,CAAC,IAAI,EAAE;gBAChC,KAAK;gBACL,MAAM,EAAE,IAAI,CAAC,KAAK,CAAC,MAAM,IAAI,UAAU;gBACvC,GAAG,CAAC,IAAI,CAAC,KAAK,CAAC,eAAe,KAAK,SAAS;oBAC1C,CAAC,CAAC,EAAE;oBACJ,CAAC,CAAC,EAAE,eAAe,EAAE,IAAI,CAAC,KAAK,CAAC,eAAe,EAAE,CAAC;gBACpD,GAAG,CAAC,IAAI,CAAC,KAAK,CAAC,mBAAmB,KAAK,SAAS;oBAC9C,CAAC,CAAC,EAAE;oBACJ,CAAC,CAAC,EAAE,mBAAmB,EAAE,IAAI,CAAC,KAAK,CAAC,mBAAmB,EAAE,CAAC;gBAC5D,GAAG,CAAC,IAAI,CAAC,KAAK,CAAC,aAAa,KAAK,SAAS;oBACxC,CAAC,CAAC,EAAE;oBACJ,CAAC,CAAC,EAAE,aAAa,EAAE,IAAI,CAAC,KAAK,CAAC,aAAa,EAAE,CAAC;gBAChD,GAAG,CAAC,IAAI,CAAC,KAAK,CAAC,GAAG,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,GAAG,EAAE,IAAI,CAAC,KAAK,CAAC,GAAG,EAAE,CAAC;aACjE,CAAC,CAAA;YACF,IAAI,CAAC,QAAQ,GAAG,OAAO,CAAA;YAEvB,KAAK,MAAM,CAAC,KAAK,EAAE,QAAQ,CAAC,IAAI,IAAI,CAAC,SAAS,EAAE,CAAC;gBAC/C,KAAK,MAAM,CAAC,IAAI,QAAQ;oBAAE,OAAO,CAAC,EAAE,CAAC,KAAK,EAAE,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAA;YAC1D,CAAC;YACD,OAAO,CAAC,SAAS,CAAC,CAAC,IAAI,EAAE,IAAI,EAAE,EAAE,CAAC,IAAI,CAAC,aAAa,CAAC,IAAI,EAAE,IAAI,CAAC,CAAC,CAAA;YAEjE,MAAM,OAAO,CAAC,KAAK,EAAE,CAAA;YACrB,IAAI,CAAC,MAAM,CAAC,EAAE,MAAM,EAAE,WAAW,EAAE,SAAS,EAAE,KAAK,OAAO,CAAC,MAAM,EAAE,EAAE,CAAC,CAAA;YAEtE,KAAK,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,EAAE;gBACzB,IAAI,CAAC,MAAM,CAAC,EAAE,MAAM,EAAE,QAAQ,EAAE,SAAS,EAAE,IAAI,EAAE,KAAK,EAAE,EAAE,EAAE,CAAC,CAAA;YAC/D,CAAC,CAAC,CAAA;QACJ,CAAC;QAAC,OAAO,CAAC,EAAE,CAAC;YACX,MAAM,GAAG,GACP,CAAC,YAAY,cAAc;gBACzB,CAAC,CAAC,CAAC;gBACH,CAAC,CAAC,IAAI,cAAc,CAAC,mBAAmB,EAAE,MAAM,CAAC,CAAC,CAAC,EAAE,uBAAuB,CAAC,CAAA;YACjF,IAAI,CAAC,MAAM,CAAC,EAAE,MAAM,EAAE,QAAQ,EAAE,SAAS,EAAE,GAAG,EAAE,CAAC,CAAA;YACjD,MAAM,GAAG,CAAA;QACX,CAAC;IACH,CAAC;IAED,yFAAyF;IACzF,aAAa,CAAC,IAAY,EAAE,IAAa;QACvC,MAAM,IAAI,GAAI,IAA2B,CAAC,IAAI,CAAA;QAC9C,IAAI,OAAO,IAAI,KAAK,QAAQ;YAAE,OAAM;QACpC,MAAM,KAAK,GAAG,IAAI,GAAG,CAAC,IAAI,CAAC,SAAS,CAAC,KAAK,CAAC,CAAA;QAC3C,IAAI,IAAI,KAAK,SAAS,CAAC,IAAI;YAAE,KAAK,CAAC,GAAG,CAAC,IAAI,CAAC,CAAA;;YACvC,KAAK,CAAC,MAAM,CAAC,IAAI,CAAC,CAAA;QACvB,IAAI,CAAC,MAAM,CAAC,EAAE,KAAK,EAAE,CAAC,GAAG,KAAK,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,CAAA;IAC3C,CAAC;IAED,eAAe;QACb,IAAI,IAAI,CAAC,QAAQ,KAAK,SAAS,EAAE,CAAC;YAChC,MAAM,IAAI,cAAc,CACtB,mBAAmB,EACnB,eAAe,EACf,kCAAkC,CACnC,CAAA;QACH,CAAC;QACD,OAAO,IAAI,CAAC,QAAQ,CAAA;IACtB,CAAC;IAED,MAAM,CAAC,IAA0B;QAC/B,IAAI,CAAC,SAAS,GAAG,MAAM,CAAC,MAAM,CAAC,EAAE,GAAG,IAAI,CAAC,SAAS,EAAE,GAAG,IAAI,EAAE,CAAC,CAAA;QAC9D,KAAK,MAAM,CAAC,IAAI,IAAI,CAAC,UAAU;YAAE,CAAC,EAAE,CAAA;IACtC,CAAC;CACF"}
|
package/dist/codec.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
/** JSON over UTF-8. PROTOCOL.md §5.3
|
|
1
|
+
/** JSON over UTF-8. PROTOCOL.md §5.3 - codec 0x01, the only one this version speaks. */
|
|
2
2
|
import { TransportError } from './errors.js';
|
|
3
3
|
const encoder = new TextEncoder();
|
|
4
4
|
const decoder = new TextDecoder('utf-8', { fatal: true });
|
package/dist/contract.d.ts
CHANGED
|
@@ -3,34 +3,50 @@
|
|
|
3
3
|
* tells you every event, payload and lane without reading anything else.
|
|
4
4
|
*/
|
|
5
5
|
import type { StandardSchemaV1, StandardTypedV1 } from '@standard-schema/spec';
|
|
6
|
-
export type Lane = '
|
|
6
|
+
export type Lane = 'reliable' | 'unreliable';
|
|
7
7
|
export type Schema = StandardSchemaV1;
|
|
8
8
|
/**
|
|
9
|
-
* `returns` is meaningful only on the
|
|
9
|
+
* `returns` is meaningful only on the reliable lane: an unreliable event has no response
|
|
10
|
+
* path. `yields` is the streaming form of `returns` and excludes it: an event answers with
|
|
11
|
+
* one value or with a sequence, never with a choice made at the call site.
|
|
10
12
|
*
|
|
11
|
-
* The
|
|
13
|
+
* The choice cannot be per call site, and the reason is on the wire rather than in taste. A
|
|
14
|
+
* handler that yields nothing closes the stream with zero CALL_RESPONSE frames, which is
|
|
15
|
+
* exactly the byte sequence a `call()` responder produces when it is broken. Identical
|
|
16
|
+
* bytes, two meanings: a protocol error for `call()`, a clean empty iteration for
|
|
17
|
+
* `stream()`. Only the contract, which both peers exchange at handshake, tells them apart.
|
|
18
|
+
*
|
|
19
|
+
* The `returns?: never` on the datagram branch does real work. Excess
|
|
12
20
|
* property checking against a *union* admits any property present on any member, so
|
|
13
|
-
* `{ lane: '
|
|
21
|
+
* `{ lane: 'unreliable', payload, returns }` compiled happily, `CallableOf` admitted it, and
|
|
14
22
|
* `call()` served it over a bidirectional stream. A contract that says "may be dropped"
|
|
15
|
-
* produced a guaranteed ordered message with the type system agreeing
|
|
23
|
+
* produced a guaranteed ordered message with the type system agreeing - a direct violation
|
|
16
24
|
* of D1, the first decision this project made.
|
|
17
25
|
*/
|
|
18
26
|
export type EventDef = {
|
|
19
|
-
readonly lane: '
|
|
27
|
+
readonly lane: 'unreliable';
|
|
20
28
|
readonly payload: Schema;
|
|
21
29
|
readonly id?: number;
|
|
22
30
|
readonly returns?: never;
|
|
31
|
+
readonly yields?: never;
|
|
23
32
|
} | {
|
|
24
|
-
readonly lane: '
|
|
33
|
+
readonly lane: 'reliable';
|
|
25
34
|
readonly payload: Schema;
|
|
26
35
|
readonly returns?: Schema;
|
|
27
36
|
readonly id?: number;
|
|
37
|
+
readonly yields?: never;
|
|
38
|
+
} | {
|
|
39
|
+
readonly lane: 'reliable';
|
|
40
|
+
readonly payload: Schema;
|
|
41
|
+
readonly yields: Schema;
|
|
42
|
+
readonly id?: number;
|
|
43
|
+
readonly returns?: never;
|
|
28
44
|
};
|
|
29
45
|
export type Contract = Readonly<Record<string, EventDef>>;
|
|
30
46
|
export type Infer<S extends StandardTypedV1> = StandardTypedV1.InferOutput<S>;
|
|
31
47
|
/**
|
|
32
48
|
* The plain payload/returns map every public signature is written against, so that no
|
|
33
|
-
* method hover ever has to print a validator's internal types. See D57
|
|
49
|
+
* method hover ever has to print a validator's internal types. See D57 - declaring
|
|
34
50
|
* `interface AppMap extends MapOf<typeof contract> {}` is what keeps hover at 126
|
|
35
51
|
* characters instead of 303.
|
|
36
52
|
*/
|
|
@@ -40,17 +56,25 @@ export type MapOf<C extends Contract> = {
|
|
|
40
56
|
readonly returns: C[K] extends {
|
|
41
57
|
readonly returns: infer R extends Schema;
|
|
42
58
|
} ? Infer<R> : never;
|
|
59
|
+
readonly yields: C[K] extends {
|
|
60
|
+
readonly yields: infer Y extends Schema;
|
|
61
|
+
} ? Infer<Y> : never;
|
|
43
62
|
};
|
|
44
63
|
};
|
|
45
64
|
export interface EventShape {
|
|
46
65
|
readonly payload: unknown;
|
|
47
66
|
readonly returns: unknown;
|
|
67
|
+
readonly yields: unknown;
|
|
48
68
|
}
|
|
49
69
|
export type AnyMap = Readonly<Record<string, EventShape>>;
|
|
50
70
|
/** Events declaring `returns`, and therefore callable. */
|
|
51
71
|
export type CallableOf<M extends AnyMap> = {
|
|
52
72
|
[K in keyof M]: [M[K]['returns']] extends [never] ? never : K;
|
|
53
73
|
}[keyof M];
|
|
74
|
+
/** Events declaring `yields`, and therefore streamable. Disjoint from `CallableOf`. */
|
|
75
|
+
export type StreamableOf<M extends AnyMap> = {
|
|
76
|
+
[K in keyof M]: [M[K]['yields']] extends [never] ? never : K;
|
|
77
|
+
}[keyof M];
|
|
54
78
|
export declare function defineContract<const C extends Contract>(contract: C): C;
|
|
55
79
|
/** A types-only schema, for inference without runtime validation. */
|
|
56
80
|
export declare function type$<T>(): StandardSchemaV1<unknown, T>;
|
|
@@ -68,7 +92,7 @@ export interface EventTable {
|
|
|
68
92
|
wire(): readonly [string, number, Lane][];
|
|
69
93
|
}
|
|
70
94
|
/**
|
|
71
|
-
* PROTOCOL.md §5.4
|
|
95
|
+
* PROTOCOL.md §5.4 - the first four bytes of SHA-256 of the event name, big-endian.
|
|
72
96
|
*
|
|
73
97
|
* Async because `crypto.subtle` is, and because writing SHA-256 by hand would mean typing
|
|
74
98
|
* its round constants from memory, which is the one thing D58 forbids. Both `connect()`
|
package/dist/contract.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"contract.d.ts","sourceRoot":"","sources":["../src/contract.ts"],"names":[],"mappings":"AAAA;;;GAGG;AACH,OAAO,KAAK,EAAE,gBAAgB,EAAE,eAAe,EAAE,MAAM,uBAAuB,CAAA;AAI9E,MAAM,MAAM,IAAI,GAAG,
|
|
1
|
+
{"version":3,"file":"contract.d.ts","sourceRoot":"","sources":["../src/contract.ts"],"names":[],"mappings":"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"}
|
package/dist/contract.js
CHANGED
|
@@ -14,7 +14,7 @@ export function type$() {
|
|
|
14
14
|
};
|
|
15
15
|
}
|
|
16
16
|
/**
|
|
17
|
-
* PROTOCOL.md §5.4
|
|
17
|
+
* PROTOCOL.md §5.4 - the first four bytes of SHA-256 of the event name, big-endian.
|
|
18
18
|
*
|
|
19
19
|
* Async because `crypto.subtle` is, and because writing SHA-256 by hand would mean typing
|
|
20
20
|
* its round constants from memory, which is the one thing D58 forbids. Both `connect()`
|
package/dist/contract.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"contract.js","sourceRoot":"","sources":["../src/contract.ts"],"names":[],"mappings":"AAKA,OAAO,EAAE,cAAc,EAAE,MAAM,aAAa,CAAA;AAC5C,OAAO,EAAE,uBAAuB,EAAE,MAAM,eAAe,CAAA;
|
|
1
|
+
{"version":3,"file":"contract.js","sourceRoot":"","sources":["../src/contract.ts"],"names":[],"mappings":"AAKA,OAAO,EAAE,cAAc,EAAE,MAAM,aAAa,CAAA;AAC5C,OAAO,EAAE,uBAAuB,EAAE,MAAM,eAAe,CAAA;AAmFvD,MAAM,UAAU,cAAc,CAA2B,QAAW;IAClE,OAAO,QAAQ,CAAA;AACjB,CAAC;AAED,qEAAqE;AACrE,MAAM,UAAU,KAAK;IACnB,OAAO;QACL,WAAW,EAAE;YACX,OAAO,EAAE,CAAC;YACV,MAAM,EAAE,cAAc;YACtB,QAAQ,EAAE,CAAC,KAAc,EAAE,EAAE,CAAC,CAAC,EAAE,KAAK,EAAE,KAAU,EAAE,CAAC;SACtD;KACF,CAAA;AACH,CAAC;AAmBD;;;;;;GAMG;AACH,MAAM,CAAC,KAAK,UAAU,SAAS,CAAC,IAAY;IAC1C,MAAM,MAAM,GAAG,MAAM,MAAM,CAAC,MAAM,CAAC,MAAM,CAAC,SAAS,EAAE,IAAI,WAAW,EAAE,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,CAAA;IACpF,OAAO,IAAI,QAAQ,CAAC,MAAM,CAAC,CAAC,SAAS,CAAC,CAAC,EAAE,KAAK,CAAC,CAAA;AACjD,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,eAAe,CAAC,QAAkB;IACtD,MAAM,KAAK,GAAG,MAAM,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC,IAAI,EAAE,CAAA;IAC1C,MAAM,OAAO,GAAiB,EAAE,CAAA;IAChC,MAAM,IAAI,GAAG,IAAI,GAAG,EAAsB,CAAA;IAC1C,MAAM,MAAM,GAAG,IAAI,GAAG,EAAsB,CAAA;IAE5C,KAAK,MAAM,IAAI,IAAI,KAAK,EAAE,CAAC;QACzB,MAAM,GAAG,GAAG,QAAQ,CAAC,IAAI,CAAa,CAAA;QACtC,MAAM,EAAE,GAAG,GAAG,CAAC,EAAE,IAAI,CAAC,MAAM,SAAS,CAAC,IAAI,CAAC,CAAC,CAAA;QAC5C,IAAI,EAAE,KAAK,uBAAuB,EAAE,CAAC;YACnC,MAAM,IAAI,cAAc,CACtB,sBAAsB,EACtB,UAAU,IAAI,iCAAiC,EAC/C,sGAAsG,CACvG,CAAA;QACH,CAAC;QACD,MAAM,KAAK,GAAG,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,CAAA;QAC1B,IAAI,KAAK,KAAK,SAAS,EAAE,CAAC;YACxB,MAAM,IAAI,cAAc,CACtB,sBAAsB,EACtB,WAAW,KAAK,CAAC,IAAI,UAAU,IAAI,qBAAqB,EAAE,EAAE,EAC5D,iEAAiE,EAAE,GAAG,CAAC,gCAAgC,CACxG,CAAA;QACH,CAAC;QACD,MAAM,KAAK,GAAe,EAAE,IAAI,EAAE,EAAE,EAAE,IAAI,EAAE,GAAG,CAAC,IAAI,EAAE,GAAG,EAAE,CAAA;QAC3D,OAAO,CAAC,IAAI,CAAC,KAAK,CAAC,CAAA;QACnB,IAAI,CAAC,GAAG,CAAC,EAAE,EAAE,KAAK,CAAC,CAAA;QACnB,MAAM,CAAC,GAAG,CAAC,IAAI,EAAE,KAAK,CAAC,CAAA;IACzB,CAAC;IAED,OAAO;QACL,OAAO;QACP,MAAM,EAAE,CAAC,CAAC,EAAE,EAAE,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC;QAC5B,IAAI,EAAE,CAAC,CAAC,EAAE,EAAE,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC;QACxB,IAAI,EAAE,GAAG,EAAE,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,IAAI,CAA2B,CAAC;KACjF,CAAA;AACH,CAAC"}
|
package/dist/datagram.d.ts
CHANGED
|
@@ -23,6 +23,8 @@ export declare class SequenceGate {
|
|
|
23
23
|
/** Returns true when the datagram is fresh and should be delivered. */
|
|
24
24
|
accept(origin: number, eventId: number, sequence: number, now: number): boolean;
|
|
25
25
|
/** A receiver discards (origin, event) state after this idle, so origins can be reused. */
|
|
26
|
+
/** Forget every origin. A disposed session has no business suppressing anyone's dupes. */
|
|
27
|
+
clear(): void;
|
|
26
28
|
sweep(now: number, retentionMs: number): void;
|
|
27
29
|
get tracked(): number;
|
|
28
30
|
}
|
package/dist/datagram.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"datagram.d.ts","sourceRoot":"","sources":["../src/datagram.ts"],"names":[],"mappings":"AASA,MAAM,WAAW,QAAQ;IACvB,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAA;IACxB,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAA;IACvB,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAA;IACzB,QAAQ,CAAC,OAAO,EAAE,UAAU,CAAA;CAC7B;AAED;;;GAGG;AACH,wBAAgB,kBAAkB,CAAC,WAAW,EAAE,MAAM,GAAG,MAAM,CAG9D;AAED,wBAAgB,cAAc,CAAC,EAAE,EAAE,QAAQ,EAAE,WAAW,EAAE,MAAM,GAAG,UAAU,CAkC5E;AAED,wBAAgB,cAAc,CAAC,KAAK,EAAE,UAAU,GAAG,QAAQ,CA+B1D;AAED;;;;;GAKG;AACH,qBAAa,YAAY;;IAIvB,IAAI,aAAa,IAAI,MAAM,CAE1B;IAED,uEAAuE;IACvE,MAAM,CAAC,MAAM,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,GAAG,OAAO,CAa9E;IAED,2FAA2F;IAC3F,KAAK,CAAC,GAAG,EAAE,MAAM,EAAE,WAAW,EAAE,MAAM,GAAG,IAAI,CAI5C;IAED,IAAI,OAAO,IAAI,MAAM,CAEpB;CACF"}
|
|
1
|
+
{"version":3,"file":"datagram.d.ts","sourceRoot":"","sources":["../src/datagram.ts"],"names":[],"mappings":"AASA,MAAM,WAAW,QAAQ;IACvB,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAA;IACxB,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAA;IACvB,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAA;IACzB,QAAQ,CAAC,OAAO,EAAE,UAAU,CAAA;CAC7B;AAED;;;GAGG;AACH,wBAAgB,kBAAkB,CAAC,WAAW,EAAE,MAAM,GAAG,MAAM,CAG9D;AAED,wBAAgB,cAAc,CAAC,EAAE,EAAE,QAAQ,EAAE,WAAW,EAAE,MAAM,GAAG,UAAU,CAkC5E;AAED,wBAAgB,cAAc,CAAC,KAAK,EAAE,UAAU,GAAG,QAAQ,CA+B1D;AAED;;;;;GAKG;AACH,qBAAa,YAAY;;IAIvB,IAAI,aAAa,IAAI,MAAM,CAE1B;IAED,uEAAuE;IACvE,MAAM,CAAC,MAAM,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,GAAG,OAAO,CAa9E;IAED,2FAA2F;IAC3F,0FAA0F;IAC1F,KAAK,IAAI,IAAI,CAEZ;IAED,KAAK,CAAC,GAAG,EAAE,MAAM,EAAE,WAAW,EAAE,MAAM,GAAG,IAAI,CAI5C;IAED,IAAI,OAAO,IAAI,MAAM,CAEpB;CACF"}
|
package/dist/datagram.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
/** Datagram header. PROTOCOL.md §7.1
|
|
1
|
+
/** Datagram header. PROTOCOL.md §7.1 - codec, event id, origin, sequence, then payload. */
|
|
2
2
|
import { TransportError } from './errors.js';
|
|
3
3
|
import { Codec, DATAGRAM_CONSERVATIVE_FLOOR, DATAGRAM_HEADER_BYTES, EVENT_ID_NOT_APPLICABLE, } from './protocol.js';
|
|
4
4
|
/**
|
|
@@ -14,13 +14,13 @@ export function encodeDatagram(dg, reportedMax) {
|
|
|
14
14
|
throw new TransportError('WT_PROTOCOL_ERROR', 'a datagram payload of zero bytes is not representable', 'Send at least one byte. A zero-length write freezes some transports.');
|
|
15
15
|
}
|
|
16
16
|
if (dg.eventId === EVENT_ID_NOT_APPLICABLE) {
|
|
17
|
-
throw new TransportError('WT_PROTOCOL_ERROR', 'event id 0 is not valid on the
|
|
17
|
+
throw new TransportError('WT_PROTOCOL_ERROR', 'event id 0 is not valid on the unreliable lane', 'Datagrams always carry a contract event. Check the event table.');
|
|
18
18
|
}
|
|
19
19
|
const limit = maxDatagramPayload(reportedMax);
|
|
20
20
|
if (dg.payload.byteLength > limit) {
|
|
21
21
|
// The transport accepts an oversized datagram, discards it, and reports success, so
|
|
22
22
|
// this check is the only thing standing between a user and a silent drop.
|
|
23
|
-
throw new TransportError('WT_DATAGRAM_TOO_LARGE', `payload is ${dg.payload.byteLength} bytes and the path allows ${limit}`, 'Shorten the payload, or declare this event on the
|
|
23
|
+
throw new TransportError('WT_DATAGRAM_TOO_LARGE', `payload is ${dg.payload.byteLength} bytes and the path allows ${limit}`, 'Shorten the payload, or declare this event on the reliable lane where size is not capped this tightly.');
|
|
24
24
|
}
|
|
25
25
|
const out = new Uint8Array(DATAGRAM_HEADER_BYTES + dg.payload.byteLength);
|
|
26
26
|
const view = new DataView(out.buffer);
|
|
@@ -42,7 +42,7 @@ export function decodeDatagram(bytes) {
|
|
|
42
42
|
}
|
|
43
43
|
const eventId = view.getUint32(1, false);
|
|
44
44
|
if (eventId === EVENT_ID_NOT_APPLICABLE) {
|
|
45
|
-
throw new TransportError('WT_PROTOCOL_ERROR', 'event id 0 is not valid on the
|
|
45
|
+
throw new TransportError('WT_PROTOCOL_ERROR', 'event id 0 is not valid on the unreliable lane', 'Check the sender against PROTOCOL.md §7.2.');
|
|
46
46
|
}
|
|
47
47
|
return {
|
|
48
48
|
eventId,
|
|
@@ -79,6 +79,10 @@ export class SequenceGate {
|
|
|
79
79
|
return true;
|
|
80
80
|
}
|
|
81
81
|
/** A receiver discards (origin, event) state after this idle, so origins can be reused. */
|
|
82
|
+
/** Forget every origin. A disposed session has no business suppressing anyone's dupes. */
|
|
83
|
+
clear() {
|
|
84
|
+
this.#seen.clear();
|
|
85
|
+
}
|
|
82
86
|
sweep(now, retentionMs) {
|
|
83
87
|
for (const [key, v] of this.#seen) {
|
|
84
88
|
if (now - v.at >= retentionMs)
|
package/dist/datagram.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"datagram.js","sourceRoot":"","sources":["../src/datagram.ts"],"names":[],"mappings":"AAAA,2FAA2F;AAC3F,OAAO,EAAE,cAAc,EAAE,MAAM,aAAa,CAAA;AAC5C,OAAO,EACL,KAAK,EACL,2BAA2B,EAC3B,qBAAqB,EACrB,uBAAuB,GACxB,MAAM,eAAe,CAAA;AAStB;;;GAGG;AACH,MAAM,UAAU,kBAAkB,CAAC,WAAmB;IACpD,MAAM,SAAS,GAAG,WAAW,GAAG,CAAC,CAAC,CAAC,CAAC,WAAW,CAAC,CAAC,CAAC,2BAA2B,CAAA;IAC7E,OAAO,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,SAAS,GAAG,qBAAqB,CAAC,CAAA;AACvD,CAAC;AAED,MAAM,UAAU,cAAc,CAAC,EAAY,EAAE,WAAmB;IAC9D,IAAI,EAAE,CAAC,OAAO,CAAC,UAAU,KAAK,CAAC,EAAE,CAAC;QAChC,MAAM,IAAI,cAAc,CACtB,mBAAmB,EACnB,uDAAuD,EACvD,sEAAsE,CACvE,CAAA;IACH,CAAC;IACD,IAAI,EAAE,CAAC,OAAO,KAAK,uBAAuB,EAAE,CAAC;QAC3C,MAAM,IAAI,cAAc,CACtB,mBAAmB,EACnB,
|
|
1
|
+
{"version":3,"file":"datagram.js","sourceRoot":"","sources":["../src/datagram.ts"],"names":[],"mappings":"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"}
|
package/dist/errors.js
CHANGED
package/dist/framer.d.ts
CHANGED
|
@@ -5,12 +5,12 @@ export interface Frame {
|
|
|
5
5
|
readonly eventId: number;
|
|
6
6
|
readonly payload: Uint8Array;
|
|
7
7
|
}
|
|
8
|
-
/** §5.1
|
|
8
|
+
/** §5.1 - the cap is per frame type: a call is the documented home for a large payload. */
|
|
9
9
|
export declare function maxPayloadFor(type: FrameType): number;
|
|
10
10
|
export declare function encodeFrame(frame: Frame): Uint8Array;
|
|
11
11
|
/**
|
|
12
|
-
* Incremental decoder. Feed it whatever the transport hands you
|
|
13
|
-
* frames, or a frame split across many reads
|
|
12
|
+
* Incremental decoder. Feed it whatever the transport hands you - a fragment, several
|
|
13
|
+
* frames, or a frame split across many reads - and it yields whole frames only.
|
|
14
14
|
*/
|
|
15
15
|
export declare class FrameDecoder {
|
|
16
16
|
#private;
|
package/dist/framer.js
CHANGED
|
@@ -3,14 +3,14 @@
|
|
|
3
3
|
*
|
|
4
4
|
* QUIC streams are byte streams and do not preserve write boundaries. Measured on the
|
|
5
5
|
* reference transport, 51 writes arrived as 217 reads, and the large write fragmented
|
|
6
|
-
* while the small ones happened to survive
|
|
6
|
+
* while the small ones happened to survive - which is the worst case, because naive
|
|
7
7
|
* boundary-trusting code passes in development and fails under load. The length prefix
|
|
8
8
|
* is the only thing that recovers frame boundaries, and nobody using this library should
|
|
9
9
|
* ever have to think about it.
|
|
10
10
|
*/
|
|
11
11
|
import { TransportError } from './errors.js';
|
|
12
12
|
import { Codec, FrameType, isFrameType, LENGTH_PREFIX_BYTES, MAX_CALL_PAYLOAD_BYTES, MAX_EMIT_PAYLOAD_BYTES, MIN_LENGTH, STREAM_HEADER_BYTES, } from './protocol.js';
|
|
13
|
-
/** §5.1
|
|
13
|
+
/** §5.1 - the cap is per frame type: a call is the documented home for a large payload. */
|
|
14
14
|
export function maxPayloadFor(type) {
|
|
15
15
|
return type === FrameType.CALL_REQUEST || type === FrameType.CALL_RESPONSE
|
|
16
16
|
? MAX_CALL_PAYLOAD_BYTES
|
|
@@ -36,8 +36,8 @@ export function encodeFrame(frame) {
|
|
|
36
36
|
return out;
|
|
37
37
|
}
|
|
38
38
|
/**
|
|
39
|
-
* Incremental decoder. Feed it whatever the transport hands you
|
|
40
|
-
* frames, or a frame split across many reads
|
|
39
|
+
* Incremental decoder. Feed it whatever the transport hands you - a fragment, several
|
|
40
|
+
* frames, or a frame split across many reads - and it yields whole frames only.
|
|
41
41
|
*/
|
|
42
42
|
export class FrameDecoder {
|
|
43
43
|
#buf = new Uint8Array(0);
|
|
@@ -63,8 +63,8 @@ export class FrameDecoder {
|
|
|
63
63
|
}
|
|
64
64
|
const payloadLength = length - STREAM_HEADER_BYTES;
|
|
65
65
|
// §5.3 gives calls 16 MiB and everything else 1 MiB. This enforced the call cap for
|
|
66
|
-
// every frame type, so a peer could declare 16 MiB on the emit lane
|
|
67
|
-
// its documented cap
|
|
66
|
+
// every frame type, so a peer could declare 16 MiB on the emit lane - sixteen times
|
|
67
|
+
// its documented cap - and the decoder would buffer toward it.
|
|
68
68
|
//
|
|
69
69
|
// The type byte is at offset 4, so it is readable as soon as five bytes are, which is
|
|
70
70
|
// before any payload has to be held. Until then the universal cap applies, which
|
package/dist/handshake.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Handshake. PROTOCOL.md §4
|
|
2
|
+
* Handshake. PROTOCOL.md §4 - frame 0 of the emit stream.
|
|
3
3
|
*
|
|
4
4
|
* Being frame 0 of a stream that already exists is what removes the early-traffic race:
|
|
5
5
|
* in-order delivery within a stream means nothing can arrive before it. There is no
|
package/dist/handshake.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Handshake. PROTOCOL.md §4
|
|
2
|
+
* Handshake. PROTOCOL.md §4 - frame 0 of the emit stream.
|
|
3
3
|
*
|
|
4
4
|
* Being frame 0 of a stream that already exists is what removes the early-traffic race:
|
|
5
5
|
* in-order delivery within a stream means nothing can arrive before it. There is no
|
|
@@ -21,7 +21,7 @@ function isWireEvent(v) {
|
|
|
21
21
|
v.length === 3 &&
|
|
22
22
|
typeof v[0] === 'string' &&
|
|
23
23
|
typeof v[1] === 'number' &&
|
|
24
|
-
(v[2] === '
|
|
24
|
+
(v[2] === 'reliable' || v[2] === 'unreliable'));
|
|
25
25
|
}
|
|
26
26
|
export function parseHandshake(value) {
|
|
27
27
|
const bad = (why) => {
|
package/dist/handshake.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"handshake.js","sourceRoot":"","sources":["../src/handshake.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAGH,OAAO,EAAE,cAAc,EAAE,MAAM,aAAa,CAAA;AAC5C,OAAO,EAAE,gBAAgB,EAAE,MAAM,eAAe,CAAA;AAUhD,oEAAoE;AACpE,MAAM,CAAC,MAAM,iBAAiB,GAAsB;IAClD,eAAe;IACf,eAAe;IACf,gBAAgB;CACjB,CAAA;AAED,MAAM,UAAU,cAAc,CAC5B,KAAiB,EACjB,IAAI,GAAsB,EAAE;IAE5B,OAAO,EAAE,CAAC,EAAE,gBAAgB,EAAE,IAAI,EAAE,MAAM,EAAE,KAAK,CAAC,IAAI,EAAE,EAAE,CAAA;AAC5D,CAAC;AAUD,SAAS,WAAW,CAAC,CAAU;IAC7B,OAAO,CACL,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC;QAChB,CAAC,CAAC,MAAM,KAAK,CAAC;QACd,OAAO,CAAC,CAAC,CAAC,CAAC,KAAK,QAAQ;QACxB,OAAO,CAAC,CAAC,CAAC,CAAC,KAAK,QAAQ;QACxB,CAAC,CAAC,CAAC,CAAC,CAAC,KAAK,
|
|
1
|
+
{"version":3,"file":"handshake.js","sourceRoot":"","sources":["../src/handshake.ts"],"names":[],"mappings":"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"}
|
package/dist/hub.d.ts
CHANGED
|
@@ -26,7 +26,7 @@ export declare class Hub {
|
|
|
26
26
|
* Teardown runs to completion whatever the bus does.
|
|
27
27
|
*
|
|
28
28
|
* `broadcast` already wrapped its adapter call; this did not, so a rejection on the
|
|
29
|
-
* first room threw straight out of the loop
|
|
29
|
+
* first room threw straight out of the loop - rooms 2..N kept their `Member` record,
|
|
30
30
|
* each holding a live Session, and `#peerRooms.delete(id)` never ran. Nothing retries,
|
|
31
31
|
* because `conn.closed` resolves exactly once. A later `to(room).emit()` then fanned
|
|
32
32
|
* frames into a session that was already gone.
|
package/dist/hub.js
CHANGED
|
@@ -13,7 +13,7 @@ export class Hub {
|
|
|
13
13
|
this.#adapter = adapter;
|
|
14
14
|
this.#table = table;
|
|
15
15
|
// A node receiving its own publish back is normal, so core dedupes by origin node
|
|
16
|
-
// rather than relying on the adapter to suppress it
|
|
16
|
+
// rather than relying on the adapter to suppress it - and dedupes against the
|
|
17
17
|
// *adapter's* id, which is the one stamped into the envelope. It used to compare
|
|
18
18
|
// against the Server's separate `nodeId`, so any deployment where those differed
|
|
19
19
|
// delivered every local broadcast twice, in silence.
|
|
@@ -30,7 +30,7 @@ export class Hub {
|
|
|
30
30
|
// the emit path's swallowing catch, so nothing surfaced, and the teardown that would
|
|
31
31
|
// have removed it had already run.
|
|
32
32
|
if (session.disposed) {
|
|
33
|
-
throw new TransportError('WT_SESSION_CLOSED', `peer ${id} disconnected before it could join '${room}'`, 'Check the peer is still connected after any await, or ignore this
|
|
33
|
+
throw new TransportError('WT_SESSION_CLOSED', `peer ${id} disconnected before it could join '${room}'`, 'Check the peer is still connected after any await, or ignore this - it is routine.');
|
|
34
34
|
}
|
|
35
35
|
let members = this.#rooms.get(room);
|
|
36
36
|
if (members === undefined) {
|
|
@@ -40,7 +40,7 @@ export class Hub {
|
|
|
40
40
|
// The bus first, local state second. Mutating before the await left a rejected join
|
|
41
41
|
// half-applied: the hub fanned broadcasts to a peer the bus had no record of, and the
|
|
42
42
|
// client was never notified it had joined. For a room whose join is gated on
|
|
43
|
-
// authorization, that is traffic reaching someone who was refused
|
|
43
|
+
// authorization, that is traffic reaching someone who was refused - permanently,
|
|
44
44
|
// because nothing rolls it back and nothing retries.
|
|
45
45
|
await this.#adapter.join(room, id);
|
|
46
46
|
members.set(id, { id, session });
|
|
@@ -69,7 +69,7 @@ export class Hub {
|
|
|
69
69
|
* Teardown runs to completion whatever the bus does.
|
|
70
70
|
*
|
|
71
71
|
* `broadcast` already wrapped its adapter call; this did not, so a rejection on the
|
|
72
|
-
* first room threw straight out of the loop
|
|
72
|
+
* first room threw straight out of the loop - rooms 2..N kept their `Member` record,
|
|
73
73
|
* each holding a live Session, and `#peerRooms.delete(id)` never ran. Nothing retries,
|
|
74
74
|
* because `conn.closed` resolves exactly once. A later `to(room).emit()` then fanned
|
|
75
75
|
* frames into a session that was already gone.
|
|
@@ -102,7 +102,7 @@ export class Hub {
|
|
|
102
102
|
}
|
|
103
103
|
const body = encodePayload(payload);
|
|
104
104
|
const except = args.except ?? [];
|
|
105
|
-
const bytes = entry.lane === '
|
|
105
|
+
const bytes = entry.lane === 'unreliable'
|
|
106
106
|
? encodeDatagram({
|
|
107
107
|
eventId: entry.id,
|
|
108
108
|
origin: args.origin,
|
|
@@ -139,7 +139,7 @@ export class Hub {
|
|
|
139
139
|
for (const m of members.values()) {
|
|
140
140
|
if (except.includes(m.id))
|
|
141
141
|
continue;
|
|
142
|
-
if (lane === '
|
|
142
|
+
if (lane === 'unreliable')
|
|
143
143
|
m.session.sendDatagramBytes(bytes);
|
|
144
144
|
else
|
|
145
145
|
m.session.sendEncodedFrame(bytes);
|