@colyseus/bun-websockets 0.15.3 → 0.16.0-alpha.5

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/README.md CHANGED
@@ -7,19 +7,19 @@
7
7
  <a href="https://npmjs.com/package/colyseus">
8
8
  <img src="https://img.shields.io/npm/dm/colyseus.svg?style=for-the-badge&logo=data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAQAAAC1+jfqAAAABGdBTUEAALGPC/xhBQAAACBjSFJNAAB6JgAAgIQAAPoAAACA6AAAdTAAAOpgAAA6mAAAF3CculE8AAAAAmJLR0QAAKqNIzIAAAAJcEhZcwAADsQAAA7EAZUrDhsAAAAHdElNRQfjAgETESWYxR33AAAAtElEQVQoz4WQMQrCQBRE38Z0QoTcwF4Qg1h4BO0sxGOk80iCtViksrIQRRBTewWxMI1mbELYjYu+4rPMDPtn12ChMT3gavb4US5Jym0tcBIta3oDHv4Gwmr7nC4QAxBrCdzM2q6XqUnm9m9r59h7Rc0n2pFv24k4ttGMUXW+sGELTJjSr7QDKuqLS6UKFChVWWuFkZw9Z2AAvAirKT+JTlppIRnd6XgaP4goefI2Shj++OnjB3tBmHYK8z9zAAAAJXRFWHRkYXRlOmNyZWF0ZQAyMDE5LTAyLTAxVDE4OjE3OjM3KzAxOjAwGQQixQAAACV0RVh0ZGF0ZTptb2RpZnkAMjAxOS0wMi0wMVQxODoxNzozNyswMTowMGhZmnkAAAAZdEVYdFNvZnR3YXJlAHd3dy5pbmtzY2FwZS5vcmeb7jwaAAAAAElFTkSuQmCC">
9
9
  </a>
10
- <a href="https://github.com/colyseus/colyseus/discussions" title="Discuss on Forum">
11
- <img src="https://img.shields.io/badge/discuss-on%20forum-brightgreen.svg?style=for-the-badge&colorB=0069b8&logo=data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAQAAAC1+jfqAAAABGdBTUEAALGPC/xhBQAAACBjSFJNAAB6JgAAgIQAAPoAAACA6AAAdTAAAOpgAAA6mAAAF3CculE8AAAAAmJLR0QAAKqNIzIAAAAJcEhZcwAADsQAAA7EAZUrDhsAAAAHdElNRQfjAgETDROxCNUzAAABB0lEQVQoz4WRvyvEARjGP193CnWRH+dHQmGwKZtFGcSmxHAL400GN95ktIpV2dzlLzDJgsGgGNRdDAzoQueS/PgY3HXHyT3T+/Y87/s89UANBKXBdoZo5J6L4K1K5ZxHfnjnlQUf3bKvkgy57a0r9hS3cXfMO1kWJMza++tj3Ac7/LY343x1NA9cNmYMwnSS/SP8JVFuSJmr44iFqvtmpjhmhBCrOOazCesq6H4P3bPBjFoIBydOk2bUA17I080Es+wSZ51B4DIA2zgjSpYcEe44Js01G0XjRcCU+y4ZMrDeLmfc9EnVd5M/o0VMeu6nJZxWJivLmhyw1WHTvrr2b4+2OFqra+ALwouTMDcqmjMAAAAldEVYdGRhdGU6Y3JlYXRlADIwMTktMDItMDFUMTg6MTM6MTkrMDE6MDAC9f6fAAAAJXRFWHRkYXRlOm1vZGlmeQAyMDE5LTAyLTAxVDE4OjEzOjE5KzAxOjAwc6hGIwAAABl0RVh0U29mdHdhcmUAd3d3Lmlua3NjYXBlLm9yZ5vuPBoAAAAASUVORK5CYII=" alt="Discussion forum" />
12
- </a>
13
10
  <a href="http://chat.colyseus.io">
14
11
  <img src="https://img.shields.io/discord/525739117951320081.svg?style=for-the-badge&colorB=7581dc&logo=discord&logoColor=white">
15
12
  </a>
13
+ <a href="https://github.com/colyseus/colyseus/discussions" title="Discuss on Forum">
14
+ <img src="https://img.shields.io/badge/discuss-on%20forum-brightgreen.svg?style=for-the-badge&colorB=0069b8&logo=data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAQAAAC1+jfqAAAABGdBTUEAALGPC/xhBQAAACBjSFJNAAB6JgAAgIQAAPoAAACA6AAAdTAAAOpgAAA6mAAAF3CculE8AAAAAmJLR0QAAKqNIzIAAAAJcEhZcwAADsQAAA7EAZUrDhsAAAAHdElNRQfjAgETDROxCNUzAAABB0lEQVQoz4WRvyvEARjGP193CnWRH+dHQmGwKZtFGcSmxHAL400GN95ktIpV2dzlLzDJgsGgGNRdDAzoQueS/PgY3HXHyT3T+/Y87/s89UANBKXBdoZo5J6L4K1K5ZxHfnjnlQUf3bKvkgy57a0r9hS3cXfMO1kWJMza++tj3Ac7/LY343x1NA9cNmYMwnSS/SP8JVFuSJmr44iFqvtmpjhmhBCrOOazCesq6H4P3bPBjFoIBydOk2bUA17I080Es+wSZ51B4DIA2zgjSpYcEe44Js01G0XjRcCU+y4ZMrDeLmfc9EnVd5M/o0VMeu6nJZxWJivLmhyw1WHTvrr2b4+2OFqra+ALwouTMDcqmjMAAAAldEVYdGRhdGU6Y3JlYXRlADIwMTktMDItMDFUMTg6MTM6MTkrMDE6MDAC9f6fAAAAJXRFWHRkYXRlOm1vZGlmeQAyMDE5LTAyLTAxVDE4OjEzOjE5KzAxOjAwc6hGIwAAABl0RVh0U29mdHdhcmUAd3d3Lmlua3NjYXBlLm9yZ5vuPBoAAAAASUVORK5CYII=" alt="Discussion forum" />
15
+ </a>
16
16
  <h3>
17
17
  Multiplayer Framework for Node.js. <br /><a href="https://docs.colyseus.io/">View documentation</a>
18
18
  </h3>
19
19
  </div>
20
20
 
