From 43ad0da01556f424c590304e45a9c8c58b366c74 Mon Sep 17 00:00:00 2001 From: infinia-yzl Date: Fri, 15 May 2026 15:50:14 +0800 Subject: [PATCH] feat(transport): adopt v3 WebSocket subprotocol MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit clockworklabs/SpacetimeDB 2.2.0 introduced a v3 WebSocket transport (PR #4761) with subprotocol identifier `v3.bsatn.spacetimedb`. v3 keeps the v2 ClientMessage / ServerMessage schema intact — the only on-the-wire change is that a single WebSocket payload may contain one OR more BSATN-encoded v2 messages concatenated back to back. Senders may coalesce as they please; receivers decode sequentially until end-of-buffer. The existing BSATNDeserializer.process_bytes_and_extract_messages already loops decoding messages from the incoming buffer until empty, so the receive-side semantics work for free on v3. The send side keeps sending one logical message per frame, still valid v3. Verified manually against a SpacetimeDB 2.2.0 server: curl -s -i -N \ -H "Connection: Upgrade" -H "Upgrade: websocket" \ -H "Sec-WebSocket-Version: 13" \ -H "Sec-WebSocket-Key: dGhlIHNhbXBsZSBub25jZQ==" \ -H "Sec-WebSocket-Protocol: v3.bsatn.spacetimedb" \ -H "Authorization: Bearer " \ http://localhost:3333/v1/database//subscribe returns `HTTP/1.1 101 Switching Protocols` with `sec-websocket-protocol: v3.bsatn.spacetimedb` and proceeds with normal message dispatch (IdentityToken delivered immediately). Also verified end-to-end via integration tests in a downstream project: anonymous connect + subscribe + iter() round-trip, plus an overlapping-subscription audit (subscribe narrow, then subscribe wide; assert on_insert fires exactly once for the new row and zero additional times for the already-cached row — analogous to the Unreal SDK fix in #4903). --- .../SpacetimeDB/core/spacetimedb_connection.gd | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/godot-client/addons/SpacetimeDB/core/spacetimedb_connection.gd b/godot-client/addons/SpacetimeDB/core/spacetimedb_connection.gd index f336c594..5c379dad 100644 --- a/godot-client/addons/SpacetimeDB/core/spacetimedb_connection.gd +++ b/godot-client/addons/SpacetimeDB/core/spacetimedb_connection.gd @@ -9,7 +9,20 @@ var _connection_requested: bool = false var _debug_mode: bool = false var version: String = "v1" # Protocol constants -const BSATN_PROTOCOL = "v2.bsatn.spacetimedb" +# +# v3 (SpacetimeDB 2.2.0+, clockworklabs/SpacetimeDB PR #4761) does not +# introduce a new outer message schema — it reuses the v2 ClientMessage / +# ServerMessage values. The only on-the-wire change is that a single +# WebSocket payload can contain one OR more BSATN-encoded v2 messages +# concatenated back to back; senders may coalesce as they please, receivers +# must decode sequentially until end-of-buffer. +# +# The existing BSATNDeserializer.process_bytes_and_extract_messages already +# loops decoding messages from the incoming buffer until empty, so the +# receive-side semantics work for free on v3. The send side keeps sending +# one logical message per frame, which is still valid v3. A future +# optimization is to coalesce client-side sends; not done in this PR. +const BSATN_PROTOCOL = "v3.bsatn.spacetimedb" enum CompressionPreference { NONE = 0, BROTLI = 1, GZIP = 2 } var preferred_compression: CompressionPreference = CompressionPreference.NONE # Default to None