@adt/json-rpc-client
Version:
Json-rpc client with pluggable transport layers
1,116 lines (918 loc) • 32.2 kB
JavaScript
(function (global, factory) {
typeof exports === 'object' && typeof module !== 'undefined' ? module.exports = factory() :
typeof define === 'function' && define.amd ? define(factory) :
(global = typeof globalThis !== 'undefined' ? globalThis : global || self, global.JsonRpcClient = factory());
}(this, (function () { 'use strict';
function _typeof(obj) {
"@babel/helpers - typeof";
if (typeof Symbol === "function" && typeof Symbol.iterator === "symbol") {
_typeof = function (obj) {
return typeof obj;
};
} else {
_typeof = function (obj) {
return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj;
};
}
return _typeof(obj);
}
/**
* JSON-RPC Element
* Base class for all JSON-RPC messages
* This is abstract class, do not try to create instance of this class!
* @class
* @abstract
*/
function JsonRpcElement() {
throw new Error("JsonRpcElement is an abstract class. Can't instantiate or run");
}
JsonRpcElement.prototype = Object.freeze(Object.create(null, /** @lends JsonRpcElement.prototype */{
jsonrpc: { value: "2.0" },
serialize: { value: function value() {
return JSON.stringify(this);
} }
}));
var _typeof$1 = typeof Symbol === "function" && typeof Symbol.iterator === "symbol" ? function (obj) {
return typeof obj;
} : function (obj) {
return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj;
};
var validateId = function validateId(o) {
if ("id" in o === false) {
throw new Error("Required 'id' param is not present");
}
};
var validateMethod = function validateMethod(method) {
var methodType = typeof method === "undefined" ? "undefined" : _typeof$1(method);
if (methodType !== "string") {
throw new Error("Method must be a string, but '" + methodType + "' given");
}
};
var validateParams = function validateParams(params) {
var paramsType = typeof params === "undefined" ? "undefined" : _typeof$1(params);
var paramsIsArray = Array.isArray(params);
if (paramsType === "undefined") {
return;
}
if (paramsIsArray === false && paramsType !== "object" && paramsType !== "undefined") {
throw new Error("Params must be an array, object or undefined, but '" + paramsType + "' given");
}
};
var validateArguments = function validateArguments(args) {
if (typeof args === "undefined") {
throw new Error("Required parameters object not present");
}
};
/**
* JSON-RPC Error object
* @class
* @param {Object} o Parameters object
* @param {Number} o.code Error code
* @param {String} [o.message=""] Error message
* @param {?Object} [o.data=undefined] Additional data associated with error
*/
function JsonRpcError(o) {
if (this instanceof JsonRpcError === false) {
return new JsonRpcError(o);
}
validateArguments(o);
if (typeof o.code !== "number") {
throw "Error code must be integer";
}
this.code = o.code;
this.message = "message" in o ? o.message : "";
this.data = o.data;
return Object.freeze(this);
}
JsonRpcError.prototype = Object.create(null, /** @lends JsonRpcError.prototype */{
code: { value: 0, writable: true },
message: { value: "", writable: true },
data: { value: undefined, writable: true }
});
/**
* Standard JSON-RPC errors
* @type {Object}
*/
JsonRpcError.ERRORS = Object.freeze(Object.create(null, {
PARSE_ERROR: {
value: Object.freeze(Object.create(JsonRpcError.prototype, {
code: { value: -32700, enumerable: true },
message: { value: "Parse error", enumerable: true }
})),
enumerable: true
},
INVALID_REQUEST: {
value: Object.freeze(Object.create(JsonRpcError.prototype, {
code: { value: -32600, enumerable: true },
message: { value: "Invalid Request", enumerable: true }
})),
enumerable: true
},
METHOD_NOT_FOUND: {
value: Object.freeze(Object.create(JsonRpcError.prototype, {
code: { value: -32601, enumerable: true },
message: { value: "Method not found", enumerable: true }
})),
enumerable: true
},
INVALID_PARAMS: {
value: Object.freeze(Object.create(JsonRpcError.prototype, {
code: { value: -32602, enumerable: true },
message: { value: "Invalid params", enumerable: true }
})),
enumerable: true },
INTERNAL_ERROR: {
value: Object.freeze(Object.create(JsonRpcError.prototype, {
code: { value: -32603, enumerable: true },
message: { value: "Internal error", enumerable: true }
})),
enumerable: true }
}));
// TODO: For now this is only one level shallow copy, but should be real deep copy with omitting functions
var copyParams = function copyParams(params) {
if (typeof params === "undefined") {
return undefined;
} else if (Array.isArray(params)) {
return Object.freeze(params.splice(0));
} else {
var ret = Object.create(null);
for (var a in params) {
ret[a] = params[a];
Object.defineProperty(ret, a, { value: params[a] });
}
return Object.freeze(ret);
}
};
/**
* JSON-RPC Event
* TODO: Maybe length of 'method' parameter should be checked? Specification does not say anything about empty string as method name
* @class
* @param {Object} o Parameters object
* @param {String} o.method Method name
* @param {?Array} [o.params=undefined] Event params
*/
function JsonRpcEvent(o) {
validateArguments(o);
validateMethod(o.method);
var method = o.method;
validateParams(o.params);
var params = copyParams(o.params);
var instance = Object.create(JsonRpcEvent.prototype);
instance.method = method;
instance.params = params;
return Object.freeze(instance);
}
JsonRpcEvent.prototype = Object.create(JsonRpcElement.prototype, /** @lends JsonRpcElement.prototype */{
method: { writable: true },
params: { writable: true },
serialize: { value: function value() {
return JSON.stringify({ jsonrpc: this.jsonrpc,
method: this.method,
params: this.params });
} },
toJSON: {
value: function value() {
return this.serialize();
}
}
});
/**
* UUID
* @constructor
*/
function UUID(uuid) {
return Object.create(UUID.prototype, /** @lends UUID.prototype */{
value: { value: uuid, writable: true },
serialize: { value: function value() {
var val = this.value;
return [val[0] + val[1], val[2], val[3], val[4], val[5] + val[6] + val[7]].join("-");
} }
});
}
UUID.randomUUID = function () {
return UUID(guid());
};
UUID.fromString = function (str) {
var replaced = str.replace(/-/g, "");
var a = [];
for (var i = 0; i < 32; i += 4) {
a.push(replaced.slice(i, i + 4));
}
return UUID(a);
};
/**
* Helper function
* @returns {String}
*/
function s4() {
return Math.floor((1 + Math.random()) * 0x10000).toString(16).substring(1);
}
/**
* Helper function
* @return {Array}
*/
function guid() {
var ar = [];
for (var i = 0; i < 8; i++) {
ar.push(s4());
}
return ar;
}
/**
* JSON-RPC Request
* TODO: Maybe length of 'method' parameter should be checked? Specification does not say anything about empty string as method name
* @class
* @param {Object} o Parameters object
* @param {String} o.method
* @param {Array|Object|undefined} o.params Params must be an Array, Object or undefined
* @param {?String} [o.id=UUID] Request id if empty it will be set to randomly generated UUID TODO: For now id is set always to 1!!!
*/
function JsonRpcRequest(o) {
validateArguments(o);
validateMethod(o.method);
var method = o.method;
validateParams(o.params);
var params = copyParams(o.params);
var id = "id" in o ? o.id : UUID.randomUUID().serialize();
//return Object.freeze(Object.create(JsonRpcRequest.prototype,));
var instance = Object.create(JsonRpcRequest.prototype);
instance.id = id;
instance.method = method;
instance.params = params;
return Object.freeze(instance);
}
JsonRpcRequest.prototype = Object.create(JsonRpcElement.prototype, /** @lends JsonRpcRequest.prototype */{
method: { writable: true },
params: { writable: true },
id: { writable: true },
/**
* Serialize request object to string
* @return {String}
*/
serialize: { value: function value() {
var ret = {
jsonrpc: this.jsonrpc,
id: this.id,
method: this.method
};
if (typeof this.params !== "undefined") {
ret.params = this.params;
}
return JSON.stringify(ret);
} },
toJSON: {
value: function value() {
return this.serialize();
}
}
});
/**
* JSON-RPC Response
* This is abstract class, do not try to create instance of this class!
* Base class for JSON-RPC responses
* @class
* @abstract
*/
function JsonRpcResponse() {
throw new Error("JsonRpcResponse is an abstract class. Can't instantiate or run");
}
JsonRpcResponse.prototype = Object.freeze(Object.create(JsonRpcElement.prototype, {
id: { value: null, writable: true }
}));
/**
* JSON-RPC Error Response
* @class
* @param {Object} o Parameters object
* @param {String} o.id
* @param {JsonRpcError} o.error
*/
function JsonRpcResponseError(o) {
validateArguments(o);
validateId(o);
if (!(o.error instanceof JsonRpcError)) {
throw Error("error property is not an instance of JsonRpcError!");
}
var id = o.id;
var error = o.error;
return Object.freeze(Object.create(JsonRpcResponseError.prototype, {
id: { value: id },
error: { value: error },
/**
* Serialize request object to string
* @return {String}
*/
serialize: { value: function value() {
return JSON.stringify({
jsonrpc: this.jsonrpc,
id: this.id,
error: this.error
});
} },
toJSON: {
value: function value() {
return this.serialize();
}
}
}));
}
JsonRpcResponseError.prototype = Object.freeze(Object.create(JsonRpcResponse.prototype));
/**
* JSON-RPC Response result
* @class
* @param {Object} o Parameters object
* @param {String} o.id
* @param {Object} o.result
*/
function JsonRpcResponseResult(o) {
validateArguments(o);
validateId(o);
if ("result" in o === false) {
throw new Error("Required 'result' param is not present");
}
var id = o.id;
var result = o.result;
return Object.freeze(Object.create(JsonRpcResponseResult.prototype, /** @lends JsonRpcResponseResult.prototype */{
id: { value: id },
result: { value: result },
/**
* Serialize request object to string
* @return {String}
*/
serialize: { value: function value() {
return JSON.stringify({
jsonrpc: this.jsonrpc,
id: this.id,
result: this.result
});
} },
toJSON: {
value: function value() {
return this.serialize();
}
}
}));
}
JsonRpcResponseResult.prototype = Object.freeze(Object.create(JsonRpcResponse.prototype));
//import JsonRpcElement from "./JsonRpcElement";
/**
* Parses Json to JsonRpc object
* @param {String} str String to parse
* @param {Boolean} [weak=false] Don't check for existence of "jsonrpc" property in object
* @return JsonRpcElement
*/
var parse = function parse(str, weak) {
var u = "undefined";
var obj = void 0;
try {
obj = JSON.parse(str);
} catch (e) {
throw new Error("String " + str + " is not a valid JSON");
}
if (weak === true && "jsonrpc" in obj === false) {
// TODO: Dedicated exception
throw new Error("Missing 'jsonrpc' property in unserialized. You can omit this check by using the `weak` param");
}
var _obj = obj,
id = _obj.id,
method = _obj.method,
result = _obj.result,
error = _obj.error,
params = _obj.params;
if ((typeof id === "undefined" ? "undefined" : _typeof$1(id)) !== u) {
// Request or response
if ((typeof method === "undefined" ? "undefined" : _typeof$1(method)) !== u) {
if ((typeof params === "undefined" ? "undefined" : _typeof$1(params)) === u) {
throw new Error("Missing 'method' property in unserialized object");
}
return JsonRpcRequest({
id: id, method: method, params: params
});
} else if ((typeof result === "undefined" ? "undefined" : _typeof$1(result)) !== u) {
return JsonRpcResponseResult({
id: id, result: result
});
} else if ((typeof error === "undefined" ? "undefined" : _typeof$1(error)) !== u) {
var code = error.code,
message = error.message,
data = error.data;
return JsonRpcResponseError({
id: id,
error: JsonRpcError({
code: code, message: message, data: data
})
});
} else {
// TODO: Dedicated Exception
throw new Error("Unserialized object is not a valid JSON-RPC element");
}
} else {
// Event
return JsonRpcEvent({
method: method, params: params
});
}
};
JsonRpcElement.parse = parse;
JsonRpcElement.fromJSON = parse;
/**
* Callback
* @class
* @private
* @param {String} evtName Event name
* @param {Function} callback Callback function
* @param {Object} context Callback execution context
* @param {?Object} args Additional arguments
*/
function Callback(evtName, callback, context, args) {
return Object.freeze(Object.create(null, {
evtName: { value: evtName },
callback: { value: callback },
context: { value: context },
args: { value: args }
}));
}
/**
* EventEmitter
*/
function EventEmitter() {
var _this = this;
var callbacks = new Map();
var ret = Object.create(EventEmitter.prototype, {
/**
* Register callback function.<br />
* Event object will be passed to registered callback function as first argument.
* @name EventEmitter#on
* @memberof EventEmitter
* @function
* @param {String} evtName Event name
* @param {Function} cbf Callback function
* @param {Object} [context=EventEmitter] Callback execution context (this)
*/
on: { value: function value(evtName, cbf, context) {
var ctx = context || _this;
var cb = Callback(evtName, cbf, ctx);
if (callbacks.has(evtName)) {
callbacks.get(evtName).push(cb);
} else {
callbacks.set(evtName, [cb]);
}
} },
/**
* Execute callbacks on given event if callbacks exist for this event (emit events).
* @protected
* @param {String} evtName Event name
* @param {Object} evt Associated source event
*/
emit: { value: function value(evtName, evt) {
if (callbacks.has(evtName)) {
callbacks.get(evtName).forEach(function (cb) {
return cb.callback.call(cb.context, evt);
});
}
} }
});
return ret;
}
/**
* Tracker constructor.
* You can use this function with or without "new" operator
*
* @constructor
* @param {Object} o
* @param {Number} o.timeout Message timeout in milliseconds
* @param {Number} [o.checkInterval=1000] Check interval in milliseconds
*/
function MessageTracker(o) {
if ( typeof o === "undefined" || o === null ) {
throw Error("Missing configuration object");
}
if ( ("timeout" in o ) === false ) {
throw Error("Required param 'timeout' is not defined");
}
var promiseRegister = [],
globalTimeout = o.timeout,
checkInterval = o.checkInterval ? o.checkInterval : 1000,
timer = null;
function checkOverdue() {
var now = new Date() / 1000 | 0; // Get seconds and cut milliseconds
promiseRegister = promiseRegister.filter( function(val) {
if ( now - val.regTime > val.timeout ) {
val.reject(val.timeoutRejectWith);
return false;
} else {
return true;
}
});
// Timer is set again only when we have any message
if ( promiseRegister.length > 0 ) {
timer = setTimeout(checkOverdue, checkInterval);
} else {
clearTimeout(timer);
timer = null;
}
}
return Object.create(MessageTracker.prototype, {
globalTimeout : { set : function (val) {
globalTimeout = val;
}, get : function(){
return globalTimeout;
}},
register : { value :
/**
* Registers message in tracker.
* Filter function is a function witch should accept one argument as object with following properties<br>
* - message - message passed to matchMessage method<br>
* - current - iterated message from internal message register)<br>
* - resolve - resolving function<br>
* - reject - rejecting function)<br>
* - params - additional params
* Filter function is executed on each registered message when you call MessageTracker#matchMessage method
* If o.context will be passed then filter function will be executed within passed context
*
* @param {Object} o
* @param {Object} o.message
* @param {Function} o.filter Filter function
* @param {Number} [o.timeout=this.globalTimeout] Individual timeout in seconds for registered message, if not given, global timeout from constructor will be used
* @param {Object} o.timeoutRejectWith Overdue messages will be rejected with this object
* @param {Object} [o.params={}] Additional params which will be passed to filter function
* @param {Object} [o.context] Context (this) to execute filter function
* @return Promise
*/
function (o) {
var that = this;
var ret = new Promise(function(resolve, reject) {
var now = new Date() / 1000 | 0, // Get seconds and cut milliseconds
params = Object.create(null);
if ("params" in o && typeof params !== "undefined" ) {
params = o.params;
}
promiseRegister.push( {
message : o.message,
filter : o.filter,
resolve : resolve,
reject : reject,
regTime : now,
timeout : o.timeout ? o.timeout : that.globalTimeout,
timeoutRejectWith : o.timeoutRejectWith,
params : params,
context : o.context } );
});
// Start timer if it's not started
if ( timer === null ) {
timer = setTimeout(checkOverdue, checkInterval);
}
return ret;
}},
/**
* Match message passed as argument with registered messages
* Matching is done by function passed to register method in filter property
* Function returns true if message was matched
* @see MessageTracker#register
* @param {Object} m Message to check
* @function
* @return Boolean
*/
matchMessage : {
value : function(m) {
var l = promiseRegister.length,
br = false, rejectForFilter, resolveForFilter;
function resolve(resolveFnc) {
return function(res) {
resolveFnc(res);
br = true;
};
}
function reject(rejectFnc) {
return function(err) {
rejectFnc(err);
br = true;
};
}
for(var i=0;i<l;i++) {
var val = promiseRegister[i];
resolveForFilter = resolve(val.resolve);
rejectForFilter = reject(val.reject);
val.filter.call(val.context, {
message : m,
current : val.message,
resolve : resolveForFilter,
reject : rejectForFilter,
params : val.params
});
if ( br === true ) {
promiseRegister.splice(i,1);
break;
}
}
return br;
}
}
});
}
var version = "#version#";
/**
* @constructor
* @param {Object} c Configuration
* @param {JsonRpcTransportProvider} c.transportProvider
* @param {Number} [c.messageCheckInterval=1000] c.messageCheckInterval Interval (in ms) of checking overdue requests with no response
* @param {Number} [c.messageTimeout=5000] Message timeout in milliseconds
* @param {Boolean} [c.reconnect=false] Reconnect flag
* @param {Number} [c.reconnectAfter=5000] Reconnect timeout in milliseconds
* @fires connected
* @fires connecting
* @fires disconnected
* @fires connectionerror
* @fires message
* @fires error
*/
function JsonRpcClient(c) {
if (typeof c === "undefined" || c === null) {
throw new Error("Missing configuration object");
}
if (typeof c.transportProvider === "undefined") {
throw new Error("Required param 'transportProvider' is not defined");
}
var that = this;
var emitter = EventEmitter();
var config = {
messageCheckInterval: "messageCheckInterval" in c ? c.messageCheckInterval : 1000,
messageTimeout: "messageTimeout" in c ? c.messageTimeout : 5000
};
var transportProvider = c.transportProvider;
transportProvider.onMessage(onMessage.bind(that));
var o = onDisconnect.bind(that);
transportProvider.onDisconnect(o);
var messageTracker = MessageTracker({
timeout: config.messageTimeout,
checkInterval: config.messageCheckInterval
});
var ret = Object.create(JsonRpcClient.prototype,
/** @lends JsonRpcClient.prototype */
{
version: {
get: function get() {
return version;
}
},
// TODO: Getter
connected: {
value: false,
writable: true
},
/**
* @type {WebSocket}
* @default null
*/
socket: {
value: null,
writable: true
},
/**
* @type {MessageTracker}
* @default null
*/
messageTracker: {
value: null,
writable: true
},
connect: {
value: connect
},
sendRequest: {
value: sendRequest
},
sendEvent: {
value: sendEvent
},
disconnect: {
value: disconnect
},
on: {
value: function value(evtName, cbf, context) {
return emitter.on(evtName, cbf, context);
}
}
});
/**
* Connects to remote endpoint by underlying transport channel
* @name JsonRpcClient#connect
* @function
* @this JsonRpcClient
* @return {Promise}
*/
function connect() {
return new Promise(function (resolve, reject) {
emitter.emit("connecting");
transportProvider.connect().then(function () {
emitter.emit("connected");
resolve();
})["catch"](function (e) {
reject(e);
});
});
}
/**
* Send request to the remote side
* If websocket is not connected then message will not be send and function returns rejected promise with JsonRpcClient.ERRORS.INVALID_STATE_ERR
* If request will be timeouted during waiting from response then returned promise will be rejected with JsonRpcError.ERRORS.TIMEOUT_EXCEEDED with request attached in data property
* @function
* @name JsonRpcClient#sendRequest
* @this JsonRpcClient
* @param {JsonRpcClient.JsonRpcRequest} req
* @param {Boolean} [enableCallbacks=false] If true, then callbacks assigned to message event will be executed before resolving/rejecting promise on response.
* @return Promise
*/
function sendRequest(req, enableCallbacks) {
var retPromise,
rejectWith = JsonRpcClient.ERRORS.TIMEOUT_EXCEEDED;
rejectWith.data = req;
if (transportProvider.isConnected() === true) {
retPromise = messageTracker.register({
message: req,
filter: filterMessage,
timeoutRejectWith: rejectWith,
params: {
enableCallbacks: enableCallbacks
},
context: this
}); // TODO: Czy powinienem tutaj pchać zaserializowane, czy może jednak JsonRpcRequest??? Chyba lepiej mieć obiekt...
transportProvider.send(req);
} else {
retPromise = Promise.reject(new JsonRpcResponseError({
id: req.id,
error: JsonRpcClient.ERRORS.INVALID_STATE_ERR
}));
}
return retPromise;
}
/**
* Sends JSON-RPC event to the remote side.
* On success method returns JsonRpcClient.ERRORS.NO_ERROR
* If websocket is not connected then message will not be send and function returns error JsonRpcClient.ERRORS.INVALID_STATE_ERR
* @function
* @name JsonRpcClient#sendEvent
* @param {JsonRpcClient.JsonRpcEvent}
* @this JsonRpcClient
* @return JsonRpcError
*/
function sendEvent(evt) {
if (transportProvider.isConnected() === true) {
transportProvider.send(evt);
} else {
return JsonRpcClient.ERRORS.INVALID_STATE_ERR;
}
return JsonRpcClient.ERRORS.NO_ERROR;
}
/**
* @this JsonRpcClient
* @param {JsonRpcElement}
*/
function onMessage(m) {
var msg,
rObj = {}; // If message tracker matched message, then eventually emit message is realized by filterFunction
// otherwise process message as event or request here
if (!messageTracker.matchMessage(m)) {
if (_typeof(m) === "object") {
if ("id" in m) {
rObj.id = m.id;
if ("result" in m) {
rObj.result = m.result;
msg = JsonRpcResponseResult(rObj);
}
if ("error" in m) {
msg = JsonRpcResponseError({
id: m.id,
error: JsonRpcError(m.error)
});
}
if ("method" in m) {
rObj.method = m.method;
rObj.params = m.params;
msg = JsonRpcRequest(rObj);
}
} else {
rObj.method = m.method;
rObj.params = m.params;
msg = JsonRpcEvent(rObj);
}
} else {
msg = m;
}
emitter.emit("message", msg);
}
}
function onDisconnect(evt) {
emitter.emit("disconnected", evt);
}
/**
* Disconnects underlying transport channel.
* @function
* @name JsonRpcClient#disconnect
* @this JsonRpcClient
*/
function disconnect() {
transportProvider.disconnect();
}
/**
* Function for filter messages in MessageTracker.
* This function is executed by message tracker in context of JsonRpcClient.
*
* @param {Object} o Parameters object
* @param {JsonRpcElement} o.message Message passed to matchMessage method
* @param {JsonRpcElement} o.current Iterated message from internal message register)
* @param {Function} o.resolve Resolving function
* @param {Function} o.reject Rejecting function
* @param {Object} o.params Additional params
* @this JsonRpcClient
*/
function filterMessage(o) {
var m = o === null || o === void 0 ? void 0 : o.message;
if (typeof m === "undefined" || m.id !== o.current.id) {
return;
}
var msg;
var err = false;
if ("result" in m) {
msg = JsonRpcResponseResult({
id: m.id,
result: m.result
});
}
if ("error" in m) {
err = true;
msg = JsonRpcResponseError({
id: m.id,
error: JsonRpcError(m.error)
});
}
if (msg !== undefined) {
if (o.params.enableCallbacks === true) {
emitter.emit("message", m);
}
if (err === true) {
o.reject(msg);
} else {
o.resolve(msg);
}
}
}
return ret;
}
JsonRpcClient.ERRORS = Object.create(null, {
NO_ERROR: {
value: Object.create(JsonRpcError.prototype, {
code: {
value: -32000,
enumerable: true
},
message: {
value: "No error",
enumerable: true
},
data: {
value: undefined,
enumerable: true,
writable: true
}
}),
enumerable: true
},
TIMEOUT_EXCEEDED: {
value: Object.create(JsonRpcError.prototype, {
code: {
value: -32001,
enumerable: true
},
message: {
value: "Waiting for response timeout exceeded",
enumerable: true
},
data: {
value: undefined,
enumerable: true,
writable: true
}
}),
enumerable: true
},
INVALID_STATE_ERR: {
value: Object.create(JsonRpcError.prototype, {
code: {
value: -32002,
enumerable: true
},
message: {
value: "WebSocket is already in CLOSING or CLOSED state",
enumerable: true
},
data: {
value: undefined,
enumerable: true,
writable: true
}
}),
enumerable: true
}
});
return JsonRpcClient;
})));