@colyseus/sdk 0.17.41 → 0.17.42

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 (48) hide show
  1. package/build/3rd_party/discord.cjs +1 -1
  2. package/build/3rd_party/discord.mjs +1 -1
  3. package/build/Auth.cjs +1 -1
  4. package/build/Auth.mjs +1 -1
  5. package/build/Client.cjs +1 -1
  6. package/build/Client.mjs +1 -1
  7. package/build/Connection.cjs +1 -1
  8. package/build/Connection.mjs +1 -1
  9. package/build/HTTP.cjs +1 -1
  10. package/build/HTTP.mjs +1 -1
  11. package/build/Room.cjs +1 -1
  12. package/build/Room.mjs +1 -1
  13. package/build/Storage.cjs +1 -1
  14. package/build/Storage.mjs +1 -1
  15. package/build/core/nanoevents.cjs +1 -1
  16. package/build/core/nanoevents.mjs +1 -1
  17. package/build/core/signal.cjs +1 -1
  18. package/build/core/signal.mjs +1 -1
  19. package/build/core/utils.cjs +1 -1
  20. package/build/core/utils.mjs +1 -1
  21. package/build/debug.cjs +1 -1
  22. package/build/debug.mjs +1 -1
  23. package/build/errors/Errors.cjs +1 -1
  24. package/build/errors/Errors.mjs +1 -1
  25. package/build/fetchXHR.cjs +1 -1
  26. package/build/fetchXHR.mjs +1 -1
  27. package/build/index.cjs +1 -1
  28. package/build/index.mjs +1 -1
  29. package/build/legacy.cjs +1 -1
  30. package/build/legacy.mjs +1 -1
  31. package/build/serializer/NoneSerializer.cjs +1 -1
  32. package/build/serializer/NoneSerializer.mjs +1 -1
  33. package/build/serializer/SchemaSerializer.cjs +1 -1
  34. package/build/serializer/SchemaSerializer.mjs +1 -1
  35. package/build/serializer/Serializer.cjs +1 -1
  36. package/build/serializer/Serializer.mjs +1 -1
  37. package/build/transport/H3Transport.cjs +70 -21
  38. package/build/transport/H3Transport.cjs.map +1 -1
  39. package/build/transport/H3Transport.d.ts +16 -0
  40. package/build/transport/H3Transport.mjs +69 -23
  41. package/build/transport/H3Transport.mjs.map +1 -1
  42. package/build/transport/WebSocketTransport.cjs +1 -1
  43. package/build/transport/WebSocketTransport.mjs +1 -1
  44. package/dist/colyseus.js +69 -21
  45. package/dist/colyseus.js.map +1 -1
  46. package/dist/debug.js +1 -1
  47. package/package.json +2 -2
  48. package/src/transport/H3Transport.ts +74 -24
package/dist/debug.js CHANGED
@@ -3,7 +3,7 @@
3
3
  // This software is released under the MIT License.
4
4
  // https://opensource.org/license/MIT
5
5
  //
