@rfkit/json-rpc-websocket 0.2.4 → 0.2.6
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/core/client.d.ts +2 -2
- package/core/client.d.ts.map +1 -1
- package/index.d.ts +1 -1
- package/index.d.ts.map +1 -1
- package/index.js +1 -1
- package/package.json +27 -5
- package/types/socket.d.ts +20 -4
- package/types/socket.d.ts.map +1 -1
package/core/client.d.ts
CHANGED
|
@@ -9,7 +9,7 @@
|
|
|
9
9
|
* - 性能监控
|
|
10
10
|
*/
|
|
11
11
|
import type { JsonRpcResponse } from '../types/jsonrpc';
|
|
12
|
-
import type { ConnectionOptions, NotificationOptions, PerformanceStats, RequestOptions, SocketEvents, StreamController, StreamOptions } from '../types/socket';
|
|
12
|
+
import type { ConnectionOptions, NotificationOptions, PerformanceStats, RequestOptions, RawOutboundData, SocketEvents, StreamController, StreamOptions } from '../types/socket';
|
|
13
13
|
import { ConnectionState } from '../types/socket';
|
|
14
14
|
import { EventEmitter } from './event-emitter';
|
|
15
15
|
export declare class JsonRpcWebSocketClient extends EventEmitter<SocketEvents> {
|
|
@@ -90,7 +90,7 @@ export declare class JsonRpcWebSocketClient extends EventEmitter<SocketEvents> {
|
|
|
90
90
|
/**
|
|
91
91
|
* 发送原始数据(用于转发)
|
|
92
92
|
*/
|
|
93
|
-
sendRaw(data:
|
|
93
|
+
sendRaw(data: RawOutboundData): void;
|
|
94
94
|
/**
|
|
95
95
|
* 关闭连接
|
|
96
96
|
*/
|
package/core/client.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"client.d.ts","sourceRoot":"","sources":["../../src/core/client.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAIH,OAAO,KAAK,EAGV,eAAe,EAChB,MAAM,kBAAkB,CAAC;AAE1B,OAAO,KAAK,EACV,iBAAiB,EACjB,mBAAmB,EACnB,gBAAgB,EAEhB,cAAc,EACd,YAAY,EACZ,gBAAgB,EAChB,aAAa,EACd,MAAM,iBAAiB,CAAC;AACzB,OAAO,EAAE,eAAe,EAAe,MAAM,iBAAiB,CAAC;AAC/D,OAAO,EAAE,YAAY,EAAE,MAAM,iBAAiB,CAAC;
|
|
1
|
+
{"version":3,"file":"client.d.ts","sourceRoot":"","sources":["../../src/core/client.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAIH,OAAO,KAAK,EAGV,eAAe,EAChB,MAAM,kBAAkB,CAAC;AAE1B,OAAO,KAAK,EACV,iBAAiB,EACjB,mBAAmB,EACnB,gBAAgB,EAEhB,cAAc,EACd,eAAe,EACf,YAAY,EACZ,gBAAgB,EAChB,aAAa,EACd,MAAM,iBAAiB,CAAC;AACzB,OAAO,EAAE,eAAe,EAAe,MAAM,iBAAiB,CAAC;AAC/D,OAAO,EAAE,YAAY,EAAE,MAAM,iBAAiB,CAAC;AAe/C,qBAAa,sBAAuB,SAAQ,YAAY,CAAC,YAAY,CAAC;IACpE,OAAO,CAAC,EAAE,CAA0B;IACpC,OAAO,CAAC,OAAO,CAA6C;IAC5D,OAAO,CAAC,eAAe,CAA+C;IACtE,OAAO,CAAC,eAAe,CAGnB;IACJ,OAAO,CAAC,iBAAiB,CAAK;IAC9B,OAAO,CAAC,kBAAkB,CAA+B;IACzD,OAAO,CAAC,mBAAmB,CAA+B;IAC1D,OAAO,CAAC,KAAK,CAQX;IACF,OAAO,CAAC,aAAa,CAAgB;gBAEzB,OAAO,EAAE,iBAAiB;IAMtC;;OAEG;IACH,IAAI,KAAK,IAAI,eAAe,CAE3B;IAED;;OAEG;IACH,IAAI,WAAW,IAAI,OAAO,CAEzB;IAED;;OAEG;IACH,QAAQ,IAAI,QAAQ,CAAC,gBAAgB,CAAC;IAItC;;OAEG;IACH,OAAO,CAAC,OAAO;IAmBf;;OAEG;IACH,OAAO,CAAC,UAAU;IAOlB;;OAEG;IACH,OAAO,CAAC,aAAa;IAkErB;;OAEG;IACH,OAAO,CAAC,WAAW;IAiBnB;;OAEG;IACH,OAAO,CAAC,WAAW;IAKnB;;OAEG;IACH,OAAO,CAAC,iBAAiB;IA6BzB;;OAEG;IACH,OAAO,CAAC,cAAc;IAmBtB;;OAEG;IACH,OAAO,CAAC,aAAa;IAOrB;;OAEG;IACH,OAAO,CAAC,wBAAwB;IAQhC;;OAEG;IACH,OAAO,CAAC,kBAAkB;IAU1B;;OAEG;IACG,OAAO,CAAC,OAAO,GAAG,OAAO,EAAE,OAAO,GAAG,OAAO,EAChD,OAAO,EAAE,cAAc,CAAC,OAAO,CAAC,GAC/B,OAAO,CAAC,OAAO,CAAC;IAkDnB;;OAEG;IACG,MAAM,CAAC,OAAO,GAAG,OAAO,EAC5B,OAAO,EAAE,mBAAmB,CAAC,OAAO,CAAC,GACpC,OAAO,CAAC,IAAI,CAAC;IAoBhB;;OAEG;IACH,MAAM,CAAC,OAAO,GAAG,OAAO,EAAE,OAAO,GAAG,OAAO,EACzC,OAAO,EAAE,aAAa,CAAC,OAAO,CAAC,EAC/B,QAAQ,EAAE,CAAC,QAAQ,EAAE,eAAe,CAAC,OAAO,CAAC,KAAK,IAAI,GACrD,gBAAgB;IAkDnB;;OAEG;IACH,OAAO,CAAC,IAAI,EAAE,eAAe,GAAG,IAAI;IAQpC;;OAEG;IACH,KAAK,CAAC,IAAI,CAAC,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,MAAM,GAAG,IAAI;IAuB3C;;OAEG;IACH,cAAc,CAAC,GAAG,EAAE,MAAM,GAAG,IAAI;IAQjC;;OAEG;IACH,OAAO,CAAC,GAAG;CAKZ"}
|
package/index.d.ts
CHANGED
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
*/
|
|
5
5
|
export { JsonRpcWebSocketClient as default } from './core/client';
|
|
6
6
|
export { JsonRpcWebSocketClient } from './core/client';
|
|
7
|
-
export type { JsonRpcRequest, JsonRpcResponse, JsonRpcSuccess, JsonRpcError, JsonRpcNotification, JsonRpcMessage, JsonRpcErrorCode, ConnectionOptions, RequestOptions, NotificationOptions, StreamOptions, StreamController, SocketEvents, PerformanceStats, ConnectionState, MessageEventData, } from './types';
|
|
7
|
+
export type { JsonRpcRequest, JsonRpcResponse, JsonRpcSuccess, JsonRpcError, JsonRpcNotification, JsonRpcMessage, JsonRpcErrorCode, ConnectionOptions, RequestOptions, NotificationOptions, StreamOptions, StreamController, SocketEvents, PerformanceStats, ConnectionState, InboundMode, OutboundMode, RawOutboundData, MessageEventData, } from './types';
|
|
8
8
|
export { SocketEvent } from './types';
|
|
9
9
|
export { encode, decode, serialize, deserialize } from './pack';
|
|
10
10
|
export type { SerializeOptions, DeserializeOptions } from './pack/types';
|
package/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAGH,OAAO,EAAE,sBAAsB,IAAI,OAAO,EAAE,MAAM,eAAe,CAAC;AAClE,OAAO,EAAE,sBAAsB,EAAE,MAAM,eAAe,CAAC;AAGvD,YAAY,EAEV,cAAc,EACd,eAAe,EACf,cAAc,EACd,YAAY,EACZ,mBAAmB,EACnB,cAAc,EACd,gBAAgB,EAEhB,iBAAiB,EACjB,cAAc,EACd,mBAAmB,EACnB,aAAa,EACb,gBAAgB,EAChB,YAAY,EACZ,gBAAgB,EAChB,eAAe,EACf,gBAAgB,GACjB,MAAM,SAAS,CAAC;AAGjB,OAAO,EAAE,WAAW,EAAE,MAAM,SAAS,CAAC;AAGtC,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,SAAS,EAAE,WAAW,EAAE,MAAM,QAAQ,CAAC;AAChE,YAAY,EAAE,gBAAgB,EAAE,kBAAkB,EAAE,MAAM,cAAc,CAAC;AAGzE,OAAO,EAAE,YAAY,EAAE,MAAM,SAAS,CAAC"}
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAGH,OAAO,EAAE,sBAAsB,IAAI,OAAO,EAAE,MAAM,eAAe,CAAC;AAClE,OAAO,EAAE,sBAAsB,EAAE,MAAM,eAAe,CAAC;AAGvD,YAAY,EAEV,cAAc,EACd,eAAe,EACf,cAAc,EACd,YAAY,EACZ,mBAAmB,EACnB,cAAc,EACd,gBAAgB,EAEhB,iBAAiB,EACjB,cAAc,EACd,mBAAmB,EACnB,aAAa,EACb,gBAAgB,EAChB,YAAY,EACZ,gBAAgB,EAChB,eAAe,EACf,WAAW,EACX,YAAY,EACZ,eAAe,EACf,gBAAgB,GACjB,MAAM,SAAS,CAAC;AAGjB,OAAO,EAAE,WAAW,EAAE,MAAM,SAAS,CAAC;AAGtC,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,SAAS,EAAE,WAAW,EAAE,MAAM,QAAQ,CAAC;AAChE,YAAY,EAAE,gBAAgB,EAAE,kBAAkB,EAAE,MAAM,cAAc,CAAC;AAGzE,OAAO,EAAE,YAAY,EAAE,MAAM,SAAS,CAAC"}
|
package/index.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
function encodeUtf8(str){const length=str.length;let ascii=true;for(let i=0;i<length;i++)if(str.charCodeAt(i)>127){ascii=false;break}if(ascii){const bytes=new Uint8Array(length);for(let i=0;i<length;i++)bytes[i]=str.charCodeAt(i);return bytes}let bytes=new Uint8Array(2*length);let pos=0;for(let i=0;i<length;i++){let code=str.charCodeAt(i);if(pos+4>bytes.length){const newBytes=new Uint8Array(Math.ceil(1.5*bytes.length));newBytes.set(bytes);bytes=newBytes}if(code<128)bytes[pos++]=code;else if(code<2048){bytes[pos++]=192|code>>>6;bytes[pos++]=128|63&code}else if(code>=55296&&code<56320){if(i+1>=length)throw new Error("UTF-8 encode: incomplete surrogate pair");const code2=str.charCodeAt(++i);if(code2<56320||code2>57343)throw new Error(`UTF-8 encode: second surrogate character 0x${code2.toString(16)} at index ${i} out of range`);code=65536+((1023&code)<<10)+(1023&code2);bytes[pos++]=240|code>>>18;bytes[pos++]=128|code>>>12&63;bytes[pos++]=128|code>>>6&63;bytes[pos++]=128|63&code}else{bytes[pos++]=224|code>>>12;bytes[pos++]=128|code>>>6&63;bytes[pos++]=128|63&code}}return bytes.subarray(0,pos)}function decodeUtf8(bytes,start,length){const end=start+length;let ascii=true;for(let i=start;i<end;i++)if(bytes[i]>127){ascii=false;break}if(ascii)return String.fromCharCode(...bytes.subarray(start,end));let str="";let i=start;while(i<end){const byte1=bytes[i++];if(byte1<128)str+=String.fromCharCode(byte1);else if(byte1<224){if(i>=end)throw new Error("UTF-8 decode: incomplete 2-byte sequence");const byte2=bytes[i++];str+=String.fromCharCode((31&byte1)<<6|63&byte2)}else if(byte1<240){if(i+1>=end)throw new Error("UTF-8 decode: incomplete 3-byte sequence");const byte2=bytes[i++];const byte3=bytes[i++];str+=String.fromCharCode((15&byte1)<<12|(63&byte2)<<6|63&byte3)}else{if(i+2>=end)throw new Error("UTF-8 decode: incomplete 4-byte sequence");const byte2=bytes[i++];const byte3=bytes[i++];const byte4=bytes[i++];let code=(7&byte1)<<18|(63&byte2)<<12|(63&byte3)<<6|63&byte4;if(code<=65535)str+=String.fromCharCode(code);else if(code<=1114111){code-=65536;str+=String.fromCharCode(55296|code>>>10);str+=String.fromCharCode(56320|1023&code)}else throw new Error(`UTF-8 decode: code point 0x${code.toString(16)} exceeds UTF-16 reach`)}}return str}const POW32=0x100000000;function deserialize(array,options){let bytes;if(array instanceof ArrayBuffer)bytes=new Uint8Array(array);else if(array instanceof Uint8Array)bytes=array;else if("object"==typeof array&&void 0!==array.length)bytes=new Uint8Array(array);else throw new Error("Invalid argument type: Expected a byte array (Array or Uint8Array) to deserialize.");if(0===bytes.length)throw new Error("Invalid argument: The byte array to deserialize is empty.");let pos=0;if(options?.multiple){const results=[];while(pos<bytes.length)results.push(read());return results}return read();function checkBounds(needed){if(pos+needed>bytes.length)throw new Error(`Buffer overflow: trying to read ${needed} bytes at position ${pos}, but only ${bytes.length-pos} bytes available`)}function read(){checkBounds(1);const byte=bytes[pos++];if(byte>=0&&byte<=127)return byte;if(byte>=128&&byte<=143)return readMap(byte-128);if(byte>=144&&byte<=159)return readArray(byte-144);if(byte>=160&&byte<=191)return readStr(byte-160);if(byte>=224&&byte<=255)return byte-256;if(192===byte)return null;if(194===byte)return false;if(195===byte)return true;if(196===byte)return readBin(-1,1);if(197===byte)return readBin(-1,2);if(198===byte)return readBin(-1,4);if(199===byte)return readExt(-1,1);if(200===byte)return readExt(-1,2);if(201===byte)return readExt(-1,4);if(212===byte)return readExt(1);if(213===byte)return readExt(2);if(214===byte)return readExt(4);if(215===byte)return readExt(8);if(216===byte)return readExt(16);if(202===byte)return readFloat(4);if(203===byte)return readFloat(8);if(204===byte)return readUInt(1);if(205===byte)return readUInt(2);if(206===byte)return readUInt(4);if(207===byte)return readUInt(8);if(208===byte)return readInt(1);if(209===byte)return readInt(2);if(210===byte)return readInt(4);if(211===byte)return readInt(8);if(217===byte)return readStr(-1,1);if(218===byte)return readStr(-1,2);if(219===byte)return readStr(-1,4);if(220===byte)return readArray(-1,2);if(221===byte)return readArray(-1,4);if(222===byte)return readMap(-1,2);if(223===byte)return readMap(-1,4);if(193===byte)throw new Error("Invalid byte code 0xc1 found.");throw new Error(`Invalid byte value '${byte}' at index ${pos-1} in the MessagePack binary data (length ${bytes.length}): Expecting a range of 0 to 255. This is not a byte array.`)}function readInt(count){checkBounds(count);let value=0;let first=true;for(let i=0;i<count;i++)if(first){const byte=bytes[pos++];value+=127&byte;if(128&byte)value-=128;first=false}else value=256*value+bytes[pos++];return value}function readUInt(count){checkBounds(count);let value=0;for(let i=0;i<count;i++)value=256*value+bytes[pos++];return value}function readFloat(size){checkBounds(size);const view=new DataView(bytes.buffer,pos+bytes.byteOffset,size);pos+=size;if(4===size)return view.getFloat32(0,false);if(8===size)return view.getFloat64(0,false);return 0}function readBin(length,lengthSize){const finalLength=length<0?readUInt(lengthSize):length;checkBounds(finalLength);const data=bytes.subarray(pos,pos+finalLength);pos+=finalLength;return data}function readMap(length,lengthSize){const finalLength=length<0&&void 0!==lengthSize?readUInt(lengthSize):length;const data={};for(let i=0;i<finalLength;i++){const key=read();if("string"!=typeof key)throw new Error(`Invalid map key type: expected string, got ${typeof key}`);data[key]=read()}return data}function readArray(length,lengthSize){const finalLength=length<0&&void 0!==lengthSize?readUInt(lengthSize):length;const data=[];for(let i=0;i<finalLength;i++)data.push(read());return data}function readStr(length,lengthSize){const finalLength=length<0&&void 0!==lengthSize?readUInt(lengthSize):length;checkBounds(finalLength);const str=decodeUtf8(bytes,pos,finalLength);pos+=finalLength;return str}function readExt(length,lengthSize){const finalLength=length<0&&void 0!==lengthSize?readUInt(lengthSize):length;checkBounds(1+finalLength);const type=readUInt(1);const data=readBin(finalLength,0);if(255===type)return readExtDate(data);return{type,data}}function readExtDate(data){if(4===data.length){const sec=(data[0]<<24>>>0)+(data[1]<<16>>>0)+(data[2]<<8>>>0)+data[3];return new Date(1e3*sec)}if(8===data.length){const ns=(data[0]<<22>>>0)+(data[1]<<14>>>0)+(data[2]<<6>>>0)+(data[3]>>>2);const sec=(3&data[3])*POW32+(data[4]<<24>>>0)+(data[5]<<16>>>0)+(data[6]<<8>>>0)+data[7];return new Date(1e3*sec+ns/1e6)}if(12===data.length){const ns=(data[0]<<24>>>0)+(data[1]<<16>>>0)+(data[2]<<8>>>0)+data[3];pos-=8;const sec=readInt(8);return new Date(1e3*sec+ns/1e6)}throw new Error("Invalid data length for a date value.")}}const serializer_POW32=0x100000000;const MAX_SAFE_INTEGER_HIGH=0x1fffffffffffff;function serialize(data,options){if(options?.multiple&&!Array.isArray(data))throw new Error("Invalid argument type: Expected an Array to serialize multiple values.");let floatBuffer;let floatView;let buffer=new Uint8Array(256);let length=0;if(options?.multiple&&Array.isArray(data))for(const item of data)append(item);else append(data);return buffer.subarray(0,length);function append(value,isReplacement=false){const type=typeof value;switch(type){case"undefined":appendNull();break;case"boolean":appendBoolean(value);break;case"number":appendNumber(value);break;case"string":appendString(value);break;case"object":if(null===value)appendNull();else if(value instanceof Date)appendDate(value);else if(Array.isArray(value))appendArray(value);else if(value instanceof Uint8Array||value instanceof Uint8ClampedArray)appendBinArray(value);else if(value instanceof Int8Array||value instanceof Int16Array||value instanceof Uint16Array||value instanceof Int32Array||value instanceof Uint32Array||value instanceof Float32Array||value instanceof Float64Array)appendArray(Array.from(value));else appendObject(value);break;default:if(!isReplacement&&options?.invalidTypeReplacement){const replacement="function"==typeof options.invalidTypeReplacement?options.invalidTypeReplacement(value):options.invalidTypeReplacement;append(replacement,true)}else throw new Error(`Invalid argument type: The type '${type}' cannot be serialized.`)}}function appendNull(){appendByte(192)}function appendBoolean(value){appendByte(value?195:194)}function appendNumber(value){if(Number.isFinite(value)&&Math.floor(value)===value){if(value>=0&&value<=127)appendByte(value);else if(value<0&&value>=-32)appendByte(value);else if(value>0&&value<=255)appendBytes([204,value]);else if(value>=-128&&value<=127)appendBytes([208,value]);else if(value>0&&value<=65535)appendBytes([205,value>>>8,value]);else if(value>=-32768&&value<=32767)appendBytes([209,value>>>8,value]);else if(value>0&&value<=0xffffffff)appendBytes([206,value>>>24,value>>>16,value>>>8,value]);else if(value>=-0x80000000&&value<=0x7fffffff)appendBytes([210,value>>>24,value>>>16,value>>>8,value]);else if(value>0&&value<=MAX_SAFE_INTEGER_HIGH){const hi=Math.floor(value/serializer_POW32);const lo=Math.floor(value%serializer_POW32);appendBytes([211,hi>>>24,hi>>>16,hi>>>8,hi,lo>>>24,lo>>>16,lo>>>8,lo])}else if(value>=-MAX_SAFE_INTEGER_HIGH&&value<=-0x80000001){appendByte(211);appendInt64(value)}else value<0?appendBytes([211,128,0,0,0,0,0,0,0]):appendBytes([207,255,255,255,255,255,255,255,255])}else{if(!floatView){floatBuffer=new ArrayBuffer(8);floatView=new DataView(floatBuffer)}floatView.setFloat64(0,value);appendByte(203);appendBytes(new Uint8Array(floatBuffer))}}function appendString(value){const bytes=encodeUtf8(value);const len=bytes.length;if(len<=31)appendByte(160+len);else if(len<=255)appendBytes([217,len]);else len<=65535?appendBytes([218,len>>>8,len]):appendBytes([219,len>>>24,len>>>16,len>>>8,len]);appendBytes(bytes)}function appendArray(value){const len=value.length;if(len<=15)appendByte(144+len);else len<=65535?appendBytes([220,len>>>8,len]):appendBytes([221,len>>>24,len>>>16,len>>>8,len]);for(const item of value)append(item)}function appendBinArray(value){const len=value.length;if(len<=255)appendBytes([196,len]);else len<=65535?appendBytes([197,len>>>8,len]):appendBytes([198,len>>>24,len>>>16,len>>>8,len]);appendBytes(value)}function appendObject(value){let count=0;for(const key in value)if(void 0!==value[key])count++;if(count<=15)appendByte(128+count);else count<=65535?appendBytes([222,count>>>8,count]):appendBytes([223,count>>>24,count>>>16,count>>>8,count]);for(const key in value){const val=value[key];if(void 0!==val){append(key);append(val)}}}function appendDate(value){const sec=value.getTime()/1e3;if(0===value.getMilliseconds()&&sec>=0&&sec<serializer_POW32){const secInt=Math.floor(sec);appendBytes([214,255,secInt>>>24,secInt>>>16,secInt>>>8,secInt])}else if(sec>=0&&sec<4*serializer_POW32){const ns=1e6*value.getMilliseconds();const secInt=Math.floor(sec);const secHigh=Math.floor(secInt/serializer_POW32);appendBytes([215,255,ns>>>22,ns>>>14,ns>>>6,ns<<2>>>0|secHigh,secInt>>>24,secInt>>>16,secInt>>>8,secInt])}else{const ns=1e6*value.getMilliseconds();appendBytes([199,12,255,ns>>>24,ns>>>16,ns>>>8,ns]);appendInt64(sec)}}function appendByte(byte){if(buffer.length<length+1)expandBuffer(length+1);buffer[length++]=byte}function appendBytes(bytes){const needed=length+bytes.length;if(buffer.length<needed)expandBuffer(needed);buffer.set(bytes,length);length+=bytes.length}function expandBuffer(minSize){let newSize=Math.ceil(1.5*buffer.length);while(newSize<minSize)newSize=Math.ceil(1.5*newSize);const newBuffer=new Uint8Array(newSize);newBuffer.set(buffer);buffer=newBuffer}function appendInt64(num){let hi;let lo;if(num>=0){hi=Math.floor(num/serializer_POW32);lo=Math.floor(num%serializer_POW32)}else{const absValue=Math.abs(num+1);hi=~Math.floor(absValue/serializer_POW32);lo=~Math.floor(absValue%serializer_POW32)}appendBytes([hi>>>24,hi>>>16,hi>>>8,hi,lo>>>24,lo>>>16,lo>>>8,lo])}}const pack_serialize=serialize;const pack_deserialize=deserialize;const encode=serialize;const decode=deserialize;const generateHexSegment=()=>((1+Math.random())*65536|0).toString(16).substring(1);const generateUUID=()=>[generateHexSegment()+generateHexSegment(),generateHexSegment(),generateHexSegment(),generateHexSegment(),generateHexSegment()+generateHexSegment()+generateHexSegment()].join("-");const generateId=(length=8)=>{let result="";const characters="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";const charactersLength=characters.length;for(let i=0;i<length;i++)result+=characters.charAt(Math.floor(Math.random()*charactersLength));return result};var jsonrpc_JsonRpcErrorCode=/*#__PURE__*/function(JsonRpcErrorCode){JsonRpcErrorCode[JsonRpcErrorCode["ParseError"]=-32700]="ParseError";JsonRpcErrorCode[JsonRpcErrorCode["InvalidRequest"]=-32600]="InvalidRequest";JsonRpcErrorCode[JsonRpcErrorCode["MethodNotFound"]=-32601]="MethodNotFound";JsonRpcErrorCode[JsonRpcErrorCode["InvalidParams"]=-32602]="InvalidParams";JsonRpcErrorCode[JsonRpcErrorCode["InternalError"]=-32603]="InternalError";JsonRpcErrorCode[JsonRpcErrorCode["ServerError"]=-32e3]="ServerError";JsonRpcErrorCode[JsonRpcErrorCode["Timeout"]=-32001]="Timeout";JsonRpcErrorCode[JsonRpcErrorCode["ConnectionClosed"]=-32002]="ConnectionClosed";return JsonRpcErrorCode}({});function createErrorResponse(id,code,message,data){return{jsonrpc:"2.0",error:{code,message,data},id}}function createSuccessResponse(id,result){return{jsonrpc:"2.0",result,id}}function isJsonRpcError(response){return"error"in response}function isJsonRpcSuccess(response){return"result"in response}function isJsonRpcNotification(message){return"method"in message&&!("id"in message)}var socket_ConnectionState=/*#__PURE__*/function(ConnectionState){ConnectionState[ConnectionState["Connecting"]=0]="Connecting";ConnectionState[ConnectionState["Open"]=1]="Open";ConnectionState[ConnectionState["Closing"]=2]="Closing";ConnectionState[ConnectionState["Closed"]=3]="Closed";return ConnectionState}({});const SocketEvent={Open:"open",Close:"close",Error:"error",Message:"message",Reconnecting:"reconnecting",Reconnected:"reconnected",ReconnectFailed:"reconnect_failed"};class EventEmitter{listeners=new Map;on(event,listener){if(!this.listeners.has(event))this.listeners.set(event,new Set);this.listeners.get(event)?.add(listener);return()=>this.off(event,listener)}once(event,listener){const wrapper=data=>{this.off(event,wrapper);listener(data)};return this.on(event,wrapper)}off(event,listener){const eventListeners=this.listeners.get(event);if(eventListeners){eventListeners.delete(listener);if(0===eventListeners.size)this.listeners.delete(event)}}emit(event,data){const eventListeners=this.listeners.get(event);if(eventListeners)for(const listener of eventListeners)try{listener(data)}catch(error){console.error(`Error in event listener for "${String(event)}":`,error)}}removeAllListeners(event){if(event)this.listeners.delete(event);else this.listeners.clear()}listenerCount(event){return this.listeners.get(event)?.size??0}}const DEFAULT_OPTIONS={autoReconnect:true,reconnectInterval:3e3,maxReconnectAttempts:5,defaultTimeout:15e3,heartbeatInterval:0,heartbeatMethod:"ping",debug:false};class JsonRpcWebSocketClient extends EventEmitter{ws=null;options;pendingRequests=new Map;streamCallbacks=new Map;reconnectAttempts=0;reconnectTimeoutId=null;heartbeatIntervalId=null;stats={requestsSent:0,responsesReceived:0,timeouts:0,errors:0,averageResponseTime:0,pendingRequests:0,reconnectCount:0};responseTimes=[];constructor(options){super();this.options={...DEFAULT_OPTIONS,...options};this.connect()}get state(){return this.ws?.readyState??socket_ConnectionState.Closed}get isConnected(){return this.state===socket_ConnectionState.Open}getStats(){return{...this.stats,pendingRequests:this.pendingRequests.size}}connect(){if(this.ws&&this.ws.readyState===socket_ConnectionState.Connecting)return;try{this.ws=new WebSocket(this.options.url,this.options.protocols);this.ws.binaryType="arraybuffer";this.ws.onopen=this.handleOpen.bind(this);this.ws.onmessage=this.handleMessage.bind(this);this.ws.onclose=this.handleClose.bind(this);this.ws.onerror=this.handleError.bind(this)}catch(error){this.log("Connection error:",error);this.scheduleReconnect()}}handleOpen(event){this.log("Connection opened");this.reconnectAttempts=0;this.startHeartbeat();this.emit(SocketEvent.Open,event)}handleMessage(event){try{const rawData=event.data;const response=decode(new Uint8Array(rawData));this.log("Received:",response);this.stats.responsesReceived++;if("error"in response)this.stats.errors++;if(null!==response.id){const streamCallback=this.streamCallbacks.get(response.id);if(streamCallback){streamCallback(response);this.emit(SocketEvent.Message,{data:response,rawData});return}const metadata=this.pendingRequests.get(response.id);if(metadata){clearTimeout(metadata.timeoutId);this.pendingRequests.delete(response.id);const responseTime=Date.now()-metadata.timestamp;this.updateResponseTime(responseTime);if("error"in response)metadata.reject(new Error(`${response.error.message} (${response.error.code})`));else metadata.resolve(response.result)}}this.emit(SocketEvent.Message,{data:response,rawData})}catch(error){this.log("Failed to decode message:",error)}}handleClose(event){this.log("Connection closed:",event.code,event.reason);this.stopHeartbeat();this.emit(SocketEvent.Close,event);this.rejectAllPendingRequests(new Error("Connection closed"),jsonrpc_JsonRpcErrorCode.ConnectionClosed);if(this.options.autoReconnect)this.scheduleReconnect()}handleError(event){this.log("Connection error:",event);this.emit(SocketEvent.Error,event)}scheduleReconnect(){if(this.reconnectTimeoutId)return;if(this.reconnectAttempts>=this.options.maxReconnectAttempts){this.log("Max reconnect attempts reached");this.emit(SocketEvent.ReconnectFailed,void 0);return}this.reconnectAttempts++;this.stats.reconnectCount++;this.log(`Reconnecting in ${this.options.reconnectInterval}ms (attempt ${this.reconnectAttempts}/${this.options.maxReconnectAttempts})`);this.emit(SocketEvent.Reconnecting,{attempt:this.reconnectAttempts,maxAttempts:this.options.maxReconnectAttempts});this.reconnectTimeoutId=setTimeout(()=>{this.reconnectTimeoutId=null;this.connect()},this.options.reconnectInterval)}startHeartbeat(){if(this.options.heartbeatInterval<=0||null!==this.heartbeatIntervalId)return;this.heartbeatIntervalId=setInterval(()=>{if(this.isConnected)this.notify({method:this.options.heartbeatMethod}).catch(error=>{this.log("Heartbeat failed:",error)})},this.options.heartbeatInterval)}stopHeartbeat(){if(this.heartbeatIntervalId){clearInterval(this.heartbeatIntervalId);this.heartbeatIntervalId=null}}rejectAllPendingRequests(error,code){for(const[id,metadata]of this.pendingRequests){clearTimeout(metadata.timeoutId);metadata.reject(error)}this.pendingRequests.clear()}updateResponseTime(time){this.responseTimes.push(time);if(this.responseTimes.length>100)this.responseTimes.shift();this.stats.averageResponseTime=this.responseTimes.reduce((sum,t)=>sum+t,0)/this.responseTimes.length}async request(options){if(!this.isConnected)throw new Error("WebSocket is not connected");const id=options.id??generateUUID();const request={jsonrpc:"2.0",method:options.method,params:options.params,id};return new Promise((resolve,reject)=>{const timeout=options.timeout??this.options.defaultTimeout;const timeoutId=setTimeout(()=>{this.pendingRequests.delete(id);this.stats.timeouts++;reject(new Error(`Request timeout after ${timeout}ms`))},timeout);this.pendingRequests.set(id,{id,timestamp:Date.now(),timeoutId,resolve:resolve,reject});try{const encoded=encode(request);this.ws?.send(encoded);this.stats.requestsSent++;this.log("Sent request:",request)}catch(error){clearTimeout(timeoutId);this.pendingRequests.delete(id);reject(error)}})}async notify(options){if(!this.isConnected)throw new Error("WebSocket is not connected");const notification={jsonrpc:"2.0",method:options.method,params:options.params};const encoded=encode(notification);this.ws?.send(encoded);this.log("Sent notification:",notification)}stream(options,callback){if(!this.isConnected)throw new Error("WebSocket is not connected");const id=options.id??generateUUID();const request={jsonrpc:"2.0",method:options.method,params:options.params,id};let closed=false;this.streamCallbacks.set(id,callback);try{const encoded=encode(request);this.ws?.send(encoded);this.stats.requestsSent++;this.log("Sent stream request:",request)}catch(error){this.streamCallbacks.delete(id);throw error}return{id,close:()=>{if(!closed){closed=true;this.streamCallbacks.delete(id);this.log("Stream closed:",id)}},get closed(){return closed}}}sendRaw(data){if(!this.isConnected)throw new Error("WebSocket is not connected");this.ws?.send(data);this.log("Sent raw data:",data.byteLength,"bytes")}close(code,reason){this.options.autoReconnect=false;if(this.reconnectTimeoutId){clearTimeout(this.reconnectTimeoutId);this.reconnectTimeoutId=null}this.stopHeartbeat();if(this.ws){this.ws.close(code,reason);this.ws=null}this.rejectAllPendingRequests(new Error("Connection closed by client"),jsonrpc_JsonRpcErrorCode.ConnectionClosed);this.removeAllListeners()}reconnectToUrl(url){this.close();this.options.url=url;this.options.autoReconnect=true;this.reconnectAttempts=0;this.connect()}log(...args){if(this.options.debug)console.log("[JsonRpcWebSocket]",...args)}}export{JsonRpcWebSocketClient,SocketEvent,decode,JsonRpcWebSocketClient as default,pack_deserialize as deserialize,encode,generateUUID,pack_serialize as serialize};
|
|
1
|
+
function encodeUtf8(str){const length=str.length;let ascii=true;for(let i=0;i<length;i++)if(str.charCodeAt(i)>127){ascii=false;break}if(ascii){const bytes=new Uint8Array(length);for(let i=0;i<length;i++)bytes[i]=str.charCodeAt(i);return bytes}let bytes=new Uint8Array(2*length);let pos=0;for(let i=0;i<length;i++){let code=str.charCodeAt(i);if(pos+4>bytes.length){const newBytes=new Uint8Array(Math.ceil(1.5*bytes.length));newBytes.set(bytes);bytes=newBytes}if(code<128)bytes[pos++]=code;else if(code<2048){bytes[pos++]=192|code>>>6;bytes[pos++]=128|63&code}else if(code>=55296&&code<56320){if(i+1>=length)throw new Error("UTF-8 encode: incomplete surrogate pair");const code2=str.charCodeAt(++i);if(code2<56320||code2>57343)throw new Error(`UTF-8 encode: second surrogate character 0x${code2.toString(16)} at index ${i} out of range`);code=65536+((1023&code)<<10)+(1023&code2);bytes[pos++]=240|code>>>18;bytes[pos++]=128|code>>>12&63;bytes[pos++]=128|code>>>6&63;bytes[pos++]=128|63&code}else{bytes[pos++]=224|code>>>12;bytes[pos++]=128|code>>>6&63;bytes[pos++]=128|63&code}}return bytes.subarray(0,pos)}function decodeUtf8(bytes,start,length){const end=start+length;let ascii=true;for(let i=start;i<end;i++)if(bytes[i]>127){ascii=false;break}if(ascii)return String.fromCharCode(...bytes.subarray(start,end));let str="";let i=start;while(i<end){const byte1=bytes[i++];if(byte1<128)str+=String.fromCharCode(byte1);else if(byte1<224){if(i>=end)throw new Error("UTF-8 decode: incomplete 2-byte sequence");const byte2=bytes[i++];str+=String.fromCharCode((31&byte1)<<6|63&byte2)}else if(byte1<240){if(i+1>=end)throw new Error("UTF-8 decode: incomplete 3-byte sequence");const byte2=bytes[i++];const byte3=bytes[i++];str+=String.fromCharCode((15&byte1)<<12|(63&byte2)<<6|63&byte3)}else{if(i+2>=end)throw new Error("UTF-8 decode: incomplete 4-byte sequence");const byte2=bytes[i++];const byte3=bytes[i++];const byte4=bytes[i++];let code=(7&byte1)<<18|(63&byte2)<<12|(63&byte3)<<6|63&byte4;if(code<=65535)str+=String.fromCharCode(code);else if(code<=1114111){code-=65536;str+=String.fromCharCode(55296|code>>>10);str+=String.fromCharCode(56320|1023&code)}else throw new Error(`UTF-8 decode: code point 0x${code.toString(16)} exceeds UTF-16 reach`)}}return str}const POW32=0x100000000;function deserialize(array,options){let bytes;if(array instanceof ArrayBuffer)bytes=new Uint8Array(array);else if(array instanceof Uint8Array)bytes=array;else if("object"==typeof array&&void 0!==array.length)bytes=new Uint8Array(array);else throw new Error("Invalid argument type: Expected a byte array (Array or Uint8Array) to deserialize.");if(0===bytes.length)throw new Error("Invalid argument: The byte array to deserialize is empty.");let pos=0;if(options?.multiple){const results=[];while(pos<bytes.length)results.push(read());return results}return read();function checkBounds(needed){if(pos+needed>bytes.length)throw new Error(`Buffer overflow: trying to read ${needed} bytes at position ${pos}, but only ${bytes.length-pos} bytes available`)}function read(){checkBounds(1);const byte=bytes[pos++];if(byte>=0&&byte<=127)return byte;if(byte>=128&&byte<=143)return readMap(byte-128);if(byte>=144&&byte<=159)return readArray(byte-144);if(byte>=160&&byte<=191)return readStr(byte-160);if(byte>=224&&byte<=255)return byte-256;if(192===byte)return null;if(194===byte)return false;if(195===byte)return true;if(196===byte)return readBin(-1,1);if(197===byte)return readBin(-1,2);if(198===byte)return readBin(-1,4);if(199===byte)return readExt(-1,1);if(200===byte)return readExt(-1,2);if(201===byte)return readExt(-1,4);if(212===byte)return readExt(1);if(213===byte)return readExt(2);if(214===byte)return readExt(4);if(215===byte)return readExt(8);if(216===byte)return readExt(16);if(202===byte)return readFloat(4);if(203===byte)return readFloat(8);if(204===byte)return readUInt(1);if(205===byte)return readUInt(2);if(206===byte)return readUInt(4);if(207===byte)return readUInt(8);if(208===byte)return readInt(1);if(209===byte)return readInt(2);if(210===byte)return readInt(4);if(211===byte)return readInt(8);if(217===byte)return readStr(-1,1);if(218===byte)return readStr(-1,2);if(219===byte)return readStr(-1,4);if(220===byte)return readArray(-1,2);if(221===byte)return readArray(-1,4);if(222===byte)return readMap(-1,2);if(223===byte)return readMap(-1,4);if(193===byte)throw new Error("Invalid byte code 0xc1 found.");throw new Error(`Invalid byte value '${byte}' at index ${pos-1} in the MessagePack binary data (length ${bytes.length}): Expecting a range of 0 to 255. This is not a byte array.`)}function readInt(count){checkBounds(count);let value=0;let first=true;for(let i=0;i<count;i++)if(first){const byte=bytes[pos++];value+=127&byte;if(128&byte)value-=128;first=false}else value=256*value+bytes[pos++];return value}function readUInt(count){checkBounds(count);let value=0;for(let i=0;i<count;i++)value=256*value+bytes[pos++];return value}function readFloat(size){checkBounds(size);const view=new DataView(bytes.buffer,pos+bytes.byteOffset,size);pos+=size;if(4===size)return view.getFloat32(0,false);if(8===size)return view.getFloat64(0,false);return 0}function readBin(length,lengthSize){const finalLength=length<0?readUInt(lengthSize):length;checkBounds(finalLength);const data=bytes.subarray(pos,pos+finalLength);pos+=finalLength;return data}function readMap(length,lengthSize){const finalLength=length<0&&void 0!==lengthSize?readUInt(lengthSize):length;const data={};for(let i=0;i<finalLength;i++){const key=read();if("string"!=typeof key)throw new Error(`Invalid map key type: expected string, got ${typeof key}`);data[key]=read()}return data}function readArray(length,lengthSize){const finalLength=length<0&&void 0!==lengthSize?readUInt(lengthSize):length;const data=[];for(let i=0;i<finalLength;i++)data.push(read());return data}function readStr(length,lengthSize){const finalLength=length<0&&void 0!==lengthSize?readUInt(lengthSize):length;checkBounds(finalLength);const str=decodeUtf8(bytes,pos,finalLength);pos+=finalLength;return str}function readExt(length,lengthSize){const finalLength=length<0&&void 0!==lengthSize?readUInt(lengthSize):length;checkBounds(1+finalLength);const type=readUInt(1);const data=readBin(finalLength,0);if(255===type)return readExtDate(data);return{type,data}}function readExtDate(data){if(4===data.length){const sec=(data[0]<<24>>>0)+(data[1]<<16>>>0)+(data[2]<<8>>>0)+data[3];return new Date(1e3*sec)}if(8===data.length){const ns=(data[0]<<22>>>0)+(data[1]<<14>>>0)+(data[2]<<6>>>0)+(data[3]>>>2);const sec=(3&data[3])*POW32+(data[4]<<24>>>0)+(data[5]<<16>>>0)+(data[6]<<8>>>0)+data[7];return new Date(1e3*sec+ns/1e6)}if(12===data.length){const ns=(data[0]<<24>>>0)+(data[1]<<16>>>0)+(data[2]<<8>>>0)+data[3];pos-=8;const sec=readInt(8);return new Date(1e3*sec+ns/1e6)}throw new Error("Invalid data length for a date value.")}}const serializer_POW32=0x100000000;const MAX_SAFE_INTEGER_HIGH=0x1fffffffffffff;function serialize(data,options){if(options?.multiple&&!Array.isArray(data))throw new Error("Invalid argument type: Expected an Array to serialize multiple values.");let floatBuffer;let floatView;let buffer=new Uint8Array(256);let length=0;if(options?.multiple&&Array.isArray(data))for(const item of data)append(item);else append(data);return buffer.subarray(0,length);function append(value,isReplacement=false){const type=typeof value;switch(type){case"undefined":appendNull();break;case"boolean":appendBoolean(value);break;case"number":appendNumber(value);break;case"string":appendString(value);break;case"object":if(null===value)appendNull();else if(value instanceof Date)appendDate(value);else if(Array.isArray(value))appendArray(value);else if(value instanceof Uint8Array||value instanceof Uint8ClampedArray)appendBinArray(value);else if(value instanceof Int8Array||value instanceof Int16Array||value instanceof Uint16Array||value instanceof Int32Array||value instanceof Uint32Array||value instanceof Float32Array||value instanceof Float64Array)appendArray(Array.from(value));else appendObject(value);break;default:if(!isReplacement&&options?.invalidTypeReplacement){const replacement="function"==typeof options.invalidTypeReplacement?options.invalidTypeReplacement(value):options.invalidTypeReplacement;append(replacement,true)}else throw new Error(`Invalid argument type: The type '${type}' cannot be serialized.`)}}function appendNull(){appendByte(192)}function appendBoolean(value){appendByte(value?195:194)}function appendNumber(value){if(Number.isFinite(value)&&Math.floor(value)===value){if(value>=0&&value<=127)appendByte(value);else if(value<0&&value>=-32)appendByte(value);else if(value>0&&value<=255)appendBytes([204,value]);else if(value>=-128&&value<=127)appendBytes([208,value]);else if(value>0&&value<=65535)appendBytes([205,value>>>8,value]);else if(value>=-32768&&value<=32767)appendBytes([209,value>>>8,value]);else if(value>0&&value<=0xffffffff)appendBytes([206,value>>>24,value>>>16,value>>>8,value]);else if(value>=-0x80000000&&value<=0x7fffffff)appendBytes([210,value>>>24,value>>>16,value>>>8,value]);else if(value>0&&value<=MAX_SAFE_INTEGER_HIGH){const hi=Math.floor(value/serializer_POW32);const lo=Math.floor(value%serializer_POW32);appendBytes([211,hi>>>24,hi>>>16,hi>>>8,hi,lo>>>24,lo>>>16,lo>>>8,lo])}else if(value>=-MAX_SAFE_INTEGER_HIGH&&value<=-0x80000001){appendByte(211);appendInt64(value)}else value<0?appendBytes([211,128,0,0,0,0,0,0,0]):appendBytes([207,255,255,255,255,255,255,255,255])}else{if(!floatView){floatBuffer=new ArrayBuffer(8);floatView=new DataView(floatBuffer)}floatView.setFloat64(0,value);appendByte(203);appendBytes(new Uint8Array(floatBuffer))}}function appendString(value){const bytes=encodeUtf8(value);const len=bytes.length;if(len<=31)appendByte(160+len);else if(len<=255)appendBytes([217,len]);else len<=65535?appendBytes([218,len>>>8,len]):appendBytes([219,len>>>24,len>>>16,len>>>8,len]);appendBytes(bytes)}function appendArray(value){const len=value.length;if(len<=15)appendByte(144+len);else len<=65535?appendBytes([220,len>>>8,len]):appendBytes([221,len>>>24,len>>>16,len>>>8,len]);for(const item of value)append(item)}function appendBinArray(value){const len=value.length;if(len<=255)appendBytes([196,len]);else len<=65535?appendBytes([197,len>>>8,len]):appendBytes([198,len>>>24,len>>>16,len>>>8,len]);appendBytes(value)}function appendObject(value){let count=0;for(const key in value)if(void 0!==value[key])count++;if(count<=15)appendByte(128+count);else count<=65535?appendBytes([222,count>>>8,count]):appendBytes([223,count>>>24,count>>>16,count>>>8,count]);for(const key in value){const val=value[key];if(void 0!==val){append(key);append(val)}}}function appendDate(value){const sec=value.getTime()/1e3;if(0===value.getMilliseconds()&&sec>=0&&sec<serializer_POW32){const secInt=Math.floor(sec);appendBytes([214,255,secInt>>>24,secInt>>>16,secInt>>>8,secInt])}else if(sec>=0&&sec<4*serializer_POW32){const ns=1e6*value.getMilliseconds();const secInt=Math.floor(sec);const secHigh=Math.floor(secInt/serializer_POW32);appendBytes([215,255,ns>>>22,ns>>>14,ns>>>6,ns<<2>>>0|secHigh,secInt>>>24,secInt>>>16,secInt>>>8,secInt])}else{const ns=1e6*value.getMilliseconds();appendBytes([199,12,255,ns>>>24,ns>>>16,ns>>>8,ns]);appendInt64(sec)}}function appendByte(byte){if(buffer.length<length+1)expandBuffer(length+1);buffer[length++]=byte}function appendBytes(bytes){const needed=length+bytes.length;if(buffer.length<needed)expandBuffer(needed);buffer.set(bytes,length);length+=bytes.length}function expandBuffer(minSize){let newSize=Math.ceil(1.5*buffer.length);while(newSize<minSize)newSize=Math.ceil(1.5*newSize);const newBuffer=new Uint8Array(newSize);newBuffer.set(buffer);buffer=newBuffer}function appendInt64(num){let hi;let lo;if(num>=0){hi=Math.floor(num/serializer_POW32);lo=Math.floor(num%serializer_POW32)}else{const absValue=Math.abs(num+1);hi=~Math.floor(absValue/serializer_POW32);lo=~Math.floor(absValue%serializer_POW32)}appendBytes([hi>>>24,hi>>>16,hi>>>8,hi,lo>>>24,lo>>>16,lo>>>8,lo])}}const pack_serialize=serialize;const pack_deserialize=deserialize;const encode=serialize;const decode=deserialize;const generateHexSegment=()=>((1+Math.random())*65536|0).toString(16).substring(1);const generateUUID=()=>[generateHexSegment()+generateHexSegment(),generateHexSegment(),generateHexSegment(),generateHexSegment(),generateHexSegment()+generateHexSegment()+generateHexSegment()].join("-");const generateId=(length=8)=>{let result="";const characters="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";const charactersLength=characters.length;for(let i=0;i<length;i++)result+=characters.charAt(Math.floor(Math.random()*charactersLength));return result};var jsonrpc_JsonRpcErrorCode=/*#__PURE__*/function(JsonRpcErrorCode){JsonRpcErrorCode[JsonRpcErrorCode["ParseError"]=-32700]="ParseError";JsonRpcErrorCode[JsonRpcErrorCode["InvalidRequest"]=-32600]="InvalidRequest";JsonRpcErrorCode[JsonRpcErrorCode["MethodNotFound"]=-32601]="MethodNotFound";JsonRpcErrorCode[JsonRpcErrorCode["InvalidParams"]=-32602]="InvalidParams";JsonRpcErrorCode[JsonRpcErrorCode["InternalError"]=-32603]="InternalError";JsonRpcErrorCode[JsonRpcErrorCode["ServerError"]=-32e3]="ServerError";JsonRpcErrorCode[JsonRpcErrorCode["Timeout"]=-32001]="Timeout";JsonRpcErrorCode[JsonRpcErrorCode["ConnectionClosed"]=-32002]="ConnectionClosed";return JsonRpcErrorCode}({});function createErrorResponse(id,code,message,data){return{jsonrpc:"2.0",error:{code,message,data},id}}function createSuccessResponse(id,result){return{jsonrpc:"2.0",result,id}}function isJsonRpcError(response){return"error"in response}function isJsonRpcSuccess(response){return"result"in response}function isJsonRpcNotification(message){return"method"in message&&!("id"in message)}var socket_ConnectionState=/*#__PURE__*/function(ConnectionState){ConnectionState[ConnectionState["Connecting"]=0]="Connecting";ConnectionState[ConnectionState["Open"]=1]="Open";ConnectionState[ConnectionState["Closing"]=2]="Closing";ConnectionState[ConnectionState["Closed"]=3]="Closed";return ConnectionState}({});const SocketEvent={Open:"open",Close:"close",Error:"error",Message:"message",Reconnecting:"reconnecting",Reconnected:"reconnected",ReconnectFailed:"reconnect_failed"};class EventEmitter{listeners=new Map;on(event,listener){if(!this.listeners.has(event))this.listeners.set(event,new Set);this.listeners.get(event)?.add(listener);return()=>this.off(event,listener)}once(event,listener){const wrapper=data=>{this.off(event,wrapper);listener(data)};return this.on(event,wrapper)}off(event,listener){const eventListeners=this.listeners.get(event);if(eventListeners){eventListeners.delete(listener);if(0===eventListeners.size)this.listeners.delete(event)}}emit(event,data){const eventListeners=this.listeners.get(event);if(eventListeners)for(const listener of eventListeners)try{listener(data)}catch(error){console.error(`Error in event listener for "${String(event)}":`,error)}}removeAllListeners(event){if(event)this.listeners.delete(event);else this.listeners.clear()}listenerCount(event){return this.listeners.get(event)?.size??0}}const DEFAULT_OPTIONS={autoReconnect:true,reconnectInterval:3e3,maxReconnectAttempts:5,defaultTimeout:15e3,heartbeatInterval:0,heartbeatMethod:"ping",debug:false,inboundMode:"messagepack",outboundMode:"messagepack"};class JsonRpcWebSocketClient extends EventEmitter{ws=null;options;pendingRequests=new Map;streamCallbacks=new Map;reconnectAttempts=0;reconnectTimeoutId=null;heartbeatIntervalId=null;stats={requestsSent:0,responsesReceived:0,timeouts:0,errors:0,averageResponseTime:0,pendingRequests:0,reconnectCount:0};responseTimes=[];constructor(options){super();this.options={...DEFAULT_OPTIONS,...options};this.connect()}get state(){return this.ws?.readyState??socket_ConnectionState.Closed}get isConnected(){return this.state===socket_ConnectionState.Open}getStats(){return{...this.stats,pendingRequests:this.pendingRequests.size}}connect(){if(this.ws&&this.ws.readyState===socket_ConnectionState.Connecting)return;try{this.ws=new WebSocket(this.options.url,this.options.protocols);this.ws.binaryType="arraybuffer";this.ws.onopen=this.handleOpen.bind(this);this.ws.onmessage=this.handleMessage.bind(this);this.ws.onclose=this.handleClose.bind(this);this.ws.onerror=this.handleError.bind(this)}catch(error){this.log("Connection error:",error);this.scheduleReconnect()}}handleOpen(event){this.log("Connection opened");this.reconnectAttempts=0;this.startHeartbeat();this.emit(SocketEvent.Open,event)}handleMessage(event){try{const rawData=event.data;if("raw"===this.options.inboundMode){this.log("Received raw message:",rawData);this.stats.responsesReceived++;this.emit(SocketEvent.Message,{decoded:false,rawData});return}const response=decode(new Uint8Array(rawData));this.log("Received:",response);this.stats.responsesReceived++;if("error"in response)this.stats.errors++;if(null!==response.id){const streamCallback=this.streamCallbacks.get(response.id);if(streamCallback){streamCallback(response);this.emit(SocketEvent.Message,{decoded:true,data:response,rawData});return}const metadata=this.pendingRequests.get(response.id);if(metadata){clearTimeout(metadata.timeoutId);this.pendingRequests.delete(response.id);const responseTime=Date.now()-metadata.timestamp;this.updateResponseTime(responseTime);if("error"in response)metadata.reject(new Error(`${response.error.message} (${response.error.code})`));else metadata.resolve(response.result)}}this.emit(SocketEvent.Message,{decoded:true,data:response,rawData})}catch(error){this.log("Failed to decode message:",error)}}handleClose(event){this.log("Connection closed:",event.code,event.reason);this.stopHeartbeat();this.emit(SocketEvent.Close,event);this.rejectAllPendingRequests(new Error("Connection closed"),jsonrpc_JsonRpcErrorCode.ConnectionClosed);if(this.options.autoReconnect)this.scheduleReconnect()}handleError(event){this.log("Connection error:",event);this.emit(SocketEvent.Error,event)}scheduleReconnect(){if(this.reconnectTimeoutId)return;if(this.reconnectAttempts>=this.options.maxReconnectAttempts){this.log("Max reconnect attempts reached");this.emit(SocketEvent.ReconnectFailed,void 0);return}this.reconnectAttempts++;this.stats.reconnectCount++;this.log(`Reconnecting in ${this.options.reconnectInterval}ms (attempt ${this.reconnectAttempts}/${this.options.maxReconnectAttempts})`);this.emit(SocketEvent.Reconnecting,{attempt:this.reconnectAttempts,maxAttempts:this.options.maxReconnectAttempts});this.reconnectTimeoutId=setTimeout(()=>{this.reconnectTimeoutId=null;this.connect()},this.options.reconnectInterval)}startHeartbeat(){if(this.options.heartbeatInterval<=0||null!==this.heartbeatIntervalId)return;this.heartbeatIntervalId=setInterval(()=>{if(this.isConnected)this.notify({method:this.options.heartbeatMethod}).catch(error=>{this.log("Heartbeat failed:",error)})},this.options.heartbeatInterval)}stopHeartbeat(){if(this.heartbeatIntervalId){clearInterval(this.heartbeatIntervalId);this.heartbeatIntervalId=null}}rejectAllPendingRequests(error,code){for(const[id,metadata]of this.pendingRequests){clearTimeout(metadata.timeoutId);metadata.reject(error)}this.pendingRequests.clear()}updateResponseTime(time){this.responseTimes.push(time);if(this.responseTimes.length>100)this.responseTimes.shift();this.stats.averageResponseTime=this.responseTimes.reduce((sum,t)=>sum+t,0)/this.responseTimes.length}async request(options){if(!this.isConnected)throw new Error("WebSocket is not connected");if("raw"===this.options.inboundMode)throw new Error("Inbound raw mode cannot resolve JSON-RPC responses.");if("raw"===this.options.outboundMode)throw new Error("Outbound raw mode cannot send JSON-RPC requests.");const id=options.id??generateUUID();const request={jsonrpc:"2.0",method:options.method,params:options.params,id};return new Promise((resolve,reject)=>{const timeout=options.timeout??this.options.defaultTimeout;const timeoutId=setTimeout(()=>{this.pendingRequests.delete(id);this.stats.timeouts++;reject(new Error(`Request timeout after ${timeout}ms`))},timeout);this.pendingRequests.set(id,{id,timestamp:Date.now(),timeoutId,resolve:resolve,reject});try{const encoded=encode(request);this.ws?.send(encoded);this.stats.requestsSent++;this.log("Sent request:",request)}catch(error){clearTimeout(timeoutId);this.pendingRequests.delete(id);reject(error)}})}async notify(options){if(!this.isConnected)throw new Error("WebSocket is not connected");if("raw"===this.options.outboundMode)throw new Error("Outbound raw mode cannot send JSON-RPC notifications.");const notification={jsonrpc:"2.0",method:options.method,params:options.params};const encoded=encode(notification);this.ws?.send(encoded);this.log("Sent notification:",notification)}stream(options,callback){if(!this.isConnected)throw new Error("WebSocket is not connected");if("raw"===this.options.inboundMode)throw new Error("Inbound raw mode cannot resolve JSON-RPC responses.");if("raw"===this.options.outboundMode)throw new Error("Outbound raw mode cannot send JSON-RPC stream requests.");const id=options.id??generateUUID();const request={jsonrpc:"2.0",method:options.method,params:options.params,id};let closed=false;this.streamCallbacks.set(id,callback);try{const encoded=encode(request);this.ws?.send(encoded);this.stats.requestsSent++;this.log("Sent stream request:",request)}catch(error){this.streamCallbacks.delete(id);throw error}return{id,close:()=>{if(!closed){closed=true;this.streamCallbacks.delete(id);this.log("Stream closed:",id)}},get closed(){return closed}}}sendRaw(data){if(!this.isConnected)throw new Error("WebSocket is not connected");this.ws?.send(data);this.log("Sent raw data:",data)}close(code,reason){this.options.autoReconnect=false;if(this.reconnectTimeoutId){clearTimeout(this.reconnectTimeoutId);this.reconnectTimeoutId=null}this.stopHeartbeat();if(this.ws){this.ws.close(code,reason);this.ws=null}this.rejectAllPendingRequests(new Error("Connection closed by client"),jsonrpc_JsonRpcErrorCode.ConnectionClosed);this.removeAllListeners()}reconnectToUrl(url){this.close();this.options.url=url;this.options.autoReconnect=true;this.reconnectAttempts=0;this.connect()}log(...args){if(this.options.debug)console.log("[JsonRpcWebSocket]",...args)}}export{JsonRpcWebSocketClient,SocketEvent,decode,JsonRpcWebSocketClient as default,pack_deserialize as deserialize,encode,generateUUID,pack_serialize as serialize};
|
package/package.json
CHANGED
|
@@ -1,12 +1,26 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@rfkit/json-rpc-websocket",
|
|
3
|
+
"version": "0.2.6",
|
|
4
|
+
"type": "module",
|
|
3
5
|
"description": "A lightweight JSON-RPC 2.0 client implementation over WebSocket, supporting request-response, notifications, and batch processing",
|
|
4
|
-
"
|
|
5
|
-
|
|
6
|
+
"exports": {
|
|
7
|
+
".": {
|
|
8
|
+
"types": "./index.d.ts",
|
|
9
|
+
"import": "./index.js"
|
|
10
|
+
}
|
|
11
|
+
},
|
|
12
|
+
"module": "./index.js",
|
|
13
|
+
"types": "./index.d.ts",
|
|
6
14
|
"author": "Hxgh",
|
|
7
15
|
"license": "MIT",
|
|
8
|
-
"
|
|
9
|
-
|
|
16
|
+
"repository": {
|
|
17
|
+
"type": "git",
|
|
18
|
+
"url": "https://github.com/Hxgh/json-rpc-websocket"
|
|
19
|
+
},
|
|
20
|
+
"homepage": "https://github.com/Hxgh/json-rpc-websocket#readme",
|
|
21
|
+
"bugs": {
|
|
22
|
+
"url": "https://github.com/Hxgh/json-rpc-websocket/issues"
|
|
23
|
+
},
|
|
10
24
|
"keywords": [
|
|
11
25
|
"json-rpc",
|
|
12
26
|
"websocket",
|
|
@@ -17,5 +31,13 @@
|
|
|
17
31
|
"real-time",
|
|
18
32
|
"communication",
|
|
19
33
|
"async"
|
|
20
|
-
]
|
|
34
|
+
],
|
|
35
|
+
"dependencies": {
|
|
36
|
+
"ws": "^8.20.1"
|
|
37
|
+
},
|
|
38
|
+
"publishConfig": {
|
|
39
|
+
"access": "public"
|
|
40
|
+
},
|
|
41
|
+
"packageManager": "pnpm@10.30.3",
|
|
42
|
+
"private": false
|
|
21
43
|
}
|
package/types/socket.d.ts
CHANGED
|
@@ -2,6 +2,9 @@
|
|
|
2
2
|
* WebSocket 客户端类型定义
|
|
3
3
|
*/
|
|
4
4
|
import type { JsonRpcResponse } from './jsonrpc';
|
|
5
|
+
export type InboundMode = 'messagepack' | 'raw';
|
|
6
|
+
export type OutboundMode = 'messagepack' | 'raw';
|
|
7
|
+
export type RawOutboundData = string | ArrayBuffer | ArrayBufferView | Blob;
|
|
5
8
|
/**
|
|
6
9
|
* WebSocket 连接状态
|
|
7
10
|
*/
|
|
@@ -33,6 +36,10 @@ export interface ConnectionOptions {
|
|
|
33
36
|
heartbeatMethod?: string;
|
|
34
37
|
/** 是否启用调试日志 */
|
|
35
38
|
debug?: boolean;
|
|
39
|
+
/** 入站消息模式,默认 MessagePack JSON-RPC 解码 */
|
|
40
|
+
inboundMode?: InboundMode;
|
|
41
|
+
/** 出站消息模式,默认 MessagePack JSON-RPC 编码 */
|
|
42
|
+
outboundMode?: OutboundMode;
|
|
36
43
|
}
|
|
37
44
|
/**
|
|
38
45
|
* 请求配置
|
|
@@ -78,15 +85,24 @@ export interface StreamController {
|
|
|
78
85
|
/** 流是否已关闭 */
|
|
79
86
|
readonly closed: boolean;
|
|
80
87
|
}
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
export interface MessageEventData {
|
|
88
|
+
export interface DecodedMessageEventData {
|
|
89
|
+
/** 消息是否已解码 */
|
|
90
|
+
decoded: true;
|
|
85
91
|
/** 解码后的消息 */
|
|
86
92
|
data: JsonRpcResponse;
|
|
87
93
|
/** 原始二进制数据(用于转发) */
|
|
88
94
|
rawData: ArrayBuffer;
|
|
89
95
|
}
|
|
96
|
+
export interface RawMessageEventData {
|
|
97
|
+
/** 消息是否已解码 */
|
|
98
|
+
decoded: false;
|
|
99
|
+
/** 原始二进制数据(用于转发) */
|
|
100
|
+
rawData: ArrayBuffer;
|
|
101
|
+
}
|
|
102
|
+
/**
|
|
103
|
+
* 消息事件数据(包含原始数据用于转发)
|
|
104
|
+
*/
|
|
105
|
+
export type MessageEventData = DecodedMessageEventData | RawMessageEventData;
|
|
90
106
|
/**
|
|
91
107
|
* 事件名称常量
|
|
92
108
|
*/
|
package/types/socket.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"socket.d.ts","sourceRoot":"","sources":["../../src/types/socket.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,WAAW,CAAC;AAEjD;;GAEG;AACH,oBAAY,eAAe;IACzB,UAAU,IAAI;IACd,IAAI,IAAI;IACR,OAAO,IAAI;IACX,MAAM,IAAI;CACX;AAED;;GAEG;AACH,MAAM,WAAW,iBAAiB;IAChC,oBAAoB;IACpB,GAAG,EAAE,MAAM,CAAC;IACZ,mBAAmB;IACnB,SAAS,CAAC,EAAE,MAAM,GAAG,MAAM,EAAE,CAAC;IAC9B,WAAW;IACX,aAAa,CAAC,EAAE,OAAO,CAAC;IACxB,eAAe;IACf,iBAAiB,CAAC,EAAE,MAAM,CAAC;IAC3B,aAAa;IACb,oBAAoB,CAAC,EAAE,MAAM,CAAC;IAC9B,iBAAiB;IACjB,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,sBAAsB;IACtB,iBAAiB,CAAC,EAAE,MAAM,CAAC;IAC3B,YAAY;IACZ,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,eAAe;IACf,KAAK,CAAC,EAAE,OAAO,CAAC;
|
|
1
|
+
{"version":3,"file":"socket.d.ts","sourceRoot":"","sources":["../../src/types/socket.ts"],"names":[],"mappings":"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"}
|