sonic-ws 1.0.6 → 1.1.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/LICENSE CHANGED
@@ -1,4 +1,4 @@
1
- Copyright 2025 Lily (liwybloc)
1
+ Copyright 2026 Lily (liwybloc)
2
2
 
3
3
  Licensed under the Apache License, Version 2.0 (the "License");
4
4
  You may not use this software except in compliance with the License.
package/README.md CHANGED
@@ -18,6 +18,7 @@ Developer Friendly:
18
18
 
19
19
  Security:
20
20
  - Tamper-proof; any invalid packet instantly causes closure, and tampering becomes incredibly difficult
21
+ - Basic but immensely effective anti-tampering for browser clients
21
22
  - Built-in ability for handshake packets, preventing repetitive initiation checks in listeners (for example, removes if(!init) everywhere)
22
23
  - Built-in rate limiting for packets; ability for global send & receive, alongside per-packet rate limiting
23
24
  - Built-in disabling & enabling of packets to prevent abuse
@@ -35,7 +36,7 @@ Developer Experience:
35
36
  - Many data types to maximize speed, clarity, bandwidth, and security
36
37
  - Debug tools for socket ids, byte size, data logging, etc. for troubleshooting
37
38
  - Very minimal learning curve, easy to work in
38
- - JSDoc's for understanding
39
+ - JSDoc's for understanding; immensely intuitive (personally, I took a break for half a year and came back and snapped right back in)
39
40
 
40
41
  Whether you're making a real-time game, a dashboard, a distributed system, or anything else, SonicWS gets you safe, structured packets, fast.
41
42
 
