@colyseus/bun-websockets 0.16.4 → 0.17.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.
- package/build/BunWebSockets.js +18 -98
- package/build/BunWebSockets.js.map +3 -3
- package/build/BunWebSockets.mjs +17 -88
- package/build/BunWebSockets.mjs.map +3 -3
- package/build/WebSocketClient.js +8 -5
- package/build/WebSocketClient.js.map +2 -2
- package/build/WebSocketClient.mjs +6 -4
- package/build/WebSocketClient.mjs.map +2 -2
- package/build/index.js +6 -5
- package/build/index.js.map +2 -2
- package/build/index.mjs.map +1 -1
- package/build/{BunWebSockets.d.ts → src/BunWebSockets.d.ts} +3 -4
- package/build/{WebSocketClient.d.ts → src/WebSocketClient.d.ts} +2 -1
- package/build/src/index.d.ts +2 -0
- package/package.json +12 -7
- package/build/index.d.ts +0 -2
package/build/BunWebSockets.js
CHANGED
|
@@ -1,8 +1,7 @@
|
|
|
1
|
-
|
|
1
|
+
"use strict";
|
|
2
2
|
var __defProp = Object.defineProperty;
|
|
3
3
|
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
4
4
|
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
5
|
-
var __getProtoOf = Object.getPrototypeOf;
|
|
6
5
|
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
7
6
|
var __export = (target, all) => {
|
|
8
7
|
for (var name in all)
|
|
@@ -16,50 +15,24 @@ var __copyProps = (to, from, except, desc) => {
|
|
|
16
15
|
}
|
|
17
16
|
return to;
|
|
18
17
|
};
|
|
19
|
-
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
|
|
20
|
-
// If the importer is in node compatibility mode or this is not an ESM
|
|
21
|
-
// file that has been converted to a CommonJS file using a Babel-
|
|
22
|
-
// compatible transform (i.e. "__esModule" has not been set), then set
|
|
23
|
-
// "default" to the CommonJS "module.exports" for node compatibility.
|
|
24
|
-
isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
|
|
25
|
-
mod
|
|
26
|
-
));
|
|
27
18
|
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
28
19
|
var BunWebSockets_exports = {};
|
|
29
20
|
__export(BunWebSockets_exports, {
|
|
30
21
|
BunWebSockets: () => BunWebSockets
|
|
31
22
|
});
|
|
32
23
|
module.exports = __toCommonJS(BunWebSockets_exports);
|
|
33
|
-
var
|
|
24
|
+
var import_bun = require("bun");
|
|
34
25
|
var import_core = require("@colyseus/core");
|
|
35
|
-
var import_WebSocketClient = require("./WebSocketClient.
|
|
26
|
+
var import_WebSocketClient = require("./WebSocketClient.ts");
|
|
36
27
|
class BunWebSockets extends import_core.Transport {
|
|
37
28
|
constructor(options = {}) {
|
|
38
29
|
super();
|
|
39
|
-
this.options = options;
|
|
40
30
|
this.clients = [];
|
|
41
31
|
this.clientWrappers = /* @__PURE__ */ new WeakMap();
|
|
42
32
|
this._originalRawSend = null;
|
|
33
|
+
this.options = {};
|
|
43
34
|
const self = this;
|
|
44
|
-
this.
|
|
45
|
-
websocket: {
|
|
46
|
-
...this.options,
|
|
47
|
-
async open(ws) {
|
|
48
|
-
await self.onConnection(ws);
|
|
49
|
-
},
|
|
50
|
-
message(ws, message) {
|
|
51
|
-
self.clientWrappers.get(ws)?.emit("message", message);
|
|
52
|
-
},
|
|
53
|
-
close(ws, code, reason) {
|
|
54
|
-
(0, import_core.spliceOne)(self.clients, self.clients.indexOf(ws));
|
|
55
|
-
const clientWrapper = self.clientWrappers.get(ws);
|
|
56
|
-
if (clientWrapper) {
|
|
57
|
-
self.clientWrappers.delete(ws);
|
|
58
|
-
clientWrapper.emit("close", code);
|
|
59
|
-
}
|
|
60
|
-
}
|
|
61
|
-
}
|
|
62
|
-
});
|
|
35
|
+
this.options = options;
|
|
63
36
|
if (!this.server) {
|
|
64
37
|
this.server = new import_core.HttpServerMock();
|
|
65
38
|
}
|
|
@@ -68,7 +41,6 @@ class BunWebSockets extends import_core.Transport {
|
|
|
68
41
|
this._listening = this.expressApp.listen(port, listeningListener);
|
|
69
42
|
this.expressApp.use(`/${import_core.matchMaker.controller.matchmakeRoute}`, async (req, res) => {
|
|
70
43
|
try {
|
|
71
|
-
await this.handleMatchMakeRequest(req, res);
|
|
72
44
|
} catch (e) {
|
|
73
45
|
res.status(500).json({
|
|
74
46
|
code: e.code,
|
|
@@ -104,82 +76,30 @@ class BunWebSockets extends import_core.Transport {
|
|
|
104
76
|
const sessionId = parsedURL.searchParams.get("sessionId");
|
|
105
77
|
const processAndRoomId = parsedURL.pathname.match(/\/[a-zA-Z0-9_\-]+\/([a-zA-Z0-9_\-]+)$/);
|
|
106
78
|
const roomId = processAndRoomId && processAndRoomId[1];
|
|
79
|
+
if (!sessionId && !roomId) {
|
|
80
|
+
const timeout = setTimeout(() => rawClient.close(import_core.CloseCode.NORMAL_CLOSURE), 1e3);
|
|
81
|
+
wrapper.on("message", (_) => rawClient.send(new Uint8Array([import_core.Protocol.PING])));
|
|
82
|
+
wrapper.on("close", () => clearTimeout(timeout));
|
|
83
|
+
return;
|
|
84
|
+
}
|
|
107
85
|
const room = import_core.matchMaker.getLocalRoomById(roomId);
|
|
108
86
|
const client = new import_WebSocketClient.WebSocketClient(sessionId, wrapper);
|
|
87
|
+
const reconnectionToken = parsedURL.searchParams.get("reconnectionToken");
|
|
88
|
+
const skipHandshake = parsedURL.searchParams.has("skipHandshake");
|
|
109
89
|
try {
|
|
110
|
-
|
|
111
|
-
throw new Error("seat reservation expired.");
|
|
112
|
-
}
|
|
113
|
-
await room._onJoin(client, {
|
|
90
|
+
await (0, import_core.connectClientToRoom)(room, client, {
|
|
114
91
|
token: parsedURL.searchParams.get("_authToken") ?? (0, import_core.getBearerToken)(rawClient.data.headers["authorization"]),
|
|
115
92
|
headers: rawClient.data.headers,
|
|
116
|
-
ip: rawClient.data.headers["x-real-ip"] ?? rawClient.remoteAddress
|
|
93
|
+
ip: rawClient.data.headers["x-real-ip"] ?? rawClient.data.headers["x-forwarded-for"] ?? rawClient.remoteAddress
|
|
94
|
+
}, {
|
|
95
|
+
reconnectionToken,
|
|
96
|
+
skipHandshake
|
|
117
97
|
});
|
|
118
98
|
} catch (e) {
|
|
119
99
|
(0, import_core.debugAndPrintError)(e);
|
|
120
100
|
client.error(e.code, e.message, () => rawClient.close());
|
|
121
101
|
}
|
|
122
102
|
}
|
|
123
|
-
async handleMatchMakeRequest(req, res) {
|
|
124
|
-
const writeHeaders = (req2, res2) => {
|
|
125
|
-
if (res2.destroyed) return;
|
|
126
|
-
res2.set(Object.assign(
|
|
127
|
-
{},
|
|
128
|
-
import_core.matchMaker.controller.DEFAULT_CORS_HEADERS,
|
|
129
|
-
import_core.matchMaker.controller.getCorsHeaders.call(void 0, req2)
|
|
130
|
-
));
|
|
131
|
-
return true;
|
|
132
|
-
};
|
|
133
|
-
try {
|
|
134
|
-
switch (req.method) {
|
|
135
|
-
case "OPTIONS": {
|
|
136
|
-
writeHeaders(req, res);
|
|
137
|
-
res.status(200).end();
|
|
138
|
-
break;
|
|
139
|
-
}
|
|
140
|
-
case "GET": {
|
|
141
|
-
writeHeaders(req, res);
|
|
142
|
-
res.status(404).end();
|
|
143
|
-
break;
|
|
144
|
-
}
|
|
145
|
-
case "POST": {
|
|
146
|
-
if (import_core.matchMaker.state === import_core.matchMaker.MatchMakerState.SHUTTING_DOWN) {
|
|
147
|
-
throw new import_core.ServerError(503, "server is shutting down");
|
|
148
|
-
}
|
|
149
|
-
const matchedParams = req.path.match(import_core.matchMaker.controller.allowedRoomNameChars);
|
|
150
|
-
const matchmakeIndex = matchedParams.indexOf(import_core.matchMaker.controller.matchmakeRoute);
|
|
151
|
-
let clientOptions = req.body;
|
|
152
|
-
if (clientOptions == null) {
|
|
153
|
-
throw new import_core.ServerError(500, "invalid JSON input");
|
|
154
|
-
}
|
|
155
|
-
if (typeof clientOptions === "string" && clientOptions.length > 2) {
|
|
156
|
-
clientOptions = JSON.parse(clientOptions);
|
|
157
|
-
} else if (typeof clientOptions !== "object") {
|
|
158
|
-
clientOptions = {};
|
|
159
|
-
}
|
|
160
|
-
const method = matchedParams[matchmakeIndex + 1];
|
|
161
|
-
const roomName = matchedParams[matchmakeIndex + 2] || "";
|
|
162
|
-
writeHeaders(req, res);
|
|
163
|
-
res.json(await import_core.matchMaker.controller.invokeMethod(
|
|
164
|
-
method,
|
|
165
|
-
roomName,
|
|
166
|
-
clientOptions,
|
|
167
|
-
{
|
|
168
|
-
token: (0, import_core.getBearerToken)(req.headers["authorization"]),
|
|
169
|
-
headers: req.headers,
|
|
170
|
-
ip: req.headers["x-real-ip"] ?? req.ips
|
|
171
|
-
}
|
|
172
|
-
));
|
|
173
|
-
break;
|
|
174
|
-
}
|
|
175
|
-
default:
|
|
176
|
-
throw new import_core.ServerError(500, "invalid request method");
|
|
177
|
-
}
|
|
178
|
-
} catch (e) {
|
|
179
|
-
writeHeaders(req, res);
|
|
180
|
-
res.status(500).json({ code: e.code, error: e.message });
|
|
181
|
-
}
|
|
182
|
-
}
|
|
183
103
|
}
|
|
184
104
|
// Annotate the CommonJS export names for ESM import in node:
|
|
185
105
|
0 && (module.exports = {
|
|
@@ -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\
|
|
5
|
-
"mappings": "
|
|
6
|
-
"names": [
|
|
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\n// import bunExpress from 'bun-serve-express';\nimport type { Application, Request, Response } from \"express\";\n\nimport { HttpServerMock, matchMaker, Protocol, Transport, debugAndPrintError, getBearerToken, CloseCode, connectClientToRoom } from '@colyseus/core';\nimport { WebSocketClient, WebSocketWrapper } from './WebSocketClient.ts';\n\nexport type TransportOptions = Partial<Omit<WebSocketHandler, \"message\" | \"open\" | \"drain\" | \"close\" | \"ping\" | \"pong\">>;\n\ninterface WebSocketData {\n url: URL;\n headers: any;\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 private options: TransportOptions = {};\n\n constructor(options: TransportOptions = {}) {\n super();\n\n const self = this;\n\n this.options = options;\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 // 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 // TODO: use shared handler here\n // await this.handleMatchMakeRequest(req, res);\n } catch (e: any) {\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 (...args: any[]) {\n let [buf, ...rest] = args;\n buf = Buffer.from(buf);\n // @ts-ignore\n setTimeout(() => originalRawSend.apply(this, [buf, ...rest]), 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 // If sessionId is not provided, allow ping-pong utility.\n if (!sessionId && !roomId) {\n // Disconnect automatically after 1 second if no message is received.\n const timeout = setTimeout(() => rawClient.close(CloseCode.NORMAL_CLOSURE), 1000);\n wrapper.on('message', (_) => rawClient.send(new Uint8Array([Protocol.PING])));\n wrapper.on('close', () => clearTimeout(timeout));\n return;\n }\n\n const room = matchMaker.getLocalRoomById(roomId);\n const client = new WebSocketClient(sessionId, wrapper);\n const reconnectionToken = parsedURL.searchParams.get(\"reconnectionToken\");\n const skipHandshake = (parsedURL.searchParams.has(\"skipHandshake\"));\n\n try {\n await connectClientToRoom(room, client, {\n token: parsedURL.searchParams.get(\"_authToken\") ?? getBearerToken(rawClient.data.headers['authorization']),\n headers: rawClient.data.headers,\n ip: rawClient.data.headers['x-real-ip'] ?? rawClient.data.headers['x-forwarded-for'] ?? rawClient.remoteAddress,\n }, {\n reconnectionToken,\n skipHandshake\n });\n\n } catch (e: any) {\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}\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
|
+
"names": []
|
|
7
7
|
}
|
package/build/BunWebSockets.mjs
CHANGED
|
@@ -1,34 +1,16 @@
|
|
|
1
1
|
// packages/transport/bun-websockets/src/BunWebSockets.ts
|
|
2
|
-
import
|
|
3
|
-
import { HttpServerMock, matchMaker, Transport, debugAndPrintError,
|
|
2
|
+
import "bun";
|
|
3
|
+
import { HttpServerMock, matchMaker, Protocol, Transport, debugAndPrintError, getBearerToken, CloseCode, connectClientToRoom } from "@colyseus/core";
|
|
4
4
|
import { WebSocketClient, WebSocketWrapper } from "./WebSocketClient.mjs";
|
|
5
5
|
var BunWebSockets = class extends Transport {
|
|
6
6
|
constructor(options = {}) {
|
|
7
7
|
super();
|
|
8
|
-
this.options = options;
|
|
9
8
|
this.clients = [];
|
|
10
9
|
this.clientWrappers = /* @__PURE__ */ new WeakMap();
|
|
11
10
|
this._originalRawSend = null;
|
|
11
|
+
this.options = {};
|
|
12
12
|
const self = this;
|
|
13
|
-
this.
|
|
14
|
-
websocket: {
|
|
15
|
-
...this.options,
|
|
16
|
-
async open(ws) {
|
|
17
|
-
await self.onConnection(ws);
|
|
18
|
-
},
|
|
19
|
-
message(ws, message) {
|
|
20
|
-
self.clientWrappers.get(ws)?.emit("message", message);
|
|
21
|
-
},
|
|
22
|
-
close(ws, code, reason) {
|
|
23
|
-
spliceOne(self.clients, self.clients.indexOf(ws));
|
|
24
|
-
const clientWrapper = self.clientWrappers.get(ws);
|
|
25
|
-
if (clientWrapper) {
|
|
26
|
-
self.clientWrappers.delete(ws);
|
|
27
|
-
clientWrapper.emit("close", code);
|
|
28
|
-
}
|
|
29
|
-
}
|
|
30
|
-
}
|
|
31
|
-
});
|
|
13
|
+
this.options = options;
|
|
32
14
|
if (!this.server) {
|
|
33
15
|
this.server = new HttpServerMock();
|
|
34
16
|
}
|
|
@@ -37,7 +19,6 @@ var BunWebSockets = class extends Transport {
|
|
|
37
19
|
this._listening = this.expressApp.listen(port, listeningListener);
|
|
38
20
|
this.expressApp.use(`/${matchMaker.controller.matchmakeRoute}`, async (req, res) => {
|
|
39
21
|
try {
|
|
40
|
-
await this.handleMatchMakeRequest(req, res);
|
|
41
22
|
} catch (e) {
|
|
42
23
|
res.status(500).json({
|
|
43
24
|
code: e.code,
|
|
@@ -73,82 +54,30 @@ var BunWebSockets = class extends Transport {
|
|
|
73
54
|
const sessionId = parsedURL.searchParams.get("sessionId");
|
|
74
55
|
const processAndRoomId = parsedURL.pathname.match(/\/[a-zA-Z0-9_\-]+\/([a-zA-Z0-9_\-]+)$/);
|
|
75
56
|
const roomId = processAndRoomId && processAndRoomId[1];
|
|
57
|
+
if (!sessionId && !roomId) {
|
|
58
|
+
const timeout = setTimeout(() => rawClient.close(CloseCode.NORMAL_CLOSURE), 1e3);
|
|
59
|
+
wrapper.on("message", (_) => rawClient.send(new Uint8Array([Protocol.PING])));
|
|
60
|
+
wrapper.on("close", () => clearTimeout(timeout));
|
|
61
|
+
return;
|
|
62
|
+
}
|
|
76
63
|
const room = matchMaker.getLocalRoomById(roomId);
|
|
77
64
|
const client = new WebSocketClient(sessionId, wrapper);
|
|
65
|
+
const reconnectionToken = parsedURL.searchParams.get("reconnectionToken");
|
|
66
|
+
const skipHandshake = parsedURL.searchParams.has("skipHandshake");
|
|
78
67
|
try {
|
|
79
|
-
|
|
80
|
-
throw new Error("seat reservation expired.");
|
|
81
|
-
}
|
|
82
|
-
await room._onJoin(client, {
|
|
68
|
+
await connectClientToRoom(room, client, {
|
|
83
69
|
token: parsedURL.searchParams.get("_authToken") ?? getBearerToken(rawClient.data.headers["authorization"]),
|
|
84
70
|
headers: rawClient.data.headers,
|
|
85
|
-
ip: rawClient.data.headers["x-real-ip"] ?? rawClient.remoteAddress
|
|
71
|
+
ip: rawClient.data.headers["x-real-ip"] ?? rawClient.data.headers["x-forwarded-for"] ?? rawClient.remoteAddress
|
|
72
|
+
}, {
|
|
73
|
+
reconnectionToken,
|
|
74
|
+
skipHandshake
|
|
86
75
|
});
|
|
87
76
|
} catch (e) {
|
|
88
77
|
debugAndPrintError(e);
|
|
89
78
|
client.error(e.code, e.message, () => rawClient.close());
|
|
90
79
|
}
|
|
91
80
|
}
|
|
92
|
-
async handleMatchMakeRequest(req, res) {
|
|
93
|
-
const writeHeaders = (req2, res2) => {
|
|
94
|
-
if (res2.destroyed) return;
|
|
95
|
-
res2.set(Object.assign(
|
|
96
|
-
{},
|
|
97
|
-
matchMaker.controller.DEFAULT_CORS_HEADERS,
|
|
98
|
-
matchMaker.controller.getCorsHeaders.call(void 0, req2)
|
|
99
|
-
));
|
|
100
|
-
return true;
|
|
101
|
-
};
|
|
102
|
-
try {
|
|
103
|
-
switch (req.method) {
|
|
104
|
-
case "OPTIONS": {
|
|
105
|
-
writeHeaders(req, res);
|
|
106
|
-
res.status(200).end();
|
|
107
|
-
break;
|
|
108
|
-
}
|
|
109
|
-
case "GET": {
|
|
110
|
-
writeHeaders(req, res);
|
|
111
|
-
res.status(404).end();
|
|
112
|
-
break;
|
|
113
|
-
}
|
|
114
|
-
case "POST": {
|
|
115
|
-
if (matchMaker.state === matchMaker.MatchMakerState.SHUTTING_DOWN) {
|
|
116
|
-
throw new ServerError(503, "server is shutting down");
|
|
117
|
-
}
|
|
118
|
-
const matchedParams = req.path.match(matchMaker.controller.allowedRoomNameChars);
|
|
119
|
-
const matchmakeIndex = matchedParams.indexOf(matchMaker.controller.matchmakeRoute);
|
|
120
|
-
let clientOptions = req.body;
|
|
121
|
-
if (clientOptions == null) {
|
|
122
|
-
throw new ServerError(500, "invalid JSON input");
|
|
123
|
-
}
|
|
124
|
-
if (typeof clientOptions === "string" && clientOptions.length > 2) {
|
|
125
|
-
clientOptions = JSON.parse(clientOptions);
|
|
126
|
-
} else if (typeof clientOptions !== "object") {
|
|
127
|
-
clientOptions = {};
|
|
128
|
-
}
|
|
129
|
-
const method = matchedParams[matchmakeIndex + 1];
|
|
130
|
-
const roomName = matchedParams[matchmakeIndex + 2] || "";
|
|
131
|
-
writeHeaders(req, res);
|
|
132
|
-
res.json(await matchMaker.controller.invokeMethod(
|
|
133
|
-
method,
|
|
134
|
-
roomName,
|
|
135
|
-
clientOptions,
|
|
136
|
-
{
|
|
137
|
-
token: getBearerToken(req.headers["authorization"]),
|
|
138
|
-
headers: req.headers,
|
|
139
|
-
ip: req.headers["x-real-ip"] ?? req.ips
|
|
140
|
-
}
|
|
141
|
-
));
|
|
142
|
-
break;
|
|
143
|
-
}
|
|
144
|
-
default:
|
|
145
|
-
throw new ServerError(500, "invalid request method");
|
|
146
|
-
}
|
|
147
|
-
} catch (e) {
|
|
148
|
-
writeHeaders(req, res);
|
|
149
|
-
res.status(500).json({ code: e.code, error: e.message });
|
|
150
|
-
}
|
|
151
|
-
}
|
|
152
81
|
};
|
|
153
82
|
export {
|
|
154
83
|
BunWebSockets
|
|
@@ -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\
|
|
5
|
-
"mappings": ";
|
|
6
|
-
"names": [
|
|
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\n// import bunExpress from 'bun-serve-express';\nimport type { Application, Request, Response } from \"express\";\n\nimport { HttpServerMock, matchMaker, Protocol, Transport, debugAndPrintError, getBearerToken, CloseCode, connectClientToRoom } from '@colyseus/core';\nimport { WebSocketClient, WebSocketWrapper } from './WebSocketClient.ts';\n\nexport type TransportOptions = Partial<Omit<WebSocketHandler, \"message\" | \"open\" | \"drain\" | \"close\" | \"ping\" | \"pong\">>;\n\ninterface WebSocketData {\n url: URL;\n headers: any;\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 private options: TransportOptions = {};\n\n constructor(options: TransportOptions = {}) {\n super();\n\n const self = this;\n\n this.options = options;\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 // 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 // TODO: use shared handler here\n // await this.handleMatchMakeRequest(req, res);\n } catch (e: any) {\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 (...args: any[]) {\n let [buf, ...rest] = args;\n buf = Buffer.from(buf);\n // @ts-ignore\n setTimeout(() => originalRawSend.apply(this, [buf, ...rest]), 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 // If sessionId is not provided, allow ping-pong utility.\n if (!sessionId && !roomId) {\n // Disconnect automatically after 1 second if no message is received.\n const timeout = setTimeout(() => rawClient.close(CloseCode.NORMAL_CLOSURE), 1000);\n wrapper.on('message', (_) => rawClient.send(new Uint8Array([Protocol.PING])));\n wrapper.on('close', () => clearTimeout(timeout));\n return;\n }\n\n const room = matchMaker.getLocalRoomById(roomId);\n const client = new WebSocketClient(sessionId, wrapper);\n const reconnectionToken = parsedURL.searchParams.get(\"reconnectionToken\");\n const skipHandshake = (parsedURL.searchParams.has(\"skipHandshake\"));\n\n try {\n await connectClientToRoom(room, client, {\n token: parsedURL.searchParams.get(\"_authToken\") ?? getBearerToken(rawClient.data.headers['authorization']),\n headers: rawClient.data.headers,\n ip: rawClient.data.headers['x-real-ip'] ?? rawClient.data.headers['x-forwarded-for'] ?? rawClient.remoteAddress,\n }, {\n reconnectionToken,\n skipHandshake\n });\n\n } catch (e: any) {\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}\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
|
+
"names": []
|
|
7
7
|
}
|
package/build/WebSocketClient.js
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
"use strict";
|
|
1
2
|
var __create = Object.create;
|
|
2
3
|
var __defProp = Object.defineProperty;
|
|
3
4
|
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
@@ -31,7 +32,7 @@ __export(WebSocketClient_exports, {
|
|
|
31
32
|
WebSocketWrapper: () => WebSocketWrapper
|
|
32
33
|
});
|
|
33
34
|
module.exports = __toCommonJS(WebSocketClient_exports);
|
|
34
|
-
var import_events = __toESM(require("events"));
|
|
35
|
+
var import_events = __toESM(require("events"), 1);
|
|
35
36
|
var import_core = require("@colyseus/core");
|
|
36
37
|
class WebSocketWrapper extends import_events.default {
|
|
37
38
|
constructor(ws) {
|
|
@@ -41,11 +42,10 @@ class WebSocketWrapper extends import_events.default {
|
|
|
41
42
|
}
|
|
42
43
|
class WebSocketClient {
|
|
43
44
|
constructor(id, ref) {
|
|
44
|
-
this.id = id;
|
|
45
|
-
this.ref = ref;
|
|
46
45
|
this.state = import_core.ClientState.JOINING;
|
|
47
46
|
this._enqueuedMessages = [];
|
|
48
|
-
this.sessionId = id;
|
|
47
|
+
this.id = this.sessionId = id;
|
|
48
|
+
this.ref = ref;
|
|
49
49
|
}
|
|
50
50
|
sendBytes(type, bytes, options) {
|
|
51
51
|
(0, import_core.debugMessage)("send bytes(to %s): '%s' -> %j", this.sessionId, type, bytes);
|
|
@@ -79,7 +79,10 @@ class WebSocketClient {
|
|
|
79
79
|
this.ref.ws.sendBinary(data);
|
|
80
80
|
}
|
|
81
81
|
error(code, message = "", cb) {
|
|
82
|
-
this.raw(import_core.getMessageBytes[import_core.Protocol.ERROR](code, message)
|
|
82
|
+
this.raw(import_core.getMessageBytes[import_core.Protocol.ERROR](code, message));
|
|
83
|
+
if (cb) {
|
|
84
|
+
setTimeout(cb, 1);
|
|
85
|
+
}
|
|
83
86
|
}
|
|
84
87
|
get readyState() {
|
|
85
88
|
return this.ref.ws.readyState;
|
|
@@ -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 type { 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
|
|
5
|
-
"mappings": "
|
|
4
|
+
"sourcesContent": ["// <reference types=\"bun-types\" />\n\n// \"bun-types\" is currently conflicting with \"ws\" types.\n// @ts-ignore\nimport type { ServerWebSocket } from 'bun';\nimport EventEmitter from 'events';\n\nimport { Protocol, type Client, type ClientPrivate, ClientState, type ISendOptions, getMessageBytes, logger, debugMessage } from '@colyseus/core';\n\nexport class WebSocketWrapper extends EventEmitter {\n public ws: ServerWebSocket<any>;\n\n constructor(ws: ServerWebSocket<any>) {\n super();\n this.ws = ws;\n }\n}\n\nexport class WebSocketClient implements Client, ClientPrivate {\n '~messages': any;\n\n public id: string;\n public ref: WebSocketWrapper;\n\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(id: string, ref: WebSocketWrapper,) {\n this.id = this.sessionId = id;\n this.ref = ref;\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, [data]]);\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(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));\n\n if (cb) {\n // (same API as \"ws\" transport)\n setTimeout(cb, 1);\n }\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: any) {\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,kBAAiI;AAE1H,MAAM,yBAAyB,cAAAA,QAAa;AAAA,EAGjD,YAAY,IAA0B;AACpC,UAAM;AACN,SAAK,KAAK;AAAA,EACZ;AACF;AAEO,MAAM,gBAAiD;AAAA,EAe5D,YAAY,IAAY,KAAwB;AARhD,SAAO,QAAqB,wBAAY;AAGxC,SAAO,oBAA2B,CAAC;AAMjC,SAAK,KAAK,KAAK,YAAY;AAC3B,SAAK,MAAM;AAAA,EACb;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,CAAC,IAAI,CAAC,CAAC;AAC7C;AAAA,IACF;AAEA,QAAI,KAAK,UAAU,wBAAY,SAAS;AAKtC,WAAK,kBAAkB,KAAK,IAAI;AAChC;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,KAAK,EAAE,MAAM,OAAO,CAAC;AAEvD,QAAI,IAAI;AAEN,iBAAW,IAAI,CAAC;AAAA,IAClB;AAAA,EACF;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,GAAQ;AACf,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
|
}
|
|
@@ -9,11 +9,10 @@ var WebSocketWrapper = class extends EventEmitter {
|
|
|
9
9
|
};
|
|
10
10
|
var WebSocketClient = class {
|
|
11
11
|
constructor(id, ref) {
|
|
12
|
-
this.id = id;
|
|
13
|
-
this.ref = ref;
|
|
14
12
|
this.state = ClientState.JOINING;
|
|
15
13
|
this._enqueuedMessages = [];
|
|
16
|
-
this.sessionId = id;
|
|
14
|
+
this.id = this.sessionId = id;
|
|
15
|
+
this.ref = ref;
|
|
17
16
|
}
|
|
18
17
|
sendBytes(type, bytes, options) {
|
|
19
18
|
debugMessage("send bytes(to %s): '%s' -> %j", this.sessionId, type, bytes);
|
|
@@ -47,7 +46,10 @@ var WebSocketClient = class {
|
|
|
47
46
|
this.ref.ws.sendBinary(data);
|
|
48
47
|
}
|
|
49
48
|
error(code, message = "", cb) {
|
|
50
|
-
this.raw(getMessageBytes[Protocol.ERROR](code, message)
|
|
49
|
+
this.raw(getMessageBytes[Protocol.ERROR](code, message));
|
|
50
|
+
if (cb) {
|
|
51
|
+
setTimeout(cb, 1);
|
|
52
|
+
}
|
|
51
53
|
}
|
|
52
54
|
get readyState() {
|
|
53
55
|
return this.ref.ws.readyState;
|
|
@@ -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 type { 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
|
|
5
|
-
"mappings": ";AAKA,OAAO,kBAAkB;AAEzB,SAAS,
|
|
4
|
+
"sourcesContent": ["// <reference types=\"bun-types\" />\n\n// \"bun-types\" is currently conflicting with \"ws\" types.\n// @ts-ignore\nimport type { ServerWebSocket } from 'bun';\nimport EventEmitter from 'events';\n\nimport { Protocol, type Client, type ClientPrivate, ClientState, type ISendOptions, getMessageBytes, logger, debugMessage } from '@colyseus/core';\n\nexport class WebSocketWrapper extends EventEmitter {\n public ws: ServerWebSocket<any>;\n\n constructor(ws: ServerWebSocket<any>) {\n super();\n this.ws = ws;\n }\n}\n\nexport class WebSocketClient implements Client, ClientPrivate {\n '~messages': any;\n\n public id: string;\n public ref: WebSocketWrapper;\n\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(id: string, ref: WebSocketWrapper,) {\n this.id = this.sessionId = id;\n this.ref = ref;\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, [data]]);\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(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));\n\n if (cb) {\n // (same API as \"ws\" transport)\n setTimeout(cb, 1);\n }\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: any) {\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,UAA2C,aAAgC,iBAAiB,QAAQ,oBAAoB;AAE1H,IAAM,mBAAN,cAA+B,aAAa;AAAA,EAGjD,YAAY,IAA0B;AACpC,UAAM;AACN,SAAK,KAAK;AAAA,EACZ;AACF;AAEO,IAAM,kBAAN,MAAuD;AAAA,EAe5D,YAAY,IAAY,KAAwB;AARhD,SAAO,QAAqB,YAAY;AAGxC,SAAO,oBAA2B,CAAC;AAMjC,SAAK,KAAK,KAAK,YAAY;AAC3B,SAAK,MAAM;AAAA,EACb;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,CAAC,IAAI,CAAC,CAAC;AAC7C;AAAA,IACF;AAEA,QAAI,KAAK,UAAU,YAAY,SAAS;AAKtC,WAAK,kBAAkB,KAAK,IAAI;AAChC;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,KAAK,EAAE,MAAM,OAAO,CAAC;AAEvD,QAAI,IAAI;AAEN,iBAAW,IAAI,CAAC;AAAA,IAClB;AAAA,EACF;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,GAAQ;AACf,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/build/index.js
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
"use strict";
|
|
1
2
|
var __defProp = Object.defineProperty;
|
|
2
3
|
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
3
4
|
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
@@ -15,14 +16,14 @@ var __copyProps = (to, from, except, desc) => {
|
|
|
15
16
|
return to;
|
|
16
17
|
};
|
|
17
18
|
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
18
|
-
var
|
|
19
|
-
__export(
|
|
19
|
+
var index_exports = {};
|
|
20
|
+
__export(index_exports, {
|
|
20
21
|
BunWebSockets: () => import_BunWebSockets.BunWebSockets,
|
|
21
22
|
WebSocketClient: () => import_WebSocketClient.WebSocketClient
|
|
22
23
|
});
|
|
23
|
-
module.exports = __toCommonJS(
|
|
24
|
-
var import_WebSocketClient = require("./WebSocketClient.
|
|
25
|
-
var import_BunWebSockets = require("./BunWebSockets.
|
|
24
|
+
module.exports = __toCommonJS(index_exports);
|
|
25
|
+
var import_WebSocketClient = require("./WebSocketClient.ts");
|
|
26
|
+
var import_BunWebSockets = require("./BunWebSockets.ts");
|
|
26
27
|
// Annotate the CommonJS export names for ESM import in node:
|
|
27
28
|
0 && (module.exports = {
|
|
28
29
|
BunWebSockets,
|
package/build/index.js.map
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../src/index.ts"],
|
|
4
|
-
"sourcesContent": ["export { WebSocketClient } from './WebSocketClient.
|
|
5
|
-
"mappings": "
|
|
4
|
+
"sourcesContent": ["export { WebSocketClient } from './WebSocketClient.ts';\nexport { BunWebSockets, type TransportOptions } from './BunWebSockets.ts';"],
|
|
5
|
+
"mappings": ";;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,6BAAgC;AAChC,2BAAqD;",
|
|
6
6
|
"names": []
|
|
7
7
|
}
|
package/build/index.mjs.map
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../src/index.ts"],
|
|
4
|
-
"sourcesContent": ["export { WebSocketClient } from './WebSocketClient.
|
|
4
|
+
"sourcesContent": ["export { WebSocketClient } from './WebSocketClient.ts';\nexport { BunWebSockets, type TransportOptions } from './BunWebSockets.ts';"],
|
|
5
5
|
"mappings": ";AAAA,SAAS,uBAAuB;AAChC,SAAS,qBAA4C;",
|
|
6
6
|
"names": []
|
|
7
7
|
}
|
|
@@ -1,24 +1,23 @@
|
|
|
1
1
|
import { ServerWebSocket, WebSocketHandler } from 'bun';
|
|
2
|
-
import type { Application
|
|
2
|
+
import type { Application } from "express";
|
|
3
3
|
import { Transport } from '@colyseus/core';
|
|
4
|
-
import { WebSocketWrapper } from './WebSocketClient.
|
|
4
|
+
import { WebSocketWrapper } from './WebSocketClient.ts';
|
|
5
5
|
export type TransportOptions = Partial<Omit<WebSocketHandler, "message" | "open" | "drain" | "close" | "ping" | "pong">>;
|
|
6
6
|
interface WebSocketData {
|
|
7
7
|
url: URL;
|
|
8
8
|
headers: any;
|
|
9
9
|
}
|
|
10
10
|
export declare class BunWebSockets extends Transport {
|
|
11
|
-
private options;
|
|
12
11
|
expressApp: Application;
|
|
13
12
|
protected clients: ServerWebSocket<WebSocketData>[];
|
|
14
13
|
protected clientWrappers: WeakMap<ServerWebSocket<WebSocketData>, WebSocketWrapper>;
|
|
15
14
|
private _listening;
|
|
16
15
|
private _originalRawSend;
|
|
16
|
+
private options;
|
|
17
17
|
constructor(options?: TransportOptions);
|
|
18
18
|
listen(port: number, hostname?: string, backlog?: number, listeningListener?: () => void): this;
|
|
19
19
|
shutdown(): void;
|
|
20
20
|
simulateLatency(milliseconds: number): void;
|
|
21
21
|
protected onConnection(rawClient: ServerWebSocket<WebSocketData>): Promise<void>;
|
|
22
|
-
protected handleMatchMakeRequest(req: Request, res: Response): Promise<void>;
|
|
23
22
|
}
|
|
24
23
|
export {};
|
|
@@ -1,11 +1,12 @@
|
|
|
1
1
|
import type { ServerWebSocket } from 'bun';
|
|
2
2
|
import EventEmitter from 'events';
|
|
3
|
-
import { Client, ClientPrivate, ClientState, ISendOptions } from '@colyseus/core';
|
|
3
|
+
import { type Client, type ClientPrivate, ClientState, type ISendOptions } from '@colyseus/core';
|
|
4
4
|
export declare class WebSocketWrapper extends EventEmitter {
|
|
5
5
|
ws: ServerWebSocket<any>;
|
|
6
6
|
constructor(ws: ServerWebSocket<any>);
|
|
7
7
|
}
|
|
8
8
|
export declare class WebSocketClient implements Client, ClientPrivate {
|
|
9
|
+
'~messages': any;
|
|
9
10
|
id: string;
|
|
10
11
|
ref: WebSocketWrapper;
|
|
11
12
|
sessionId: string;
|
package/package.json
CHANGED
|
@@ -1,24 +1,29 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@colyseus/bun-websockets",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.17.0",
|
|
4
|
+
"type": "module",
|
|
4
5
|
"input": "./src/index.ts",
|
|
5
6
|
"main": "./build/index.js",
|
|
6
|
-
"module": "./
|
|
7
|
+
"module": "./src/index.ts",
|
|
7
8
|
"typings": "./build/index.d.ts",
|
|
8
9
|
"exports": {
|
|
9
10
|
".": {
|
|
10
11
|
"types": "./build/index.d.ts",
|
|
11
|
-
"import": "./
|
|
12
|
+
"import": "./src/index.ts",
|
|
12
13
|
"require": "./build/index.js"
|
|
14
|
+
},
|
|
15
|
+
"./*": {
|
|
16
|
+
"types": "./build/*.d.ts",
|
|
17
|
+
"import": "./src/*.ts",
|
|
18
|
+
"require": "./build/*.js"
|
|
13
19
|
}
|
|
14
20
|
},
|
|
15
21
|
"dependencies": {
|
|
16
|
-
"
|
|
17
|
-
"express": ">=4.16.0",
|
|
18
|
-
"@colyseus/core": "^0.16.16"
|
|
22
|
+
"@colyseus/core": "^0.17.0"
|
|
19
23
|
},
|
|
20
24
|
"devDependencies": {
|
|
21
|
-
"
|
|
25
|
+
"bun-types": "^1.2.0",
|
|
26
|
+
"@colyseus/core": "^0.17.0"
|
|
22
27
|
},
|
|
23
28
|
"author": "Endel Dreyer",
|
|
24
29
|
"license": "MIT",
|
package/build/index.d.ts
DELETED