sonic-ws 1.3.3 → 2.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (78) hide show
  1. package/LICENSE +56 -196
  2. package/README.md +88 -17
  3. package/dist/{index.d.ts → ts/index.d.ts} +6 -0
  4. package/dist/{index.js → ts/index.js} +10 -11
  5. package/dist/ts/native/wrapper.d.ts +59 -0
  6. package/dist/ts/native/wrapper.js +7 -0
  7. package/dist/{version.d.ts → ts/version.d.ts} +5 -0
  8. package/dist/ts/version.js +7 -0
  9. package/dist/{ws → ts/ws}/Connection.d.ts +5 -0
  10. package/dist/ts/ws/Connection.js +7 -0
  11. package/dist/{ws → ts/ws}/PacketProcessor.d.ts +5 -0
  12. package/dist/ts/ws/PacketProcessor.js +7 -0
  13. package/dist/{ws → ts/ws}/client/core/ClientCore.d.ts +5 -0
  14. package/dist/ts/ws/client/core/ClientCore.js +7 -0
  15. package/dist/{ws → ts/ws}/client/node/ClientNode.d.ts +5 -0
  16. package/dist/ts/ws/client/node/ClientNode.js +7 -0
  17. package/dist/{ws → ts/ws}/debug/DebugServer.d.ts +5 -0
  18. package/dist/ts/ws/debug/DebugServer.js +7 -0
  19. package/dist/{ws → ts/ws}/packets/PacketType.d.ts +6 -1
  20. package/dist/ts/ws/packets/PacketType.js +7 -0
  21. package/dist/{ws → ts/ws}/packets/Packets.d.ts +5 -3
  22. package/dist/ts/ws/packets/Packets.js +7 -0
  23. package/dist/{ws → ts/ws}/server/SonicWSConnection.d.ts +5 -0
  24. package/dist/ts/ws/server/SonicWSConnection.js +7 -0
  25. package/dist/{ws → ts/ws}/server/SonicWSServer.d.ts +8 -0
  26. package/dist/ts/ws/server/SonicWSServer.js +7 -0
  27. package/dist/{ws → ts/ws}/util/BufferUtil.d.ts +5 -0
  28. package/dist/ts/ws/util/BufferUtil.js +7 -0
  29. package/dist/{ws → ts/ws}/util/StringUtil.d.ts +5 -2
  30. package/dist/ts/ws/util/StringUtil.js +7 -0
  31. package/dist/{ws → ts/ws}/util/enums/EnumHandler.d.ts +5 -0
  32. package/dist/ts/ws/util/enums/EnumHandler.js +7 -0
  33. package/dist/{ws → ts/ws}/util/enums/EnumType.d.ts +5 -0
  34. package/dist/ts/ws/util/enums/EnumType.js +7 -0
  35. package/dist/ts/ws/util/packets/BatchHelper.d.ts +6 -0
  36. package/dist/ts/ws/util/packets/BatchHelper.js +7 -0
  37. package/dist/ts/ws/util/packets/CompressionUtil.d.ts +13 -0
  38. package/dist/ts/ws/util/packets/CompressionUtil.js +7 -0
  39. package/dist/ts/ws/util/packets/HashUtil.d.ts +7 -0
  40. package/dist/ts/ws/util/packets/HashUtil.js +7 -0
  41. package/dist/ts/ws/util/packets/JSONUtil.d.ts +7 -0
  42. package/dist/ts/ws/util/packets/JSONUtil.js +7 -0
  43. package/dist/ts/ws/util/packets/PacketHolder.d.ts +6 -0
  44. package/dist/ts/ws/util/packets/PacketHolder.js +7 -0
  45. package/dist/{ws → ts/ws}/util/packets/PacketUtils.d.ts +5 -0
  46. package/dist/ts/ws/util/packets/PacketUtils.js +7 -0
  47. package/dist/ts/ws/util/packets/RateHandler.d.ts +6 -0
  48. package/dist/ts/ws/util/packets/RateHandler.js +7 -0
  49. package/package.json +14 -10
  50. package/dist/version.js +0 -25
  51. package/dist/ws/Connection.js +0 -126
  52. package/dist/ws/PacketProcessor.js +0 -52
  53. package/dist/ws/client/core/ClientCore.js +0 -251
  54. package/dist/ws/client/node/ClientNode.js +0 -36
  55. package/dist/ws/debug/DebugServer.js +0 -607
  56. package/dist/ws/packets/PacketProcessors.d.ts +0 -13
  57. package/dist/ws/packets/PacketProcessors.js +0 -317
  58. package/dist/ws/packets/PacketType.js +0 -61
  59. package/dist/ws/packets/Packets.js +0 -277
  60. package/dist/ws/server/SonicWSConnection.js +0 -298
  61. package/dist/ws/server/SonicWSServer.js +0 -307
  62. package/dist/ws/util/BufferUtil.js +0 -42
  63. package/dist/ws/util/StringUtil.js +0 -51
  64. package/dist/ws/util/enums/EnumHandler.js +0 -60
  65. package/dist/ws/util/enums/EnumType.js +0 -72
  66. package/dist/ws/util/packets/BatchHelper.d.ts +0 -1
  67. package/dist/ws/util/packets/BatchHelper.js +0 -85
  68. package/dist/ws/util/packets/CompressionUtil.d.ts +0 -35
  69. package/dist/ws/util/packets/CompressionUtil.js +0 -277
  70. package/dist/ws/util/packets/HashUtil.d.ts +0 -2
  71. package/dist/ws/util/packets/HashUtil.js +0 -122
  72. package/dist/ws/util/packets/JSONUtil.d.ts +0 -2
  73. package/dist/ws/util/packets/JSONUtil.js +0 -179
  74. package/dist/ws/util/packets/PacketHolder.d.ts +0 -1
  75. package/dist/ws/util/packets/PacketHolder.js +0 -126
  76. package/dist/ws/util/packets/PacketUtils.js +0 -283
  77. package/dist/ws/util/packets/RateHandler.d.ts +0 -1
  78. package/dist/ws/util/packets/RateHandler.js +0 -66