@@ -109,6 +110,10 @@ ws.on_close((event) => {
109
110
 
110
111
  ## KNOWN ISSUES
111
112
 
113
+ Some weird error messages when invalid inputs are in like CreatePacket() and stuff
114
+
112
115
  ## PLANNED FEATURES
113
116
 
114
- Better error handling
117
+ Better error handling
118
+
119
+ ZLib/gzip compression
package/dist/index.js CHANGED
@@ -1,6 +1,6 @@
1
1
  "use strict";
2
2
  /*
3
- * Copyright 2025 Lily (liwybloc)
3
+ * Copyright 2026 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,5 +1,5 @@
1
1
  /** Current protocol version */
2
- export declare const VERSION = 13;
2
+ export declare const VERSION = 14;
3
3
  /** Server data suffix */
4
4
  export declare const SERVER_SUFFIX = "SWS";
5
5
  /** Server data suffix in array */
package/dist/version.js CHANGED
@@ -1,6 +1,6 @@
1
1
  "use strict";
2
2
  /*
3
- * Copyright 2025 Lily (liwybloc)
3
+ * Copyright 2026 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.
@@ -18,7 +18,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
18
18
  exports.SERVER_SUFFIX_NUMS = exports.SERVER_SUFFIX = exports.VERSION = void 0;
19
19
  const StringUtil_1 = require("./ws/util/StringUtil");
20
20
  /** Current protocol version */
21
- exports.VERSION = 13;
21
+ exports.VERSION = 14;
22
22
  /** Server data suffix */
23
23
  exports.SERVER_SUFFIX = "SWS";
24
24
  /** Server data suffix in array */
@@ -3,17 +3,18 @@
3
3
  */
4
4
  export interface Connection {
5
5
  /**
6
- * List of timers, in object just for efficiency.
6
+ * List of timers.
7
7
  * For internal use only.
8
8
  */
9
- _timers: Record<number, number>;
9
+ _timers: Record<number, [number, (closed: boolean) => void, boolean]>;
10
10
  /**
11
11
  * Sets a timeout that will automatically end when the socket closes
12
12
  * @param call The function to call
13
13
  * @param time The time between now and the call (ms)
14
+ * @param callOnClose If the callback should be fired anyways when the socket closes
14
15
  * @returns The timeout id to be used with socket.clearInterval(id)
15
16
  */
16
- setTimeout(call: () => void, time: number): number;
17
+ setTimeout(call: () => void, time: number, callOnClose: boolean): number;
17
18
  /**
18
19
  * Sets an interval that will automatically end when the socket closes
19
20
  * @param call The function to call
@@ -1,6 +1,6 @@
1
1
  "use strict";
2
2
  /*
3
- * Copyright 2025 Lily (liwybloc)
3
+ * Copyright 2026 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.
@@ -21,7 +21,7 @@ export declare abstract class SonicWSCore implements Connection {
21
21
  private batcher;
22
22
  private bufferHandler;
23
23
  id: number;
24
- _timers: Record<number, number>;
24
+ _timers: Record<number, [number, (closed: boolean) => void, boolean]>;
25
25
  constructor(ws: WebSocket, bufferHandler: (val: MessageEvent) => Promise<Uint8Array>);
26
26
  private reading;
27
27
  private serverKeyHandler;
@@ -62,9 +62,8 @@ export declare abstract class SonicWSCore implements Connection {
62
62
  */
63
63
  on(tag: string, listener: (value: any[]) => void): void;
64
64
  raw_send(data: Uint8Array): void;
65
- setTimeout(call: () => void, time: number): number;
66
- setInterval(call: () => void, time: number): number;
67
- private setTimer;
65
+ setTimeout(call: () => void, time: number, callOnClose?: boolean): number;
66
+ setInterval(call: () => void, time: number, callOnClose?: boolean): number;
68
67
  clearTimeout(id: number): void;
69
68
  clearInterval(id: number): void;
70
69
  close(code?: number, reason?: string): void;
@@ -1,6 +1,6 @@
1
1
  "use strict";
2
2
  /*
3
- * Copyright 2025 Lily (liwybloc)
3
+ * Copyright 2026 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.
@@ -52,7 +52,11 @@ class SonicWSCore {
52
52
  this.socket.addEventListener('message', this.serverKeyHandler);
53
53
  this.socket.addEventListener('close', (event) => {
54
54
  this.listeners.close.forEach(listener => listener(event));
55
- Object.values(this._timers).forEach(clearTimeout);
55
+ for (const [id, callback, shouldCall] of Object.values(this._timers)) {
56
+ this.clearTimeout(id);
57
+ if (shouldCall)
58
+ callback(true);
59
+ }
56
60
  });
57
61
  this.bufferHandler = bufferHandler;
58
62
  }
@@ -192,22 +196,19 @@ class SonicWSCore {
192
196
  this.listeners.send.forEach(d => d(data));
193
197
  this.socket.send(data);
194
198
  }
195
- setTimeout(call, time) {
199
+ setTimeout(call, time, callOnClose = false) {
196
200
  const timeout = setTimeout(() => {
197
201
  call();
198
202
  this.clearTimeout(timeout);
199
203
  }, time);
200
- this.setTimer(timeout);
204
+ this._timers[timeout] = [timeout, call, callOnClose];
201
205
  return timeout;
202
206
  }
203
- setInterval(call, time) {
207
+ setInterval(call, time, callOnClose = false) {
204
208
  const interval = setInterval(call, time);
205
- this.setTimer(interval);
209
+ this._timers[interval] = [interval, call, callOnClose];
206
210
  return interval;
207
211
  }
208
- setTimer(id) {
209
- this._timers[id] = id;
210
- }
211
212
  clearTimeout(id) {
212
213
  clearTimeout(id);
213
214
  delete this._timers[id];
@@ -1,6 +1,6 @@
1
1
  "use strict";
2
2
  /*
3
- * Copyright 2025 Lily (liwybloc)
3
+ * Copyright 2026 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.
@@ -1,6 +1,6 @@
1
1
  "use strict";
2
2
  /*
3
- * Copyright 2025 Lily (liwybloc)
3
+ * Copyright 2026 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.
@@ -1,6 +1,6 @@
1
1
  "use strict";
2
2
  /*
3
- * Copyright 2025 Lily (liwybloc)
3
+ * Copyright 2026 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.
@@ -24,7 +24,7 @@ export declare class Packet<T extends (PacketType | readonly PacketType[])> {
24
24
  private sendProcessor;
25
25
  private validator;
26
26
  processReceive: (data: Uint8Array, validationResult: any) => any;
27
- processSend: (data: any[]) => number[];
27
+ processSend: (data: any[]) => Uint8Array;
28
28
  validate: (data: Uint8Array) => boolean;
29
29
  customValidator: ((socket: SonicWSConnection, ...values: any[]) => boolean) | null;
30
30
  constructor(tag: string, schema: PacketSchema<T>, customValidator: ValidatorFunction, enabled: boolean, client: boolean);
@@ -1,6 +1,6 @@
1
1
  "use strict";
2
2
  /*
3
- * Copyright 2025 Lily (liwybloc)
3
+ * Copyright 2026 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.
@@ -85,7 +85,7 @@ class Packet {
85
85
  this.sendProcessor = (0, PacketProcessors_1.createSendProcessor)(this.type);
86
86
  }
87
87
  this.processReceive = (data, validationResult) => this.receiveProcessor(data, validationResult, 0);
88
- this.processSend = (data) => this.sendProcessor(data);
88
+ this.processSend = (data) => new Uint8Array(this.sendProcessor(data));
89
89
  this.validate = (data) => this.validator(data, 0);
90
90
  this.customValidator = customValidator;
91
91
  }
@@ -19,7 +19,8 @@ export declare class SonicWSConnection implements Connection {
19
19
  handshakeComplete: boolean;
20
20
  /** The index of the connection; unique for all connected, recycles old disconnected ids. Should be safe for INTS_C unless you have more than 27,647 connected at once. */
21
21
  id: number;
22
- _timers: Record<number, number>;
22
+ _timers: Record<number, [number, (closed: boolean) => void, boolean]>;
23
+ private closed;
23
24
  constructor(socket: WS.WebSocket, host: SonicWSServer, id: number, handshakePacket: string | null, clientRateLimit: number, serverRateLimit: number);
24
25
  private parseData;
25
26
  private handshakeHandler;
@@ -55,7 +56,7 @@ export declare class SonicWSConnection implements Connection {
55
56
  /**
56
57
  * For internal use.
57
58
  */
58
- send_processed(code: number, data: number[], packet: Packet<any>): void;
59
+ send_processed(code: number, data: Uint8Array, packet: Packet<any>): void;
59
60
  /**
60
61
  * Sends a packet with the tag and values
61
62
  * @param tag The tag to send
@@ -80,8 +81,8 @@ export declare class SonicWSConnection implements Connection {
80
81
  togglePrint(): void;
81
82
  raw_send(data: Uint8Array): void;
82
83
  close(code?: number, reason?: string | Buffer): void;
83
- setTimeout(call: () => void, time: number): number;
84
- setInterval(call: () => void, time: number): number;
84
+ setTimeout(call: () => void, time: number, callOnClose?: boolean): number;
85
+ setInterval(call: () => void, time: number, callOnClose?: boolean): number;
85
86
  clearTimeout(id: number): void;
86
87
  clearInterval(id: number): void;
87
88
  /**
@@ -1,6 +1,6 @@
1
1
  "use strict";
2
2
  /*
3
- * Copyright 2025 Lily (liwybloc)
3
+ * Copyright 2026 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.
@@ -80,6 +80,7 @@ class SonicWSConnection {
80
80
  /** The index of the connection; unique for all connected, recycles old disconnected ids. Should be safe for INTS_C unless you have more than 27,647 connected at once. */
81
81
  id;
82
82
  _timers = {};
83
+ closed = false;
83
84
  constructor(socket, host, id, handshakePacket, clientRateLimit, serverRateLimit) {
84
85
  this.socket = socket;
85
86
  this.host = host;
@@ -108,7 +109,12 @@ class SonicWSConnection {
108
109
  this.socket.addEventListener('message', this.handshakeLambda);
109
110
  }
110
111
  this.socket.on('close', () => {
111
- Object.values(this._timers).forEach(clearTimeout);
112
+ this.closed = true;
113
+ for (const [id, callback, shouldCall] of Object.values(this._timers)) {
114
+ this.clearTimeout(id);
115
+ if (shouldCall)
116
+ callback(true);
117
+ }
112
118
  });
113
119
  }
114
120
  parseData(event) {
@@ -158,6 +164,8 @@ class SonicWSConnection {
158
164
  this.socket.close(4003, listened);
159
165
  }
160
166
  listenPacket(data, tag) {
167
+ if (this.closed)
168
+ return;
161
169
  (0, PacketUtils_1.listenPacket)(data, this.listeners[tag], this.invalidPacket);
162
170
  }
163
171
  messageHandler(data) {
@@ -196,7 +204,7 @@ class SonicWSConnection {
196
204
  * @returns If it's closed or not
197
205
  */
198
206
  isClosed() {
199
- return this.socket.readyState == WS.CLOSED;
207
+ return this.closed || this.socket.readyState == WS.CLOSED;
200
208
  }
201
209
  /**
202
210
  * Listens for when the connection closes
@@ -270,19 +278,20 @@ class SonicWSConnection {
270
278
  this.socket.send(data);
271
279
  }
272
280
  close(code = 1000, reason) {
281
+ this.closed = true;
273
282
  this.socket.close(code, reason);
274
283
  }
275
- setTimeout(call, time) {
284
+ setTimeout(call, time, callOnClose = false) {
276
285
  const timeout = setTimeout(() => {
277
286
  call();
278
287
  this.clearTimeout(timeout);
279
288
  }, time);
280
- this._timers[timeout] = timeout;
289
+ this._timers[timeout] = [timeout, call, callOnClose];
281
290
  return timeout;
282
291
  }
283
- setInterval(call, time) {
292
+ setInterval(call, time, callOnClose = false) {
284
293
  const interval = setInterval(call, time);
285
- this._timers[interval] = interval;
294
+ this._timers[interval] = [interval, call, callOnClose];
286
295
  return interval;
287
296
  }
288
297
  clearTimeout(id) {
@@ -1,6 +1,6 @@
1
1
  "use strict";
2
2
  /*
3
- * Copyright 2025 Lily (liwybloc)
3
+ * Copyright 2026 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.
@@ -1,6 +1,6 @@
1
1
  "use strict";
2
2
  /*
3
- * Copyright 2025 Lily (liwybloc)
3
+ * Copyright 2026 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.
@@ -1,4 +1,4 @@
1
- export declare function toPacketBuffer(code: number, data: number[]): Uint8Array;
1
+ export declare function toPacketBuffer(code: number, data: Uint8Array): Uint8Array;
2
2
  export declare function splitBuffer(arr: Uint8Array, x: number): number[][];
3
3
  export declare function as8String(data: Uint8Array): string;
4
4
  export declare function as16String(data: Uint8Array): string;
@@ -1,6 +1,6 @@
1
1
  "use strict";
2
2
  /*
3
- * Copyright 2025 Lily (liwybloc)
3
+ * Copyright 2026 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.
@@ -1,6 +1,6 @@
1
1
  "use strict";
2
2
  /*
3
- * Copyright 2025 Lily (liwybloc)
3
+ * Copyright 2026 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.
@@ -1,6 +1,6 @@
1
1
  "use strict";
2
2
  /*
3
- * Copyright 2025 Lily (liwybloc)
3
+ * Copyright 2026 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.
@@ -1,6 +1,6 @@
1
1
  "use strict";
2
2
  /*
3
- * Copyright 2025 Lily (liwybloc)
3
+ * Copyright 2026 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.
@@ -10,6 +10,6 @@ export declare class BatchHelper {
10
10
  registerSendPackets(packetHolder: PacketHolder, conn: Connection): void;
11
11
  private initiateBatch;
12
12
  private startBatch;
13
- batchPacket(code: number, data: number[]): void;
13
+ batchPacket(code: number, data: Uint8Array): void;
14
14
  static unravelBatch(packet: Packet<any>, data: Uint8Array, socket: SonicWSConnection | null): any[] | string;
15
15
  }
@@ -1,6 +1,6 @@
1
1
  "use strict";
2
2
  /*
3
- * Copyright 2025 Lily (liwybloc)
3
+ * Copyright 2026 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.
@@ -39,10 +39,10 @@ class BatchHelper {
39
39
  }
40
40
  startBatch(code) {
41
41
  this.batchTimeouts[code] = this.conn.setTimeout(() => {
42
- this.conn.raw_send((0, BufferUtil_1.toPacketBuffer)(code, this.batchedData[code]));
42
+ this.conn.raw_send((0, BufferUtil_1.toPacketBuffer)(code, new Uint8Array(this.batchedData[code])));
43
43
  this.batchedData[code] = [];
44
44
  delete this.batchTimeouts[code];
45
- }, this.batchTimes[code]);
45
+ }, this.batchTimes[code], false);
46
46
  }
47
47
  batchPacket(code, data) {
48
48
  const batch = this.batchedData[code];
@@ -1,6 +1,6 @@
1
1
  "use strict";
2
2
  /*
3
- * Copyright 2025 Lily (liwybloc)
3
+ * Copyright 2026 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.
@@ -1,6 +1,6 @@
1
1
  "use strict";
2
2
  /*
3
- * Copyright 2025 Lily (liwybloc)
3
+ * Copyright 2026 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.
@@ -9,7 +9,7 @@ import { EnumPackage } from "../enums/EnumType";
9
9
  * @param values The values
10
10
  * @returns The indexed code, the data, and the packet schema
11
11
  */
12
- export declare function processPacket(packets: PacketHolder, tag: string, values: any[]): [code: number, data: number[], packet: Packet<any>];
12
+ export declare function processPacket(packets: PacketHolder, tag: string, values: any[]): [code: number, data: Uint8Array, packet: Packet<any>];
13
13
  /**
14
14
  * Calls the listener for a packet with error callback
15
15
  * @param listened The listened data
@@ -1,6 +1,6 @@
1
1
  "use strict";
2
2
  /*
3
- * Copyright 2025 Lily (liwybloc)
3
+ * Copyright 2026 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.
@@ -65,7 +65,7 @@ function processPacket(packets, tag, values) {
65
65
  }
66
66
  }
67
67
  }
68
- return [code, values.length > 0 ? packet.processSend(values) : [], packet];
68
+ return [code, values.length > 0 ? packet.processSend(values) : new Uint8Array([]), packet];
69
69
  }
70
70
  /**
71
71
  * Calls the listener for a packet with error callback
@@ -127,7 +127,9 @@ function clampDataMin(dataMin, dataMax) {
127
127
  * @throws {Error} If the `type` is invalid.
128
128
  */
129
129
  function CreatePacket(settings) {
130
- let { tag, type = PacketType_1.PacketType.NONE, dataMax = 1, dataMin, noDataRange = false, dontSpread = false, validator = null, dataBatching = 0, maxBatchSize = 10, rateLimit = 0, enabled = true } = settings;
130
+ let { tag, type = PacketType_1.PacketType.NONE, dataMax = 1, dataMin = 1, noDataRange = false, dontSpread = false, validator = null, dataBatching = 0, maxBatchSize = 10, rateLimit = 0, enabled = true, } = settings;
131
+ if (!tag)
132
+ throw new Error("Tag not selected!");
131
133
  if (noDataRange) {
132
134
  dataMin = 0;
133
135
  dataMax = MAX_DATA_MAX;
@@ -148,7 +150,11 @@ function CreatePacket(settings) {
148
150
  * @throws {Error} If any type in `types` is invalid.
149
151
  */
150
152
  function CreateObjPacket(settings) {
151
- let { tag, types, dataMaxes, dataMins, noDataRange = false, dontSpread = false, autoFlatten = false, validator = null, dataBatching = 0, maxBatchSize = 10, rateLimit = 0, enabled = true } = settings;
153
+ let { tag, types = [], dataMaxes, dataMins, noDataRange = false, dontSpread = false, autoFlatten = false, validator = null, dataBatching = 0, maxBatchSize = 10, rateLimit = 0, enabled = true } = settings;
154
+ if (!tag)
155
+ throw new Error("Tag not selected!");
156
+ if (types.length == 0)
157
+ throw new Error("Types is set to 0 length");
152
158
  for (const type of types) {
153
159
  if (!isInvalidType(type))
154
160
  continue;
@@ -1,6 +1,6 @@
1
1
  "use strict";
2
2
  /*
3
- * Copyright 2025 Lily (liwybloc)
3
+ * Copyright 2026 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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "sonic-ws",
3
- "version": "1.0.6",
3
+ "version": "1.1.0",
4
4
  "description": "Ultra-lightweight, high-performance, and bandwidth efficient websocket library",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",
@@ -24,7 +24,8 @@
24
24
  "author": "lily",
25
25
  "license": "Apache-2.0",
26
26
  "dependencies": {
27
- "ws": "^8.18.2"
27
+ "ws": "^8.18.2",
28
+ "zstd-codec": "^0.1.5"
28
29
  },
29
30
  "devDependencies": {
30
31
  "@types/node": "^24.2.1",