sonic-ws 1.0.0-rc.7 → 1.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 (40) hide show
  1. package/README.md +19 -11
  2. package/dist/index.js +1 -1
  3. package/dist/version.d.ts +5 -3
  4. package/dist/version.js +8 -5
  5. package/dist/ws/Connection.d.ts +19 -0
  6. package/dist/ws/Connection.js +17 -0
  7. package/dist/ws/client/core/ClientCore.d.ts +27 -9
  8. package/dist/ws/client/core/ClientCore.js +162 -64
  9. package/dist/ws/client/node/ClientNode.js +2 -2
  10. package/dist/ws/packets/PacketProcessors.d.ts +11 -6
  11. package/dist/ws/packets/PacketProcessors.js +233 -175
  12. package/dist/ws/packets/PacketType.d.ts +30 -16
  13. package/dist/ws/packets/PacketType.js +31 -17
  14. package/dist/ws/packets/Packets.d.ts +15 -14
  15. package/dist/ws/packets/Packets.js +117 -99
  16. package/dist/ws/server/SonicWSConnection.d.ts +30 -8
  17. package/dist/ws/server/SonicWSConnection.js +67 -25
  18. package/dist/ws/server/SonicWSServer.d.ts +22 -0
  19. package/dist/ws/server/SonicWSServer.js +50 -8
  20. package/dist/ws/util/ArrayUtil.js +1 -1
  21. package/dist/ws/util/BufferUtil.d.ts +4 -0
  22. package/dist/ws/util/BufferUtil.js +40 -0
  23. package/dist/ws/util/StringUtil.d.ts +6 -0
  24. package/dist/ws/util/StringUtil.js +66 -0
  25. package/dist/ws/util/enums/EnumHandler.d.ts +2 -3
  26. package/dist/ws/util/enums/EnumHandler.js +4 -7
  27. package/dist/ws/util/enums/EnumType.d.ts +3 -2
  28. package/dist/ws/util/enums/EnumType.js +21 -10
  29. package/dist/ws/util/packets/BatchHelper.d.ts +10 -6
  30. package/dist/ws/util/packets/BatchHelper.js +28 -16
  31. package/dist/ws/util/packets/CompressionUtil.d.ts +44 -0
  32. package/dist/ws/util/packets/CompressionUtil.js +321 -0
  33. package/dist/ws/util/packets/PacketHolder.d.ts +5 -10
  34. package/dist/ws/util/packets/PacketHolder.js +25 -13
  35. package/dist/ws/util/packets/PacketUtils.d.ts +11 -8
  36. package/dist/ws/util/packets/PacketUtils.js +31 -26
  37. package/dist/ws/util/packets/RateHandler.js +16 -1
  38. package/package.json +2 -2
  39. package/dist/ws/util/packets/CodePointUtil.d.ts +0 -22
  40. package/dist/ws/util/packets/CodePointUtil.js +0 -220
package/README.md CHANGED
@@ -7,17 +7,19 @@ SonicWS is an ultra-lightweight, high-performance WebSocket library focused on m
7
7
  Compression:
8
8
  - Lossless compression up to 70% or more (for example, 38kb -> 14kb)
9
9
  - Optimized bandwidth for many different types to fit special constraints
10
- - Automatic helpers to flatten nested arrays for maximum wire efficiency
10
+ - Automatic helpers to flatten typed nested arrays for maximum wire efficiency (for example, [[1,2,3],[4,5,6]] to [[1,4],[2,5],[3,6]])
11
+ - Uses raw binary bytes to transmit data as efficiently as possible while still using high level readable code
11
12
 
12
13
  Developer Friendly:
13
14
  - Predefined data types of various sized integers, decimals, strings, enums, etc. and RAW for any special cases
14
- - Keys are automatically indexed before transfer, improving readability (for example, send("pixel") and send("p") become identical)
15
+ - Keys are automatically indexed before transfer, improving readability and efficiency (for example, send("pixel") and send("p") use the same bandwidth)
15
16
  - Data is validated and supports custom validation, ensuring only valid, safe, and untampered packets ever call your listeners