@@ -1,298 +0,0 @@
1
- "use strict";
2
- /*
3
- * Copyright 2026 Lily (liwybloc)
4
- *
5
- * Licensed under the Apache License, Version 2.0 (the "License");
6
- * you may not use this file except in compliance with the License.
7
- * You may obtain a copy of the License at
8
- *
9
- * http://www.apache.org/licenses/LICENSE-2.0
10
- *
11
- * Unless required by applicable law or agreed to in writing, software
12
- * distributed under the License is distributed on an "AS IS" BASIS,
13
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14
- * See the License for the specific language governing permissions and
15
- * limitations under the License.
16
- */
17
- Object.defineProperty(exports, "__esModule", { value: true });
18
- exports.SonicWSConnection = void 0;
19
- const PacketUtils_1 = require("../util/packets/PacketUtils");
20
- const BatchHelper_1 = require("../util/packets/BatchHelper");
21
- const RateHandler_1 = require("../util/packets/RateHandler");
22
- const BufferUtil_1 = require("../util/BufferUtil");
23
- const Connection_1 = require("../Connection");
24
- const CLIENT_RATELIMIT_TAG = "C", SERVER_RATELIMIT_TAG = "S";
25
- class SonicWSConnection extends Connection_1.Connection {
26
- host;
27
- print = false;
28
- handshakePacket;
29
- handshakeLambda;
30
- messageLambda = (data) => this.messageHandler(this.parseData(data));
31
- handshakedMessageLambda = (data) => {
32
- const parsed = this.parseData(data);
33
- if (parsed == null)
34
- return this.socket.close(Connection_1.CloseCodes.INVALID_DATA);
35
- if (parsed[0] == this.handshakePacket)
36
- return this.socket.close(Connection_1.CloseCodes.REPEATED_HANDSHAKE);
37
- this.messageHandler(parsed);
38
- };
39
- rater;
40
- enabledPackets = {};
41
- /** If the packet handshake has been completed; `wss.requireHandshake(packet)` */
42
- handshakeComplete = false;
43
- asyncMap = {};
44
- asyncData = {};
45
- constructor(socket, host, id, handshakePacket, clientRateLimit, serverRateLimit) {
46
- super(socket, id, "Socket " + id, socket.addEventListener.bind(socket), socket.removeEventListener.bind(socket));
47
- this.host = host;
48
- this.handshakePacket = handshakePacket;
49
- for (const pack of host.clientPackets.getPackets()) {
50
- const tag = pack.tag;
51
- this.listeners[tag] = [];
52
- pack.lastReceived[this.id] = undefined;
53
- this.enabledPackets[tag] = pack.defaultEnabled;
54
- this.asyncMap[tag] = pack.async;
55
- if (pack.async)
56
- this.asyncData[tag] = [false, []];
57
- }
58
- this.setInterval = this.setInterval.bind(this);
59
- this.batcher.registerSendPackets(this.host.serverPackets, this);
60
- this.invalidPacket = this.invalidPacket.bind(this);
61
- this.rater = new RateHandler_1.RateHandler(this);
62
- this.rater.registerRate(CLIENT_RATELIMIT_TAG, clientRateLimit);
63
- this.rater.registerRate(SERVER_RATELIMIT_TAG, serverRateLimit);
64
- this.rater.registerAll(host.clientPackets, "client");
65
- this.rater.registerAll(host.serverPackets, "server");
66
- this.rater.start();
67
- if (this.handshakePacket == null) {
68
- this.socket.addEventListener('message', this.messageLambda);
69
- }
70
- else {
71
- this.handshakeLambda = (data) => this.handshakeHandler(data);
72
- this.socket.addEventListener('message', this.handshakeLambda);
73
- }
74
- this.socket.on('close', () => {
75
- for (const packet of host.clientPackets.getPackets()) {
76
- delete packet.lastReceived[this.id];
77
- }
78
- for (const packet of host.serverPackets.getPackets()) {
79
- delete packet.lastSent[this.id];
80
- }
81
- });
82
- }
83
- parseData(event) {
84
- if (this.rater.trigger(CLIENT_RATELIMIT_TAG))
85
- return null;
86
- if (!(event.data instanceof Buffer))
87
- return null;
88
- const message = new Uint8Array(event.data);
89
- if (this.print)
90
- console.log(`\x1b[31m⬇ \x1b[38;5;245m(${this.id},${message.byteLength})\x1b[0m`, (message.length > 0 && this.host.clientPackets.getTag(message[0])) || "<INVALID>", (0, BufferUtil_1.stringifyBuffer)(message));
91
- if (message.byteLength < 1) {
92
- this.socket.close(Connection_1.CloseCodes.SMALL);
93
- return null;
94
- }
95
- const key = message[0];
96
- const value = message.slice(1);
97
- // not a key, bye bye
98
- if (!this.host.clientPackets.hasKey(key)) {
99
- this.socket.close(Connection_1.CloseCodes.INVALID_KEY);
100
- return null;
101
- }
102
- const tag = this.host.clientPackets.getTag(key);
103
- // disabled, bye bye
104
- if (!this.enabledPackets[tag]) {
105
- this.socket.close(Connection_1.CloseCodes.DISABLED_PACKET);
106
- return null;
107
- }
108
- if (this.rater.trigger("client" + key))
109
- return null;
110
- return [tag, value];
111
- }
112
- handshakeHandler(data) {
113
- const parsed = this.parseData(data);
114
- if (parsed == null)
115
- return this.socket.close(Connection_1.CloseCodes.INVALID_DATA);
116
- if (parsed[0] != this.handshakePacket) {
117
- this.socket.close(Connection_1.CloseCodes.INVALID_DATA);
118
- return;
119
- }
120
- this.messageHandler(parsed);
121
- this.socket.removeEventListener('message', this.handshakeLambda);
122
- this.socket.addEventListener('message', this.handshakedMessageLambda);
123
- this.handshakeComplete = true;
124
- }
125
- invalidPacket(listened) {
126
- console.log("Closure cause", listened);
127
- this.socket.close(Connection_1.CloseCodes.INVALID_PACKET, listened);
128
- }
129
- isAsync(tag) {
130
- return this.asyncMap[tag];
131
- }
132
- listenLock = false;
133
- packetQueue = [];
134
- async listenPacket(data, tag, packetQueue, isAsync, asyncData) {
135
- if (this.closed)
136
- return;
137
- await (0, PacketUtils_1.listenPacket)(data, this.listeners[tag], this.invalidPacket);
138
- await this.callMiddleware('onReceive_post', tag, typeof data == 'string' ? [data] : data[0]);
139
- if (isAsync)
140
- asyncData[0] = false;
141
- else
142
- this.listenLock = false;
143
- if (packetQueue.length != 0) {
144
- this.messageHandler(packetQueue.shift());
145
- return;
146
- }
147
- }
148
- async messageHandler(data, recall = false) {
149
- if (data == null)
150
- return;
151
- const [tag, value] = data;
152
- const isAsync = this.isAsync(tag);
153
- let locked, packetQueue, asyncData;
154
- if (isAsync) {
155
- asyncData = this.asyncData[tag];
156
- locked = asyncData[0];
157
- packetQueue = asyncData[1];
158
- }
159
- else {
160
- locked = this.listenLock;
161
- packetQueue = this.packetQueue;
162
- }
163
- if (locked) {
164
- packetQueue.push(data);
165
- return;
166
- }
167
- if (isAsync)
168
- asyncData[0] = true;
169
- else
170
- this.listenLock = true;
171
- const packet = this.host.clientPackets.getPacket(tag);
172
- if (!recall && await this.callMiddleware('onReceive_pre', packet.tag, value, value.length))
173
- return;
174
- if (packet.rereference && value.length == 0) {
175
- const lastRecv = packet.lastReceived[this.id];
176
- if (lastRecv === undefined)
177
- return this.invalidPacket("No previous value to rereference");
178
- await this.listenPacket(lastRecv, tag, packetQueue, isAsync, asyncData);
179
- return;
180
- }
181
- if (packet.dataBatching == 0) {
182
- const res = await packet.listen(value, this);
183
- packet.lastReceived[this.id] = res;
184
- await this.listenPacket(res, tag, packetQueue, isAsync, asyncData);
185
- return;
186
- }
187
- const batchData = await BatchHelper_1.BatchHelper.unravelBatch(packet, value, this);
188
- if (typeof batchData == 'string')
189
- return this.invalidPacket(batchData);
190
- for (const data of batchData) {
191
- if (isAsync)
192
- asyncData[0] = true;
193
- else
194
- this.listenLock = true;
195
- await this.listenPacket(data, tag, packetQueue, isAsync, asyncData);
196
- }
197
- }
198
- /**
199
- * Enables a packet for the client.
200
- * @param tag The tag of the packet
201
- */
202
- enablePacket(tag) {
203
- this.enabledPackets[tag] = true;
204
- }
205
- /**
206
- * Disables a packet for the client.
207
- * @param tag The tag of the packet
208
- */
209
- disablePacket(tag) {
210
- this.enabledPackets[tag] = false;
211
- }
212
- /**
213
- * Listens for when the connection closes
214
- * @param listener Called when it closes
215
- */
216
- on_close(listener) {
217
- this.socket.on('close', (code, reason) => listener(code, String(reason)));
218
- }
219
- /**
220
- * Listens for a packet
221
- * @param tag The tag of the key to listen for
222
- * @param listener A function to listen for it
223
- */
224
- on(tag, listener) {
225
- if (!this.host.clientPackets.hasTag(tag))
226
- throw new Error(`Tag "${String(tag)}" has not been created!`);
227
- this.listeners[tag] ??= [];
228
- this.listeners[tag].push(listener);
229
- }
230
- /**
231
- * For internal use.
232
- */
233
- send_processed(code, data, packet) {
234
- if (this.rater.trigger("server" + code))
235
- return;
236
- if (packet.dataBatching == 0)
237
- this.raw_send((0, BufferUtil_1.toPacketBuffer)(code, data));
238
- else
239
- this.batcher.batchPacket(code, data);
240
- }
241
- sendQueue = [false, [], undefined];
242
- /**
243
- * Sends a packet with the tag and values
244
- * @param tag The tag to send
245
- * @param values The values to send
246
- */
247
- async send(tag, ...values) {
248
- if (await this.callMiddleware('onSend_pre', tag, values, Date.now(), performance.now()))
249
- return;
250
- const [code, data, packet] = await (0, PacketUtils_1.processPacket)(this.host.serverPackets, tag, values, this.sendQueue, this.id);
251
- if (await this.callMiddleware('onSend_post', tag, data, data.length))
252
- return;
253
- this.send_processed(code, data, packet);
254
- }
255
- /**
256
- * Broadcasts a packet to all other users connected
257
- * @param tag The tag to send
258
- * @param values The values to send
259
- */
260
- broadcastFiltered(tag, filter, ...values) {
261
- this.host.broadcastFiltered(tag, (socket) => socket != this && filter(socket), ...values);
262
- }
263
- /**
264
- * Broadcasts a packet to all other users connected
265
- * @param tag The tag to send
266
- * @param values The values to send
267
- */
268
- broadcast(tag, ...values) {
269
- this.broadcastFiltered(tag, () => true, ...values);
270
- }
271
- /**
272
- * Toggles printing all sent and received messages
273
- */
274
- togglePrint() {
275
- this.print = !this.print;
276
- }
277
- /* JSDocs in Connection.ts class */
278
- raw_send(data) {
279
- if (this.isClosed()) {
280
- console.warn("WARN! Connection already closed when trying to send message!", this.id, (0, BufferUtil_1.stringifyBuffer)(data));
281
- return;
282
- }
283
- if (this.rater.trigger(SERVER_RATELIMIT_TAG))
284
- return;
285
- if (this.print)
286
- console.log(`\x1b[32m⬆ \x1b[38;5;245m(${this.id},${data.byteLength})\x1b[0m`, (data.length > 0 && this.host.serverPackets.getTag(data[0])) || "<INVALID>", (0, BufferUtil_1.stringifyBuffer)(data));
287
- super.raw_send(data);
288
- }
289
- /**
290
- * Tags the socket with a key
291
- * @param tag The tag to add
292
- * @param replace If it should replace a previous tag; defaults to true. If using false, you can add multiple tags.
293
- */
294
- tag(tag, replace = true) {
295
- this.host.tag(this, tag, replace);
296
- }
297
- }
298
- exports.SonicWSConnection = SonicWSConnection;
@@ -1,307 +0,0 @@
1
- "use strict";
2
- /*
3
- * Copyright 2026 Lily (liwybloc)
4
- *
5
- * Licensed under the Apache License, Version 2.0 (the "License");
6
- * you may not use this file except in compliance with the License.
7
- * You may obtain a copy of the License at
8
- *
9
- * http://www.apache.org/licenses/LICENSE-2.0
10
- *
11
- * Unless required by applicable law or agreed to in writing, software
12
- * distributed under the License is distributed on an "AS IS" BASIS,
13
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14
- * See the License for the specific language governing permissions and
15
- * limitations under the License.
16
- */
17
- var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
18
- if (k2 === undefined) k2 = k;
19
- var desc = Object.getOwnPropertyDescriptor(m, k);
20
- if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
21
- desc = { enumerable: true, get: function() { return m[k]; } };
22
- }
23
- Object.defineProperty(o, k2, desc);
24
- }) : (function(o, m, k, k2) {
25
- if (k2 === undefined) k2 = k;
26
- o[k2] = m[k];
27
- }));
28
- var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
29
- Object.defineProperty(o, "default", { enumerable: true, value: v });
30
- }) : function(o, v) {
31
- o["default"] = v;
32
- });
33
- var __importStar = (this && this.__importStar) || (function () {
34
- var ownKeys = function(o) {
35
- ownKeys = Object.getOwnPropertyNames || function (o) {
36
- var ar = [];
37
- for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
38
- return ar;
39
- };
40
- return ownKeys(o);
41
- };
42
- return function (mod) {
43
- if (mod && mod.__esModule) return mod;
44
- var result = {};
45
- if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
46
- __setModuleDefault(result, mod);
47
- return result;
48
- };
49
- })();
50
- Object.defineProperty(exports, "__esModule", { value: true });
51
- exports.SonicWSServer = void 0;
52
- const WS = __importStar(require("ws"));
53
- const SonicWSConnection_1 = require("./SonicWSConnection");
54
- const PacketHolder_1 = require("../util/packets/PacketHolder");
55
- const CompressionUtil_1 = require("../util/packets/CompressionUtil");
56
- const version_1 = require("../../version");
57
- const PacketUtils_1 = require("../util/packets/PacketUtils");
58
- const PacketProcessor_1 = require("../PacketProcessor");
59
- const HashUtil_1 = require("../util/packets/HashUtil");
60
- const Connection_1 = require("../Connection");
61
- const DebugServer_1 = require("../debug/DebugServer");
62
- class SonicWSServer extends PacketProcessor_1.MiddlewareHolder {
63
- wss;
64
- availableIds = [];
65
- lastId = 0;
66
- connectListeners = [];
67
- clientPackets;
68
- serverPackets;
69
- connections = [];
70
- connectionMap = {};
71
- clientRateLimit = 500;
72
- serverRateLimit = 500;
73
- handshakePacket = null;
74
- tags = new Map();
75
- tagsInv = new Map();
76
- serverwideSendQueue = [false, [], undefined];
77
- /**
78
- * Initializes and hosts a websocket with sonic protocol
79
- * Rate limits can be set with wss.setClientRateLimit(x) and wss.setServerRateLimit(x); it is defaulted at 500/second per both
80
- * @param settings Sonic Server Options such as schema data for client and server packets, alongside websocket options
81
- */
82
- constructor(settings) {
83
- super();
84
- const { clientPackets = [], serverPackets = [], websocketOptions = {} } = settings;
85
- this.wss = new WS.WebSocketServer(websocketOptions);
86
- this.clientPackets = new PacketHolder_1.PacketHolder(clientPackets);
87
- this.serverPackets = new PacketHolder_1.PacketHolder(serverPackets);
88
- const s_clientPackets = this.clientPackets.serialize();
89
- const s_serverPackets = this.serverPackets.serialize();
90
- const serverData = [...version_1.SERVER_SUFFIX_NUMS, version_1.VERSION];
91
- const keyData = [...(0, CompressionUtil_1.convertVarInt)(s_clientPackets.length), ...s_clientPackets, ...s_serverPackets];
92
- (0, HashUtil_1.setHashFunc)(settings.sonicServerSettings?.bit64Hash ?? true);
93
- this.wss.on('connection', async (socket) => {
94
- const sonicConnection = new SonicWSConnection_1.SonicWSConnection(socket, this, this.generateSocketID(), this.handshakePacket, this.clientRateLimit, this.serverRateLimit);
95
- if (await this.callMiddleware("onClientConnect", sonicConnection)) {
96
- sonicConnection.close(Connection_1.CloseCodes.MIDDLEWARE, "Connection blocked by middleware.");
97
- this.callMiddleware("onClientDisconnect", sonicConnection, Connection_1.CloseCodes.MIDDLEWARE, Buffer.from("Connection blocked by middleware."));
98
- this.availableIds.push(sonicConnection.id);
99
- return;
100
- }
101
- // send tags to the client so it doesn't have to hard code them in
102
- const data = new Uint8Array([...(0, CompressionUtil_1.convertVarInt)(sonicConnection.id), ...keyData]);
103
- socket.send([...serverData, ...await (0, CompressionUtil_1.compressGzip)(data)]);
104
- this.connections.push(sonicConnection);
105
- this.connectionMap[sonicConnection.id] = sonicConnection;
106
- this.connectListeners.forEach(l => l(sonicConnection));
107
- socket.on('close', (code, reason) => {
108
- this.connections.splice(this.connections.indexOf(sonicConnection), 1);
109
- delete this.connectionMap[sonicConnection.id];
110
- this.availableIds.push(sonicConnection.id);
111
- if (this.tags.has(sonicConnection)) {
112
- for (const tag of this.tags.get(sonicConnection))
113
- this.tagsInv.get(tag)?.delete(sonicConnection);
114
- this.tags.delete(sonicConnection);
115
- }
116
- this.callMiddleware("onClientDisconnect", sonicConnection, code, reason);
117
- });
118
- });
119
- if (settings.sonicServerSettings?.checkForUpdates ?? true) {
120
- fetch('https://raw.githubusercontent.com/liwybloc/sonic-ws/refs/heads/main/release/version')
121
- .then((res) => res.text())
122
- .then((ver) => {
123
- if (parseInt(ver) > version_1.VERSION) {
124
- console.warn(`SonicWS is currently running outdated! (current: ${version_1.VERSION}, latest: ${ver}) Update with "npm update sonic-ws"`);
125
- }
126
- })
127
- .catch((err) => {
128
- console.error(err);
129
- console.warn(`Could not check SonicWS version.`);
130
- });
131
- }
132
- }
133
- generateSocketID() {
134
- if (this.availableIds.length == 0)
135
- this.availableIds.push(this.lastId + 1);
136
- this.lastId = this.availableIds.shift();
137
- return this.lastId;
138
- }
139
- /**
140
- * Requires each client to send this packet upon initialization
141
- *
142
- * Recreates this:
143
- * ```js
144
- * let initiated = false;
145
- * socket.on('init', () => {
146
- * if(initiated) return socket.close();
147
- * initiated = true;
148
- * // process
149
- * });
150
- *
151
- * socket.on('otherPacket', () => {
152
- * if(!initiated) return socket.close();
153
- * // process
154
- * })
155
- * ```
156
- *
157
- * @param packet The tag of the packet to require as a handshake
158
- */
159
- requireHandshake(packet) {
160
- if (!this.clientPackets.hasTag(packet))
161
- throw new Error(`The client does not send "${packet}" and so it cannot use it as a handshake!`);
162
- if (this.clientPackets.getPacket(packet).dataBatching != 0)
163
- throw new Error(`The packet "${packet}" is a batched packet, and cannot be used as a handshake!`);
164
- this.handshakePacket = packet;
165
- }
166
- /**
167
- * Sets the rate limit for all client-side packets
168
- * @param limit Amount of packets the sockets can send every second, or 0 for infinite
169
- */
170
- setClientRateLimit(limit) {
171
- // so that i can store limits in 1 packet
172
- if (limit > CompressionUtil_1.MAX_BYTE) {
173
- limit = 0;
174
- console.warn(`A rate limit above ${CompressionUtil_1.MAX_BYTE} is considered infinite.`);
175
- }
176
- this.clientRateLimit = limit;
177
- }
178
- /**
179
- * Sets the rate limit for server-side packets per-socket
180
- * @param limit Amount of packets the server can send every second, or 0 for infinite
181
- */
182
- setServerRateLimit(limit) {
183
- // so that i can store limits in 1 packet
184
- if (limit > CompressionUtil_1.MAX_BYTE) {
185
- limit = 0;
186
- console.warn(`A rate limit above ${CompressionUtil_1.MAX_BYTE} is considered infinite.`);
187
- }
188
- this.serverRateLimit = limit;
189
- }
190
- /**
191
- * Enables a packet for all current & new clients.
192
- * @param tag The tag of the packet
193
- */
194
- enablePacket(tag) {
195
- this.clientPackets.getPacket(tag).defaultEnabled = true;
196
- this.connections.forEach(socket => socket.enablePacket(tag));
197
- }
198
- /**
199
- * Disables a packet for all current & new clients.
200
- * @param tag The tag of the packet
201
- */
202
- disablePacket(tag) {
203
- this.clientPackets.getPacket(tag).defaultEnabled = false;
204
- this.connections.forEach(socket => socket.disablePacket(tag));
205
- }
206
- /**
207
- * Listens for whenever a client connects
208
- * @param runner Called when ready
209
- */
210
- on_connect(runner) {
211
- this.connectListeners.push(runner);
212
- }
213
- /**
214
- * Listens for whenever the server is ready
215
- * @param runner Called when ready
216
- */
217
- on_ready(runner) {
218
- this.wss.on('listening', runner);
219
- }
220
- /**
221
- * Closes the server
222
- * @param callback Called when server closes
223
- */
224
- shutdown(callback) {
225
- this.wss.close(callback);
226
- }
227
- async broadcastInternal(packetTag, target, values) {
228
- let recipients;
229
- if (target.type === "all") {
230
- recipients = this.connections;
231
- }
232
- else if (target.type === "tagged") {
233
- if (!this.tagsInv.has(target.tag))
234
- return;
235
- recipients = Array.from(this.tagsInv.get(target.tag));
236
- }
237
- else {
238
- recipients = this.connections.filter(target.filter);
239
- }
240
- if (await this.callMiddleware("onPacketBroadcast_pre", packetTag, { recipients, ...target }, values))
241
- return;
242
- if (recipients.length === 0)
243
- return;
244
- const [code, data, packet] = await (0, PacketUtils_1.processPacket)(this.serverPackets, packetTag, values, this.serverwideSendQueue, -1);
245
- if (await this.callMiddleware("onPacketBroadcast_post", packetTag, { recipients, ...target }, data, data.length))
246
- return;
247
- recipients.forEach(conn => conn.send_processed(code, data, packet));
248
- }
249
- async broadcastTagged(tag, packetTag, ...values) {
250
- await this.broadcastInternal(packetTag, { type: "tagged", tag }, values);
251
- }
252
- async broadcastFiltered(tag, filter, ...values) {
253
- await this.broadcastInternal(tag, { type: "filter", filter }, values);
254
- }
255
- async broadcast(tag, ...values) {
256
- await this.broadcastInternal(tag, { type: "all" }, values);
257
- }
258
- /**
259
- * @returns All users connected to the socket
260
- */
261
- getConnected() {
262
- return this.connections;
263
- }
264
- /**
265
- * @param id The socket id
266
- * @returns The socket
267
- */
268
- getSocket(id) {
269
- return this.connectionMap[id];
270
- }
271
- /**
272
- * Closes a socket by id
273
- * @param id The socket id
274
- */
275
- closeSocket(id, code = 1000, reason) {
276
- this.getSocket(id).close(code, reason);
277
- }
278
- /**
279
- * Tags the socket with a key
280
- * @param socket The socket to tag
281
- * @param tag The tag to add
282
- * @param replace If it should replace a previous tag; defaults to true. If using false, you can add multiple tags.
283
- */
284
- tag(socket, tag, replace = true) {
285
- if (!this.tags.get(socket))
286
- this.tags.set(socket, new Set());
287
- if (!this.tagsInv.get(tag))
288
- this.tagsInv.set(tag, new Set());
289
- if (replace) {
290
- this.tags.get(socket).forEach(v => this.tagsInv.get(v)?.delete(socket));
291
- }
292
- this.tags.get(socket).add(tag);
293
- this.tagsInv.get(tag).add(socket);
294
- }
295
- debugServer = null;
296
- /**
297
- * Opens a debug menu; this launches the browser and starts a subserver
298
- * @param port Port of the server/http, defaults to 0 which finds an open port
299
- * @param password Toggles the requirement of a password to access the server. Defaults to empty, which doesn't ask for a password.
300
- */
301
- OpenDebug(data = {}) {
302
- if (this.debugServer != null)
303
- throw new Error("Attempted to open a debug server when one has already been opened.");
304
- this.debugServer = new DebugServer_1.DebugServer(this, data);
305
- }
306
- }
307
- exports.SonicWSServer = SonicWSServer;
@@ -1,42 +0,0 @@
1
- "use strict";
2
- /*
3
- * Copyright 2026 Lily (liwybloc)
4
- *
5
- * Licensed under the Apache License, Version 2.0 (the "License");
6
- * you may not use this file except in compliance with the License.
7
- * You may obtain a copy of the License at
8
- *
9
- * http://www.apache.org/licenses/LICENSE-2.0
10
- *
11
- * Unless required by applicable law or agreed to in writing, software
12
- * distributed under the License is distributed on an "AS IS" BASIS,
13
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14
- * See the License for the specific language governing permissions and
15
- * limitations under the License.
16
- */
17
- Object.defineProperty(exports, "__esModule", { value: true });
18
- exports.splitArray = splitArray;
19
- exports.toPacketBuffer = toPacketBuffer;
20
- exports.splitBuffer = splitBuffer;
21
- exports.stringifyBuffer = stringifyBuffer;
22
- function splitArray(arr, size) {
23
- const result = [];
24
- for (let i = 0; i < arr.length; i += size) {
25
- const chunk = arr.slice(i, i + size);
26
- result.push(chunk);
27
- }
28
- return result;
29
- }
30
- function toPacketBuffer(code, data) {
31
- const buffer = new Uint8Array(1 + data.length);
32
- buffer[0] = code;
33
- buffer.set(data, 1);
34
- return buffer;
35
- }
36
- function splitBuffer(arr, x) {
37
- return splitArray(Array.from(arr), x);
38
- }
39
- function stringifyBuffer(data) {
40
- const contents = Array.from(data).map(n => n.toString(16).padStart(2, "0")).join(" ");
41
- return `<Buffer ${contents}>`;
42
- }