@colyseus/core 0.17.43 → 0.18.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.
Files changed (95) hide show
  1. package/build/MatchMaker.cjs +19 -6
  2. package/build/MatchMaker.cjs.map +2 -2
  3. package/build/MatchMaker.d.ts +10 -0
  4. package/build/MatchMaker.mjs +18 -6
  5. package/build/MatchMaker.mjs.map +2 -2
  6. package/build/Protocol.cjs +102 -37
  7. package/build/Protocol.cjs.map +2 -2
  8. package/build/Protocol.d.ts +33 -2
  9. package/build/Protocol.mjs +102 -37
  10. package/build/Protocol.mjs.map +2 -2
  11. package/build/Room.cjs +296 -19
  12. package/build/Room.cjs.map +3 -3
  13. package/build/Room.d.ts +186 -3
  14. package/build/Room.mjs +303 -21
  15. package/build/Room.mjs.map +3 -3
  16. package/build/RoomPlugin.cjs +252 -0
  17. package/build/RoomPlugin.cjs.map +7 -0
  18. package/build/RoomPlugin.d.ts +271 -0
  19. package/build/RoomPlugin.mjs +220 -0
  20. package/build/RoomPlugin.mjs.map +7 -0
  21. package/build/Server.cjs +49 -15
  22. package/build/Server.cjs.map +2 -2
  23. package/build/Server.d.ts +25 -0
  24. package/build/Server.mjs +50 -16
  25. package/build/Server.mjs.map +2 -2
  26. package/build/Transport.cjs +38 -2
  27. package/build/Transport.cjs.map +2 -2
  28. package/build/Transport.d.ts +40 -4
  29. package/build/Transport.mjs +38 -2
  30. package/build/Transport.mjs.map +2 -2
  31. package/build/index.cjs +11 -2
  32. package/build/index.cjs.map +2 -2
  33. package/build/index.d.ts +2 -1
  34. package/build/index.mjs +12 -2
  35. package/build/index.mjs.map +2 -2
  36. package/build/input/InputBuffer.cjs +113 -0
  37. package/build/input/InputBuffer.cjs.map +7 -0
  38. package/build/input/InputBuffer.d.ts +136 -0
  39. package/build/input/InputBuffer.mjs +86 -0
  40. package/build/input/InputBuffer.mjs.map +7 -0
  41. package/build/internal.cjs +61 -0
  42. package/build/internal.cjs.map +7 -0
  43. package/build/internal.d.ts +9 -0
  44. package/build/internal.mjs +29 -0
  45. package/build/internal.mjs.map +7 -0
  46. package/build/matchmaker/LocalDriver/LocalDriver.cjs +13 -0
  47. package/build/matchmaker/LocalDriver/LocalDriver.cjs.map +2 -2
  48. package/build/matchmaker/LocalDriver/LocalDriver.d.ts +1 -0
  49. package/build/matchmaker/LocalDriver/LocalDriver.mjs +13 -0
  50. package/build/matchmaker/LocalDriver/LocalDriver.mjs.map +2 -2
  51. package/build/matchmaker/driver.cjs.map +1 -1
  52. package/build/matchmaker/driver.d.ts +12 -0
  53. package/build/matchmaker/driver.mjs.map +1 -1
  54. package/build/presence/LocalPresence.d.ts +1 -1
  55. package/build/rooms/LobbyRoom.cjs +8 -10
  56. package/build/rooms/LobbyRoom.cjs.map +2 -2
  57. package/build/rooms/LobbyRoom.d.ts +4 -3
  58. package/build/rooms/LobbyRoom.mjs +8 -10
  59. package/build/rooms/LobbyRoom.mjs.map +2 -2
  60. package/build/rooms/RelayRoom.cjs +12 -16
  61. package/build/rooms/RelayRoom.cjs.map +2 -2
  62. package/build/rooms/RelayRoom.d.ts +32 -11
  63. package/build/rooms/RelayRoom.mjs +10 -16
  64. package/build/rooms/RelayRoom.mjs.map +2 -2
  65. package/build/router/index.cjs +65 -4
  66. package/build/router/index.cjs.map +2 -2
  67. package/build/router/index.d.ts +30 -6
  68. package/build/router/index.mjs +66 -6
  69. package/build/router/index.mjs.map +3 -3
  70. package/build/utils/Env.cjs +4 -8
  71. package/build/utils/Env.cjs.map +3 -3
  72. package/build/utils/Env.mjs +4 -8
  73. package/build/utils/Env.mjs.map +2 -2
  74. package/build/utils/UserSessionIndex.cjs +162 -0
  75. package/build/utils/UserSessionIndex.cjs.map +7 -0
  76. package/build/utils/UserSessionIndex.d.ts +166 -0
  77. package/build/utils/UserSessionIndex.mjs +130 -0
  78. package/build/utils/UserSessionIndex.mjs.map +7 -0
  79. package/package.json +20 -15
  80. package/src/MatchMaker.ts +40 -6
  81. package/src/Protocol.ts +130 -59
  82. package/src/Room.ts +475 -22
  83. package/src/RoomPlugin.ts +563 -0
  84. package/src/Server.ts +81 -22
  85. package/src/Transport.ts +76 -8
  86. package/src/index.ts +10 -1
  87. package/src/input/InputBuffer.ts +192 -0
  88. package/src/internal.ts +46 -0
  89. package/src/matchmaker/LocalDriver/LocalDriver.ts +10 -0
  90. package/src/matchmaker/driver.ts +13 -0
  91. package/src/rooms/LobbyRoom.ts +12 -8
  92. package/src/rooms/RelayRoom.ts +9 -15
  93. package/src/router/index.ts +112 -11
  94. package/src/utils/Env.ts +4 -12
  95. package/src/utils/UserSessionIndex.ts +311 -0
