sonic-ws 2.3.0 → 2.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (35) hide show
  1. package/README.md +17 -5
  2. package/bin/sonicws.mjs +2 -2
  3. package/bundled/bundle.js +1 -1
  4. package/dist/index.d.ts +7 -6
  5. package/dist/index.js +6 -4
  6. package/dist/version.d.ts +1 -1
  7. package/dist/version.js +1 -1
  8. package/dist/ws/Connection.d.ts +2 -1
  9. package/dist/ws/Connection.js +1 -1
  10. package/dist/ws/client/core/ClientCore.d.ts +1 -0
  11. package/dist/ws/client/core/ClientCore.js +1 -1
  12. package/dist/ws/packets/Packets.d.ts +5 -0
  13. package/dist/ws/packets/Packets.js +1 -1
  14. package/dist/ws/server/SonicWSConnection.d.ts +1 -0
  15. package/dist/ws/server/SonicWSConnection.js +1 -1
  16. package/dist/ws/server/SonicWSServer.d.ts +5 -2
  17. package/dist/ws/server/SonicWSServer.js +1 -1
  18. package/dist/ws/util/JSONUtil.js +7 -0
  19. package/dist/ws/util/packets/ControlProtocol.d.ts +7 -1
  20. package/dist/ws/util/packets/ControlProtocol.js +1 -1
  21. package/dist/ws/util/packets/PacketHolder.js +1 -1
  22. package/dist/ws/util/packets/PacketUtils.d.ts +28 -2
  23. package/dist/ws/util/packets/PacketUtils.js +1 -1
  24. package/dist/ws/util/packets/VariantPermutation.d.ts +83 -0
  25. package/dist/ws/util/packets/VariantPermutation.js +7 -0
  26. package/dist/ws/util/packets/{PacketManifest.d.ts → metadata/PacketManifest.d.ts} +1 -1
  27. package/dist/ws/util/packets/{PacketManifest.js → metadata/PacketManifest.js} +1 -1
  28. package/dist/ws/util/packets/{SchemaValidation.d.ts → metadata/SchemaValidation.d.ts} +1 -1
  29. package/dist/ws/util/packets/metadata/SchemaValidation.js +7 -0
  30. package/package.json +1 -1
  31. package/dist/ws/util/packets/JSONUtil.js +0 -7
  32. package/dist/ws/util/packets/SchemaValidation.js +0 -7
  33. /package/dist/ws/util/{packets/JSONUtil.d.ts → JSONUtil.d.ts} +0 -0
  34. /package/dist/ws/util/packets/{ConstructorRegistry.d.ts → metadata/ConstructorRegistry.d.ts} +0 -0
  35. /package/dist/ws/util/packets/{ConstructorRegistry.js → metadata/ConstructorRegistry.js} +0 -0
@@ -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.VariantPermutation=void 0;class e{values;opposites;generated;constructor(e,t){if(!e.length||e.some(e=>"string"!=typeof e||!e||e.includes(",")))throw new Error("Variant permutation values must be non-empty strings without commas");if(new Set(e).size!==e.length)throw new Error("Variant permutation values must be unique");for(const[n,s]of t??[])if(!Number.isInteger(n)||!Number.isInteger(s)||n<0||s<0||n>=e.length||s>=e.length||n===s)throw new Error("Variant permutation opposite indexes are invalid");this.values=e,this.opposites=t??[]}static from(t,n){return new e(t,n)}static WASD(){return new e(["W","A","S","D"],[[0,2],[1,3]])}static Arrows(){return new e(["Up","Left","Down","Right"],[[0,2],[1,3]])}generate(){if(this.generated)return[...this.generated];const e=[],t=1<<this.values.length,n=this.createGroupOrder();for(let s=1;s<t;s++){const t=[];for(let e=0;e<this.values.length;e++)s&1<<e&&t.push(e);if(this.containsOpposites(t))continue;const r=[...t].sort((e,t)=>{const s=n.get(e)-n.get(t);return 0!==s?s:e-t});e.push({indexes:r,value:r.map(e=>this.values[e]).join(",")})}return this.generated=e.sort((e,t)=>{if(e.indexes.length!==t.indexes.length)return e.indexes.length-t.indexes.length;for(let n=0;n<Math.min(e.indexes.length,t.indexes.length);n++)if(e.indexes[n]!==t.indexes[n])return e.indexes[n]-t.indexes[n];return 0}).map(e=>e.value),[...this.generated]}getValues(){return[...this.values]}resolve(e){const t=new Set;if(Array.isArray(e)){if(e.length!==this.values.length||e.some(e=>"boolean"!=typeof e))throw new Error(`Variant permutation requires ${this.values.length} boolean flags`);e.forEach((e,n)=>e&&t.add(this.values[n]))}else{const n=e,s=Object.keys(n);if(s.length!==this.values.length||s.some(e=>!this.values.includes(e)||"boolean"!=typeof n[e]))throw new Error("Variant permutation object must define every known key as a boolean");this.values.forEach(e=>n[e]&&t.add(e))}if(!t.size)return"";const n=this.generate().find(e=>{const n=e.split(",");return n.length===t.size&&n.every(e=>t.has(e))});if(!n)throw new Error("Variant permutation contains an invalid or opposite combination");return n}expand(e){const t=new Set(e?e.split(","):[]);if(t.size&&!this.generate().includes(e))throw new Error(`Unknown generated permutation: ${e}`);return Object.fromEntries(this.values.map(e=>[e,t.has(e)]))}containsOpposites(e){const t=new Set(e);return this.opposites.some(([e,n])=>t.has(e)&&t.has(n))}createGroupOrder(){const e=new Map;this.opposites.forEach(([t,n],s)=>{e.has(t)||e.set(t,s),e.has(n)||e.set(n,s)});let t=this.opposites.length;for(let n=0;n<this.values.length;n++)e.has(n)||e.set(n,t++);return e}}exports.VariantPermutation=e;
@@ -3,7 +3,7 @@
3
3
  * License-Identifier: LicenseRef-Lily-Personal-NonCommercial-2026
