sonic-ws 2.0.0 → 2.0.2

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 (68) hide show
  1. package/README.md +50 -85
  2. package/bundled/bundle.js +6 -0
  3. package/bundled/bundle.wasm +0 -0
  4. package/dist/native/wasm/node/README.md +6 -0
  5. package/dist/native/wasm/node/package.json +13 -0
  6. package/dist/native/wasm/node/sonic_ws_core.d.ts +51 -0
  7. package/dist/native/wasm/node/sonic_ws_core.js +7 -0
  8. package/dist/native/wasm/node/sonic_ws_core_bg.wasm +0 -0
  9. package/dist/native/wasm/node/sonic_ws_core_bg.wasm.d.ts +36 -0
  10. package/dist/native/wasm/pkg/README.md +6 -0
  11. package/dist/native/wasm/pkg/package.json +19 -0
  12. package/dist/native/wasm/pkg/sonic_ws_core.d.ts +51 -0
  13. package/dist/native/wasm/pkg/sonic_ws_core.js +7 -0
  14. package/dist/native/wasm/pkg/sonic_ws_core_bg.js +7 -0
  15. package/dist/native/wasm/pkg/sonic_ws_core_bg.wasm +0 -0
  16. package/dist/native/wasm/pkg/sonic_ws_core_bg.wasm.d.ts +36 -0
  17. package/dist/{ts/native → native}/wrapper.d.ts +0 -1
  18. package/dist/native/wrapper.js +7 -0
  19. package/dist/{ts/ws → ws}/Connection.d.ts +4 -0
  20. package/dist/ws/Connection.js +7 -0
  21. package/dist/{ts/ws → ws}/client/core/ClientCore.d.ts +0 -5
  22. package/dist/{ts/ws → ws}/client/core/ClientCore.js +1 -1
  23. package/dist/ws/server/SonicWSServer.js +7 -0
  24. package/dist/{ts/ws → ws}/util/packets/CompressionUtil.d.ts +1 -0
  25. package/dist/ws/util/packets/CompressionUtil.js +7 -0
  26. package/dist/ws/util/packets/PacketUtils.js +7 -0
  27. package/package.json +22 -10
  28. package/dist/ts/native/wrapper.js +0 -7
  29. package/dist/ts/ws/Connection.js +0 -7
  30. package/dist/ts/ws/server/SonicWSServer.js +0 -7
  31. package/dist/ts/ws/util/packets/CompressionUtil.js +0 -7
  32. package/dist/ts/ws/util/packets/PacketUtils.js +0 -7
  33. /package/dist/{ts/index.d.ts → index.d.ts} +0 -0
  34. /package/dist/{ts/index.js → index.js} +0 -0
  35. /package/dist/{ts/version.d.ts → version.d.ts} +0 -0
  36. /package/dist/{ts/version.js → version.js} +0 -0
  37. /package/dist/{ts/ws → ws}/PacketProcessor.d.ts +0 -0
  38. /package/dist/{ts/ws → ws}/PacketProcessor.js +0 -0
  39. /package/dist/{ts/ws → ws}/client/node/ClientNode.d.ts +0 -0
  40. /package/dist/{ts/ws → ws}/client/node/ClientNode.js +0 -0
  41. /package/dist/{ts/ws → ws}/debug/DebugServer.d.ts +0 -0
  42. /package/dist/{ts/ws → ws}/debug/DebugServer.js +0 -0
  43. /package/dist/{ts/ws → ws}/packets/PacketType.d.ts +0 -0
  44. /package/dist/{ts/ws → ws}/packets/PacketType.js +0 -0
  45. /package/dist/{ts/ws → ws}/packets/Packets.d.ts +0 -0
  46. /package/dist/{ts/ws → ws}/packets/Packets.js +0 -0
  47. /package/dist/{ts/ws → ws}/server/SonicWSConnection.d.ts +0 -0
  48. /package/dist/{ts/ws → ws}/server/SonicWSConnection.js +0 -0
  49. /package/dist/{ts/ws → ws}/server/SonicWSServer.d.ts +0 -0
  50. /package/dist/{ts/ws → ws}/util/BufferUtil.d.ts +0 -0
  51. /package/dist/{ts/ws → ws}/util/BufferUtil.js +0 -0
  52. /package/dist/{ts/ws → ws}/util/StringUtil.d.ts +0 -0
  53. /package/dist/{ts/ws → ws}/util/StringUtil.js +0 -0
  54. /package/dist/{ts/ws → ws}/util/enums/EnumHandler.d.ts +0 -0
  55. /package/dist/{ts/ws → ws}/util/enums/EnumHandler.js +0 -0
  56. /package/dist/{ts/ws → ws}/util/enums/EnumType.d.ts +0 -0
  57. /package/dist/{ts/ws → ws}/util/enums/EnumType.js +0 -0
  58. /package/dist/{ts/ws → ws}/util/packets/BatchHelper.d.ts +0 -0
  59. /package/dist/{ts/ws → ws}/util/packets/BatchHelper.js +0 -0
  60. /package/dist/{ts/ws → ws}/util/packets/HashUtil.d.ts +0 -0
  61. /package/dist/{ts/ws → ws}/util/packets/HashUtil.js +0 -0
  62. /package/dist/{ts/ws → ws}/util/packets/JSONUtil.d.ts +0 -0
  63. /package/dist/{ts/ws → ws}/util/packets/JSONUtil.js +0 -0
  64. /package/dist/{ts/ws → ws}/util/packets/PacketHolder.d.ts +0 -0
  65. /package/dist/{ts/ws → ws}/util/packets/PacketHolder.js +0 -0
  66. /package/dist/{ts/ws → ws}/util/packets/PacketUtils.d.ts +0 -0
  67. /package/dist/{ts/ws → ws}/util/packets/RateHandler.d.ts +0 -0
  68. /package/dist/{ts/ws → ws}/util/packets/RateHandler.js +0 -0
package/README.md CHANGED
@@ -46,7 +46,7 @@ Security:
46
46
  - Prevents niche bugs found in other websocket libraries, such as functions calling after the socket already closed.
47
47
 
48
48
  Performance & Scaling:
49
- - Can handle very large packets in microseconds
49
+ - Can parse very large packets in microseconds
50
50
  - Can support megabytes of data and millions of values with minimal latency
51
51
  - Can broadcast to a filtered list of connections such as all, except sender, or any other subset
52
52
  - Built-in packet batching feature with no boilerplate and with per-client queues and bandwidth efficiency
@@ -70,110 +70,62 @@ Whether you're making a real-time game, a dashboard, a distributed system, or an
70
70
 
71
71
  You define the packets each side is allowed to send. SonicWS exchanges that schema during the connection handshake, assigns compact numeric packet IDs, and validates incoming data before calling your listeners.
72
72
 
73
- The TypeScript layer handles connections, packet definitions, middleware, and the public API. The Rust core handles the wire format:
73
+ The TypeScript/python layer handles connections, packet definitions, middleware, and the public API. The Rust core handles the wire format:
74
74
 
75
75
  - Primitive and object packet encoding/decoding
76
76
  - Packet validation and range checks
77
77
  - Enum, string, boolean, varint, delta, float, and hex codecs
78
78
  - Object framing, batching, and raw DEFLATE compression
79
- - TypeScript-side JSON conversion transported through reserved wire type 16 as raw bytes
79
+ - TypeScript/Python-side JSON conversion transported through reserved wire type 16 as raw bytes
80
80
 
81
81
  The same Rust implementation is exposed through N-API for native Node use and through WASM for browsers and the portable Node fallback. Protocol behavior therefore does not depend on which runtime is connected.
82
82
 
83
- ## INSTALLATION
84
-
85
- ```sh
86
- npm install sonic-ws
87
- ```
83
+ Automatic browser-file serving at `/SonicWS/bundle.js` and
84
+ `/SonicWS/bundle.wasm` is supported only by the Node.js server, where it can be
85
+ installed directly on the native HTTP server. If the SonicWS server is written
86
+ in Python or another language, serve the browser files yourself or use the CDN
87
+ bundle:
88
88
 
89
- ## SAMPLES
90
-
91
- ### Node (Client & Server)
92
- ```js
93
- import { SonicWS, SonicWSServer, CreatePacket, PacketType } from "sonic-ws";
94
- ```
95
-
96
- Browser (Client):
97
89
  ```html
98
- <script src="/SonicWS/bundle.js"></script>
99
- <script>
100
- async function connect() {
101
- await SonicWS.initialize();
102
- const ws = new SonicWS(`ws://${location.host}`);
103
- // Register listeners and send packets here.
104
- }
105
-
106
- connect();
107
- </script>
90
+ <script src="https://cdn.jsdelivr.net/gh/liwybloc/sonic-ws/release/SonicWS_bundle"></script>
108
91
  ```
109
92
 
110
- `SonicWSServer` serves this browser bundle and its WASM module automatically at
111
- `/SonicWS/bundle.js` and `/SonicWS/bundle.wasm`. Set
112
- `sonicServerSettings.serveBrowserClient` to `false` to disable these routes.
113
-
114
- The WASM core must finish initializing before constructing a browser client. Node initializes its codec automatically.
93
+ The browser loader prefers the server's local `bundle.wasm`. If it isn't
94
+ available, it verifies that jsDelivr's release protocol matches the client and
95
+ then loads the CDN WASM module. Initialization fails on a version mismatch or
96
+ invalid download.
115
97
 
116
- ### Simple Example: Clicker Server
117
-
118
- #### Server
119
- ```js
120
- const wss = new SonicWSServer({
121
- clientPackets: [
122
- CreatePacket({ tag: "click", type: PacketType.NONE }),
123
- CreatePacket({ tag: "token", type: PacketType.STRINGS }),
124
- ],
125
- serverPackets: [
126
- CreatePacket({ tag: "pointsInfo", type: PacketType.UVARINT }),
127
- CreatePacket({ tag: "notification", type: PacketType.STRINGS }),
128
- ],
129
- websocketOptions: { port: 1234 },
130
- });
131
-
132
- wss.requireHandshake("token");
133
-
134
- wss.on_connect(ws => {
135
- console.log("Client connected:", ws.id);
136
-
137
- let clicks = 0;
138
-
139
- ws.on("token", token => {
140
- if(!isValidToken(token)) // No listeners will ever trigger after this, unlike base websocket
141
- return ws.close();
142
- })
143
-
144
- // auto validation, no boilerplate. always passed the token check
145
- ws.on("click", () => {
146
- ws.send("pointsInfo", ++clicks);
147
- });
148
-
149
- ws.setInterval(() => ws.send("notification", "Keep going!"), 5000); // auto cleanup on close
150
- });
98
+ ## INSTALLATION
151
99
 
152
- wss.on_ready(() => console.log("Server ready!"));
100
+ NodeJS/Typescript:
101
+ ```sh
102
+ npm install sonic-ws
103
+ ```
104
+ Python* (*unpublished currently):
105
+ ```sh
106
+ pip install sonic-ws
153
107
  ```
154
108
 
155
- #### Client
156
- ```js
157
- await SonicWS.initialize();
158
- const ws = new SonicWS("ws://localhost:1234");
159
-
160
- ws.on_ready(() => console.log("Connected to server"));
161
-
162
- ws.on("pointsInfo", clicks => console.log("Total Clicks: ", clicks));
109
+ ## BUILDING AND TESTING
163
110
 
164
- ws.on("notification", msg => console.log("Notification:", msg));
111
+ Building requires Node.js, Rust with the `wasm32-unknown-unknown` target, and `wasm-pack`.
165
112
 
166
- button.addEventListener("click", () => {
167
- ws.send("click");
168
- });
113
+ From the repository root, use the build dispatcher:
169
114
 
115
+ ```sh
116
+ ./build.sh all # Build every project
117
+ ./build.sh rust # Rust core only
118
+ ./build.sh ts # Complete Node/browser package
119
+ ./build.sh py # Python wheel and sdist
120
+ ./build.sh test # Run all test suites
121
+ ./build.sh help # List every target
170
122
  ```
171
123
 
172
- ## BUILDING AND TESTING
173
-
174
- Building requires Node.js, Rust with the `wasm32-unknown-unknown` target, and `wasm-pack`.
124
+ The underlying TypeScript commands can also be run directly:
175
125
 
176
126
  ```sh
127
+ cd projects/ts
128
+ npm install
177
129
  npm run build # TypeScript, Node WASM, browser WASM, and browser bundle
178
130
  npm run build_node # Node distribution and WASM fallback
179
131
  npm run build_web # Browser bundle and WASM
@@ -181,7 +133,20 @@ npm run test_node # Node end-to-end packet tests
181
133
  npm run test_web # Headless browser/WASM end-to-end tests