@@ -1,5 +1,5 @@
1
1
  // packages/core/src/Protocol.ts
2
- import { Packr } from "@colyseus/msgpackr";
2
+ import { Packr, RESERVE_START_SPACE } from "msgpackr";
3
3
  import { encode } from "@colyseus/schema";
4
4
  import { Protocol } from "@colyseus/shared-types";
5
5
  var IpcProtocol = {
@@ -9,63 +9,128 @@ var IpcProtocol = {
9
9
  };
10
10
  var packr = new Packr({
11
11
  useRecords: false
12
- // increased compatibility with decoders other than "msgpackr"
12
+ // interop with non-msgpackr decoders
13
13
  });
14
- packr.encode(void 0);
14
+ var frameBuffer = Buffer.allocUnsafe(8192);
15
+ function ensureFrameCapacity(capacity) {
16
+ if (capacity > frameBuffer.byteLength) {
17
+ const next = Buffer.allocUnsafe(capacity);
18
+ frameBuffer.copy(next);
19
+ frameBuffer = next;
20
+ }
21
+ }
22
+ var it = { offset: 0 };
15
23
  var getMessageBytes = {
16
- [Protocol.JOIN_ROOM]: (reconnectionToken, serializerId, handshake) => {
17
- const it = { offset: 1 };
18
- packr.buffer[0] = Protocol.JOIN_ROOM;
19
- packr.buffer[it.offset++] = Buffer.byteLength(reconnectionToken, "utf8");
20
- encode.utf8Write(packr.buffer, reconnectionToken, it);
21
- packr.buffer[it.offset++] = Buffer.byteLength(serializerId, "utf8");
22
- encode.utf8Write(packr.buffer, serializerId, it);
24
+ /**
25
+ * Build the JOIN_ROOM payload.
26
+ *
27
+ * Wire layout:
28
+ * [JOIN_ROOM byte][rt-len][rt][sid-len][sid][stateReflectionLen varint][stateReflection][...sections]
29
+ *
30
+ * The varint length prefix on `stateReflection` is required because the
31
+ * schema decoder on the SDK side runs `while (offset < bytes.byteLength)`
32
+ * — without a boundary it consumes past the state reflection into the
33
+ * trailing tagged-section bytes, producing "definition mismatch" warnings.
34
+ * Length is `0` when no state reflection is present.
35
+ *
36
+ * Each trailing section is `[tag (uint8)][length (varint)][payload]`. The
37
+ * SDK skips unknown tags via `length`, so new sections can be added without
38
+ * breaking older clients. See {@link HandshakeSection} in shared-types.
39
+ */
40
+ [Protocol.JOIN_ROOM]: (reconnectionToken, serializerId, handshake, extraSections) => {
41
+ const reconnectionTokenLength = Buffer.byteLength(reconnectionToken, "utf8");
42
+ const serializerIdLength = Buffer.byteLength(serializerId, "utf8");
23
43
  let handshakeLength = handshake?.byteLength || 0;
24
- if (handshakeLength > packr.buffer.byteLength - it.offset) {
25
- packr.useBuffer(Buffer.alloc(it.offset + handshakeLength, packr.buffer));
44
+ let extraLength = 0;
45
+ if (extraSections !== void 0) {
46
+ for (let i = 0; i < extraSections.length; i++) {
47
+ extraLength += 1 + 9 + extraSections[i].bytes.byteLength;
48
+ }
26
49
  }
50
+ ensureFrameCapacity(1 + 1 + reconnectionTokenLength + 1 + serializerIdLength + 9 + handshakeLength + extraLength);
51
+ it.offset = 1;
52
+ frameBuffer[0] = Protocol.JOIN_ROOM;
53
+ frameBuffer[it.offset++] = reconnectionTokenLength;
54
+ encode.utf8Write(frameBuffer, reconnectionToken, it);
55
+ frameBuffer[it.offset++] = serializerIdLength;
56
+ encode.utf8Write(frameBuffer, serializerId, it);
57
+ encode.number(frameBuffer, handshakeLength, it);
27
58
  if (handshakeLength > 0) {
28
- packr.buffer.set(handshake, it.offset);
59
+ frameBuffer.set(handshake, it.offset);
60
+ it.offset += handshakeLength;
29
61
  }
30
- return Buffer.from(packr.buffer.subarray(0, it.offset + handshakeLength));
62
+ if (extraSections !== void 0) {
63
+ for (let i = 0; i < extraSections.length; i++) {
64
+ const section = extraSections[i];
65
+ frameBuffer[it.offset++] = section.tag;
66
+ encode.number(frameBuffer, section.bytes.byteLength, it);
67
+ frameBuffer.set(section.bytes, it.offset);
68
+ it.offset += section.bytes.byteLength;
69
+ }
70
+ }
71
+ return Buffer.from(frameBuffer.subarray(0, it.offset));
31
72
  },
32
73
  [Protocol.ERROR]: (code, message = "") => {
33
- const it = { offset: 1 };
34
- packr.buffer[0] = Protocol.ERROR;
35
- encode.number(packr.buffer, code, it);
36
- encode.string(packr.buffer, message, it);
37
- return Buffer.from(packr.buffer.subarray(0, it.offset));
74
+ ensureFrameCapacity(1 + 9 + 9 + Buffer.byteLength(message, "utf8"));
75
+ it.offset = 1;
76
+ frameBuffer[0] = Protocol.ERROR;
77
+ encode.number(frameBuffer, code, it);
78
+ encode.string(frameBuffer, message, it);
79
+ return Buffer.from(frameBuffer.subarray(0, it.offset));
38
80
  },
39
81
  [Protocol.ROOM_STATE]: (bytes) => {
40
82
  return [Protocol.ROOM_STATE, ...bytes];
41
83
  },
84
+ /**
85
+ * Reply to a client {@link Protocol.ROOM_REQUEST}.
86
+ *
87
+ * Wire layout: `[ROOM_RESPONSE byte][requestId varint][status uint8][msgpack payload?]`
88
+ *
89
+ * `requestId` is opaque — echoed back exactly as the SDK sent it so the
90
+ * pending callback/promise can be correlated. `status` is a
91
+ * {@link ResponseStatus} (0 = OK, 1 = ERROR). The payload is omitted when a
92
+ * handler resolves with `undefined`. Returns a fresh Buffer copy for the
93
+ * same back-pressure reason documented on `raw` below.
94
+ */
95
+ [Protocol.ROOM_RESPONSE]: (requestId, status, message) => {
96
+ it.offset = 1;
97
+ frameBuffer[0] = Protocol.ROOM_RESPONSE;
98
+ encode.number(frameBuffer, requestId, it);
99
+ frameBuffer[it.offset++] = status;
100
+ const headerLength = it.offset;
101
+ if (message !== void 0) {
102
+ const packed = packr.pack(message, RESERVE_START_SPACE | headerLength);
103
+ packed.set(frameBuffer.subarray(0, headerLength), 0);
104
+ return Buffer.from(packed);
105
+ }
106
+ return Buffer.from(frameBuffer.subarray(0, headerLength));
107
+ },
42
108
  [Protocol.PING]: () => {
43
- packr.buffer[0] = Protocol.PING;
44
- return Buffer.from(packr.buffer.subarray(0, 1));
109
+ frameBuffer[0] = Protocol.PING;
110
+ return Buffer.from(frameBuffer.subarray(0, 1));
45
111
  },
112
+ // Returns a fresh copy: frameBuffer/packr are reused next call, but callers pass
113
+ // the result to async consumers (Node retains it for libuv writev across ticks).
114
+ // See benchmark/test-buffer-corruption.ts for the back-pressure repro.
46
115
  raw: (code, type, message, rawMessage) => {
47
- const it = { offset: 1 };
48
- packr.buffer[0] = code;
116
+ it.offset = 1;
117
+ frameBuffer[0] = code;
49
118
  if (typeof type === "string") {
50
- encode.string(packr.buffer, type, it);
119
+ encode.string(frameBuffer, type, it);
51
120
  } else {
52
- encode.number(packr.buffer, type, it);
121
+ encode.number(frameBuffer, type, it);
53
122
  }
123
+ const headerLength = it.offset;
54
124
  if (message !== void 0) {
55
- packr.position = 0;
56
- if (process.env.NODE_ENV !== "production") {
57
- packr.useBuffer(packr.buffer);
58
- }
59
- const endOfBufferOffset = packr.pack(message, 2048 + it.offset).byteLength;
60
- return Buffer.from(packr.buffer.subarray(0, endOfBufferOffset));
125
+ const packed = packr.pack(message, RESERVE_START_SPACE | headerLength);
126
+ packed.set(frameBuffer.subarray(0, headerLength), 0);
127
+ return Buffer.from(packed);
61
128
  } else if (rawMessage !== void 0) {
62
- if (rawMessage.length + it.offset > packr.buffer.byteLength) {
63
- packr.useBuffer(Buffer.alloc(it.offset + rawMessage.length, packr.buffer));
64
- }
65
- packr.buffer.set(rawMessage, it.offset);
66
- return Buffer.from(packr.buffer.subarray(0, it.offset + rawMessage.byteLength));
129
+ ensureFrameCapacity(headerLength + rawMessage.byteLength);
130
+ frameBuffer.set(rawMessage, headerLength);
131
+ return Buffer.from(frameBuffer.subarray(0, headerLength + rawMessage.byteLength));
67
132
  } else {
68
- return Buffer.from(packr.buffer.subarray(0, it.offset));
133
+ return Buffer.from(frameBuffer.subarray(0, headerLength));
69
134
  }
70
135
  }
71
136
  };
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../src/Protocol.ts"],
4
- "sourcesContent": ["import { Packr } from '@colyseus/msgpackr';\nimport { encode, type Iterator } from '@colyseus/schema';\nimport { Protocol } from '@colyseus/shared-types';\n\n// Inter-process communication protocol\nexport const IpcProtocol = {\n SUCCESS: 0,\n ERROR: 1,\n TIMEOUT: 2,\n} as const;\nexport type IpcProtocol = typeof IpcProtocol[keyof typeof IpcProtocol];\n\nconst packr = new Packr({\n useRecords: false, // increased compatibility with decoders other than \"msgpackr\"\n});\n\n// msgpackr workaround: initialize buffer\npackr.encode(undefined);\n\nexport const getMessageBytes = {\n [Protocol.JOIN_ROOM]: (reconnectionToken: string, serializerId: string, handshake?: Uint8Array) => {\n const it: Iterator = { offset: 1 };\n packr.buffer[0] = Protocol.JOIN_ROOM;\n\n packr.buffer[it.offset++] = Buffer.byteLength(reconnectionToken, \"utf8\");\n encode.utf8Write(packr.buffer, reconnectionToken, it);\n\n packr.buffer[it.offset++] = Buffer.byteLength(serializerId, \"utf8\");\n encode.utf8Write(packr.buffer, serializerId, it);\n\n let handshakeLength = handshake?.byteLength || 0;\n\n // check if buffer needs to be resized\n if (handshakeLength > packr.buffer.byteLength - it.offset) {\n packr.useBuffer(Buffer.alloc(it.offset + handshakeLength, packr.buffer));\n }\n\n if (handshakeLength > 0) {\n packr.buffer.set(handshake, it.offset);\n }\n\n return Buffer.from(packr.buffer.subarray(0, it.offset + handshakeLength));\n },\n\n [Protocol.ERROR]: (code: number, message: string = '') => {\n const it: Iterator = { offset: 1 };\n packr.buffer[0] = Protocol.ERROR;\n\n encode.number(packr.buffer, code, it);\n encode.string(packr.buffer, message, it);\n\n return Buffer.from(packr.buffer.subarray(0, it.offset));\n },\n\n [Protocol.ROOM_STATE]: (bytes: number[]) => {\n return [Protocol.ROOM_STATE, ...bytes];\n },\n\n [Protocol.PING]: () => {\n packr.buffer[0] = Protocol.PING;\n return Buffer.from(packr.buffer.subarray(0, 1));\n },\n\n raw: (code: Protocol, type: string | number, message?: any, rawMessage?: Uint8Array | Buffer) => {\n const it: Iterator = { offset: 1 };\n packr.buffer[0] = code;\n\n if (typeof (type) === 'string') {\n encode.string(packr.buffer, type, it);\n\n } else {\n encode.number(packr.buffer, type, it);\n }\n\n if (message !== undefined) {\n // force to encode from offset\n packr.position = 0;\n\n //\n // TODO: remove this after issue is fixed https://github.com/kriszyp/msgpackr/issues/139\n //\n // - This check is only required when running integration tests.\n // (colyseus.js' usage of msgpackr/buffer is conflicting)\n //\n if (process.env.NODE_ENV !== \"production\") {\n packr.useBuffer(packr.buffer);\n }\n\n // pack message into the same packr.buffer\n const endOfBufferOffset = packr.pack(message, 2048 + it.offset).byteLength;\n // 2048 = RESERVE_START_SPACE\n return Buffer.from(packr.buffer.subarray(0, endOfBufferOffset));\n\n } else if (rawMessage !== undefined) {\n\n // check if buffer needs to be resized\n // TODO: can we avoid this?\n if (rawMessage.length + it.offset > packr.buffer.byteLength) {\n packr.useBuffer(Buffer.alloc(it.offset + rawMessage.length, packr.buffer));\n }\n\n // copy raw message into packr.buffer\n packr.buffer.set(rawMessage, it.offset);\n\n return Buffer.from(packr.buffer.subarray(0, it.offset + rawMessage.byteLength));\n\n } else {\n return Buffer.from(packr.buffer.subarray(0, it.offset));\n }\n },\n\n};\n\n"],
5
- "mappings": "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",
4
+ "sourcesContent": ["import { Packr, RESERVE_START_SPACE } from 'msgpackr';\nimport { encode, type Iterator } from '@colyseus/schema';\nimport { Protocol } from '@colyseus/shared-types';\n\n// Inter-process communication protocol\nexport const IpcProtocol = {\n SUCCESS: 0,\n ERROR: 1,\n TIMEOUT: 2,\n} as const;\nexport type IpcProtocol = typeof IpcProtocol[keyof typeof IpcProtocol];\n\nconst packr = new Packr({\n useRecords: false, // interop with non-msgpackr decoders\n});\n\n// Buffer for assembling outgoing frames; keeps us off msgpackr's internal\n// buffer so `core` can use the upstream package directly.\nlet frameBuffer = Buffer.allocUnsafe(8192);\n\n// Grow to `capacity`, preserving written bytes (`rawMessage` writes the header\n// before the payload size is known).\nfunction ensureFrameCapacity(capacity: number) {\n if (capacity > frameBuffer.byteLength) {\n const next = Buffer.allocUnsafe(capacity);\n frameBuffer.copy(next);\n frameBuffer = next;\n }\n}\n\n// Shared across calls to avoid a per-call allocation on the hot send path.\n// Safe: encode.* mutate `.offset` in place and never re-enter this module.\nconst it: Iterator = { offset: 0 };\n\nexport const getMessageBytes = {\n /**\n * Build the JOIN_ROOM payload.\n *\n * Wire layout:\n * [JOIN_ROOM byte][rt-len][rt][sid-len][sid][stateReflectionLen varint][stateReflection][...sections]\n *\n * The varint length prefix on `stateReflection` is required because the\n * schema decoder on the SDK side runs `while (offset < bytes.byteLength)`\n * \u2014 without a boundary it consumes past the state reflection into the\n * trailing tagged-section bytes, producing \"definition mismatch\" warnings.\n * Length is `0` when no state reflection is present.\n *\n * Each trailing section is `[tag (uint8)][length (varint)][payload]`. The\n * SDK skips unknown tags via `length`, so new sections can be added without\n * breaking older clients. See {@link HandshakeSection} in shared-types.\n */\n [Protocol.JOIN_ROOM]: (\n reconnectionToken: string,\n serializerId: string,\n handshake?: Uint8Array,\n extraSections?: Array<{ tag: number; bytes: Uint8Array }>,\n ) => {\n const reconnectionTokenLength = Buffer.byteLength(reconnectionToken, \"utf8\");\n const serializerIdLength = Buffer.byteLength(serializerId, \"utf8\");\n let handshakeLength = handshake?.byteLength || 0;\n\n // per section: 1 tag byte + 9 (max varint) + payload\n let extraLength = 0;\n if (extraSections !== undefined) {\n for (let i = 0; i < extraSections.length; i++) {\n extraLength += 1 + 9 + extraSections[i].bytes.byteLength;\n }\n }\n\n // capacity: header + 9 (handshake-len varint) + handshake + sections\n ensureFrameCapacity(1 + 1 + reconnectionTokenLength + 1 + serializerIdLength + 9 + handshakeLength + extraLength);\n\n it.offset = 1;\n frameBuffer[0] = Protocol.JOIN_ROOM;\n\n frameBuffer[it.offset++] = reconnectionTokenLength;\n encode.utf8Write(frameBuffer, reconnectionToken, it);\n\n frameBuffer[it.offset++] = serializerIdLength;\n encode.utf8Write(frameBuffer, serializerId, it);\n\n encode.number(frameBuffer, handshakeLength, it);\n if (handshakeLength > 0) {\n frameBuffer.set(handshake, it.offset);\n it.offset += handshakeLength;\n }\n\n if (extraSections !== undefined) {\n for (let i = 0; i < extraSections.length; i++) {\n const section = extraSections[i];\n frameBuffer[it.offset++] = section.tag;\n encode.number(frameBuffer, section.bytes.byteLength, it);\n frameBuffer.set(section.bytes, it.offset);\n it.offset += section.bytes.byteLength;\n }\n }\n\n return Buffer.from(frameBuffer.subarray(0, it.offset));\n },\n\n [Protocol.ERROR]: (code: number, message: string = '') => {\n // capacity: 1 + code varint + length-prefixed message\n ensureFrameCapacity(1 + 9 + 9 + Buffer.byteLength(message, \"utf8\"));\n\n it.offset = 1;\n frameBuffer[0] = Protocol.ERROR;\n\n encode.number(frameBuffer, code, it);\n encode.string(frameBuffer, message, it);\n\n return Buffer.from(frameBuffer.subarray(0, it.offset));\n },\n\n [Protocol.ROOM_STATE]: (bytes: number[]) => {\n return [Protocol.ROOM_STATE, ...bytes];\n },\n\n /**\n * Reply to a client {@link Protocol.ROOM_REQUEST}.\n *\n * Wire layout: `[ROOM_RESPONSE byte][requestId varint][status uint8][msgpack payload?]`\n *\n * `requestId` is opaque \u2014 echoed back exactly as the SDK sent it so the\n * pending callback/promise can be correlated. `status` is a\n * {@link ResponseStatus} (0 = OK, 1 = ERROR). The payload is omitted when a\n * handler resolves with `undefined`. Returns a fresh Buffer copy for the\n * same back-pressure reason documented on `raw` below.\n */\n [Protocol.ROOM_RESPONSE]: (requestId: number, status: number, message?: any): Buffer => {\n it.offset = 1;\n frameBuffer[0] = Protocol.ROOM_RESPONSE;\n\n encode.number(frameBuffer, requestId, it);\n frameBuffer[it.offset++] = status;\n const headerLength = it.offset;\n\n if (message !== undefined) {\n // reserve `headerLength` bytes up front in the pack output for the header\n const packed = packr.pack(message, RESERVE_START_SPACE | headerLength);\n packed.set(frameBuffer.subarray(0, headerLength), 0);\n return Buffer.from(packed);\n }\n\n return Buffer.from(frameBuffer.subarray(0, headerLength));\n },\n\n [Protocol.PING]: () => {\n frameBuffer[0] = Protocol.PING;\n return Buffer.from(frameBuffer.subarray(0, 1));\n },\n\n // Returns a fresh copy: frameBuffer/packr are reused next call, but callers pass\n // the result to async consumers (Node retains it for libuv writev across ticks).\n // See benchmark/test-buffer-corruption.ts for the back-pressure repro.\n raw: (code: Protocol, type: string | number, message?: any, rawMessage?: Uint8Array | Buffer): Buffer => {\n it.offset = 1;\n frameBuffer[0] = code;\n\n if (typeof (type) === 'string') {\n encode.string(frameBuffer, type, it);\n\n } else {\n encode.number(frameBuffer, type, it);\n }\n const headerLength = it.offset;\n\n if (message !== undefined) {\n // reserve `headerLength` bytes up front in the pack output for the header\n const packed = packr.pack(message, RESERVE_START_SPACE | headerLength);\n packed.set(frameBuffer.subarray(0, headerLength), 0);\n return Buffer.from(packed);\n\n } else if (rawMessage !== undefined) {\n ensureFrameCapacity(headerLength + rawMessage.byteLength);\n frameBuffer.set(rawMessage, headerLength);\n return Buffer.from(frameBuffer.subarray(0, headerLength + rawMessage.byteLength));\n\n } else {\n return Buffer.from(frameBuffer.subarray(0, headerLength));\n }\n },\n\n};\n\n"],
5
+ "mappings": ";AAAA,SAAS,OAAO,2BAA2B;AAC3C,SAAS,cAA6B;AACtC,SAAS,gBAAgB;AAGlB,IAAM,cAAc;AAAA,EACzB,SAAS;AAAA,EACT,OAAO;AAAA,EACP,SAAS;AACX;AAGA,IAAM,QAAQ,IAAI,MAAM;AAAA,EACtB,YAAY;AAAA;AACd,CAAC;AAID,IAAI,cAAc,OAAO,YAAY,IAAI;AAIzC,SAAS,oBAAoB,UAAkB;AAC7C,MAAI,WAAW,YAAY,YAAY;AACrC,UAAM,OAAO,OAAO,YAAY,QAAQ;AACxC,gBAAY,KAAK,IAAI;AACrB,kBAAc;AAAA,EAChB;AACF;AAIA,IAAM,KAAe,EAAE,QAAQ,EAAE;AAE1B,IAAM,kBAAkB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAiB7B,CAAC,SAAS,SAAS,GAAG,CACpB,mBACA,cACA,WACA,kBACG;AACH,UAAM,0BAA0B,OAAO,WAAW,mBAAmB,MAAM;AAC3E,UAAM,qBAAqB,OAAO,WAAW,cAAc,MAAM;AACjE,QAAI,kBAAkB,WAAW,cAAc;AAG/C,QAAI,cAAc;AAClB,QAAI,kBAAkB,QAAW;AAC/B,eAAS,IAAI,GAAG,IAAI,cAAc,QAAQ,KAAK;AAC7C,uBAAe,IAAI,IAAI,cAAc,CAAC,EAAE,MAAM;AAAA,MAChD;AAAA,IACF;AAGA,wBAAoB,IAAI,IAAI,0BAA0B,IAAI,qBAAqB,IAAI,kBAAkB,WAAW;AAEhH,OAAG,SAAS;AACZ,gBAAY,CAAC,IAAI,SAAS;AAE1B,gBAAY,GAAG,QAAQ,IAAI;AAC3B,WAAO,UAAU,aAAa,mBAAmB,EAAE;AAEnD,gBAAY,GAAG,QAAQ,IAAI;AAC3B,WAAO,UAAU,aAAa,cAAc,EAAE;AAE9C,WAAO,OAAO,aAAa,iBAAiB,EAAE;AAC9C,QAAI,kBAAkB,GAAG;AACvB,kBAAY,IAAI,WAAW,GAAG,MAAM;AACpC,SAAG,UAAU;AAAA,IACf;AAEA,QAAI,kBAAkB,QAAW;AAC/B,eAAS,IAAI,GAAG,IAAI,cAAc,QAAQ,KAAK;AAC7C,cAAM,UAAU,cAAc,CAAC;AAC/B,oBAAY,GAAG,QAAQ,IAAI,QAAQ;AACnC,eAAO,OAAO,aAAa,QAAQ,MAAM,YAAY,EAAE;AACvD,oBAAY,IAAI,QAAQ,OAAO,GAAG,MAAM;AACxC,WAAG,UAAU,QAAQ,MAAM;AAAA,MAC7B;AAAA,IACF;AAEA,WAAO,OAAO,KAAK,YAAY,SAAS,GAAG,GAAG,MAAM,CAAC;AAAA,EACvD;AAAA,EAEA,CAAC,SAAS,KAAK,GAAG,CAAC,MAAc,UAAkB,OAAO;AAExD,wBAAoB,IAAI,IAAI,IAAI,OAAO,WAAW,SAAS,MAAM,CAAC;AAElE,OAAG,SAAS;AACZ,gBAAY,CAAC,IAAI,SAAS;AAE1B,WAAO,OAAO,aAAa,MAAM,EAAE;AACnC,WAAO,OAAO,aAAa,SAAS,EAAE;AAEtC,WAAO,OAAO,KAAK,YAAY,SAAS,GAAG,GAAG,MAAM,CAAC;AAAA,EACvD;AAAA,EAEA,CAAC,SAAS,UAAU,GAAG,CAAC,UAAoB;AAC1C,WAAO,CAAC,SAAS,YAAY,GAAG,KAAK;AAAA,EACvC;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAaA,CAAC,SAAS,aAAa,GAAG,CAAC,WAAmB,QAAgB,YAA0B;AACtF,OAAG,SAAS;AACZ,gBAAY,CAAC,IAAI,SAAS;AAE1B,WAAO,OAAO,aAAa,WAAW,EAAE;AACxC,gBAAY,GAAG,QAAQ,IAAI;AAC3B,UAAM,eAAe,GAAG;AAExB,QAAI,YAAY,QAAW;AAEzB,YAAM,SAAS,MAAM,KAAK,SAAS,sBAAsB,YAAY;AACrE,aAAO,IAAI,YAAY,SAAS,GAAG,YAAY,GAAG,CAAC;AACnD,aAAO,OAAO,KAAK,MAAM;AAAA,IAC3B;AAEA,WAAO,OAAO,KAAK,YAAY,SAAS,GAAG,YAAY,CAAC;AAAA,EAC1D;AAAA,EAEA,CAAC,SAAS,IAAI,GAAG,MAAM;AACrB,gBAAY,CAAC,IAAI,SAAS;AAC1B,WAAO,OAAO,KAAK,YAAY,SAAS,GAAG,CAAC,CAAC;AAAA,EAC/C;AAAA;AAAA;AAAA;AAAA,EAKA,KAAK,CAAC,MAAgB,MAAuB,SAAe,eAA6C;AACvG,OAAG,SAAS;AACZ,gBAAY,CAAC,IAAI;AAEjB,QAAI,OAAQ,SAAU,UAAU;AAC9B,aAAO,OAAO,aAAa,MAAM,EAAE;AAAA,IAErC,OAAO;AACL,aAAO,OAAO,aAAa,MAAM,EAAE;AAAA,IACrC;AACA,UAAM,eAAe,GAAG;AAExB,QAAI,YAAY,QAAW;AAEzB,YAAM,SAAS,MAAM,KAAK,SAAS,sBAAsB,YAAY;AACrE,aAAO,IAAI,YAAY,SAAS,GAAG,YAAY,GAAG,CAAC;AACnD,aAAO,OAAO,KAAK,MAAM;AAAA,IAE3B,WAAW,eAAe,QAAW;AACnC,0BAAoB,eAAe,WAAW,UAAU;AACxD,kBAAY,IAAI,YAAY,YAAY;AACxC,aAAO,OAAO,KAAK,YAAY,SAAS,GAAG,eAAe,WAAW,UAAU,CAAC;AAAA,IAElF,OAAO;AACL,aAAO,OAAO,KAAK,YAAY,SAAS,GAAG,YAAY,CAAC;AAAA,IAC1D;AAAA,EACF;AAEF;",
6
6
  "names": []
7
7
  }