16
17
 
17
18
  Security:
18
- - Tamper-proof; any invalid packet instantly causes closure, and tampering is very likely to as well
19
- - Built-in ability for handshake packets, preventing constant if(!init) checks and null checks in every listener
19
+ - Tamper-proof; any invalid packet instantly causes closure, and tampering becomes incredibly difficult
20
+ - Built-in ability for handshake packets, preventing repetitive initiation checks in listeners (for example, removes if(!init) everywhere)
20
21
  - Built-in rate limiting for packets; ability for global send & receive, alongside per-packet rate limiting
22
+ - Built-in disabling & enabling of packets to prevent abuse
21
23
 
22
24
  Performance & Scaling:
23
25
  - Can handle very large packets in microseconds
@@ -27,9 +29,11 @@ Performance & Scaling:
27
29
 
28
30
  Developer Experience:
29
31
  - Minimal boilerplate code due to listeners only receiving valid data
30
- - Enums can map to any primitive value, such as numbers, strings, null, etc. in 1 byte
32
+ - Enums can map to any primitive value (e.g. number, string, boolean, null) and transmits in 1 byte
31
33
  - Timers and intervals for sockets that automatically clear upon closure
34
+ - Many data types to maximize speed, clarity, bandwidth, and security
32
35
  - Debug tools for socket ids, byte size, data logging, etc. for troubleshooting
36
+ - Very minimal learning curve, easy to work in
33
37
  - JSDoc's for understanding
34
38
 
35
39
  Whether you're making a real-time game, a dashboard, a distributed system, or anything else, SonicWS gets you safe, structured packets, fast.
