sonic-ws 2.1.0 → 2.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +19 -6
- package/bin/sonicws.mjs +159 -0
- package/bundled/bundle.js +1 -1
- package/bundled/bundle.wasm +0 -0
- package/dist/index.d.ts +12 -0
- package/dist/index.js +12 -1
- package/dist/native/wasm/node/sonic_ws_core_bg.wasm +0 -0
- package/dist/native/wrapper.d.ts +3 -3
- package/dist/native/wrapper.js +1 -1
- package/dist/version.d.ts +1 -1
- package/dist/version.js +1 -1
- package/dist/ws/Connection.d.ts +16 -3
- package/dist/ws/Connection.js +1 -1
- package/dist/ws/PacketProcessor.js +1 -1
- package/dist/ws/client/core/ClientCore.d.ts +70 -9
- package/dist/ws/client/core/ClientCore.js +1 -1
- package/dist/ws/client/node/ClientNode.d.ts +9 -3
- package/dist/ws/client/node/ClientNode.js +1 -1
- package/dist/ws/debug/PacketLogger.d.ts +30 -0
- package/dist/ws/debug/PacketLogger.js +7 -0
- package/dist/ws/packets/PacketType.d.ts +4 -3
- package/dist/ws/packets/PacketType.js +1 -1
- package/dist/ws/packets/Packets.d.ts +21 -2
- package/dist/ws/packets/Packets.js +1 -1
- package/dist/ws/server/Adapter.d.ts +21 -0
- package/dist/ws/server/Adapter.js +7 -0
- package/dist/ws/server/SonicWSConnection.d.ts +28 -2
- package/dist/ws/server/SonicWSConnection.js +1 -1
- package/dist/ws/server/SonicWSServer.d.ts +46 -8
- package/dist/ws/server/SonicWSServer.js +1 -1
- package/dist/ws/util/packets/BatchHelper.js +1 -1
- package/dist/ws/util/packets/ConstructorRegistry.d.ts +10 -0
- package/dist/ws/util/packets/ConstructorRegistry.js +7 -0
- package/dist/ws/util/packets/ControlProtocol.d.ts +47 -0
- package/dist/ws/util/packets/ControlProtocol.js +7 -0
- package/dist/ws/util/packets/PacketHolder.js +1 -1
- package/dist/ws/util/packets/PacketManifest.d.ts +17 -0
- package/dist/ws/util/packets/PacketManifest.js +7 -0
- package/dist/ws/util/packets/PacketUtils.d.ts +45 -15
- package/dist/ws/util/packets/PacketUtils.js +1 -1
- package/dist/ws/util/packets/SchemaValidation.d.ts +17 -0
- package/dist/ws/util/packets/SchemaValidation.js +7 -0
- package/package.json +13 -7
- package/dist/native/wasm/pkg/README.md +0 -6
- package/dist/native/wasm/pkg/package.json +0 -19
- package/dist/native/wasm/pkg/sonic_ws_core.d.ts +0 -51
- package/dist/native/wasm/pkg/sonic_ws_core.js +0 -7
- package/dist/native/wasm/pkg/sonic_ws_core_bg.js +0 -7
- package/dist/native/wasm/pkg/sonic_ws_core_bg.wasm +0 -0
- package/dist/native/wasm/pkg/sonic_ws_core_bg.wasm.d.ts +0 -36
package/dist/index.js
CHANGED
|
@@ -12,7 +12,7 @@
|
|
|
12
12
|
* License-Identifier: LicenseRef-Lily-Personal-NonCommercial-2026
|
|
13
13
|
*/
|
|
14
14
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
15
|
-
exports.initializeWasmCore = exports.WrapEnum = exports.DefineEnum = exports.UnFlattenData = exports.FlattenData = exports.CreatePacketGroup = exports.CreateEnumPacket = exports.CreateObjPacket = exports.CreatePacket = exports.PacketType = exports.SonicWSServer = exports.SonicWSConnection = exports.SonicWS = void 0;
|
|
15
|
+
exports.initializeWasmCore = exports.WrapEnum = exports.DefineEnum = exports.UnregisterPacketConstructor = exports.RegisterPacketConstructor = exports.PacketLogger = exports.AssertPacketSchema = exports.ValidatePacketSchema = exports.LoadPacketManifest = exports.CreatePacketManifest = exports.UnFlattenData = exports.FlattenData = exports.CreatePacketGroup = exports.CreateEnumPacket = exports.CreateObjPacket = exports.CreatePacket = exports.PacketType = exports.SonicWSServer = exports.SonicWSConnection = exports.SonicWS = void 0;
|
|
16
16
|
var ClientNode_1 = require("./ws/client/node/ClientNode");
|
|
17
17
|
Object.defineProperty(exports, "SonicWS", { enumerable: true, get: function () { return ClientNode_1.SonicWS; } });
|
|
18
18
|
var SonicWSConnection_1 = require("./ws/server/SonicWSConnection");
|
|
@@ -28,6 +28,17 @@ Object.defineProperty(exports, "CreateEnumPacket", { enumerable: true, get: func
|
|
|
28
28
|
Object.defineProperty(exports, "CreatePacketGroup", { enumerable: true, get: function () { return PacketUtils_1.CreatePacketGroup; } });
|
|
29
29
|
Object.defineProperty(exports, "FlattenData", { enumerable: true, get: function () { return PacketUtils_1.FlattenData; } });
|
|
30
30
|
Object.defineProperty(exports, "UnFlattenData", { enumerable: true, get: function () { return PacketUtils_1.UnFlattenData; } });
|
|
31
|
+
var PacketManifest_1 = require("./ws/util/packets/PacketManifest");
|
|
32
|
+
Object.defineProperty(exports, "CreatePacketManifest", { enumerable: true, get: function () { return PacketManifest_1.CreatePacketManifest; } });
|
|
33
|
+
Object.defineProperty(exports, "LoadPacketManifest", { enumerable: true, get: function () { return PacketManifest_1.LoadPacketManifest; } });
|
|
34
|
+
var SchemaValidation_1 = require("./ws/util/packets/SchemaValidation");
|
|
35
|
+
Object.defineProperty(exports, "ValidatePacketSchema", { enumerable: true, get: function () { return SchemaValidation_1.ValidatePacketSchema; } });
|
|
36
|
+
Object.defineProperty(exports, "AssertPacketSchema", { enumerable: true, get: function () { return SchemaValidation_1.AssertPacketSchema; } });
|
|
37
|
+
var PacketLogger_1 = require("./ws/debug/PacketLogger");
|
|
38
|
+
Object.defineProperty(exports, "PacketLogger", { enumerable: true, get: function () { return PacketLogger_1.PacketLogger; } });
|
|
39
|
+
var ConstructorRegistry_1 = require("./ws/util/packets/ConstructorRegistry");
|
|
40
|
+
Object.defineProperty(exports, "RegisterPacketConstructor", { enumerable: true, get: function () { return ConstructorRegistry_1.RegisterPacketConstructor; } });
|
|
41
|
+
Object.defineProperty(exports, "UnregisterPacketConstructor", { enumerable: true, get: function () { return ConstructorRegistry_1.UnregisterPacketConstructor; } });
|
|
31
42
|
var EnumHandler_1 = require("./ws/util/enums/EnumHandler");
|
|
32
43
|
Object.defineProperty(exports, "DefineEnum", { enumerable: true, get: function () { return EnumHandler_1.DefineEnum; } });
|
|
33
44
|
Object.defineProperty(exports, "WrapEnum", { enumerable: true, get: function () { return EnumHandler_1.WrapEnum; } });
|
|
Binary file
|
package/dist/native/wrapper.d.ts
CHANGED
|
@@ -35,12 +35,12 @@ export interface NativeObjectSchema {
|
|
|
35
35
|
dataMaxes: readonly number[];
|
|
36
36
|
enumData?: readonly EnumPackage[];
|
|
37
37
|
}
|
|
38
|
-
/** Injects a
|
|
38
|
+
/** Injects a codec implementation, primarily for tests. */
|
|
39
39
|
export declare function setNativeCore(core: SonicNativeCore): void;
|
|
40
40
|
/** Loads and selects the webpack-compatible browser WASM implementation. */
|
|
41
41
|
export declare function initializeWasmCore(): Promise<SonicNativeCore>;
|
|
42
|
-
/** Loads the
|
|
43
|
-
export declare function loadNativeCore(
|
|
42
|
+
/** Loads the packaged Node-target WASM codec synchronously. */
|
|
43
|
+
export declare function loadNativeCore(): SonicNativeCore;
|
|
44
44
|
export declare function encodeNative(type: PacketType, input: unknown, enumData?: EnumPackage, core?: SonicNativeCore): Uint8Array;
|
|
45
45
|
export declare function decodeNative(type: PacketType, data: Uint8Array, dataMax?: number, enumData?: EnumPackage, core?: SonicNativeCore): unknown;
|
|
46
46
|
export declare function validateNative(type: PacketType, data: Uint8Array, dataMin: number, dataMax: number, options?: {
|
package/dist/native/wrapper.js
CHANGED
|
@@ -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.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
|
|
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 codec module; 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 r=await e(CDN_WASM);if(!await isWasm(r))throw new Error("SonicWS CDN returned an invalid WASM module");return r}async function initializeBrowserWasm(){const e=window.fetch.bind(window);window.fetch=async(t,a)=>{const r=fetchUrl(t);if(r===CDN_WASM||!new URL(r,window.location.href).pathname.endsWith("/bundle.wasm"))return e(t,a);try{const r=await e(t,a);if(await isWasm(r))return r}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(){if(loadedCore)return loadedCore;if("undefined"!=typeof window)throw new Error("SonicWS codec is not initialized; await initializeWasmCore() in browsers.");try{const wasm=eval("require")("./wasm/node/sonic_ws_core.js");return assertNativeCore(wasm),loadedCore=wasm,wasm}catch(e){const t=e instanceof Error?e.message:String(e);throw new Error(`Unable to load the packaged SonicWS Node WASM codec: ${t}`)}}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 encodeIntegerVarints(e,t){const a=values(e),r=new Uint8Array(5*a.length);let n=0;for(let e=0;e<a.length;e++){const o=a[e];if(!Number.isInteger(o)||!Number.isFinite(o))throw new TypeError((t?"VARINT":"UVARINT")+" requires integer values");if(!t&&(o<0||o>4294967295))throw new RangeError("UVARINT value must be between 0 and 4294967295");const c=t?Math.max(-2147483648,Math.min(2147483647,o)):o;let i=t?(c<<1^c>>31)>>>0:c;do{let e=i%128;i=Math.floor(i/128),0!==i&&(e|=128),r[n++]=e}while(0!==i)}return r.slice(0,n)}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))){const t=e===PacketType_1.PacketType.JSON?"JSON wire data":"RAW";throw new TypeError(`${t} 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.DELTAS:return r.encodeSigned(e,values(t));case PacketType_1.PacketType.VARINT:return encodeIntegerVarints(t,!0);case PacketType_1.PacketType.UBYTES:case PacketType_1.PacketType.USHORTS:return r.encodeUnsigned(e,values(t));case PacketType_1.PacketType.UVARINT:return encodeIntegerVarints(t,!1);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)));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]});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()){if(!t){let t=0;for(const a of e){let e=a.byteLength;for(t+=e+1;e>=128;)t++,e=Math.floor(e/128)}const a=new Uint8Array(t);let r=0;for(const t of e){let e=t.byteLength;do{let t=e%128;e=Math.floor(e/128),0!==e&&(t|=128),a[r++]=t}while(0!==e);a.set(t,r),r+=t.byteLength}return a}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)}
|
package/dist/version.d.ts
CHANGED
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
* See LICENSE for personal, non-commercial license terms.
|
|
5
5
|
*/
|
|
6
6
|
/** Current protocol version */
|
|
7
|
-
export declare const VERSION =
|
|
7
|
+
export declare const VERSION = 24;
|
|
8
8
|
/** Server data suffix */
|
|
9
9
|
export declare const SERVER_SUFFIX = "SWS";
|
|
10
10
|
/** Server data suffix in array */
|
package/dist/version.js
CHANGED
|
@@ -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.SERVER_SUFFIX_NUMS=exports.SERVER_SUFFIX=exports.VERSION=void 0;const e=require("./ws/util/StringUtil");exports.VERSION=
|
|
7
|
+
Object.defineProperty(exports,"__esModule",{value:!0}),exports.SERVER_SUFFIX_NUMS=exports.SERVER_SUFFIX=exports.VERSION=void 0;const e=require("./ws/util/StringUtil");exports.VERSION=24,exports.SERVER_SUFFIX="SWS",exports.SERVER_SUFFIX_NUMS=(0,e.processCharCodes)(exports.SERVER_SUFFIX);
|
package/dist/ws/Connection.d.ts
CHANGED
|
@@ -72,8 +72,8 @@ export interface IConnection<T> extends IMiddlewareHolder<ConnectionMiddleware>
|
|
|
72
72
|
}
|
|
73
73
|
export declare abstract class Connection<T extends {
|
|
74
74
|
readyState: number;
|
|
75
|
-
send: (
|
|
76
|
-
close: (
|
|
75
|
+
send: (data: Uint8Array) => void;
|
|
76
|
+
close: (code: number, reason: string | undefined) => void;
|
|
77
77
|
}, K> extends MiddlewareHolder<ConnectionMiddleware> implements IConnection<K> {
|
|
78
78
|
protected listeners: Record<string, Array<(...data: any[]) => void>>;
|
|
79
79
|
private rawSendListeners;
|
|
@@ -88,12 +88,24 @@ export declare abstract class Connection<T extends {
|
|
|
88
88
|
id: number;
|
|
89
89
|
/** Mutable application-owned state scoped to this connection. */
|
|
90
90
|
state: Record<string, unknown>;
|
|
91
|
+
private volatileAtBytes;
|
|
92
|
+
private closeAtBytes;
|
|
91
93
|
constructor(socket: T, id: number, name: string, addListener: Function, removeListener: Function);
|
|
94
|
+
/** Rebinds this connection object to a replacement transport. */
|
|
95
|
+
protected replaceTransport(socket: T, addListener: Function, removeListener: Function): void;
|
|
92
96
|
setTimeout(call: () => void, time: number, callOnClose?: boolean): number;
|
|
93
97
|
setInterval(call: () => void, time: number, callOnClose?: boolean): number;
|
|
94
98
|
clearTimeout(id: number): void;
|
|
95
99
|
clearInterval(id: number): void;
|
|
96
100
|
raw_send(data: Uint8Array): void;
|
|
101
|
+
/** Bytes currently queued by the underlying transport. */
|
|
102
|
+
getBufferedAmount(): number;
|
|
103
|
+
/** Configures volatile-drop and forced-close outbound buffer thresholds. */
|
|
104
|
+
setBackpressureLimits(options: {
|
|
105
|
+
volatileAtBytes?: number;
|
|
106
|
+
closeAtBytes?: number;
|
|
107
|
+
}): void;
|
|
108
|
+
protected canSendVolatile(): boolean;
|
|
97
109
|
raw_onmessage(listener: (data: K) => void): void;
|
|
98
110
|
raw_onsend(listener: (data: Uint8Array) => void): void;
|
|
99
111
|
close(code?: number, reason?: string | Buffer): void;
|
|
@@ -110,6 +122,7 @@ export declare enum CloseCodes {
|
|
|
110
122
|
REPEATED_HANDSHAKE = 4005,
|
|
111
123
|
DISABLED_PACKET = 4006,
|
|
112
124
|
MIDDLEWARE = 4007,
|
|
113
|
-
MANUAL_SHUTDOWN = 4008
|
|
125
|
+
MANUAL_SHUTDOWN = 4008,
|
|
126
|
+
BACKPRESSURE = 4009
|
|
114
127
|
}
|
|
115
128
|
export declare function getClosureCause(id: number): string;
|
package/dist/ws/Connection.js
CHANGED
|
@@ -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.CloseCodes=exports.Connection=void 0,exports.getClosureCause=function(e){if(e>=4e3)return
|
|
7
|
+
Object.defineProperty(exports,"__esModule",{value:!0}),exports.CloseCodes=exports.Connection=void 0,exports.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 e=require("./PacketProcessor"),t=require("./util/packets/BatchHelper");class s extends e.MiddlewareHolder{listeners;rawSendListeners=[];name;closed=!1;socket;_timers={};batcher;_on;_off;id;state={};volatileAtBytes=1048576;closeAtBytes=16777216;constructor(e,s,i,o,r){super(),this.id=s,this.listeners={},this.name=i,this.socket=e,this.batcher=new t.BatchHelper,this._on=o,this._off=r,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))}replaceTransport(e,t,s){this.socket=e,this._on=t,this._off=s,this.closed=!1,this._on("close",()=>{this.callMiddleware("onStatusChange",WebSocket.CLOSED),this.closed=!0}),this._on("open",()=>this.callMiddleware("onStatusChange",WebSocket.OPEN))}setTimeout(e,t,s=!1){const i=setTimeout(()=>{e(),this.clearTimeout(i)},t);return this._timers[i]=[i,e,s],i}setInterval(e,t,s=!1){const i=setInterval(e,t);return this._timers[i]=[i,e,s],i}clearTimeout(e){clearTimeout(e),delete this._timers[e]}clearInterval(e){this.clearTimeout(e)}raw_send(e){if(this.getBufferedAmount()>=this.closeAtBytes)throw this.close(i.BACKPRESSURE,"Outbound buffer exceeded the configured limit"),new Error("SonicWS outbound backpressure limit exceeded");this.socket.send(e);for(const t of this.rawSendListeners)t(e)}getBufferedAmount(){const e=this.socket.bufferedAmount;return"number"==typeof e&&Number.isFinite(e)?e:0}setBackpressureLimits(e){const t=e.volatileAtBytes??this.volatileAtBytes,s=e.closeAtBytes??this.closeAtBytes;if(!Number.isFinite(t)||!Number.isFinite(s)||t<0||s<=0||t>s)throw new Error("Invalid SonicWS backpressure limits");this.volatileAtBytes=t,this.closeAtBytes=s}canSendVolatile(){return this.getBufferedAmount()<this.volatileAtBytes}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;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",e[e.BACKPRESSURE=4009]="BACKPRESSURE"}(i||(exports.CloseCodes=i={}));
|
|
@@ -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.MiddlewareHolder=void 0;exports.MiddlewareHolder=class{middlewares=[];addMiddleware(e){this.middlewares.push(e);const r=e;try{
|
|
7
|
+
Object.defineProperty(exports,"__esModule",{value:!0}),exports.MiddlewareHolder=void 0;exports.MiddlewareHolder=class{middlewares=[];addMiddleware(e){this.middlewares.push(e);const r=e;try{r.init?.(this)}catch(e){console.warn("Middleware init threw an error",e)}}async callMiddleware(e,...r){let d=!1;for(const a of this.middlewares){const t=a[e];if(t)try{await t.call(a,...r)&&(d=!0)}catch(r){console.warn(`Middleware ${String(e)} threw an error`,r)}}return d}};
|
|
@@ -5,12 +5,25 @@
|
|
|
5
5
|
*/
|
|
6
6
|
import { PacketHolder } from "../../util/packets/PacketHolder";
|
|
7
7
|
import { Connection } from "../../Connection";
|
|
8
|
-
|
|
9
|
-
|
|
8
|
+
export type ReconnectOptions = {
|
|
9
|
+
enabled?: boolean;
|
|
10
|
+
attempts?: number;
|
|
11
|
+
minDelayMs?: number;
|
|
12
|
+
maxDelayMs?: number;
|
|
13
|
+
jitter?: number;
|
|
14
|
+
};
|
|
15
|
+
type TransportBinding<T, K> = {
|
|
16
|
+
socket: T;
|
|
17
|
+
bufferHandler: (value: K) => Promise<Uint8Array>;
|
|
18
|
+
on: Function;
|
|
19
|
+
off: Function;
|
|
20
|
+
};
|
|
21
|
+
type ClientTransport = {
|
|
10
22
|
readyState: number;
|
|
11
|
-
send: (
|
|
12
|
-
close: (
|
|
13
|
-
}
|
|
23
|
+
send: (data: Uint8Array<ArrayBufferLike>) => void;
|
|
24
|
+
close: (code: number, reason: string | undefined) => void;
|
|
25
|
+
};
|
|
26
|
+
export declare abstract class SonicWSCore<T extends ClientTransport, K> extends Connection<T, K> {
|
|
14
27
|
protected preListen: {
|
|
15
28
|
[key: string]: Array<(data: any[]) => void>;
|
|
16
29
|
} | null;
|
|
@@ -22,18 +35,42 @@ export declare abstract class SonicWSCore<T extends {
|
|
|
22
35
|
_timers: Record<number, [number, (closed: boolean) => void, boolean]>;
|
|
23
36
|
private asyncData;
|
|
24
37
|
private asyncMap;
|
|
38
|
+
private reconnectFactory?;
|
|
39
|
+
private reconnectOptions;
|
|
40
|
+
private reconnectAttempt;
|
|
41
|
+
private reconnectTimer?;
|
|
42
|
+
private intentionalClose;
|
|
43
|
+
private connectedOnce;
|
|
44
|
+
private reconnectingListeners;
|
|
45
|
+
private reconnectListeners;
|
|
46
|
+
private reconnectFailedListeners;
|
|
47
|
+
private nextRequestId;
|
|
48
|
+
private pendingRequests;
|
|
49
|
+
private responders;
|
|
50
|
+
private sessionId?;
|
|
51
|
+
private lastReplaySequence;
|
|
52
|
+
private recoveredListeners;
|
|
53
|
+
private pendingResumeSession?;
|
|
54
|
+
private handshakeTimeoutMs;
|
|
55
|
+
private handshakeTimer?;
|
|
25
56
|
constructor(ws: T, bufferHandler: (val: K) => Promise<Uint8Array>, on: Function, off: Function);
|
|
57
|
+
protected configureHandshakeTimeout(milliseconds: number): void;
|
|
58
|
+
private armHandshakeTimeout;
|
|
59
|
+
protected configureReconnect(factory: () => TransportBinding<T, K>, options?: ReconnectOptions): void;
|
|
60
|
+
private attachClientTransport;
|
|
61
|
+
private scheduleReconnect;
|
|
62
|
+
private beginReconnect;
|
|
26
63
|
private reading;
|
|
27
64
|
private readQueue;
|
|
28
65
|
private serverKeyHandler;
|
|
29
66
|
private invalidPacket;
|
|
30
67
|
private listenLock;
|
|
31
68
|
private packetQueue;
|
|
32
|
-
|
|
69
|
+
private deliverPacket;
|
|
70
|
+
private releasePacketLock;
|
|
33
71
|
private isAsync;
|
|
34
|
-
private enqueuePacket;
|
|
35
|
-
private triggerNextPacket;
|
|
36
72
|
private dataHandler;
|
|
73
|
+
private handleControl;
|
|
37
74
|
private messageHandler;
|
|
38
75
|
protected listen(tag: string, listener: (data: any[]) => void): void;
|
|
39
76
|
private sendQueue;
|
|
@@ -44,7 +81,15 @@ export declare abstract class SonicWSCore<T extends {
|
|
|
44
81
|
*/
|
|
45
82
|
send(tag: string, ...values: any[]): Promise<void>;
|
|
46
83
|
sendVariant(parent: string, variant: string, ...values: any[]): Promise<void>;
|
|
84
|
+
/** Sends a validated packet as an RPC request and waits for its response. */
|
|
85
|
+
request(tag: string, ...valuesAndOptions: any[]): Promise<any>;
|
|
86
|
+
/** Registers the client-side responder for server requests using this packet tag. */
|
|
87
|
+
respond(tag: string, handler: (...values: any[]) => any): void;
|
|
47
88
|
sendSafe(tag: string, ...values: any[]): Promise<boolean>;
|
|
89
|
+
/** Drops this update before encoding when the transport is backpressured. */
|
|
90
|
+
sendVolatile(tag: string, ...values: any[]): Promise<boolean>;
|
|
91
|
+
/** Sends a packet without applying the volatile backpressure drop policy. */
|
|
92
|
+
sendReliable(tag: string, ...values: any[]): Promise<void>;
|
|
48
93
|
/**
|
|
49
94
|
* Listens for when the client connects
|
|
50
95
|
* @param listener Callback on connection
|
|
@@ -54,7 +99,22 @@ export declare abstract class SonicWSCore<T extends {
|
|
|
54
99
|
* Listens for when the client closes
|
|
55
100
|
* @param listener Callback on close with close event
|
|
56
101
|
*/
|
|
57
|
-
on_close(listener: (
|
|
102
|
+
on_close(listener: (...args: any[]) => void): void;
|
|
103
|
+
/** Listens for reconnect attempts before a replacement transport opens. */
|
|
104
|
+
on_reconnecting(listener: (event: {
|
|
105
|
+
attempt: number;
|
|
106
|
+
delayMs: number;
|
|
107
|
+
}) => void): void;
|
|
108
|
+
/** Listens for successful reconnection and schema negotiation. */
|
|
109
|
+
on_reconnect(listener: () => void): void;
|
|
110
|
+
/** Listens for reconnect exhaustion. */
|
|
111
|
+
on_reconnect_failed(listener: () => void): void;
|
|
112
|
+
/** Listens for the result of connection-state recovery. */
|
|
113
|
+
on_recovered(listener: (event: {
|
|
114
|
+
recovered: boolean;
|
|
115
|
+
replayed: number;
|
|
116
|
+
}) => void): void;
|
|
117
|
+
close(code?: number, reason?: string | Buffer): void;
|
|
58
118
|
/**
|
|
59
119
|
* Listens to a packet from the server
|
|
60
120
|
* @param tag The tag to listen for
|
|
@@ -62,3 +122,4 @@ export declare abstract class SonicWSCore<T extends {
|
|
|
62
122
|
*/
|
|
63
123
|
on(tag: string, listener: (value: any[]) => void): void;
|
|
64
124
|
}
|
|
125
|
+
export {};
|
|
@@ -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],e.clearQuantizationState(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 v=c.subarray(d+u,c.length);this.serverPackets.holdPackets(r.Packet.deserializeAll(v,!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,a,r){const n=this.listeners[t],c=this.serverPackets.getPacket(t),o=c.parent?this.listeners[c.parent]:void 0;if(!n&&!o)return console.warn("Warn: No listener for packet "+t),void await this.triggerNextPacket(s,a,r);if(n&&await(0,i.listenPacket)(e,n,this.invalidPacket),"string"!=typeof e&&c.parent&&c.variant)for(const t of o??[])await t({variant:c.variant,payload:e[0]});await this.triggerNextPacket(s,a,r),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){if(!this.serverPackets.hasTag(e))return void console.log("Tag is not available on server: "+e);const s=this.serverPackets.resolveTag(e);(this.listeners[s]??=[]).push(t)}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)}sendVariant(e,t,...s){return this.send(this.clientPackets.getVariantTag(e,t),...s)}async sendSafe(e,...t){try{return await this.send(e,...t),!0}catch(t){return console.error(`Failed to send packet "${e}"`,t),!1}}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"),n=require("../../util/packets/PacketUtils"),i=require("../../../version"),r=require("../../packets/Packets"),a=require("../../util/packets/BatchHelper"),o=require("../../util/BufferUtil"),c=require("../../Connection"),h=require("../../util/StringUtil"),l=require("../../util/packets/ControlProtocol");class d extends c.Connection{preListen;clientPackets=new e.PacketHolder;serverPackets=new e.PacketHolder;pastKeys=!1;readyListeners=[];bufferHandler;_timers={};asyncData={};asyncMap={};reconnectFactory;reconnectOptions={enabled:!1,attempts:1/0,minDelayMs:500,maxDelayMs:1e4,jitter:.25};reconnectAttempt=0;reconnectTimer;intentionalClose=!1;connectedOnce=!1;reconnectingListeners=[];reconnectListeners=[];reconnectFailedListeners=[];nextRequestId=1;pendingRequests=new Map;responders=new Map;sessionId;lastReplaySequence=0;recoveredListeners=[];pendingResumeSession;handshakeTimeoutMs=1e4;handshakeTimer;constructor(e,t,s,n){super(e,-1,"LocalSocket",s,n),this.socket=e,this.preListen={},this.invalidPacket=this.invalidPacket.bind(this),this.serverKeyHandler=this.serverKeyHandler.bind(this),this.messageHandler=this.messageHandler.bind(this),this.attachClientTransport(),this.armHandshakeTimeout(),this.bufferHandler=t}configureHandshakeTimeout(e){if(!Number.isFinite(e)||e<=0)throw new Error("Handshake timeout must be positive");this.handshakeTimeoutMs=e,this.armHandshakeTimeout()}armHandshakeTimeout(){this.handshakeTimer&&clearTimeout(this.handshakeTimer),this.handshakeTimer=setTimeout(()=>{this.pastKeys||this.socket.close(c.CloseCodes.INVALID_DATA,"SonicWS schema handshake timed out")},this.handshakeTimeoutMs)}configureReconnect(e,t={}){if(this.reconnectFactory=e,this.reconnectOptions={enabled:t.enabled??!0,attempts:t.attempts??1/0,minDelayMs:t.minDelayMs??500,maxDelayMs:t.maxDelayMs??1e4,jitter:t.jitter??.25},this.reconnectOptions.attempts<0||this.reconnectOptions.minDelayMs<0||this.reconnectOptions.maxDelayMs<this.reconnectOptions.minDelayMs)throw new Error("Invalid reconnect timing options");if(this.reconnectOptions.jitter<0||this.reconnectOptions.jitter>1)throw new Error("Reconnect jitter must be between 0 and 1")}attachClientTransport(){this._on("message",this.serverKeyHandler),this._on("close",(...e)=>{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],e.clearQuantizationState(0);for(const e of this.serverPackets.getPackets())delete e.lastReceived[0];const t=e[0],s="number"==typeof t?t:t?.code;this.intentionalClose||1e3===s||this.scheduleReconnect()})}scheduleReconnect(){if(!this.reconnectFactory||!this.reconnectOptions.enabled||this.reconnectTimer)return;if(this.reconnectAttempt>=this.reconnectOptions.attempts)return void this.reconnectFailedListeners.forEach(e=>e());const e=++this.reconnectAttempt,t=Math.min(this.reconnectOptions.maxDelayMs,this.reconnectOptions.minDelayMs*2**(e-1)),s=t*this.reconnectOptions.jitter,n=Math.max(0,Math.round(t-s+Math.random()*s*2));this.reconnectingListeners.forEach(t=>t({attempt:e,delayMs:n})),this.reconnectTimer=setTimeout(()=>{this.reconnectTimer=void 0,this.beginReconnect()},n)}beginReconnect(){try{const t=this.reconnectFactory();this.clientPackets=new e.PacketHolder,this.serverPackets=new e.PacketHolder,this.asyncData={},this.asyncMap={},this.reading=!1,this.readQueue=[],this.pastKeys=!1,this.preListen={},this.bufferHandler=t.bufferHandler,this.batcher=new a.BatchHelper,this.replaceTransport(t.socket,t.on,t.off),this.attachClientTransport(),this.armHandshakeTimeout()}catch{this.scheduleReconnect()}}reading=!1;readQueue=[];async serverKeyHandler(e){if(this.reading)return void this.readQueue.push(e);this.reading=!0;const n=await this.bufferHandler(e);if(n.length<3||(0,h.as8String)(n.slice(0,3))!==i.SERVER_SUFFIX)throw this.close(1e3),new Error("The requested server does not use the SonicWS protocol");const a=n[3];if(a!==i.VERSION)throw this.close(1e3),new Error(`Protocol mismatch: ${a>i.VERSION?"client":"server"} is outdated (server: ${a}, client: ${i.VERSION})`);const o=(0,s.inflateNative)(n.subarray(4)),c=this.sessionId,[d,u]=(0,t.readVarInt)(o,0);this.id=u;const[p,k]=(0,t.readVarInt)(o,d);this.sessionId=(new TextDecoder).decode(o.slice(p,p+k));const[m,v]=(0,t.readVarInt)(o,p+k),y=o.subarray(m,m+v);this.clientPackets.holdPackets(r.Packet.deserializeAll(y,!0));const f=o.subarray(m+v);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,[]])}for(const[e,t]of Object.entries(this.preListen??{}))if(this.serverPackets.hasTag(e))for(const s of t)this.listen(e,s);else console.error(new Error(`The server does not define packet tag "${e}"`));this.preListen=null,this.pastKeys=!0,this.handshakeTimer&&clearTimeout(this.handshakeTimer),this.connectedOnce&&(this.reconnectAttempt=0,this.reconnectListeners.forEach(e=>e())),this.connectedOnce=!0,this.readyListeners?.forEach(e=>e()),this.readyListeners=null,this._off("message",this.serverKeyHandler),this._on("message",this.messageHandler),c&&c!==this.sessionId&&(this.pendingResumeSession=c,this.raw_send((0,l.encodeResume)(c,this.lastReplaySequence))),this.readQueue.forEach(e=>{this.messageHandler(e)}),this.readQueue=[]}invalidPacket(e){throw console.error(e),new Error("SonicWS rejected data from the server. Report reproducible codec failures at https://github.com/liwybloc/sonic-ws")}listenLock=!1;packetQueue=[];async deliverPacket(e,t,s,i,r){if(this.closed)return void this.releasePacketLock(s,i,r);const a=this.listeners[t],o=this.serverPackets.getPacket(t),c=o.parent?this.listeners[o.parent]:void 0;if(!a&&!c)return console.warn(`No listener is registered for packet "${t}"`),void this.releasePacketLock(s,i,r);if(a&&await(0,n.listenPacket)(e,a,this.invalidPacket),"string"!=typeof e&&o.parent&&o.variant)for(const t of c??[])await t({variant:o.variant,payload:e[0]});await this.callMiddleware("onReceive_post",t,"string"==typeof e?[e]:e[0]),this.releasePacketLock(s,i,r)}releasePacketLock(e,t,s){t?s[0]=!1:this.listenLock=!1,e.length>0&&this.dataHandler(e.shift())}isAsync(e){return this.asyncMap[e]}async dataHandler(e){if(0===e[0])return void await this.handleControl(e);const t=e[0],s=e.slice(1),n=this.isAsync(t);let i,r,o;if(n?(o=this.asyncData[t],i=o[0],r=o[1]):(i=this.listenLock,r=this.packetQueue),i)return void r.push(e);n?o[0]=!0:this.listenLock=!0;const c=this.serverPackets.getTag(t),h=this.serverPackets.getPacket(c);if(await this.callMiddleware("onReceive_pre",h.tag,e,e.length))return void this.releasePacketLock(r,n,o);if(h.rereference&&0===s.length)return void 0===h.lastReceived[0]&&this.invalidPacket("No previous value to rereference"),void this.deliverPacket(h.lastReceived[0],c,r,n,o);if(0===h.dataBatching){const e=h.lastReceived[0]=await h.listen(s,null);return void this.deliverPacket(e,c,r,n,o)}const l=await a.BatchHelper.unravelBatch(h,s,null);"string"==typeof l&&this.invalidPacket(l),l.forEach(e=>{this.deliverPacket(e,c,r,n,o)})}async handleControl(e){let t;try{t=(0,l.decodeControl)(e)}catch{return void this.close(c.CloseCodes.INVALID_DATA,"Malformed SonicWS control frame")}switch(t.type){case l.ControlType.REPLAY:if(t.sequence<=this.lastReplaySequence)return;return this.lastReplaySequence=t.sequence,void await this.dataHandler(t.payload);case l.ControlType.RESUMED:return t.recovered&&this.pendingResumeSession&&(this.sessionId=this.pendingResumeSession),this.pendingResumeSession=void 0,this.recoveredListeners.forEach(e=>e({recovered:t.recovered,replayed:t.replayed})),void(t.recovered||(this.lastReplaySequence=0));case l.ControlType.RESUME:throw new Error("A client cannot receive a recovery request");case l.ControlType.RESPONSE:{const e=this.pendingRequests.get(t.id);if(!e)return;return clearTimeout(e.timer),this.pendingRequests.delete(t.id),void(t.ok?e.resolve(t.value):e.reject(new Error(String(t.value))))}default:try{const e=this.serverPackets.getTag(t.packetKey);if(!e)throw new Error(`Unknown RPC packet key ${t.packetKey}`);const s=this.responders.get(e);if(!s)throw new Error(`No responder registered for packet "${e}"`);const n=await this.serverPackets.getPacket(e).listen(t.payload,null);if("string"==typeof n)throw new Error(n);const[i,r]=n,a=r?await s(...i):await s(i);this.raw_send((0,l.encodeControlResponse)(t.id,!0,a??null))}catch(e){this.raw_send((0,l.encodeControlResponse)(t.id,!1,e instanceof Error?e.message:String(e)))}}}async messageHandler(e){const t=await this.bufferHandler(e);t.length<1||await this.dataHandler(t)}listen(e,t){if(!this.serverPackets.hasTag(e))return void console.warn(`Packet tag "${e}" is not available on the server`);const s=this.serverPackets.resolveTag(e);(this.listeners[s]??=[]).push(t)}sendQueue=[!1,[],void 0];async send(e,...t){if(await this.callMiddleware("onSend_pre",e,t,Date.now(),performance.now()))return;const[s,i,r]=await(0,n.processPacket)(this.clientPackets,e,t,this.sendQueue,0);0===r.dataBatching?this.raw_send((0,o.toPacketBuffer)(s,i)):this.batcher.batchPacket(s,i),await this.callMiddleware("onSend_post",e,i,i.length)}sendVariant(e,t,...s){return this.send(this.clientPackets.getVariantTag(e,t),...s)}async request(e,...t){const s=t.at(-1),i=t.length>1&&s&&"object"==typeof s&&!Array.isArray(s)&&Object.keys(s).every(e=>"timeoutMs"===e)?t.pop():{},[r,a]=await(0,n.processPacket)(this.clientPackets,e,t,this.sendQueue,0),o=this.nextRequestId++;return this.nextRequestId>2147483647&&(this.nextRequestId=1),new Promise((t,s)=>{const n=setTimeout(()=>{this.pendingRequests.delete(o),s(new Error(`RPC request "${e}" timed out`))},i.timeoutMs??5e3);this.pendingRequests.set(o,{resolve:t,reject:s,timer:n}),this.raw_send((0,l.encodeControlRequest)(o,r,a))})}respond(e,t){const s=this.serverPackets.resolveTag(e);this.responders.set(s,t)}async sendSafe(e,...t){try{return await this.send(e,...t),!0}catch(t){return console.error(`Failed to send packet "${e}"`,t),!1}}async sendVolatile(e,...t){return!!this.canSendVolatile()&&(await this.send(e,...t),!0)}sendReliable(e,...t){return this.send(e,...t)}on_ready(e){this.pastKeys?e():(this.readyListeners??=[]).push(e)}on_close(e){this._on("close",e)}on_reconnecting(e){this.reconnectingListeners.push(e)}on_reconnect(e){this.reconnectListeners.push(e)}on_reconnect_failed(e){this.reconnectFailedListeners.push(e)}on_recovered(e){this.recoveredListeners.push(e)}close(e=1e3,t){this.intentionalClose=!0,this.reconnectTimer&&clearTimeout(this.reconnectTimer),super.close(e,t)}on(e,t){if(this.socket.readyState!==WebSocket.OPEN){const s=this.preListen??={};return s[e]??=[],void s[e].push(t)}this.listen(e,t)}}exports.SonicWSCore=d;
|
|
@@ -4,13 +4,19 @@
|
|
|
4
4
|
* See LICENSE for personal, non-commercial license terms.
|
|
5
5
|
*/
|
|
6
6
|
import WS from 'ws';
|
|
7
|
-
import { SonicWSCore } from "../core/ClientCore";
|
|
8
|
-
|
|
7
|
+
import { ReconnectOptions, SonicWSCore } from "../core/ClientCore";
|
|
8
|
+
export type SonicConnectOptions = WS.ClientOptions & {
|
|
9
|
+
reconnect?: ReconnectOptions;
|
|
10
|
+
readyTimeoutMs?: number;
|
|
11
|
+
};
|
|
12
|
+
/** Connects a Node.js process to a SonicWS server. */
|
|
9
13
|
export declare class SonicWS extends SonicWSCore<WS.WebSocket, Buffer> {
|
|
10
14
|
/**
|
|
11
15
|
* Creates a connection to the url
|
|
12
16
|
* @param url The url to connect to
|
|
13
17
|
* @param options The websocket options
|
|
14
18
|
*/
|
|
15
|
-
constructor(url: string, options?: WS.ClientOptions);
|
|
19
|
+
constructor(url: string, options?: WS.ClientOptions, reconnect?: ReconnectOptions, readyTimeoutMs?: number);
|
|
20
|
+
/** Creates a client and resolves after WASM loading and schema negotiation. */
|
|
21
|
+
static connect(url: string, options?: SonicConnectOptions): Promise<SonicWS>;
|
|
16
22
|
}
|
|
@@ -4,4 +4,4 @@
|
|
|
4
4
|
* See LICENSE for personal, non-commercial license terms.
|
|
5
5
|
*/
|
|
6
6
|
|
|
7
|
-
var e=this&&this.__importDefault||function(e){return e&&e.__esModule?e:{default:e}};Object.defineProperty(exports,"__esModule",{value:!0}),exports.SonicWS=void 0;const o=e(require("ws")),
|
|
7
|
+
var e=this&&this.__importDefault||function(e){return e&&e.__esModule?e:{default:e}};Object.defineProperty(exports,"__esModule",{value:!0}),exports.SonicWS=void 0;const o=e(require("ws")),n=require("../core/ClientCore");class r extends n.SonicWSCore{constructor(e,n,r,t=1e4){const c=new o.default.WebSocket(e,n);c.on("error",()=>{}),super(c,e=>Promise.resolve(new Uint8Array(e)),c.on.bind(c),c.off.bind(c)),this.configureHandshakeTimeout(t),r?.enabled&&this.configureReconnect(()=>{const r=new o.default.WebSocket(e,n);return r.on("error",()=>{}),{socket:r,bufferHandler:e=>Promise.resolve(new Uint8Array(e)),on:r.on.bind(r),off:r.off.bind(r)}},r)}static async connect(e,o={}){const{reconnect:n,readyTimeoutMs:t,...c}=o,s=new r(e,c,n,t);return await new Promise((e,o)=>{s.on_ready(e),s.on_close((e,n)=>{s.clientPackets.getPackets()?.length||o(new Error(`SonicWS connection closed before ready (${e}: ${n})`))})}),s}}exports.SonicWS=r;
|
|
@@ -0,0 +1,30 @@
|
|
|
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
|
+
import type { ConnectionMiddleware } from "../PacketProcessor";
|
|
7
|
+
export type PacketLogEntry = {
|
|
8
|
+
direction: "send" | "receive";
|
|
9
|
+
tag: string;
|
|
10
|
+
values: unknown;
|
|
11
|
+
bytes: number;
|
|
12
|
+
timestamp: number;
|
|
13
|
+
};
|
|
14
|
+
export type PacketLoggerOptions = {
|
|
15
|
+
logger?: (entry: PacketLogEntry) => void;
|
|
16
|
+
includeValues?: boolean;
|
|
17
|
+
};
|
|
18
|
+
/** Readable packet logging implemented through the public middleware hooks. */
|
|
19
|
+
export declare class PacketLogger implements ConnectionMiddleware {
|
|
20
|
+
private readonly logger;
|
|
21
|
+
private readonly includeValues;
|
|
22
|
+
private readonly sends;
|
|
23
|
+
private readonly receiveSizes;
|
|
24
|
+
constructor(options?: PacketLoggerOptions);
|
|
25
|
+
onSend_pre: (tag: string, values: unknown[]) => void;
|
|
26
|
+
onSend_post: (tag: string, _data: Uint8Array, size: number) => void;
|
|
27
|
+
onReceive_pre: (tag: string, _data: Uint8Array, size: number) => void;
|
|
28
|
+
onReceive_post: (tag: string, values: unknown) => void;
|
|
29
|
+
private emit;
|
|
30
|
+
}
|
|
@@ -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.PacketLogger=void 0;exports.PacketLogger=class{logger;includeValues;sends=new Map;receiveSizes=new Map;constructor(e={}){this.includeValues=e.includeValues??!0,this.logger=e.logger??(e=>{const s="send"===e.direction?"→":"←";console.debug(`${s} ${e.tag}`,e.values,`${e.bytes} bytes`)})}onSend_pre=(e,s)=>{this.sends.set(e,s)};onSend_post=(e,s,t)=>{this.emit("send",e,this.sends.get(e),t+1),this.sends.delete(e)};onReceive_pre=(e,s,t)=>{const i=this.receiveSizes.get(e)??[];i.push(t+1),this.receiveSizes.set(e,i)};onReceive_post=(e,s)=>{const t=this.receiveSizes.get(e);this.emit("receive",e,s,t?.shift()??0),0===t?.length&&this.receiveSizes.delete(e)};emit(e,s,t,i){this.logger({direction:e,tag:s,values:this.includeValues?t:void 0,bytes:i,timestamp:Date.now()})}};
|
|
@@ -37,10 +37,11 @@ export declare enum PacketType {
|
|
|
37
37
|
DOUBLES = 13,
|
|
38
38
|
/** One or more true/false */
|
|
39
39
|
BOOLEANS = 14,
|
|
40
|
-
/** Consumes multiple keys to describe the value. E.g. if you want to send a boolean, this could take up 2 keys instead of sending 2 bytes. Currently W.I.P. */
|
|
41
|
-
KEY_EFFECTIVE = 15,
|
|
42
40
|
/** TypeScript-side JSONUtil codec carried as opaque RAW bytes through reserved wire type 16. */
|
|
43
41
|
JSON = 16,
|
|
44
|
-
/**
|
|
42
|
+
/**
|
|
43
|
+
* Hex bytes returned in lowercase.
|
|
44
|
+
* This carries one string and behaves like automatically parsed UBYTES.
|
|
45
|
+
*/
|
|
45
46
|
HEX = 17
|
|
46
47
|
}
|
|
@@ -4,4 +4,4 @@
|
|
|
4
4
|
* See LICENSE for personal, non-commercial license terms.
|
|
5
5
|
*/
|
|
6
6
|
|
|
7
|
-
var S;Object.defineProperty(exports,"__esModule",{value:!0}),exports.PacketType=void 0,function(S){S[S.NONE=0]="NONE",S[S.RAW=1]="RAW",S[S.STRINGS_ASCII=2]="STRINGS_ASCII",S[S.STRINGS_UTF16=3]="STRINGS_UTF16",S[S.STRINGS=2]="STRINGS",S[S.ENUMS=4]="ENUMS",S[S.BYTES=5]="BYTES",S[S.UBYTES=6]="UBYTES",S[S.SHORTS=7]="SHORTS",S[S.USHORTS=8]="USHORTS",S[S.VARINT=9]="VARINT",S[S.UVARINT=10]="UVARINT",S[S.DELTAS=11]="DELTAS",S[S.FLOATS=12]="FLOATS",S[S.DOUBLES=13]="DOUBLES",S[S.BOOLEANS=14]="BOOLEANS",S[S.
|
|
7
|
+
var S;Object.defineProperty(exports,"__esModule",{value:!0}),exports.PacketType=void 0,function(S){S[S.NONE=0]="NONE",S[S.RAW=1]="RAW",S[S.STRINGS_ASCII=2]="STRINGS_ASCII",S[S.STRINGS_UTF16=3]="STRINGS_UTF16",S[S.STRINGS=2]="STRINGS",S[S.ENUMS=4]="ENUMS",S[S.BYTES=5]="BYTES",S[S.UBYTES=6]="UBYTES",S[S.SHORTS=7]="SHORTS",S[S.USHORTS=8]="USHORTS",S[S.VARINT=9]="VARINT",S[S.UVARINT=10]="UVARINT",S[S.DELTAS=11]="DELTAS",S[S.FLOATS=12]="FLOATS",S[S.DOUBLES=13]="DOUBLES",S[S.BOOLEANS=14]="BOOLEANS",S[S.JSON=16]="JSON",S[S.HEX=17]="HEX"}(S||(exports.PacketType=S={}));
|
|
@@ -32,6 +32,9 @@ export declare class Packet<T extends (PacketType | readonly PacketType[])> {
|
|
|
32
32
|
readonly valueMax?: number;
|
|
33
33
|
readonly parent?: string;
|
|
34
34
|
readonly variant?: string;
|
|
35
|
+
readonly isParent: boolean;
|
|
36
|
+
readonly constructorName?: string;
|
|
37
|
+
readonly replay: boolean;
|
|
35
38
|
readonly rateLimit: number;
|
|
36
39
|
readonly async: boolean;
|
|
37
40
|
readonly rereference: boolean;
|
|
@@ -39,14 +42,18 @@ export declare class Packet<T extends (PacketType | readonly PacketType[])> {
|
|
|
39
42
|
readonly object: boolean;
|
|
40
43
|
readonly client: boolean;
|
|
41
44
|
processReceive: (data: Uint8Array, validationResult: any) => any;
|
|
42
|
-
processSend: (data: any[]) => Promise<Uint8Array>;
|
|
45
|
+
processSend: (data: any[]) => Uint8Array | Promise<Uint8Array>;
|
|
43
46
|
validate: (data: Uint8Array) => Promise<[Uint8Array, boolean]>;
|
|
44
47
|
customValidator: ((socket: SonicWSConnection, ...values: any[]) => boolean) | null;
|
|
45
48
|
lastReceived: Record<number, any>;
|
|
46
49
|
lastSent: Record<number, number | bigint>;
|
|
47
50
|
private quantizationErrors;
|
|
51
|
+
private readonly recordValues?;
|
|
48
52
|
constructor(tag: string, schema: PacketSchema<T>, customValidator: ValidatorFunction, enabled: boolean, client: boolean);
|
|
53
|
+
private static compileRecordValues;
|
|
49
54
|
private assertRecord;
|
|
55
|
+
private construct;
|
|
56
|
+
private logicalValue;
|
|
50
57
|
private logical;
|
|
51
58
|
/** Converts ergonomic application values into the existing positional wire model. */
|
|
52
59
|
prepareSend(values: any[], stateKey?: number): any[];
|
|
@@ -55,6 +62,7 @@ export declare class Packet<T extends (PacketType | readonly PacketType[])> {
|
|
|
55
62
|
/** Converts decoded positional data into schema objects and application-level numbers. */
|
|
56
63
|
finishReceive(decoded: any): any;
|
|
57
64
|
listen(value: Uint8Array, socket: SonicWSConnection | null): Promise<[processed: any, flatten: boolean] | string>;
|
|
65
|
+
/** Serializes this packet definition for schema negotiation. */
|
|
58
66
|
serialize(): number[];
|
|
59
67
|
private static readVarInts;
|
|
60
68
|
static deserialize(data: Uint8Array, offset: number, client: boolean): [packet: Packet<any>, offset: number];
|
|
@@ -81,10 +89,21 @@ export declare class PacketSchema<T extends (PacketType | readonly PacketType[])
|
|
|
81
89
|
};
|
|
82
90
|
valueMin?: number;
|
|
83
91
|
valueMax?: number;
|
|
92
|
+
group?: {
|
|
93
|
+
parent: string;
|
|
94
|
+
variant: string;
|
|
95
|
+
isParent: boolean;
|
|
96
|
+
};
|
|
97
|
+
constructorName?: string;
|
|
98
|
+
replay: boolean;
|
|
84
99
|
constructor(object: boolean, type: ImpactType<T, ArguableType>, async: boolean, dataMin: ImpactType<T, number>, dataMax: ImpactType<T, number>, rateLimit: number, dontSpread: boolean, autoFlatten: boolean, rereference: boolean, dataBatching: number, maxBatchSize: number, gzipCompression: boolean, fields?: readonly string[], quantized?: {
|
|
85
100
|
scale: number;
|
|
86
101
|
trackError?: boolean;
|
|
87
|
-
}, valueMin?: number, valueMax?: number
|
|
102
|
+
}, valueMin?: number, valueMax?: number, group?: {
|
|
103
|
+
parent: string;
|
|
104
|
+
variant: string;
|
|
105
|
+
isParent: boolean;
|
|
106
|
+
}, constructorName?: string, replay?: boolean);
|
|
88
107
|
testObject(packet: Packet<PacketType | readonly PacketType[]>): packet is Packet<PacketType[]>;
|
|
89
108
|
}
|
|
90
109
|
export {};
|
|
@@ -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.PacketSchema=exports.Packet=void 0;const t=require("../util/enums/EnumHandler"),e=require("../util/enums/EnumType"),i=require("../util/packets/CompressionUtil"),a=require("../util/packets/PacketUtils"),s=require("./PacketType"),r=require("../util/StringUtil"),n=require("../../native/wrapper"),h=require("../util/packets/JSONUtil");class o{defaultEnabled;tag;maxSize;minSize;type;enumData;dataMax;dataMin;dataBatching;maxBatchSize;dontSpread;autoFlatten;fields;quantized;valueMin;valueMax;parent;variant;rateLimit;async;rereference;gzipCompression;object;client;processReceive;processSend;validate;customValidator;lastReceived={};lastSent={};quantizationErrors={};constructor(t,e,i,a,r){this.tag=t,this.defaultEnabled=a,this.client=r,this.async=e.async,this.enumData=e.enumData,this.rateLimit=e.rateLimit,this.dontSpread=e.dontSpread,this.autoFlatten=e.autoFlatten,this.rereference=e.rereference,this.dataBatching=e.dataBatching,this.maxBatchSize=r?1/0:e.maxBatchSize,this.gzipCompression=e.gzipCompression,this.fields=e.fields,this.quantized=e.quantized?{...e.quantized,trackError:e.quantized.trackError??!0}:void 0,this.valueMin=e.valueMin,this.valueMax=e.valueMax;const o=/^__(.+)\$([^$]+)$/.exec(t);if(this.parent=o?.[1],this.variant=o?.[2],this.object=e.object,this.type=e.type,this.dataMax=e.dataMax,this.dataMin=e.dataMin,e.testObject(this)){this.maxSize=this.minSize=this.type.length;for(let t=0;t<this.type.length;t++)this.type[t]==s.PacketType.NONE&&(this.dataMax[t]=this.dataMin[t]=0);const t={types:this.type,dataMins:this.dataMin,dataMaxes:this.dataMax,enumData:this.enumData};this.processReceive=e=>(0,n.decodeNativeObject)(t,e).map((t,e)=>this.type[e]===s.PacketType.JSON?(0,h.decompressJSON)(t):t),this.processSend=async e=>{let i=0;const a=e.map((t,e)=>{if(this.type[e]===s.PacketType.JSON)return(0,h.compressJSON)(t);if(this.type[e]!==s.PacketType.ENUMS)return t;const a=this.enumData[i++];return(Array.isArray(t)?t:[t]).map(t=>{if(!Number.isInteger(t)||t<0||t>=a.values.length)throw new Error(`Invalid wrapped enum index: ${t}`);return a.values[t]})});return(0,n.encodeNativeObject)(t,a)},this.validate=async e=>{(0,n.validateNativeObject)(t,e);return(0,n.decodeNativeObject)(t,e).forEach((t,e)=>{if(this.type[e]!==s.PacketType.JSON)return;const i=(0,h.decompressJSON)(t),a=Array.isArray(i)?i.length:1;if(a<this.dataMin[e]||a>this.dataMax[e])throw new Error("JSON value count is outside schema limits")}),[e,!0]}}else{{this.maxSize=this.dataMax,this.minSize=this.dataMin,this.type==s.PacketType.NONE&&(this.dataMax=this.dataMin=0);const t=this.enumData[0];this.processReceive=e=>this.type===s.PacketType.JSON?(0,h.decompressJSON)(e):(0,n.decodeNative)(this.type,e,this.dataMax,t),this.processSend=async e=>{let i;if(this.type===s.PacketType.JSON)i=(0,h.compressJSON)(e);else if(this.type===s.PacketType.ENUMS)i=Uint8Array.from(e);else{const a=this.type===s.PacketType.RAW&&1===e.length&&e[0]instanceof Uint8Array?e[0]:e;i=(0,n.encodeNative)(this.type,a,t)}return this.gzipCompression&&0===this.dataBatching?(0,n.deflateNative)(i):i},this.validate=async e=>{const i=this.gzipCompression&&0===this.dataBatching?(0,n.inflateNative)(e):e;if(this.type===s.PacketType.JSON){const t=(0,h.decompressJSON)(i),e=Array.isArray(t)?t.length:1;if(e<this.dataMin||e>this.dataMax)throw new Error("JSON value count is outside schema limits")}else(0,n.validateNative)(this.type,i,this.dataMin,this.dataMax,{enumData:t});return[i,!0]}}}this.customValidator=i}assertRecord(t,e){if(!this.fields)throw new Error(`Packet "${this.tag}" ${e} requires schema`);if(null===t||"object"!=typeof t||Array.isArray(t))throw new Error(`Packet "${this.tag}" ${e} requires an object record`);const i=this.fields.filter(e=>!Object.prototype.hasOwnProperty.call(t,e));if(i.length)throw new Error(`Packet "${this.tag}" is missing schema field(s): ${i.join(", ")}`);const a=Object.keys(t).filter(t=>!this.fields.includes(t));if(a.length)throw new Error(`Packet "${this.tag}" has unknown schema field(s): ${a.join(", ")}`);return this.fields.map(e=>t[e])}logical(t,e,i=-1){const a=this.quantized?.scale;return t.map(t=>{if("number"!=typeof t||!Number.isFinite(t))throw new Error(`Packet "${this.tag}" ${e} value must be a finite number`);const s="receive"===e&&a?t/a:t;if(void 0!==this.valueMin&&s<this.valueMin)throw new Error(`Packet "${this.tag}" value ${s} is below minimum ${this.valueMin}`);if(void 0!==this.valueMax&&s>this.valueMax)throw new Error(`Packet "${this.tag}" value ${s} exceeds maximum ${this.valueMax}`);if("send"===e&&a){const t=s*a+(this.quantized?.trackError?this.quantizationErrors[i]??0:0),e=Math.round(t);return this.quantized?.trackError&&(this.quantizationErrors[i]=t-e),e}return s})}prepareSend(t,e=-1){if(this.object){if(this.autoFlatten&&this.fields){if(1!==t.length||!Array.isArray(t[0]))throw new Error(`Packet "${this.tag}" autoTranspose requires one array of records`);const e=t[0].map(t=>this.assertRecord(t,"autoTranspose"));return this.fields.map((t,i)=>e.map(t=>t[i]))}return t}let i=t;if(this.autoFlatten){if(1!==t.length||!Array.isArray(t[0]))throw new Error(`Packet "${this.tag}" autoFlatten requires one array of records`);if(i=t[0].flatMap(t=>this.assertRecord(t,"autoFlatten")),this.fields&&i.length%this.fields.length!==0)throw new Error(`Packet "${this.tag}" flat value count must be divisible by schema length ${this.fields.length}`)}else this.fields&&1===t.length&&null!==t[0]&&"object"==typeof t[0]&&!Array.isArray(t[0])&&(i=this.assertRecord(t[0],"schema mapping"));return this.quantized||void 0!==this.valueMin||void 0!==this.valueMax?this.logical(i,"send",e):i}clearQuantizationState(t){delete this.quantizationErrors[t]}finishReceive(t){if(this.object){if(this.autoFlatten&&this.fields){const e=t,i=e[0]?.length??0;if(e.some(t=>t.length!==i))throw new Error(`Packet "${this.tag}" autoTranspose columns have different lengths`);return Array.from({length:i},(t,i)=>Object.fromEntries(this.fields.map((t,a)=>[t,e[a][i]])))}return this.autoFlatten?(0,a.UnFlattenData)(t):t}let e=Array.isArray(t)?t:[t];if((this.quantized||void 0!==this.valueMin||void 0!==this.valueMax)&&(e=this.logical(e,"receive")),this.autoFlatten){const t=this.fields.length;if(e.length%t!==0)throw new Error(`Packet "${this.tag}" flat value count ${e.length} is not divisible by schema length ${t}`);return Array.from({length:e.length/t},(i,a)=>Object.fromEntries(this.fields.map((i,s)=>[i,e[a*t+s]])))}return this.fields?Object.fromEntries(this.fields.map((t,i)=>[t,e[i]])):t}async listen(t,e){try{const[i,a]=await this.validate(t);if(!this.client&&!1===a)return"Invalid packet";const s=this.processReceive(i,a),r=this.finishReceive(s);if(null!=this.customValidator)if(this.dontSpread||this.fields){if(!this.customValidator(e,r))return"Didn't pass custom validator"}else if(!this.customValidator(e,...r))return"Didn't pass custom validator";return[r,!this.fields&&!this.dontSpread]}catch(t){return console.error("There was an error processing the packet! This is probably my fault... report at https://github.com/liwybloc/sonic-ws",t),"Error: "+t}}serialize(){const t=(new TextEncoder).encode(JSON.stringify({schema:this.fields,quantized:this.quantized,min:this.valueMin,max:this.valueMax})),e=[this.tag.length,...(0,r.processCharCodes)(this.tag),(0,i.compressBools)([this.dontSpread,this.async,this.object,this.autoFlatten,this.gzipCompression,this.rereference]),...(0,i.convertVarInt)(t.length),...t,this.dataBatching,this.enumData.length,...this.enumData.map(t=>t.serialize()).flat()];return this.object?[...e,this.maxSize,...this.dataMax.map(i.convertVarInt).flat(),...this.dataMin.map(i.convertVarInt).flat(),...this.type]:[...e,...(0,i.convertVarInt)(this.dataMax),...(0,i.convertVarInt)(this.dataMin),this.type]}static readVarInts(t,e,a){const s=[];for(let r=0;r<a;r++){const[a,r]=(0,i.readVarInt)(t,e);e=a,s.push(r)}return[s,e]}static deserialize(a,n,h){const c=n,d=a[n++],u=(0,r.as8String)(a.slice(n,n+=d)),[p,m,f,y,v,g]=(0,i.decompressBools)(a[n++]),[M,S]=(0,i.readVarInt)(a,n);n=M;const x=JSON.parse((new TextDecoder).decode(a.slice(n,n+=S))),w=a[n++],z=a[n++],k=[];for(let i=0;i<z;i++){const i=a[n++],s=(0,r.as8String)(a.slice(n,n+=i)),h=a[n++],o=[];for(let t=0;t<h;t++){const t=a[n++],i=a[n++],s=(0,r.as8String)(a.slice(n,n+=t));o.push(e.TYPE_CONVERSION_MAP[i](s))}k.push((0,t.DefineEnum)(s,o))}if(f){const t=a[n++],[e,i]=this.readVarInts(a,n,t);n=i;const[r,d]=this.readVarInts(a,n,t);n=d;const f=Array.from(a.slice(n,n+=t));let g=0;const M=f.map(t=>t==s.PacketType.ENUMS?k[g++]:t),S=new l(!0,M,m,r,e,-1,p,y,!1,w,-1,v,x.schema);return[new o(u,S,null,!1,h),n-c]}const[E,b]=(0,i.readVarInt)(a,n);n=E;const[N,P]=(0,i.readVarInt)(a,n);n=N;const O=a[n++],q=O==s.PacketType.ENUMS?k[0]:O,$=new l(!1,q,m,P,b,-1,p,y,g,w,-1,v,x.schema,x.quantized,x.min,x.max);return[new o(u,$,null,!1,h),n-c]}static deserializeAll(t,e){const i=[];let a=0;for(;a<t.length;){const[s,r]=this.deserialize(t,a,e);i.push(s),a+=r}return i}}exports.Packet=o;const c=(t,i)=>t instanceof e.EnumPackage?(i.push(t),s.PacketType.ENUMS):t;class l{type;enumData=[];dataMax;dataMin;dataBatching;maxBatchSize;rateLimit;dontSpread=!1;autoFlatten=!1;async=!1;rereference=!1;gzipCompression=!1;object;fields;quantized;valueMin;valueMax;constructor(t,e,i,a,s,r,n,h,o,l,d,u,p,m,f,y){this.object=t,this.async=i,this.dataMin=a,this.dataMax=s,this.rateLimit=r,this.dontSpread=n,this.autoFlatten=h,this.rereference=o,this.dataBatching=l,this.maxBatchSize=d,this.gzipCompression=u,this.fields=p?[...p]:void 0,this.quantized=m?{...m}:void 0,this.valueMin=f,this.valueMax=y,this.type=t?e.map(t=>c(t,this.enumData)):c(e,this.enumData)}testObject(t){return this.object}}exports.PacketSchema=l;
|
|
7
|
+
Object.defineProperty(exports,"__esModule",{value:!0}),exports.PacketSchema=exports.Packet=void 0;const t=require("../util/enums/EnumHandler"),e=require("../util/enums/EnumType"),i=require("../util/packets/CompressionUtil"),a=require("../util/packets/PacketUtils"),s=require("./PacketType"),r=require("../util/StringUtil"),n=require("../../native/wrapper"),o=require("../util/packets/JSONUtil"),c=require("../util/packets/ConstructorRegistry");class h{defaultEnabled;tag;maxSize;minSize;type;enumData;dataMax;dataMin;dataBatching;maxBatchSize;dontSpread;autoFlatten;fields;quantized;valueMin;valueMax;parent;variant;isParent;constructorName;replay;rateLimit;async;rereference;gzipCompression;object;client;processReceive;processSend;validate;customValidator;lastReceived={};lastSent={};quantizationErrors={};recordValues;constructor(t,e,i,a,r){if(this.tag=t,this.defaultEnabled=a,this.client=r,this.async=e.async,this.enumData=e.enumData,this.rateLimit=e.rateLimit,this.dontSpread=e.dontSpread,this.autoFlatten=e.autoFlatten,this.rereference=e.rereference,this.dataBatching=e.dataBatching,this.maxBatchSize=r?1/0:e.maxBatchSize,this.gzipCompression=e.gzipCompression,this.fields=e.fields,this.recordValues=this.fields?h.compileRecordValues(this.fields):void 0,this.quantized=e.quantized?{...e.quantized,trackError:e.quantized.trackError??!0}:void 0,this.valueMin=e.valueMin,this.valueMax=e.valueMax,this.parent=e.group?.parent,this.variant=e.group?.variant,this.isParent=e.group?.isParent??!1,this.constructorName=e.constructorName,this.replay=e.replay,this.object=e.object,this.type=e.type,this.dataMax=e.dataMax,this.dataMin=e.dataMin,e.testObject(this)){this.maxSize=this.minSize=this.type.length;for(let t=0;t<this.type.length;t++)this.type[t]==s.PacketType.NONE&&(this.dataMax[t]=this.dataMin[t]=0);const t={types:this.type,dataMins:this.dataMin,dataMaxes:this.dataMax,enumData:this.enumData};this.processReceive=e=>(0,n.decodeNativeObject)(t,e).map((t,e)=>this.type[e]===s.PacketType.JSON?(0,o.decompressJSON)(t):t),this.processSend=e=>{let i=0;const a=e.map((t,e)=>{if(this.type[e]===s.PacketType.JSON)return(0,o.compressJSON)(t);if(this.type[e]!==s.PacketType.ENUMS)return t;const a=this.enumData[i++];return(Array.isArray(t)?t:[t]).map(t=>{if(!Number.isInteger(t)||t<0||t>=a.values.length)throw new Error(`Invalid wrapped enum index: ${t}`);return a.values[t]})});return(0,n.encodeNativeObject)(t,a)},this.validate=async e=>{(0,n.validateNativeObject)(t,e);return(0,n.decodeNativeObject)(t,e).forEach((t,e)=>{if(this.type[e]!==s.PacketType.JSON)return;const i=(0,o.decompressJSON)(t),a=Array.isArray(i)?i.length:1;if(a<this.dataMin[e]||a>this.dataMax[e])throw new Error("JSON value count is outside schema limits")}),[e,!0]}}else{{this.maxSize=this.dataMax,this.minSize=this.dataMin,this.type==s.PacketType.NONE&&(this.dataMax=this.dataMin=0);const t=this.enumData[0];this.processReceive=e=>this.type===s.PacketType.JSON?(0,o.decompressJSON)(e):(0,n.decodeNative)(this.type,e,this.dataMax,t),this.processSend=e=>{let i;if(this.type===s.PacketType.JSON)i=(0,o.compressJSON)(e);else if(this.type===s.PacketType.ENUMS)i=Uint8Array.from(e);else{const a=this.type===s.PacketType.RAW&&1===e.length&&e[0]instanceof Uint8Array?e[0]:e;i=(0,n.encodeNative)(this.type,a,t)}return this.gzipCompression&&0===this.dataBatching?(0,n.deflateNative)(i):i},this.validate=async e=>{const i=this.gzipCompression&&0===this.dataBatching?(0,n.inflateNative)(e):e;if(this.type===s.PacketType.JSON){const t=(0,o.decompressJSON)(i),e=Array.isArray(t)?t.length:1;if(e<this.dataMin||e>this.dataMax)throw new Error("JSON value count is outside schema limits")}else(0,n.validateNative)(this.type,i,this.dataMin,this.dataMax,{enumData:t});return[i,!0]}}}this.customValidator=i}static compileRecordValues(t){switch(t.length){case 0:return()=>[];case 1:{const[e]=t;return t=>[t[e]]}case 2:{const[e,i]=t;return t=>[t[e],t[i]]}case 3:{const[e,i,a]=t;return t=>[t[e],t[i],t[a]]}case 4:{const[e,i,a,s]=t;return t=>[t[e],t[i],t[a],t[s]]}case 5:{const[e,i,a,s,r]=t;return t=>[t[e],t[i],t[a],t[s],t[r]]}case 6:{const[e,i,a,s,r,n]=t;return t=>[t[e],t[i],t[a],t[s],t[r],t[n]]}case 7:{const[e,i,a,s,r,n,o]=t;return t=>[t[e],t[i],t[a],t[s],t[r],t[n],t[o]]}case 8:{const[e,i,a,s,r,n,o,c]=t;return t=>[t[e],t[i],t[a],t[s],t[r],t[n],t[o],t[c]]}default:return e=>{const i=new Array(t.length);for(let a=0;a<t.length;a++)i[a]=e[t[a]];return i}}}assertRecord(t,e){if(!this.fields)throw new Error(`Packet "${this.tag}" ${e} requires schema`);if(null===t||"object"!=typeof t||Array.isArray(t))throw new Error(`Packet "${this.tag}" ${e} requires an object record`);for(const e of this.fields)if(!Object.prototype.hasOwnProperty.call(t,e))throw new Error(`Packet "${this.tag}" is missing schema field(s): ${e}`);const i=Object.keys(t);if(i.length!==this.fields.length){const t=i.filter(t=>!this.fields.includes(t));if(t.length)throw new Error(`Packet "${this.tag}" has unknown schema field(s): ${t.join(", ")}`)}return this.recordValues(t)}construct(t){return this.constructorName?new((0,c.resolvePacketConstructor)(this.constructorName))(t):t}logicalValue(t,e,i){const a=this.quantized?.scale;if("number"!=typeof t||!Number.isFinite(t))throw new Error(`Packet "${this.tag}" ${e} value must be a finite number`);const s="receive"===e&&a?t/a:t;if(void 0!==this.valueMin&&s<this.valueMin)throw new Error(`Packet "${this.tag}" value ${s} is below minimum ${this.valueMin}`);if(void 0!==this.valueMax&&s>this.valueMax)throw new Error(`Packet "${this.tag}" value ${s} exceeds maximum ${this.valueMax}`);if("send"===e&&a){const t=s*a+(this.quantized?.trackError?this.quantizationErrors[i]??0:0),e=Math.round(t);return this.quantized?.trackError&&(this.quantizationErrors[i]=t-e),e}return s}logical(t,e,i=-1){const a=new Array(t.length);for(let s=0;s<t.length;s++)a[s]=this.logicalValue(t[s],e,i);return a}prepareSend(t,e=-1){if(this.object){if(this.autoFlatten&&this.fields){if(1!==t.length||!Array.isArray(t[0]))throw new Error(`Packet "${this.tag}" autoTranspose requires one array of records`);const e=t[0].map(t=>this.assertRecord(t,"autoTranspose"));return this.fields.map((t,i)=>e.map(t=>t[i]))}return t}let i=t;if(this.autoFlatten){if(1!==t.length||!Array.isArray(t[0]))throw new Error(`Packet "${this.tag}" autoFlatten requires one array of records`);const a=t[0],s=this.fields.length;i=new Array(a.length*s);let r=0;const n=this.quantized||void 0!==this.valueMin||void 0!==this.valueMax;for(const t of a){const a=this.assertRecord(t,"autoFlatten");for(let t=0;t<s;t++){const s=a[t];i[r++]=n?this.logicalValue(s,"send",e):s}}if(this.fields&&i.length%this.fields.length!==0)throw new Error(`Packet "${this.tag}" flat value count must be divisible by schema length ${this.fields.length}`);if(n)return i}else this.fields&&1===t.length&&null!==t[0]&&"object"==typeof t[0]&&!Array.isArray(t[0])&&(i=this.assertRecord(t[0],"schema mapping"));return this.quantized||void 0!==this.valueMin||void 0!==this.valueMax?this.logical(i,"send",e):i}clearQuantizationState(t){delete this.quantizationErrors[t]}finishReceive(t){if(this.object){if(this.autoFlatten&&this.fields){const e=t,i=e[0]?.length??0;if(e.some(t=>t.length!==i))throw new Error(`Packet "${this.tag}" autoTranspose columns have different lengths`);return Array.from({length:i},(t,i)=>{const a=this.fields.map((t,a)=>[t,e[a][i]]);return this.construct(Object.fromEntries(a))})}return this.autoFlatten?(0,a.UnFlattenData)(t):t}let e=Array.isArray(t)?t:[t];if((this.quantized||void 0!==this.valueMin||void 0!==this.valueMax)&&(e=this.logical(e,"receive")),this.autoFlatten){const t=this.fields.length;if(e.length%t!==0)throw new Error(`Packet "${this.tag}" flat value count ${e.length} is not divisible by schema length ${t}`);return Array.from({length:e.length/t},(i,a)=>this.construct(Object.fromEntries(this.fields.map((i,s)=>[i,e[a*t+s]]))))}if(this.fields){const t=this.fields.map((t,i)=>[t,e[i]]);return this.construct(Object.fromEntries(t))}return t}async listen(t,e){try{const[i,a]=await this.validate(t);if(!this.client&&!1===a)return"Invalid packet";const s=this.processReceive(i,a),r=this.finishReceive(s);if(null!=this.customValidator)if(this.dontSpread||this.fields){if(!this.customValidator(e,r))return"Didn't pass custom validator"}else if(!this.customValidator(e,...r))return"Didn't pass custom validator";return[this.isParent?{variant:"",payload:r}:r,!this.isParent&&!this.fields&&!this.dontSpread]}catch(t){return console.error("SonicWS failed to process a packet. Report reproducible codec failures at https://github.com/liwybloc/sonic-ws",t),`Error: ${String(t)}`}}serialize(){const t=(new TextEncoder).encode(JSON.stringify({schema:this.fields,quantized:this.quantized,min:this.valueMin,max:this.valueMax,group:void 0!==this.parent?{parent:this.parent,variant:this.variant??"",isParent:this.isParent}:void 0,constructor:this.constructorName,replay:this.replay||void 0})),e=[this.tag.length,...(0,r.processCharCodes)(this.tag),(0,i.compressBools)([this.dontSpread,this.async,this.object,this.autoFlatten,this.gzipCompression,this.rereference]),...(0,i.convertVarInt)(t.length),...t,this.dataBatching,this.enumData.length,...this.enumData.flatMap(t=>t.serialize())];return this.object?[...e,this.maxSize,...this.dataMax.flatMap(i.convertVarInt),...this.dataMin.flatMap(i.convertVarInt),...this.type]:[...e,...(0,i.convertVarInt)(this.dataMax),...(0,i.convertVarInt)(this.dataMin),this.type]}static readVarInts(t,e,a){const s=[];for(let r=0;r<a;r++){const[a,r]=(0,i.readVarInt)(t,e);e=a,s.push(r)}return[s,e]}static deserialize(a,n,o){const c=n,l=a[n++],d=(0,r.as8String)(a.slice(n,n+=l)),[p,m,f,y,v,g]=(0,i.decompressBools)(a[n++]),[M,S]=(0,i.readVarInt)(a,n);n=M;const x=a.slice(n,n+=S),w=JSON.parse((new TextDecoder).decode(x)),z=Array.isArray(w.schema)?w.schema:void 0,N=w.quantized&&"number"==typeof w.quantized.scale?w.quantized:void 0,k="number"==typeof w.min?w.min:void 0,P="number"==typeof w.max?w.max:void 0,b=w.group&&"string"==typeof w.group.parent?w.group:void 0,E="string"==typeof w.constructor?w.constructor:void 0,q=a[n++],O=a[n++],A=[];for(let i=0;i<O;i++){const i=a[n++],s=(0,r.as8String)(a.slice(n,n+=i)),o=a[n++],c=[];for(let t=0;t<o;t++){const t=a[n++],i=a[n++],s=(0,r.as8String)(a.slice(n,n+=t));c.push(e.TYPE_CONVERSION_MAP[i](s))}A.push((0,t.DefineEnum)(s,c))}if(f){const t=a[n++],[e,i]=this.readVarInts(a,n,t);n=i;const[r,l]=this.readVarInts(a,n,t);n=l;const f=Array.from(a.slice(n,n+=t));let g=0;const M=f.map(t=>t===s.PacketType.ENUMS?A[g++]:t),S=new u(!0,M,m,r,e,-1,p,y,!1,q,-1,v,z,void 0,void 0,void 0,b,E,!0===w.replay);return[new h(d,S,null,!1,o),n-c]}const[j,V]=(0,i.readVarInt)(a,n);n=j;const[$,T]=(0,i.readVarInt)(a,n);n=$;const D=a[n++],J=D===s.PacketType.ENUMS?A[0]:D,R=new u(!1,J,m,T,V,-1,p,y,g,q,-1,v,z,N,k,P,b,E,!0===w.replay);return[new h(d,R,null,!1,o),n-c]}static deserializeAll(t,e){const i=[];let a=0;for(;a<t.length;){const[s,r]=this.deserialize(t,a,e);i.push(s),a+=r}return i}}function l(t,i){return t instanceof e.EnumPackage?(i.push(t),s.PacketType.ENUMS):t}exports.Packet=h;class u{type;enumData=[];dataMax;dataMin;dataBatching;maxBatchSize;rateLimit;dontSpread=!1;autoFlatten=!1;async=!1;rereference=!1;gzipCompression=!1;object;fields;quantized;valueMin;valueMax;group;constructorName;replay;constructor(t,e,i,a,s,r,n,o,c,h,u,d,p,m,f,y,v,g,M=!1){this.object=t,this.async=i,this.dataMin=a,this.dataMax=s,this.rateLimit=r,this.dontSpread=n,this.autoFlatten=o,this.rereference=c,this.dataBatching=h,this.maxBatchSize=u,this.gzipCompression=d,this.fields=p?[...p]:void 0,this.quantized=m?{...m}:void 0,this.valueMin=f,this.valueMax=y,this.group=v?{...v}:void 0,this.constructorName=g,this.replay=M,this.type=t?e.map(t=>l(t,this.enumData)):l(e,this.enumData)}testObject(t){return this.object}}exports.PacketSchema=u;
|
|
@@ -0,0 +1,21 @@
|
|
|
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
|
+
export type AdapterBroadcast = {
|
|
7
|
+
origin: string;
|
|
8
|
+
room: string;
|
|
9
|
+
packetTag: string;
|
|
10
|
+
values: any[];
|
|
11
|
+
exceptConnectionId?: number;
|
|
12
|
+
};
|
|
13
|
+
/** Cross-process room membership and broadcast contract. */
|
|
14
|
+
export interface SonicWSAdapter {
|
|
15
|
+
start?(serverId: string, receiver: (message: AdapterBroadcast) => Promise<void>): void | Promise<void>;
|
|
16
|
+
publish(message: AdapterBroadcast): void | Promise<void>;
|
|
17
|
+
join(connectionId: number, room: string): void | Promise<void>;
|
|
18
|
+
leave(connectionId: number, room: string): void | Promise<void>;
|
|
19
|
+
disconnect(connectionId: number): void | Promise<void>;
|
|
20
|
+
close?(): void | Promise<void>;
|
|
21
|
+
}
|