@statewalker/webrun-streams-webrtc 0.4.0 → 0.4.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/dist/index.js +25 -7
- package/dist/port-mux.d.ts +2 -1
- package/dist/port-mux.d.ts.map +1 -1
- package/package.json +3 -3
- package/src/port-mux.ts +30 -8
package/dist/index.js
CHANGED
|
@@ -333,7 +333,8 @@ const claimed = /* @__PURE__ */ new WeakSet();
|
|
|
333
333
|
* ```
|
|
334
334
|
*
|
|
335
335
|
* Messages that arrive before a port's first listener are held for it and delivered after that
|
|
336
|
-
* tick, to every listener added by then.
|
|
336
|
+
* tick, to every listener added by then. Messages posted before a port's channel opens are queued
|
|
337
|
+
* and sent, in order, when it opens.
|
|
337
338
|
*/
|
|
338
339
|
async function webrtcPortMux(options) {
|
|
339
340
|
const { pc, codec, onPort } = options;
|
|
@@ -376,9 +377,26 @@ async function webrtcPortMux(options) {
|
|
|
376
377
|
if (held) held.push(data);
|
|
377
378
|
else deliver(data);
|
|
378
379
|
};
|
|
380
|
+
let queued = dc.readyState === "connecting" ? [] : void 0;
|
|
381
|
+
const send = (bytes) => {
|
|
382
|
+
try {
|
|
383
|
+
dc.send(bytes);
|
|
384
|
+
} catch (err) {
|
|
385
|
+
end(err instanceof Error ? err : new Error(String(err)));
|
|
386
|
+
}
|
|
387
|
+
};
|
|
388
|
+
const onOpen = () => {
|
|
389
|
+
const pending = queued;
|
|
390
|
+
queued = void 0;
|
|
391
|
+
for (const bytes of pending ?? []) {
|
|
392
|
+
if (closeSignal.aborted) return;
|
|
393
|
+
send(bytes);
|
|
394
|
+
}
|
|
395
|
+
};
|
|
379
396
|
const onClose = () => end(/* @__PURE__ */ new Error("webrun-streams-webrtc: the data channel closed"));
|
|
380
397
|
const onError = (ev) => end(/* @__PURE__ */ new Error(`webrun-streams-webrtc: the data channel failed: ${ev.error?.message ?? "unknown"}`));
|
|
381
398
|
dc.addEventListener("message", onMessage);
|
|
399
|
+
dc.addEventListener("open", onOpen);
|
|
382
400
|
dc.addEventListener("close", onClose);
|
|
383
401
|
dc.addEventListener("error", onError);
|
|
384
402
|
if (dc.readyState === "closing" || dc.readyState === "closed") onClose();
|
|
@@ -386,6 +404,8 @@ async function webrtcPortMux(options) {
|
|
|
386
404
|
const cleanUp = () => {
|
|
387
405
|
live.delete(port);
|
|
388
406
|
dc.removeEventListener("message", onMessage);
|
|
407
|
+
dc.removeEventListener("open", onOpen);
|
|
408
|
+
queued = void 0;
|
|
389
409
|
listeners.clear();
|
|
390
410
|
held = void 0;
|
|
391
411
|
if (dc.readyState !== "closed") dc.close();
|
|
@@ -408,18 +428,16 @@ async function webrtcPortMux(options) {
|
|
|
408
428
|
});
|
|
409
429
|
},
|
|
410
430
|
postMessage(message) {
|
|
411
|
-
if (closeSignal.aborted
|
|
431
|
+
if (closeSignal.aborted) return;
|
|
432
|
+
if (!queued && dc.readyState !== "open") return;
|
|
412
433
|
const bytes = codec.encode(message);
|
|
413
434
|
if (bytes.byteLength > maxFrameBytes) {
|
|
414
435
|
const err = /* @__PURE__ */ new RangeError(`webrun-streams-webrtc: a ${bytes.byteLength}-byte message exceeds maxFrameBytes (${maxFrameBytes})`);
|
|
415
436
|
end(err);
|
|
416
437
|
throw err;
|
|
417
438
|
}
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
} catch (err) {
|
|
421
|
-
end(err instanceof Error ? err : new Error(String(err)));
|
|
422
|
-
}
|
|
439
|
+
if (queued) queued.push(bytes);
|
|
440
|
+
else send(bytes);
|
|
423
441
|
},
|
|
424
442
|
addEventListener(_type, listener) {
|
|
425
443
|
listeners.add(listener);
|
package/dist/port-mux.d.ts
CHANGED
|
@@ -67,7 +67,8 @@ export interface WebRtcPortMux {
|
|
|
67
67
|
* ```
|
|
68
68
|
*
|
|
69
69
|
* Messages that arrive before a port's first listener are held for it and delivered after that
|
|
70
|
-
* tick, to every listener added by then.
|
|
70
|
+
* tick, to every listener added by then. Messages posted before a port's channel opens are queued
|
|
71
|
+
* and sent, in order, when it opens.
|
|
71
72
|
*/
|
|
72
73
|
export declare function webrtcPortMux(options: WebRtcPortMuxOptions): Promise<WebRtcPortMux>;
|
|
73
74
|
export {};
|
package/dist/port-mux.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"port-mux.d.ts","sourceRoot":"","sources":["../src/port-mux.ts"],"names":[],"mappings":"AAAA,yFAAyF;AACzF,eAAO,MAAM,iBAAiB,iBAAiB,CAAC;AAEhD;;;GAGG;AACH,eAAO,MAAM,4BAA4B,QAAY,CAAC;AAEtD,sHAAsH;AACtH,eAAO,MAAM,6BAA6B,QAAqC,CAAC;AAEhF,kFAAkF;AAClF,eAAO,MAAM,oBAAoB,QAAa,CAAC;AAE/C;;;GAGG;AACH,MAAM,WAAW,UAAU;IACzB,MAAM,CAAC,KAAK,EAAE,OAAO,GAAG,UAAU,CAAC;IACnC,MAAM,CAAC,KAAK,EAAE,UAAU,GAAG,OAAO,CAAC;CACpC;AAED,KAAK,QAAQ,GAAG,CAAC,KAAK,EAAE,YAAY,KAAK,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;AAE9D,4FAA4F;AAC5F,MAAM,WAAW,eAAe;IAC9B,gBAAgB,CAAC,IAAI,EAAE,SAAS,EAAE,QAAQ,EAAE,QAAQ,GAAG,IAAI,CAAC;IAC5D,mBAAmB,CAAC,IAAI,EAAE,SAAS,EAAE,QAAQ,EAAE,QAAQ,GAAG,IAAI,CAAC;IAC/D,+EAA+E;IAC/E,WAAW,CAAC,OAAO,EAAE,OAAO,GAAG,IAAI,CAAC;IACpC,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;IACvB,QAAQ,CAAC,cAAc,EAAE,MAAM,CAAC;IAChC,WAAW,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;IAC7B,gGAAgG;IAChG,QAAQ,CAAC,WAAW,EAAE,WAAW,CAAC;CACnC;AAED,MAAM,WAAW,oBAAoB;IACnC,wFAAwF;IACxF,EAAE,EAAE,iBAAiB,CAAC;IACtB,kDAAkD;IAClD,KAAK,EAAE,UAAU,CAAC;IAClB;;;;OAIG;IACH,MAAM,CAAC,EAAE,CAAC,IAAI,EAAE,eAAe,KAAK,OAAO,GAAG,SAAS,CAAC;IACxD,mFAAmF;IACnF,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,oDAAoD;IACpD,aAAa,CAAC,EAAE,MAAM,CAAC;CACxB;AAED,+EAA+E;AAC/E,MAAM,WAAW,aAAa;IAC5B,QAAQ,CAAC,IAAI,CAAC,EAAE,OAAO,EAAE,OAAO,CAAC,EAAE;QAAE,MAAM,CAAC,EAAE,WAAW,CAAA;KAAE,GAAG,OAAO,CAAC,eAAe,CAAC,CAAC;IACvF,KAAK,CAAC,MAAM,CAAC,EAAE,OAAO,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IACvC,QAAQ,CAAC,cAAc,EAAE,MAAM,CAAC;CACjC;AAMD
|
|
1
|
+
{"version":3,"file":"port-mux.d.ts","sourceRoot":"","sources":["../src/port-mux.ts"],"names":[],"mappings":"AAAA,yFAAyF;AACzF,eAAO,MAAM,iBAAiB,iBAAiB,CAAC;AAEhD;;;GAGG;AACH,eAAO,MAAM,4BAA4B,QAAY,CAAC;AAEtD,sHAAsH;AACtH,eAAO,MAAM,6BAA6B,QAAqC,CAAC;AAEhF,kFAAkF;AAClF,eAAO,MAAM,oBAAoB,QAAa,CAAC;AAE/C;;;GAGG;AACH,MAAM,WAAW,UAAU;IACzB,MAAM,CAAC,KAAK,EAAE,OAAO,GAAG,UAAU,CAAC;IACnC,MAAM,CAAC,KAAK,EAAE,UAAU,GAAG,OAAO,CAAC;CACpC;AAED,KAAK,QAAQ,GAAG,CAAC,KAAK,EAAE,YAAY,KAAK,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;AAE9D,4FAA4F;AAC5F,MAAM,WAAW,eAAe;IAC9B,gBAAgB,CAAC,IAAI,EAAE,SAAS,EAAE,QAAQ,EAAE,QAAQ,GAAG,IAAI,CAAC;IAC5D,mBAAmB,CAAC,IAAI,EAAE,SAAS,EAAE,QAAQ,EAAE,QAAQ,GAAG,IAAI,CAAC;IAC/D,+EAA+E;IAC/E,WAAW,CAAC,OAAO,EAAE,OAAO,GAAG,IAAI,CAAC;IACpC,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;IACvB,QAAQ,CAAC,cAAc,EAAE,MAAM,CAAC;IAChC,WAAW,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;IAC7B,gGAAgG;IAChG,QAAQ,CAAC,WAAW,EAAE,WAAW,CAAC;CACnC;AAED,MAAM,WAAW,oBAAoB;IACnC,wFAAwF;IACxF,EAAE,EAAE,iBAAiB,CAAC;IACtB,kDAAkD;IAClD,KAAK,EAAE,UAAU,CAAC;IAClB;;;;OAIG;IACH,MAAM,CAAC,EAAE,CAAC,IAAI,EAAE,eAAe,KAAK,OAAO,GAAG,SAAS,CAAC;IACxD,mFAAmF;IACnF,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,oDAAoD;IACpD,aAAa,CAAC,EAAE,MAAM,CAAC;CACxB;AAED,+EAA+E;AAC/E,MAAM,WAAW,aAAa;IAC5B,QAAQ,CAAC,IAAI,CAAC,EAAE,OAAO,EAAE,OAAO,CAAC,EAAE;QAAE,MAAM,CAAC,EAAE,WAAW,CAAA;KAAE,GAAG,OAAO,CAAC,eAAe,CAAC,CAAC;IACvF,KAAK,CAAC,MAAM,CAAC,EAAE,OAAO,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IACvC,QAAQ,CAAC,cAAc,EAAE,MAAM,CAAC;CACjC;AAMD;;;;;;;;;;;;;;;GAeG;AACH,wBAAsB,aAAa,CAAC,OAAO,EAAE,oBAAoB,GAAG,OAAO,CAAC,aAAa,CAAC,CAkOzF"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@statewalker/webrun-streams-webrtc",
|
|
3
|
-
"version": "0.4.
|
|
3
|
+
"version": "0.4.1",
|
|
4
4
|
"private": false,
|
|
5
5
|
"type": "module",
|
|
6
6
|
"description": "WebRTC DataChannel-backed Connect/Serve adapter (native multi-stream) in the webrun-streams-* family",
|
|
@@ -43,8 +43,8 @@
|
|
|
43
43
|
"typescript": "^7.0.2",
|
|
44
44
|
"vitest": "^5.0.5",
|
|
45
45
|
"@statewalker/webrun-msgpack": "^0.11.0",
|
|
46
|
-
"@statewalker/webrun-
|
|
47
|
-
"@statewalker/webrun-
|
|
46
|
+
"@statewalker/webrun-streams-conformance": "^0.5.0",
|
|
47
|
+
"@statewalker/webrun-rpc": "^0.12.0"
|
|
48
48
|
},
|
|
49
49
|
"sideEffects": false,
|
|
50
50
|
"publishConfig": {
|
package/src/port-mux.ts
CHANGED
|
@@ -78,7 +78,8 @@ const claimed = new WeakSet<RTCDataChannel>();
|
|
|
78
78
|
* ```
|
|
79
79
|
*
|
|
80
80
|
* Messages that arrive before a port's first listener are held for it and delivered after that
|
|
81
|
-
* tick, to every listener added by then.
|
|
81
|
+
* tick, to every listener added by then. Messages posted before a port's channel opens are queued
|
|
82
|
+
* and sent, in order, when it opens.
|
|
82
83
|
*/
|
|
83
84
|
export async function webrtcPortMux(options: WebRtcPortMuxOptions): Promise<WebRtcPortMux> {
|
|
84
85
|
const { pc, codec, onPort } = options;
|
|
@@ -132,6 +133,26 @@ export async function webrtcPortMux(options: WebRtcPortMuxOptions): Promise<WebR
|
|
|
132
133
|
if (held) held.push(data);
|
|
133
134
|
else deliver(data);
|
|
134
135
|
};
|
|
136
|
+
// Posts made while the channel is still connecting, sent in order when it opens, as a
|
|
137
|
+
// MessagePort queues them (statewalker/statewalker-root#57). `undefined` once the channel has
|
|
138
|
+
// opened, or when it was open already.
|
|
139
|
+
let queued: Uint8Array[] | undefined = dc.readyState === "connecting" ? [] : undefined;
|
|
140
|
+
const send = (bytes: Uint8Array) => {
|
|
141
|
+
try {
|
|
142
|
+
dc.send(bytes as Uint8Array<ArrayBuffer>);
|
|
143
|
+
} catch (err) {
|
|
144
|
+
// a send queue full, or a channel closing meanwhile: the port is broken
|
|
145
|
+
end(err instanceof Error ? err : new Error(String(err)));
|
|
146
|
+
}
|
|
147
|
+
};
|
|
148
|
+
const onOpen = () => {
|
|
149
|
+
const pending = queued;
|
|
150
|
+
queued = undefined;
|
|
151
|
+
for (const bytes of pending ?? []) {
|
|
152
|
+
if (closeSignal.aborted) return;
|
|
153
|
+
send(bytes);
|
|
154
|
+
}
|
|
155
|
+
};
|
|
135
156
|
const onClose = () => end(new Error("webrun-streams-webrtc: the data channel closed"));
|
|
136
157
|
const onError = (ev: Event) =>
|
|
137
158
|
end(
|
|
@@ -140,6 +161,7 @@ export async function webrtcPortMux(options: WebRtcPortMuxOptions): Promise<WebR
|
|
|
140
161
|
),
|
|
141
162
|
);
|
|
142
163
|
dc.addEventListener("message", onMessage);
|
|
164
|
+
dc.addEventListener("open", onOpen);
|
|
143
165
|
dc.addEventListener("close", onClose);
|
|
144
166
|
dc.addEventListener("error", onError);
|
|
145
167
|
if (dc.readyState === "closing" || dc.readyState === "closed") onClose();
|
|
@@ -147,6 +169,8 @@ export async function webrtcPortMux(options: WebRtcPortMuxOptions): Promise<WebR
|
|
|
147
169
|
const cleanUp = () => {
|
|
148
170
|
live.delete(port);
|
|
149
171
|
dc.removeEventListener("message", onMessage);
|
|
172
|
+
dc.removeEventListener("open", onOpen);
|
|
173
|
+
queued = undefined;
|
|
150
174
|
listeners.clear();
|
|
151
175
|
held = undefined;
|
|
152
176
|
if (dc.readyState !== "closed") dc.close();
|
|
@@ -170,7 +194,9 @@ export async function webrtcPortMux(options: WebRtcPortMuxOptions): Promise<WebR
|
|
|
170
194
|
});
|
|
171
195
|
},
|
|
172
196
|
postMessage(message) {
|
|
173
|
-
if (closeSignal.aborted
|
|
197
|
+
if (closeSignal.aborted) return; // `closeSignal` says so
|
|
198
|
+
// a channel closing or closed: its close event aborts `closeSignal`
|
|
199
|
+
if (!queued && dc.readyState !== "open") return;
|
|
174
200
|
const bytes = codec.encode(message);
|
|
175
201
|
if (bytes.byteLength > maxFrameBytes) {
|
|
176
202
|
const err = new RangeError(
|
|
@@ -179,12 +205,8 @@ export async function webrtcPortMux(options: WebRtcPortMuxOptions): Promise<WebR
|
|
|
179
205
|
end(err);
|
|
180
206
|
throw err;
|
|
181
207
|
}
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
} catch (err) {
|
|
185
|
-
// a send queue full, or a channel closing meanwhile: the port is broken
|
|
186
|
-
end(err instanceof Error ? err : new Error(String(err)));
|
|
187
|
-
}
|
|
208
|
+
if (queued) queued.push(bytes);
|
|
209
|
+
else send(bytes);
|
|
188
210
|
},
|
|
189
211
|
addEventListener(_type, listener) {
|
|
190
212
|
listeners.add(listener);
|