@@ -51,11 +55,11 @@ Browser (Client):
51
55
  ```js
52
56
  const wss = new SonicWSServer({
53
57
  clientPackets: [
54
- CreatePacket({tag: "pong", type: PacketType.INTS_D, dataMax: 1})
58
+ CreatePacket({tag: "pong", type: PacketType.VARINT, dataMax: 1})
55
59
  ],
56
60
  serverPackets: [
57
- CreatePacket({tag: "ping", type: PacketType.INTS_D, dataMax: 1}),
58
- CreateObjPacket({tag: "data", types: [PacketType.INTS_A, PacketTypes.STRING], dataMaxes: [2, 3]})
61
+ CreatePacket({tag: "ping", type: PacketType.VARINT, dataMax: 1}),
62
+ CreateObjPacket({tag: "data", types: [PacketType.BYTES, PacketTypes.STRINGS], dataMaxes: [2, 3]})
59
63
  ],
60
64
  websocketOptions: { port: 1234 }
61
65
  });
@@ -66,10 +70,10 @@ wss.on_connect((socket) => {
66
70
 
67
71
  socket.on("pong", (num) => {
68
72
  console.log("Ponged!", num);
69
- socket.send("data", [Math.floor(Math.random() * 1000), Math.floor(Math.random() * 1000)], ["hello", "from", "server"]);
73
+ socket.send("data", [Math.floor(Math.random() * 26), Math.floor(Math.random() * 256)], ["hello", "from", "server"]);
70
74
  });
71
75
 
72
- setInterval(() => {
76
+ socket.setInterval(() => {
73
77
  socket.send("ping", Date.now());
74
78
  }, 10000);
75
79
 
@@ -106,6 +110,10 @@ ws.on_close((event) => {
106
110
 
107
111
  Batch rate limit is off by 1
108
112
 
113
+ Varint max is off by a bit
114
+
109
115
  ## PLANNED FEATURES
110
116
 
111
- More data checking and better error handling
117
+ More data checking and better error handling
118
+
119
+ Implement a better system for data min/max
package/dist/index.js CHANGED
@@ -1,6 +1,6 @@
1
1
  "use strict";
2
2
  /*
3
- * Copyright 2025 Lily (cutelittlelily)
3
+ * Copyright 2025 Lily (liwybloc)
4
4
  *
5
5
  * Licensed under the Apache License, Version 2.0 (the "License");
6
6
  * you may not use this file except in compliance with the License.
package/dist/version.d.ts CHANGED
@@ -1,4 +1,6 @@
1
1
  /** Current protocol version */
2
- export declare const VERSION = 8;
3
- /** Current protocol version as a character */
4
- export declare const VERSION_CHAR: string;
2
+ export declare const VERSION = 9;
3
+ /** Server data suffix */
4
+ export declare const SERVER_SUFFIX = "SWS";
5
+ /** Server data suffix in array */
6
+ export declare const SERVER_SUFFIX_NUMS: number[];
package/dist/version.js CHANGED
@@ -1,6 +1,6 @@
1
1
  "use strict";
2
2
  /*
3
- * Copyright 2025 Lily (cutelittlelily)
3
+ * Copyright 2025 Lily (liwybloc)
4
4
  *
5
5
  * Licensed under the Apache License, Version 2.0 (the "License");
6
6
  * you may not use this file except in compliance with the License.
@@ -15,8 +15,11 @@
15
15
  * limitations under the License.
16
16
  */
17
17
  Object.defineProperty(exports, "__esModule", { value: true });
18
- exports.VERSION_CHAR = exports.VERSION = void 0;
18
+ exports.SERVER_SUFFIX_NUMS = exports.SERVER_SUFFIX = exports.VERSION = void 0;
19
+ var StringUtil_1 = require("./ws/util/StringUtil");
19
20
  /** Current protocol version */
20
- exports.VERSION = 8;
21
- /** Current protocol version as a character */
22
- exports.VERSION_CHAR = String.fromCharCode(exports.VERSION);
21
+ exports.VERSION = 9;
22
+ /** Server data suffix */
23
+ exports.SERVER_SUFFIX = "SWS";
24
+ /** Server data suffix in array */
25
+ exports.SERVER_SUFFIX_NUMS = (0, StringUtil_1.processCharCodes)(exports.SERVER_SUFFIX);
@@ -0,0 +1,19 @@
1
+ export interface Connection {
2
+ timers: Record<number, number>;
3
+ /** Sets an auto closing timer on the connection. Use connection.clearTimeout to prevent memory waste. */
4
+ setTimeout(call: () => void, time: number): number;
5
+ /** Sets an auto closing interval on the connection. Use connection.clearInterval to prevent memory waste. */
6
+ setInterval(call: () => void, time: number): number;
7
+ /** Safely clears a timer */
8
+ clearTimeout(index: number): void;
9
+ /** Safely clears an interval */
10
+ clearInterval(index: number): void;
11
+ /**
12
+ * Sends the uint8array through the connection
13
+ */
14
+ raw_send(data: Uint8Array): void;
15
+ /**
16
+ * Closes the connection
17
+ */
18
+ close(code?: number, reason?: string): void;
19
+ }
@@ -0,0 +1,17 @@
1
+ "use strict";
2
+ /*
3
+ * Copyright 2025 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 });
@@ -1,12 +1,13 @@
1
1
  import { PacketHolder } from '../../util/packets/PacketHolder';
2
- export declare abstract class SonicWSCore {
2
+ import { Connection } from '../../Connection';
3
+ export declare abstract class SonicWSCore implements Connection {
3
4
  /** Raw 'ws' library connection / webjs WebSocket class */
4
5
  socket: WebSocket;
5
6
  protected listeners: {
6
- message: Array<(data: string) => void>;
7
+ message: Array<(data: Uint8Array) => void>;
7
8
  close: Array<(event: CloseEvent) => void>;
8
9
  event: {
9
- [key: string]: Array<(...data: any[]) => void>;
10
+ [key: number]: Array<(...data: any[]) => void>;
10
11
  };
11
12
  };
12
13
  protected preListen: {
@@ -16,12 +17,12 @@ export declare abstract class SonicWSCore {
16
17
  protected serverPackets: PacketHolder;
17
18
  private pastKeys;
18
19
  private readyListeners;
19
- private keyHandler;
20
- private sendQueue;
21
- private timers;
22
20
  private batcher;
21
+ private bufferHandler;
23
22
  id: number;
24
- constructor(ws: WebSocket);
23
+ timers: Record<number, number>;
24
+ constructor(ws: WebSocket, bufferHandler: (val: MessageEvent) => Promise<Uint8Array>);
25
+ private reading;
25
26
  private serverKeyHandler;
26
27
  private invalidPacket;
27
28
  private listenPacket;
@@ -31,11 +32,11 @@ export declare abstract class SonicWSCore {
31
32
  * Listens for all messages rawly
32
33
  * @param listener Callback for when data is received
33
34
  */
34
- raw_onmessage(listener: (data: string) => void): void;
35
+ raw_onmessage(listener: (data: Uint8Array) => void): void;
35
36
  /**
36
37
  * Sends raw data
37
38
  */
38
- raw_send(data: string): void;
39
+ raw_send(data: Uint8Array): void;
39
40
  /**
40
41
  * Sends a packet to the server
41
42
  * @param tag The tag of the packet
@@ -58,16 +59,33 @@ export declare abstract class SonicWSCore {
58
59
  * @param listener The callback with the values
59
60
  */
60
61
  on(tag: string, listener: (value: any[]) => void): void;
62
+ private setTimer;
61
63
  /**
62
64
  * Sets a timeout that will automatically end when the socket closes
63
65
  * @param call The function to call
64
66
  * @param time The time between now and the call (ms)
67
+ * @returns The timeout id to be used with socket.clearInterval(id)
65
68
  */
66
69
  setTimeout(call: () => void, time: number): number;
67
70
  /**
68
71
  * Sets an interval that will automatically end when the socket closes
69
72
  * @param call The function to call
70
73
  * @param time The time between calls (ms)
74
+ * @returns The interval id to be used with socket.clearInterval(id)
71
75
  */
72
76
  setInterval(call: () => void, time: number): number;
77
+ /**
78
+ * Clears a timeout
79
+ * @param id The timeout id
80
+ */
81
+ clearTimeout(id: number): void;
82
+ /**
83
+ * Clears an interval
84
+ * @param id The interval id
85
+ */
86
+ clearInterval(id: number): void;
87
+ /**
88
+ * Closes the connection
89
+ */
90
+ close(code?: number, reason?: string): void;
73
91
  }
@@ -1,6 +1,6 @@
1
1
  "use strict";
2
2
  /*
3
- * Copyright 2025 Lily (cutelittlelily)
3
+ * Copyright 2025 Lily (liwybloc)
4
4
  *
5
5
  * Licensed under the Apache License, Version 2.0 (the "License");
6
6
  * you may not use this file except in compliance with the License.
@@ -14,26 +14,61 @@
14
14
  * See the License for the specific language governing permissions and
15
15
  * limitations under the License.
16
16
  */
17
+ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
18
+ function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
19
+ return new (P || (P = Promise))(function (resolve, reject) {
20
+ function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
21
+ function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
22
+ function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
23
+ step((generator = generator.apply(thisArg, _arguments || [])).next());
24
+ });
25
+ };
26
+ var __generator = (this && this.__generator) || function (thisArg, body) {
27
+ var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g = Object.create((typeof Iterator === "function" ? Iterator : Object).prototype);
28
+ return g.next = verb(0), g["throw"] = verb(1), g["return"] = verb(2), typeof Symbol === "function" && (g[Symbol.iterator] = function() { return this; }), g;
29
+ function verb(n) { return function (v) { return step([n, v]); }; }
30
+ function step(op) {
31
+ if (f) throw new TypeError("Generator is already executing.");
32
+ while (g && (g = 0, op[0] && (_ = 0)), _) try {
33
+ if (f = 1, y && (t = op[0] & 2 ? y["return"] : op[0] ? y["throw"] || ((t = y["return"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t;
34
+ if (y = 0, t) op = [op[0] & 2, t.value];
35
+ switch (op[0]) {
36
+ case 0: case 1: t = op; break;
37
+ case 4: _.label++; return { value: op[1], done: false };
38
+ case 5: _.label++; y = op[1]; op = [0]; continue;
39
+ case 7: op = _.ops.pop(); _.trys.pop(); continue;
40
+ default:
41
+ if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; }
42
+ if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; }
43
+ if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; }
44
+ if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; }
45
+ if (t[2]) _.ops.pop();
46
+ _.trys.pop(); continue;
47
+ }
48
+ op = body.call(thisArg, _);
49
+ } catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; }
50
+ if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true };
51
+ }
52
+ };
17
53
  Object.defineProperty(exports, "__esModule", { value: true });
18
54
  exports.SonicWSCore = void 0;
19
55
  var PacketHolder_1 = require("../../util/packets/PacketHolder");
20
- var CodePointUtil_1 = require("../../util/packets/CodePointUtil");
56
+ var CompressionUtil_1 = require("../../util/packets/CompressionUtil");
21
57
  var PacketUtils_1 = require("../../util/packets/PacketUtils");
22
58
  var version_1 = require("../../../version");
23
59
  var Packets_1 = require("../../packets/Packets");
24
60
  var BatchHelper_1 = require("../../util/packets/BatchHelper");
25
- // throttle at 90% of rate limit to avoid spikes and kicks
26
- var THRESHOLD_MULT = 0.90;
61
+ var BufferUtil_1 = require("../../util/BufferUtil");
27
62
  var SonicWSCore = /** @class */ (function () {
28
- function SonicWSCore(ws) {
63
+ function SonicWSCore(ws, bufferHandler) {
29
64
  var _this = this;
30
65
  this.clientPackets = new PacketHolder_1.PacketHolder();
31
66
  this.serverPackets = new PacketHolder_1.PacketHolder();
32
67
  this.pastKeys = false;
33
68
  this.readyListeners = [];
34
- this.sendQueue = [];
35
- this.timers = [];
36
69
  this.id = -1;
70
+ this.timers = {};
71
+ this.reading = false;
37
72
  this.socket = ws;
38
73
  this.listeners = {
39
74
  message: [],
@@ -43,74 +78,107 @@ var SonicWSCore = /** @class */ (function () {
43
78
  this.preListen = {};
44
79
  this.batcher = new BatchHelper_1.BatchHelper();
45
80
  this.invalidPacket = this.invalidPacket.bind(this);
46
- this.keyHandler = function (event) { return _this.serverKeyHandler(event); };
47
- this.socket.addEventListener('message', this.keyHandler); // lambda to persist 'this'
81
+ this.serverKeyHandler = this.serverKeyHandler.bind(this);
82
+ this.messageHandler = this.messageHandler.bind(this);
83
+ this.socket.addEventListener('message', this.serverKeyHandler);
48
84
  this.socket.addEventListener('close', function (event) {
49
85
  _this.listeners.close.forEach(function (listener) { return listener(event); });
50
- _this.timers.forEach(clearTimeout);
86
+ Object.values(_this.timers).forEach(clearTimeout);
51
87
  });
88
+ this.bufferHandler = bufferHandler;
52
89
  }
53
90
  SonicWSCore.prototype.serverKeyHandler = function (event) {
54
- var _this = this;
55
- var data = event.data.toString();
56
- if (!data.startsWith("SWS")) {
57
- this.socket.close(1000);
58
- throw new Error("The server requested is not a Sonic WS server.");
59
- }
60
- var version = data.charCodeAt(3);
61
- if (version != version_1.VERSION) {
62
- this.socket.close(1000);
63
- throw new Error("Version mismatch: ".concat(version > version_1.VERSION ? "client" : "server", " is outdated (server: ").concat(version, ", client: ").concat(version_1.VERSION, ")"));
64
- }
65
- var _a = data.substring(4).split(CodePointUtil_1.NULL), ckData = _a[0], skData = _a[1], uData = _a[2];
66
- this.clientPackets.holdPackets(Packets_1.Packet.deserializeAll(ckData, true));
67
- this.serverPackets.holdPackets(Packets_1.Packet.deserializeAll(skData, true));
68
- this.batcher.registerSendPackets(this.clientPackets, this);
69
- Object.keys(this.preListen).forEach(function (tag) { return _this.preListen[tag].forEach(function (listener) {
70
- var key = _this.serverPackets.get(tag);
71
- // print the error to console without halting execution
72
- if (key == null)
73
- return console.error(new Error("The server does not send the packet with tag \"".concat(tag, "\"!")));
74
- _this.listen(tag, listener);
75
- }); });
76
- this.preListen = null; // clear
77
- this.pastKeys = true;
78
- this.readyListeners.forEach(function (l) { return l(); });
79
- this.readyListeners = null; // clear
80
- this.socket.removeEventListener('message', this.keyHandler);
81
- this.socket.addEventListener('message', function (event) { return _this.messageHandler(event); }); // lambda to persist 'this'
82
- this.keyHandler = null;
91
+ return __awaiter(this, void 0, void 0, function () {
92
+ var data, version, _a, off, ckLength, ckData, skData;
93
+ var _this = this;
94
+ return __generator(this, function (_b) {
95
+ switch (_b.label) {
96
+ case 0:
97
+ // stupid asynchronous bullshit
98
+ if (this.reading)
99
+ return [2 /*return*/, this.messageHandler(event)];
100
+ this.reading = true;
101
+ return [4 /*yield*/, this.bufferHandler(event)];
102
+ case 1:
103
+ data = _b.sent();
104
+ if (data.length < 3 || (0, BufferUtil_1.as8String)(data.slice(0, 3)) != version_1.SERVER_SUFFIX) {
105
+ this.socket.close(1000);
106
+ throw new Error("The server requested is not a Sonic WS server.");
107
+ }
108
+ if (data.length == 3) {
109
+ // todo: queue
110
+ return [2 /*return*/];
111
+ }
112
+ version = data[3];
113
+ if (version != version_1.VERSION) {
114
+ this.socket.close(1000);
115
+ throw new Error("Version mismatch: ".concat(version > version_1.VERSION ? "client" : "server", " is outdated (server: ").concat(version, ", client: ").concat(version_1.VERSION, ")"));
116
+ }
117
+ _a = (0, CompressionUtil_1.readVarInt)(data, 4, false), off = _a[0], ckLength = _a[1];
118
+ ckData = data.slice(off, off + ckLength);
119
+ this.clientPackets.holdPackets(Packets_1.Packet.deserializeAll(ckData, true));
120
+ skData = data.slice(off + ckLength, data.length - 1);
121
+ this.serverPackets.holdPackets(Packets_1.Packet.deserializeAll(skData, true));
122
+ this.id = data[data.length - 1];
123
+ this.batcher.registerSendPackets(this.clientPackets, this);
124
+ Object.keys(this.preListen).forEach(function (tag) { return _this.preListen[tag].forEach(function (listener) {
125
+ var key = _this.serverPackets.getKey(tag);
126
+ // print the error to console without halting execution
127
+ if (key == null)
128
+ return console.error(new Error("The server does not send the packet with tag \"".concat(tag, "\"!")));
129
+ _this.listen(tag, listener);
130
+ }); });
131
+ this.preListen = null; // clear
132
+ this.pastKeys = true;
133
+ this.readyListeners.forEach(function (l) { return l(); });
134
+ this.readyListeners = null; // clear
135
+ this.socket.removeEventListener('message', this.serverKeyHandler);
136
+ this.socket.addEventListener('message', this.messageHandler);
137
+ return [2 /*return*/];
138
+ }
139
+ });
140
+ });
83
141
  };
84
142
  SonicWSCore.prototype.invalidPacket = function (listened) {
85
143
  console.log(listened);
86
144
  throw new Error("An error occured with data from the server!! This is probably my fault.. make an issue at https://github.com/cutelittlelily/sonic-ws");
87
145
  };
88
146
  SonicWSCore.prototype.listenPacket = function (data, code) {
89
- (0, PacketUtils_1.listenPacket)(data, this.listeners.event[code], this.invalidPacket);
147
+ var listeners = this.listeners.event[code];
148
+ if (!listeners)
149
+ return console.warn("Warn: No listener for packet " + this.serverPackets.getTag(code));
150
+ (0, PacketUtils_1.listenPacket)(data, listeners, this.invalidPacket);
90
151
  };
91
152
  SonicWSCore.prototype.messageHandler = function (event) {
92
- var _this = this;
93
- var data = event.data.toString();
94
- this.listeners.message.forEach(function (listener) { return listener(data); });
95
- if (data.length < 1)
96
- return;
97
- var key = data.substring(0, 1);
98
- var value = data.substring(1);
99
- var code = key.charCodeAt(0);
100
- if (code == null)
101
- return;
102
- var packet = this.serverPackets.getPacket(this.serverPackets.getTag(key));
103
- if (packet.dataBatching == 0) {
104
- this.listenPacket(packet.listen(value, null), code);
105
- return;
106
- }
107
- var batchData = BatchHelper_1.BatchHelper.unravelBatch(packet, value, null);
108
- if (typeof batchData == 'string')
109
- return this.invalidPacket(batchData);
110
- batchData.forEach(function (data) { return _this.listenPacket(data, code); });
153
+ return __awaiter(this, void 0, void 0, function () {
154
+ var data, key, value, packet, batchData;
155
+ var _this = this;
156
+ return __generator(this, function (_a) {
157
+ switch (_a.label) {
158
+ case 0: return [4 /*yield*/, this.bufferHandler(event)];
159
+ case 1:
160
+ data = _a.sent();
161
+ this.listeners.message.forEach(function (listener) { return listener(data); });
162
+ if (data.length < 1)
163
+ return [2 /*return*/];
164
+ key = data[0];
165
+ value = data.slice(1);
166
+ packet = this.serverPackets.getPacket(this.serverPackets.getTag(key));
167
+ if (packet.dataBatching == 0) {
168
+ this.listenPacket(packet.listen(value, null), key);
169
+ return [2 /*return*/];
170
+ }
171
+ batchData = BatchHelper_1.BatchHelper.unravelBatch(packet, value, null);
172
+ if (typeof batchData == 'string')
173
+ return [2 /*return*/, this.invalidPacket(batchData)];
174
+ batchData.forEach(function (data) { return _this.listenPacket(data, key); });
175
+ return [2 /*return*/];
176
+ }
177
+ });
178
+ });
111
179
  };
112
180
  SonicWSCore.prototype.listen = function (key, listener) {
113
- var skey = this.serverPackets.get(key);
181
+ var skey = this.serverPackets.getKey(key);
114
182
  if (!skey) {
115
183
  console.log("Key is not available on server: " + key);
116
184
  return;
@@ -144,7 +212,7 @@ var SonicWSCore = /** @class */ (function () {
144
212
  }
145
213
  var _a = (0, PacketUtils_1.processPacket)(this.clientPackets, tag, values), code = _a[0], data = _a[1], packet = _a[2];
146
214
  if (packet.dataBatching == 0)
147
- this.raw_send(code + data);
215
+ this.raw_send((0, BufferUtil_1.toPacketBuffer)(code, data));
148
216
  else
149
217
  this.batcher.batchPacket(code, data);
150
218
  };
@@ -179,26 +247,56 @@ var SonicWSCore = /** @class */ (function () {
179
247
  }
180
248
  this.listen(tag, listener);
181
249
  };
250
+ SonicWSCore.prototype.setTimer = function (id) {
251
+ this.timers[id] = id;
252
+ };
182
253
  /**
183
254
  * Sets a timeout that will automatically end when the socket closes
184
255
  * @param call The function to call
185
256
  * @param time The time between now and the call (ms)
257
+ * @returns The timeout id to be used with socket.clearInterval(id)
186
258
  */
187
259
  SonicWSCore.prototype.setTimeout = function (call, time) {
188
- var timeout = setTimeout(call, time);
189
- this.timers.push(timeout);
260
+ var _this = this;
261
+ var timeout = setTimeout(function () {
262
+ call();
263
+ _this.clearTimeout(timeout);
264
+ }, time);
265
+ this.setTimer(timeout);
190
266
  return timeout;
191
267
  };
192
268
  /**
193
269
  * Sets an interval that will automatically end when the socket closes
194
270
  * @param call The function to call
195
271
  * @param time The time between calls (ms)
272
+ * @returns The interval id to be used with socket.clearInterval(id)
196
273
  */
197
274
  SonicWSCore.prototype.setInterval = function (call, time) {
198
275
  var interval = setInterval(call, time);
199
- this.timers.push(interval);
276
+ this.setTimer(interval);
200
277
  return interval;
201
278
  };
279
+ /**
280
+ * Clears a timeout
281
+ * @param id The timeout id
282
+ */
283
+ SonicWSCore.prototype.clearTimeout = function (id) {
284
+ clearTimeout(id);
285
+ delete this.timers[id];
286
+ };
287
+ /**
288
+ * Clears an interval
289
+ * @param id The interval id
290
+ */
291
+ SonicWSCore.prototype.clearInterval = function (id) {
292
+ this.clearTimeout(id);
293
+ };
294
+ /**
295
+ * Closes the connection
296
+ */
297
+ SonicWSCore.prototype.close = function (code, reason) {
298
+ this.socket.close(code, reason);
299
+ };
202
300
  return SonicWSCore;
203
301
  }());
204
302
  exports.SonicWSCore = SonicWSCore;
@@ -1,6 +1,6 @@
1
1
  "use strict";
2
2
  /*
3
- * Copyright 2025 Lily (cutelittlelily)
3
+ * Copyright 2025 Lily (liwybloc)
4
4
  *
5
5
  * Licensed under the Apache License, Version 2.0 (the "License");
6
6
  * you may not use this file except in compliance with the License.
@@ -46,7 +46,7 @@ var SonicWS = /** @class */ (function (_super) {
46
46
  */
47
47
  function SonicWS(url, options) {
48
48
  var ws = new ws_1.default.WebSocket(url, options);
49
- return _super.call(this, ws) || this;
49
+ return _super.call(this, ws, function (val) { return Promise.resolve(new Uint8Array(val.data)); }) || this;
50
50
  }
51
51
  return SonicWS;
52
52
  }(ClientCore_1.SonicWSCore));
@@ -1,8 +1,13 @@
1
+ import { EnumPackage } from "../util/enums/EnumType";
1
2
  import { Packet } from "./Packets";
2
3
  import { PacketType } from "./PacketType";
3
- export declare const PacketValidityProcessors: Record<PacketType, (data: string, dataCap: number, dataMin: number, packet: Packet, index: number) => boolean>;
4
- export declare const PacketReceiveProcessors: Record<PacketType, (data: string, cap: number, packet: Packet, index: number) => "" | string | string[] | number | number[] | boolean[]>;
5
- export declare const PacketSendProcessors: Record<PacketType, (...data: any) => string>;
6
- export declare function createObjSendProcessor(types: PacketType[], packetDelimitSize: number): (data: any[]) => string;
7
- export declare function createObjReceiveProcessor(types: PacketType[], packetDelimitSize: number): (data: string, dataCaps: number[], packet: Packet) => any;
8
- export declare function createObjValidator(types: PacketType[], packetDelimitSize: number): (data: string, dataCaps: number[], dataMins: number[], packet: Packet) => boolean;
4
+ export type PacketTypeValidator = (data: Uint8Array, index: number) => false | any;
5
+ export type PacketReceiveProcessor = (data: Uint8Array, validationResult: any, index: number) => any;
6
+ export type PacketSendProcessor = (...data: any) => number[];
7
+ export declare function createValidator(type: PacketType, dataCap: number, dataMin: number, enumData: EnumPackage[]): PacketTypeValidator;
8
+ export declare function createReceiveProcessor(type: PacketType, enumData: EnumPackage[], cap: number): PacketReceiveProcessor;
9
+ /** Creates a function that processes a packet type */
10
+ export declare function createSendProcessor(type: PacketType): PacketSendProcessor;
11
+ export declare function createObjSendProcessor(packet: Packet): PacketSendProcessor;
12
+ export declare function createObjReceiveProcessor(packet: Packet): PacketReceiveProcessor;
13
+ export declare function createObjValidator(packet: Packet): PacketTypeValidator;