From 5f775eb95001293596b7e9337b3b12edaf5d0e23 Mon Sep 17 00:00:00 2001 From: mertushka Date: Sun, 14 Jun 2026 21:29:49 +0300 Subject: [PATCH] fix: preserve data channel message order --- lib/index.js | 1 + test/basic.test.js | 34 ++++++++++++++++++++++++++++++++++ 2 files changed, 35 insertions(+) diff --git a/lib/index.js b/lib/index.js index 3e1c903..cbbec79 100644 --- a/lib/index.js +++ b/lib/index.js @@ -2101,6 +2101,7 @@ class RTCDataChannel extends SimpleEventTarget { _dispatchNativeMessageBatch(events) { if (this._readyState === "closed") return true; + if (this._queuedMessageEvents.length > 0) return false; const pendingPeer = this._pc._operationsPending > 0 ? this._pc diff --git a/test/basic.test.js b/test/basic.test.js index 64b4755..d76da48 100644 --- a/test/basic.test.js +++ b/test/basic.test.js @@ -679,6 +679,40 @@ test("data-channel opening burst is delivered after the datachannel event task", answerer.close(); }); +test("native message batches do not overtake queued messages", async (t) => { + const peerConnection = new RTCPeerConnection(); + t.after(() => closeAllAndWait(peerConnection)); + const channel = peerConnection.createDataChannel("queued-before-native-batch"); + const queuedEvents = ["message 0", "message 1"].map((data) => ({ + type: "message", + binary: false, + data, + })); + const nativeBatch = ["message 2", "message 3"].map((data) => ({ + type: "message", + binary: false, + data, + })); + const received = []; + const done = new Promise((resolve) => { + channel.onmessage = (event) => { + received.push(event.data); + if (received.length === queuedEvents.length + nativeBatch.length) resolve(); + }; + }); + + channel._queueMessageEvents(queuedEvents); + if (!channel._dispatchNativeMessageBatch(nativeBatch)) { + channel._queueMessageEvents(nativeBatch); + } + await done; + + assert.deepEqual( + received, + [...queuedEvents, ...nativeBatch].map((event) => event.data), + ); +}); + test("message listener added during onmessage receives later burst messages", async (t) => { const offerer = new RTCPeerConnection(); const answerer = new RTCPeerConnection();