21
- Colyseus is an Authoritative Multiplayer Framework for Node.js, with clients
22
- available for the Web, Unity3d, Defold, Haxe, and Cocos. ([See official clients](#%EF%B8%8F-official-client-integration))
21
+ Colyseus is an Authoritative Multiplayer Framework for Node.js, with SDKs
22
+ available for the Web, Unity, Defold, Haxe, Cocos and Construct3. ([See official SDKs](https://docs.colyseus.io/client/))
23
23
 
24
24
  The project focuses on providing synchronizable data structures for realtime and
25
25
  turn-based games, matchmaking, and ease of usage both on the server-side and
@@ -57,7 +57,7 @@ class BunWebSockets extends import_core.Transport {
57
57
  }
58
58
  });
59
59
  if (!this.server) {
60
- this.server = new import_core.DummyServer();
60
+ this.server = new import_core.HttpServerMock();
61
61
  }
62
62
  }
63
63
  listen(port, hostname, backlog, listeningListener) {
@@ -98,7 +98,7 @@ class BunWebSockets extends import_core.Transport {
98
98
  const sessionId = parsedURL.searchParams.get("sessionId");
99
99
  const processAndRoomId = parsedURL.pathname.match(/\/[a-zA-Z0-9_\-]+\/([a-zA-Z0-9_\-]+)$/);
100
100
  const roomId = processAndRoomId && processAndRoomId[1];
101
- const room = import_core.matchMaker.getRoomById(roomId);
101
+ const room = import_core.matchMaker.getLocalRoomById(roomId);
102
102
  const client = new import_WebSocketClient.WebSocketClient(sessionId, wrapper);
103
103
  try {
104
104
  if (!room || !room.hasReservedSeat(sessionId, parsedURL.searchParams.get("reconnectionToken"))) {
@@ -130,13 +130,13 @@ class BunWebSockets extends import_core.Transport {
130
130
  }
131
131
  case "GET": {
132
132
  const matchedParams = req.path.match(import_core.matchMaker.controller.allowedRoomNameChars);
133
- const roomName = matchedParams && matchedParams.length > 1 ? matchedParams[matchedParams.length - 1] : "";
133
+ const roomName = matchedParams.length > 1 ? matchedParams[matchedParams.length - 1] : "";
134
134
  writeHeaders(req, res);
135
135
  res.json(await import_core.matchMaker.controller.getAvailableRooms(roomName || ""));
136
136
  break;
137
137
  }
138
138
  case "POST": {
139
- if (import_core.matchMaker.isGracefullyShuttingDown) {
139
+ if (import_core.matchMaker.state === import_core.matchMaker.MatchMakerState.SHUTTING_DOWN) {
140
140
  throw new import_core.ServerError(503, "server is shutting down");
141
141
  }
142
142
  const matchedParams = req.path.match(import_core.matchMaker.controller.allowedRoomNameChars);
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../src/BunWebSockets.ts"],
4
- "sourcesContent": ["// <reference types=\"bun-types\" />\n\n// \"bun-types\" is currently conflicting with \"ws\" types.\n// @ts-ignore\nimport { ServerWebSocket, WebSocketHandler } from \"bun\";\n\nimport type http from 'http';\nimport bunExpress from \"bun-serve-express\";\n\nimport { DummyServer, matchMaker, Transport, debugAndPrintError, spliceOne, ServerError, getBearerToken } from '@colyseus/core';\nimport { WebSocketClient, WebSocketWrapper } from './WebSocketClient';\nimport type { Application, Request, Response } from \"express\";\n\nexport type TransportOptions = Partial<Omit<WebSocketHandler, \"message\" | \"open\" | \"drain\" | \"close\" | \"ping\" | \"pong\">>;\n\ninterface WebSocketData {\n url: URL;\n // query: string,\n // headers: { [key: string]: string },\n // connection: { remoteAddress: string },\n}\n\nexport class BunWebSockets extends Transport {\n public expressApp: Application;\n\n protected clients: ServerWebSocket<WebSocketData>[] = [];\n protected clientWrappers = new WeakMap<ServerWebSocket<WebSocketData>, WebSocketWrapper>();\n\n private _listening: any;\n private _originalRawSend: typeof WebSocketClient.prototype.raw | null = null;\n\n constructor(private options: TransportOptions = {}) {\n super();\n\n const self = this;\n\n this.expressApp = bunExpress({\n websocket: {\n ...this.options,\n\n async open(ws) {\n await self.onConnection(ws);\n },\n\n message(ws, message) {\n // this.clientWrappers.get(ws)?.emit('message', Buffer.from(message.slice(0)));\n self.clientWrappers.get(ws)?.emit('message', message);\n },\n\n close(ws, code, reason) {\n // remove from client list\n spliceOne(self.clients, self.clients.indexOf(ws));\n\n const clientWrapper = self.clientWrappers.get(ws);\n if (clientWrapper) {\n self.clientWrappers.delete(ws);\n\n // emit 'close' on wrapper\n clientWrapper.emit('close', code);\n }\n },\n }\n });\n\n // Adding a mock object for Transport.server\n if (!this.server) {\n this.server = new DummyServer();\n }\n }\n\n public listen(port: number, hostname?: string, backlog?: number, listeningListener?: () => void) {\n this._listening = this.expressApp.listen(port, listeningListener);\n\n this.expressApp.use(`/${matchMaker.controller.matchmakeRoute}`, async (req, res) => {\n try {\n await this.handleMatchMakeRequest(req, res);\n } catch (e) {\n res.status(500).json({\n code: e.code,\n error: e.message\n });\n }\n });\n\n // Mocking Transport.server behaviour, https://github.com/colyseus/colyseus/issues/458\n // @ts-ignore\n this.server.emit(\"listening\");\n\n return this;\n }\n\n public shutdown() {\n if (this._listening) {\n this._listening.close();\n\n // @ts-ignore\n this.server.emit(\"close\"); // Mocking Transport.server behaviour, https://github.com/colyseus/colyseus/issues/458\n }\n }\n\n public simulateLatency(milliseconds: number) {\n if (this._originalRawSend == null) {\n this._originalRawSend = WebSocketClient.prototype.raw;\n }\n\n const originalRawSend = this._originalRawSend;\n WebSocketClient.prototype.raw = milliseconds <= Number.EPSILON ? originalRawSend : function () {\n setTimeout(() => originalRawSend.apply(this, arguments), milliseconds);\n };\n }\n\n protected async onConnection(rawClient: ServerWebSocket<WebSocketData>) {\n const wrapper = new WebSocketWrapper(rawClient);\n // keep reference to client and its wrapper\n this.clients.push(rawClient);\n this.clientWrappers.set(rawClient, wrapper);\n\n const parsedURL = new URL(rawClient.data.url);\n\n const sessionId = parsedURL.searchParams.get(\"sessionId\");\n const processAndRoomId = parsedURL.pathname.match(/\\/[a-zA-Z0-9_\\-]+\\/([a-zA-Z0-9_\\-]+)$/);\n const roomId = processAndRoomId && processAndRoomId[1];\n\n const room = matchMaker.getRoomById(roomId);\n const client = new WebSocketClient(sessionId, wrapper);\n\n //\n // TODO: DRY code below with all transports\n //\n\n try {\n if (!room || !room.hasReservedSeat(sessionId, parsedURL.searchParams.get(\"reconnectionToken\") as string)) {\n throw new Error('seat reservation expired.');\n }\n\n await room._onJoin(client, rawClient as unknown as http.IncomingMessage);\n\n } catch (e) {\n debugAndPrintError(e);\n\n // send error code to client then terminate\n client.error(e.code, e.message, () => rawClient.close());\n }\n }\n\n protected async handleMatchMakeRequest(req: Request, res: Response) {\n const writeHeaders = (req: Request, res: Response) => {\n if (res.destroyed) return;\n\n res.set(Object.assign(\n {},\n matchMaker.controller.DEFAULT_CORS_HEADERS,\n matchMaker.controller.getCorsHeaders.call(undefined, req)\n ));\n\n return true;\n };\n\n try {\n switch (req.method) {\n case 'OPTIONS': {\n writeHeaders(req, res);\n res.status(200).end();\n break;\n }\n\n case 'GET': {\n const matchedParams = req.path.match(matchMaker.controller.allowedRoomNameChars);\n const roomName = (matchedParams && matchedParams.length > 1)\n ? matchedParams[matchedParams.length - 1]\n : \"\";\n\n writeHeaders(req, res);\n res.json(await matchMaker.controller.getAvailableRooms(roomName || ''));\n break;\n }\n\n case 'POST': {\n // do not accept matchmaking requests if already shutting down\n if (matchMaker.isGracefullyShuttingDown) {\n throw new ServerError(503, \"server is shutting down\");\n }\n\n const matchedParams = req.path.match(matchMaker.controller.allowedRoomNameChars);\n const matchmakeIndex = matchedParams.indexOf(matchMaker.controller.matchmakeRoute);\n let clientOptions = req.body; // Bun.readableStreamToJSON(req.body);\n\n if (clientOptions == null) {\n throw new ServerError(500, \"invalid JSON input\");\n }\n\n if (typeof clientOptions === 'string' && clientOptions.length > 2) {\n clientOptions = JSON.parse(clientOptions);\n } else if (typeof clientOptions !== 'object') {\n clientOptions = {};\n }\n\n const method = matchedParams[matchmakeIndex + 1];\n const roomName = matchedParams[matchmakeIndex + 2] || '';\n\n writeHeaders(req, res);\n res.json(await matchMaker.controller.invokeMethod(\n method,\n roomName,\n clientOptions,\n { token: getBearerToken(req.headers['authorization']), request: req },\n ));\n break;\n }\n\n default: throw new ServerError(500, \"invalid request method\");\n }\n\n } catch (e) {\n writeHeaders(req, res);\n res.status(500)\n .json({ code: e.code, error: e.message });\n }\n }\n\n}\n"],
5
- "mappings": "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",
4
+ "sourcesContent": ["// <reference types=\"bun-types\" />\n\n// \"bun-types\" is currently conflicting with \"ws\" types.\n// @ts-ignore\nimport { ServerWebSocket, WebSocketHandler } from \"bun\";\n\nimport type http from 'http';\nimport bunExpress from \"bun-serve-express\";\n\nimport { HttpServerMock, matchMaker, Transport, debugAndPrintError, spliceOne, ServerError, getBearerToken } from '@colyseus/core';\nimport { WebSocketClient, WebSocketWrapper } from './WebSocketClient';\nimport type { Application, Request, Response } from \"express\";\n\nexport type TransportOptions = Partial<Omit<WebSocketHandler, \"message\" | \"open\" | \"drain\" | \"close\" | \"ping\" | \"pong\">>;\n\ninterface WebSocketData {\n url: URL;\n // query: string,\n // headers: { [key: string]: string },\n // connection: { remoteAddress: string },\n}\n\nexport class BunWebSockets extends Transport {\n public expressApp: Application;\n\n protected clients: ServerWebSocket<WebSocketData>[] = [];\n protected clientWrappers = new WeakMap<ServerWebSocket<WebSocketData>, WebSocketWrapper>();\n\n private _listening: any;\n private _originalRawSend: typeof WebSocketClient.prototype.raw | null = null;\n\n constructor(private options: TransportOptions = {}) {\n super();\n\n const self = this;\n\n this.expressApp = bunExpress({\n websocket: {\n ...this.options,\n\n async open(ws) {\n await self.onConnection(ws);\n },\n\n message(ws, message) {\n // this.clientWrappers.get(ws)?.emit('message', Buffer.from(message.slice(0)));\n self.clientWrappers.get(ws)?.emit('message', message);\n },\n\n close(ws, code, reason) {\n // remove from client list\n spliceOne(self.clients, self.clients.indexOf(ws));\n\n const clientWrapper = self.clientWrappers.get(ws);\n if (clientWrapper) {\n self.clientWrappers.delete(ws);\n\n // emit 'close' on wrapper\n clientWrapper.emit('close', code);\n }\n },\n }\n });\n\n // Adding a mock object for Transport.server\n if (!this.server) {\n // @ts-ignore\n this.server = new HttpServerMock();\n }\n }\n\n public listen(port: number, hostname?: string, backlog?: number, listeningListener?: () => void) {\n this._listening = this.expressApp.listen(port, listeningListener);\n\n this.expressApp.use(`/${matchMaker.controller.matchmakeRoute}`, async (req, res) => {\n try {\n await this.handleMatchMakeRequest(req, res);\n } catch (e) {\n res.status(500).json({\n code: e.code,\n error: e.message\n });\n }\n });\n\n // Mocking Transport.server behaviour, https://github.com/colyseus/colyseus/issues/458\n // @ts-ignore\n this.server.emit(\"listening\");\n\n return this;\n }\n\n public shutdown() {\n if (this._listening) {\n this._listening.close();\n\n // @ts-ignore\n this.server.emit(\"close\"); // Mocking Transport.server behaviour, https://github.com/colyseus/colyseus/issues/458\n }\n }\n\n public simulateLatency(milliseconds: number) {\n if (this._originalRawSend == null) {\n this._originalRawSend = WebSocketClient.prototype.raw;\n }\n\n const originalRawSend = this._originalRawSend;\n WebSocketClient.prototype.raw = milliseconds <= Number.EPSILON ? originalRawSend : function () {\n setTimeout(() => originalRawSend.apply(this, arguments), milliseconds);\n };\n }\n\n protected async onConnection(rawClient: ServerWebSocket<WebSocketData>) {\n const wrapper = new WebSocketWrapper(rawClient);\n // keep reference to client and its wrapper\n this.clients.push(rawClient);\n this.clientWrappers.set(rawClient, wrapper);\n\n const parsedURL = new URL(rawClient.data.url);\n\n const sessionId = parsedURL.searchParams.get(\"sessionId\");\n const processAndRoomId = parsedURL.pathname.match(/\\/[a-zA-Z0-9_\\-]+\\/([a-zA-Z0-9_\\-]+)$/);\n const roomId = processAndRoomId && processAndRoomId[1];\n\n const room = matchMaker.getLocalRoomById(roomId);\n const client = new WebSocketClient(sessionId, wrapper);\n\n //\n // TODO: DRY code below with all transports\n //\n\n try {\n if (!room || !room.hasReservedSeat(sessionId, parsedURL.searchParams.get(\"reconnectionToken\") as string)) {\n throw new Error('seat reservation expired.');\n }\n\n await room._onJoin(client, rawClient as unknown as http.IncomingMessage);\n\n } catch (e) {\n debugAndPrintError(e);\n\n // send error code to client then terminate\n client.error(e.code, e.message, () => rawClient.close());\n }\n }\n\n protected async handleMatchMakeRequest(req: Request, res: Response) {\n const writeHeaders = (req: Request, res: Response) => {\n if (res.destroyed) return;\n\n res.set(Object.assign(\n {},\n matchMaker.controller.DEFAULT_CORS_HEADERS,\n matchMaker.controller.getCorsHeaders.call(undefined, req)\n ));\n\n return true;\n };\n\n try {\n switch (req.method) {\n case 'OPTIONS': {\n writeHeaders(req, res);\n res.status(200).end();\n break;\n }\n\n case 'GET': {\n const matchedParams = req.path.match(matchMaker.controller.allowedRoomNameChars);\n const roomName = matchedParams.length > 1 ? matchedParams[matchedParams.length - 1] : \"\";\n\n writeHeaders(req, res);\n res.json(await matchMaker.controller.getAvailableRooms(roomName || ''));\n break;\n }\n\n case 'POST': {\n // do not accept matchmaking requests if already shutting down\n if (matchMaker.state === matchMaker.MatchMakerState.SHUTTING_DOWN) {\n throw new ServerError(503, \"server is shutting down\");\n }\n\n const matchedParams = req.path.match(matchMaker.controller.allowedRoomNameChars);\n const matchmakeIndex = matchedParams.indexOf(matchMaker.controller.matchmakeRoute);\n let clientOptions = req.body; // Bun.readableStreamToJSON(req.body);\n\n if (clientOptions == null) {\n throw new ServerError(500, \"invalid JSON input\");\n }\n\n if (typeof clientOptions === 'string' && clientOptions.length > 2) {\n clientOptions = JSON.parse(clientOptions);\n } else if (typeof clientOptions !== 'object') {\n clientOptions = {};\n }\n\n const method = matchedParams[matchmakeIndex + 1];\n const roomName = matchedParams[matchmakeIndex + 2] || '';\n\n writeHeaders(req, res);\n res.json(await matchMaker.controller.invokeMethod(\n method,\n roomName,\n clientOptions,\n { token: getBearerToken(req.headers['authorization']), request: req },\n ));\n break;\n }\n\n default: throw new ServerError(500, \"invalid request method\");\n }\n\n } catch (e) {\n writeHeaders(req, res);\n res.status(500)\n .json({ code: e.code, error: e.message });\n }\n }\n\n}\n"],
5
+ "mappings": "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",
6
6
  "names": ["bunExpress", "req", "res"]
7
7
  }
@@ -1,5 +1,5 @@
1
1
  import bunExpress from "bun-serve-express";
2
- import { DummyServer, matchMaker, Transport, debugAndPrintError, spliceOne, ServerError, getBearerToken } from "@colyseus/core";
2
+ import { HttpServerMock, matchMaker, Transport, debugAndPrintError, spliceOne, ServerError, getBearerToken } from "@colyseus/core";
3
3
  import { WebSocketClient, WebSocketWrapper } from "./WebSocketClient";
4
4
  class BunWebSockets extends Transport {
5
5
  constructor(options = {}) {
@@ -29,7 +29,7 @@ class BunWebSockets extends Transport {
29
29
  }
30
30
  });
31
31
  if (!this.server) {
32
- this.server = new DummyServer();
32
+ this.server = new HttpServerMock();
33
33
  }
34
34
  }
35
35
  listen(port, hostname, backlog, listeningListener) {
@@ -70,7 +70,7 @@ class BunWebSockets extends Transport {
70
70
  const sessionId = parsedURL.searchParams.get("sessionId");
71
71
  const processAndRoomId = parsedURL.pathname.match(/\/[a-zA-Z0-9_\-]+\/([a-zA-Z0-9_\-]+)$/);
72
72
  const roomId = processAndRoomId && processAndRoomId[1];
73
- const room = matchMaker.getRoomById(roomId);
73
+ const room = matchMaker.getLocalRoomById(roomId);
74
74
  const client = new WebSocketClient(sessionId, wrapper);
75
75
  try {
76
76
  if (!room || !room.hasReservedSeat(sessionId, parsedURL.searchParams.get("reconnectionToken"))) {
@@ -102,13 +102,13 @@ class BunWebSockets extends Transport {
102
102
  }
103
103
  case "GET": {
104
104
  const matchedParams = req.path.match(matchMaker.controller.allowedRoomNameChars);
105
- const roomName = matchedParams && matchedParams.length > 1 ? matchedParams[matchedParams.length - 1] : "";
105
+ const roomName = matchedParams.length > 1 ? matchedParams[matchedParams.length - 1] : "";
106
106
  writeHeaders(req, res);
107
107
  res.json(await matchMaker.controller.getAvailableRooms(roomName || ""));
108
108
  break;
109
109
  }
110
110
  case "POST": {
111
- if (matchMaker.isGracefullyShuttingDown) {
111
+ if (matchMaker.state === matchMaker.MatchMakerState.SHUTTING_DOWN) {
112
112
  throw new ServerError(503, "server is shutting down");
113
113
  }
114
114
  const matchedParams = req.path.match(matchMaker.controller.allowedRoomNameChars);
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../src/BunWebSockets.ts"],
4
- "sourcesContent": ["// <reference types=\"bun-types\" />\n\n// \"bun-types\" is currently conflicting with \"ws\" types.\n// @ts-ignore\nimport { ServerWebSocket, WebSocketHandler } from \"bun\";\n\nimport type http from 'http';\nimport bunExpress from \"bun-serve-express\";\n\nimport { DummyServer, matchMaker, Transport, debugAndPrintError, spliceOne, ServerError, getBearerToken } from '@colyseus/core';\nimport { WebSocketClient, WebSocketWrapper } from './WebSocketClient';\nimport type { Application, Request, Response } from \"express\";\n\nexport type TransportOptions = Partial<Omit<WebSocketHandler, \"message\" | \"open\" | \"drain\" | \"close\" | \"ping\" | \"pong\">>;\n\ninterface WebSocketData {\n url: URL;\n // query: string,\n // headers: { [key: string]: string },\n // connection: { remoteAddress: string },\n}\n\nexport class BunWebSockets extends Transport {\n public expressApp: Application;\n\n protected clients: ServerWebSocket<WebSocketData>[] = [];\n protected clientWrappers = new WeakMap<ServerWebSocket<WebSocketData>, WebSocketWrapper>();\n\n private _listening: any;\n private _originalRawSend: typeof WebSocketClient.prototype.raw | null = null;\n\n constructor(private options: TransportOptions = {}) {\n super();\n\n const self = this;\n\n this.expressApp = bunExpress({\n websocket: {\n ...this.options,\n\n async open(ws) {\n await self.onConnection(ws);\n },\n\n message(ws, message) {\n // this.clientWrappers.get(ws)?.emit('message', Buffer.from(message.slice(0)));\n self.clientWrappers.get(ws)?.emit('message', message);\n },\n\n close(ws, code, reason) {\n // remove from client list\n spliceOne(self.clients, self.clients.indexOf(ws));\n\n const clientWrapper = self.clientWrappers.get(ws);\n if (clientWrapper) {\n self.clientWrappers.delete(ws);\n\n // emit 'close' on wrapper\n clientWrapper.emit('close', code);\n }\n },\n }\n });\n\n // Adding a mock object for Transport.server\n if (!this.server) {\n this.server = new DummyServer();\n }\n }\n\n public listen(port: number, hostname?: string, backlog?: number, listeningListener?: () => void) {\n this._listening = this.expressApp.listen(port, listeningListener);\n\n this.expressApp.use(`/${matchMaker.controller.matchmakeRoute}`, async (req, res) => {\n try {\n await this.handleMatchMakeRequest(req, res);\n } catch (e) {\n res.status(500).json({\n code: e.code,\n error: e.message\n });\n }\n });\n\n // Mocking Transport.server behaviour, https://github.com/colyseus/colyseus/issues/458\n // @ts-ignore\n this.server.emit(\"listening\");\n\n return this;\n }\n\n public shutdown() {\n if (this._listening) {\n this._listening.close();\n\n // @ts-ignore\n this.server.emit(\"close\"); // Mocking Transport.server behaviour, https://github.com/colyseus/colyseus/issues/458\n }\n }\n\n public simulateLatency(milliseconds: number) {\n if (this._originalRawSend == null) {\n this._originalRawSend = WebSocketClient.prototype.raw;\n }\n\n const originalRawSend = this._originalRawSend;\n WebSocketClient.prototype.raw = milliseconds <= Number.EPSILON ? originalRawSend : function () {\n setTimeout(() => originalRawSend.apply(this, arguments), milliseconds);\n };\n }\n\n protected async onConnection(rawClient: ServerWebSocket<WebSocketData>) {\n const wrapper = new WebSocketWrapper(rawClient);\n // keep reference to client and its wrapper\n this.clients.push(rawClient);\n this.clientWrappers.set(rawClient, wrapper);\n\n const parsedURL = new URL(rawClient.data.url);\n\n const sessionId = parsedURL.searchParams.get(\"sessionId\");\n const processAndRoomId = parsedURL.pathname.match(/\\/[a-zA-Z0-9_\\-]+\\/([a-zA-Z0-9_\\-]+)$/);\n const roomId = processAndRoomId && processAndRoomId[1];\n\n const room = matchMaker.getRoomById(roomId);\n const client = new WebSocketClient(sessionId, wrapper);\n\n //\n // TODO: DRY code below with all transports\n //\n\n try {\n if (!room || !room.hasReservedSeat(sessionId, parsedURL.searchParams.get(\"reconnectionToken\") as string)) {\n throw new Error('seat reservation expired.');\n }\n\n await room._onJoin(client, rawClient as unknown as http.IncomingMessage);\n\n } catch (e) {\n debugAndPrintError(e);\n\n // send error code to client then terminate\n client.error(e.code, e.message, () => rawClient.close());\n }\n }\n\n protected async handleMatchMakeRequest(req: Request, res: Response) {\n const writeHeaders = (req: Request, res: Response) => {\n if (res.destroyed) return;\n\n res.set(Object.assign(\n {},\n matchMaker.controller.DEFAULT_CORS_HEADERS,\n matchMaker.controller.getCorsHeaders.call(undefined, req)\n ));\n\n return true;\n };\n\n try {\n switch (req.method) {\n case 'OPTIONS': {\n writeHeaders(req, res);\n res.status(200).end();\n break;\n }\n\n case 'GET': {\n const matchedParams = req.path.match(matchMaker.controller.allowedRoomNameChars);\n const roomName = (matchedParams && matchedParams.length > 1)\n ? matchedParams[matchedParams.length - 1]\n : \"\";\n\n writeHeaders(req, res);\n res.json(await matchMaker.controller.getAvailableRooms(roomName || ''));\n break;\n }\n\n case 'POST': {\n // do not accept matchmaking requests if already shutting down\n if (matchMaker.isGracefullyShuttingDown) {\n throw new ServerError(503, \"server is shutting down\");\n }\n\n const matchedParams = req.path.match(matchMaker.controller.allowedRoomNameChars);\n const matchmakeIndex = matchedParams.indexOf(matchMaker.controller.matchmakeRoute);\n let clientOptions = req.body; // Bun.readableStreamToJSON(req.body);\n\n if (clientOptions == null) {\n throw new ServerError(500, \"invalid JSON input\");\n }\n\n if (typeof clientOptions === 'string' && clientOptions.length > 2) {\n clientOptions = JSON.parse(clientOptions);\n } else if (typeof clientOptions !== 'object') {\n clientOptions = {};\n }\n\n const method = matchedParams[matchmakeIndex + 1];\n const roomName = matchedParams[matchmakeIndex + 2] || '';\n\n writeHeaders(req, res);\n res.json(await matchMaker.controller.invokeMethod(\n method,\n roomName,\n clientOptions,\n { token: getBearerToken(req.headers['authorization']), request: req },\n ));\n break;\n }\n\n default: throw new ServerError(500, \"invalid request method\");\n }\n\n } catch (e) {\n writeHeaders(req, res);\n res.status(500)\n .json({ code: e.code, error: e.message });\n }\n }\n\n}\n"],
5
- "mappings": "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",
4
+ "sourcesContent": ["// <reference types=\"bun-types\" />\n\n// \"bun-types\" is currently conflicting with \"ws\" types.\n// @ts-ignore\nimport { ServerWebSocket, WebSocketHandler } from \"bun\";\n\nimport type http from 'http';\nimport bunExpress from \"bun-serve-express\";\n\nimport { HttpServerMock, matchMaker, Transport, debugAndPrintError, spliceOne, ServerError, getBearerToken } from '@colyseus/core';\nimport { WebSocketClient, WebSocketWrapper } from './WebSocketClient';\nimport type { Application, Request, Response } from \"express\";\n\nexport type TransportOptions = Partial<Omit<WebSocketHandler, \"message\" | \"open\" | \"drain\" | \"close\" | \"ping\" | \"pong\">>;\n\ninterface WebSocketData {\n url: URL;\n // query: string,\n // headers: { [key: string]: string },\n // connection: { remoteAddress: string },\n}\n\nexport class BunWebSockets extends Transport {\n public expressApp: Application;\n\n protected clients: ServerWebSocket<WebSocketData>[] = [];\n protected clientWrappers = new WeakMap<ServerWebSocket<WebSocketData>, WebSocketWrapper>();\n\n private _listening: any;\n private _originalRawSend: typeof WebSocketClient.prototype.raw | null = null;\n\n constructor(private options: TransportOptions = {}) {\n super();\n\n const self = this;\n\n this.expressApp = bunExpress({\n websocket: {\n ...this.options,\n\n async open(ws) {\n await self.onConnection(ws);\n },\n\n message(ws, message) {\n // this.clientWrappers.get(ws)?.emit('message', Buffer.from(message.slice(0)));\n self.clientWrappers.get(ws)?.emit('message', message);\n },\n\n close(ws, code, reason) {\n // remove from client list\n spliceOne(self.clients, self.clients.indexOf(ws));\n\n const clientWrapper = self.clientWrappers.get(ws);\n if (clientWrapper) {\n self.clientWrappers.delete(ws);\n\n // emit 'close' on wrapper\n clientWrapper.emit('close', code);\n }\n },\n }\n });\n\n // Adding a mock object for Transport.server\n if (!this.server) {\n // @ts-ignore\n this.server = new HttpServerMock();\n }\n }\n\n public listen(port: number, hostname?: string, backlog?: number, listeningListener?: () => void) {\n this._listening = this.expressApp.listen(port, listeningListener);\n\n this.expressApp.use(`/${matchMaker.controller.matchmakeRoute}`, async (req, res) => {\n try {\n await this.handleMatchMakeRequest(req, res);\n } catch (e) {\n res.status(500).json({\n code: e.code,\n error: e.message\n });\n }\n });\n\n // Mocking Transport.server behaviour, https://github.com/colyseus/colyseus/issues/458\n // @ts-ignore\n this.server.emit(\"listening\");\n\n return this;\n }\n\n public shutdown() {\n if (this._listening) {\n this._listening.close();\n\n // @ts-ignore\n this.server.emit(\"close\"); // Mocking Transport.server behaviour, https://github.com/colyseus/colyseus/issues/458\n }\n }\n\n public simulateLatency(milliseconds: number) {\n if (this._originalRawSend == null) {\n this._originalRawSend = WebSocketClient.prototype.raw;\n }\n\n const originalRawSend = this._originalRawSend;\n WebSocketClient.prototype.raw = milliseconds <= Number.EPSILON ? originalRawSend : function () {\n setTimeout(() => originalRawSend.apply(this, arguments), milliseconds);\n };\n }\n\n protected async onConnection(rawClient: ServerWebSocket<WebSocketData>) {\n const wrapper = new WebSocketWrapper(rawClient);\n // keep reference to client and its wrapper\n this.clients.push(rawClient);\n this.clientWrappers.set(rawClient, wrapper);\n\n const parsedURL = new URL(rawClient.data.url);\n\n const sessionId = parsedURL.searchParams.get(\"sessionId\");\n const processAndRoomId = parsedURL.pathname.match(/\\/[a-zA-Z0-9_\\-]+\\/([a-zA-Z0-9_\\-]+)$/);\n const roomId = processAndRoomId && processAndRoomId[1];\n\n const room = matchMaker.getLocalRoomById(roomId);\n const client = new WebSocketClient(sessionId, wrapper);\n\n //\n // TODO: DRY code below with all transports\n //\n\n try {\n if (!room || !room.hasReservedSeat(sessionId, parsedURL.searchParams.get(\"reconnectionToken\") as string)) {\n throw new Error('seat reservation expired.');\n }\n\n await room._onJoin(client, rawClient as unknown as http.IncomingMessage);\n\n } catch (e) {\n debugAndPrintError(e);\n\n // send error code to client then terminate\n client.error(e.code, e.message, () => rawClient.close());\n }\n }\n\n protected async handleMatchMakeRequest(req: Request, res: Response) {\n const writeHeaders = (req: Request, res: Response) => {\n if (res.destroyed) return;\n\n res.set(Object.assign(\n {},\n matchMaker.controller.DEFAULT_CORS_HEADERS,\n matchMaker.controller.getCorsHeaders.call(undefined, req)\n ));\n\n return true;\n };\n\n try {\n switch (req.method) {\n case 'OPTIONS': {\n writeHeaders(req, res);\n res.status(200).end();\n break;\n }\n\n case 'GET': {\n const matchedParams = req.path.match(matchMaker.controller.allowedRoomNameChars);\n const roomName = matchedParams.length > 1 ? matchedParams[matchedParams.length - 1] : \"\";\n\n writeHeaders(req, res);\n res.json(await matchMaker.controller.getAvailableRooms(roomName || ''));\n break;\n }\n\n case 'POST': {\n // do not accept matchmaking requests if already shutting down\n if (matchMaker.state === matchMaker.MatchMakerState.SHUTTING_DOWN) {\n throw new ServerError(503, \"server is shutting down\");\n }\n\n const matchedParams = req.path.match(matchMaker.controller.allowedRoomNameChars);\n const matchmakeIndex = matchedParams.indexOf(matchMaker.controller.matchmakeRoute);\n let clientOptions = req.body; // Bun.readableStreamToJSON(req.body);\n\n if (clientOptions == null) {\n throw new ServerError(500, \"invalid JSON input\");\n }\n\n if (typeof clientOptions === 'string' && clientOptions.length > 2) {\n clientOptions = JSON.parse(clientOptions);\n } else if (typeof clientOptions !== 'object') {\n clientOptions = {};\n }\n\n const method = matchedParams[matchmakeIndex + 1];\n const roomName = matchedParams[matchmakeIndex + 2] || '';\n\n writeHeaders(req, res);\n res.json(await matchMaker.controller.invokeMethod(\n method,\n roomName,\n clientOptions,\n { token: getBearerToken(req.headers['authorization']), request: req },\n ));\n break;\n }\n\n default: throw new ServerError(500, \"invalid request method\");\n }\n\n } catch (e) {\n writeHeaders(req, res);\n res.status(500)\n .json({ code: e.code, error: e.message });\n }\n }\n\n}\n"],
5
+ "mappings": "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",
6
6
  "names": ["req", "res"]
7
7
  }
@@ -1,24 +1,25 @@
1
- /// <reference types="node" />
2
1
  import { ServerWebSocket } from "bun";
3
2
  import EventEmitter from 'events';
4
- import { Client, ClientState, ISendOptions } from '@colyseus/core';
3
+ import { Client, ClientPrivate, ClientState, ISendOptions } from '@colyseus/core';
5
4
  export declare class WebSocketWrapper extends EventEmitter {
6
5
  ws: ServerWebSocket<any>;
7
6
  constructor(ws: ServerWebSocket<any>);
8
7
  }
9
- export declare class WebSocketClient implements Client {
8
+ export declare class WebSocketClient implements Client, ClientPrivate {
10
9
  id: string;
11
10
  ref: WebSocketWrapper;
12
11
  sessionId: string;
13
12
  state: ClientState;
13
+ reconnectionToken: string;
14
14
  _enqueuedMessages: any[];
15
15
  _afterNextPatchQueue: any;
16
16
  _reconnectionToken: string;
17
+ _joinedAt: number;
17
18
  constructor(id: string, ref: WebSocketWrapper);
18
- sendBytes(type: string | number, bytes: number[] | Uint8Array, options?: ISendOptions): void;
19
+ sendBytes(type: string | number, bytes: Buffer | Uint8Array, options?: ISendOptions): void;
19
20
  send(messageOrType: any, messageOrOptions?: any | ISendOptions, options?: ISendOptions): void;
20
- enqueueRaw(data: ArrayLike<number>, options?: ISendOptions): void;
21
- raw(data: ArrayLike<number>, options?: ISendOptions, cb?: (err?: Error) => void): void;
21
+ enqueueRaw(data: Uint8Array | Buffer, options?: ISendOptions): void;
22
+ raw(data: Uint8Array | Buffer, options?: ISendOptions, cb?: (err?: Error) => void): void;
22
23
  error(code: number, message?: string, cb?: (err?: Error) => void): void;
23
24
  get readyState(): any;
24
25
  leave(code?: number, data?: string): void;
@@ -29,7 +29,6 @@ __export(WebSocketClient_exports, {
29
29
  module.exports = __toCommonJS(WebSocketClient_exports);
30
30
  var import_events = __toESM(require("events"));
31
31
  var import_core = require("@colyseus/core");
32
- var import_schema = require("@colyseus/schema");
33
32
  class WebSocketWrapper extends import_events.default {
34
33
  constructor(ws) {
35
34
  super();
@@ -54,7 +53,7 @@ class WebSocketClient {
54
53
  send(messageOrType, messageOrOptions, options) {
55
54
  (0, import_core.debugMessage)("send(to %s): '%s' -> %j", this.sessionId, messageOrType, messageOrOptions);
56
55
  this.enqueueRaw(
57
- messageOrType instanceof import_schema.Schema ? import_core.getMessageBytes[import_core.Protocol.ROOM_DATA_SCHEMA](messageOrType) : import_core.getMessageBytes.raw(import_core.Protocol.ROOM_DATA, messageOrType, messageOrOptions),
56
+ import_core.getMessageBytes.raw(import_core.Protocol.ROOM_DATA, messageOrType, messageOrOptions),
58
57
  options
59
58
  );
60
59
  }
@@ -64,7 +63,7 @@ class WebSocketClient {
64
63
  return;
65
64
  }
66
65
  if (this.state === import_core.ClientState.JOINING) {
67
- this._enqueuedMessages.push(data);
66
+ this._enqueuedMessages.push(Buffer.from(data));
68
67
  return;
69
68
  }
70
69
  this.raw(data, options);
@@ -73,7 +72,7 @@ class WebSocketClient {
73
72
  if (this.ref.ws.readyState !== WebSocket.OPEN) {
74
73
  return;
75
74
  }
76
- this.ref.ws.sendBinary(Buffer.from(data));
75
+ this.ref.ws.sendBinary(data);
77
76
  }
78
77
  error(code, message = "", cb) {
79
78
  this.raw(import_core.getMessageBytes[import_core.Protocol.ERROR](code, message), void 0, cb);
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../src/WebSocketClient.ts"],
4
- "sourcesContent": ["// <reference types=\"bun-types\" />\n\n// \"bun-types\" is currently conflicting with \"ws\" types.\n// @ts-ignore\nimport { ServerWebSocket } from \"bun\";\nimport EventEmitter from 'events';\n\nimport { Protocol, Client, ClientState, ISendOptions, getMessageBytes, logger, debugMessage } from '@colyseus/core';\nimport { Schema } from '@colyseus/schema';\n\nexport class WebSocketWrapper extends EventEmitter {\n constructor(public ws: ServerWebSocket<any>) {\n super();\n }\n}\n\nexport class WebSocketClient implements Client {\n public sessionId: string;\n public state: ClientState = ClientState.JOINING;\n public _enqueuedMessages: any[] = [];\n public _afterNextPatchQueue;\n public _reconnectionToken: string;\n\n constructor(\n public id: string,\n public ref: WebSocketWrapper,\n ) {\n this.sessionId = id;\n }\n\n public sendBytes(type: string | number, bytes: number[] | Uint8Array, options?: ISendOptions) {\n debugMessage(\"send bytes(to %s): '%s' -> %j\", this.sessionId, type, bytes);\n\n this.enqueueRaw(\n getMessageBytes.raw(Protocol.ROOM_DATA_BYTES, type, undefined, bytes),\n options,\n );\n }\n\n public send(messageOrType: any, messageOrOptions?: any | ISendOptions, options?: ISendOptions) {\n debugMessage(\"send(to %s): '%s' -> %j\", this.sessionId, messageOrType, messageOrOptions);\n\n this.enqueueRaw(\n (messageOrType instanceof Schema)\n ? getMessageBytes[Protocol.ROOM_DATA_SCHEMA](messageOrType)\n : getMessageBytes.raw(Protocol.ROOM_DATA, messageOrType, messageOrOptions),\n options,\n );\n }\n\n public enqueueRaw(data: ArrayLike<number>, options?: ISendOptions) {\n // use room's afterNextPatch queue\n if (options?.afterNextPatch) {\n this._afterNextPatchQueue.push([this, arguments]);\n return;\n }\n\n if (this.state === ClientState.JOINING) {\n // sending messages during `onJoin`.\n // - the client-side cannot register \"onMessage\" callbacks at this point.\n // - enqueue the messages to be send after JOIN_ROOM message has been sent\n this._enqueuedMessages.push(data);\n return;\n }\n\n this.raw(data, options);\n }\n\n public raw(data: ArrayLike<number>, options?: ISendOptions, cb?: (err?: Error) => void) {\n // skip if client not open\n\n // WebSocket is globally available on Bun runtime\n // @ts-ignore\n if (this.ref.ws.readyState !== WebSocket.OPEN) {\n return;\n }\n\n // FIXME: can we avoid creating a new buffer here?\n this.ref.ws.sendBinary(Buffer.from(data as unknown as ArrayBufferLike));\n }\n\n public error(code: number, message: string = '', cb?: (err?: Error) => void) {\n this.raw(getMessageBytes[Protocol.ERROR](code, message), undefined, cb);\n }\n\n get readyState() {\n return this.ref.ws.readyState;\n }\n\n public leave(code?: number, data?: string) {\n this.ref.ws.close(code, data);\n }\n\n public close(code?: number, data?: string) {\n logger.warn('DEPRECATION WARNING: use client.leave() instead of client.close()');\n try {\n throw new Error();\n } catch (e) {\n logger.info(e.stack);\n }\n this.leave(code, data);\n }\n\n public toJSON() {\n return { sessionId: this.sessionId, readyState: this.readyState };\n }\n}\n"],
5
- "mappings": ";;;;;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAKA,oBAAyB;AAEzB,kBAAmG;AACnG,oBAAuB;AAEhB,MAAM,yBAAyB,cAAAA,QAAa;AAAA,EACjD,YAAmB,IAA0B;AAC3C,UAAM;AADW;AAAA,EAEnB;AACF;AAEO,MAAM,gBAAkC;AAAA,EAO7C,YACS,IACA,KACP;AAFO;AACA;AAPT,SAAO,QAAqB,wBAAY;AACxC,SAAO,oBAA2B,CAAC;AAQjC,SAAK,YAAY;AAAA,EACnB;AAAA,EAEO,UAAU,MAAuB,OAA8B,SAAwB;AAC5F,kCAAa,iCAAiC,KAAK,WAAW,MAAM,KAAK;AAEzE,SAAK;AAAA,MACH,4BAAgB,IAAI,qBAAS,iBAAiB,MAAM,QAAW,KAAK;AAAA,MACpE;AAAA,IACF;AAAA,EACF;AAAA,EAEO,KAAK,eAAoB,kBAAuC,SAAwB;AAC7F,kCAAa,2BAA2B,KAAK,WAAW,eAAe,gBAAgB;AAEvF,SAAK;AAAA,MACF,yBAAyB,uBACtB,4BAAgB,qBAAS,kBAAkB,aAAa,IACxD,4BAAgB,IAAI,qBAAS,WAAW,eAAe,gBAAgB;AAAA,MAC3E;AAAA,IACF;AAAA,EACF;AAAA,EAEO,WAAW,MAAyB,SAAwB;AAEjE,QAAI,SAAS,gBAAgB;AAC3B,WAAK,qBAAqB,KAAK,CAAC,MAAM,SAAS,CAAC;AAChD;AAAA,IACF;AAEA,QAAI,KAAK,UAAU,wBAAY,SAAS;AAItC,WAAK,kBAAkB,KAAK,IAAI;AAChC;AAAA,IACF;AAEA,SAAK,IAAI,MAAM,OAAO;AAAA,EACxB;AAAA,EAEO,IAAI,MAAyB,SAAwB,IAA4B;AAKtF,QAAI,KAAK,IAAI,GAAG,eAAe,UAAU,MAAM;AAC7C;AAAA,IACF;AAGA,SAAK,IAAI,GAAG,WAAW,OAAO,KAAK,IAAkC,CAAC;AAAA,EACxE;AAAA,EAEO,MAAM,MAAc,UAAkB,IAAI,IAA4B;AAC3E,SAAK,IAAI,4BAAgB,qBAAS,OAAO,MAAM,OAAO,GAAG,QAAW,EAAE;AAAA,EACxE;AAAA,EAEA,IAAI,aAAa;AACf,WAAO,KAAK,IAAI,GAAG;AAAA,EACrB;AAAA,EAEO,MAAM,MAAe,MAAe;AACzC,SAAK,IAAI,GAAG,MAAM,MAAM,IAAI;AAAA,EAC9B;AAAA,EAEO,MAAM,MAAe,MAAe;AACzC,uBAAO,KAAK,mEAAmE;AAC/E,QAAI;AACF,YAAM,IAAI,MAAM;AAAA,IAClB,SAAS,GAAP;AACA,yBAAO,KAAK,EAAE,KAAK;AAAA,IACrB;AACA,SAAK,MAAM,MAAM,IAAI;AAAA,EACvB;AAAA,EAEO,SAAS;AACd,WAAO,EAAE,WAAW,KAAK,WAAW,YAAY,KAAK,WAAW;AAAA,EAClE;AACF;",
4
+ "sourcesContent": ["// <reference types=\"bun-types\" />\n\n// \"bun-types\" is currently conflicting with \"ws\" types.\n// @ts-ignore\nimport { ServerWebSocket } from \"bun\";\nimport EventEmitter from 'events';\n\nimport { Protocol, Client, ClientPrivate, ClientState, ISendOptions, getMessageBytes, logger, debugMessage } from '@colyseus/core';\n\nexport class WebSocketWrapper extends EventEmitter {\n constructor(public ws: ServerWebSocket<any>) {\n super();\n }\n}\n\nexport class WebSocketClient implements Client, ClientPrivate {\n public sessionId: string;\n public state: ClientState = ClientState.JOINING;\n public reconnectionToken: string;\n\n public _enqueuedMessages: any[] = [];\n public _afterNextPatchQueue;\n public _reconnectionToken: string;\n public _joinedAt: number;\n\n constructor(\n public id: string,\n public ref: WebSocketWrapper,\n ) {\n this.sessionId = id;\n }\n\n public sendBytes(type: string | number, bytes: Buffer | Uint8Array, options?: ISendOptions) {\n debugMessage(\"send bytes(to %s): '%s' -> %j\", this.sessionId, type, bytes);\n\n this.enqueueRaw(\n getMessageBytes.raw(Protocol.ROOM_DATA_BYTES, type, undefined, bytes),\n options,\n );\n }\n\n public send(messageOrType: any, messageOrOptions?: any | ISendOptions, options?: ISendOptions) {\n debugMessage(\"send(to %s): '%s' -> %j\", this.sessionId, messageOrType, messageOrOptions);\n\n this.enqueueRaw(\n getMessageBytes.raw(Protocol.ROOM_DATA, messageOrType, messageOrOptions),\n options,\n );\n }\n\n public enqueueRaw(data: Uint8Array | Buffer, options?: ISendOptions) {\n // use room's afterNextPatch queue\n if (options?.afterNextPatch) {\n this._afterNextPatchQueue.push([this, arguments]);\n return;\n }\n\n if (this.state === ClientState.JOINING) {\n // sending messages during `onJoin`.\n // - the client-side cannot register \"onMessage\" callbacks at this point.\n // - enqueue the messages to be send after JOIN_ROOM message has been sent\n // - create a new buffer for enqueued messages, as the underlying buffer might be modified\n this._enqueuedMessages.push(Buffer.from(data));\n return;\n }\n\n this.raw(data, options);\n }\n\n public raw(data: Uint8Array | Buffer, options?: ISendOptions, cb?: (err?: Error) => void) {\n // skip if client not open\n\n // WebSocket is globally available on Bun runtime\n // @ts-ignore\n if (this.ref.ws.readyState !== WebSocket.OPEN) {\n return;\n }\n\n // FIXME: can we avoid creating a new buffer here?\n this.ref.ws.sendBinary(data);\n }\n\n public error(code: number, message: string = '', cb?: (err?: Error) => void) {\n this.raw(getMessageBytes[Protocol.ERROR](code, message), undefined, cb);\n }\n\n get readyState() {\n return this.ref.ws.readyState;\n }\n\n public leave(code?: number, data?: string) {\n this.ref.ws.close(code, data);\n }\n\n public close(code?: number, data?: string) {\n logger.warn('DEPRECATION WARNING: use client.leave() instead of client.close()');\n try {\n throw new Error();\n } catch (e) {\n logger.info(e.stack);\n }\n this.leave(code, data);\n }\n\n public toJSON() {\n return { sessionId: this.sessionId, readyState: this.readyState };\n }\n}\n"],
5
+ "mappings": ";;;;;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAKA,oBAAyB;AAEzB,kBAAkH;AAE3G,MAAM,yBAAyB,cAAAA,QAAa;AAAA,EACjD,YAAmB,IAA0B;AAC3C,UAAM;AADW;AAAA,EAEnB;AACF;AAEO,MAAM,gBAAiD;AAAA,EAU5D,YACS,IACA,KACP;AAFO;AACA;AAVT,SAAO,QAAqB,wBAAY;AAGxC,SAAO,oBAA2B,CAAC;AASjC,SAAK,YAAY;AAAA,EACnB;AAAA,EAEO,UAAU,MAAuB,OAA4B,SAAwB;AAC1F,kCAAa,iCAAiC,KAAK,WAAW,MAAM,KAAK;AAEzE,SAAK;AAAA,MACH,4BAAgB,IAAI,qBAAS,iBAAiB,MAAM,QAAW,KAAK;AAAA,MACpE;AAAA,IACF;AAAA,EACF;AAAA,EAEO,KAAK,eAAoB,kBAAuC,SAAwB;AAC7F,kCAAa,2BAA2B,KAAK,WAAW,eAAe,gBAAgB;AAEvF,SAAK;AAAA,MACH,4BAAgB,IAAI,qBAAS,WAAW,eAAe,gBAAgB;AAAA,MACvE;AAAA,IACF;AAAA,EACF;AAAA,EAEO,WAAW,MAA2B,SAAwB;AAEnE,QAAI,SAAS,gBAAgB;AAC3B,WAAK,qBAAqB,KAAK,CAAC,MAAM,SAAS,CAAC;AAChD;AAAA,IACF;AAEA,QAAI,KAAK,UAAU,wBAAY,SAAS;AAKtC,WAAK,kBAAkB,KAAK,OAAO,KAAK,IAAI,CAAC;AAC7C;AAAA,IACF;AAEA,SAAK,IAAI,MAAM,OAAO;AAAA,EACxB;AAAA,EAEO,IAAI,MAA2B,SAAwB,IAA4B;AAKxF,QAAI,KAAK,IAAI,GAAG,eAAe,UAAU,MAAM;AAC7C;AAAA,IACF;AAGA,SAAK,IAAI,GAAG,WAAW,IAAI;AAAA,EAC7B;AAAA,EAEO,MAAM,MAAc,UAAkB,IAAI,IAA4B;AAC3E,SAAK,IAAI,4BAAgB,qBAAS,OAAO,MAAM,OAAO,GAAG,QAAW,EAAE;AAAA,EACxE;AAAA,EAEA,IAAI,aAAa;AACf,WAAO,KAAK,IAAI,GAAG;AAAA,EACrB;AAAA,EAEO,MAAM,MAAe,MAAe;AACzC,SAAK,IAAI,GAAG,MAAM,MAAM,IAAI;AAAA,EAC9B;AAAA,EAEO,MAAM,MAAe,MAAe;AACzC,uBAAO,KAAK,mEAAmE;AAC/E,QAAI;AACF,YAAM,IAAI,MAAM;AAAA,IAClB,SAAS,GAAP;AACA,yBAAO,KAAK,EAAE,KAAK;AAAA,IACrB;AACA,SAAK,MAAM,MAAM,IAAI;AAAA,EACvB;AAAA,EAEO,SAAS;AACd,WAAO,EAAE,WAAW,KAAK,WAAW,YAAY,KAAK,WAAW;AAAA,EAClE;AACF;",
6
6
  "names": ["EventEmitter"]
7
7
  }
@@ -1,6 +1,5 @@
1
1
  import EventEmitter from "events";
2
2
  import { Protocol, ClientState, getMessageBytes, logger, debugMessage } from "@colyseus/core";
3
- import { Schema } from "@colyseus/schema";
4
3
  class WebSocketWrapper extends EventEmitter {
5
4
  constructor(ws) {
6
5
  super();
@@ -25,7 +24,7 @@ class WebSocketClient {
25
24
  send(messageOrType, messageOrOptions, options) {
26
25
  debugMessage("send(to %s): '%s' -> %j", this.sessionId, messageOrType, messageOrOptions);
27
26
  this.enqueueRaw(
28
- messageOrType instanceof Schema ? getMessageBytes[Protocol.ROOM_DATA_SCHEMA](messageOrType) : getMessageBytes.raw(Protocol.ROOM_DATA, messageOrType, messageOrOptions),
27
+ getMessageBytes.raw(Protocol.ROOM_DATA, messageOrType, messageOrOptions),
29
28
  options
30
29
  );
31
30
  }
@@ -35,7 +34,7 @@ class WebSocketClient {
35
34
  return;
36
35
  }
37
36
  if (this.state === ClientState.JOINING) {
38
- this._enqueuedMessages.push(data);
37
+ this._enqueuedMessages.push(Buffer.from(data));
39
38
  return;
40
39
  }
41
40
  this.raw(data, options);
@@ -44,7 +43,7 @@ class WebSocketClient {
44
43
  if (this.ref.ws.readyState !== WebSocket.OPEN) {
45
44
  return;
46
45
  }
47
- this.ref.ws.sendBinary(Buffer.from(data));
46
+ this.ref.ws.sendBinary(data);
48
47
  }
49
48
  error(code, message = "", cb) {
50
49
  this.raw(getMessageBytes[Protocol.ERROR](code, message), void 0, cb);
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../src/WebSocketClient.ts"],
4
- "sourcesContent": ["// <reference types=\"bun-types\" />\n\n// \"bun-types\" is currently conflicting with \"ws\" types.\n// @ts-ignore\nimport { ServerWebSocket } from \"bun\";\nimport EventEmitter from 'events';\n\nimport { Protocol, Client, ClientState, ISendOptions, getMessageBytes, logger, debugMessage } from '@colyseus/core';\nimport { Schema } from '@colyseus/schema';\n\nexport class WebSocketWrapper extends EventEmitter {\n constructor(public ws: ServerWebSocket<any>) {\n super();\n }\n}\n\nexport class WebSocketClient implements Client {\n public sessionId: string;\n public state: ClientState = ClientState.JOINING;\n public _enqueuedMessages: any[] = [];\n public _afterNextPatchQueue;\n public _reconnectionToken: string;\n\n constructor(\n public id: string,\n public ref: WebSocketWrapper,\n ) {\n this.sessionId = id;\n }\n\n public sendBytes(type: string | number, bytes: number[] | Uint8Array, options?: ISendOptions) {\n debugMessage(\"send bytes(to %s): '%s' -> %j\", this.sessionId, type, bytes);\n\n this.enqueueRaw(\n getMessageBytes.raw(Protocol.ROOM_DATA_BYTES, type, undefined, bytes),\n options,\n );\n }\n\n public send(messageOrType: any, messageOrOptions?: any | ISendOptions, options?: ISendOptions) {\n debugMessage(\"send(to %s): '%s' -> %j\", this.sessionId, messageOrType, messageOrOptions);\n\n this.enqueueRaw(\n (messageOrType instanceof Schema)\n ? getMessageBytes[Protocol.ROOM_DATA_SCHEMA](messageOrType)\n : getMessageBytes.raw(Protocol.ROOM_DATA, messageOrType, messageOrOptions),\n options,\n );\n }\n\n public enqueueRaw(data: ArrayLike<number>, options?: ISendOptions) {\n // use room's afterNextPatch queue\n if (options?.afterNextPatch) {\n this._afterNextPatchQueue.push([this, arguments]);\n return;\n }\n\n if (this.state === ClientState.JOINING) {\n // sending messages during `onJoin`.\n // - the client-side cannot register \"onMessage\" callbacks at this point.\n // - enqueue the messages to be send after JOIN_ROOM message has been sent\n this._enqueuedMessages.push(data);\n return;\n }\n\n this.raw(data, options);\n }\n\n public raw(data: ArrayLike<number>, options?: ISendOptions, cb?: (err?: Error) => void) {\n // skip if client not open\n\n // WebSocket is globally available on Bun runtime\n // @ts-ignore\n if (this.ref.ws.readyState !== WebSocket.OPEN) {\n return;\n }\n\n // FIXME: can we avoid creating a new buffer here?\n this.ref.ws.sendBinary(Buffer.from(data as unknown as ArrayBufferLike));\n }\n\n public error(code: number, message: string = '', cb?: (err?: Error) => void) {\n this.raw(getMessageBytes[Protocol.ERROR](code, message), undefined, cb);\n }\n\n get readyState() {\n return this.ref.ws.readyState;\n }\n\n public leave(code?: number, data?: string) {\n this.ref.ws.close(code, data);\n }\n\n public close(code?: number, data?: string) {\n logger.warn('DEPRECATION WARNING: use client.leave() instead of client.close()');\n try {\n throw new Error();\n } catch (e) {\n logger.info(e.stack);\n }\n this.leave(code, data);\n }\n\n public toJSON() {\n return { sessionId: this.sessionId, readyState: this.readyState };\n }\n}\n"],
5
- "mappings": "AAKA,OAAO,kBAAkB;AAEzB,SAAS,UAAkB,aAA2B,iBAAiB,QAAQ,oBAAoB;AACnG,SAAS,cAAc;AAEhB,MAAM,yBAAyB,aAAa;AAAA,EACjD,YAAmB,IAA0B;AAC3C,UAAM;AADW;AAAA,EAEnB;AACF;AAEO,MAAM,gBAAkC;AAAA,EAO7C,YACS,IACA,KACP;AAFO;AACA;AAPT,SAAO,QAAqB,YAAY;AACxC,SAAO,oBAA2B,CAAC;AAQjC,SAAK,YAAY;AAAA,EACnB;AAAA,EAEO,UAAU,MAAuB,OAA8B,SAAwB;AAC5F,iBAAa,iCAAiC,KAAK,WAAW,MAAM,KAAK;AAEzE,SAAK;AAAA,MACH,gBAAgB,IAAI,SAAS,iBAAiB,MAAM,QAAW,KAAK;AAAA,MACpE;AAAA,IACF;AAAA,EACF;AAAA,EAEO,KAAK,eAAoB,kBAAuC,SAAwB;AAC7F,iBAAa,2BAA2B,KAAK,WAAW,eAAe,gBAAgB;AAEvF,SAAK;AAAA,MACF,yBAAyB,SACtB,gBAAgB,SAAS,kBAAkB,aAAa,IACxD,gBAAgB,IAAI,SAAS,WAAW,eAAe,gBAAgB;AAAA,MAC3E;AAAA,IACF;AAAA,EACF;AAAA,EAEO,WAAW,MAAyB,SAAwB;AAEjE,QAAI,SAAS,gBAAgB;AAC3B,WAAK,qBAAqB,KAAK,CAAC,MAAM,SAAS,CAAC;AAChD;AAAA,IACF;AAEA,QAAI,KAAK,UAAU,YAAY,SAAS;AAItC,WAAK,kBAAkB,KAAK,IAAI;AAChC;AAAA,IACF;AAEA,SAAK,IAAI,MAAM,OAAO;AAAA,EACxB;AAAA,EAEO,IAAI,MAAyB,SAAwB,IAA4B;AAKtF,QAAI,KAAK,IAAI,GAAG,eAAe,UAAU,MAAM;AAC7C;AAAA,IACF;AAGA,SAAK,IAAI,GAAG,WAAW,OAAO,KAAK,IAAkC,CAAC;AAAA,EACxE;AAAA,EAEO,MAAM,MAAc,UAAkB,IAAI,IAA4B;AAC3E,SAAK,IAAI,gBAAgB,SAAS,OAAO,MAAM,OAAO,GAAG,QAAW,EAAE;AAAA,EACxE;AAAA,EAEA,IAAI,aAAa;AACf,WAAO,KAAK,IAAI,GAAG;AAAA,EACrB;AAAA,EAEO,MAAM,MAAe,MAAe;AACzC,SAAK,IAAI,GAAG,MAAM,MAAM,IAAI;AAAA,EAC9B;AAAA,EAEO,MAAM,MAAe,MAAe;AACzC,WAAO,KAAK,mEAAmE;AAC/E,QAAI;AACF,YAAM,IAAI,MAAM;AAAA,IAClB,SAAS,GAAP;AACA,aAAO,KAAK,EAAE,KAAK;AAAA,IACrB;AACA,SAAK,MAAM,MAAM,IAAI;AAAA,EACvB;AAAA,EAEO,SAAS;AACd,WAAO,EAAE,WAAW,KAAK,WAAW,YAAY,KAAK,WAAW;AAAA,EAClE;AACF;",
4
+ "sourcesContent": ["// <reference types=\"bun-types\" />\n\n// \"bun-types\" is currently conflicting with \"ws\" types.\n// @ts-ignore\nimport { ServerWebSocket } from \"bun\";\nimport EventEmitter from 'events';\n\nimport { Protocol, Client, ClientPrivate, ClientState, ISendOptions, getMessageBytes, logger, debugMessage } from '@colyseus/core';\n\nexport class WebSocketWrapper extends EventEmitter {\n constructor(public ws: ServerWebSocket<any>) {\n super();\n }\n}\n\nexport class WebSocketClient implements Client, ClientPrivate {\n public sessionId: string;\n public state: ClientState = ClientState.JOINING;\n public reconnectionToken: string;\n\n public _enqueuedMessages: any[] = [];\n public _afterNextPatchQueue;\n public _reconnectionToken: string;\n public _joinedAt: number;\n\n constructor(\n public id: string,\n public ref: WebSocketWrapper,\n ) {\n this.sessionId = id;\n }\n\n public sendBytes(type: string | number, bytes: Buffer | Uint8Array, options?: ISendOptions) {\n debugMessage(\"send bytes(to %s): '%s' -> %j\", this.sessionId, type, bytes);\n\n this.enqueueRaw(\n getMessageBytes.raw(Protocol.ROOM_DATA_BYTES, type, undefined, bytes),\n options,\n );\n }\n\n public send(messageOrType: any, messageOrOptions?: any | ISendOptions, options?: ISendOptions) {\n debugMessage(\"send(to %s): '%s' -> %j\", this.sessionId, messageOrType, messageOrOptions);\n\n this.enqueueRaw(\n getMessageBytes.raw(Protocol.ROOM_DATA, messageOrType, messageOrOptions),\n options,\n );\n }\n\n public enqueueRaw(data: Uint8Array | Buffer, options?: ISendOptions) {\n // use room's afterNextPatch queue\n if (options?.afterNextPatch) {\n this._afterNextPatchQueue.push([this, arguments]);\n return;\n }\n\n if (this.state === ClientState.JOINING) {\n // sending messages during `onJoin`.\n // - the client-side cannot register \"onMessage\" callbacks at this point.\n // - enqueue the messages to be send after JOIN_ROOM message has been sent\n // - create a new buffer for enqueued messages, as the underlying buffer might be modified\n this._enqueuedMessages.push(Buffer.from(data));\n return;\n }\n\n this.raw(data, options);\n }\n\n public raw(data: Uint8Array | Buffer, options?: ISendOptions, cb?: (err?: Error) => void) {\n // skip if client not open\n\n // WebSocket is globally available on Bun runtime\n // @ts-ignore\n if (this.ref.ws.readyState !== WebSocket.OPEN) {\n return;\n }\n\n // FIXME: can we avoid creating a new buffer here?\n this.ref.ws.sendBinary(data);\n }\n\n public error(code: number, message: string = '', cb?: (err?: Error) => void) {\n this.raw(getMessageBytes[Protocol.ERROR](code, message), undefined, cb);\n }\n\n get readyState() {\n return this.ref.ws.readyState;\n }\n\n public leave(code?: number, data?: string) {\n this.ref.ws.close(code, data);\n }\n\n public close(code?: number, data?: string) {\n logger.warn('DEPRECATION WARNING: use client.leave() instead of client.close()');\n try {\n throw new Error();\n } catch (e) {\n logger.info(e.stack);\n }\n this.leave(code, data);\n }\n\n public toJSON() {\n return { sessionId: this.sessionId, readyState: this.readyState };\n }\n}\n"],
5
+ "mappings": "AAKA,OAAO,kBAAkB;AAEzB,SAAS,UAAiC,aAA2B,iBAAiB,QAAQ,oBAAoB;AAE3G,MAAM,yBAAyB,aAAa;AAAA,EACjD,YAAmB,IAA0B;AAC3C,UAAM;AADW;AAAA,EAEnB;AACF;AAEO,MAAM,gBAAiD;AAAA,EAU5D,YACS,IACA,KACP;AAFO;AACA;AAVT,SAAO,QAAqB,YAAY;AAGxC,SAAO,oBAA2B,CAAC;AASjC,SAAK,YAAY;AAAA,EACnB;AAAA,EAEO,UAAU,MAAuB,OAA4B,SAAwB;AAC1F,iBAAa,iCAAiC,KAAK,WAAW,MAAM,KAAK;AAEzE,SAAK;AAAA,MACH,gBAAgB,IAAI,SAAS,iBAAiB,MAAM,QAAW,KAAK;AAAA,MACpE;AAAA,IACF;AAAA,EACF;AAAA,EAEO,KAAK,eAAoB,kBAAuC,SAAwB;AAC7F,iBAAa,2BAA2B,KAAK,WAAW,eAAe,gBAAgB;AAEvF,SAAK;AAAA,MACH,gBAAgB,IAAI,SAAS,WAAW,eAAe,gBAAgB;AAAA,MACvE;AAAA,IACF;AAAA,EACF;AAAA,EAEO,WAAW,MAA2B,SAAwB;AAEnE,QAAI,SAAS,gBAAgB;AAC3B,WAAK,qBAAqB,KAAK,CAAC,MAAM,SAAS,CAAC;AAChD;AAAA,IACF;AAEA,QAAI,KAAK,UAAU,YAAY,SAAS;AAKtC,WAAK,kBAAkB,KAAK,OAAO,KAAK,IAAI,CAAC;AAC7C;AAAA,IACF;AAEA,SAAK,IAAI,MAAM,OAAO;AAAA,EACxB;AAAA,EAEO,IAAI,MAA2B,SAAwB,IAA4B;AAKxF,QAAI,KAAK,IAAI,GAAG,eAAe,UAAU,MAAM;AAC7C;AAAA,IACF;AAGA,SAAK,IAAI,GAAG,WAAW,IAAI;AAAA,EAC7B;AAAA,EAEO,MAAM,MAAc,UAAkB,IAAI,IAA4B;AAC3E,SAAK,IAAI,gBAAgB,SAAS,OAAO,MAAM,OAAO,GAAG,QAAW,EAAE;AAAA,EACxE;AAAA,EAEA,IAAI,aAAa;AACf,WAAO,KAAK,IAAI,GAAG;AAAA,EACrB;AAAA,EAEO,MAAM,MAAe,MAAe;AACzC,SAAK,IAAI,GAAG,MAAM,MAAM,IAAI;AAAA,EAC9B;AAAA,EAEO,MAAM,MAAe,MAAe;AACzC,WAAO,KAAK,mEAAmE;AAC/E,QAAI;AACF,YAAM,IAAI,MAAM;AAAA,IAClB,SAAS,GAAP;AACA,aAAO,KAAK,EAAE,KAAK;AAAA,IACrB;AACA,SAAK,MAAM,MAAM,IAAI;AAAA,EACvB;AAAA,EAEO,SAAS;AACd,WAAO,EAAE,WAAW,KAAK,WAAW,YAAY,KAAK,WAAW;AAAA,EAClE;AACF;",
6
6
  "names": []
7
7
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@colyseus/bun-websockets",
3
- "version": "0.15.3",
3
+ "version": "0.16.0-alpha.5",
4
4
  "input": "./src/index.ts",
5
5
  "main": "./build/index.js",
6
6
  "module": "./build/index.mjs",
@@ -8,12 +8,9 @@
8
8
  "dependencies": {
9
9
  "bun-serve-express": "^1.0.2",
10
10
  "express": "^4.17.1",
11
- "@colyseus/core": "^0.15.41"
11
+ "@colyseus/core": "^0.16.0-alpha.21"
12
12
  },
13
13
  "devDependencies": {},
14
- "peerDependencies": {
15
- "@colyseus/schema": ">=1.0.0"
16
- },
17
14
  "author": "Endel Dreyer",
18
15
  "license": "MIT",
19
16
  "keywords": [