182
134
  ```
183
135
 
184
- The Rust crate lives in `src/core`, and the TypeScript API lives in `src/ts`. Generated JavaScript is written to `dist/ts`; browser artifacts are written to `bundled/bundle.js` and `bundled/bundle.wasm`.
136
+ The workspace is split into `projects/core`, `projects/ts`, and `projects/py`.
137
+ Each project owns its source, tests, and packaging configuration. Shared browser
138
+ artifacts remain at `bundled/bundle.js` and `bundled/bundle.wasm`.
139
+
140
+ Build or install the Python project separately:
141
+
142
+ ```sh
143
+ python -m pip install ./projects/py
144
+ ```
145
+
146
+ Full API documentation:
147
+
148
+ - [TypeScript / Node / browser](docs/ts/README.md)
149
+ - [Python](docs/py/README.md)
185
150
 
186
151
  ## KNOWN ISSUES
187
152
 
@@ -191,8 +156,8 @@ The Rust crate lives in `src/core`, and the TypeScript API lives in `src/ts`. Ge
191
156
  ## PLANNED FEATURES
192
157
  - Better encoding for the first packet that sends packet information
193
158
  - Publish the Rust core as a standalone, documented crate
194
- - Add first-class Python and Go bindings
195
- - Provide prebuilt N-API binaries for the main Node platforms
159
+ - Add first-class Go bindings
160
+ - Provide prebuilt N-API binaries for the main Node platforms to avoid using WASM for the server
196
161
 
197
162
  ## LICENSE
198
163
  This project is source-available.
@@ -0,0 +1,6 @@
1
+ /*!
2
+ * Copyright (c) 2026 Lily (liwybloc)
3
+ * License-Identifier: LicenseRef-Lily-Personal-NonCommercial-2026
4
+ * See LICENSE for personal, non-commercial license terms.
5
+ */
6
+ (()=>{"use strict";var __webpack_modules__={8(e,t,n){Object.defineProperty(t,"__esModule",{value:!0}),t.BatchHelper=void 0;const a=n(950),r=n(351);t.BatchHelper=class{batchInfo={};batchTimeouts={};batchedData={};conn;registerSendPackets(e,t){this.conn=t,e.getTags().forEach(t=>{const n=e.getPacket(t);if(0==n.dataBatching)return;const a=e.getKey(t);this.initiateBatch(a,n.dataBatching,n.gzipCompression)})}initiateBatch(e,t,n){this.batchedData[e]=[],this.batchInfo[e]=[t,n]}startBatch(e){const[t,n]=this.batchInfo[e];this.batchTimeouts[e]=this.conn.setInterval(()=>{if(0==this.batchedData[e].length)return;const t=(0,r.encodeNativeBatch)(this.batchedData[e],n);this.conn.raw_send((0,a.toPacketBuffer)(e,t)),this.batchedData[e]=[],delete this.batchTimeouts[e]},t)}batchPacket(e,t){this.batchedData[e].push(t),this.batchTimeouts[e]||this.startBatch(e)}static async unravelBatch(e,t,n){let a;try{a=(0,r.decodeNativeBatch)(t,e.gzipCompression,e.maxBatchSize)}catch(e){return"Invalid batch: "+e}const s=[];for(const t of a){const a=await e.listen(t,n);if("string"==typeof a)return"Batched packet: "+a;s.push([a[0],!e.dontSpread])}return s}}},30(e,t){Object.defineProperty(t,"__esModule",{value:!0}),t.decompressBools=t.compressBools=t.EMPTY_UINT8=t.MAX_UVARINT=t.MAX_USHORT=t.MAX_BYTE=void 0,t.convertVarInt=function(e){if(!Number.isSafeInteger(e)||e<0||e>t.MAX_UVARINT)throw new Error(`Variable Ints must be within range 0 and ${t.MAX_UVARINT}: ${e}`);const n=[];do{let t=e%128;(e=Math.floor(e/128))>0&&(t|=128),n.push(t)}while(e>0);return n},t.readVarInt=function(e,t){let n=0,a=1;for(let r=0;r<8;r++){if(t>=e.length)throw new Error("Truncated variable integer");const r=e[t++];if(n+=(127&r)*a,!(128&r))return[t,n];a*=128}throw new Error("Variable integer is too long")},t.MAX_BYTE=255,t.MAX_USHORT=65535,t.MAX_UVARINT=128**7-1,t.EMPTY_UINT8=new Uint8Array([]);t.compressBools=e=>e.reduce((e,t,n)=>e|Number(t)<<7-n,0);t.decompressBools=e=>Array.from({length:8},(t,n)=>!!(e&1<<7-n))},72(e,t,n){Object.defineProperty(t,"__esModule",{value:!0}),t.decompressJSON=t.compressJSON=void 0;const a=n(950),r=e=>Array.from({length:8},(t,n)=>!!(e&1<<7-n));function s(e){if(!Number.isInteger(e)||e<0)throw new Error(`Invalid JSON variable integer: ${e}`);const t=[];do{let n=127&e;(e>>>=7)>0&&(n|=128),t.push(n)}while(e>0);return t}function i(e,t){let n=0,a=0;for(;;){if(t>=e.length||a>28)throw new Error("Invalid JSON variable integer");const r=e[t++];if(n+=(127&r)<<a,!(128&r))return[t,n];a+=7}}var o;!function(e){e[e.NULL=0]="NULL",e[e.BOOL=1]="BOOL",e[e.INT=2]="INT",e[e.FLOAT=3]="FLOAT",e[e.STRING=4]="STRING",e[e.ARRAY=5]="ARRAY",e[e.OBJECT=6]="OBJECT"}(o||(o={}));const c=e=>{const t=(new TextEncoder).encode(e);return[...s(t.length),...t]},d=(e,t)=>{const[n,a]=i(e,t);return{value:(new TextDecoder).decode(e.subarray(n,n+a)),length:n+a-t}},l=e=>{let t="";for(const n of e)t+=n.toString(2).padStart(3,"0");return(e=>new Uint8Array(e.match(/.{1,8}/g)?.map(e=>parseInt(e.padEnd(8,"0"),2))??[]))(t)},u=(e,t)=>{const n=(e=>Array.from(e,e=>e.toString(2).padStart(8,"0")).join(""))(e),a=[];for(let e=0;e<t;e++)a.push(parseInt(n.slice(3*e,3*e+3),2));return a};t.compressJSON=e=>{const t=[],n=[],r=[],i=e=>{switch(null===e?"null":Array.isArray(e)?"array":typeof e){case"null":r.push(o.NULL);break;case"boolean":r.push(o.BOOL),t.push(e);break;case"number":Number.isInteger(e)?(r.push(o.INT),n.push(...s((e=>e<<1^e>>31)(e)))):(r.push(o.FLOAT),n.push(...function(e){if(Number.isNaN(e))return[127,128,0,1];const t=e<0?1:0;if(0===(e=Math.abs(e)))return[0,0,0,0];const n=Math.floor(Math.log2(e));if(!Number.isFinite(e)||n>127||n<-126)return[t?255:127,128,0,0];const a=(t<<31|n+127<<23|8388607&Math.round((e/2**n-1)*2**23))>>>0;return[a>>>24,a>>>16&255,a>>>8&255,255&a]}(e)));break;case"string":r.push(o.STRING),n.push(...c(e));break;case"array":r.push(o.ARRAY),n.push(...s(e.length));for(const t of e)i(t);break;case"object":{r.push(o.OBJECT);const t=Object.keys(e);n.push(...s(t.length));for(const a of t)n.push(...c(a)),i(e[a]);break}default:throw new Error("Unsupported type")}};i(e);const d=t.length?(0,a.splitArray)(t,8).map(e=>e.reduce((e,t,n)=>e|Number(t)<<7-n,0)):[],u=l(r),h=[...s(d.length),...s(u.length)];return Uint8Array.from([...h,...d.flat(),...u,...n])};t.decompressJSON=e=>{let t=0;const[n,a]=i(e,t);t=n;const[s,c]=i(e,t);t=s;const l=[];for(let n=0;n<a;n++)l.push(...r(e[t++]));let h=0;const p=e.subarray(t,t+c);t+=c;const f=u(p,8*p.length/3);let w=0;const _=n=>{if(n>500)throw new Error("JSON array too deep.");const a=f[w++];switch(a){case o.NULL:return null;case o.BOOL:return l[h++];case o.INT:{const[n,a]=i(e,t);return t=n,(r=a)>>>1^-(1&r)}case o.FLOAT:{const n=function(e){const t=(e[0]<<24|e[1]<<16|e[2]<<8|e[3])>>>0,n=t>>>23&255,a=(0===n?0:1)+(8388607&t)/2**23,r=255===n?0===a?1/0:NaN:a*2**(0===n?-126:n-127);return t>>>31?-r:r}(Array.from(e.subarray(t,t+4)));return t+=4,n}case o.STRING:{const{value:n,length:a}=d(e,t);return t+=a,n}case o.ARRAY:{const[a,r]=i(e,t);t=a;const s=[];for(let e=0;e<r;e++)s.push(_(n+1));return s}case o.OBJECT:{const[a,r]=i(e,t);t=a;const s={};for(let a=0;a<r;a++){const{value:a,length:r}=d(e,t);t+=r,s[a]=_(n+1)}return s}default:throw new Error(`Unknown type ${a}`)}var r};return _(0)}},98(e,t,n){Object.defineProperty(t,"__esModule",{value:!0}),t.EnumPackage=t.TYPE_CONVERSION_MAP=void 0;const a=n(157),r=n(388),s={string:0,number:1,boolean:2,undefined:3,object:4};function i(e){const t=typeof e;if(!(t in s)&&null!=e)throw new Error(`Cannot serialize type "${t}" in an enum!`);return s[t]}t.TYPE_CONVERSION_MAP={0:e=>e,1:e=>parseFloat(e),2:e=>"true"==e,3:()=>{},4:()=>null};t.EnumPackage=class{tag;values;constructor(e,t){this.tag=e,this.values=t,this.wrap=this.wrap.bind(this)}serialize(){const e=(0,a.processCharCodes)(this.tag);return[this.tag.length,...e,this.values.length,...this.values.map(e=>[String(e).length,i(e),...(0,a.processCharCodes)(String(e))]).flat()]}wrap(e){return(0,r.WrapEnum)(this.tag,e)}}},102(e,t,n){Object.defineProperty(t,"__esModule",{value:!0}),t.PacketSchema=t.Packet=void 0;const a=n(388),r=n(98),s=n(30),i=n(433),o=n(619),c=n(157),d=n(351),l=n(72);class u{defaultEnabled;tag;maxSize;minSize;type;enumData;dataMax;dataMin;dataBatching;maxBatchSize;dontSpread;autoFlatten;rateLimit;async;rereference;gzipCompression;object;client;processReceive;processSend;validate;customValidator;lastReceived={};lastSent={};constructor(e,t,n,a,r){if(this.tag=e,this.defaultEnabled=a,this.client=r,this.async=t.async,this.enumData=t.enumData,this.rateLimit=t.rateLimit,this.dontSpread=t.dontSpread,this.autoFlatten=t.autoFlatten,this.rereference=t.rereference,this.dataBatching=t.dataBatching,this.maxBatchSize=r?1/0:t.maxBatchSize,this.gzipCompression=t.gzipCompression,this.object=t.object,this.type=t.type,this.dataMax=t.dataMax,this.dataMin=t.dataMin,t.testObject(this)){this.maxSize=this.minSize=this.type.length;for(let e=0;e<this.type.length;e++)this.type[e]==o.PacketType.NONE&&(this.dataMax[e]=this.dataMin[e]=0);const e={types:this.type,dataMins:this.dataMin,dataMaxes:this.dataMax,enumData:this.enumData};this.processReceive=t=>(0,d.decodeNativeObject)(e,t).map((e,t)=>this.type[t]===o.PacketType.JSON?(0,l.decompressJSON)(e):e),this.processSend=async t=>{let n=0;const a=t.map((e,t)=>{if(this.type[t]===o.PacketType.JSON)return(0,l.compressJSON)(e);if(this.type[t]!==o.PacketType.ENUMS)return e;const a=this.enumData[n++];return(Array.isArray(e)?e:[e]).map(e=>{if(!Number.isInteger(e)||e<0||e>=a.values.length)throw new Error(`Invalid wrapped enum index: ${e}`);return a.values[e]})});return(0,d.encodeNativeObject)(e,a)},this.validate=async t=>{(0,d.validateNativeObject)(e,t);return(0,d.decodeNativeObject)(e,t).forEach((e,t)=>{if(this.type[t]!==o.PacketType.JSON)return;const n=(0,l.decompressJSON)(e),a=Array.isArray(n)?n.length:1;if(a<this.dataMin[t]||a>this.dataMax[t])throw new Error("JSON value count is outside schema limits")}),[t,!0]}}else{{this.maxSize=this.dataMax,this.minSize=this.dataMin,this.type==o.PacketType.NONE&&(this.dataMax=this.dataMin=0);const e=this.enumData[0];this.processReceive=t=>this.type===o.PacketType.JSON?(0,l.decompressJSON)(t):(0,d.decodeNative)(this.type,t,this.dataMax,e),this.processSend=async t=>{let n;if(this.type===o.PacketType.JSON)n=(0,l.compressJSON)(t);else if(this.type===o.PacketType.ENUMS)n=Uint8Array.from(t);else{const a=this.type===o.PacketType.RAW&&1===t.length&&t[0]instanceof Uint8Array?t[0]:t;n=(0,d.encodeNative)(this.type,a,e)}return this.gzipCompression&&0===this.dataBatching?(0,d.deflateNative)(n):n},this.validate=async t=>{const n=this.gzipCompression&&0===this.dataBatching?(0,d.inflateNative)(t):t;if(this.type===o.PacketType.JSON){const e=(0,l.decompressJSON)(n),t=Array.isArray(e)?e.length:1;if(t<this.dataMin||t>this.dataMax)throw new Error("JSON value count is outside schema limits")}else(0,d.validateNative)(this.type,n,this.dataMin,this.dataMax,{enumData:e});return[n,!0]}}}this.customValidator=n}async listen(e,t){try{const[n,a]=await this.validate(e);if(!this.client&&!1===a)return"Invalid packet";const r=this.processReceive(n,a),s=this.autoFlatten?(0,i.UnFlattenData)(r):r;if(null!=this.customValidator)if(this.dontSpread){if(!this.customValidator(t,s))return"Didn't pass custom validator"}else if(!this.customValidator(t,...s))return"Didn't pass custom validator";return[s,!this.dontSpread]}catch(e){return console.error("There was an error processing the packet! This is probably my fault... report at https://github.com/liwybloc/sonic-ws",e),"Error: "+e}}serialize(){const e=[this.tag.length,...(0,c.processCharCodes)(this.tag),(0,s.compressBools)([this.dontSpread,this.async,this.object,this.autoFlatten,this.gzipCompression,this.rereference]),this.dataBatching,this.enumData.length,...this.enumData.map(e=>e.serialize()).flat()];return this.object?[...e,this.maxSize,...this.dataMax.map(s.convertVarInt).flat(),...this.dataMin.map(s.convertVarInt).flat(),...this.type]:[...e,...(0,s.convertVarInt)(this.dataMax),...(0,s.convertVarInt)(this.dataMin),this.type]}static readVarInts(e,t,n){const a=[];for(let r=0;r<n;r++){const[n,r]=(0,s.readVarInt)(e,t);t=n,a.push(r)}return[a,t]}static deserialize(e,t,n){const i=t,d=e[t++],l=(0,c.as8String)(e.slice(t,t+=d)),[h,f,w,_,y,m]=(0,s.decompressBools)(e[t++]),g=e[t++],b=e[t++],v=[];for(let n=0;n<b;n++){const n=e[t++],s=(0,c.as8String)(e.slice(t,t+=n)),i=e[t++],o=[];for(let n=0;n<i;n++){const n=e[t++],a=e[t++],s=(0,c.as8String)(e.slice(t,t+=n));o.push(r.TYPE_CONVERSION_MAP[a](s))}v.push((0,a.DefineEnum)(s,o))}if(w){const a=e[t++],[r,s]=this.readVarInts(e,t,a);t=s;const[c,d]=this.readVarInts(e,t,a);t=d;const w=Array.from(e.slice(t,t+=a));let m=0;const b=w.map(e=>e==o.PacketType.ENUMS?v[m++]:e),S=new p(!0,b,f,c,r,-1,h,_,!1,g,-1,y);return[new u(l,S,null,!1,n),t-i]}const[S,k]=(0,s.readVarInt)(e,t);t=S;const[E,T]=(0,s.readVarInt)(e,t);t=E;const N=e[t++],P=N==o.PacketType.ENUMS?v[0]:N,A=new p(!1,P,f,T,k,-1,h,!1,m,g,-1,y);return[new u(l,A,null,!1,n),t-i]}static deserializeAll(e,t){const n=[];let a=0;for(;a<e.length;){const[r,s]=this.deserialize(e,a,t);n.push(r),a+=s}return n}}t.Packet=u;const h=(e,t)=>e instanceof r.EnumPackage?(t.push(e),o.PacketType.ENUMS):e;class p{type;enumData=[];dataMax;dataMin;dataBatching;maxBatchSize;rateLimit;dontSpread=!1;autoFlatten=!1;async=!1;rereference=!1;gzipCompression=!1;object;constructor(e,t,n,a,r,s,i,o,c,d,l,u){this.object=e,this.async=n,this.dataMin=a,this.dataMax=r,this.rateLimit=s,this.dontSpread=i,this.autoFlatten=o,this.rereference=c,this.dataBatching=d,this.maxBatchSize=l,this.gzipCompression=u,this.type=e?t.map(e=>h(e,this.enumData)):h(t,this.enumData)}testObject(e){return this.object}}t.PacketSchema=p},157(e,t){function n(e){return String.fromCodePoint(...e)}Object.defineProperty(t,"__esModule",{value:!0}),t.processCharCodes=function(e){return Array.from(e,e=>e.codePointAt(0))},t.convertCharCodes=n,t.as8String=function(e){return n(Array.from(e))}},234(e,t,n){Object.defineProperty(t,"__esModule",{value:!0}),t.SERVER_SUFFIX_NUMS=t.SERVER_SUFFIX=t.VERSION=void 0;const a=n(157);t.VERSION=22,t.SERVER_SUFFIX="SWS",t.SERVER_SUFFIX_NUMS=(0,a.processCharCodes)(t.SERVER_SUFFIX)},351(__unused_webpack_module,exports,__webpack_require__){var __webpack_dirname__="/";Object.defineProperty(exports,"__esModule",{value:!0}),exports.setNativeCore=setNativeCore,exports.initializeWasmCore=initializeWasmCore,exports.loadNativeCore=loadNativeCore,exports.encodeNative=encodeNative,exports.decodeNative=decodeNative,exports.validateNative=validateNative,exports.encodeNativeObject=encodeNativeObject,exports.decodeNativeObject=decodeNativeObject,exports.validateNativeObject=validateNativeObject,exports.encodeNativeBatch=encodeNativeBatch,exports.decodeNativeBatch=decodeNativeBatch,exports.deflateNative=deflateNative,exports.inflateNative=inflateNative;const PacketType_1=__webpack_require__(619),version_1=__webpack_require__(234),CDN_RELEASE="https://cdn.jsdelivr.net/gh/liwybloc/sonic-ws/release",CDN_WASM=`${CDN_RELEASE}/bundle.wasm`,CDN_VERSION=`${CDN_RELEASE}/version`;let loadedCore,wasmInitialization;function buffer(e){return"undefined"!=typeof Buffer?Buffer.from(e.buffer,e.byteOffset,e.byteLength):new Uint8Array(e.buffer,e.byteOffset,e.byteLength)}function values(e){return Array.isArray(e)?[...e]:[e]}function assertNativeCore(e){const t=["encodeSigned","decodeSigned","encodeUnsigned","decodeUnsigned","encodeFloats","decodeFloats","encodeStrings","decodeStrings","encodeBooleans","decodeBooleans","decodeRaw","encodeHex","decodeHex","frameObject","unframeObject","encodeBatch","decodeBatch","deflateRaw","inflateRaw","validateEncoded","validateEnum","validateObject"].filter(t=>"function"!=typeof e[t]);if(t.length>0)throw new Error(`Invalid SonicWS native addon; missing: ${t.join(", ")}`)}function setNativeCore(e){assertNativeCore(e),loadedCore=e}function fetchUrl(e){return"string"==typeof e?e:e instanceof URL?e.href:e.url}async function isWasm(e){if(!e.ok)return!1;const t=new Uint8Array(await e.clone().arrayBuffer());return t.length>=4&&0===t[0]&&97===t[1]&&115===t[2]&&109===t[3]}async function fetchCdnWasm(e){const t=await e(CDN_VERSION,{cache:"no-store"});if(!t.ok)throw new Error(`Unable to verify SonicWS CDN protocol version (${t.status})`);const n=Number((await t.text()).trim());if(!Number.isInteger(n)||n!==version_1.VERSION)throw new Error(`SonicWS CDN protocol mismatch: expected ${version_1.VERSION}, received ${String(n)}`);const a=await e(CDN_WASM);if(!await isWasm(a))throw new Error("SonicWS CDN returned an invalid WASM module");return a}async function initializeBrowserWasm(){const e=window.fetch.bind(window);window.fetch=async(t,n)=>{const a=fetchUrl(t);if(a===CDN_WASM||!new URL(a,window.location.href).pathname.endsWith("/bundle.wasm"))return e(t,n);try{const a=await e(t,n);if(await isWasm(a))return a}catch{}return fetchCdnWasm(e)};try{return setNativeCore(await Promise.resolve().then(__webpack_require__.bind(__webpack_require__,880))),loadedCore}finally{window.fetch=e}}function initializeWasmCore(){return loadedCore?Promise.resolve(loadedCore):wasmInitialization||(wasmInitialization=(async()=>{if("undefined"!=typeof window)return initializeBrowserWasm();const wasm=eval("require")("./wasm/node/sonic_ws_core.js");return setNativeCore(wasm),loadedCore})().finally(()=>{wasmInitialization=void 0}),wasmInitialization)}function loadNativeCore(addonPath){if(loadedCore&&!addonPath)return loadedCore;const candidates=addonPath?[addonPath]:["undefined"!=typeof process?process.env.SONIC_WS_CORE_PATH:void 0,`${__webpack_dirname__}/sonic_ws_core.node`,`${__webpack_dirname__}/../../../native/sonic_ws_core.node`].filter(e=>Boolean(e)),failures=[],nodeRequire="undefined"==typeof window?eval("require"):void 0;for(const e of candidates)try{const t=nodeRequire(e);return assertNativeCore(t),addonPath||(loadedCore=t),t}catch(t){failures.push(`${e}: ${t instanceof Error?t.message:String(t)}`)}if("undefined"==typeof window)try{const e=nodeRequire("./wasm/node/sonic_ws_core.js");return assertNativeCore(e),loadedCore=e,e}catch(e){failures.push(`Node WASM fallback: ${e instanceof Error?e.message:String(e)}`)}throw new Error(`SonicWS codec is not initialized. In Node, set SONIC_WS_CORE_PATH; in browsers, await initializeWasmCore().\n${failures.join("\n")}`)}function enumIndex(e,t){const n=e.values.findIndex(e=>e===t||"number"==typeof e&&"number"==typeof t&&Number.isNaN(e)&&Number.isNaN(t));if(n<0)throw new Error(`Value ${String(t)} does not exist in enum ${e.tag}`);return n}function encodeNative(e,t,n,a=loadNativeCore()){switch(e){case PacketType_1.PacketType.NONE:if(null!=t&&(!Array.isArray(t)||0!==t.length))throw new TypeError("NONE only accepts null, undefined, or an empty array");return new Uint8Array(0);case PacketType_1.PacketType.RAW:case PacketType_1.PacketType.JSON:if(!(t instanceof Uint8Array||Array.isArray(t)))throw new TypeError((e===PacketType_1.PacketType.JSON?"JSON wire data":"RAW")+" requires a Uint8Array or number array");return t instanceof Uint8Array?buffer(t):Uint8Array.from(t);case PacketType_1.PacketType.BYTES:case PacketType_1.PacketType.SHORTS:case PacketType_1.PacketType.VARINT:case PacketType_1.PacketType.DELTAS:return a.encodeSigned(e,values(t));case PacketType_1.PacketType.UBYTES:case PacketType_1.PacketType.USHORTS:case PacketType_1.PacketType.UVARINT:return a.encodeUnsigned(e,values(t));case PacketType_1.PacketType.FLOATS:case PacketType_1.PacketType.DOUBLES:return a.encodeFloats(e,values(t));case PacketType_1.PacketType.STRINGS_ASCII:case PacketType_1.PacketType.STRINGS_UTF16:return a.encodeStrings(e,values(t));case PacketType_1.PacketType.BOOLEANS:return a.encodeBooleans(values(t));case PacketType_1.PacketType.HEX:{const e=Array.isArray(t)?t[0]:t;if("string"!=typeof e)throw new TypeError("HEX requires one string");return a.encodeHex(e)}case PacketType_1.PacketType.ENUMS:if(!n)throw new Error("ENUMS requires an EnumPackage");return Uint8Array.from(values(t).map(e=>enumIndex(n,e)));case PacketType_1.PacketType.KEY_EFFECTIVE:throw new Error("KEY_EFFECTIVE is not implemented");default:throw new Error(`Unknown packet type: ${e}`)}}function decodeNative(e,t,n=4294967295,a,r=loadNativeCore()){const s=buffer(t);switch(e){case PacketType_1.PacketType.NONE:if(0!==t.byteLength)throw new Error("NONE packet contains data");return;case PacketType_1.PacketType.RAW:case PacketType_1.PacketType.JSON:return r.decodeRaw(s);case PacketType_1.PacketType.BYTES:case PacketType_1.PacketType.SHORTS:case PacketType_1.PacketType.VARINT:case PacketType_1.PacketType.DELTAS:return r.decodeSigned(e,s);case PacketType_1.PacketType.UBYTES:case PacketType_1.PacketType.USHORTS:case PacketType_1.PacketType.UVARINT:return r.decodeUnsigned(e,s);case PacketType_1.PacketType.FLOATS:case PacketType_1.PacketType.DOUBLES:return r.decodeFloats(e,s);case PacketType_1.PacketType.STRINGS_ASCII:case PacketType_1.PacketType.STRINGS_UTF16:return r.decodeStrings(e,s);case PacketType_1.PacketType.BOOLEANS:return r.decodeBooleans(s,n);case PacketType_1.PacketType.HEX:return r.decodeHex(s);case PacketType_1.PacketType.ENUMS:if(!a)throw new Error("ENUMS requires an EnumPackage");return[...t].map(e=>{if(e>=a.values.length)throw new Error(`Enum index ${e} is out of range`);return a.values[e]});case PacketType_1.PacketType.KEY_EFFECTIVE:throw new Error("KEY_EFFECTIVE is not implemented");default:throw new Error(`Unknown packet type: ${e}`)}}function validateNative(e,t,n,a,r={},s=loadNativeCore()){if(e!==PacketType_1.PacketType.ENUMS)s.validateEncoded(e,buffer(t),n,a,r.compressed??!1,r.batched??!1,r.maxBatchSize);else{if(!r.enumData)throw new Error("ENUMS requires an EnumPackage");s.validateEnum(buffer(t),r.enumData.values.length,n,a)}}function encodeNativeObject(e,t,n=loadNativeCore()){if(t.length!==e.types.length)throw new Error("Object field count does not match schema");let a=0;const r=e.types.map((r,s)=>encodeNative(r,t[s],r===PacketType_1.PacketType.ENUMS?e.enumData?.[a++]:void 0,n));return n.frameObject(r)}function decodeNativeObject(e,t,n=loadNativeCore()){const a=n.unframeObject(buffer(t),e.types.length);let r=0;return a.map((t,a)=>decodeNative(e.types[a],t,e.dataMaxes[a],e.types[a]===PacketType_1.PacketType.ENUMS?e.enumData?.[r++]:void 0,n))}function validateNativeObject(e,t,n=loadNativeCore()){n.validateObject(buffer(t),[...e.types],[...e.dataMins],[...e.dataMaxes],(e.enumData??[]).map(e=>e.values.length))}function encodeNativeBatch(e,t,n=loadNativeCore()){return n.encodeBatch(e.map(buffer),t)}function decodeNativeBatch(e,t,n=0,a,r=loadNativeCore()){const s=Number.isFinite(n)&&n>0?n:0;return r.decodeBatch(buffer(e),t,s,a)}function deflateNative(e,t=loadNativeCore()){return t.deflateRaw(buffer(e))}function inflateNative(e,t,n=loadNativeCore()){return n.inflateRaw(buffer(e),t)}},388(e,t,n){Object.defineProperty(t,"__esModule",{value:!0}),t.SET_PACKAGES=t.ENUM_KEY_TO_TAG=t.ENUM_TAG_TO_KEY=t.MAX_ENUM_SIZE=void 0,t.DefineEnum=function(e,n){const a=t.SET_PACKAGES[e];if(a){if(a.values.find((e,t)=>n[t]!=e))throw new Error(`Pre-existing enum package of tag '${e}' is set and different!`);return a}if(n.length>t.MAX_ENUM_SIZE)throw new Error(`An enum can only hold ${t.MAX_ENUM_SIZE} possible values.`);return t.ENUM_TAG_TO_KEY[e]=Object.fromEntries(n.map((e,t)=>[e,t])),t.ENUM_KEY_TO_TAG[e]=Object.fromEntries(n.map((e,t)=>[t,e])),t.SET_PACKAGES[e]=new r.EnumPackage(e,n)},t.WrapEnum=function(e,n){if(!(n in t.ENUM_TAG_TO_KEY[e]))throw new Error(`Value "${n}" does not exist in enum "${e}"`);return t.ENUM_TAG_TO_KEY[e][n]},t.DeWrapEnum=function(e,n){return t.ENUM_KEY_TO_TAG[e][n]};const a=n(30),r=n(98);t.MAX_ENUM_SIZE=a.MAX_BYTE,t.ENUM_TAG_TO_KEY={},t.ENUM_KEY_TO_TAG={},t.SET_PACKAGES={}},404(e,t){Object.defineProperty(t,"__esModule",{value:!0}),t.PacketHolder=void 0;t.PacketHolder=class{key;keys;tags;packetMap;packets;constructor(e){this.key=1,this.keys={},this.tags={},this.packetMap={},e&&this.holdPackets(e)}createKey(e){this.keys[e]=this.key,this.tags[this.key]=e,this.key++}holdPackets(e){this.packets=e;for(const t of e)this.createKey(t.tag),this.packetMap[t.tag]=t}getKey(e){if(!(e in this.keys))throw new Error(`Not a valid tag: ${e}`);return this.keys[e]}getTag(e){if(e in this.tags)return this.tags[e]}getPacket(e){if(!(e in this.packetMap))throw new Error("Unknown packet tag: "+e);return this.packetMap[e]}hasKey(e){return e in this.tags}hasTag(e){return e in this.keys}getKeys(){return this.keys}getTagMap(){return this.tags}getTags(){return Object.values(this.tags)}getPackets(){return this.packets}serialize(){return this.packets.map(e=>e.serialize()).flat()}}},410(e,t){Object.defineProperty(t,"__esModule",{value:!0}),t.setHashFunc=function(e){i=e?r:s},t.hashValue=function(e){return i(e)};const n=1099511628211n,a=(1n<<64n)-1n,r=e=>{let t=14695981039346656037n;const r=e=>{if(null===e)return t^=0n,void(t=t*n&a);const s=typeof e;if("number"===s)return t^=BigInt(Math.trunc(e)),void(t=t*n&a);if("string"!==s){if("boolean"===s)return t^=e?1n:0n,void(t=t*n&a);if(Array.isArray(e))for(let t=0;t<e.length;t++)r(e[t]);else if("object"===s){const s=Object.keys(e).sort();for(let i=0;i<s.length;i++){const o=s[i];for(let e=0;e<o.length;e++)t^=BigInt(o.charCodeAt(e)),t=t*n&a;r(e[o])}}}else for(let r=0;r<e.length;r++)t^=BigInt(e.charCodeAt(r)),t=t*n&a};return r(e),t},s=e=>{let t=2166136261;const n=e=>{if(null===e)return void(t^=0);const a=typeof e;if("number"===a)return t^=0|e,void(t+=(t<<1)+(t<<4)+(t<<7)+(t<<8)+(t<<24));if("string"!==a)if("boolean"!==a){if(Array.isArray(e))for(let t=0;t<e.length;t++)n(e[t]);else if("object"===a){const a=Object.keys(e).sort();for(let r=0;r<a.length;r++){const s=a[r];for(let e=0;e<s.length;e++)t^=s.charCodeAt(e),t+=(t<<1)+(t<<4)+(t<<7)+(t<<8)+(t<<24);n(e[s])}}}else t^=e?1:0;else for(let n=0;n<e.length;n++)t^=e.charCodeAt(n),t+=(t<<1)+(t<<4)+(t<<7)+(t<<8)+(t<<24)};return n(e),t>>>0};let i=r},433(e,t,n){Object.defineProperty(t,"__esModule",{value:!0}),t.processPacket=c,t.listenPacket=async function(e,t,n){if("string"==typeof e)return n(e);const[a,r]=e;try{if(r&&Array.isArray(a))for(const e of t)await e(...a);else for(const e of t)await e(a)}catch(e){console.error(e),n(e)}},t.CreatePacket=f,t.CreateObjPacket=function(e){let{tag:t,types:n=[],dataMaxes:s,dataMins:i,noDataRange:o=!1,dontSpread:c=!1,autoFlatten:f=!1,validator:w=null,dataBatching:_=0,maxBatchSize:y=10,rateLimit:m=0,enabled:g=!0,async:b=!1,gzipCompression:v=n&&n.includes(r.PacketType.JSON)}=e;if(!t)throw new Error("Tag not selected!");if(!n||0==n.length)throw new Error("Types is set to 0 length");for(const e of n)if(d(e))throw new Error(`Invalid packet type in "${t}" packet: ${e}`);o?(s=Array.from({length:n.length}).map(()=>l),i=Array.from({length:n.length}).map(()=>0)):(null==s?s=Array.from({length:n.length}).map(()=>1):Array.isArray(s)||(s=Array.from({length:n.length}).map(()=>s)),null==i?i=Array.from({length:n.length}).map((e,t)=>s[t]):Array.isArray(i)||(i=Array.from({length:n.length}).map(()=>i)));const S=s.map(u),k=i.map((e,t)=>n[t]==r.PacketType.NONE?0:h(e,S[t])),E=new a.PacketSchema(!0,n,b,k,S,p(m),c,f,!1,_,y,v);return new a.Packet(t,E,w,g,!1)},t.CreateEnumPacket=function(e){const{tag:t,enumData:n,dataMax:a=1,dataMin:r=0,noDataRange:s=!1,dontSpread:i=!1,validator:o=null,dataBatching:c=0,maxBatchSize:d=10,rateLimit:l=0,enabled:u=!0,async:h=!1}=e;return f({tag:t,type:n,dataMax:a,dataMin:r,noDataRange:s,dontSpread:i,validator:o,dataBatching:c,maxBatchSize:d,rateLimit:l,enabled:u,async:h})},t.CreateKeyEffective=function(e){const{tag:t,count:n=2,validator:a=null,async:r=!1}=e;if(!t)throw new Error("Tag not selected!");if(n<2)throw new Error("Must have at least 2 key consumptions on key effective packet!");throw new Error("Currently W.I.P.")},t.FlattenData=w,t.UnFlattenData=function(e){return e[0]?.map((t,n)=>e.map(e=>e[n]))??[]};const a=n(102),r=n(619),s=n(98),i=n(30),o=n(410);async function c(e,t,n,a,s,d=!1){const l=e.getKey(t),u=e.getPacket(t);return async function(e,t,n,a,r,s,i){if(e[0]&&!s)return new Promise(t=>e[1].push([t,a,r]));e[0]=!0;const o=await i();if(e[1].length>0){const[a,r,s]=e[1].shift();queueMicrotask(async()=>{a(await c(t,r,s,e,n,!0))})}else e[0]=!1;return o}(a,e,s,t,n,d,async()=>{if(u.rereference){if(-1===s)throw new Error("Cannot send a re-referenced packet from the server-wide sender!");const e=(0,o.hashValue)(n);if(u.lastSent[s]===e)return[l,i.EMPTY_UINT8,u];u.lastSent[s]=e}if(u.autoFlatten)n=w(n[0]);else{if(n.length>u.maxSize)throw new Error(`Packet "${t}" only allows ${u.maxSize} values!`);if(n.length<u.minSize)throw new Error(`Packet "${t}" requires at least ${u.minSize} values!`)}if(u.object){if(n=n.map(e=>Array.isArray(e)?e:[e]),!u.autoFlatten){const e=u.dataMin,a=u.dataMax;for(let r=0;r<e.length;r++){if(n[r].length<e[r])throw new Error(`Section ${r+1} of packet "${t}" requires at least ${e[r]} values!`);if(n[r].length>a[r])throw new Error(`Section ${r+1} of packet "${t}" only allows ${a[r]} values!`)}}}else if(u.type!==r.PacketType.JSON){const e=n.find(e=>"object"==typeof e&&null!=e);e&&console.warn(`Passing an array will result in undefined behavior (${JSON.stringify(e)}). Spread the array with ...arr`)}const e=n.length>0?await u.processSend(n):i.EMPTY_UINT8;return[l,e,u]})}function d(e){return!(("number"==typeof e&&e in r.PacketType||e instanceof s.EnumPackage)&&e!=r.PacketType.KEY_EFFECTIVE)}const l=2048383;function u(e){return e<0?(console.warn("Having a data maximum below 0 does not do anything!"),0):e>l?(console.warn("Only 2048383 values can be sent on a type! Uhh make an issue if you want to send more."),l):e}function h(e,t){return e<0?(console.warn("Having a data minimum below 0 does not do anything!"),0):e>t?(console.warn("Data minimum can not be higher than the data maximum!"),t):e}function p(e){if(!Number.isFinite(e)||e<0)throw new Error("Rate limit must be a non-negative finite number");return(e=Math.floor(e))>i.MAX_USHORT?(console.warn(`A rate limit above ${i.MAX_USHORT} is considered infinite.`),0):e}function f(e){let{tag:t,type:n=r.PacketType.NONE,dataMax:s=1,dataMin:i=1,noDataRange:o=!1,dontSpread:c=!1,validator:f=null,dataBatching:w=0,maxBatchSize:_=10,rateLimit:y=0,enabled:m=!0,async:g=!1,gzipCompression:b=n==r.PacketType.JSON,rereference:v=!1}=e;if(!t)throw new Error("Tag not selected!");if(o?(i=v?1:0,s=l):null==i&&(i=n==r.PacketType.NONE?0:s),v&&0==i)throw new Error("Rereference cannot be true if the dataMin is 0");if(d(n))throw new Error(`Invalid packet type: ${n}`);const S=new a.PacketSchema(!1,n,g,h(i,s),u(s),p(y),c,!1,v,w,_,b);return new a.Packet(t,S,f,m,!1)}function w(e){if(null==e)return[];const t=e[0];if(null==t)return[];if(!Array.isArray(t))throw new Error(`Cannot flatten array: ${e}`);return t.map((t,n)=>e.map(e=>e[n]))??[]}},605(e,t,n){var a=n(804);e.exports=n.v(t,e.id,"a8f247f5205d0c667c14",{"./sonic_ws_core_bg.js":{__wbg_get_unchecked_6e0ad6d2a41b06f6:a.ss,__wbg_length_370319915dc99107:a.Sg,__wbg_push_d2ae3af0c1217ae6:a.Tb,__wbg_new_32b398fb48b6d94a:a.gV,__wbg_new_cd45aabdf6073e84:a.EW,__wbg_length_1f0964f4a5e2c6d8:a.Pt,__wbg_prototypesetcall_4770620bbe4688a0:a.pe,__wbg_new_from_slice_77cdfb7977362f3c:a.BV,__wbg___wbindgen_string_get_b0ca35b86a603356:a.oF,__wbg___wbindgen_number_get_394265ed1e1b84ee:a.JV,__wbg___wbindgen_throw_344f42d3211c4765:a.F6,__wbg___wbindgen_boolean_get_fa956cfa2d1bd751:a.sL,__wbindgen_init_externref_table:a.bL,__wbindgen_cast_0000000000000001:a.NR,__wbindgen_cast_0000000000000002:a.U_}})},619(e,t){var n;Object.defineProperty(t,"__esModule",{value:!0}),t.PacketType=void 0,function(e){e[e.NONE=0]="NONE",e[e.RAW=1]="RAW",e[e.STRINGS_ASCII=2]="STRINGS_ASCII",e[e.STRINGS_UTF16=3]="STRINGS_UTF16",e[e.STRINGS=2]="STRINGS",e[e.ENUMS=4]="ENUMS",e[e.BYTES=5]="BYTES",e[e.UBYTES=6]="UBYTES",e[e.SHORTS=7]="SHORTS",e[e.USHORTS=8]="USHORTS",e[e.VARINT=9]="VARINT",e[e.UVARINT=10]="UVARINT",e[e.DELTAS=11]="DELTAS",e[e.FLOATS=12]="FLOATS",e[e.DOUBLES=13]="DOUBLES",e[e.BOOLEANS=14]="BOOLEANS",e[e.KEY_EFFECTIVE=15]="KEY_EFFECTIVE",e[e.JSON=16]="JSON",e[e.HEX=17]="HEX"}(n||(t.PacketType=n={}))},804(e,t,n){function a(e,t,n,a){const r=Z.decodeBatch(e,t,n,K(a)?Number.MAX_SAFE_INTEGER:a>>>0);if(r[2])throw Y(r[1]);return Y(r[0])}function r(e,t){const n=Z.decodeBooleans(e,t);if(n[2])throw Y(n[1]);return Y(n[0])}function s(e,t){const n=Z.decodeFloats(e,t);if(n[2])throw Y(n[1]);return Y(n[0])}function i(e){let t,n;try{const s=Z.decodeHex(e);var a=s[0],r=s[1];if(s[3])throw a=0,r=0,Y(s[2]);return t=a,n=r,V(a,r)}finally{Z.__wbindgen_free(t,n,1)}}function o(e){const t=Z.decodeRaw(e);if(t[2])throw Y(t[1]);return Y(t[0])}function c(e,t){const n=Z.decodeSigned(e,t);if(n[2])throw Y(n[1]);return Y(n[0])}function d(e,t){const n=Z.decodeStrings(e,t);if(n[2])throw Y(n[1]);return Y(n[0])}function l(e,t){const n=Z.decodeUnsigned(e,t);if(n[2])throw Y(n[1]);return Y(n[0])}function u(e){const t=Z.deflateRaw(e);if(t[2])throw Y(t[1]);return Y(t[0])}function h(e,t){const n=Z.encodeBatch(e,t);if(n[2])throw Y(n[1]);return Y(n[0])}function p(e){const t=Z.encodeBooleans(e);if(t[2])throw Y(t[1]);return Y(t[0])}function f(e,t){const n=Z.encodeFloats(e,t);if(n[2])throw Y(n[1]);return Y(n[0])}function w(e){const t=q(e,Z.__wbindgen_malloc,Z.__wbindgen_realloc),n=ee,a=Z.encodeHex(t,n);if(a[2])throw Y(a[1]);return Y(a[0])}function _(e,t){const n=Z.encodeSigned(e,t);if(n[2])throw Y(n[1]);return Y(n[0])}function y(e,t){const n=Z.encodeStrings(e,t);if(n[2])throw Y(n[1]);return Y(n[0])}function m(e,t){const n=Z.encodeUnsigned(e,t);if(n[2])throw Y(n[1]);return Y(n[0])}function g(e){const t=Z.frameObject(e);if(t[2])throw Y(t[1]);return Y(t[0])}function b(e,t){const n=Z.inflateRaw(e,K(t)?Number.MAX_SAFE_INTEGER:t>>>0);if(n[2])throw Y(n[1]);return Y(n[0])}function v(e,t){const n=Z.unframeObject(e,t);if(n[2])throw Y(n[1]);return Y(n[0])}function S(e,t,n,a,r,s,i){const o=Z.validateEncoded(e,t,n,a,r,s,K(i)?Number.MAX_SAFE_INTEGER:i>>>0);if(o[1])throw Y(o[0])}function k(e,t,n,a){const r=Z.validateEnum(e,t,n,a);if(r[1])throw Y(r[0])}function E(e,t,n,a,r){const s=Z.validateObject(e,t,n,a,r);if(s[1])throw Y(s[0])}function T(e){const t="boolean"==typeof e?e:void 0;return K(t)?16777215:t?1:0}function N(e,t){const n="number"==typeof t?t:void 0;W().setFloat64(e+8,K(n)?0:n,!0),W().setInt32(e+0,!K(n),!0)}function P(e,t){const n="string"==typeof t?t:void 0;var a=K(n)?0:q(n,Z.__wbindgen_malloc,Z.__wbindgen_realloc),r=ee;W().setInt32(e+4,r,!0),W().setInt32(e+0,a,!0)}function A(e,t){throw new Error(V(e,t))}function O(e,t){return e[t>>>0]}function x(e){return e.length}function M(e){return e.length}function C(){return new Array}function I(e){return new Uint8Array(e)}function R(e,t){return new Uint8Array(F(e,t))}function B(e,t,n){Uint8Array.prototype.set.call(F(e,t),n)}function U(e,t){return e.push(t)}function D(e){return e}function L(e,t){return V(e,t)}function j(){const e=Z.__wbindgen_externrefs,t=e.grow(4);e.set(0,void 0),e.set(t+0,void 0),e.set(t+1,null),e.set(t+2,!0),e.set(t+3,!1)}function F(e,t){return e>>>=0,$().subarray(e/1,e/1+t)}n.d(t,{B4:()=>h,BV:()=>R,Dq:()=>o,EF:()=>i,EW:()=>I,F6:()=>A,JV:()=>N,NR:()=>D,Pt:()=>x,Q5:()=>E,Sg:()=>M,Tb:()=>U,Ts:()=>_,U_:()=>L,XC:()=>y,_s:()=>f,at:()=>u,bL:()=>j,cv:()=>v,gV:()=>C,hD:()=>S,i1:()=>k,i4:()=>s,iT:()=>p,iX:()=>r,jN:()=>a,lI:()=>te,mU:()=>w,mk:()=>l,nt:()=>g,oF:()=>P,pe:()=>B,qO:()=>m,sL:()=>T,ss:()=>O,tD:()=>c,wS:()=>b,zC:()=>d});let z=null;function W(){return(null===z||!0===z.buffer.detached||void 0===z.buffer.detached&&z.buffer!==Z.memory.buffer)&&(z=new DataView(Z.memory.buffer)),z}function V(e,t){return function(e,t){G+=t,G>=X&&(J=new TextDecoder("utf-8",{ignoreBOM:!0,fatal:!0}),J.decode(),G=t);return J.decode($().subarray(e,e+t))}(e>>>0,t)}let H=null;function $(){return null!==H&&0!==H.byteLength||(H=new Uint8Array(Z.memory.buffer)),H}function K(e){return null==e}function q(e,t,n){if(void 0===n){const n=Q.encode(e),a=t(n.length,1)>>>0;return $().subarray(a,a+n.length).set(n),ee=n.length,a}let a=e.length,r=t(a,1)>>>0;const s=$();let i=0;for(;i<a;i++){const t=e.charCodeAt(i);if(t>127)break;s[r+i]=t}if(i!==a){0!==i&&(e=e.slice(i)),r=n(r,a,a=i+3*e.length,1)>>>0;const t=$().subarray(r+i,r+a);i+=Q.encodeInto(e,t).written,r=n(r,a,i,1)>>>0}return ee=i,r}function Y(e){const t=Z.__wbindgen_externrefs.get(e);return Z.__externref_table_dealloc(e),t}let J=new TextDecoder("utf-8",{ignoreBOM:!0,fatal:!0});J.decode();const X=2146435072;let G=0;const Q=new TextEncoder;"encodeInto"in Q||(Q.encodeInto=function(e,t){const n=Q.encode(e);return t.set(n),{read:e.length,written:n.length}});let Z,ee=0;function te(e){Z=e}},853(e,t){Object.defineProperty(t,"__esModule",{value:!0}),t.DebugClient=void 0;t.DebugClient=class{host;constructor(e){this.host=e;const t=document.createElement("sonicws");t.innerHTML="<style>sws-h3{margin:0;color:#fff;font-size:16px;font-weight:600}#sonicws-container{display:flex;flex-direction:column;position:absolute;top:50px;left:50px;width:75vw;min-width:33vw;min-height:25vh;max-height:75vh;max-width:75vw;font-family:Arial,sans-serif;background-color:#2c2c2c;border-radius:10px;box-shadow:0 8px 20px rgba(0,0,0,.4);overflow:hidden;user-select:none;transition:box-shadow .2s ease;z-index:2147483647}#sonicws-container:hover{box-shadow:0 12px 28px rgba(0,0,0,.6)}#sonicws-header{display:flex;justify-content:space-between;align-items:center;cursor:move;background:linear-gradient(90deg,#4a90e2,#357ab7);padding:10px 12px;border-top-left-radius:10px;border-top-right-radius:10px}#sonicws-toggle{font-size:18px;font-weight:700;cursor:pointer;color:#fff;user-select:none}#sonicws-body{flex:1;display:flex;padding:12px;color:#e0e0e0;font-size:14px;min-height:0}#sonicws-stats{display:flex;flex-direction:column;min-width:140px}#sonicws-stats sws-p{margin:4px 0}#sonicws-packets{min-height:0;display:flex;flex-direction:column;flex:1;margin-left:10px;background-color:#1e1e1e;padding:8px;border-radius:8px;overflow-y:scroll}sws-div.packet{background-color:#2a2a2a;border-radius:6px;padding:3px 5px;margin-bottom:2px;cursor:pointer;transition:background .2s ease,transform .1s ease;display:flex;flex-direction:column}sws-div.packet:hover{background-color:#3a3a3a;transform:translateY(-1px)}sws-div.packet-header{display:flex;align-items:flex-start;flex-wrap:wrap;font-size:11px;white-space:normal;word-break:break-word}sws-span.packet-arrow{font-weight:700;margin-right:6px}sws-div.packet-details{margin-top:6px;font-size:10px;color:#aaa;display:none;flex-direction:column}sws-div.packet.expanded sws-div.packet-details{display:flex}#sonicws-resizer{width:12px;height:12px;background:#666;position:absolute;right:0;bottom:0;cursor:se-resize;border-bottom-right-radius:10px;transition:background .2s ease}#sonicws-resizer:hover{background:#888}#sonicws-container.minimized{width:auto!important;height:auto!important;min-width:unset;min-height:unset}#sonicws-container.minimized #sonicws-body,#sonicws-container.minimized #sonicws-resizer{display:none}#sonicws-container.minimized #sonicws-header{padding:8px 12px}#sonicws-container.minimized #sonicws-title{font-size:14px}</style><sws-div id=sonicws-container><sws-div id=sonicws-header><sws-h3 id=sonicws-title>SonicWS Debug Menu</sws-h3><sws-span id=sonicws-toggle>−</sws-span></sws-div><sws-div id=sonicws-body><sws-div id=sonicws-stats><sws-p>Status:<sws-span id=sonicws-status>Connecting</sws-span></sws-p><sws-p>Sent Packets:<sws-span id=sonicws-sent>0</sws-span></sws-p><sws-p>Received Packets:<sws-span id=sonicws-received>0</sws-span></sws-p><sws-p>Total Bytes Sent:<sws-span id=sonicws-sentbytes>0</sws-span></sws-p><sws-p>Total Bytes Received:<sws-span id=sonicws-receivedbytes>0</sws-span></sws-p><sws-p>Total Bytes Saved:<sws-span id=sonicws-savedbytes>0</sws-span></sws-p></sws-div><sws-div id=sonicws-packets></sws-div></sws-div><sws-div id=sonicws-resizer></sws-div></sws-div>",document.body?(document.body.appendChild(t),this._loadDebugScript()):document.addEventListener("DOMContentLoaded",()=>{document.body.appendChild(t),this._loadDebugScript()})}_evalInScope(e){const t=this.host;return new Function("send","WrapEnum","DeWrapEnum","FlattenData","UnFlattenData",`"use strict"; return (${e});`)(t.send.bind(t),t.WrapEnum.bind(t),t.DeWrapEnum.bind(t),t.FlattenData.bind(t),t.UnFlattenData.bind(t))}_loadDebugScript(){const e={},t={},n=this.host;this.host.addMiddleware(new class{onReceive_pre(e,n){t[e]??=[],t[e].push([n,performance.now()])}onReceive_post(e,a){const[r,s]=t[e].shift();T("received",`${e} (0x${n.serverPackets.getKey(e).toString(16).toUpperCase()})`,r,JSON.stringify(a),performance.now()-s)}onSend_pre(t,n){e[t]??=[],e[t].push([n,performance.now()])}onSend_post(t,a){const[r,s]=e[t].shift();T("sent",`${t} (0x${n.clientPackets.getKey(t).toString(16).toUpperCase()})`,a,JSON.stringify(r),performance.now()-s)}onStatusChange(e){k(e)}});const a=e=>document.getElementById(e),r=a("sonicws-container"),s=a("sonicws-header"),i=a("sonicws-resizer"),o=a("sonicws-status"),c=a("sonicws-packets"),d=a("sonicws-sent"),l=a("sonicws-received"),u=a("sonicws-sentbytes"),h=a("sonicws-receivedbytes"),p=a("sonicws-savedbytes"),f=document.getElementById("sonicws-toggle"),w=document.getElementById("sonicws-title");let _=!1;const y=document.createElement("input");y.type="text",y.placeholder='send("tag", 5)',y.style.marginTop="8px",y.style.width="100%",y.style.boxSizing="border-box";const m=document.createElement("button");function g(){const e=r.getBoundingClientRect(),t=window.innerWidth-e.width,n=window.innerHeight-e.height,a=Math.min(Math.max(0,e.left),Math.max(0,t)),s=Math.min(Math.max(0,e.top),Math.max(0,n));r.style.left=a+"px",r.style.top=s+"px"}m.innerText="Run",m.style.marginTop="4px",m.style.width="100%",a("sonicws-stats").appendChild(y),a("sonicws-stats").appendChild(m),m.addEventListener("click",()=>{try{this._evalInScope(y.value)}catch(e){console.error(e)}}),f.addEventListener("click",e=>{e.stopPropagation(),_=!_,_?(r.classList.add("minimized"),w.innerText="SWS",f.innerText="+",r.style.width="",r.style.height=""):(r.classList.remove("minimized"),w.innerText="SonicWS Debug Menu",f.innerText="−"),g()});const b={sentPackets:0,receivedPackets:0,totalBytesSent:0,totalBytesReceived:0,totalBytesSaved:0},v=new Proxy(b,{get(e,t){switch(t){case"sonicws-sent":return b.sentPackets;case"sonicws-received":return b.receivedPackets;case"sonicws-sentbytes":return b.totalBytesSent;case"sonicws-receivedbytes":return b.totalBytesReceived;case"sonicws-savedbytes":return b.totalBytesSaved;default:return}},set(e,t,n){switch(t){case"sonicws-sent":return b.sentPackets=n,d.innerText=n.toLocaleString(),!0;case"sonicws-received":return b.receivedPackets=n,l.innerText=n.toLocaleString(),!0;case"sonicws-sentbytes":{b.totalBytesSent=n;const{amt:e,unit:t}=S(n);return u.innerText=e+t,!0}case"sonicws-receivedbytes":{b.totalBytesReceived=n;const{amt:e,unit:t}=S(n);return h.innerText=e+t,!0}case"sonicws-savedbytes":{b.totalBytesSaved=n;const{amt:e,unit:t}=S(n);return p.innerText=e+t,!0}default:return!1}}}),S=e=>{if(!Number.isFinite(e)||e<0)return{amt:0,unit:"B"};const t=["B","KB","MB","GB","TB"];let n=e,a=0;for(;n>=1024&&a<t.length-1;)n/=1024,a++;return{amt:0==a?n.toString():n.toFixed(2),unit:t[a]}};function k(e){switch(e){case WebSocket.CLOSED:o.innerText="Closed",o.style.color="#f00";break;case WebSocket.CLOSING:o.innerText="Closing",o.style.color="#fa0";break;case WebSocket.OPEN:o.innerText="Open",o.style.color="#0f0";break;case WebSocket.CONNECTING:o.innerText="Connecting",o.style.color="#ff0";break;default:o.innerText="Unknown",o.style.color="#777"}}k(WebSocket.CONNECTING);const E=new TextEncoder;function T(e,t,n,a,r){const s=new Date,i=n.length+("sent"==e?1:0),o=E.encode(a).length-i+1,d=document.createElement("sws-div");d.classList.add("packet");const l=document.createElement("sws-div");l.classList.add("packet-header");const u=document.createElement("sws-span");u.classList.add("packet-arrow"),u.innerText="sent"===e?"⬆":"⬇",u.style.color="sent"===e?"#0f0":"#f00";const h=document.createElement("sws-span");h.innerText=t+": "+a,l.appendChild(u),l.appendChild(h);const p=document.createElement("sws-div");p.classList.add("packet-details"),p.innerHTML=`\n <sws-p> Raw Bytes: ${i}b (saved ~${o}b)</sws-p>\n <sws-p> Processed At: ${s.toISOString()} </sws-p>\n <sws-p> Processing Time: <sws-span class="processing-time" > ${r.toFixed(1)} </sws-span> ms</sws-p>\n `,d.appendChild(l),d.appendChild(p),c.append(d),l.addEventListener("click",()=>d.classList.toggle("expanded")),"sent"===e?(v["sonicws-sent"]++,v["sonicws-sentbytes"]+=i):(v["sonicws-received"]++,v["sonicws-receivedbytes"]+=i),v["sonicws-savedbytes"]+=o}let N=!1,P=0,A=0,O=0,x=0,M=!1,C=0,I=0,R=0,B=0;s.addEventListener("mousedown",e=>{N=!0,P=e.clientX,A=e.clientY;const t=r.getBoundingClientRect();O=t.left,x=t.top,e.preventDefault()}),i.addEventListener("mousedown",e=>{M=!0,C=e.clientX,I=e.clientY;const t=r.getBoundingClientRect();R=t.width,B=t.height,e.preventDefault()}),document.addEventListener("mousemove",e=>{N&&(r.style.left=O+e.clientX-P+"px",r.style.top=x+e.clientY-A+"px",g()),M&&!_&&(r.style.width=R+e.clientX-C+"px",r.style.height=B+e.clientY-I+"px",g())}),document.addEventListener("mouseup",()=>{N=!1,M=!1}),g(),window.addEventListener("resize",g)}}},880(e,t,n){n.a(e,async(e,a)=>{try{n.r(t),n.d(t,{decodeBatch:()=>s.jN,decodeBooleans:()=>s.iX,decodeFloats:()=>s.i4,decodeHex:()=>s.EF,decodeRaw:()=>s.Dq,decodeSigned:()=>s.tD,decodeStrings:()=>s.zC,decodeUnsigned:()=>s.mk,deflateRaw:()=>s.at,encodeBatch:()=>s.B4,encodeBooleans:()=>s.iT,encodeFloats:()=>s._s,encodeHex:()=>s.mU,encodeSigned:()=>s.Ts,encodeStrings:()=>s.XC,encodeUnsigned:()=>s.qO,frameObject:()=>s.nt,inflateRaw:()=>s.wS,unframeObject:()=>s.cv,validateEncoded:()=>s.hD,validateEnum:()=>s.i1,validateObject:()=>s.Q5});var r=n(605),s=n(804),i=e([r]);r=(i.then?(await i)():i)[0],(0,s.lI)(r),r.__wbindgen_start(),a()}catch(e){a(e)}})},913(e,t,n){Object.defineProperty(t,"__esModule",{value:!0}),t.CloseCodes=t.Connection=void 0,t.getClosureCause=function(e){if(e>=4e3)return i[e]??"UNKNOWN";switch(e){case 1e3:return"NORMAL_CLOSURE";case 1001:return"GOING_AWAY";case 1002:return"PROTOCOL_ERROR";case 1003:return"UNSUPPORTED_DATA";case 1006:return"ABNORMAL_CLOSURE";default:return"UNKNOWN"}};const a=n(985),r=n(8);class s extends a.MiddlewareHolder{listeners;rawSendListeners=[];name;closed=!1;socket;_timers={};batcher;_on;_off;id;constructor(e,t,n,a,s){super(),this.id=t,this.listeners={},this.name=n,this.socket=e,this.batcher=new r.BatchHelper,this._on=a,this._off=s,this._on("close",()=>{this.callMiddleware("onStatusChange",WebSocket.CLOSED),this.closed=!0;for(const[e,t,n]of Object.values(this._timers))this.clearTimeout(e),n&&t(!0)}),this._on("open",()=>this.callMiddleware("onStatusChange",WebSocket.OPEN))}setTimeout(e,t,n=!1){const a=setTimeout(()=>{e(),this.clearTimeout(a)},t);return this._timers[a]=[a,e,n],a}setInterval(e,t,n=!1){const a=setInterval(e,t);return this._timers[a]=[a,e,n],a}clearTimeout(e){clearTimeout(e),delete this._timers[e]}clearInterval(e){this.clearTimeout(e)}raw_send(e){this.socket.send(e);for(const t of this.rawSendListeners)t(e)}raw_onmessage(e){this._on("message",e)}raw_onsend(e){this.rawSendListeners.push(e)}close(e=1e3,t){this.closed=!0,this.socket.close(e,t?.toString())}isClosed(){return this.closed||this.socket.readyState==WebSocket.CLOSED}async setName(e){await this.callMiddleware("onNameChange",e)||(this.name=e)}getName(){return this.name}}var i;t.Connection=s,function(e){e[e.RATELIMIT=4e3]="RATELIMIT",e[e.SMALL=4001]="SMALL",e[e.INVALID_KEY=4002]="INVALID_KEY",e[e.INVALID_PACKET=4003]="INVALID_PACKET",e[e.INVALID_DATA=4004]="INVALID_DATA",e[e.REPEATED_HANDSHAKE=4005]="REPEATED_HANDSHAKE",e[e.DISABLED_PACKET=4006]="DISABLED_PACKET",e[e.MIDDLEWARE=4007]="MIDDLEWARE",e[e.MANUAL_SHUTDOWN=4008]="MANUAL_SHUTDOWN"}(i||(t.CloseCodes=i={}))},937(e,t,n){Object.defineProperty(t,"__esModule",{value:!0}),t.SonicWSCore=void 0;const a=n(404),r=n(30),s=n(351),i=n(433),o=n(234),c=n(102),d=n(8),l=n(950),u=n(913),h=n(157);class p extends u.Connection{preListen;clientPackets=new a.PacketHolder;serverPackets=new a.PacketHolder;pastKeys=!1;readyListeners=[];bufferHandler;_timers={};asyncData={};asyncMap={};constructor(e,t,n,a){super(e,-1,"LocalSocket",n,a),this.socket=e,this.preListen={},this.invalidPacket=this.invalidPacket.bind(this),this.serverKeyHandler=this.serverKeyHandler.bind(this),this.messageHandler=this.messageHandler.bind(this),this._on("message",this.serverKeyHandler),this._on("close",()=>{this.callMiddleware("onStatusChange",WebSocket.CLOSED);for(const[e,t,n]of Object.values(this._timers))this.clearTimeout(e),n&&t(!0);for(const e of this.clientPackets.getPackets())delete e.lastSent[0];for(const e of this.serverPackets.getPackets())delete e.lastReceived[0]}),this.bufferHandler=t}reading=!1;readQueue=[];async serverKeyHandler(e){if(this.reading)return this.readQueue.push(e);this.reading=!0;const t=await this.bufferHandler(e);if(t.length<3||(0,h.as8String)(t.slice(0,3))!=o.SERVER_SUFFIX)throw this.close(1e3),new Error("The server requested is not a Sonic WS server.");const n=t[3];if(n!=o.VERSION)throw this.close(1e3),new Error(`Version mismatch: ${n>o.VERSION?"client":"server"} is outdated (server: ${n}, client: ${o.VERSION})`);const a=(0,s.inflateNative)(t.subarray(4,t.length)),[i,d]=(0,r.readVarInt)(a,0);this.id=d;const[l,u]=(0,r.readVarInt)(a,i),p=a.subarray(l,l+u);this.clientPackets.holdPackets(c.Packet.deserializeAll(p,!0));const f=a.subarray(l+u,a.length);this.serverPackets.holdPackets(c.Packet.deserializeAll(f,!0)),this.batcher.registerSendPackets(this.clientPackets,this);for(const e of this.serverPackets.getPackets()){const t=this.serverPackets.getKey(e.tag);this.asyncMap[t]=e.async,e.async&&(this.asyncData[t]=[!1,[]])}Object.keys(this.preListen).forEach(e=>this.preListen[e].forEach(t=>{if(!this.serverPackets.hasTag(e))return console.error(new Error(`The server does not send the packet with tag "${e}"!`));this.listen(e,t)})),this.preListen=null,this.pastKeys=!0,this.readyListeners.forEach(e=>e()),this.readyListeners=null,this._off("message",this.serverKeyHandler),this._on("message",this.messageHandler),this.readQueue.forEach(e=>this.messageHandler(e)),this.readQueue=[]}invalidPacket(e){throw console.error(e),new Error("An error occured with data from the server!! This is probably my fault.. make an issue at https://github.com/liwybloc/sonic-ws")}listenLock=!1;packetQueue=[];async listenPacket(e,t,n,a,r){const s=this.listeners[t];if(!s)return console.warn("Warn: No listener for packet "+t);await this.enqueuePacket(e,s,n,a,r),await this.callMiddleware("onReceive_post",t,"string"==typeof e?[e]:e[0])}isAsync(e){return this.asyncMap[e]}async enqueuePacket(e,t,n,a,r){await(0,i.listenPacket)(e,t,this.invalidPacket),await this.triggerNextPacket(n,a,r)}async triggerNextPacket(e,t,n){t?n[0]=!1:this.listenLock=!1,e.length>0&&this.dataHandler(e.shift())}async dataHandler(e){const t=e[0],n=e.slice(1),a=this.isAsync(t);let r,s,i;if(a?(i=this.asyncData[t],r=i[0],s=i[1]):(r=this.listenLock,s=this.packetQueue),r)return void s.push(e);a?i[0]=!0:this.listenLock=!0;const o=this.serverPackets.getTag(t),c=this.serverPackets.getPacket(o);if(await this.callMiddleware("onReceive_pre",c.tag,e,e.length))return;if(c.rereference&&0==n.length)return void 0===c.lastReceived[0]?this.invalidPacket("No previous value to rereference"):void this.listenPacket(c.lastReceived[0],o,s,a,i);if(0==c.dataBatching){const e=c.lastReceived[0]=await c.listen(n,null);return void this.listenPacket(e,o,s,a,i)}const l=await d.BatchHelper.unravelBatch(c,n,null);if("string"==typeof l)return this.invalidPacket(l);l.forEach(e=>this.listenPacket(e,o,s,a,i))}async messageHandler(e){const t=await this.bufferHandler(e);t.length<1||await this.dataHandler(t)}listen(e,t){this.serverPackets.hasTag(e)?(this.listeners[e]??=[]).push(t):console.log("Tag is not available on server: "+e)}sendQueue=[!1,[],void 0];async send(e,...t){if(await this.callMiddleware("onSend_pre",e,t,Date.now(),performance.now()))return;const[n,a,r]=await(0,i.processPacket)(this.clientPackets,e,t,this.sendQueue,0);0==r.dataBatching?this.raw_send((0,l.toPacketBuffer)(n,a)):this.batcher.batchPacket(n,a),await this.callMiddleware("onSend_post",e,a,a.length)}on_ready(e){this.pastKeys?e():this.readyListeners.push(e)}on_close(e){this._on("close",e)}on(e,t){if(this.socket.readyState!==WebSocket.OPEN)return this.preListen[e]||(this.preListen[e]=[]),void this.preListen[e].push(t);this.listen(e,t)}}t.SonicWSCore=p},950(e,t){function n(e,t){const n=[];for(let a=0;a<e.length;a+=t){const r=e.slice(a,a+t);n.push(r)}return n}Object.defineProperty(t,"__esModule",{value:!0}),t.splitArray=n,t.toPacketBuffer=function(e,t){const n=new Uint8Array(1+t.length);return n[0]=e,n.set(t,1),n},t.splitBuffer=function(e,t){return n(Array.from(e),t)},t.stringifyBuffer=function(e){return`<Buffer ${Array.from(e).map(e=>e.toString(16).padStart(2,"0")).join(" ")}>`}},985(e,t){Object.defineProperty(t,"__esModule",{value:!0}),t.MiddlewareHolder=void 0;t.MiddlewareHolder=class{middlewares=[];addMiddleware(e){this.middlewares.push(e);const t=e;try{"function"==typeof t.init&&t.init(this)}catch(e){console.warn("Middleware init threw an error:",e)}}async callMiddleware(e,...t){let n=!1;for(const a of this.middlewares){const r=a[e];if(r)try{await r(...t)&&(n=!0)}catch(t){console.warn(`Middleware ${String(e)} threw an error:`,t)}}return n}}}},__webpack_module_cache__={},hasSymbol,webpackQueues,webpackExports,webpackError,resolveQueue;function __webpack_require__(e){var t=__webpack_module_cache__[e];if(void 0!==t)return t.exports;var n=__webpack_module_cache__[e]={id:e,exports:{}};return __webpack_modules__[e](n,n.exports,__webpack_require__),n.exports}hasSymbol="function"==typeof Symbol,webpackQueues=hasSymbol?Symbol("webpack queues"):"__webpack_queues__",webpackExports=hasSymbol?Symbol("webpack exports"):"__webpack_exports__",webpackError=hasSymbol?Symbol("webpack error"):"__webpack_error__",resolveQueue=e=>{e&&e.d<1&&(e.d=1,e.forEach(e=>e.r--),e.forEach(e=>e.r--?e.r++:e()))},__webpack_require__.a=(e,t,n)=>{var a;n&&((a=[]).d=-1);var r,s,i,o=new Set,c=e.exports,d=new Promise((e,t)=>{i=t,s=e});d[webpackExports]=c,d[webpackQueues]=e=>(a&&e(a),o.forEach(e),d.catch(e=>{})),e.exports=d,t(e=>{var t;r=(e=>e.map(e=>{if(null!==e&&"object"==typeof e){if(e[webpackQueues])return e;if(e.then){var t=[];t.d=0,e.then(e=>{n[webpackExports]=e,resolveQueue(t)},e=>{n[webpackError]=e,resolveQueue(t)});var n={};return n[webpackQueues]=e=>e(t),n}}var a={};return a[webpackQueues]=e=>{},a[webpackExports]=e,a}))(e);var n=()=>r.map(e=>{if(e[webpackError])throw e[webpackError];return e[webpackExports]}),s=new Promise(e=>{(t=()=>e(n)).r=0;var s=e=>e!==a&&!o.has(e)&&(o.add(e),e&&!e.d&&(t.r++,e.push(t)));r.map(e=>e[webpackQueues](s))});return t.r?s:n()},e=>(e?i(d[webpackError]=e):s(c),resolveQueue(a))),a&&a.d<0&&(a.d=0)},__webpack_require__.d=(e,t)=>{for(var n in t)__webpack_require__.o(t,n)&&!__webpack_require__.o(e,n)&&Object.defineProperty(e,n,{enumerable:!0,get:t[n]})},__webpack_require__.g=function(){if("object"==typeof globalThis)return globalThis;try{return this||new Function("return this")()}catch(e){if("object"==typeof window)return window}}(),__webpack_require__.o=(e,t)=>Object.prototype.hasOwnProperty.call(e,t),__webpack_require__.r=e=>{"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(e,"__esModule",{value:!0})},__webpack_require__.v=(e,t,n,a)=>{var r=fetch(__webpack_require__.p+"bundle.wasm"),s=()=>r.then(e=>e.arrayBuffer()).then(e=>WebAssembly.instantiate(e,a)).then(t=>Object.assign(e,t.instance.exports));return r.then(t=>"function"==typeof WebAssembly.instantiateStreaming?WebAssembly.instantiateStreaming(t,a).then(t=>Object.assign(e,t.instance.exports),e=>{if("application/wasm"!==t.headers.get("Content-Type"))return console.warn("`WebAssembly.instantiateStreaming` failed because your server does not serve wasm with `application/wasm` MIME type. Falling back to `WebAssembly.instantiate` which is slower. Original error:\n",e),s();throw e}):s())},(()=>{var e;__webpack_require__.g.importScripts&&(e=__webpack_require__.g.location+"");var t=__webpack_require__.g.document;if(!e&&t&&(t.currentScript&&"SCRIPT"===t.currentScript.tagName.toUpperCase()&&(e=t.currentScript.src),!e)){var n=t.getElementsByTagName("script");if(n.length)for(var a=n.length-1;a>-1&&(!e||!/^http(s?):/.test(e));)e=n[a--].src}if(!e)throw new Error("Automatic publicPath is not supported in this browser");e=e.replace(/^blob:/,"").replace(/#.*$/,"").replace(/\?.*$/,"").replace(/\/[^\/]+$/,"/"),__webpack_require__.p=e})();var __webpack_exports__={};(()=>{const e=__webpack_require__(853),t=__webpack_require__(388),n=__webpack_require__(433),a=__webpack_require__(937),r=__webpack_require__(351);class s extends a.SonicWSCore{static initialize(){return(0,r.initializeWasmCore)()}antiTamperCall=()=>{};constructor(e,t,n=!1){const a=new WebSocket(e,t);if(super(a,async e=>new Uint8Array(await e.data.arrayBuffer()),a.addEventListener.bind(a),a.removeEventListener.bind(a)),n){const e=this,t=a.send.bind(a),n=this.send.bind(this);let r;this.send=async(t,...a)=>(r=e.clientPackets.getKey(t),await n(t,...a)),a.send=n=>n instanceof Uint8Array&&r==n[0]?t(n):(e.antiTamperCall(),void e.close())}}on_tamper(e){this.antiTamperCall=e}WrapEnum(e,n){return(0,t.WrapEnum)(e,n)}DeWrapEnum(e,n){return(0,t.DeWrapEnum)(e,n)}FlattenData(e){return(0,n.FlattenData)(e)}UnFlattenData(e){return(0,n.UnFlattenData)(e)}debugClient=null;OpenDebug(){if(null!=this.debugClient)throw new Error("Debug client has already been opened!");this.debugClient=new e.DebugClient(this)}}window.SonicWS=s})()})();
Binary file
@@ -0,0 +1,6 @@
1
+ # SonicWS Core
2
+
3
+ Rust implementation of the language-neutral SonicWS packet model and codec.
4
+
5
+ The legacy `gzip_compression` schema flag uses raw DEFLATE for TypeScript wire
6
+ compatibility; it does not produce a gzip container.
@@ -0,0 +1,13 @@
1
+ {
2
+ "name": "sonic-ws-core",
3
+ "description": "Language-neutral SonicWS packet codec core",
4
+ "version": "0.1.0",
5
+ "license": "LicenseRef-Lily-Personal-NonCommercial-2026",
6
+ "files": [
7
+ "sonic_ws_core_bg.wasm",
8
+ "sonic_ws_core.js",
9
+ "sonic_ws_core.d.ts"
10
+ ],
11
+ "main": "sonic_ws_core.js",
12
+ "types": "sonic_ws_core.d.ts"
13
+ }
@@ -0,0 +1,51 @@
1
+ /**
2
+ * Copyright (c) 2026 Lily (liwybloc)
3
+ * License-Identifier: LicenseRef-Lily-Personal-NonCommercial-2026
4
+ * See LICENSE for personal, non-commercial license terms.
5
+ */
6
+
7
+
8
+
9
+ export function decodeBatch(data: Uint8Array, compressed: boolean, max: number, max_output_size?: number | null): Array<any>;
10
+
11
+ export function decodeBooleans(data: Uint8Array, count: number): Array<any>;
12
+
13
+ export function decodeFloats(value: number, data: Uint8Array): Array<any>;
14
+
15
+ export function decodeHex(data: Uint8Array): string;
16
+
17
+ export function decodeRaw(data: Uint8Array): Uint8Array;
18
+
19
+ export function decodeSigned(value: number, data: Uint8Array): Array<any>;
20
+
21
+ export function decodeStrings(value: number, data: Uint8Array): Array<any>;
22
+
23
+ export function decodeUnsigned(value: number, data: Uint8Array): Array<any>;
24
+
25
+ export function deflateRaw(data: Uint8Array): Uint8Array;
26
+
27
+ export function encodeBatch(values: Array<any>, compressed: boolean): Uint8Array;
28
+
29
+ export function encodeBooleans(values: Array<any>): Uint8Array;
30
+
31
+ export function encodeFloats(value: number, values: Array<any>): Uint8Array;
32
+
33
+ export function encodeHex(value: string): Uint8Array;
34
+
35
+ export function encodeSigned(value: number, values: Array<any>): Uint8Array;
36
+
37
+ export function encodeStrings(value: number, values: Array<any>): Uint8Array;
38
+
39
+ export function encodeUnsigned(value: number, values: Array<any>): Uint8Array;
40
+
41
+ export function frameObject(sectors: Array<any>): Uint8Array;
42
+
43
+ export function inflateRaw(data: Uint8Array, max_output_size?: number | null): Uint8Array;
44
+
45
+ export function unframeObject(data: Uint8Array, count: number): Array<any>;
46
+
47
+ export function validateEncoded(value: number, data: Uint8Array, min: number, max: number, compressed: boolean, batched: boolean, max_batch?: number | null): void;
48
+
49
+ export function validateEnum(data: Uint8Array, size: number, min: number, max: number): void;
50
+
51
+ export function validateObject(data: Uint8Array, kinds: Array<any>, mins: Array<any>, maxes: Array<any>, enum_sizes: Array<any>): void;
@@ -0,0 +1,7 @@
1
+ /**
2
+ * Copyright (c) 2026 Lily (liwybloc)
3
+ * License-Identifier: LicenseRef-Lily-Personal-NonCommercial-2026
4
+ * See LICENSE for personal, non-commercial license terms.
5
+ */
6
+
7
+ function e(e,n){return e>>>=0,c().subarray(e/1,e/1+n)}exports.decodeBatch=function(e,n,t,o){const r=b.decodeBatch(e,n,t,i(o)?Number.MAX_SAFE_INTEGER:o>>>0);if(r[2])throw d(r[1]);return d(r[0])},exports.decodeBooleans=function(e,n){const t=b.decodeBooleans(e,n);if(t[2])throw d(t[1]);return d(t[0])},exports.decodeFloats=function(e,n){const t=b.decodeFloats(e,n);if(t[2])throw d(t[1]);return d(t[0])},exports.decodeHex=function(e){let n,t;try{const i=b.decodeHex(e);var r=i[0],c=i[1];if(i[3])throw r=0,c=0,d(i[2]);return n=r,t=c,o(r,c)}finally{b.__wbindgen_free(n,t,1)}},exports.decodeRaw=function(e){const n=b.decodeRaw(e);if(n[2])throw d(n[1]);return d(n[0])},exports.decodeSigned=function(e,n){const t=b.decodeSigned(e,n);if(t[2])throw d(t[1]);return d(t[0])},exports.decodeStrings=function(e,n){const t=b.decodeStrings(e,n);if(t[2])throw d(t[1]);return d(t[0])},exports.decodeUnsigned=function(e,n){const t=b.decodeUnsigned(e,n);if(t[2])throw d(t[1]);return d(t[0])},exports.deflateRaw=function(e){const n=b.deflateRaw(e);if(n[2])throw d(n[1]);return d(n[0])},exports.encodeBatch=function(e,n){const t=b.encodeBatch(e,n);if(t[2])throw d(t[1]);return d(t[0])},exports.encodeBooleans=function(e){const n=b.encodeBooleans(e);if(n[2])throw d(n[1]);return d(n[0])},exports.encodeFloats=function(e,n){const t=b.encodeFloats(e,n);if(t[2])throw d(t[1]);return d(t[0])},exports.encodeHex=function(e){const n=_(e,b.__wbindgen_malloc,b.__wbindgen_realloc),t=s,o=b.encodeHex(n,t);if(o[2])throw d(o[1]);return d(o[0])},exports.encodeSigned=function(e,n){const t=b.encodeSigned(e,n);if(t[2])throw d(t[1]);return d(t[0])},exports.encodeStrings=function(e,n){const t=b.encodeStrings(e,n);if(t[2])throw d(t[1]);return d(t[0])},exports.encodeUnsigned=function(e,n){const t=b.encodeUnsigned(e,n);if(t[2])throw d(t[1]);return d(t[0])},exports.frameObject=function(e){const n=b.frameObject(e);if(n[2])throw d(n[1]);return d(n[0])},exports.inflateRaw=function(e,n){const t=b.inflateRaw(e,i(n)?Number.MAX_SAFE_INTEGER:n>>>0);if(t[2])throw d(t[1]);return d(t[0])},exports.unframeObject=function(e,n){const t=b.unframeObject(e,n);if(t[2])throw d(t[1]);return d(t[0])},exports.validateEncoded=function(e,n,t,o,r,c,_){const u=b.validateEncoded(e,n,t,o,r,c,i(_)?Number.MAX_SAFE_INTEGER:_>>>0);if(u[1])throw d(u[0])},exports.validateEnum=function(e,n,t,o){const r=b.validateEnum(e,n,t,o);if(r[1])throw d(r[0])},exports.validateObject=function(e,n,t,o,r){const c=b.validateObject(e,n,t,o,r);if(c[1])throw d(c[0])};let n=null;function t(){return(null===n||!0===n.buffer.detached||void 0===n.buffer.detached&&n.buffer!==b.memory.buffer)&&(n=new DataView(b.memory.buffer)),n}function o(e,n){return function(e,n){return u.decode(c().subarray(e,e+n))}(e>>>0,n)}let r=null;function c(){return null!==r&&0!==r.byteLength||(r=new Uint8Array(b.memory.buffer)),r}function i(e){return null==e}function _(e,n,t){if(void 0===t){const t=f.encode(e),o=n(t.length,1)>>>0;return c().subarray(o,o+t.length).set(t),s=t.length,o}let o=e.length,r=n(o,1)>>>0;const i=c();let _=0;for(;_<o;_++){const n=e.charCodeAt(_);if(n>127)break;i[r+_]=n}if(_!==o){0!==_&&(e=e.slice(_)),r=t(r,o,o=_+3*e.length,1)>>>0;const n=c().subarray(r+_,r+o);_+=f.encodeInto(e,n).written,r=t(r,o,_,1)>>>0}return s=_,r}function d(e){const n=b.__wbindgen_externrefs.get(e);return b.__externref_table_dealloc(e),n}let u=new TextDecoder("utf-8",{ignoreBOM:!0,fatal:!0});u.decode();const f=new TextEncoder;"encodeInto"in f||(f.encodeInto=function(e,n){const t=f.encode(e);return n.set(t),{read:e.length,written:t.length}});let s=0;const a=`${__dirname}/sonic_ws_core_bg.wasm`,l=require("fs").readFileSync(a),w=new WebAssembly.Module(l);let b=new WebAssembly.Instance(w,{__proto__:null,"./sonic_ws_core_bg.js":{__proto__:null,__wbg___wbindgen_boolean_get_fa956cfa2d1bd751:function(e){const n="boolean"==typeof e?e:void 0;return i(n)?16777215:n?1:0},__wbg___wbindgen_number_get_394265ed1e1b84ee:function(e,n){const o="number"==typeof n?n:void 0;t().setFloat64(e+8,i(o)?0:o,!0),t().setInt32(e+0,!i(o),!0)},__wbg___wbindgen_string_get_b0ca35b86a603356:function(e,n){const o="string"==typeof n?n:void 0;var r=i(o)?0:_(o,b.__wbindgen_malloc,b.__wbindgen_realloc),c=s;t().setInt32(e+4,c,!0),t().setInt32(e+0,r,!0)},__wbg___wbindgen_throw_344f42d3211c4765:function(e,n){throw new Error(o(e,n))},__wbg_get_unchecked_6e0ad6d2a41b06f6:function(e,n){return e[n>>>0]},__wbg_length_1f0964f4a5e2c6d8:function(e){return e.length},__wbg_length_370319915dc99107:function(e){return e.length},__wbg_new_32b398fb48b6d94a:function(){return new Array},__wbg_new_cd45aabdf6073e84:function(e){return new Uint8Array(e)},__wbg_new_from_slice_77cdfb7977362f3c:function(n,t){return new Uint8Array(e(n,t))},__wbg_prototypesetcall_4770620bbe4688a0:function(n,t,o){Uint8Array.prototype.set.call(e(n,t),o)},__wbg_push_d2ae3af0c1217ae6:function(e,n){return e.push(n)},__wbindgen_cast_0000000000000001:function(e){return e},__wbindgen_cast_0000000000000002:function(e,n){return o(e,n)},__wbindgen_init_externref_table:function(){const e=b.__wbindgen_externrefs,n=e.grow(4);e.set(0,void 0),e.set(n+0,void 0),e.set(n+1,null),e.set(n+2,!0),e.set(n+3,!1)}}}).exports;b.__wbindgen_start();
@@ -0,0 +1,36 @@
1
+ /**
2
+ * Copyright (c) 2026 Lily (liwybloc)
3
+ * License-Identifier: LicenseRef-Lily-Personal-NonCommercial-2026
4
+ * See LICENSE for personal, non-commercial license terms.
5
+ */
6
+
7
+
8
+ export const memory: WebAssembly.Memory;
9
+ export const decodeBatch: (a: any, b: number, c: number, d: number) => [number, number, number];
10
+ export const decodeBooleans: (a: any, b: number) => [number, number, number];
11
+ export const decodeFloats: (a: number, b: any) => [number, number, number];
12
+ export const decodeHex: (a: any) => [number, number, number, number];
13
+ export const decodeRaw: (a: any) => [number, number, number];
14
+ export const decodeSigned: (a: number, b: any) => [number, number, number];
15
+ export const decodeStrings: (a: number, b: any) => [number, number, number];
16
+ export const decodeUnsigned: (a: number, b: any) => [number, number, number];
17
+ export const deflateRaw: (a: any) => [number, number, number];
18
+ export const encodeBatch: (a: any, b: number) => [number, number, number];
19
+ export const encodeBooleans: (a: any) => [number, number, number];
20
+ export const encodeFloats: (a: number, b: any) => [number, number, number];
21
+ export const encodeHex: (a: number, b: number) => [number, number, number];
22
+ export const encodeSigned: (a: number, b: any) => [number, number, number];
23
+ export const encodeStrings: (a: number, b: any) => [number, number, number];
24
+ export const encodeUnsigned: (a: number, b: any) => [number, number, number];
25
+ export const frameObject: (a: any) => [number, number, number];
26
+ export const inflateRaw: (a: any, b: number) => [number, number, number];
27
+ export const unframeObject: (a: any, b: number) => [number, number, number];
28
+ export const validateEncoded: (a: number, b: any, c: number, d: number, e: number, f: number, g: number) => [number, number];
29
+ export const validateEnum: (a: any, b: number, c: number, d: number) => [number, number];
30
+ export const validateObject: (a: any, b: any, c: any, d: any, e: any) => [number, number];
31
+ export const __wbindgen_malloc: (a: number, b: number) => number;
32
+ export const __wbindgen_realloc: (a: number, b: number, c: number, d: number) => number;
33
+ export const __wbindgen_externrefs: WebAssembly.Table;
34
+ export const __externref_table_dealloc: (a: number) => void;
35
+ export const __wbindgen_free: (a: number, b: number, c: number) => void;
36
+ export const __wbindgen_start: () => void;
@@ -0,0 +1,6 @@
1
+ # SonicWS Core
2
+
3
+ Rust implementation of the language-neutral SonicWS packet model and codec.
4
+
5
+ The legacy `gzip_compression` schema flag uses raw DEFLATE for TypeScript wire
6
+ compatibility; it does not produce a gzip container.
@@ -0,0 +1,19 @@
1
+ {
2
+ "name": "sonic-ws-core",
3
+ "type": "module",
4
+ "description": "Language-neutral SonicWS packet codec core",
5
+ "version": "0.1.0",
6
+ "license": "LicenseRef-Lily-Personal-NonCommercial-2026",
7
+ "files": [
8
+ "sonic_ws_core_bg.wasm",
9
+ "sonic_ws_core.js",
10
+ "sonic_ws_core_bg.js",
11
+ "sonic_ws_core.d.ts"
12
+ ],
13
+ "main": "sonic_ws_core.js",
14
+ "types": "sonic_ws_core.d.ts",
15
+ "sideEffects": [
16
+ "./sonic_ws_core.js",
17
+ "./snippets/*"
18
+ ]
19
+ }
@@ -0,0 +1,51 @@
1
+ /**
2
+ * Copyright (c) 2026 Lily (liwybloc)
3
+ * License-Identifier: LicenseRef-Lily-Personal-NonCommercial-2026
4
+ * See LICENSE for personal, non-commercial license terms.
5
+ */
6
+
7
+
8
+
9
+ export function decodeBatch(data: Uint8Array, compressed: boolean, max: number, max_output_size?: number | null): Array<any>;
10
+
11
+ export function decodeBooleans(data: Uint8Array, count: number): Array<any>;
12
+
13
+ export function decodeFloats(value: number, data: Uint8Array): Array<any>;
14
+
15
+ export function decodeHex(data: Uint8Array): string;
16
+
17
+ export function decodeRaw(data: Uint8Array): Uint8Array;
18
+
19
+ export function decodeSigned(value: number, data: Uint8Array): Array<any>;
20
+
21
+ export function decodeStrings(value: number, data: Uint8Array): Array<any>;
22
+
23
+ export function decodeUnsigned(value: number, data: Uint8Array): Array<any>;
24
+
25
+ export function deflateRaw(data: Uint8Array): Uint8Array;
26
+
27
+ export function encodeBatch(values: Array<any>, compressed: boolean): Uint8Array;
28
+
29
+ export function encodeBooleans(values: Array<any>): Uint8Array;
30
+
31
+ export function encodeFloats(value: number, values: Array<any>): Uint8Array;
32
+
33
+ export function encodeHex(value: string): Uint8Array;
34
+
35
+ export function encodeSigned(value: number, values: Array<any>): Uint8Array;
36
+
37
+ export function encodeStrings(value: number, values: Array<any>): Uint8Array;
38
+
39
+ export function encodeUnsigned(value: number, values: Array<any>): Uint8Array;
40
+
41
+ export function frameObject(sectors: Array<any>): Uint8Array;
42
+
43
+ export function inflateRaw(data: Uint8Array, max_output_size?: number | null): Uint8Array;
44
+
45
+ export function unframeObject(data: Uint8Array, count: number): Array<any>;
46
+
47
+ export function validateEncoded(value: number, data: Uint8Array, min: number, max: number, compressed: boolean, batched: boolean, max_batch?: number | null): void;
48
+
49
+ export function validateEnum(data: Uint8Array, size: number, min: number, max: number): void;
50
+
51
+ export function validateObject(data: Uint8Array, kinds: Array<any>, mins: Array<any>, maxes: Array<any>, enum_sizes: Array<any>): void;
@@ -0,0 +1,7 @@
1
+ /**
2
+ * Copyright (c) 2026 Lily (liwybloc)
3
+ * License-Identifier: LicenseRef-Lily-Personal-NonCommercial-2026
4
+ * See LICENSE for personal, non-commercial license terms.
5
+ */
6
+
7
+ import*as e from"./sonic_ws_core_bg.wasm";import{__wbg_set_wasm as d}from"./sonic_ws_core_bg.js";d(e),e.__wbindgen_start();export{decodeBatch,decodeBooleans,decodeFloats,decodeHex,decodeRaw,decodeSigned,decodeStrings,decodeUnsigned,deflateRaw,encodeBatch,encodeBooleans,encodeFloats,encodeHex,encodeSigned,encodeStrings,encodeUnsigned,frameObject,inflateRaw,unframeObject,validateEncoded,validateEnum,validateObject}from"./sonic_ws_core_bg.js";
@@ -0,0 +1,7 @@
1
+ /**
2
+ * Copyright (c) 2026 Lily (liwybloc)
3
+ * License-Identifier: LicenseRef-Lily-Personal-NonCommercial-2026
4
+ * See LICENSE for personal, non-commercial license terms.
5
+ */
6
+
7
+ export function decodeBatch(e,n,t,o){const r=l.decodeBatch(e,n,t,i(o)?Number.MAX_SAFE_INTEGER:o>>>0);if(r[2])throw f(r[1]);return f(r[0])}export function decodeBooleans(e,n){const t=l.decodeBooleans(e,n);if(t[2])throw f(t[1]);return f(t[0])}export function decodeFloats(e,n){const t=l.decodeFloats(e,n);if(t[2])throw f(t[1]);return f(t[0])}export function decodeHex(e){let n,t;try{const i=l.decodeHex(e);var r=i[0],c=i[1];if(i[3])throw r=0,c=0,f(i[2]);return n=r,t=c,o(r,c)}finally{l.__wbindgen_free(n,t,1)}}export function decodeRaw(e){const n=l.decodeRaw(e);if(n[2])throw f(n[1]);return f(n[0])}export function decodeSigned(e,n){const t=l.decodeSigned(e,n);if(t[2])throw f(t[1]);return f(t[0])}export function decodeStrings(e,n){const t=l.decodeStrings(e,n);if(t[2])throw f(t[1]);return f(t[0])}export function decodeUnsigned(e,n){const t=l.decodeUnsigned(e,n);if(t[2])throw f(t[1]);return f(t[0])}export function deflateRaw(e){const n=l.deflateRaw(e);if(n[2])throw f(n[1]);return f(n[0])}export function encodeBatch(e,n){const t=l.encodeBatch(e,n);if(t[2])throw f(t[1]);return f(t[0])}export function encodeBooleans(e){const n=l.encodeBooleans(e);if(n[2])throw f(n[1]);return f(n[0])}export function encodeFloats(e,n){const t=l.encodeFloats(e,n);if(t[2])throw f(t[1]);return f(t[0])}export function encodeHex(e){const n=d(e,l.__wbindgen_malloc,l.__wbindgen_realloc),t=w,o=l.encodeHex(n,t);if(o[2])throw f(o[1]);return f(o[0])}export function encodeSigned(e,n){const t=l.encodeSigned(e,n);if(t[2])throw f(t[1]);return f(t[0])}export function encodeStrings(e,n){const t=l.encodeStrings(e,n);if(t[2])throw f(t[1]);return f(t[0])}export function encodeUnsigned(e,n){const t=l.encodeUnsigned(e,n);if(t[2])throw f(t[1]);return f(t[0])}export function frameObject(e){const n=l.frameObject(e);if(n[2])throw f(n[1]);return f(n[0])}export function inflateRaw(e,n){const t=l.inflateRaw(e,i(n)?Number.MAX_SAFE_INTEGER:n>>>0);if(t[2])throw f(t[1]);return f(t[0])}export function unframeObject(e,n){const t=l.unframeObject(e,n);if(t[2])throw f(t[1]);return f(t[0])}export function validateEncoded(e,n,t,o,r,c,d){const u=l.validateEncoded(e,n,t,o,r,c,i(d)?Number.MAX_SAFE_INTEGER:d>>>0);if(u[1])throw f(u[0])}export function validateEnum(e,n,t,o){const r=l.validateEnum(e,n,t,o);if(r[1])throw f(r[0])}export function validateObject(e,n,t,o,r){const c=l.validateObject(e,n,t,o,r);if(c[1])throw f(c[0])}export function __wbg___wbindgen_boolean_get_fa956cfa2d1bd751(e){const n="boolean"==typeof e?e:void 0;return i(n)?16777215:n?1:0}export function __wbg___wbindgen_number_get_394265ed1e1b84ee(e,n){const o="number"==typeof n?n:void 0;t().setFloat64(e+8,i(o)?0:o,!0),t().setInt32(e+0,!i(o),!0)}export function __wbg___wbindgen_string_get_b0ca35b86a603356(e,n){const o="string"==typeof n?n:void 0;var r=i(o)?0:d(o,l.__wbindgen_malloc,l.__wbindgen_realloc),c=w;t().setInt32(e+4,c,!0),t().setInt32(e+0,r,!0)}export function __wbg___wbindgen_throw_344f42d3211c4765(e,n){throw new Error(o(e,n))}export function __wbg_get_unchecked_6e0ad6d2a41b06f6(e,n){return e[n>>>0]}export function __wbg_length_1f0964f4a5e2c6d8(e){return e.length}export function __wbg_length_370319915dc99107(e){return e.length}export function __wbg_new_32b398fb48b6d94a(){return new Array}export function __wbg_new_cd45aabdf6073e84(e){return new Uint8Array(e)}export function __wbg_new_from_slice_77cdfb7977362f3c(n,t){return new Uint8Array(e(n,t))}export function __wbg_prototypesetcall_4770620bbe4688a0(n,t,o){Uint8Array.prototype.set.call(e(n,t),o)}export function __wbg_push_d2ae3af0c1217ae6(e,n){return e.push(n)}export function __wbindgen_cast_0000000000000001(e){return e}export function __wbindgen_cast_0000000000000002(e,n){return o(e,n)}export function __wbindgen_init_externref_table(){const e=l.__wbindgen_externrefs,n=e.grow(4);e.set(0,void 0),e.set(n+0,void 0),e.set(n+1,null),e.set(n+2,!0),e.set(n+3,!1)}function e(e,n){return e>>>=0,c().subarray(e/1,e/1+n)}let n=null;function t(){return(null===n||!0===n.buffer.detached||void 0===n.buffer.detached&&n.buffer!==l.memory.buffer)&&(n=new DataView(l.memory.buffer)),n}function o(e,n){return function(e,n){a+=n,a>=_&&(u=new TextDecoder("utf-8",{ignoreBOM:!0,fatal:!0}),u.decode(),a=n);return u.decode(c().subarray(e,e+n))}(e>>>0,n)}let r=null;function c(){return null!==r&&0!==r.byteLength||(r=new Uint8Array(l.memory.buffer)),r}function i(e){return null==e}function d(e,n,t){if(void 0===t){const t=s.encode(e),o=n(t.length,1)>>>0;return c().subarray(o,o+t.length).set(t),w=t.length,o}let o=e.length,r=n(o,1)>>>0;const i=c();let d=0;for(;d<o;d++){const n=e.charCodeAt(d);if(n>127)break;i[r+d]=n}if(d!==o){0!==d&&(e=e.slice(d)),r=t(r,o,o=d+3*e.length,1)>>>0;const n=c().subarray(r+d,r+o);d+=s.encodeInto(e,n).written,r=t(r,o,d,1)>>>0}return w=d,r}function f(e){const n=l.__wbindgen_externrefs.get(e);return l.__externref_table_dealloc(e),n}let u=new TextDecoder("utf-8",{ignoreBOM:!0,fatal:!0});u.decode();const _=2146435072;let a=0;const s=new TextEncoder;"encodeInto"in s||(s.encodeInto=function(e,n){const t=s.encode(e);return n.set(t),{read:e.length,written:t.length}});let l,w=0;export function __wbg_set_wasm(e){l=e}
@@ -0,0 +1,36 @@
1
+ /**
2
+ * Copyright (c) 2026 Lily (liwybloc)
3
+ * License-Identifier: LicenseRef-Lily-Personal-NonCommercial-2026
4
+ * See LICENSE for personal, non-commercial license terms.
5
+ */
6
+
7
+
8
+ export const memory: WebAssembly.Memory;
9
+ export const decodeBatch: (a: any, b: number, c: number, d: number) => [number, number, number];
10
+ export const decodeBooleans: (a: any, b: number) => [number, number, number];
11
+ export const decodeFloats: (a: number, b: any) => [number, number, number];
12
+ export const decodeHex: (a: any) => [number, number, number, number];
13
+ export const decodeRaw: (a: any) => [number, number, number];
14
+ export const decodeSigned: (a: number, b: any) => [number, number, number];
15
+ export const decodeStrings: (a: number, b: any) => [number, number, number];
16
+ export const decodeUnsigned: (a: number, b: any) => [number, number, number];
17
+ export const deflateRaw: (a: any) => [number, number, number];
18
+ export const encodeBatch: (a: any, b: number) => [number, number, number];
19
+ export const encodeBooleans: (a: any) => [number, number, number];
20
+ export const encodeFloats: (a: number, b: any) => [number, number, number];
21
+ export const encodeHex: (a: number, b: number) => [number, number, number];
22
+ export const encodeSigned: (a: number, b: any) => [number, number, number];
23
+ export const encodeStrings: (a: number, b: any) => [number, number, number];
24
+ export const encodeUnsigned: (a: number, b: any) => [number, number, number];
25
+ export const frameObject: (a: any) => [number, number, number];
26
+ export const inflateRaw: (a: any, b: number) => [number, number, number];
27
+ export const unframeObject: (a: any, b: number) => [number, number, number];
28
+ export const validateEncoded: (a: number, b: any, c: number, d: number, e: number, f: number, g: number) => [number, number];
29
+ export const validateEnum: (a: any, b: number, c: number, d: number) => [number, number];
30
+ export const validateObject: (a: any, b: any, c: any, d: any, e: any) => [number, number];
31
+ export const __wbindgen_malloc: (a: number, b: number) => number;
32
+ export const __wbindgen_realloc: (a: number, b: number, c: number, d: number) => number;
33
+ export const __wbindgen_externrefs: WebAssembly.Table;
34
+ export const __externref_table_dealloc: (a: number) => void;
35
+ export const __wbindgen_free: (a: number, b: number, c: number) => void;
36
+ export const __wbindgen_start: () => void;
@@ -16,7 +16,6 @@ export interface SonicNativeCore {
16
16
  decodeStrings(kind: number, data: Uint8Array): string[];
17
17
  encodeBooleans(values: boolean[]): Uint8Array;
18
18
  decodeBooleans(data: Uint8Array, count: number): boolean[];
19
- encodeRaw(data: Uint8Array): Uint8Array;
20
19
  decodeRaw(data: Uint8Array): Uint8Array;
21
20
  encodeHex(value: string): Uint8Array;
22
21
  decodeHex(data: Uint8Array): string;
@@ -0,0 +1,7 @@
1
+ /**
2
+ * Copyright (c) 2026 Lily (liwybloc)
3
+ * License-Identifier: LicenseRef-Lily-Personal-NonCommercial-2026
4
+ * See LICENSE for personal, non-commercial license terms.
5
+ */
6
+
7
+ Object.defineProperty(exports,"__esModule",{value:!0}),exports.setNativeCore=setNativeCore,exports.initializeWasmCore=initializeWasmCore,exports.loadNativeCore=loadNativeCore,exports.encodeNative=encodeNative,exports.decodeNative=decodeNative,exports.validateNative=validateNative,exports.encodeNativeObject=encodeNativeObject,exports.decodeNativeObject=decodeNativeObject,exports.validateNativeObject=validateNativeObject,exports.encodeNativeBatch=encodeNativeBatch,exports.decodeNativeBatch=decodeNativeBatch,exports.deflateNative=deflateNative,exports.inflateNative=inflateNative;const PacketType_1=require("../ws/packets/PacketType"),version_1=require("../version"),CDN_RELEASE="https://cdn.jsdelivr.net/gh/liwybloc/sonic-ws/release",CDN_WASM=`${CDN_RELEASE}/bundle.wasm`,CDN_VERSION=`${CDN_RELEASE}/version`;let loadedCore,wasmInitialization;function buffer(e){return"undefined"!=typeof Buffer?Buffer.from(e.buffer,e.byteOffset,e.byteLength):new Uint8Array(e.buffer,e.byteOffset,e.byteLength)}function values(e){return Array.isArray(e)?[...e]:[e]}function assertNativeCore(e){const t=["encodeSigned","decodeSigned","encodeUnsigned","decodeUnsigned","encodeFloats","decodeFloats","encodeStrings","decodeStrings","encodeBooleans","decodeBooleans","decodeRaw","encodeHex","decodeHex","frameObject","unframeObject","encodeBatch","decodeBatch","deflateRaw","inflateRaw","validateEncoded","validateEnum","validateObject"].filter(t=>"function"!=typeof e[t]);if(t.length>0)throw new Error(`Invalid SonicWS native addon; missing: ${t.join(", ")}`)}function setNativeCore(e){assertNativeCore(e),loadedCore=e}function fetchUrl(e){return"string"==typeof e?e:e instanceof URL?e.href:e.url}async function isWasm(e){if(!e.ok)return!1;const t=new Uint8Array(await e.clone().arrayBuffer());return t.length>=4&&0===t[0]&&97===t[1]&&115===t[2]&&109===t[3]}async function fetchCdnWasm(e){const t=await e(CDN_VERSION,{cache:"no-store"});if(!t.ok)throw new Error(`Unable to verify SonicWS CDN protocol version (${t.status})`);const a=Number((await t.text()).trim());if(!Number.isInteger(a)||a!==version_1.VERSION)throw new Error(`SonicWS CDN protocol mismatch: expected ${version_1.VERSION}, received ${String(a)}`);const n=await e(CDN_WASM);if(!await isWasm(n))throw new Error("SonicWS CDN returned an invalid WASM module");return n}async function initializeBrowserWasm(){const e=window.fetch.bind(window);window.fetch=async(t,a)=>{const n=fetchUrl(t);if(n===CDN_WASM||!new URL(n,window.location.href).pathname.endsWith("/bundle.wasm"))return e(t,a);try{const n=await e(t,a);if(await isWasm(n))return n}catch{}return fetchCdnWasm(e)};try{return setNativeCore(await import("./wasm/pkg/sonic_ws_core.js")),loadedCore}finally{window.fetch=e}}function initializeWasmCore(){return loadedCore?Promise.resolve(loadedCore):wasmInitialization||(wasmInitialization=(async()=>{if("undefined"!=typeof window)return initializeBrowserWasm();const wasm=eval("require")("./wasm/node/sonic_ws_core.js");return setNativeCore(wasm),loadedCore})().finally(()=>{wasmInitialization=void 0}),wasmInitialization)}function loadNativeCore(addonPath){if(loadedCore&&!addonPath)return loadedCore;const candidates=addonPath?[addonPath]:["undefined"!=typeof process?process.env.SONIC_WS_CORE_PATH:void 0,"undefined"!=typeof __dirname?`${__dirname}/sonic_ws_core.node`:void 0,"undefined"!=typeof __dirname?`${__dirname}/../../../native/sonic_ws_core.node`:void 0].filter(e=>Boolean(e)),failures=[],nodeRequire="undefined"==typeof window?eval("require"):void 0;for(const e of candidates)try{const t=nodeRequire(e);return assertNativeCore(t),addonPath||(loadedCore=t),t}catch(t){failures.push(`${e}: ${t instanceof Error?t.message:String(t)}`)}if("undefined"==typeof window)try{const e=nodeRequire("./wasm/node/sonic_ws_core.js");return assertNativeCore(e),loadedCore=e,e}catch(e){failures.push(`Node WASM fallback: ${e instanceof Error?e.message:String(e)}`)}throw new Error(`SonicWS codec is not initialized. In Node, set SONIC_WS_CORE_PATH; in browsers, await initializeWasmCore().\n${failures.join("\n")}`)}function enumIndex(e,t){const a=e.values.findIndex(e=>e===t||"number"==typeof e&&"number"==typeof t&&Number.isNaN(e)&&Number.isNaN(t));if(a<0)throw new Error(`Value ${String(t)} does not exist in enum ${e.tag}`);return a}function encodeNative(e,t,a,n=loadNativeCore()){switch(e){case PacketType_1.PacketType.NONE:if(null!=t&&(!Array.isArray(t)||0!==t.length))throw new TypeError("NONE only accepts null, undefined, or an empty array");return new Uint8Array(0);case PacketType_1.PacketType.RAW:case PacketType_1.PacketType.JSON:if(!(t instanceof Uint8Array||Array.isArray(t)))throw new TypeError((e===PacketType_1.PacketType.JSON?"JSON wire data":"RAW")+" requires a Uint8Array or number array");return t instanceof Uint8Array?buffer(t):Uint8Array.from(t);case PacketType_1.PacketType.BYTES:case PacketType_1.PacketType.SHORTS:case PacketType_1.PacketType.VARINT:case PacketType_1.PacketType.DELTAS:return n.encodeSigned(e,values(t));case PacketType_1.PacketType.UBYTES:case PacketType_1.PacketType.USHORTS:case PacketType_1.PacketType.UVARINT:return n.encodeUnsigned(e,values(t));case PacketType_1.PacketType.FLOATS:case PacketType_1.PacketType.DOUBLES:return n.encodeFloats(e,values(t));case PacketType_1.PacketType.STRINGS_ASCII:case PacketType_1.PacketType.STRINGS_UTF16:return n.encodeStrings(e,values(t));case PacketType_1.PacketType.BOOLEANS:return n.encodeBooleans(values(t));case PacketType_1.PacketType.HEX:{const e=Array.isArray(t)?t[0]:t;if("string"!=typeof e)throw new TypeError("HEX requires one string");return n.encodeHex(e)}case PacketType_1.PacketType.ENUMS:if(!a)throw new Error("ENUMS requires an EnumPackage");return Uint8Array.from(values(t).map(e=>enumIndex(a,e)));case PacketType_1.PacketType.KEY_EFFECTIVE:throw new Error("KEY_EFFECTIVE is not implemented");default:throw new Error(`Unknown packet type: ${e}`)}}function decodeNative(e,t,a=4294967295,n,r=loadNativeCore()){const o=buffer(t);switch(e){case PacketType_1.PacketType.NONE:if(0!==t.byteLength)throw new Error("NONE packet contains data");return;case PacketType_1.PacketType.RAW:case PacketType_1.PacketType.JSON:return r.decodeRaw(o);case PacketType_1.PacketType.BYTES:case PacketType_1.PacketType.SHORTS:case PacketType_1.PacketType.VARINT:case PacketType_1.PacketType.DELTAS:return r.decodeSigned(e,o);case PacketType_1.PacketType.UBYTES:case PacketType_1.PacketType.USHORTS:case PacketType_1.PacketType.UVARINT:return r.decodeUnsigned(e,o);case PacketType_1.PacketType.FLOATS:case PacketType_1.PacketType.DOUBLES:return r.decodeFloats(e,o);case PacketType_1.PacketType.STRINGS_ASCII:case PacketType_1.PacketType.STRINGS_UTF16:return r.decodeStrings(e,o);case PacketType_1.PacketType.BOOLEANS:return r.decodeBooleans(o,a);case PacketType_1.PacketType.HEX:return r.decodeHex(o);case PacketType_1.PacketType.ENUMS:if(!n)throw new Error("ENUMS requires an EnumPackage");return[...t].map(e=>{if(e>=n.values.length)throw new Error(`Enum index ${e} is out of range`);return n.values[e]});case PacketType_1.PacketType.KEY_EFFECTIVE:throw new Error("KEY_EFFECTIVE is not implemented");default:throw new Error(`Unknown packet type: ${e}`)}}function validateNative(e,t,a,n,r={},o=loadNativeCore()){if(e!==PacketType_1.PacketType.ENUMS)o.validateEncoded(e,buffer(t),a,n,r.compressed??!1,r.batched??!1,r.maxBatchSize);else{if(!r.enumData)throw new Error("ENUMS requires an EnumPackage");o.validateEnum(buffer(t),r.enumData.values.length,a,n)}}function encodeNativeObject(e,t,a=loadNativeCore()){if(t.length!==e.types.length)throw new Error("Object field count does not match schema");let n=0;const r=e.types.map((r,o)=>encodeNative(r,t[o],r===PacketType_1.PacketType.ENUMS?e.enumData?.[n++]:void 0,a));return a.frameObject(r)}function decodeNativeObject(e,t,a=loadNativeCore()){const n=a.unframeObject(buffer(t),e.types.length);let r=0;return n.map((t,n)=>decodeNative(e.types[n],t,e.dataMaxes[n],e.types[n]===PacketType_1.PacketType.ENUMS?e.enumData?.[r++]:void 0,a))}function validateNativeObject(e,t,a=loadNativeCore()){a.validateObject(buffer(t),[...e.types],[...e.dataMins],[...e.dataMaxes],(e.enumData??[]).map(e=>e.values.length))}function encodeNativeBatch(e,t,a=loadNativeCore()){return a.encodeBatch(e.map(buffer),t)}function decodeNativeBatch(e,t,a=0,n,r=loadNativeCore()){const o=Number.isFinite(a)&&a>0?a:0;return r.decodeBatch(buffer(e),t,o,n)}function deflateNative(e,t=loadNativeCore()){return t.deflateRaw(buffer(e))}function inflateNative(e,t,a=loadNativeCore()){return a.inflateRaw(buffer(e),t)}
@@ -50,6 +50,8 @@ export interface IConnection<T> extends IMiddlewareHolder<ConnectionMiddleware>
50
50
  * @param listener Callback for when data is received
51
51
  */
52
52
  raw_onmessage(listener: (data: T) => void): void;
53
+ /** Listens for all raw outgoing messages. */
54
+ raw_onsend(listener: (data: Uint8Array) => void): void;
53
55
  /**
54
56
  * Closes the connection
55
57
  */
@@ -74,6 +76,7 @@ export declare abstract class Connection<T extends {
74
76
  close: (c: number, d: string | undefined) => void;
75
77
  }, K> extends MiddlewareHolder<ConnectionMiddleware> implements IConnection<K> {
76
78
  protected listeners: Record<string, Array<(...data: any[]) => void>>;
79
+ private rawSendListeners;
77
80
  private name;
78
81
  protected closed: boolean;
79
82
  socket: T;
@@ -90,6 +93,7 @@ export declare abstract class Connection<T extends {
90
93
  clearInterval(id: number): void;
91
94
  raw_send(data: Uint8Array): void;
92
95
  raw_onmessage(listener: (data: K) => void): void;
96
+ raw_onsend(listener: (data: Uint8Array) => void): void;
93
97
  close(code?: number, reason?: string | Buffer): void;
94
98
  isClosed(): boolean;
95
99
  setName(name: string): Promise<void>;
@@ -0,0 +1,7 @@
1
+ /**
2
+ * Copyright (c) 2026 Lily (liwybloc)
3
+ * License-Identifier: LicenseRef-Lily-Personal-NonCommercial-2026
4
+ * See LICENSE for personal, non-commercial license terms.
5
+ */
6
+
7
+ Object.defineProperty(exports,"__esModule",{value:!0}),exports.CloseCodes=exports.Connection=void 0,exports.getClosureCause=function(e){if(e>=4e3)return r[e]??"UNKNOWN";switch(e){case 1e3:return"NORMAL_CLOSURE";case 1001:return"GOING_AWAY";case 1002:return"PROTOCOL_ERROR";case 1003:return"UNSUPPORTED_DATA";case 1006:return"ABNORMAL_CLOSURE";default:return"UNKNOWN"}};const e=require("./PacketProcessor"),t=require("./util/packets/BatchHelper");class s extends e.MiddlewareHolder{listeners;rawSendListeners=[];name;closed=!1;socket;_timers={};batcher;_on;_off;id;constructor(e,s,r,o,i){super(),this.id=s,this.listeners={},this.name=r,this.socket=e,this.batcher=new t.BatchHelper,this._on=o,this._off=i,this._on("close",()=>{this.callMiddleware("onStatusChange",WebSocket.CLOSED),this.closed=!0;for(const[e,t,s]of Object.values(this._timers))this.clearTimeout(e),s&&t(!0)}),this._on("open",()=>this.callMiddleware("onStatusChange",WebSocket.OPEN))}setTimeout(e,t,s=!1){const r=setTimeout(()=>{e(),this.clearTimeout(r)},t);return this._timers[r]=[r,e,s],r}setInterval(e,t,s=!1){const r=setInterval(e,t);return this._timers[r]=[r,e,s],r}clearTimeout(e){clearTimeout(e),delete this._timers[e]}clearInterval(e){this.clearTimeout(e)}raw_send(e){this.socket.send(e);for(const t of this.rawSendListeners)t(e)}raw_onmessage(e){this._on("message",e)}raw_onsend(e){this.rawSendListeners.push(e)}close(e=1e3,t){this.closed=!0,this.socket.close(e,t?.toString())}isClosed(){return this.closed||this.socket.readyState==WebSocket.CLOSED}async setName(e){await this.callMiddleware("onNameChange",e)||(this.name=e)}getName(){return this.name}}var r;exports.Connection=s,function(e){e[e.RATELIMIT=4e3]="RATELIMIT",e[e.SMALL=4001]="SMALL",e[e.INVALID_KEY=4002]="INVALID_KEY",e[e.INVALID_PACKET=4003]="INVALID_PACKET",e[e.INVALID_DATA=4004]="INVALID_DATA",e[e.REPEATED_HANDSHAKE=4005]="REPEATED_HANDSHAKE",e[e.DISABLED_PACKET=4006]="DISABLED_PACKET",e[e.MIDDLEWARE=4007]="MIDDLEWARE",e[e.MANUAL_SHUTDOWN=4008]="MANUAL_SHUTDOWN"}(r||(exports.CloseCodes=r={}));
@@ -36,11 +36,6 @@ export declare abstract class SonicWSCore<T extends {
36
36
  private dataHandler;
37
37
  private messageHandler;
38
38
  protected listen(tag: string, listener: (data: any[]) => void): void;
39
- /**
40
- * Listens for all sent messages rawly
41
- * @param listener Callback for when data is received
42
- */
43
- raw_onsend(listener: (data: Uint8Array) => void): void;
44
39
  private sendQueue;
45
40
  /**
46
41
  * Sends a packet to the server
@@ -4,4 +4,4 @@
4
4
  * See LICENSE for personal, non-commercial license terms.
5
5
  */
6
6
 
7
- Object.defineProperty(exports,"__esModule",{value:!0}),exports.SonicWSCore=void 0;const e=require("../../util/packets/PacketHolder"),t=require("../../util/packets/CompressionUtil"),s=require("../../../native/wrapper"),i=require("../../util/packets/PacketUtils"),a=require("../../../version"),r=require("../../packets/Packets"),n=require("../../util/packets/BatchHelper"),c=require("../../util/BufferUtil"),o=require("../../Connection"),h=require("../../util/StringUtil");class l extends o.Connection{preListen;clientPackets=new e.PacketHolder;serverPackets=new e.PacketHolder;pastKeys=!1;readyListeners=[];bufferHandler;_timers={};asyncData={};asyncMap={};constructor(e,t,s,i){super(e,-1,"LocalSocket",s,i),this.socket=e,this.preListen={},this.invalidPacket=this.invalidPacket.bind(this),this.serverKeyHandler=this.serverKeyHandler.bind(this),this.messageHandler=this.messageHandler.bind(this),this._on("message",this.serverKeyHandler),this._on("close",()=>{this.callMiddleware("onStatusChange",WebSocket.CLOSED);for(const[e,t,s]of Object.values(this._timers))this.clearTimeout(e),s&&t(!0);for(const e of this.clientPackets.getPackets())delete e.lastSent[0];for(const e of this.serverPackets.getPackets())delete e.lastReceived[0]}),this.bufferHandler=t}reading=!1;readQueue=[];async serverKeyHandler(e){if(this.reading)return this.readQueue.push(e);this.reading=!0;const i=await this.bufferHandler(e);if(i.length<3||(0,h.as8String)(i.slice(0,3))!=a.SERVER_SUFFIX)throw this.close(1e3),new Error("The server requested is not a Sonic WS server.");const n=i[3];if(n!=a.VERSION)throw this.close(1e3),new Error(`Version mismatch: ${n>a.VERSION?"client":"server"} is outdated (server: ${n}, client: ${a.VERSION})`);const c=(0,s.inflateNative)(i.subarray(4,i.length)),[o,l]=(0,t.readVarInt)(c,0);this.id=l;const[d,u]=(0,t.readVarInt)(c,o),k=c.subarray(d,d+u);this.clientPackets.holdPackets(r.Packet.deserializeAll(k,!0));const f=c.subarray(d+u,c.length);this.serverPackets.holdPackets(r.Packet.deserializeAll(f,!0)),this.batcher.registerSendPackets(this.clientPackets,this);for(const e of this.serverPackets.getPackets()){const t=this.serverPackets.getKey(e.tag);this.asyncMap[t]=e.async,e.async&&(this.asyncData[t]=[!1,[]])}Object.keys(this.preListen).forEach(e=>this.preListen[e].forEach(t=>{if(!this.serverPackets.hasTag(e))return console.error(new Error(`The server does not send the packet with tag "${e}"!`));this.listen(e,t)})),this.preListen=null,this.pastKeys=!0,this.readyListeners.forEach(e=>e()),this.readyListeners=null,this._off("message",this.serverKeyHandler),this._on("message",this.messageHandler),this.readQueue.forEach(e=>this.messageHandler(e)),this.readQueue=[]}invalidPacket(e){throw console.error(e),new Error("An error occured with data from the server!! This is probably my fault.. make an issue at https://github.com/liwybloc/sonic-ws")}listenLock=!1;packetQueue=[];async listenPacket(e,t,s,i,a){const r=this.listeners[t];if(!r)return console.warn("Warn: No listener for packet "+t);await this.enqueuePacket(e,r,s,i,a),await this.callMiddleware("onReceive_post",t,"string"==typeof e?[e]:e[0])}isAsync(e){return this.asyncMap[e]}async enqueuePacket(e,t,s,a,r){await(0,i.listenPacket)(e,t,this.invalidPacket),await this.triggerNextPacket(s,a,r)}async triggerNextPacket(e,t,s){t?s[0]=!1:this.listenLock=!1,e.length>0&&this.dataHandler(e.shift())}async dataHandler(e){const t=e[0],s=e.slice(1),i=this.isAsync(t);let a,r,c;if(i?(c=this.asyncData[t],a=c[0],r=c[1]):(a=this.listenLock,r=this.packetQueue),a)return void r.push(e);i?c[0]=!0:this.listenLock=!0;const o=this.serverPackets.getTag(t),h=this.serverPackets.getPacket(o);if(await this.callMiddleware("onReceive_pre",h.tag,e,e.length))return;if(h.rereference&&0==s.length)return void 0===h.lastReceived[0]?this.invalidPacket("No previous value to rereference"):void this.listenPacket(h.lastReceived[0],o,r,i,c);if(0==h.dataBatching){const e=h.lastReceived[0]=await h.listen(s,null);return void this.listenPacket(e,o,r,i,c)}const l=await n.BatchHelper.unravelBatch(h,s,null);if("string"==typeof l)return this.invalidPacket(l);l.forEach(e=>this.listenPacket(e,o,r,i,c))}async messageHandler(e){const t=await this.bufferHandler(e);t.length<1||await this.dataHandler(t)}listen(e,t){this.serverPackets.hasTag(e)?(this.listeners[e]??=[]).push(t):console.log("Tag is not available on server: "+e)}raw_onsend(e){this.listeners.send.push(e)}sendQueue=[!1,[],void 0];async send(e,...t){if(await this.callMiddleware("onSend_pre",e,t,Date.now(),performance.now()))return;const[s,a,r]=await(0,i.processPacket)(this.clientPackets,e,t,this.sendQueue,0);0==r.dataBatching?this.raw_send((0,c.toPacketBuffer)(s,a)):this.batcher.batchPacket(s,a),await this.callMiddleware("onSend_post",e,a,a.length)}on_ready(e){this.pastKeys?e():this.readyListeners.push(e)}on_close(e){this._on("close",e)}on(e,t){if(this.socket.readyState!==WebSocket.OPEN)return this.preListen[e]||(this.preListen[e]=[]),void this.preListen[e].push(t);this.listen(e,t)}}exports.SonicWSCore=l;
7
+ Object.defineProperty(exports,"__esModule",{value:!0}),exports.SonicWSCore=void 0;const e=require("../../util/packets/PacketHolder"),t=require("../../util/packets/CompressionUtil"),s=require("../../../native/wrapper"),i=require("../../util/packets/PacketUtils"),a=require("../../../version"),r=require("../../packets/Packets"),n=require("../../util/packets/BatchHelper"),c=require("../../util/BufferUtil"),o=require("../../Connection"),h=require("../../util/StringUtil");class l extends o.Connection{preListen;clientPackets=new e.PacketHolder;serverPackets=new e.PacketHolder;pastKeys=!1;readyListeners=[];bufferHandler;_timers={};asyncData={};asyncMap={};constructor(e,t,s,i){super(e,-1,"LocalSocket",s,i),this.socket=e,this.preListen={},this.invalidPacket=this.invalidPacket.bind(this),this.serverKeyHandler=this.serverKeyHandler.bind(this),this.messageHandler=this.messageHandler.bind(this),this._on("message",this.serverKeyHandler),this._on("close",()=>{this.callMiddleware("onStatusChange",WebSocket.CLOSED);for(const[e,t,s]of Object.values(this._timers))this.clearTimeout(e),s&&t(!0);for(const e of this.clientPackets.getPackets())delete e.lastSent[0];for(const e of this.serverPackets.getPackets())delete e.lastReceived[0]}),this.bufferHandler=t}reading=!1;readQueue=[];async serverKeyHandler(e){if(this.reading)return this.readQueue.push(e);this.reading=!0;const i=await this.bufferHandler(e);if(i.length<3||(0,h.as8String)(i.slice(0,3))!=a.SERVER_SUFFIX)throw this.close(1e3),new Error("The server requested is not a Sonic WS server.");const n=i[3];if(n!=a.VERSION)throw this.close(1e3),new Error(`Version mismatch: ${n>a.VERSION?"client":"server"} is outdated (server: ${n}, client: ${a.VERSION})`);const c=(0,s.inflateNative)(i.subarray(4,i.length)),[o,l]=(0,t.readVarInt)(c,0);this.id=l;const[d,u]=(0,t.readVarInt)(c,o),k=c.subarray(d,d+u);this.clientPackets.holdPackets(r.Packet.deserializeAll(k,!0));const f=c.subarray(d+u,c.length);this.serverPackets.holdPackets(r.Packet.deserializeAll(f,!0)),this.batcher.registerSendPackets(this.clientPackets,this);for(const e of this.serverPackets.getPackets()){const t=this.serverPackets.getKey(e.tag);this.asyncMap[t]=e.async,e.async&&(this.asyncData[t]=[!1,[]])}Object.keys(this.preListen).forEach(e=>this.preListen[e].forEach(t=>{if(!this.serverPackets.hasTag(e))return console.error(new Error(`The server does not send the packet with tag "${e}"!`));this.listen(e,t)})),this.preListen=null,this.pastKeys=!0,this.readyListeners.forEach(e=>e()),this.readyListeners=null,this._off("message",this.serverKeyHandler),this._on("message",this.messageHandler),this.readQueue.forEach(e=>this.messageHandler(e)),this.readQueue=[]}invalidPacket(e){throw console.error(e),new Error("An error occured with data from the server!! This is probably my fault.. make an issue at https://github.com/liwybloc/sonic-ws")}listenLock=!1;packetQueue=[];async listenPacket(e,t,s,i,a){const r=this.listeners[t];if(!r)return console.warn("Warn: No listener for packet "+t);await this.enqueuePacket(e,r,s,i,a),await this.callMiddleware("onReceive_post",t,"string"==typeof e?[e]:e[0])}isAsync(e){return this.asyncMap[e]}async enqueuePacket(e,t,s,a,r){await(0,i.listenPacket)(e,t,this.invalidPacket),await this.triggerNextPacket(s,a,r)}async triggerNextPacket(e,t,s){t?s[0]=!1:this.listenLock=!1,e.length>0&&this.dataHandler(e.shift())}async dataHandler(e){const t=e[0],s=e.slice(1),i=this.isAsync(t);let a,r,c;if(i?(c=this.asyncData[t],a=c[0],r=c[1]):(a=this.listenLock,r=this.packetQueue),a)return void r.push(e);i?c[0]=!0:this.listenLock=!0;const o=this.serverPackets.getTag(t),h=this.serverPackets.getPacket(o);if(await this.callMiddleware("onReceive_pre",h.tag,e,e.length))return;if(h.rereference&&0==s.length)return void 0===h.lastReceived[0]?this.invalidPacket("No previous value to rereference"):void this.listenPacket(h.lastReceived[0],o,r,i,c);if(0==h.dataBatching){const e=h.lastReceived[0]=await h.listen(s,null);return void this.listenPacket(e,o,r,i,c)}const l=await n.BatchHelper.unravelBatch(h,s,null);if("string"==typeof l)return this.invalidPacket(l);l.forEach(e=>this.listenPacket(e,o,r,i,c))}async messageHandler(e){const t=await this.bufferHandler(e);t.length<1||await this.dataHandler(t)}listen(e,t){this.serverPackets.hasTag(e)?(this.listeners[e]??=[]).push(t):console.log("Tag is not available on server: "+e)}sendQueue=[!1,[],void 0];async send(e,...t){if(await this.callMiddleware("onSend_pre",e,t,Date.now(),performance.now()))return;const[s,a,r]=await(0,i.processPacket)(this.clientPackets,e,t,this.sendQueue,0);0==r.dataBatching?this.raw_send((0,c.toPacketBuffer)(s,a)):this.batcher.batchPacket(s,a),await this.callMiddleware("onSend_post",e,a,a.length)}on_ready(e){this.pastKeys?e():this.readyListeners.push(e)}on_close(e){this._on("close",e)}on(e,t){if(this.socket.readyState!==WebSocket.OPEN)return this.preListen[e]||(this.preListen[e]=[]),void this.preListen[e].push(t);this.listen(e,t)}}exports.SonicWSCore=l;
@@ -0,0 +1,7 @@
1
+ /**
2
+ * Copyright (c) 2026 Lily (liwybloc)
3
+ * License-Identifier: LicenseRef-Lily-Personal-NonCommercial-2026
4
+ * See LICENSE for personal, non-commercial license terms.
5
+ */
6
+
7
+ var e,t=this&&this.__createBinding||(Object.create?function(e,t,s,n){void 0===n&&(n=s);var i=Object.getOwnPropertyDescriptor(t,s);i&&!("get"in i?!t.__esModule:i.writable||i.configurable)||(i={enumerable:!0,get:function(){return t[s]}}),Object.defineProperty(e,n,i)}:function(e,t,s,n){void 0===n&&(n=s),e[n]=t[s]}),s=this&&this.__setModuleDefault||(Object.create?function(e,t){Object.defineProperty(e,"default",{enumerable:!0,value:t})}:function(e,t){e.default=t}),n=this&&this.__importStar||(e=function(t){return e=Object.getOwnPropertyNames||function(e){var t=[];for(var s in e)Object.prototype.hasOwnProperty.call(e,s)&&(t[t.length]=s);return t},e(t)},function(n){if(n&&n.__esModule)return n;var i={};if(null!=n)for(var a=e(n),r=0;r<a.length;r++)"default"!==a[r]&&t(i,n,a[r]);return s(i,n),i});Object.defineProperty(exports,"__esModule",{value:!0}),exports.SonicWSServer=void 0;const i=n(require("ws")),a=require("node:fs/promises"),r=require("node:path"),o=require("./SonicWSConnection"),c=require("../util/packets/PacketHolder"),l=require("../util/packets/CompressionUtil"),h=require("../../native/wrapper"),d=require("../../version"),u=require("../util/packets/PacketUtils"),g=require("../PacketProcessor"),p=require("../util/packets/HashUtil"),w=require("../Connection"),v=require("../debug/DebugServer"),f=e=>{if(!Number.isFinite(e)||e<0)throw new Error("Rate limit must be a non-negative finite number.");return(e=Math.floor(e))>l.MAX_USHORT?(console.warn(`A rate limit above ${l.MAX_USHORT} is considered infinite.`),0):e};class b extends g.MiddlewareHolder{wss;availableIds=[];lastId=0;connectListeners=[];clientPackets;serverPackets;connections=[];connectionMap={};clientRateLimit=500;serverRateLimit=500;handshakePacket=null;tags=new Map;tagsInv=new Map;serverwideSendQueue=[!1,[],void 0];constructor(e){super();const{clientPackets:t=[],serverPackets:s=[],websocketOptions:n={}}=e;if(this.wss=new i.WebSocketServer(n),e.sonicServerSettings?.serveBrowserClient??1){const e=n.server??this.wss._server;e&&this.installBrowserAssetRoutes(e)}this.clientPackets=new c.PacketHolder(t),this.serverPackets=new c.PacketHolder(s);const a=this.clientPackets.serialize(),r=this.serverPackets.serialize(),u=[...d.SERVER_SUFFIX_NUMS,d.VERSION],g=[...(0,l.convertVarInt)(a.length),...a,...r];(0,p.setHashFunc)(e.sonicServerSettings?.bit64Hash??!0),this.wss.on("connection",async e=>{const t=new o.SonicWSConnection(e,this,this.generateSocketID(),this.handshakePacket,this.clientRateLimit,this.serverRateLimit);if(await this.callMiddleware("onClientConnect",t))return t.close(w.CloseCodes.MIDDLEWARE,"Connection blocked by middleware."),this.callMiddleware("onClientDisconnect",t,w.CloseCodes.MIDDLEWARE,Buffer.from("Connection blocked by middleware.")),void this.availableIds.push(t.id);const s=new Uint8Array([...(0,l.convertVarInt)(t.id),...g]);e.send([...u,...(0,h.deflateNative)(s)]),this.connections.push(t),this.connectionMap[t.id]=t,this.connectListeners.forEach(e=>e(t)),e.on("close",(e,s)=>{if(this.connections.splice(this.connections.indexOf(t),1),delete this.connectionMap[t.id],this.availableIds.push(t.id),this.tags.has(t)){for(const e of this.tags.get(t))this.tagsInv.get(e)?.delete(t);this.tags.delete(t)}this.callMiddleware("onClientDisconnect",t,e,s)})}),(e.sonicServerSettings?.checkForUpdates??1)&&fetch("https://raw.githubusercontent.com/liwybloc/sonic-ws/refs/heads/main/release/version").then(e=>e.text()).then(e=>{parseInt(e)>d.VERSION&&console.warn(`SonicWS is currently running outdated! (current: ${d.VERSION}, latest: ${e}) Update with "npm update sonic-ws"`)}).catch(e=>{console.error(e),console.warn("Could not check SonicWS version.")})}installBrowserAssetRoutes(e){const t=e.listeners("request");e.removeAllListeners("request"),e.on("request",(s,n)=>{const i=new URL(s.url??"/","http://localhost").pathname,o="/SonicWS/bundle.js"===i?["bundle.js","text/javascript; charset=utf-8"]:"/SonicWS/bundle.wasm"===i?["bundle.wasm","application/wasm"]:void 0;if(!o){for(const i of t)Reflect.apply(i,e,[s,n]);return}const c=(0,r.resolve)(__dirname,"../../../bundled",o[0]);(0,a.readFile)(c).then(e=>{n.writeHead(200,{"content-type":o[1],"content-length":e.byteLength,"cache-control":"public, max-age=3600"}),n.end(e)}).catch(e=>{n.writeHead(500,{"content-type":"text/plain; charset=utf-8"}),n.end(`Unable to load SonicWS browser asset: ${e instanceof Error?e.message:String(e)}`)})})}generateSocketID(){return 0==this.availableIds.length&&this.availableIds.push(this.lastId+1),this.lastId=this.availableIds.shift(),this.lastId}requireHandshake(e){if(!this.clientPackets.hasTag(e))throw new Error(`The client does not send "${e}" and so it cannot use it as a handshake!`);if(0!=this.clientPackets.getPacket(e).dataBatching)throw new Error(`The packet "${e}" is a batched packet, and cannot be used as a handshake!`);this.handshakePacket=e}setClientRateLimit(e){this.clientRateLimit=f(e)}setServerRateLimit(e){this.serverRateLimit=f(e)}enablePacket(e){this.clientPackets.getPacket(e).defaultEnabled=!0,this.connections.forEach(t=>t.enablePacket(e))}disablePacket(e){this.clientPackets.getPacket(e).defaultEnabled=!1,this.connections.forEach(t=>t.disablePacket(e))}on_connect(e){this.connectListeners.push(e)}on_ready(e){this.wss.on("listening",e)}shutdown(e){this.wss.close(e)}async broadcastInternal(e,t,s){let n;if("all"===t.type)n=this.connections;else if("tagged"===t.type){if(!this.tagsInv.has(t.tag))return;n=Array.from(this.tagsInv.get(t.tag))}else n=this.connections.filter(t.filter);if(await this.callMiddleware("onPacketBroadcast_pre",e,{recipients:n,...t},s))return;if(0===n.length)return;const[i,a,r]=await(0,u.processPacket)(this.serverPackets,e,s,this.serverwideSendQueue,-1);await this.callMiddleware("onPacketBroadcast_post",e,{recipients:n,...t},a,a.length)||n.forEach(e=>e.send_processed(i,a,r))}async broadcastTagged(e,t,...s){await this.broadcastInternal(t,{type:"tagged",tag:e},s)}async broadcastFiltered(e,t,...s){await this.broadcastInternal(e,{type:"filter",filter:t},s)}async broadcast(e,...t){await this.broadcastInternal(e,{type:"all"},t)}getConnected(){return this.connections}getSocket(e){return this.connectionMap[e]}closeSocket(e,t=1e3,s){this.getSocket(e).close(t,s)}tag(e,t,s=!0){this.tags.get(e)||this.tags.set(e,new Set),this.tagsInv.get(t)||this.tagsInv.set(t,new Set),s&&this.tags.get(e).forEach(t=>this.tagsInv.get(t)?.delete(e)),this.tags.get(e).add(t),this.tagsInv.get(t).add(e)}debugServer=null;OpenDebug(e={}){if(null!=this.debugServer)throw new Error("Attempted to open a debug server when one has already been opened.");this.debugServer=new v.DebugServer(this,e)}}exports.SonicWSServer=b;
@@ -5,6 +5,7 @@
5
5
  */
6
6
  /** Utilities still required by schema serialization and the connection handshake. */
7
7
  export declare const MAX_BYTE = 255;
8
+ export declare const MAX_USHORT = 65535;
8
9
  export declare const MAX_UVARINT: number;
9
10
  export declare const EMPTY_UINT8: Uint8Array<ArrayBuffer>;
10
11
  export declare const compressBools: (values: boolean[]) => number;
@@ -0,0 +1,7 @@
1
+ /**
2
+ * Copyright (c) 2026 Lily (liwybloc)
3
+ * License-Identifier: LicenseRef-Lily-Personal-NonCommercial-2026
4
+ * See LICENSE for personal, non-commercial license terms.
5
+ */
6
+
7
+ Object.defineProperty(exports,"__esModule",{value:!0}),exports.decompressBools=exports.compressBools=exports.EMPTY_UINT8=exports.MAX_UVARINT=exports.MAX_USHORT=exports.MAX_BYTE=void 0,exports.convertVarInt=function(e){if(!Number.isSafeInteger(e)||e<0||e>exports.MAX_UVARINT)throw new Error(`Variable Ints must be within range 0 and ${exports.MAX_UVARINT}: ${e}`);const r=[];do{let o=e%128;(e=Math.floor(e/128))>0&&(o|=128),r.push(o)}while(e>0);return r},exports.readVarInt=function(e,r){let o=0,t=1;for(let s=0;s<8;s++){if(r>=e.length)throw new Error("Truncated variable integer");const s=e[r++];if(o+=(127&s)*t,!(128&s))return[r,o];t*=128}throw new Error("Variable integer is too long")},exports.MAX_BYTE=255,exports.MAX_USHORT=65535,exports.MAX_UVARINT=128**7-1,exports.EMPTY_UINT8=new Uint8Array([]);exports.compressBools=e=>e.reduce((e,r,o)=>e|Number(r)<<7-o,0);exports.decompressBools=e=>Array.from({length:8},(r,o)=>!!(e&1<<7-o));
@@ -0,0 +1,7 @@
1
+ /**
2
+ * Copyright (c) 2026 Lily (liwybloc)
3
+ * License-Identifier: LicenseRef-Lily-Personal-NonCommercial-2026
4
+ * See LICENSE for personal, non-commercial license terms.
5
+ */
6
+
7
+ Object.defineProperty(exports,"__esModule",{value:!0}),exports.processPacket=o,exports.listenPacket=async function(e,t,a){if("string"==typeof e)return a(e);const[n,r]=e;try{if(r&&Array.isArray(n))for(const e of t)await e(...n);else for(const e of t)await e(n)}catch(e){console.error(e),a(e)}},exports.CreatePacket=f,exports.CreateObjPacket=function(a){let{tag:n,types:r=[],dataMaxes:o,dataMins:f,noDataRange:h=!1,dontSpread:p=!1,autoFlatten:m=!1,validator:y=null,dataBatching:d=0,maxBatchSize:w=10,rateLimit:g=0,enabled:k=!0,async:E=!1,gzipCompression:P=r&&r.includes(t.PacketType.JSON)}=a;if(!n)throw new Error("Tag not selected!");if(!r||0==r.length)throw new Error("Types is set to 0 length");for(const e of r)if(i(e))throw new Error(`Invalid packet type in "${n}" packet: ${e}`);h?(o=Array.from({length:r.length}).map(()=>s),f=Array.from({length:r.length}).map(()=>0)):(null==o?o=Array.from({length:r.length}).map(()=>1):Array.isArray(o)||(o=Array.from({length:r.length}).map(()=>o)),null==f?f=Array.from({length:r.length}).map((e,t)=>o[t]):Array.isArray(f)||(f=Array.from({length:r.length}).map(()=>f)));const S=o.map(c),v=f.map((e,a)=>r[a]==t.PacketType.NONE?0:l(e,S[a])),x=new e.PacketSchema(!0,r,E,v,S,u(g),p,m,!1,d,w,P);return new e.Packet(n,x,y,k,!1)},exports.CreateEnumPacket=function(e){const{tag:t,enumData:a,dataMax:n=1,dataMin:r=0,noDataRange:o=!1,dontSpread:i=!1,validator:s=null,dataBatching:c=0,maxBatchSize:l=10,rateLimit:u=0,enabled:h=!0,async:p=!1}=e;return f({tag:t,type:a,dataMax:n,dataMin:r,noDataRange:o,dontSpread:i,validator:s,dataBatching:c,maxBatchSize:l,rateLimit:u,enabled:h,async:p})},exports.CreateKeyEffective=function(e){const{tag:t,count:a=2,validator:n=null,async:r=!1}=e;if(!t)throw new Error("Tag not selected!");if(a<2)throw new Error("Must have at least 2 key consumptions on key effective packet!");throw new Error("Currently W.I.P.")},exports.FlattenData=h,exports.UnFlattenData=function(e){return e[0]?.map((t,a)=>e.map(e=>e[a]))??[]};const e=require("../../packets/Packets"),t=require("../../packets/PacketType"),a=require("../enums/EnumType"),n=require("./CompressionUtil"),r=require("./HashUtil");async function o(e,a,i,s,c,l=!1){const u=e.getKey(a),f=e.getPacket(a);return async function(e,t,a,n,r,i,s){if(e[0]&&!i)return new Promise(t=>e[1].push([t,n,r]));e[0]=!0;const c=await s();if(e[1].length>0){const[n,r,i]=e[1].shift();queueMicrotask(async()=>{n(await o(t,r,i,e,a,!0))})}else e[0]=!1;return c}(s,e,c,a,i,l,async()=>{if(f.rereference){if(-1===c)throw new Error("Cannot send a re-referenced packet from the server-wide sender!");const e=(0,r.hashValue)(i);if(f.lastSent[c]===e)return[u,n.EMPTY_UINT8,f];f.lastSent[c]=e}if(f.autoFlatten)i=h(i[0]);else{if(i.length>f.maxSize)throw new Error(`Packet "${a}" only allows ${f.maxSize} values!`);if(i.length<f.minSize)throw new Error(`Packet "${a}" requires at least ${f.minSize} values!`)}if(f.object){if(i=i.map(e=>Array.isArray(e)?e:[e]),!f.autoFlatten){const e=f.dataMin,t=f.dataMax;for(let n=0;n<e.length;n++){if(i[n].length<e[n])throw new Error(`Section ${n+1} of packet "${a}" requires at least ${e[n]} values!`);if(i[n].length>t[n])throw new Error(`Section ${n+1} of packet "${a}" only allows ${t[n]} values!`)}}}else if(f.type!==t.PacketType.JSON){const e=i.find(e=>"object"==typeof e&&null!=e);e&&console.warn(`Passing an array will result in undefined behavior (${JSON.stringify(e)}). Spread the array with ...arr`)}const e=i.length>0?await f.processSend(i):n.EMPTY_UINT8;return[u,e,f]})}function i(e){return!(("number"==typeof e&&e in t.PacketType||e instanceof a.EnumPackage)&&e!=t.PacketType.KEY_EFFECTIVE)}const s=2048383;function c(e){return e<0?(console.warn("Having a data maximum below 0 does not do anything!"),0):e>s?(console.warn(`Only ${s} values can be sent on a type! Uhh make an issue if you want to send more.`),s):e}function l(e,t){return e<0?(console.warn("Having a data minimum below 0 does not do anything!"),0):e>t?(console.warn("Data minimum can not be higher than the data maximum!"),t):e}function u(e){if(!Number.isFinite(e)||e<0)throw new Error("Rate limit must be a non-negative finite number");return(e=Math.floor(e))>n.MAX_USHORT?(console.warn(`A rate limit above ${n.MAX_USHORT} is considered infinite.`),0):e}function f(a){let{tag:n,type:r=t.PacketType.NONE,dataMax:o=1,dataMin:f=1,noDataRange:h=!1,dontSpread:p=!1,validator:m=null,dataBatching:y=0,maxBatchSize:d=10,rateLimit:w=0,enabled:g=!0,async:k=!1,gzipCompression:E=r==t.PacketType.JSON,rereference:P=!1}=a;if(!n)throw new Error("Tag not selected!");if(h?(f=P?1:0,o=s):null==f&&(f=r==t.PacketType.NONE?0:o),P&&0==f)throw new Error("Rereference cannot be true if the dataMin is 0");if(i(r))throw new Error(`Invalid packet type: ${r}`);const S=new e.PacketSchema(!1,r,k,l(f,o),c(o),u(w),p,!1,P,y,d,E);return new e.Packet(n,S,m,g,!1)}function h(e){if(null==e)return[];const t=e[0];if(null==t)return[];if(!Array.isArray(t))throw new Error(`Cannot flatten array: ${e}`);return t.map((t,a)=>e.map(e=>e[a]))??[]}
package/package.json CHANGED
@@ -1,20 +1,32 @@
1
1
  {
2
2
  "name": "sonic-ws",
3
- "version": "2.0.0",
3
+ "version": "2.0.2",
4
4
  "description": "Ultra-lightweight, high-performance, and bandwidth efficient websocket library",
5
- "main": "dist/ts/index.js",
6
- "types": "dist/ts/index.d.ts",
5
+ "main": "dist/index.js",
6
+ "types": "dist/index.d.ts",
7
+ "files": [
8
+ "dist/**/*",
9
+ "bundled/bundle.js",
10
+ "bundled/bundle.wasm",
11
+ "README.md",
12
+ "LICENSE"
13
+ ],
7
14
  "scripts": {
8
15
  "webpack": "webpack --mode production",
9
- "build_wasm_browser": "wasm-pack build --release --target bundler --out-dir ../ts/native/wasm/pkg --out-name sonic_ws_core ./src/core --features wasm --no-default-features",
10
- "build_wasm_node": "wasm-pack build --release --target nodejs --out-dir ../ts/native/wasm/node --out-name sonic_ws_core ./src/core --features wasm --no-default-features",
16
+
17
+ "build_wasm_browser": "wasm-pack build --release --target bundler --out-dir ../ts/src/native/wasm/pkg --out-name sonic_ws_core ../core --features wasm --no-default-features",
18
+ "build_wasm_node": "wasm-pack build --release --target nodejs --out-dir ../ts/src/native/wasm/node --out-name sonic_ws_core ../core --features wasm --no-default-features",
11
19
  "build_wasm": "npm run build_wasm_browser && npm run build_wasm_node",
12
- "build_web": "npm run build_wasm_browser && tsc --moduleResolution nodenext --module nodenext --outDir ./dist/ts src/ts/ws/client/browser/ClientBrowser.ts && cpy \"src/ts/native/wasm/pkg/*\" dist/ts/native/wasm/pkg --flat && npm run webpack",
13
- "build_node": "npm run build_wasm && rimraf ./dist/ts && tsc -d && cpy \"src/ts/native/wasm/node/*\" dist/ts/native/wasm/node --flat",
14
- "build": "npm run build_node && npm run build_web && rimraf ./dist/ts/ws/client/browser && rimraf ./dist/ts/ws/debug/DebugClient.d.ts && rimraf ./dist/ts/ws/debug/DebugClient.js && node minify",
20
+ "build_web": "npm run build_wasm_browser && tsc --moduleResolution nodenext --module nodenext --outDir ./dist src/ws/client/browser/ClientBrowser.ts && cpy \"src/native/wasm/pkg/*\" dist/native/wasm/pkg --flat && rimraf ./dist/native/wasm/pkg/.gitignore && npm run webpack && node package-files.mjs",
21
+ "build_node": "npm run build_wasm && rimraf ./dist && tsc -d && cpy \"src/native/wasm/node/*\" dist/native/wasm/node --flat && rimraf ./dist/native/wasm/node/.gitignore",
22
+ "build": "npm run build_node && npm run build_web && rimraf ./dist/ws/client/browser && rimraf ./dist/ws/debug/DebugClient.d.ts && rimraf ./dist/ws/debug/DebugClient.js && node minify.mjs && node package-files.mjs",
23
+
15
24
  "test_web": "npm run build && node tests/test_web.mjs",
16
- "test_node": "npm --prefix src/core/tests/typescript run build:native && npm run build_node && node tests/test_node.mjs",
17
- "publish": "npm run build && node minify && rimraf ./release/SonicWS_bundle.js ./release/SonicWS_core.wasm && cp ./bundled/bundle.js ./release/bundle.js && cp ./bundled/bundle.wasm ./release/bundle.wasm && sleep 1"
25
+ "test_node": "npm --prefix ../core/tests/typescript run build:native && npm run build_node && node tests/test_node.mjs",
26
+ "prepack": "npm run build",
27
+
28
+ "stage_package": "node package-files.mjs",
29
+ "publish:assets": "rimraf ../../release/SonicWS_bundle.js ../../release/SonicWS_core.wasm && cp ../../bundled/bundle.js ../../release/bundle.js && cp ../../bundled/bundle.wasm ../../release/bundle.wasm"
18
30
  },
19
31
  "repository": {
20
32
  "type": "git",
@@ -1,7 +0,0 @@
1
- /**
2
- * Copyright (c) 2026 Lily (liwybloc)
3
- * License-Identifier: LicenseRef-Lily-Personal-NonCommercial-2026
4
- * See LICENSE for personal, non-commercial license terms.
5
- */
6
-
7
- Object.defineProperty(exports,"__esModule",{value:!0}),exports.setNativeCore=setNativeCore,exports.initializeWasmCore=initializeWasmCore,exports.loadNativeCore=loadNativeCore,exports.encodeNative=encodeNative,exports.decodeNative=decodeNative,exports.validateNative=validateNative,exports.encodeNativeObject=encodeNativeObject,exports.decodeNativeObject=decodeNativeObject,exports.validateNativeObject=validateNativeObject,exports.encodeNativeBatch=encodeNativeBatch,exports.decodeNativeBatch=decodeNativeBatch,exports.deflateNative=deflateNative,exports.inflateNative=inflateNative;const PacketType_1=require("../ws/packets/PacketType");let loadedCore;function buffer(e){return"undefined"!=typeof Buffer?Buffer.from(e.buffer,e.byteOffset,e.byteLength):new Uint8Array(e.buffer,e.byteOffset,e.byteLength)}function values(e){return Array.isArray(e)?[...e]:[e]}function assertNativeCore(e){const t=["encodeSigned","decodeSigned","encodeUnsigned","decodeUnsigned","encodeFloats","decodeFloats","encodeStrings","decodeStrings","encodeBooleans","decodeBooleans","encodeRaw","decodeRaw","encodeHex","decodeHex","frameObject","unframeObject","encodeBatch","decodeBatch","deflateRaw","inflateRaw","validateEncoded","validateEnum","validateObject"].filter(t=>"function"!=typeof e[t]);if(t.length>0)throw new Error(`Invalid SonicWS native addon; missing: ${t.join(", ")}`)}function setNativeCore(e){assertNativeCore(e),loadedCore=e}async function initializeWasmCore(){const wasm="undefined"==typeof window?eval("require")("./wasm/node/sonic_ws_core.js"):await import("./wasm/pkg/sonic_ws_core.js");return setNativeCore(wasm),loadedCore}function loadNativeCore(addonPath){if(loadedCore&&!addonPath)return loadedCore;const candidates=addonPath?[addonPath]:["undefined"!=typeof process?process.env.SONIC_WS_CORE_PATH:void 0,"undefined"!=typeof __dirname?`${__dirname}/sonic_ws_core.node`:void 0,"undefined"!=typeof __dirname?`${__dirname}/../../../native/sonic_ws_core.node`:void 0].filter(e=>Boolean(e)),failures=[],nodeRequire="undefined"==typeof window?eval("require"):void 0;for(const e of candidates)try{const t=nodeRequire(e);return assertNativeCore(t),addonPath||(loadedCore=t),t}catch(t){failures.push(`${e}: ${t instanceof Error?t.message:String(t)}`)}if("undefined"==typeof window)try{const e=nodeRequire("./wasm/node/sonic_ws_core.js");return assertNativeCore(e),loadedCore=e,e}catch(e){failures.push(`Node WASM fallback: ${e instanceof Error?e.message:String(e)}`)}throw new Error(`SonicWS codec is not initialized. In Node, set SONIC_WS_CORE_PATH; in browsers, await initializeWasmCore().\n${failures.join("\n")}`)}function enumIndex(e,t){const a=e.values.findIndex(e=>e===t||"number"==typeof e&&"number"==typeof t&&Number.isNaN(e)&&Number.isNaN(t));if(a<0)throw new Error(`Value ${String(t)} does not exist in enum ${e.tag}`);return a}function encodeNative(e,t,a,r=loadNativeCore()){switch(e){case PacketType_1.PacketType.NONE:if(null!=t&&(!Array.isArray(t)||0!==t.length))throw new TypeError("NONE only accepts null, undefined, or an empty array");return new Uint8Array(0);case PacketType_1.PacketType.RAW:case PacketType_1.PacketType.JSON:if(!(t instanceof Uint8Array||Array.isArray(t)))throw new TypeError((e===PacketType_1.PacketType.JSON?"JSON wire data":"RAW")+" requires a Uint8Array or number array");return r.encodeRaw(t instanceof Uint8Array?buffer(t):Uint8Array.from(t));case PacketType_1.PacketType.BYTES:case PacketType_1.PacketType.SHORTS:case PacketType_1.PacketType.VARINT:case PacketType_1.PacketType.DELTAS:return r.encodeSigned(e,values(t));case PacketType_1.PacketType.UBYTES:case PacketType_1.PacketType.USHORTS:case PacketType_1.PacketType.UVARINT:return r.encodeUnsigned(e,values(t));case PacketType_1.PacketType.FLOATS:case PacketType_1.PacketType.DOUBLES:return r.encodeFloats(e,values(t));case PacketType_1.PacketType.STRINGS_ASCII:case PacketType_1.PacketType.STRINGS_UTF16:return r.encodeStrings(e,values(t));case PacketType_1.PacketType.BOOLEANS:return r.encodeBooleans(values(t));case PacketType_1.PacketType.HEX:{const e=Array.isArray(t)?t[0]:t;if("string"!=typeof e)throw new TypeError("HEX requires one string");return r.encodeHex(e)}case PacketType_1.PacketType.ENUMS:if(!a)throw new Error("ENUMS requires an EnumPackage");return Uint8Array.from(values(t).map(e=>enumIndex(a,e)));case PacketType_1.PacketType.KEY_EFFECTIVE:throw new Error("KEY_EFFECTIVE is not implemented");default:throw new Error(`Unknown packet type: ${e}`)}}function decodeNative(e,t,a=4294967295,r,n=loadNativeCore()){const o=buffer(t);switch(e){case PacketType_1.PacketType.NONE:if(0!==t.byteLength)throw new Error("NONE packet contains data");return;case PacketType_1.PacketType.RAW:case PacketType_1.PacketType.JSON:return n.decodeRaw(o);case PacketType_1.PacketType.BYTES:case PacketType_1.PacketType.SHORTS:case PacketType_1.PacketType.VARINT:case PacketType_1.PacketType.DELTAS:return n.decodeSigned(e,o);case PacketType_1.PacketType.UBYTES:case PacketType_1.PacketType.USHORTS:case PacketType_1.PacketType.UVARINT:return n.decodeUnsigned(e,o);case PacketType_1.PacketType.FLOATS:case PacketType_1.PacketType.DOUBLES:return n.decodeFloats(e,o);case PacketType_1.PacketType.STRINGS_ASCII:case PacketType_1.PacketType.STRINGS_UTF16:return n.decodeStrings(e,o);case PacketType_1.PacketType.BOOLEANS:return n.decodeBooleans(o,a);case PacketType_1.PacketType.HEX:return n.decodeHex(o);case PacketType_1.PacketType.ENUMS:if(!r)throw new Error("ENUMS requires an EnumPackage");return[...t].map(e=>{if(e>=r.values.length)throw new Error(`Enum index ${e} is out of range`);return r.values[e]});case PacketType_1.PacketType.KEY_EFFECTIVE:throw new Error("KEY_EFFECTIVE is not implemented");default:throw new Error(`Unknown packet type: ${e}`)}}function validateNative(e,t,a,r,n={},o=loadNativeCore()){if(e!==PacketType_1.PacketType.ENUMS)o.validateEncoded(e,buffer(t),a,r,n.compressed??!1,n.batched??!1,n.maxBatchSize);else{if(!n.enumData)throw new Error("ENUMS requires an EnumPackage");o.validateEnum(buffer(t),n.enumData.values.length,a,r)}}function encodeNativeObject(e,t,a=loadNativeCore()){if(t.length!==e.types.length)throw new Error("Object field count does not match schema");let r=0;const n=e.types.map((n,o)=>encodeNative(n,t[o],n===PacketType_1.PacketType.ENUMS?e.enumData?.[r++]:void 0,a));return a.frameObject(n)}function decodeNativeObject(e,t,a=loadNativeCore()){const r=a.unframeObject(buffer(t),e.types.length);let n=0;return r.map((t,r)=>decodeNative(e.types[r],t,e.dataMaxes[r],e.types[r]===PacketType_1.PacketType.ENUMS?e.enumData?.[n++]:void 0,a))}function validateNativeObject(e,t,a=loadNativeCore()){a.validateObject(buffer(t),[...e.types],[...e.dataMins],[...e.dataMaxes],(e.enumData??[]).map(e=>e.values.length))}function encodeNativeBatch(e,t,a=loadNativeCore()){return a.encodeBatch(e.map(buffer),t)}function decodeNativeBatch(e,t,a=0,r,n=loadNativeCore()){const o=Number.isFinite(a)&&a>0?a:0;return n.decodeBatch(buffer(e),t,o,r)}function deflateNative(e,t=loadNativeCore()){return t.deflateRaw(buffer(e))}function inflateNative(e,t,a=loadNativeCore()){return a.inflateRaw(buffer(e),t)}
@@ -1,7 +0,0 @@
1
- /**
2
- * Copyright (c) 2026 Lily (liwybloc)
3
- * License-Identifier: LicenseRef-Lily-Personal-NonCommercial-2026
4
- * See LICENSE for personal, non-commercial license terms.
5
- */
6
-
7
- Object.defineProperty(exports,"__esModule",{value:!0}),exports.CloseCodes=exports.Connection=void 0,exports.getClosureCause=function(e){if(e>=4e3)return r[e]??"UNKNOWN";switch(e){case 1e3:return"NORMAL_CLOSURE";case 1001:return"GOING_AWAY";case 1002:return"PROTOCOL_ERROR";case 1003:return"UNSUPPORTED_DATA";case 1006:return"ABNORMAL_CLOSURE";default:return"UNKNOWN"}};const e=require("./PacketProcessor"),t=require("./util/packets/BatchHelper");class s extends e.MiddlewareHolder{listeners;name;closed=!1;socket;_timers={};batcher;_on;_off;id;constructor(e,s,r,o,i){super(),this.id=s,this.listeners={},this.name=r,this.socket=e,this.batcher=new t.BatchHelper,this._on=o,this._off=i,this._on("close",()=>{this.callMiddleware("onStatusChange",WebSocket.CLOSED),this.closed=!0;for(const[e,t,s]of Object.values(this._timers))this.clearTimeout(e),s&&t(!0)}),this._on("open",()=>this.callMiddleware("onStatusChange",WebSocket.OPEN))}setTimeout(e,t,s=!1){const r=setTimeout(()=>{e(),this.clearTimeout(r)},t);return this._timers[r]=[r,e,s],r}setInterval(e,t,s=!1){const r=setInterval(e,t);return this._timers[r]=[r,e,s],r}clearTimeout(e){clearTimeout(e),delete this._timers[e]}clearInterval(e){this.clearTimeout(e)}raw_send(e){this.socket.send(e)}raw_onmessage(e){this._on("message",e)}close(e=1e3,t){this.closed=!0,this.socket.close(e,t?.toString())}isClosed(){return this.closed||this.socket.readyState==WebSocket.CLOSED}async setName(e){await this.callMiddleware("onNameChange",e)||(this.name=e)}getName(){return this.name}}var r;exports.Connection=s,function(e){e[e.RATELIMIT=4e3]="RATELIMIT",e[e.SMALL=4001]="SMALL",e[e.INVALID_KEY=4002]="INVALID_KEY",e[e.INVALID_PACKET=4003]="INVALID_PACKET",e[e.INVALID_DATA=4004]="INVALID_DATA",e[e.REPEATED_HANDSHAKE=4005]="REPEATED_HANDSHAKE",e[e.DISABLED_PACKET=4006]="DISABLED_PACKET",e[e.MIDDLEWARE=4007]="MIDDLEWARE",e[e.MANUAL_SHUTDOWN=4008]="MANUAL_SHUTDOWN"}(r||(exports.CloseCodes=r={}));
@@ -1,7 +0,0 @@
1
- /**
2
- * Copyright (c) 2026 Lily (liwybloc)
3
- * License-Identifier: LicenseRef-Lily-Personal-NonCommercial-2026
4
- * See LICENSE for personal, non-commercial license terms.
5
- */
6
-
7
- var e,t=this&&this.__createBinding||(Object.create?function(e,t,s,n){void 0===n&&(n=s);var i=Object.getOwnPropertyDescriptor(t,s);i&&!("get"in i?!t.__esModule:i.writable||i.configurable)||(i={enumerable:!0,get:function(){return t[s]}}),Object.defineProperty(e,n,i)}:function(e,t,s,n){void 0===n&&(n=s),e[n]=t[s]}),s=this&&this.__setModuleDefault||(Object.create?function(e,t){Object.defineProperty(e,"default",{enumerable:!0,value:t})}:function(e,t){e.default=t}),n=this&&this.__importStar||(e=function(t){return e=Object.getOwnPropertyNames||function(e){var t=[];for(var s in e)Object.prototype.hasOwnProperty.call(e,s)&&(t[t.length]=s);return t},e(t)},function(n){if(n&&n.__esModule)return n;var i={};if(null!=n)for(var a=e(n),r=0;r<a.length;r++)"default"!==a[r]&&t(i,n,a[r]);return s(i,n),i});Object.defineProperty(exports,"__esModule",{value:!0}),exports.SonicWSServer=void 0;const i=n(require("ws")),a=require("node:fs/promises"),r=require("node:path"),o=require("./SonicWSConnection"),c=require("../util/packets/PacketHolder"),l=require("../util/packets/CompressionUtil"),d=require("../../native/wrapper"),h=require("../../version"),u=require("../util/packets/PacketUtils"),g=require("../PacketProcessor"),p=require("../util/packets/HashUtil"),w=require("../Connection"),v=require("../debug/DebugServer");class f extends g.MiddlewareHolder{wss;availableIds=[];lastId=0;connectListeners=[];clientPackets;serverPackets;connections=[];connectionMap={};clientRateLimit=500;serverRateLimit=500;handshakePacket=null;tags=new Map;tagsInv=new Map;serverwideSendQueue=[!1,[],void 0];constructor(e){super();const{clientPackets:t=[],serverPackets:s=[],websocketOptions:n={}}=e;if(this.wss=new i.WebSocketServer(n),e.sonicServerSettings?.serveBrowserClient??1){const e=n.server??this.wss._server;e&&this.installBrowserAssetRoutes(e)}this.clientPackets=new c.PacketHolder(t),this.serverPackets=new c.PacketHolder(s);const a=this.clientPackets.serialize(),r=this.serverPackets.serialize(),u=[...h.SERVER_SUFFIX_NUMS,h.VERSION],g=[...(0,l.convertVarInt)(a.length),...a,...r];(0,p.setHashFunc)(e.sonicServerSettings?.bit64Hash??!0),this.wss.on("connection",async e=>{const t=new o.SonicWSConnection(e,this,this.generateSocketID(),this.handshakePacket,this.clientRateLimit,this.serverRateLimit);if(await this.callMiddleware("onClientConnect",t))return t.close(w.CloseCodes.MIDDLEWARE,"Connection blocked by middleware."),this.callMiddleware("onClientDisconnect",t,w.CloseCodes.MIDDLEWARE,Buffer.from("Connection blocked by middleware.")),void this.availableIds.push(t.id);const s=new Uint8Array([...(0,l.convertVarInt)(t.id),...g]);e.send([...u,...(0,d.deflateNative)(s)]),this.connections.push(t),this.connectionMap[t.id]=t,this.connectListeners.forEach(e=>e(t)),e.on("close",(e,s)=>{if(this.connections.splice(this.connections.indexOf(t),1),delete this.connectionMap[t.id],this.availableIds.push(t.id),this.tags.has(t)){for(const e of this.tags.get(t))this.tagsInv.get(e)?.delete(t);this.tags.delete(t)}this.callMiddleware("onClientDisconnect",t,e,s)})}),(e.sonicServerSettings?.checkForUpdates??1)&&fetch("https://raw.githubusercontent.com/liwybloc/sonic-ws/refs/heads/main/release/version").then(e=>e.text()).then(e=>{parseInt(e)>h.VERSION&&console.warn(`SonicWS is currently running outdated! (current: ${h.VERSION}, latest: ${e}) Update with "npm update sonic-ws"`)}).catch(e=>{console.error(e),console.warn("Could not check SonicWS version.")})}installBrowserAssetRoutes(e){const t=e.listeners("request");e.removeAllListeners("request"),e.on("request",(s,n)=>{const i=new URL(s.url??"/","http://localhost").pathname,o="/SonicWS/bundle.js"===i?["bundle.js","text/javascript; charset=utf-8"]:"/SonicWS/bundle.wasm"===i?["bundle.wasm","application/wasm"]:void 0;if(!o){for(const i of t)Reflect.apply(i,e,[s,n]);return}const c=(0,r.resolve)(__dirname,"../../../../bundled",o[0]);(0,a.readFile)(c).then(e=>{n.writeHead(200,{"content-type":o[1],"content-length":e.byteLength,"cache-control":"public, max-age=3600"}),n.end(e)}).catch(e=>{n.writeHead(500,{"content-type":"text/plain; charset=utf-8"}),n.end(`Unable to load SonicWS browser asset: ${e instanceof Error?e.message:String(e)}`)})})}generateSocketID(){return 0==this.availableIds.length&&this.availableIds.push(this.lastId+1),this.lastId=this.availableIds.shift(),this.lastId}requireHandshake(e){if(!this.clientPackets.hasTag(e))throw new Error(`The client does not send "${e}" and so it cannot use it as a handshake!`);if(0!=this.clientPackets.getPacket(e).dataBatching)throw new Error(`The packet "${e}" is a batched packet, and cannot be used as a handshake!`);this.handshakePacket=e}setClientRateLimit(e){e>l.MAX_BYTE&&(e=0,console.warn(`A rate limit above ${l.MAX_BYTE} is considered infinite.`)),this.clientRateLimit=e}setServerRateLimit(e){e>l.MAX_BYTE&&(e=0,console.warn(`A rate limit above ${l.MAX_BYTE} is considered infinite.`)),this.serverRateLimit=e}enablePacket(e){this.clientPackets.getPacket(e).defaultEnabled=!0,this.connections.forEach(t=>t.enablePacket(e))}disablePacket(e){this.clientPackets.getPacket(e).defaultEnabled=!1,this.connections.forEach(t=>t.disablePacket(e))}on_connect(e){this.connectListeners.push(e)}on_ready(e){this.wss.on("listening",e)}shutdown(e){this.wss.close(e)}async broadcastInternal(e,t,s){let n;if("all"===t.type)n=this.connections;else if("tagged"===t.type){if(!this.tagsInv.has(t.tag))return;n=Array.from(this.tagsInv.get(t.tag))}else n=this.connections.filter(t.filter);if(await this.callMiddleware("onPacketBroadcast_pre",e,{recipients:n,...t},s))return;if(0===n.length)return;const[i,a,r]=await(0,u.processPacket)(this.serverPackets,e,s,this.serverwideSendQueue,-1);await this.callMiddleware("onPacketBroadcast_post",e,{recipients:n,...t},a,a.length)||n.forEach(e=>e.send_processed(i,a,r))}async broadcastTagged(e,t,...s){await this.broadcastInternal(t,{type:"tagged",tag:e},s)}async broadcastFiltered(e,t,...s){await this.broadcastInternal(e,{type:"filter",filter:t},s)}async broadcast(e,...t){await this.broadcastInternal(e,{type:"all"},t)}getConnected(){return this.connections}getSocket(e){return this.connectionMap[e]}closeSocket(e,t=1e3,s){this.getSocket(e).close(t,s)}tag(e,t,s=!0){this.tags.get(e)||this.tags.set(e,new Set),this.tagsInv.get(t)||this.tagsInv.set(t,new Set),s&&this.tags.get(e).forEach(t=>this.tagsInv.get(t)?.delete(e)),this.tags.get(e).add(t),this.tagsInv.get(t).add(e)}debugServer=null;OpenDebug(e={}){if(null!=this.debugServer)throw new Error("Attempted to open a debug server when one has already been opened.");this.debugServer=new v.DebugServer(this,e)}}exports.SonicWSServer=f;
@@ -1,7 +0,0 @@
1
- /**
2
- * Copyright (c) 2026 Lily (liwybloc)
3
- * License-Identifier: LicenseRef-Lily-Personal-NonCommercial-2026
4
- * See LICENSE for personal, non-commercial license terms.
5
- */
6
-
7
- Object.defineProperty(exports,"__esModule",{value:!0}),exports.decompressBools=exports.compressBools=exports.EMPTY_UINT8=exports.MAX_UVARINT=exports.MAX_BYTE=void 0,exports.convertVarInt=function(e){if(!Number.isSafeInteger(e)||e<0||e>exports.MAX_UVARINT)throw new Error(`Variable Ints must be within range 0 and ${exports.MAX_UVARINT}: ${e}`);const r=[];do{let o=e%128;(e=Math.floor(e/128))>0&&(o|=128),r.push(o)}while(e>0);return r},exports.readVarInt=function(e,r){let o=0,t=1;for(let s=0;s<8;s++){if(r>=e.length)throw new Error("Truncated variable integer");const s=e[r++];if(o+=(127&s)*t,!(128&s))return[r,o];t*=128}throw new Error("Variable integer is too long")},exports.MAX_BYTE=255,exports.MAX_UVARINT=128**7-1,exports.EMPTY_UINT8=new Uint8Array([]);exports.compressBools=e=>e.reduce((e,r,o)=>e|Number(r)<<7-o,0);exports.decompressBools=e=>Array.from({length:8},(r,o)=>!!(e&1<<7-o));
@@ -1,7 +0,0 @@
1
- /**
2
- * Copyright (c) 2026 Lily (liwybloc)
3
- * License-Identifier: LicenseRef-Lily-Personal-NonCommercial-2026
4
- * See LICENSE for personal, non-commercial license terms.
5
- */
6
-
7
- Object.defineProperty(exports,"__esModule",{value:!0}),exports.processPacket=o,exports.listenPacket=async function(e,t,a){if("string"==typeof e)return a(e);const[n,r]=e;try{if(r&&Array.isArray(n))for(const e of t)await e(...n);else for(const e of t)await e(n)}catch(e){console.error(e),a(e)}},exports.CreatePacket=u,exports.CreateObjPacket=function(a){let{tag:n,types:r=[],dataMaxes:o,dataMins:u,noDataRange:f=!1,dontSpread:p=!1,autoFlatten:h=!1,validator:y=null,dataBatching:m=0,maxBatchSize:d=10,rateLimit:w=0,enabled:g=!0,async:k=!1,gzipCompression:P=r&&r.includes(t.PacketType.JSON)}=a;if(!n)throw new Error("Tag not selected!");if(!r||0==r.length)throw new Error("Types is set to 0 length");for(const e of r)if(i(e))throw new Error(`Invalid packet type in "${n}" packet: ${e}`);f?(o=Array.from({length:r.length}).map(()=>s),u=Array.from({length:r.length}).map(()=>0)):(null==o?o=Array.from({length:r.length}).map(()=>1):Array.isArray(o)||(o=Array.from({length:r.length}).map(()=>o)),null==u?u=Array.from({length:r.length}).map((e,t)=>o[t]):Array.isArray(u)||(u=Array.from({length:r.length}).map(()=>u)));const E=o.map(c),S=u.map((e,a)=>r[a]==t.PacketType.NONE?0:l(e,E[a])),x=new e.PacketSchema(!0,r,k,S,E,w,p,h,!1,m,d,P);return new e.Packet(n,x,y,g,!1)},exports.CreateEnumPacket=function(e){const{tag:t,enumData:a,dataMax:n=1,dataMin:r=0,noDataRange:o=!1,dontSpread:i=!1,validator:s=null,dataBatching:c=0,maxBatchSize:l=10,rateLimit:f=0,enabled:p=!0,async:h=!1}=e;return u({tag:t,type:a,dataMax:n,dataMin:r,noDataRange:o,dontSpread:i,validator:s,dataBatching:c,maxBatchSize:l,rateLimit:f,enabled:p,async:h})},exports.CreateKeyEffective=function(e){const{tag:t,count:a=2,validator:n=null,async:r=!1}=e;if(!t)throw new Error("Tag not selected!");if(a<2)throw new Error("Must have at least 2 key consumptions on key effective packet!");throw new Error("Currently W.I.P.")},exports.FlattenData=f,exports.UnFlattenData=function(e){return e[0]?.map((t,a)=>e.map(e=>e[a]))??[]};const e=require("../../packets/Packets"),t=require("../../packets/PacketType"),a=require("../enums/EnumType"),n=require("./CompressionUtil"),r=require("./HashUtil");async function o(e,a,i,s,c,l=!1){const u=e.getKey(a),p=e.getPacket(a);return async function(e,t,a,n,r,i,s){if(e[0]&&!i)return new Promise(t=>e[1].push([t,n,r]));e[0]=!0;const c=await s();if(e[1].length>0){const[n,r,i]=e[1].shift();queueMicrotask(async()=>{n(await o(t,r,i,e,a,!0))})}else e[0]=!1;return c}(s,e,c,a,i,l,async()=>{if(p.rereference){if(-1===c)throw new Error("Cannot send a re-referenced packet from the server-wide sender!");const e=(0,r.hashValue)(i);if(p.lastSent[c]===e)return[u,n.EMPTY_UINT8,p];p.lastSent[c]=e}if(p.autoFlatten)i=f(i[0]);else{if(i.length>p.maxSize)throw new Error(`Packet "${a}" only allows ${p.maxSize} values!`);if(i.length<p.minSize)throw new Error(`Packet "${a}" requires at least ${p.minSize} values!`)}if(p.object){if(i=i.map(e=>Array.isArray(e)?e:[e]),!p.autoFlatten){const e=p.dataMin,t=p.dataMax;for(let n=0;n<e.length;n++){if(i[n].length<e[n])throw new Error(`Section ${n+1} of packet "${a}" requires at least ${e[n]} values!`);if(i[n].length>t[n])throw new Error(`Section ${n+1} of packet "${a}" only allows ${t[n]} values!`)}}}else if(p.type!==t.PacketType.JSON){const e=i.find(e=>"object"==typeof e&&null!=e);e&&console.warn(`Passing an array will result in undefined behavior (${JSON.stringify(e)}). Spread the array with ...arr`)}const e=i.length>0?await p.processSend(i):n.EMPTY_UINT8;return[u,e,p]})}function i(e){return!(("number"==typeof e&&e in t.PacketType||e instanceof a.EnumPackage)&&e!=t.PacketType.KEY_EFFECTIVE)}const s=2048383;function c(e){return e<0?(console.warn("Having a data maximum below 0 does not do anything!"),0):e>s?(console.warn(`Only ${s} values can be sent on a type! Uhh make an issue if you want to send more.`),s):e}function l(e,t){return e<0?(console.warn("Having a data minimum below 0 does not do anything!"),0):e>t?(console.warn("Data minimum can not be higher than the data maximum!"),t):e}function u(a){let{tag:n,type:r=t.PacketType.NONE,dataMax:o=1,dataMin:u=1,noDataRange:f=!1,dontSpread:p=!1,validator:h=null,dataBatching:y=0,maxBatchSize:m=10,rateLimit:d=0,enabled:w=!0,async:g=!1,gzipCompression:k=r==t.PacketType.JSON,rereference:P=!1}=a;if(!n)throw new Error("Tag not selected!");if(f?(u=P?1:0,o=s):null==u&&(u=r==t.PacketType.NONE?0:o),P&&0==u)throw new Error("Rereference cannot be true if the dataMin is 0");if(i(r))throw new Error(`Invalid packet type: ${r}`);const E=new e.PacketSchema(!1,r,g,l(u,o),c(o),d,p,!1,P,y,m,k);return new e.Packet(n,E,h,w,!1)}function f(e){if(null==e)return[];const t=e[0];if(null==t)return[];if(!Array.isArray(t))throw new Error(`Cannot flatten array: ${e}`);return t.map((t,a)=>e.map(e=>e[a]))??[]}
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes