sonic-ws 1.0.5 → 1.0.6

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/dist/version.d.ts CHANGED
@@ -1,5 +1,5 @@
1
1
  /** Current protocol version */
2
- export declare const VERSION = 12;
2
+ export declare const VERSION = 13;
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
@@ -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 = 12;
21
+ exports.VERSION = 13;
22
22
  /** Server data suffix */
23
23
  exports.SERVER_SUFFIX = "SWS";
24
24
  /** Server data suffix in array */
@@ -14,8 +14,8 @@ export declare abstract class SonicWSCore implements Connection {
14
14
  protected preListen: {
15
15
  [key: string]: Array<(data: any[]) => void>;
16
16
  } | null;
17
- protected clientPackets: PacketHolder<any>;
18
- protected serverPackets: PacketHolder<any>;
17
+ protected clientPackets: PacketHolder;
18
+ protected serverPackets: PacketHolder;
19
19
  private pastKeys;
20
20
  private readyListeners;
21
21
  private batcher;
@@ -37,7 +37,7 @@ function SHORT_LEN(cap, min) {
37
37
  function VARINT_VERIF(cap, min) {
38
38
  return (data) => {
39
39
  if (data.length == 0)
40
- return false;
40
+ return min <= 0 ? [] : false;
41
41
  let sectors = 0, i = 0, computed = [];
42
42
  while (i < data.length) {
43
43
  const [off, varint] = (0, CompressionUtil_1.readVarInt)(data, i);
@@ -96,20 +96,22 @@ function createValidator(type, dataCap, dataMin, packet) {
96
96
  }
97
97
  ;
98
98
  case PacketType_1.PacketType.STRINGS_ASCII: return (data) => {
99
- let sectors = 0, index = 0, computed = [];
100
- while (index < data.length) {
101
- sectors++;
102
- if (sectors > dataCap)
103
- return false;
104
- const [off, varint] = (0, CompressionUtil_1.readVarInt)(data, index);
105
- computed.push([off - index, varint]);
106
- index = off + varint;
107
- if (index > data.length)
108
- return false;
99
+ let index = 0;
100
+ const [offCount, stringCount] = (0, CompressionUtil_1.readVarInt)(data, index);
101
+ index = offCount;
102
+ if (stringCount < dataMin || stringCount > dataCap)
103
+ return false;
104
+ const lengths = [];
105
+ let totalLength = 0;
106
+ for (let i = 0; i < stringCount; i++) {
107
+ const [offLen, strLen] = (0, CompressionUtil_1.readVarInt)(data, index);
108
+ index = offLen;
109
+ lengths.push(strLen);
110
+ totalLength += strLen;
109
111
  }
110
- if (sectors < dataMin)
112
+ if (index + Math.ceil(totalLength / 8) > data.length)
111
113
  return false;
112
- return computed;
114
+ return [stringCount, lengths, index];
113
115
  };
114
116
  case PacketType_1.PacketType.STRINGS_UTF16: return (data) => {
115
117
  let sectors = 0, index = 0, computed = [];
@@ -154,14 +156,17 @@ function createReceiveProcessor(type, enumData, cap) {
154
156
  const pkg = enumData[index];
155
157
  return Array.from(data).map(code => pkg.values[code]);
156
158
  };
157
- case PacketType_1.PacketType.STRINGS_ASCII: return (data, computed) => {
159
+ case PacketType_1.PacketType.STRINGS_ASCII: return (data, validationResult) => {
160
+ const [stringCount, lengths, dataStart] = validationResult;
161
+ const bitString = (0, CompressionUtil_1.bytesToBits)(data.subarray(dataStart));
162
+ const decoded = (0, CompressionUtil_1.decodeHuffman)(bitString);
163
+ if (!decoded)
164
+ return [];
158
165
  const strings = [];
159
- let index = 0;
160
- for (let i = 0; i < computed.length; i++) {
161
- const [strLenLen, strLen] = computed[i];
162
- index += strLenLen;
163
- const str = (0, BufferUtil_1.as8String)(data.subarray(index, index += strLen));
164
- strings.push(str);
166
+ let offset = 0;
167
+ for (let i = 0; i < stringCount; i++) {
168
+ strings.push(decoded.slice(offset, offset + lengths[i]));
169
+ offset += lengths[i];
165
170
  }
166
171
  return strings;
167
172
  };
@@ -188,18 +193,11 @@ function createSendProcessor(type) {
188
193
  case PacketType_1.PacketType.DOUBLES: return (doubles) => doubles.map(CompressionUtil_1.convertDouble).flat();
189
194
  case PacketType_1.PacketType.BOOLEANS: return (bools) => (0, ArrayUtil_1.splitArray)(bools, 8).map((bools) => (0, CompressionUtil_1.compressBools)(bools)).flat();
190
195
  case PacketType_1.PacketType.STRINGS_ASCII: return (strings) => {
191
- const res = [];
192
- for (const v of strings) {
193
- const string = String(v);
194
- const lenVI = (0, CompressionUtil_1.convertVarInt)(string.length);
195
- res.push(...lenVI);
196
- const codes = (0, StringUtil_1.processCharCodes)(string);
197
- const highCode = codes.find(x => x > CompressionUtil_1.MAX_BYTE);
198
- if (highCode)
199
- throw new Error(`Cannot store code ${highCode} (${String.fromCharCode(highCode)}) in a UTF-8 String! Use STRINGS_UTF16.`);
200
- res.push(...codes);
201
- }
202
- return res;
196
+ return [
197
+ ...(0, CompressionUtil_1.convertVarInt)(strings.length),
198
+ ...strings.map(str => (0, CompressionUtil_1.convertVarInt)(str.length)).flat(),
199
+ ...(0, CompressionUtil_1.encodeHuffman)(strings.reduce((a, b) => a + String(b), "")),
200
+ ];
203
201
  };
204
202
  case PacketType_1.PacketType.STRINGS_UTF16: return (strings) => {
205
203
  const res = [];
@@ -1,7 +1,7 @@
1
1
  import { EnumPackage } from "../util/enums/EnumType";
2
2
  import { SonicWSConnection } from "../server/SonicWSConnection";
3
3
  import { PacketType } from "./PacketType";
4
- export type ValidatorFunction = ((socket: SonicWSConnection<any, any>, values: any[]) => boolean) | null;
4
+ export type ValidatorFunction = ((socket: SonicWSConnection, values: any) => boolean) | null;
5
5
  export type ConvertType<T> = T extends EnumPackage ? PacketType.ENUMS : T;
6
6
  type ImpactType<T extends (PacketType | readonly PacketType[]), K> = T extends PacketType[] ? K[] : K;
7
7
  export declare class Packet<T extends (PacketType | readonly PacketType[])> {
@@ -26,9 +26,9 @@ export declare class Packet<T extends (PacketType | readonly PacketType[])> {
26
26
  processReceive: (data: Uint8Array, validationResult: any) => any;
27
27
  processSend: (data: any[]) => number[];
28
28
  validate: (data: Uint8Array) => boolean;
29
- customValidator: ((socket: SonicWSConnection<any, any>, ...values: any[]) => boolean) | null;
29
+ customValidator: ((socket: SonicWSConnection, ...values: any[]) => boolean) | null;
30
30
  constructor(tag: string, schema: PacketSchema<T>, customValidator: ValidatorFunction, enabled: boolean, client: boolean);
31
- listen(value: Uint8Array, socket: SonicWSConnection<any, any> | null): [processed: any, flatten: boolean] | string;
31
+ listen(value: Uint8Array, socket: SonicWSConnection | null): [processed: any, flatten: boolean] | string;
32
32
  serialize(): number[];
33
33
  private static readVarInts;
34
34
  static deserialize(data: Uint8Array, offset: number, client: boolean): [packet: Packet<any>, offset: number];
@@ -92,7 +92,8 @@ class Packet {
92
92
  listen(value, socket) {
93
93
  try {
94
94
  const validationResult = this.validate(value);
95
- if (!this.client && validationResult == false)
95
+ // holy shit i used === to fix another bug
96
+ if (!this.client && validationResult === false)
96
97
  return "Invalid packet";
97
98
  const processed = this.processReceive(value, validationResult);
98
99
  const useableData = this.autoFlatten ? (0, PacketUtils_1.UnFlattenData)(processed) : processed;
@@ -1,9 +1,8 @@
1
1
  import * as WS from 'ws';
2
- import { PacketTypings, SonicWSServer } from './SonicWSServer';
2
+ import { SonicWSServer } from './SonicWSServer';
3
3
  import { Packet } from '../packets/Packets';
4
4
  import { Connection } from '../Connection';
5
- import { PacketResponse } from '../packets/PacketProcessors';
6
- export declare class SonicWSConnection<ClientTypes extends PacketTypings, ServerTypes extends PacketTypings> implements Connection {
5
+ export declare class SonicWSConnection implements Connection {
7
6
  /** Raw 'ws' library socket */
8
7
  socket: WS.WebSocket;
9
8
  private host;
@@ -21,7 +20,7 @@ export declare class SonicWSConnection<ClientTypes extends PacketTypings, Server
21
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. */
22
21
  id: number;
23
22
  _timers: Record<number, number>;
24
- constructor(socket: WS.WebSocket, host: SonicWSServer<ClientTypes, ServerTypes>, id: number, handshakePacket: string | null, clientRateLimit: number, serverRateLimit: number);
23
+ constructor(socket: WS.WebSocket, host: SonicWSServer, id: number, handshakePacket: string | null, clientRateLimit: number, serverRateLimit: number);
25
24
  private parseData;
26
25
  private handshakeHandler;
27
26
  private invalidPacket;
@@ -46,17 +45,17 @@ export declare class SonicWSConnection<ClientTypes extends PacketTypings, Server
46
45
  * Listens for when the connection closes
47
46
  * @param listener Called when it closes
48
47
  */
49
- on_close(listener: (code: number, reason: Buffer) => void): void;
48
+ on_close(listener: (code: number, reason: string) => void): void;
50
49
  /**
51
50
  * Listens for a packet
52
51
  * @param tag The tag of the key to listen for
53
52
  * @param listener A function to listen for it
54
53
  */
55
- on<K extends number, T extends ClientTypes[K], Tag extends T['tag'] = T['tag'], Type extends T['type'] = T['type'], DataMax extends T['dataMax'] = T['dataMax']>(tag: Tag, listener: T['dontSpread'] extends true ? (packet: PacketResponse<Type, DataMax>) => void : (...packet: PacketResponse<Type, DataMax>) => void): void;
54
+ on(tag: string, listener: (...values: any) => void): void;
56
55
  /**
57
56
  * For internal use.
58
57
  */
59
- send_processed(code: number, data: number[], packet: Packet<ClientTypes[number]['type']>): void;
58
+ send_processed(code: number, data: number[], packet: Packet<any>): void;
60
59
  /**
61
60
  * Sends a packet with the tag and values
62
61
  * @param tag The tag to send
@@ -68,7 +67,7 @@ export declare class SonicWSConnection<ClientTypes extends PacketTypings, Server
68
67
  * @param tag The tag to send
69
68
  * @param values The values to send
70
69
  */
71
- broadcastFiltered(tag: string, filter: (socket: SonicWSConnection<ClientTypes, ServerTypes>) => boolean, ...values: any[]): void;
70
+ broadcastFiltered(tag: string, filter: (socket: SonicWSConnection) => boolean, ...values: any[]): void;
72
71
  /**
73
72
  * Broadcasts a packet to all other users connected
74
73
  * @param tag The tag to send
@@ -85,4 +84,10 @@ export declare class SonicWSConnection<ClientTypes extends PacketTypings, Server
85
84
  setInterval(call: () => void, time: number): number;
86
85
  clearTimeout(id: number): void;
87
86
  clearInterval(id: number): void;
87
+ /**
88
+ * Tags the socket with a key
89
+ * @param tag The tag to add
90
+ * @param replace If it should replace a previous tag; defaults to true. If using false, you can add multiple tags.
91
+ */
92
+ tag(tag: string, replace?: boolean): void;
88
93
  }
@@ -67,7 +67,7 @@ class SonicWSConnection {
67
67
  handshakedMessageLambda = (data) => {
68
68
  const parsed = this.parseData(data);
69
69
  if (parsed == null)
70
- return;
70
+ return this.socket.close(4004);
71
71
  if (parsed[0] == this.handshakePacket)
72
72
  return this.socket.close(4005);
73
73
  this.messageHandler(parsed);
@@ -143,7 +143,7 @@ class SonicWSConnection {
143
143
  handshakeHandler(data) {
144
144
  const parsed = this.parseData(data);
145
145
  if (parsed == null)
146
- return;
146
+ return this.socket.close(4004);
147
147
  if (parsed[0] != this.handshakePacket) {
148
148
  this.socket.close(4004);
149
149
  return;
@@ -154,6 +154,7 @@ class SonicWSConnection {
154
154
  this.handshakeComplete = true;
155
155
  }
156
156
  invalidPacket(listened) {
157
+ console.log("Closure cause", listened);
157
158
  this.socket.close(4003, listened);
158
159
  }
159
160
  listenPacket(data, tag) {
@@ -202,7 +203,7 @@ class SonicWSConnection {
202
203
  * @param listener Called when it closes
203
204
  */
204
205
  on_close(listener) {
205
- this.socket.on('close', listener);
206
+ this.socket.on('close', (code, reason) => listener(code, String(reason)));
206
207
  }
207
208
  /**
208
209
  * Listens for a packet
@@ -258,8 +259,10 @@ class SonicWSConnection {
258
259
  }
259
260
  /* JSDocs in Connection.ts class */
260
261
  raw_send(data) {
261
- if (this.isClosed())
262
- throw new Error("Connection is already closed!");
262
+ if (this.isClosed()) {
263
+ console.warn("WARN! Connection already closed when trying to send message!", this.id, (0, BufferUtil_1.stringifyBuffer)(data));
264
+ return;
265
+ }
263
266
  if (this.rater.trigger(SERVER_RATELIMIT_TAG))
264
267
  return;
265
268
  if (this.print)
@@ -289,5 +292,13 @@ class SonicWSConnection {
289
292
  clearInterval(id) {
290
293
  this.clearTimeout(id);
291
294
  }
295
+ /**
296
+ * Tags the socket with a key
297
+ * @param tag The tag to add
298
+ * @param replace If it should replace a previous tag; defaults to true. If using false, you can add multiple tags.
299
+ */
300
+ tag(tag, replace = true) {
301
+ this.host.tag(this, tag, replace);
302
+ }
292
303
  }
293
304
  exports.SonicWSConnection = SonicWSConnection;
@@ -6,33 +6,35 @@ import { PacketType } from '../packets/PacketType';
6
6
  /**
7
7
  * Sonic WS Server Options
8
8
  */
9
- export type SonicServerOptions<ClientTypes extends PacketTypings, ServerTypes extends PacketTypings> = {
9
+ export type SonicServerOptions = {
10
10
  /** An array of packets the client can send and server can listen for; using CreatePacket(), CreateObjPacket(), and CreateEnumPacket() */
11
- readonly clientPackets?: ClientTypes;
11
+ readonly clientPackets?: PacketTypings;
12
12
  /** An array of packets the server can send and client can listen for; using CreatePacket(), CreateObjPacket(), and CreateEnumPacket() */
13
- readonly serverPackets?: ServerTypes;
13
+ readonly serverPackets?: PacketTypings;
14
14
  /** Default WS Options */
15
15
  readonly websocketOptions?: WS.ServerOptions;
16
16
  };
17
17
  export type PacketTypings = readonly Packet<PacketType | readonly PacketType[]>[];
18
- export declare class SonicWSServer<ClientTypes extends PacketTypings, ServerTypes extends PacketTypings> {
18
+ export declare class SonicWSServer {
19
19
  private wss;
20
20
  private availableIds;
21
21
  private lastId;
22
22
  private connectListeners;
23
- clientPackets: PacketHolder<ClientTypes>;
24
- serverPackets: PacketHolder<ServerTypes>;
25
- connections: SonicWSServer.Connection[];
23
+ clientPackets: PacketHolder;
24
+ serverPackets: PacketHolder;
25
+ connections: SonicWSConnection[];
26
26
  private connectionMap;
27
27
  private clientRateLimit;
28
28
  private serverRateLimit;
29
29
  private handshakePacket;
30
+ tags: Map<SonicWSConnection, Set<String>>;
31
+ tagsInv: Map<String, Set<SonicWSConnection>>;
30
32
  /**
31
33
  * Initializes and hosts a websocket with sonic protocol
32
34
  * Rate limits can be set with wss.setClientRateLimit(x) and wss.setServerRateLimit(x); it is defaulted at 500/second per both
33
35
  * @param settings Sonic Server Options such as schema data for client and server packets, alongside websocket options
34
36
  */
35
- constructor(settings: SonicServerOptions<ClientTypes, ServerTypes>);
37
+ constructor(settings: SonicServerOptions);
36
38
  private generateSocketID;
37
39
  /**
38
40
  * Requires each client to send this packet upon initialization
@@ -79,7 +81,7 @@ export declare class SonicWSServer<ClientTypes extends PacketTypings, ServerType
79
81
  * Listens for whenever a client connects
80
82
  * @param runner Called when ready
81
83
  */
82
- on_connect(runner: (client: SonicWSConnection<ClientTypes, ServerTypes>) => void): void;
84
+ on_connect(runner: (client: SonicWSConnection) => void): void;
83
85
  /**
84
86
  * Listens for whenever the server is ready
85
87
  * @param runner Called when ready
@@ -90,13 +92,20 @@ export declare class SonicWSServer<ClientTypes extends PacketTypings, ServerType
90
92
  * @param callback Called when server closes
91
93
  */
92
94
  shutdown(callback: (err?: Error) => void): void;
95
+ /**
96
+ * Broadcasts a packet to tagged users; this is fast as it is a record rather than looping and filtering
97
+ * @param tag The tag to send packets to
98
+ * @param packetTag Packet tag to send
99
+ * @param values Values to send
100
+ */
101
+ broadcastTagged(tag: string, packetTag: string, ...values: any): void;
93
102
  /**
94
103
  * Broadcasts a packet to all users connected, but with a filter
95
104
  * @param tag The tag to send
96
105
  * @param filter The filter for who to send to
97
106
  * @param values The values to send
98
107
  */
99
- broadcastFiltered(tag: string, filter: (socket: SonicWSConnection<ClientTypes, ServerTypes>) => boolean, ...values: any): void;
108
+ broadcastFiltered(tag: string, filter: (socket: SonicWSConnection) => boolean, ...values: any): void;
100
109
  /**
101
110
  * Broadcasts a packet to all users connected
102
111
  * @param tag The tag to send
@@ -106,18 +115,22 @@ export declare class SonicWSServer<ClientTypes extends PacketTypings, ServerType
106
115
  /**
107
116
  * @returns All users connected to the socket
108
117
  */
109
- getConnected(): SonicWSServer.Connection[];
118
+ getConnected(): SonicWSConnection[];
110
119
  /**
111
120
  * @param id The socket id
112
121
  * @returns The socket
113
122
  */
114
- getSocket(id: number): SonicWSConnection<ClientTypes, ServerTypes>;
123
+ getSocket(id: number): SonicWSConnection;
115
124
  /**
116
125
  * Closes a socket by id
117
126
  * @param id The socket id
118
127
  */
119
128
  closeSocket(id: number, code?: number, reason?: string | Buffer): void;
120
- }
121
- export declare namespace SonicWSServer {
122
- type Connection<ClientTypes extends PacketTypings = any, ServerTypes extends PacketTypings = any> = import('./SonicWSConnection').SonicWSConnection<ClientTypes, ServerTypes>;
129
+ /**
130
+ * Tags the socket with a key
131
+ * @param socket The socket to tag
132
+ * @param tag The tag to add
133
+ * @param replace If it should replace a previous tag; defaults to true. If using false, you can add multiple tags.
134
+ */
135
+ tag(socket: SonicWSConnection, tag: string, replace?: boolean): void;
123
136
  }
@@ -67,6 +67,8 @@ class SonicWSServer {
67
67
  clientRateLimit = 500;
68
68
  serverRateLimit = 500;
69
69
  handshakePacket = null;
70
+ tags = new Map();
71
+ tagsInv = new Map();
70
72
  /**
71
73
  * Initializes and hosts a websocket with sonic protocol
72
74
  * Rate limits can be set with wss.setClientRateLimit(x) and wss.setServerRateLimit(x); it is defaulted at 500/second per both
@@ -200,6 +202,18 @@ class SonicWSServer {
200
202
  shutdown(callback) {
201
203
  this.wss.close(callback);
202
204
  }
205
+ /**
206
+ * Broadcasts a packet to tagged users; this is fast as it is a record rather than looping and filtering
207
+ * @param tag The tag to send packets to
208
+ * @param packetTag Packet tag to send
209
+ * @param values Values to send
210
+ */
211
+ broadcastTagged(tag, packetTag, ...values) {
212
+ if (!this.tagsInv.has(tag))
213
+ return;
214
+ const data = (0, PacketUtils_1.processPacket)(this.serverPackets, packetTag, values);
215
+ this.tagsInv.get(tag).forEach(conn => conn.send_processed(...data));
216
+ }
203
217
  /**
204
218
  * Broadcasts a packet to all users connected, but with a filter
205
219
  * @param tag The tag to send
@@ -208,7 +222,6 @@ class SonicWSServer {
208
222
  */
209
223
  broadcastFiltered(tag, filter, ...values) {
210
224
  const data = (0, PacketUtils_1.processPacket)(this.serverPackets, tag, values);
211
- // weird type bug here so i make it as any
212
225
  this.connections.filter(filter).forEach(conn => conn.send_processed(...data));
213
226
  }
214
227
  /**
@@ -239,5 +252,22 @@ class SonicWSServer {
239
252
  closeSocket(id, code = 1000, reason) {
240
253
  this.getSocket(id).close(code, reason);
241
254
  }
255
+ /**
256
+ * Tags the socket with a key
257
+ * @param socket The socket to tag
258
+ * @param tag The tag to add
259
+ * @param replace If it should replace a previous tag; defaults to true. If using false, you can add multiple tags.
260
+ */
261
+ tag(socket, tag, replace = true) {
262
+ if (!this.tags.get(socket))
263
+ this.tags.set(socket, new Set());
264
+ if (!this.tagsInv.get(tag))
265
+ this.tagsInv.set(tag, new Set());
266
+ if (replace) {
267
+ this.tags.get(socket).forEach(v => this.tagsInv.get(v)?.delete(socket));
268
+ }
269
+ this.tags.get(socket).add(tag);
270
+ this.tagsInv.get(tag).add(socket);
271
+ }
242
272
  }
243
273
  exports.SonicWSServer = SonicWSServer;
@@ -9,7 +9,7 @@ export declare const SET_PACKAGES: Record<string, EnumPackage>;
9
9
  * @param values The possible values of the enum
10
10
  * @returns A packaged enum
11
11
  */
12
- export declare function DefineEnum(tag: string, values: any[]): EnumPackage;
12
+ export declare function DefineEnum(tag: string, values: any[] | readonly any[]): EnumPackage;
13
13
  /**
14
14
  * Wraps an enum into a transmittable format
15
15
  * @param tag The tag of the enum
@@ -17,3 +17,4 @@ export declare function DefineEnum(tag: string, values: any[]): EnumPackage;
17
17
  * @returns A transmittable enum value
18
18
  */
19
19
  export declare function WrapEnum(tag: string, value: any): number;
20
+ export declare function DeWrapEnum(tag: string, value: number): any;
@@ -18,6 +18,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
18
18
  exports.SET_PACKAGES = exports.ENUM_KEY_TO_TAG = exports.ENUM_TAG_TO_KEY = exports.MAX_ENUM_SIZE = void 0;
19
19
  exports.DefineEnum = DefineEnum;
20
20
  exports.WrapEnum = WrapEnum;
21
+ exports.DeWrapEnum = DeWrapEnum;
21
22
  const CompressionUtil_1 = require("../packets/CompressionUtil");
22
23
  const EnumType_1 = require("./EnumType");
23
24
  exports.MAX_ENUM_SIZE = CompressionUtil_1.MAX_BYTE;
@@ -54,3 +55,6 @@ function WrapEnum(tag, value) {
54
55
  throw new Error(`Value "${value}" does not exist in enum "${tag}"`);
55
56
  return exports.ENUM_TAG_TO_KEY[tag][value];
56
57
  }
58
+ function DeWrapEnum(tag, value) {
59
+ return exports.ENUM_KEY_TO_TAG[tag][value];
60
+ }
@@ -2,7 +2,13 @@ export declare const TYPE_CONVERSION_MAP: Record<number, (data: string) => strin
2
2
  export type EnumValue = string | number | boolean | undefined | null;
3
3
  export declare class EnumPackage {
4
4
  tag: string;
5
- values: EnumValue[];
6
- constructor(tag: string, values: any[]);
5
+ values: EnumValue[] | readonly EnumValue[];
6
+ constructor(tag: string, values: any[] | readonly any[]);
7
7
  serialize(): number[];
8
+ /**
9
+ * Wraps a value with this enum package
10
+ * @param value Value to wrap
11
+ * @returns Network encoded value
12
+ */
13
+ wrap(value: any): number;
8
14
  }
@@ -17,6 +17,7 @@
17
17
  Object.defineProperty(exports, "__esModule", { value: true });
18
18
  exports.EnumPackage = exports.TYPE_CONVERSION_MAP = void 0;
19
19
  const StringUtil_1 = require("../StringUtil");
20
+ const EnumHandler_1 = require("./EnumHandler");
20
21
  const TYPE_INDEX_MAP = {
21
22
  'string': 0,
22
23
  'number': 1,
@@ -43,6 +44,7 @@ class EnumPackage {
43
44
  constructor(tag, values) {
44
45
  this.tag = tag;
45
46
  this.values = values;
47
+ this.wrap = this.wrap.bind(this);
46
48
  }
47
49
  serialize() {
48
50
  const tag = (0, StringUtil_1.processCharCodes)(this.tag);
@@ -57,5 +59,13 @@ class EnumPackage {
57
59
  ]).flat(),
58
60
  ];
59
61
  }
62
+ /**
63
+ * Wraps a value with this enum package
64
+ * @param value Value to wrap
65
+ * @returns Network encoded value
66
+ */
67
+ wrap(value) {
68
+ return (0, EnumHandler_1.WrapEnum)(this.tag, value);
69
+ }
60
70
  }
61
71
  exports.EnumPackage = EnumPackage;
@@ -1,15 +1,15 @@
1
1
  import { Connection } from "../../Connection";
2
2
  import { Packet } from "../../packets/Packets";
3
- import { SonicWSServer } from "../../server/SonicWSServer";
3
+ import { SonicWSConnection } from "../../server/SonicWSConnection";
4
4
  import { PacketHolder } from "./PacketHolder";
5
5
  export declare class BatchHelper {
6
6
  private batchTimes;
7
7
  private batchTimeouts;
8
8
  private batchedData;
9
9
  private conn;
10
- registerSendPackets(packetHolder: PacketHolder<any>, conn: Connection): void;
10
+ registerSendPackets(packetHolder: PacketHolder, conn: Connection): void;
11
11
  private initiateBatch;
12
12
  private startBatch;
13
13
  batchPacket(code: number, data: number[]): void;
14
- static unravelBatch(packet: Packet<any>, data: Uint8Array, socket: SonicWSServer.Connection | null): any[] | string;
14
+ static unravelBatch(packet: Packet<any>, data: Uint8Array, socket: SonicWSConnection | null): any[] | string;
15
15
  }
@@ -35,3 +35,7 @@ export declare function mapShort_ZZ(short: number): SHORT_BITS;
35
35
  export declare function convertVarInt(num: number): number[];
36
36
  export declare function readVarInt(arr: number[] | Uint8Array, off: number): [offset: number, number: number];
37
37
  export declare function deconvertVarInts(arr: Uint8Array | number[]): number[];
38
+ export declare function bytesToBits(bytes: ArrayLike<number>): string;
39
+ export declare function bitsToBytes(bitString: string): Uint8Array;
40
+ export declare function encodeHuffman(text: string): Uint8Array;
41
+ export declare function decodeHuffman(bits: string): string;
@@ -32,6 +32,10 @@ exports.mapShort_ZZ = mapShort_ZZ;
32
32
  exports.convertVarInt = convertVarInt;
33
33
  exports.readVarInt = readVarInt;
34
34
  exports.deconvertVarInts = deconvertVarInts;
35
+ exports.bytesToBits = bytesToBits;
36
+ exports.bitsToBytes = bitsToBytes;
37
+ exports.encodeHuffman = encodeHuffman;
38
+ exports.decodeHuffman = decodeHuffman;
35
39
  const ArrayUtil_1 = require("../ArrayUtil");
36
40
  // this shit is so complex so i commented it...
37
41
  // the highest 8-bit
@@ -259,14 +263,10 @@ function deconvertDouble(bytes) {
259
263
  }
260
264
  // zig_zag
261
265
  function mapZigZag(n) {
262
- return (n << 1) // shifts left (multiply by 2 to get into zigzag)
263
- ^
264
- (n >> 15); // then xor the sign away
266
+ return ((n << 1) ^ (n >> 31));
265
267
  }
266
268
  function demapZigZag(n) {
267
- return (n >>> 1) // shifts right unsigned to remove the sign & divide by 2
268
- ^
269
- -(n & 1); // flips bits to give negative back
269
+ return (n >>> 1) ^ -((n & 1));
270
270
  }
271
271
  function demapShort_ZZ(short) {
272
272
  return demapZigZag(fromShort(short));
@@ -302,3 +302,33 @@ function deconvertVarInts(arr) {
302
302
  }
303
303
  return res;
304
304
  }
305
+ function bytesToBits(bytes) {
306
+ return Array.from(bytes).map(b => b.toString(2).padStart(8, '0')).join('');
307
+ }
308
+ function bitsToBytes(bitString) {
309
+ const bytes = [];
310
+ for (let i = 0; i < bitString.length; i += 8) {
311
+ const byte = bitString.slice(i, i + 8).padEnd(8, '0');
312
+ bytes.push(parseInt(byte, 2));
313
+ }
314
+ return new Uint8Array(bytes);
315
+ }
316
+ const codeToChar = { "1000001": "w", "1000010": "m", "1000100": "u", "1000101": "c", "1000110": "l", "1000111": "d", "1001001": "r", "1001010": "h", "1001100": "s", "1001101": "n", "1001110": "i", "1001111": "o", "1010001": "a", "1010010": "t", "1010100": "e", "1010101": "", "10000000": "ˆ", "10000001": "‡", "10000111": "†", "10010000": "…", "10010001": "„", "10010111": "ƒ", "10100000": "‚", "10100001": "", "10100111": "€", "10101100": "", "10101101": "~", "10101111": "}", "10110000": "|", "10110001": "{", "10110011": "`", "10110100": "_", "10110101": "^", "10110111": "]", "10111000": "", "10111001": "[", "10111011": "@", "10111100": "?", "10111101": ">", "10111111": "=", "11000000": "<", "11000001": ";", "11000011": ":", "11000100": "9", "11000101": "8", "11000111": "7", "11001000": "6", "11001001": "5", "11001011": "4", "11001100": "3", "11001101": "2", "11001111": "1", "11010000": "0", "11010001": "/", "11010011": ".", "11010100": "-", "11010101": ",", "11010111": "+", "11011000": "*", "11011001": ")", "11011011": "(", "11011100": "'", "11011101": "&", "11011111": "$", "11100001": "#", "11100010": "\"", "11100100": "!", "11100101": "\u001f", "11100110": "\u001e", "11100111": "\u001d", "11101001": "\u001c", "11101010": "\u001b", "11101100": "\u001a", "11101101": "\u0019", "11101110": "\u0018", "11101111": "\u0017", "11110001": "\u0016", "11110010": "\u0015", "11110100": "\u0014", "11110101": "\u0013", "11110110": "\u0012", "11110111": "\u0011", "11111001": "\u0010", "11111010": "\u000f", "11111100": "\u000e", "11111101": "", "11111110": "", "11111111": "", "100001100": "Ã", "100101100": "Â", "100101101": "Á", "101001100": "À", "101011100": "¿", "101011101": "¾", "101100100": "½", "101101100": "¼", "101101101": "»", "101110100": "º", "101111100": "¹", "101111101": "¸", "110000100": "·", "110001100": "¶", "110001101": "µ", "110010100": "´", "110011100": "³", "110011101": "²", "110100100": "±", "110101100": "°", "110101101": "¯", "110110100": "®", "110111100": "­", "110111101": "%", "111000000": "¬", "111000001": "«", "111000111": "ª", "111010000": "©", "111010001": "¨", "111010111": "§", "111100000": "¦", "111100001": "¥", "111100111": "¤", "111110000": "£", "111110001": "¢", "111110111": "¡", "1000011010": "á", "1010011010": "à", "1010011011": "ß", "1011001010": "Þ", "1011101010": "Ý", "1011101011": "Ü", "1100001010": "Û", "1100101010": "Ú", "1100101011": "Ù", "1101001010": "Ø", "1101101010": "×", "1101101011": "Ö", "1110001100": "Õ", "1110101100": "Ô", "1110101101": "Ó", "1111001100": "Ò", "1111101100": "Ñ", "1111101101": "Ð", "00000000": " ", "00000001": "Ÿ", "0000001": "\n", "0000010": "", "000001100": "Ï", "0000011010": "ç", "00000110110": "ó", "000001101110": "ù", "0000011011110": "ü", "00000110111110": "þ", "00000110111111": "ý", "00000111": "ž", "0000100": "\b", "0000101": "\u0007", "0000110": "\u0006", "0000111": "\u0005", "00010000": "", "00010001": "œ", "0001001": "\u0004", "0001010": "\u0003", "000101100": "Î", "000101101": "Í", "00010111": "›", "0001100": "\u0002", "0001101": "\u0001", "0001110": "", "0001111": "Z", "00100000": "š", "00100001": "™", "0010001": "Q", "0010010": "X", "001001100": "Ì", "0010011010": "æ", "0010011011": "å", "00100111": "˜", "0010100": "J", "0010101": "K", "0010110": "V", "0010111": "B", "00110000": "—", "00110001": "–", "0011001": "P", "0011010": "Y", "001101100": "Ë", "001101101": "Ê", "00110111": "•", "0011100": "G", "0011101": "F", "0011110": "W", "0011111": "M", "01000000": "”", "01000001": "“", "0100001": "U", "0100010": "C", "010001100": "É", "0100011010": "ä", "01000110110": "ò", "01000110111": "ñ", "01000111": "’", "0100100": "L", "0100101": "D", "0100110": "R", "0100111": "H", "01010000": "‘", "01010001": "", "0101001": "S", "0101010": "N", "010101100": "È", "010101101": "Ç", "01010111": "", "0101100": "I", "0101101": "O", "0101110": "A", "0101111": "T", "01100000": "Ž", "01100001": "", "0110001": "E", "0110010": "z", "011001100": "Æ", "0110011010": "ã", "0110011011": "â", "01100111": "Œ", "0110100": "q", "0110101": "x", "0110110": "j", "0110111": "k", "01110000": "‹", "01110001": "Š", "0111001": "v", "0111010": "b", "011101100": "Å", "011101101": "Ä", "01110111": "‰", "0111100": "p", "0111101": "y", "0111110": "g", "0111111": "f", "10000110110": "ð", "100001101110": "ø", "100001101111": "÷", "10110010110": "ï", "10110010111": "î", "11000010110": "í", "110000101110": "ö", "1100001011110": "û", "1100001011111": "ú", "11010010110": "ì", "11010010111": "ë", "11100011010": "ê", "111000110110": "õ", "111000110111": "ô", "11110011010": "é", "11110011011": "è" };
317
+ const charToCode = Object.fromEntries(Object.entries(codeToChar).map(([code, char]) => [char, code]));
318
+ function encodeHuffman(text) {
319
+ return bitsToBytes(Array.from(text).map(char => charToCode[char]).join(""));
320
+ }
321
+ ;
322
+ function decodeHuffman(bits) {
323
+ let result = '';
324
+ let buffer = '';
325
+ for (const bit of bits) {
326
+ buffer += bit;
327
+ if (codeToChar[buffer]) {
328
+ result += codeToChar[buffer];
329
+ buffer = '';
330
+ }
331
+ }
332
+ return result;
333
+ }
334
+ ;
@@ -1,8 +1,9 @@
1
1
  import { Packet } from "../../packets/Packets";
2
+ import { PacketTypings } from "../../server/SonicWSServer";
2
3
  /**
3
4
  * Holds and maps packets to indexed keys and tags for serialization and lookup
4
5
  */
5
- export declare class PacketHolder<Typings extends readonly Packet<any>[], K extends Typings[number] = Typings[number], Type extends K['type'] = K['type'], Tag extends K['tag'] = K['tag']> {
6
+ export declare class PacketHolder {
6
7
  /** Current key index for packet tags */
7
8
  private key;
8
9
  /** Maps tags to keys */
@@ -17,19 +18,19 @@ export declare class PacketHolder<Typings extends readonly Packet<any>[], K exte
17
18
  * Creates a new PacketHolder with an array of packets
18
19
  * @param packets Array of packets to register
19
20
  */
20
- constructor(packets?: Typings);
21
+ constructor(packets?: PacketTypings);
21
22
  /** Assigns a new unique key to a tag */
22
- createKey(tag: Tag): void;
23
+ createKey(tag: string): void;
23
24
  /**
24
25
  * Registers an array of packets and assigns them keys
25
26
  * @param packets Array of packets to register
26
27
  */
27
- holdPackets(packets: Typings): void;
28
+ holdPackets(packets: PacketTypings): void;
28
29
  /**
29
30
  * Returns the numeric key for a given tag
30
31
  * @param tag The packet tag
31
32
  */
32
- getKey(tag: Tag): number;
33
+ getKey(tag: string): number;
33
34
  /**
34
35
  * Returns the tag associated with a given character key
35
36
  * @param key A 1-character string key
@@ -39,7 +40,7 @@ export declare class PacketHolder<Typings extends readonly Packet<any>[], K exte
39
40
  * Returns the packet instance associated with a tag
40
41
  * @param tag The packet tag
41
42
  */
42
- getPacket(tag: string): Packet<Type>;
43
+ getPacket(tag: string): Packet<any>;
43
44
  /**
44
45
  * Checks if a given character key exists
45
46
  * @param key A string index
@@ -57,7 +58,7 @@ export declare class PacketHolder<Typings extends readonly Packet<any>[], K exte
57
58
  /** Returns an array of all registered tags */
58
59
  getTags(): string[];
59
60
  /** Returns the list of all registered packets */
60
- getPackets(): Typings;
61
+ getPackets(): PacketTypings;
61
62
  /** Serializes all registered packets into a string */
62
63
  serialize(): number[];
63
64
  }
@@ -2,7 +2,6 @@ import { PacketHolder } from "./PacketHolder";
2
2
  import { ConvertType, Packet, ValidatorFunction } from "../../packets/Packets";
3
3
  import { PacketType } from "../../packets/PacketType";
4
4
  import { EnumPackage } from "../enums/EnumType";
5
- import { PacketTypings } from "../../server/SonicWSServer";
6
5
  /**
7
6
  * Processes and verifies values into a sendable format
8
7
  * @param packets Packet holder
@@ -10,7 +9,7 @@ import { PacketTypings } from "../../server/SonicWSServer";
10
9
  * @param values The values
11
10
  * @returns The indexed code, the data, and the packet schema
12
11
  */
13
- export declare function processPacket<T extends PacketTypings, K extends T[number]>(packets: PacketHolder<T>, tag: K['tag'], values: any[]): [code: number, data: number[], packet: Packet<K['type']>];
12
+ export declare function processPacket(packets: PacketHolder, tag: string, values: any[]): [code: number, data: number[], packet: Packet<any>];
14
13
  /**
15
14
  * Calls the listener for a packet with error callback
16
15
  * @param listened The listened data
@@ -95,9 +94,11 @@ export declare function CreatePacket<T extends ArguableType>(settings: SinglePac
95
94
  * @returns The constructed packet structure data.
96
95
  * @throws {Error} If any type in `types` is invalid.
97
96
  */
98
- export declare function CreateObjPacket<T extends readonly PacketType[]>(settings: MultiPacketSettings & {
97
+ export declare function CreateObjPacket<T extends readonly ArguableType[], V extends readonly PacketType[] = {
98
+ [K in keyof T]: ConvertType<T[K]>;
99
+ }>(settings: MultiPacketSettings & {
99
100
  readonly types: T;
100
- }): Packet<T>;
101
+ }): Packet<V>;
101
102
  /**
102
103
  * Creates and defines an enum packet. This can be used to create an enum-based packet
103
104
  * with a specific tag and possible values.
@@ -1,14 +1,14 @@
1
- import { SonicWSServer } from "../../server/SonicWSServer";
1
+ import { SonicWSConnection } from "../../server/SonicWSConnection";
2
2
  import { PacketHolder } from "./PacketHolder";
3
3
  export declare class RateHandler {
4
4
  private rates;
5
5
  private limits;
6
6
  private setInterval;
7
7
  private socket;
8
- constructor(host: SonicWSServer.Connection);
8
+ constructor(host: SonicWSConnection);
9
9
  start(): void;
10
10
  registerRate(tag: string, limit: number): void;
11
- registerAll(packetHolder: PacketHolder<any>, prefix: string): void;
11
+ registerAll(packetHolder: PacketHolder, prefix: string): void;
12
12
  trigger(tag: string | number): boolean;
13
13
  subtract(tag: string | number): void;
14
14
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "sonic-ws",
3
- "version": "1.0.5",
3
+ "version": "1.0.6",
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",