6
- // colyseus.js@0.17.41
6
+ // colyseus.js@0.17.42
7
7
  (function (Client_ts, sharedTypes) {
8
8
  'use strict';
9
9
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@colyseus/sdk",
3
- "version": "0.17.41",
3
+ "version": "0.17.42",
4
4
  "description": "Colyseus Multiplayer SDK for JavaScript/TypeScript",
5
5
  "author": "Endel Dreyer",
6
6
  "license": "MIT",
@@ -82,7 +82,7 @@
82
82
  "typescript": "^5.9.3",
83
83
  "vite": "^5.0.11",
84
84
  "vitest": "^2.1.1",
85
- "@colyseus/core": "^0.17.41"
85
+ "@colyseus/core": "^0.17.42"
86
86
  },
87
87
  "peerDependencies": {
88
88
  "@colyseus/core": "0.17.x"
@@ -1,6 +1,69 @@
1
1
  import { encode, decode, type Iterator } from '@colyseus/schema';
2
2
  import type { ITransport, ITransportEventMap } from "./ITransport.ts";
3
3
 
4
+ // 9 bytes is the maximum length of a variable-length integer prefix
5
+ const MAX_LENGTH_PREFIX_BYTES = 9;
6
+
7
+ /**
8
+ * Reassembles length-prefixed frames from arbitrary byte chunks.
9
+ *
10
+ * A single WebTransport `reader.read()` may:
11
+ * - deliver multiple whole frames in one chunk
12
+ * - split a frame (or its length prefix) across multiple chunks
13
+ *
14
+ * This reassembler buffers partial data across reads so each dispatched
15
+ * frame is exactly one complete message.
16
+ */
17
+ export class FrameReassembler {
18
+ private pending: Uint8Array = new Uint8Array(0);
19
+
20
+ push(chunk: Uint8Array | undefined): Uint8Array[] {
21
+ if (!chunk || chunk.byteLength === 0) { return []; }
22
+
23
+ const bytes = (this.pending.byteLength === 0)
24
+ ? chunk
25
+ : concatBytes(this.pending, chunk);
26
+
27
+ const frames: Uint8Array[] = [];
28
+ let offset = 0;
29
+
30
+ while (offset < bytes.byteLength) {
31
+ const it: Iterator = { offset };
32
+ let length: number;
33
+
34
+ try {
35
+ length = decode.number(bytes as any, it);
36
+ } catch (e) {
37
+ // length prefix is incomplete — wait for more bytes
38
+ if (bytes.byteLength - offset <= MAX_LENGTH_PREFIX_BYTES) { break; }
39
+ throw e;
40
+ }
41
+
42
+ const frameEnd = it.offset + length;
43
+ if (frameEnd > bytes.byteLength) {
44
+ // payload is incomplete — wait for more bytes
45
+ break;
46
+ }
47
+
48
+ frames.push(bytes.subarray(it.offset, frameEnd));
49
+ offset = frameEnd;
50
+ }
51
+
52
+ this.pending = (offset < bytes.byteLength)
53
+ ? bytes.slice(offset)
54
+ : new Uint8Array(0);
55
+
56
+ return frames;
57
+ }
58
+ }
59
+
60
+ function concatBytes(a: Uint8Array, b: Uint8Array): Uint8Array {
61
+ const out = new Uint8Array(a.byteLength + b.byteLength);
62
+ out.set(a, 0);
63
+ out.set(b, a.byteLength);
64
+ return out;
65
+ }
66
+
4
67
  export class H3TransportTransport implements ITransport {
5
68
  wt: WebTransport;
6
69
  isOpen: boolean = false;
@@ -14,6 +77,9 @@ export class H3TransportTransport implements ITransport {
14
77
 
15
78
  private lengthPrefixBuffer = new Uint8Array(9); // 9 bytes is the maximum length of a length prefix
16
79
 
80
+ private reliableReassembler = new FrameReassembler();
81
+ private unreliableReassembler = new FrameReassembler();
82
+
17
83
  constructor(events: ITransportEventMap) {
18
84
  this.events = events;
19
85
  }
@@ -110,19 +176,11 @@ export class H3TransportTransport implements ITransport {
110
176
  //
111
177
  // a single read may contain multiple messages
112
178
  // each message is prefixed with its length
179
+ // a read may also deliver a partial frame; buffer across reads
113
180
  //
114
-
115
- const messages = result.value;
116
- const it: Iterator = { offset: 0 };
117
- do {
118
- //
119
- // QUESTION: should we buffer the message in case it's not fully read?
120
- //
121
-
122
- const length = decode.number(messages as any, it);
123
- this.events.onmessage({ data: messages.subarray(it.offset, it.offset + length) });
124
- it.offset += length;
125
- } while (it.offset < messages.length);
181
+ for (const frame of this.reliableReassembler.push(result.value)) {
182
+ this.events.onmessage({ data: frame });
183
+ }
126
184
 
127
185
  } catch (e) {
128
186
  if (e.message.indexOf("session is closed") === -1) {
@@ -147,19 +205,11 @@ export class H3TransportTransport implements ITransport {
147
205
  //
148
206
  // a single read may contain multiple messages
149
207
  // each message is prefixed with its length
208
+ // a read may also deliver a partial frame; buffer across reads
150
209
  //
151
-
152
- const messages = result.value;
153
- const it: Iterator = { offset: 0 };
154
- do {
155
- //
156
- // QUESTION: should we buffer the message in case it's not fully read?
157
- //
158
-
159
- const length = decode.number(messages as any, it);
160
- this.events.onmessage({ data: messages.subarray(it.offset, it.offset + length) });
161
- it.offset += length;
162
- } while (it.offset < messages.length);
210
+ for (const frame of this.unreliableReassembler.push(result.value)) {
211
+ this.events.onmessage({ data: frame });
212
+ }
163
213
 
164
214
  } catch (e) {
165
215
  if (e.message.indexOf("session is closed") === -1) {