4
4
  * See LICENSE for personal, non-commercial license terms.
5
5
  */
6
- import { Packet } from "../../packets/Packets";
6
+ import { Packet } from "../../../packets/Packets";
7
7
  export type PacketManifest = {
8
8
  clientPackets: readonly Packet<any>[];
9
9
  serverPackets: readonly Packet<any>[];
@@ -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.CreatePacketManifest=function(t){const i=t.clientPackets.flatMap(e=>e.serialize()),n=t.serverPackets.flatMap(e=>e.serialize());return Uint8Array.from([...a,e.VERSION,...(0,r.convertVarInt)(i.length),...i,...n])},exports.LoadPacketManifest=function(i){if(i.length<6||a.some((e,t)=>i[t]!==e))throw new Error("Invalid SonicWS packet manifest");if(i[4]!==e.VERSION)throw new Error(`Packet manifest protocol mismatch: ${i[4]} != ${e.VERSION}`);const[n,s]=(0,r.readVarInt)(i,5),c=n+s;if(c>i.length)throw new Error("Truncated SonicWS packet manifest");return{clientPackets:t.Packet.deserializeAll(i.slice(n,c),!1),serverPackets:t.Packet.deserializeAll(i.slice(c),!1)}};const e=require("../../../version"),t=require("../../packets/Packets"),r=require("./CompressionUtil"),a=[83,87,83,77];
7
+ Object.defineProperty(exports,"__esModule",{value:!0}),exports.CreatePacketManifest=function(t){const i=t.clientPackets.flatMap(e=>e.serialize()),n=t.serverPackets.flatMap(e=>e.serialize());return Uint8Array.from([...a,e.VERSION,...(0,r.convertVarInt)(i.length),...i,...n])},exports.LoadPacketManifest=function(i){if(i.length<6||a.some((e,t)=>i[t]!==e))throw new Error("Invalid SonicWS packet manifest");if(i[4]!==e.VERSION)throw new Error(`Packet manifest protocol mismatch: ${i[4]} != ${e.VERSION}`);const[n,s]=(0,r.readVarInt)(i,5),c=n+s;if(c>i.length)throw new Error("Truncated SonicWS packet manifest");return{clientPackets:t.Packet.deserializeAll(i.slice(n,c),!1),serverPackets:t.Packet.deserializeAll(i.slice(c),!1)}};const e=require("../../../../version"),t=require("../../../packets/Packets"),r=require("../CompressionUtil"),a=[83,87,83,77];
@@ -3,7 +3,7 @@
3
3
  * License-Identifier: LicenseRef-Lily-Personal-NonCommercial-2026
4
4
  * See LICENSE for personal, non-commercial license terms.
5
5
  */
6
- import { Packet } from "../../packets/Packets";
6
+ import { Packet } from "../../../packets/Packets";
7
7
  export type SchemaValidationResult = {
8
8
  errors: string[];
9
9
  warnings: 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.ValidatePacketSchema=n,exports.AssertPacketSchema=function(e,a){const t=n(e,a);if(t.errors.length)throw new Error(`Invalid SonicWS packet schema:\n- ${t.errors.join("\n- ")}`);for(const e of t.warnings)console.warn(`SonicWS schema warning: ${e}`)};const e=require("../../../packets/PacketType"),a=new Set([e.PacketType.UBYTES,e.PacketType.USHORTS,e.PacketType.UVARINT]),t=new Set([e.PacketType.BYTES,e.PacketType.UBYTES,e.PacketType.SHORTS,e.PacketType.USHORTS,e.PacketType.VARINT,e.PacketType.UVARINT,e.PacketType.DELTAS,e.PacketType.FLOATS,e.PacketType.DOUBLES]);function n(n,c={}){const s=[],r=[],p=new Set,o=new Map,i=new Set;n.length>254&&s.push(`Packet table contains ${n.length} packets; the maximum is 254`);for(const e of n){p.has(e.tag)&&s.push(`Duplicate packet tag "${e.tag}"`),p.add(e.tag),e.isParent&&o.set(e.tag,e),e.replay&&e.dataBatching&&s.push(`Packet "${e.tag}" combines replay with batching`);const n=Array.isArray(e.type)?e.type:[e.type];e.quantized&&n.some(e=>!t.has(e))&&s.push(`Packet "${e.tag}" quantizes a non-numeric type`),void 0!==e.valueMin&&e.valueMin<0&&n.some(e=>a.has(e))&&s.push(`Packet "${e.tag}" has a negative minimum for an unsigned type`),!e.fields||e.autoFlatten||e.object||e.dataMin!==e.dataMax||e.fields.length===e.dataMax||s.push(`Packet "${e.tag}" schema length does not match its fixed value count`);const u=Array.isArray(e.dataMax)?e.dataMax.some(e=>e>=2048383):e.dataMax>=2048383;if(c.warnUnbounded&&"client"===c.direction&&u&&r.push(`Client packet "${e.tag}" has an effectively unbounded value count`),e.parent&&e.variant){const a=`${e.parent}.${e.variant}`;i.has(a)&&s.push(`Duplicate packet-group variant "${a}"`),i.add(a)}}for(const a of n){if(!a.parent)continue;const t=o.get(a.parent);t?t.type!==e.PacketType.NONE&&s.push(`Packet-group parent "${a.parent}" must use PacketType.NONE`):s.push(`Packet "${a.tag}" references missing group parent "${a.parent}"`)}return{errors:s,warnings:r}}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "sonic-ws",
3
- "version": "2.3.0",
3
+ "version": "2.4.0",
4
4
  "description": "Ultra-lightweight, high-performance, and bandwidth efficient websocket library",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",
@@ -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.decompressJSON=exports.compressJSON=void 0;const r=require("../BufferUtil"),e=r=>Array.from({length:8},(e,t)=>!!(r&1<<7-t));function t(r){if(!Number.isInteger(r)||r<0)throw new Error(`Invalid JSON variable integer: ${r}`);const e=[];do{let t=127&r;(r>>>=7)>0&&(t|=128),e.push(t)}while(r>0);return e}function n(r,e){let t=0,n=0;for(;;){if(e>=r.length||n>28)throw new Error("Invalid JSON variable integer");const s=r[e++];if(t+=(127&s)<<n,!(128&s))return[e,t];n+=7}}var s;!function(r){r[r.NULL=0]="NULL",r[r.BOOL=1]="BOOL",r[r.INT=2]="INT",r[r.FLOAT=3]="FLOAT",r[r.STRING=4]="STRING",r[r.ARRAY=5]="ARRAY",r[r.OBJECT=6]="OBJECT"}(s||(s={}));const o=r=>{const e=(new TextEncoder).encode(r);return[...t(e.length),...e]},a=(r,e)=>{const[t,s]=n(r,e);return{value:(new TextDecoder).decode(r.subarray(t,t+s)),length:t+s-e}},u=r=>{let e="";for(const t of r)e+=t.toString(2).padStart(3,"0");return(r=>new Uint8Array(r.match(/.{1,8}/g)?.map(r=>parseInt(r.padEnd(8,"0"),2))??[]))(e)},c=(r,e)=>{const t=(r=>Array.from(r,r=>r.toString(2).padStart(8,"0")).join(""))(r),n=[];for(let r=0;r<e;r++)n.push(parseInt(t.slice(3*r,3*r+3),2));return n};exports.compressJSON=e=>{const n=[],a=[],c=[],l=r=>{switch(null===r?"null":Array.isArray(r)?"array":typeof r){case"null":c.push(s.NULL);break;case"boolean":c.push(s.BOOL),n.push(r);break;case"number":Number.isInteger(r)?(c.push(s.INT),a.push(...t((r=>r<<1^r>>31)(r)))):(c.push(s.FLOAT),a.push(...function(r){if(Number.isNaN(r))return[127,128,0,1];const e=r<0?1:0;if(0===(r=Math.abs(r)))return[0,0,0,0];const t=Math.floor(Math.log2(r));if(!Number.isFinite(r)||t>127||t<-126)return[e?255:127,128,0,0];const n=(e<<31|t+127<<23|8388607&Math.round((r/2**t-1)*2**23))>>>0;return[n>>>24,n>>>16&255,n>>>8&255,255&n]}(r)));break;case"string":c.push(s.STRING),a.push(...o(r));break;case"array":c.push(s.ARRAY),a.push(...t(r.length));for(const e of r)l(e);break;case"object":{c.push(s.OBJECT);const e=Object.keys(r);a.push(...t(e.length));for(const t of e)a.push(...o(t)),l(r[t]);break}default:throw new Error("Unsupported type")}};l(e);const h=n.length?(0,r.splitArray)(n,8).map(r=>r.reduce((r,e,t)=>r|Number(e)<<7-t,0)):[],p=u(c),i=[...t(h.length),...t(p.length)];return Uint8Array.from([...i,...h.flat(),...p,...a])};exports.decompressJSON=r=>{let t=0;const[o,u]=n(r,t);t=o;const[l,h]=n(r,t);t=l;const p=[];for(let n=0;n<u;n++)p.push(...e(r[t++]));let i=0;const f=r.subarray(t,t+h);t+=h;const N=c(f,8*f.length/3);let O=0;const d=e=>{if(e>500)throw new Error("JSON array too deep.");const o=N[O++];switch(o){case s.NULL:return null;case s.BOOL:return p[i++];case s.INT:{const[e,s]=n(r,t);return t=e,(u=s)>>>1^-(1&u)}case s.FLOAT:{const e=function(r){const e=(r[0]<<24|r[1]<<16|r[2]<<8|r[3])>>>0,t=e>>>23&255,n=(0===t?0:1)+(8388607&e)/2**23,s=255===t?0===n?1/0:NaN:n*2**(0===t?-126:t-127);return e>>>31?-s:s}(Array.from(r.subarray(t,t+4)));return t+=4,e}case s.STRING:{const{value:e,length:n}=a(r,t);return t+=n,e}case s.ARRAY:{const[s,o]=n(r,t);t=s;const a=[];for(let r=0;r<o;r++)a.push(d(e+1));return a}case s.OBJECT:{const[s,o]=n(r,t);t=s;const u={};for(let n=0;n<o;n++){const{value:n,length:s}=a(r,t);t+=s,u[n]=d(e+1)}return u}default:throw new Error(`Unknown type ${o}`)}var u};return d(0)};
@@ -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.ValidatePacketSchema=n,exports.AssertPacketSchema=function(e,a){const t=n(e,a);if(t.errors.length)throw new Error(`Invalid SonicWS packet schema:\n- ${t.errors.join("\n- ")}`);for(const e of t.warnings)console.warn(`SonicWS schema warning: ${e}`)};const e=require("../../packets/PacketType"),a=new Set([e.PacketType.UBYTES,e.PacketType.USHORTS,e.PacketType.UVARINT]),t=new Set([e.PacketType.BYTES,e.PacketType.UBYTES,e.PacketType.SHORTS,e.PacketType.USHORTS,e.PacketType.VARINT,e.PacketType.UVARINT,e.PacketType.DELTAS,e.PacketType.FLOATS,e.PacketType.DOUBLES]);function n(n,c={}){const s=[],r=[],p=new Set,o=new Map,i=new Set;n.length>254&&s.push(`Packet table contains ${n.length} packets; the maximum is 254`);for(const e of n){p.has(e.tag)&&s.push(`Duplicate packet tag "${e.tag}"`),p.add(e.tag),e.isParent&&o.set(e.tag,e),e.replay&&e.dataBatching&&s.push(`Packet "${e.tag}" combines replay with batching`);const n=Array.isArray(e.type)?e.type:[e.type];e.quantized&&n.some(e=>!t.has(e))&&s.push(`Packet "${e.tag}" quantizes a non-numeric type`),void 0!==e.valueMin&&e.valueMin<0&&n.some(e=>a.has(e))&&s.push(`Packet "${e.tag}" has a negative minimum for an unsigned type`),!e.fields||e.autoFlatten||e.object||e.dataMin!==e.dataMax||e.fields.length===e.dataMax||s.push(`Packet "${e.tag}" schema length does not match its fixed value count`);const u=Array.isArray(e.dataMax)?e.dataMax.some(e=>e>=2048383):e.dataMax>=2048383;if(c.warnUnbounded&&"client"===c.direction&&u&&r.push(`Client packet "${e.tag}" has an effectively unbounded value count`),e.parent&&e.variant){const a=`${e.parent}.${e.variant}`;i.has(a)&&s.push(`Duplicate packet-group variant "${a}"`),i.add(a)}}for(const a of n){if(!a.parent)continue;const t=o.get(a.parent);t?t.type!==e.PacketType.NONE&&s.push(`Packet-group parent "${a.parent}" must use PacketType.NONE`):s.push(`Packet "${a.tag}" references missing group parent "${a.parent}"`)}return{errors:s,warnings:r}}