FRE-600: Fix code review blockers

- Consolidated duplicate UndoManagers to single instance
- Fixed connection promise to only resolve on 'connected' status
- Fixed WebSocketProvider import (WebsocketProvider)
- Added proper doc.destroy() cleanup
- Renamed isPresenceInitialized property to avoid conflict

Co-Authored-By: Paperclip <noreply@paperclip.ing>
This commit is contained in:
2026-04-25 00:08:01 -04:00
parent 65b552bb08
commit 7c684a42cc
48450 changed files with 5679671 additions and 383 deletions

File diff suppressed because one or more lines are too long

425
node_modules/rpc-websockets/dist/index.browser.cjs generated vendored Normal file
View File

@@ -0,0 +1,425 @@
'use strict';
var buffer = require('buffer');
var eventemitter3 = require('eventemitter3');
// node_modules/esbuild-plugin-polyfill-node/polyfills/buffer.js
var WebSocketBrowserImpl = class extends eventemitter3.EventEmitter {
socket;
/** Instantiate a WebSocket class
* @constructor
* @param {String} address - url to a websocket server
* @param {WebSocketBrowserOptions} options - websocket options
* @return {WebSocketBrowserImpl} - returns a WebSocket instance
*/
constructor(address, options) {
super();
this.socket = new window.WebSocket(address, options.protocols);
this.socket.onopen = () => this.emit("open");
this.socket.onmessage = (event) => this.emit("message", event.data);
this.socket.onerror = (error) => this.emit("error", error);
this.socket.onclose = (event) => {
this.emit("close", event.code, event.reason);
};
}
/**
* Sends data through a websocket connection
* @method
* @param {(String|Object)} data - data to be sent via websocket
* @param {Object} optionsOrCallback - ws options
* @param {Function} callback - a callback called once the data is sent
* @return {Undefined}
*/
send(data, optionsOrCallback, callback) {
const cb = callback || optionsOrCallback;
try {
this.socket.send(data);
cb();
} catch (error) {
cb(error);
}
}
/**
* Closes an underlying socket
* @method
* @param {Number} code - status code explaining why the connection is being closed
* @param {String} reason - a description why the connection is closing
* @return {Undefined}
* @throws {Error}
*/
close(code, reason) {
this.socket.close(code, reason);
}
addEventListener(type, listener, options) {
this.socket.addEventListener(type, listener, options);
}
};
function WebSocket(address, options) {
return new WebSocketBrowserImpl(address, options);
}
// src/lib/utils.ts
var DefaultDataPack = class {
encode(value) {
return JSON.stringify(value);
}
decode(value) {
return JSON.parse(value);
}
};
// src/lib/client.ts
var CommonClient = class extends eventemitter3.EventEmitter {
address;
rpc_id;
queue;
options;
autoconnect;
ready;
reconnect;
reconnect_timer_id;
reconnect_interval;
max_reconnects;
rest_options;
current_reconnects;
generate_request_id;
socket;
webSocketFactory;
dataPack;
/**
* Instantiate a Client class.
* @constructor
* @param {webSocketFactory} webSocketFactory - factory method for WebSocket
* @param {String} address - url to a websocket server
* @param {Object} options - ws options object with reconnect parameters
* @param {Function} generate_request_id - custom generation request Id
* @param {DataPack} dataPack - data pack contains encoder and decoder
* @return {CommonClient}
*/
constructor(webSocketFactory, address = "ws://localhost:8080", {
autoconnect = true,
reconnect = true,
reconnect_interval = 1e3,
max_reconnects = 5,
...rest_options
} = {}, generate_request_id, dataPack) {
super();
this.webSocketFactory = webSocketFactory;
this.queue = {};
this.rpc_id = 0;
this.address = address;
this.autoconnect = autoconnect;
this.ready = false;
this.reconnect = reconnect;
this.reconnect_timer_id = void 0;
this.reconnect_interval = reconnect_interval;
this.max_reconnects = max_reconnects;
this.rest_options = rest_options;
this.current_reconnects = 0;
this.generate_request_id = generate_request_id || (() => typeof this.rpc_id === "number" ? ++this.rpc_id : Number(this.rpc_id) + 1);
if (!dataPack) this.dataPack = new DefaultDataPack();
else this.dataPack = dataPack;
if (this.autoconnect)
this._connect(this.address, {
autoconnect: this.autoconnect,
reconnect: this.reconnect,
reconnect_interval: this.reconnect_interval,
max_reconnects: this.max_reconnects,
...this.rest_options
});
}
/**
* Connects to a defined server if not connected already.
* @method
* @return {Undefined}
*/
connect() {
if (this.socket) return;
this._connect(this.address, {
autoconnect: this.autoconnect,
reconnect: this.reconnect,
reconnect_interval: this.reconnect_interval,
max_reconnects: this.max_reconnects,
...this.rest_options
});
}
/**
* Calls a registered RPC method on server.
* @method
* @param {String} method - RPC method name
* @param {Object|Array} params - optional method parameters
* @param {Number} timeout - RPC reply timeout value
* @param {Object} ws_opts - options passed to ws
* @return {Promise}
*/
call(method, params, timeout, ws_opts) {
if (!ws_opts && "object" === typeof timeout) {
ws_opts = timeout;
timeout = null;
}
return new Promise((resolve, reject) => {
if (!this.ready) return reject(new Error("socket not ready"));
const rpc_id = this.generate_request_id(method, params);
const message = {
jsonrpc: "2.0",
method,
params: params || void 0,
id: rpc_id
};
this.socket.send(this.dataPack.encode(message), ws_opts, (error) => {
if (error) return reject(error);
this.queue[rpc_id] = { promise: [resolve, reject] };
if (timeout) {
this.queue[rpc_id].timeout = setTimeout(() => {
delete this.queue[rpc_id];
reject(new Error("reply timeout"));
}, timeout);
}
});
});
}
/**
* Logins with the other side of the connection.
* @method
* @param {Object} params - Login credentials object
* @return {Promise}
*/
async login(params) {
const resp = await this.call("rpc.login", params);
if (!resp) throw new Error("authentication failed");
return resp;
}
/**
* Fetches a list of client's methods registered on server.
* @method
* @return {Array}
*/
async listMethods() {
return await this.call("__listMethods");
}
/**
* Sends a JSON-RPC 2.0 notification to server.
* @method
* @param {String} method - RPC method name
* @param {Object} params - optional method parameters
* @return {Promise}
*/
notify(method, params) {
return new Promise((resolve, reject) => {
if (!this.ready) return reject(new Error("socket not ready"));
const message = {
jsonrpc: "2.0",
method,
params
};
this.socket.send(this.dataPack.encode(message), (error) => {
if (error) return reject(error);
resolve();
});
});
}
/**
* Subscribes for a defined event.
* @method
* @param {String|Array} event - event name
* @return {Undefined}
* @throws {Error}
*/
async subscribe(event) {
if (typeof event === "string") event = [event];
const result = await this.call("rpc.on", event);
if (typeof event === "string" && result[event] !== "ok")
throw new Error(
"Failed subscribing to an event '" + event + "' with: " + result[event]
);
return result;
}
/**
* Unsubscribes from a defined event.
* @method
* @param {String|Array} event - event name
* @return {Undefined}
* @throws {Error}
*/
async unsubscribe(event) {
if (typeof event === "string") event = [event];
const result = await this.call("rpc.off", event);
if (typeof event === "string" && result[event] !== "ok")
throw new Error("Failed unsubscribing from an event with: " + result);
return result;
}
/**
* Closes a WebSocket connection gracefully.
* @method
* @param {Number} code - socket close code
* @param {String} data - optional data to be sent before closing
* @return {Undefined}
*/
close(code, data) {
if (this.socket) this.socket.close(code || 1e3, data);
}
/**
* Enable / disable automatic reconnection.
* @method
* @param {Boolean} reconnect - enable / disable reconnection
* @return {Undefined}
*/
setAutoReconnect(reconnect) {
this.reconnect = reconnect;
}
/**
* Set the interval between reconnection attempts.
* @method
* @param {Number} interval - reconnection interval in milliseconds
* @return {Undefined}
*/
setReconnectInterval(interval) {
this.reconnect_interval = interval;
}
/**
* Set the maximum number of reconnection attempts.
* @method
* @param {Number} max_reconnects - maximum reconnection attempts
* @return {Undefined}
*/
setMaxReconnects(max_reconnects) {
this.max_reconnects = max_reconnects;
}
/**
* Get the current number of reconnection attempts made.
* @method
* @return {Number} current reconnection attempts
*/
getCurrentReconnects() {
return this.current_reconnects;
}
/**
* Get the maximum number of reconnection attempts.
* @method
* @return {Number} maximum reconnection attempts
*/
getMaxReconnects() {
return this.max_reconnects;
}
/**
* Check if the client is currently attempting to reconnect.
* @method
* @return {Boolean} true if reconnection is in progress
*/
isReconnecting() {
return this.reconnect_timer_id !== void 0;
}
/**
* Check if the client will attempt to reconnect on the next close event.
* @method
* @return {Boolean} true if reconnection will be attempted
*/
willReconnect() {
return this.reconnect && (this.max_reconnects === 0 || this.current_reconnects < this.max_reconnects);
}
/**
* Connection/Message handler.
* @method
* @private
* @param {String} address - WebSocket API address
* @param {Object} options - ws options object
* @return {Undefined}
*/
_connect(address, options) {
clearTimeout(this.reconnect_timer_id);
this.socket = this.webSocketFactory(address, options);
this.socket.addEventListener("open", () => {
this.ready = true;
this.emit("open");
this.current_reconnects = 0;
});
this.socket.addEventListener("message", ({ data: message }) => {
if (message instanceof ArrayBuffer)
message = buffer.Buffer.from(message).toString();
try {
message = this.dataPack.decode(message);
} catch (_error) {
return;
}
if (message.notification && this.listeners(message.notification).length) {
if (!Object.keys(message.params).length)
return this.emit(message.notification);
const args = [message.notification];
if (message.params.constructor === Object) args.push(message.params);
else
for (let i = 0; i < message.params.length; i++)
args.push(message.params[i]);
return Promise.resolve().then(() => {
this.emit.apply(this, args);
});
}
if (!this.queue[message.id]) {
if (message.method) {
return Promise.resolve().then(() => {
this.emit(message.method, message?.params);
});
}
return;
}
if ("error" in message === "result" in message)
this.queue[message.id].promise[1](
new Error(
'Server response malformed. Response must include either "result" or "error", but not both.'
)
);
if (this.queue[message.id].timeout)
clearTimeout(this.queue[message.id].timeout);
if (message.error) this.queue[message.id].promise[1](message.error);
else this.queue[message.id].promise[0](message.result);
delete this.queue[message.id];
});
this.socket.addEventListener("error", (error) => this.emit("error", error));
this.socket.addEventListener("close", ({ code, reason }) => {
if (this.ready)
setTimeout(() => this.emit("close", code, reason), 0);
this.ready = false;
this.socket = void 0;
if (code === 1e3) return;
this.current_reconnects++;
if (this.reconnect && (this.max_reconnects > this.current_reconnects || this.max_reconnects === 0))
this.reconnect_timer_id = setTimeout(
() => this._connect(address, options),
this.reconnect_interval
);
else if (this.reconnect && this.max_reconnects > 0 && this.current_reconnects >= this.max_reconnects) {
setTimeout(() => this.emit("max_reconnects_reached", code, reason), 1);
}
});
}
};
// src/index.browser.ts
var Client = class extends CommonClient {
constructor(address = "ws://localhost:8080", {
autoconnect = true,
reconnect = true,
reconnect_interval = 1e3,
max_reconnects = 5,
...rest_options
} = {}, generate_request_id) {
super(
WebSocket,
address,
{
autoconnect,
reconnect,
reconnect_interval,
max_reconnects,
...rest_options
},
generate_request_id
);
}
};
exports.Client = Client;
exports.CommonClient = CommonClient;
exports.DefaultDataPack = DefaultDataPack;
exports.WebSocket = WebSocket;
//# sourceMappingURL=index.browser.cjs.map
//# sourceMappingURL=index.browser.cjs.map

File diff suppressed because one or more lines are too long

255
node_modules/rpc-websockets/dist/index.browser.d.mts generated vendored Normal file
View File

@@ -0,0 +1,255 @@
import { EventEmitter } from 'eventemitter3';
import NodeWebSocket from 'ws';
type BrowserWebSocketType = InstanceType<typeof WebSocket>;
type NodeWebSocketType = InstanceType<typeof NodeWebSocket>;
type NodeWebSocketTypeOptions = NodeWebSocket.ClientOptions;
interface IWSClientAdditionalOptions {
autoconnect?: boolean;
reconnect?: boolean;
reconnect_interval?: number;
max_reconnects?: number;
}
interface ICommonWebSocketFactory {
(address: string, options: IWSClientAdditionalOptions): ICommonWebSocket;
}
interface ICommonWebSocket {
send: (data: Parameters<BrowserWebSocketType["send"]>[0], optionsOrCallback: ((error?: Error) => void) | Parameters<NodeWebSocketType["send"]>[1], callback?: (error?: Error) => void) => void;
close: (code?: number, reason?: string) => void;
addEventListener<K extends keyof WebSocketEventMap>(type: K, listener: (ev: WebSocketEventMap[K]) => any, options?: boolean | AddEventListenerOptions): void;
}
/**
* WebSocket implements a browser-side WebSocket specification.
* @module Client
*/
type WebSocketBrowserOptions = {
/**
* One or more protocols passed to the websocket constructor
* @link https://developer.mozilla.org/en-US/docs/Web/API/WebSocket/WebSocket
*/
protocols?: string | string[];
};
declare class WebSocketBrowserImpl extends EventEmitter {
socket: BrowserWebSocketType;
/** Instantiate a WebSocket class
* @constructor
* @param {String} address - url to a websocket server
* @param {WebSocketBrowserOptions} options - websocket options
* @return {WebSocketBrowserImpl} - returns a WebSocket instance
*/
constructor(address: string, options: WebSocketBrowserOptions);
/**
* Sends data through a websocket connection
* @method
* @param {(String|Object)} data - data to be sent via websocket
* @param {Object} optionsOrCallback - ws options
* @param {Function} callback - a callback called once the data is sent
* @return {Undefined}
*/
send(data: Parameters<BrowserWebSocketType["send"]>[0], optionsOrCallback: (error?: Error) => void | Parameters<NodeWebSocketType["send"]>[1], callback?: () => void): void;
/**
* Closes an underlying socket
* @method
* @param {Number} code - status code explaining why the connection is being closed
* @param {String} reason - a description why the connection is closing
* @return {Undefined}
* @throws {Error}
*/
close(code?: number, reason?: string): void;
addEventListener<K extends keyof WebSocketEventMap>(type: K, listener: (ev: WebSocketEventMap[K]) => any, options?: boolean | AddEventListenerOptions): void;
}
/**
* factory method for common WebSocket instance
* @method
* @param {String} address - url to a websocket server
* @param {(Object)} options - websocket options
* @return {Undefined}
*/
declare function WebSocket$1(address: string, options: IWSClientAdditionalOptions & WebSocketBrowserOptions): WebSocketBrowserImpl;
interface DataPack<T, R extends string | ArrayBufferLike | Blob | ArrayBufferView> {
encode(value: T): R;
decode(value: R): T;
}
declare class DefaultDataPack implements DataPack<Object, string> {
encode(value: Object): string;
decode(value: string): Object;
}
/**
* "Client" wraps "ws" or a browser-implemented "WebSocket" library
* according to the environment providing JSON RPC 2.0 support on top.
* @module Client
*/
interface IQueueElement {
promise: [
Parameters<ConstructorParameters<typeof Promise>[0]>[0],
Parameters<ConstructorParameters<typeof Promise>[0]>[1]
];
timeout?: ReturnType<typeof setTimeout>;
}
interface IQueue {
[x: number | string]: IQueueElement;
}
interface IWSRequestParams {
[x: string]: any;
[x: number]: any;
}
declare class CommonClient extends EventEmitter {
private address;
private rpc_id;
private queue;
private options;
private autoconnect;
private ready;
private reconnect;
private reconnect_timer_id;
private reconnect_interval;
private max_reconnects;
private rest_options;
private current_reconnects;
private generate_request_id;
private socket;
private webSocketFactory;
private dataPack;
/**
* Instantiate a Client class.
* @constructor
* @param {webSocketFactory} webSocketFactory - factory method for WebSocket
* @param {String} address - url to a websocket server
* @param {Object} options - ws options object with reconnect parameters
* @param {Function} generate_request_id - custom generation request Id
* @param {DataPack} dataPack - data pack contains encoder and decoder
* @return {CommonClient}
*/
constructor(webSocketFactory: ICommonWebSocketFactory, address?: string, { autoconnect, reconnect, reconnect_interval, max_reconnects, ...rest_options }?: {
autoconnect?: boolean;
reconnect?: boolean;
reconnect_interval?: number;
max_reconnects?: number;
}, generate_request_id?: (method: string, params: object | Array<any>) => number | string, dataPack?: DataPack<object, string>);
/**
* Connects to a defined server if not connected already.
* @method
* @return {Undefined}
*/
connect(): void;
/**
* Calls a registered RPC method on server.
* @method
* @param {String} method - RPC method name
* @param {Object|Array} params - optional method parameters
* @param {Number} timeout - RPC reply timeout value
* @param {Object} ws_opts - options passed to ws
* @return {Promise}
*/
call(method: string, params?: IWSRequestParams, timeout?: number, ws_opts?: Parameters<NodeWebSocketType["send"]>[1]): Promise<unknown>;
/**
* Logins with the other side of the connection.
* @method
* @param {Object} params - Login credentials object
* @return {Promise}
*/
login(params: IWSRequestParams): Promise<unknown>;
/**
* Fetches a list of client's methods registered on server.
* @method
* @return {Array}
*/
listMethods(): Promise<unknown>;
/**
* Sends a JSON-RPC 2.0 notification to server.
* @method
* @param {String} method - RPC method name
* @param {Object} params - optional method parameters
* @return {Promise}
*/
notify(method: string, params?: IWSRequestParams): Promise<void>;
/**
* Subscribes for a defined event.
* @method
* @param {String|Array} event - event name
* @return {Undefined}
* @throws {Error}
*/
subscribe(event: string | Array<string>): Promise<unknown>;
/**
* Unsubscribes from a defined event.
* @method
* @param {String|Array} event - event name
* @return {Undefined}
* @throws {Error}
*/
unsubscribe(event: string | Array<string>): Promise<unknown>;
/**
* Closes a WebSocket connection gracefully.
* @method
* @param {Number} code - socket close code
* @param {String} data - optional data to be sent before closing
* @return {Undefined}
*/
close(code?: number, data?: string): void;
/**
* Enable / disable automatic reconnection.
* @method
* @param {Boolean} reconnect - enable / disable reconnection
* @return {Undefined}
*/
setAutoReconnect(reconnect: boolean): void;
/**
* Set the interval between reconnection attempts.
* @method
* @param {Number} interval - reconnection interval in milliseconds
* @return {Undefined}
*/
setReconnectInterval(interval: number): void;
/**
* Set the maximum number of reconnection attempts.
* @method
* @param {Number} max_reconnects - maximum reconnection attempts
* @return {Undefined}
*/
setMaxReconnects(max_reconnects: number): void;
/**
* Get the current number of reconnection attempts made.
* @method
* @return {Number} current reconnection attempts
*/
getCurrentReconnects(): number;
/**
* Get the maximum number of reconnection attempts.
* @method
* @return {Number} maximum reconnection attempts
*/
getMaxReconnects(): number;
/**
* Check if the client is currently attempting to reconnect.
* @method
* @return {Boolean} true if reconnection is in progress
*/
isReconnecting(): boolean;
/**
* Check if the client will attempt to reconnect on the next close event.
* @method
* @return {Boolean} true if reconnection will be attempted
*/
willReconnect(): boolean;
/**
* Connection/Message handler.
* @method
* @private
* @param {String} address - WebSocket API address
* @param {Object} options - ws options object
* @return {Undefined}
*/
private _connect;
}
declare class Client extends CommonClient {
constructor(address?: string, { autoconnect, reconnect, reconnect_interval, max_reconnects, ...rest_options }?: IWSClientAdditionalOptions & WebSocketBrowserOptions, generate_request_id?: (method: string, params: object | Array<any>) => number | string);
}
export { type BrowserWebSocketType, Client, CommonClient, type DataPack, DefaultDataPack, type ICommonWebSocket, type ICommonWebSocketFactory, type IQueue, type IWSClientAdditionalOptions, type IWSRequestParams, type NodeWebSocketType, type NodeWebSocketTypeOptions, WebSocket$1 as WebSocket, type WebSocketBrowserOptions };

255
node_modules/rpc-websockets/dist/index.browser.d.ts generated vendored Normal file
View File

@@ -0,0 +1,255 @@
import { EventEmitter } from 'eventemitter3';
import NodeWebSocket from 'ws';
type BrowserWebSocketType = InstanceType<typeof WebSocket>;
type NodeWebSocketType = InstanceType<typeof NodeWebSocket>;
type NodeWebSocketTypeOptions = NodeWebSocket.ClientOptions;
interface IWSClientAdditionalOptions {
autoconnect?: boolean;
reconnect?: boolean;
reconnect_interval?: number;
max_reconnects?: number;
}
interface ICommonWebSocketFactory {
(address: string, options: IWSClientAdditionalOptions): ICommonWebSocket;
}
interface ICommonWebSocket {
send: (data: Parameters<BrowserWebSocketType["send"]>[0], optionsOrCallback: ((error?: Error) => void) | Parameters<NodeWebSocketType["send"]>[1], callback?: (error?: Error) => void) => void;
close: (code?: number, reason?: string) => void;
addEventListener<K extends keyof WebSocketEventMap>(type: K, listener: (ev: WebSocketEventMap[K]) => any, options?: boolean | AddEventListenerOptions): void;
}
/**
* WebSocket implements a browser-side WebSocket specification.
* @module Client
*/
type WebSocketBrowserOptions = {
/**
* One or more protocols passed to the websocket constructor
* @link https://developer.mozilla.org/en-US/docs/Web/API/WebSocket/WebSocket
*/
protocols?: string | string[];
};
declare class WebSocketBrowserImpl extends EventEmitter {
socket: BrowserWebSocketType;
/** Instantiate a WebSocket class
* @constructor
* @param {String} address - url to a websocket server
* @param {WebSocketBrowserOptions} options - websocket options
* @return {WebSocketBrowserImpl} - returns a WebSocket instance
*/
constructor(address: string, options: WebSocketBrowserOptions);
/**
* Sends data through a websocket connection
* @method
* @param {(String|Object)} data - data to be sent via websocket
* @param {Object} optionsOrCallback - ws options
* @param {Function} callback - a callback called once the data is sent
* @return {Undefined}
*/
send(data: Parameters<BrowserWebSocketType["send"]>[0], optionsOrCallback: (error?: Error) => void | Parameters<NodeWebSocketType["send"]>[1], callback?: () => void): void;
/**
* Closes an underlying socket
* @method
* @param {Number} code - status code explaining why the connection is being closed
* @param {String} reason - a description why the connection is closing
* @return {Undefined}
* @throws {Error}
*/
close(code?: number, reason?: string): void;
addEventListener<K extends keyof WebSocketEventMap>(type: K, listener: (ev: WebSocketEventMap[K]) => any, options?: boolean | AddEventListenerOptions): void;
}
/**
* factory method for common WebSocket instance
* @method
* @param {String} address - url to a websocket server
* @param {(Object)} options - websocket options
* @return {Undefined}
*/
declare function WebSocket$1(address: string, options: IWSClientAdditionalOptions & WebSocketBrowserOptions): WebSocketBrowserImpl;
interface DataPack<T, R extends string | ArrayBufferLike | Blob | ArrayBufferView> {
encode(value: T): R;
decode(value: R): T;
}
declare class DefaultDataPack implements DataPack<Object, string> {
encode(value: Object): string;
decode(value: string): Object;
}
/**
* "Client" wraps "ws" or a browser-implemented "WebSocket" library
* according to the environment providing JSON RPC 2.0 support on top.
* @module Client
*/
interface IQueueElement {
promise: [
Parameters<ConstructorParameters<typeof Promise>[0]>[0],
Parameters<ConstructorParameters<typeof Promise>[0]>[1]
];
timeout?: ReturnType<typeof setTimeout>;
}
interface IQueue {
[x: number | string]: IQueueElement;
}
interface IWSRequestParams {
[x: string]: any;
[x: number]: any;
}
declare class CommonClient extends EventEmitter {
private address;
private rpc_id;
private queue;
private options;
private autoconnect;
private ready;
private reconnect;
private reconnect_timer_id;
private reconnect_interval;
private max_reconnects;
private rest_options;
private current_reconnects;
private generate_request_id;
private socket;
private webSocketFactory;
private dataPack;
/**
* Instantiate a Client class.
* @constructor
* @param {webSocketFactory} webSocketFactory - factory method for WebSocket
* @param {String} address - url to a websocket server
* @param {Object} options - ws options object with reconnect parameters
* @param {Function} generate_request_id - custom generation request Id
* @param {DataPack} dataPack - data pack contains encoder and decoder
* @return {CommonClient}
*/
constructor(webSocketFactory: ICommonWebSocketFactory, address?: string, { autoconnect, reconnect, reconnect_interval, max_reconnects, ...rest_options }?: {
autoconnect?: boolean;
reconnect?: boolean;
reconnect_interval?: number;
max_reconnects?: number;
}, generate_request_id?: (method: string, params: object | Array<any>) => number | string, dataPack?: DataPack<object, string>);
/**
* Connects to a defined server if not connected already.
* @method
* @return {Undefined}
*/
connect(): void;
/**
* Calls a registered RPC method on server.
* @method
* @param {String} method - RPC method name
* @param {Object|Array} params - optional method parameters
* @param {Number} timeout - RPC reply timeout value
* @param {Object} ws_opts - options passed to ws
* @return {Promise}
*/
call(method: string, params?: IWSRequestParams, timeout?: number, ws_opts?: Parameters<NodeWebSocketType["send"]>[1]): Promise<unknown>;
/**
* Logins with the other side of the connection.
* @method
* @param {Object} params - Login credentials object
* @return {Promise}
*/
login(params: IWSRequestParams): Promise<unknown>;
/**
* Fetches a list of client's methods registered on server.
* @method
* @return {Array}
*/
listMethods(): Promise<unknown>;
/**
* Sends a JSON-RPC 2.0 notification to server.
* @method
* @param {String} method - RPC method name
* @param {Object} params - optional method parameters
* @return {Promise}
*/
notify(method: string, params?: IWSRequestParams): Promise<void>;
/**
* Subscribes for a defined event.
* @method
* @param {String|Array} event - event name
* @return {Undefined}
* @throws {Error}
*/
subscribe(event: string | Array<string>): Promise<unknown>;
/**
* Unsubscribes from a defined event.
* @method
* @param {String|Array} event - event name
* @return {Undefined}
* @throws {Error}
*/
unsubscribe(event: string | Array<string>): Promise<unknown>;
/**
* Closes a WebSocket connection gracefully.
* @method
* @param {Number} code - socket close code
* @param {String} data - optional data to be sent before closing
* @return {Undefined}
*/
close(code?: number, data?: string): void;
/**
* Enable / disable automatic reconnection.
* @method
* @param {Boolean} reconnect - enable / disable reconnection
* @return {Undefined}
*/
setAutoReconnect(reconnect: boolean): void;
/**
* Set the interval between reconnection attempts.
* @method
* @param {Number} interval - reconnection interval in milliseconds
* @return {Undefined}
*/
setReconnectInterval(interval: number): void;
/**
* Set the maximum number of reconnection attempts.
* @method
* @param {Number} max_reconnects - maximum reconnection attempts
* @return {Undefined}
*/
setMaxReconnects(max_reconnects: number): void;
/**
* Get the current number of reconnection attempts made.
* @method
* @return {Number} current reconnection attempts
*/
getCurrentReconnects(): number;
/**
* Get the maximum number of reconnection attempts.
* @method
* @return {Number} maximum reconnection attempts
*/
getMaxReconnects(): number;
/**
* Check if the client is currently attempting to reconnect.
* @method
* @return {Boolean} true if reconnection is in progress
*/
isReconnecting(): boolean;
/**
* Check if the client will attempt to reconnect on the next close event.
* @method
* @return {Boolean} true if reconnection will be attempted
*/
willReconnect(): boolean;
/**
* Connection/Message handler.
* @method
* @private
* @param {String} address - WebSocket API address
* @param {Object} options - ws options object
* @return {Undefined}
*/
private _connect;
}
declare class Client extends CommonClient {
constructor(address?: string, { autoconnect, reconnect, reconnect_interval, max_reconnects, ...rest_options }?: IWSClientAdditionalOptions & WebSocketBrowserOptions, generate_request_id?: (method: string, params: object | Array<any>) => number | string);
}
export { type BrowserWebSocketType, Client, CommonClient, type DataPack, DefaultDataPack, type ICommonWebSocket, type ICommonWebSocketFactory, type IQueue, type IWSClientAdditionalOptions, type IWSRequestParams, type NodeWebSocketType, type NodeWebSocketTypeOptions, WebSocket$1 as WebSocket, type WebSocketBrowserOptions };

420
node_modules/rpc-websockets/dist/index.browser.mjs generated vendored Normal file
View File

@@ -0,0 +1,420 @@
import { Buffer } from 'buffer';
import { EventEmitter } from 'eventemitter3';
// node_modules/esbuild-plugin-polyfill-node/polyfills/buffer.js
var WebSocketBrowserImpl = class extends EventEmitter {
socket;
/** Instantiate a WebSocket class
* @constructor
* @param {String} address - url to a websocket server
* @param {WebSocketBrowserOptions} options - websocket options
* @return {WebSocketBrowserImpl} - returns a WebSocket instance
*/
constructor(address, options) {
super();
this.socket = new window.WebSocket(address, options.protocols);
this.socket.onopen = () => this.emit("open");
this.socket.onmessage = (event) => this.emit("message", event.data);
this.socket.onerror = (error) => this.emit("error", error);
this.socket.onclose = (event) => {
this.emit("close", event.code, event.reason);
};
}
/**
* Sends data through a websocket connection
* @method
* @param {(String|Object)} data - data to be sent via websocket
* @param {Object} optionsOrCallback - ws options
* @param {Function} callback - a callback called once the data is sent
* @return {Undefined}
*/
send(data, optionsOrCallback, callback) {
const cb = callback || optionsOrCallback;
try {
this.socket.send(data);
cb();
} catch (error) {
cb(error);
}
}
/**
* Closes an underlying socket
* @method
* @param {Number} code - status code explaining why the connection is being closed
* @param {String} reason - a description why the connection is closing
* @return {Undefined}
* @throws {Error}
*/
close(code, reason) {
this.socket.close(code, reason);
}
addEventListener(type, listener, options) {
this.socket.addEventListener(type, listener, options);
}
};
function WebSocket(address, options) {
return new WebSocketBrowserImpl(address, options);
}
// src/lib/utils.ts
var DefaultDataPack = class {
encode(value) {
return JSON.stringify(value);
}
decode(value) {
return JSON.parse(value);
}
};
// src/lib/client.ts
var CommonClient = class extends EventEmitter {
address;
rpc_id;
queue;
options;
autoconnect;
ready;
reconnect;
reconnect_timer_id;
reconnect_interval;
max_reconnects;
rest_options;
current_reconnects;
generate_request_id;
socket;
webSocketFactory;
dataPack;
/**
* Instantiate a Client class.
* @constructor
* @param {webSocketFactory} webSocketFactory - factory method for WebSocket
* @param {String} address - url to a websocket server
* @param {Object} options - ws options object with reconnect parameters
* @param {Function} generate_request_id - custom generation request Id
* @param {DataPack} dataPack - data pack contains encoder and decoder
* @return {CommonClient}
*/
constructor(webSocketFactory, address = "ws://localhost:8080", {
autoconnect = true,
reconnect = true,
reconnect_interval = 1e3,
max_reconnects = 5,
...rest_options
} = {}, generate_request_id, dataPack) {
super();
this.webSocketFactory = webSocketFactory;
this.queue = {};
this.rpc_id = 0;
this.address = address;
this.autoconnect = autoconnect;
this.ready = false;
this.reconnect = reconnect;
this.reconnect_timer_id = void 0;
this.reconnect_interval = reconnect_interval;
this.max_reconnects = max_reconnects;
this.rest_options = rest_options;
this.current_reconnects = 0;
this.generate_request_id = generate_request_id || (() => typeof this.rpc_id === "number" ? ++this.rpc_id : Number(this.rpc_id) + 1);
if (!dataPack) this.dataPack = new DefaultDataPack();
else this.dataPack = dataPack;
if (this.autoconnect)
this._connect(this.address, {
autoconnect: this.autoconnect,
reconnect: this.reconnect,
reconnect_interval: this.reconnect_interval,
max_reconnects: this.max_reconnects,
...this.rest_options
});
}
/**
* Connects to a defined server if not connected already.
* @method
* @return {Undefined}
*/
connect() {
if (this.socket) return;
this._connect(this.address, {
autoconnect: this.autoconnect,
reconnect: this.reconnect,
reconnect_interval: this.reconnect_interval,
max_reconnects: this.max_reconnects,
...this.rest_options
});
}
/**
* Calls a registered RPC method on server.
* @method
* @param {String} method - RPC method name
* @param {Object|Array} params - optional method parameters
* @param {Number} timeout - RPC reply timeout value
* @param {Object} ws_opts - options passed to ws
* @return {Promise}
*/
call(method, params, timeout, ws_opts) {
if (!ws_opts && "object" === typeof timeout) {
ws_opts = timeout;
timeout = null;
}
return new Promise((resolve, reject) => {
if (!this.ready) return reject(new Error("socket not ready"));
const rpc_id = this.generate_request_id(method, params);
const message = {
jsonrpc: "2.0",
method,
params: params || void 0,
id: rpc_id
};
this.socket.send(this.dataPack.encode(message), ws_opts, (error) => {
if (error) return reject(error);
this.queue[rpc_id] = { promise: [resolve, reject] };
if (timeout) {
this.queue[rpc_id].timeout = setTimeout(() => {
delete this.queue[rpc_id];
reject(new Error("reply timeout"));
}, timeout);
}
});
});
}
/**
* Logins with the other side of the connection.
* @method
* @param {Object} params - Login credentials object
* @return {Promise}
*/
async login(params) {
const resp = await this.call("rpc.login", params);
if (!resp) throw new Error("authentication failed");
return resp;
}
/**
* Fetches a list of client's methods registered on server.
* @method
* @return {Array}
*/
async listMethods() {
return await this.call("__listMethods");
}
/**
* Sends a JSON-RPC 2.0 notification to server.
* @method
* @param {String} method - RPC method name
* @param {Object} params - optional method parameters
* @return {Promise}
*/
notify(method, params) {
return new Promise((resolve, reject) => {
if (!this.ready) return reject(new Error("socket not ready"));
const message = {
jsonrpc: "2.0",
method,
params
};
this.socket.send(this.dataPack.encode(message), (error) => {
if (error) return reject(error);
resolve();
});
});
}
/**
* Subscribes for a defined event.
* @method
* @param {String|Array} event - event name
* @return {Undefined}
* @throws {Error}
*/
async subscribe(event) {
if (typeof event === "string") event = [event];
const result = await this.call("rpc.on", event);
if (typeof event === "string" && result[event] !== "ok")
throw new Error(
"Failed subscribing to an event '" + event + "' with: " + result[event]
);
return result;
}
/**
* Unsubscribes from a defined event.
* @method
* @param {String|Array} event - event name
* @return {Undefined}
* @throws {Error}
*/
async unsubscribe(event) {
if (typeof event === "string") event = [event];
const result = await this.call("rpc.off", event);
if (typeof event === "string" && result[event] !== "ok")
throw new Error("Failed unsubscribing from an event with: " + result);
return result;
}
/**
* Closes a WebSocket connection gracefully.
* @method
* @param {Number} code - socket close code
* @param {String} data - optional data to be sent before closing
* @return {Undefined}
*/
close(code, data) {
if (this.socket) this.socket.close(code || 1e3, data);
}
/**
* Enable / disable automatic reconnection.
* @method
* @param {Boolean} reconnect - enable / disable reconnection
* @return {Undefined}
*/
setAutoReconnect(reconnect) {
this.reconnect = reconnect;
}
/**
* Set the interval between reconnection attempts.
* @method
* @param {Number} interval - reconnection interval in milliseconds
* @return {Undefined}
*/
setReconnectInterval(interval) {
this.reconnect_interval = interval;
}
/**
* Set the maximum number of reconnection attempts.
* @method
* @param {Number} max_reconnects - maximum reconnection attempts
* @return {Undefined}
*/
setMaxReconnects(max_reconnects) {
this.max_reconnects = max_reconnects;
}
/**
* Get the current number of reconnection attempts made.
* @method
* @return {Number} current reconnection attempts
*/
getCurrentReconnects() {
return this.current_reconnects;
}
/**
* Get the maximum number of reconnection attempts.
* @method
* @return {Number} maximum reconnection attempts
*/
getMaxReconnects() {
return this.max_reconnects;
}
/**
* Check if the client is currently attempting to reconnect.
* @method
* @return {Boolean} true if reconnection is in progress
*/
isReconnecting() {
return this.reconnect_timer_id !== void 0;
}
/**
* Check if the client will attempt to reconnect on the next close event.
* @method
* @return {Boolean} true if reconnection will be attempted
*/
willReconnect() {
return this.reconnect && (this.max_reconnects === 0 || this.current_reconnects < this.max_reconnects);
}
/**
* Connection/Message handler.
* @method
* @private
* @param {String} address - WebSocket API address
* @param {Object} options - ws options object
* @return {Undefined}
*/
_connect(address, options) {
clearTimeout(this.reconnect_timer_id);
this.socket = this.webSocketFactory(address, options);
this.socket.addEventListener("open", () => {
this.ready = true;
this.emit("open");
this.current_reconnects = 0;
});
this.socket.addEventListener("message", ({ data: message }) => {
if (message instanceof ArrayBuffer)
message = Buffer.from(message).toString();
try {
message = this.dataPack.decode(message);
} catch (_error) {
return;
}
if (message.notification && this.listeners(message.notification).length) {
if (!Object.keys(message.params).length)
return this.emit(message.notification);
const args = [message.notification];
if (message.params.constructor === Object) args.push(message.params);
else
for (let i = 0; i < message.params.length; i++)
args.push(message.params[i]);
return Promise.resolve().then(() => {
this.emit.apply(this, args);
});
}
if (!this.queue[message.id]) {
if (message.method) {
return Promise.resolve().then(() => {
this.emit(message.method, message?.params);
});
}
return;
}
if ("error" in message === "result" in message)
this.queue[message.id].promise[1](
new Error(
'Server response malformed. Response must include either "result" or "error", but not both.'
)
);
if (this.queue[message.id].timeout)
clearTimeout(this.queue[message.id].timeout);
if (message.error) this.queue[message.id].promise[1](message.error);
else this.queue[message.id].promise[0](message.result);
delete this.queue[message.id];
});
this.socket.addEventListener("error", (error) => this.emit("error", error));
this.socket.addEventListener("close", ({ code, reason }) => {
if (this.ready)
setTimeout(() => this.emit("close", code, reason), 0);
this.ready = false;
this.socket = void 0;
if (code === 1e3) return;
this.current_reconnects++;
if (this.reconnect && (this.max_reconnects > this.current_reconnects || this.max_reconnects === 0))
this.reconnect_timer_id = setTimeout(
() => this._connect(address, options),
this.reconnect_interval
);
else if (this.reconnect && this.max_reconnects > 0 && this.current_reconnects >= this.max_reconnects) {
setTimeout(() => this.emit("max_reconnects_reached", code, reason), 1);
}
});
}
};
// src/index.browser.ts
var Client = class extends CommonClient {
constructor(address = "ws://localhost:8080", {
autoconnect = true,
reconnect = true,
reconnect_interval = 1e3,
max_reconnects = 5,
...rest_options
} = {}, generate_request_id) {
super(
WebSocket,
address,
{
autoconnect,
reconnect,
reconnect_interval,
max_reconnects,
...rest_options
},
generate_request_id
);
}
};
export { Client, CommonClient, DefaultDataPack, WebSocket };
//# sourceMappingURL=index.browser.mjs.map
//# sourceMappingURL=index.browser.mjs.map

File diff suppressed because one or more lines are too long

938
node_modules/rpc-websockets/dist/index.cjs generated vendored Normal file
View File

@@ -0,0 +1,938 @@
'use strict';
var WebSocketImpl = require('ws');
var eventemitter3 = require('eventemitter3');
var url = require('url');
var uuid = require('uuid');
function _interopDefault (e) { return e && e.__esModule ? e : { default: e }; }
var WebSocketImpl__default = /*#__PURE__*/_interopDefault(WebSocketImpl);
var url__default = /*#__PURE__*/_interopDefault(url);
// src/lib/client/websocket.ts
function WebSocket(address, options) {
return new WebSocketImpl__default.default(address, options);
}
// src/lib/utils.ts
var DefaultDataPack = class {
encode(value) {
return JSON.stringify(value);
}
decode(value) {
return JSON.parse(value);
}
};
// src/lib/client.ts
var CommonClient = class extends eventemitter3.EventEmitter {
address;
rpc_id;
queue;
options;
autoconnect;
ready;
reconnect;
reconnect_timer_id;
reconnect_interval;
max_reconnects;
rest_options;
current_reconnects;
generate_request_id;
socket;
webSocketFactory;
dataPack;
/**
* Instantiate a Client class.
* @constructor
* @param {webSocketFactory} webSocketFactory - factory method for WebSocket
* @param {String} address - url to a websocket server
* @param {Object} options - ws options object with reconnect parameters
* @param {Function} generate_request_id - custom generation request Id
* @param {DataPack} dataPack - data pack contains encoder and decoder
* @return {CommonClient}
*/
constructor(webSocketFactory, address = "ws://localhost:8080", {
autoconnect = true,
reconnect = true,
reconnect_interval = 1e3,
max_reconnects = 5,
...rest_options
} = {}, generate_request_id, dataPack) {
super();
this.webSocketFactory = webSocketFactory;
this.queue = {};
this.rpc_id = 0;
this.address = address;
this.autoconnect = autoconnect;
this.ready = false;
this.reconnect = reconnect;
this.reconnect_timer_id = void 0;
this.reconnect_interval = reconnect_interval;
this.max_reconnects = max_reconnects;
this.rest_options = rest_options;
this.current_reconnects = 0;
this.generate_request_id = generate_request_id || (() => typeof this.rpc_id === "number" ? ++this.rpc_id : Number(this.rpc_id) + 1);
if (!dataPack) this.dataPack = new DefaultDataPack();
else this.dataPack = dataPack;
if (this.autoconnect)
this._connect(this.address, {
autoconnect: this.autoconnect,
reconnect: this.reconnect,
reconnect_interval: this.reconnect_interval,
max_reconnects: this.max_reconnects,
...this.rest_options
});
}
/**
* Connects to a defined server if not connected already.
* @method
* @return {Undefined}
*/
connect() {
if (this.socket) return;
this._connect(this.address, {
autoconnect: this.autoconnect,
reconnect: this.reconnect,
reconnect_interval: this.reconnect_interval,
max_reconnects: this.max_reconnects,
...this.rest_options
});
}
/**
* Calls a registered RPC method on server.
* @method
* @param {String} method - RPC method name
* @param {Object|Array} params - optional method parameters
* @param {Number} timeout - RPC reply timeout value
* @param {Object} ws_opts - options passed to ws
* @return {Promise}
*/
call(method, params, timeout, ws_opts) {
if (!ws_opts && "object" === typeof timeout) {
ws_opts = timeout;
timeout = null;
}
return new Promise((resolve, reject) => {
if (!this.ready) return reject(new Error("socket not ready"));
const rpc_id = this.generate_request_id(method, params);
const message = {
jsonrpc: "2.0",
method,
params: params || void 0,
id: rpc_id
};
this.socket.send(this.dataPack.encode(message), ws_opts, (error) => {
if (error) return reject(error);
this.queue[rpc_id] = { promise: [resolve, reject] };
if (timeout) {
this.queue[rpc_id].timeout = setTimeout(() => {
delete this.queue[rpc_id];
reject(new Error("reply timeout"));
}, timeout);
}
});
});
}
/**
* Logins with the other side of the connection.
* @method
* @param {Object} params - Login credentials object
* @return {Promise}
*/
async login(params) {
const resp = await this.call("rpc.login", params);
if (!resp) throw new Error("authentication failed");
return resp;
}
/**
* Fetches a list of client's methods registered on server.
* @method
* @return {Array}
*/
async listMethods() {
return await this.call("__listMethods");
}
/**
* Sends a JSON-RPC 2.0 notification to server.
* @method
* @param {String} method - RPC method name
* @param {Object} params - optional method parameters
* @return {Promise}
*/
notify(method, params) {
return new Promise((resolve, reject) => {
if (!this.ready) return reject(new Error("socket not ready"));
const message = {
jsonrpc: "2.0",
method,
params
};
this.socket.send(this.dataPack.encode(message), (error) => {
if (error) return reject(error);
resolve();
});
});
}
/**
* Subscribes for a defined event.
* @method
* @param {String|Array} event - event name
* @return {Undefined}
* @throws {Error}
*/
async subscribe(event) {
if (typeof event === "string") event = [event];
const result = await this.call("rpc.on", event);
if (typeof event === "string" && result[event] !== "ok")
throw new Error(
"Failed subscribing to an event '" + event + "' with: " + result[event]
);
return result;
}
/**
* Unsubscribes from a defined event.
* @method
* @param {String|Array} event - event name
* @return {Undefined}
* @throws {Error}
*/
async unsubscribe(event) {
if (typeof event === "string") event = [event];
const result = await this.call("rpc.off", event);
if (typeof event === "string" && result[event] !== "ok")
throw new Error("Failed unsubscribing from an event with: " + result);
return result;
}
/**
* Closes a WebSocket connection gracefully.
* @method
* @param {Number} code - socket close code
* @param {String} data - optional data to be sent before closing
* @return {Undefined}
*/
close(code, data) {
if (this.socket) this.socket.close(code || 1e3, data);
}
/**
* Enable / disable automatic reconnection.
* @method
* @param {Boolean} reconnect - enable / disable reconnection
* @return {Undefined}
*/
setAutoReconnect(reconnect) {
this.reconnect = reconnect;
}
/**
* Set the interval between reconnection attempts.
* @method
* @param {Number} interval - reconnection interval in milliseconds
* @return {Undefined}
*/
setReconnectInterval(interval) {
this.reconnect_interval = interval;
}
/**
* Set the maximum number of reconnection attempts.
* @method
* @param {Number} max_reconnects - maximum reconnection attempts
* @return {Undefined}
*/
setMaxReconnects(max_reconnects) {
this.max_reconnects = max_reconnects;
}
/**
* Get the current number of reconnection attempts made.
* @method
* @return {Number} current reconnection attempts
*/
getCurrentReconnects() {
return this.current_reconnects;
}
/**
* Get the maximum number of reconnection attempts.
* @method
* @return {Number} maximum reconnection attempts
*/
getMaxReconnects() {
return this.max_reconnects;
}
/**
* Check if the client is currently attempting to reconnect.
* @method
* @return {Boolean} true if reconnection is in progress
*/
isReconnecting() {
return this.reconnect_timer_id !== void 0;
}
/**
* Check if the client will attempt to reconnect on the next close event.
* @method
* @return {Boolean} true if reconnection will be attempted
*/
willReconnect() {
return this.reconnect && (this.max_reconnects === 0 || this.current_reconnects < this.max_reconnects);
}
/**
* Connection/Message handler.
* @method
* @private
* @param {String} address - WebSocket API address
* @param {Object} options - ws options object
* @return {Undefined}
*/
_connect(address, options) {
clearTimeout(this.reconnect_timer_id);
this.socket = this.webSocketFactory(address, options);
this.socket.addEventListener("open", () => {
this.ready = true;
this.emit("open");
this.current_reconnects = 0;
});
this.socket.addEventListener("message", ({ data: message }) => {
if (message instanceof ArrayBuffer)
message = Buffer.from(message).toString();
try {
message = this.dataPack.decode(message);
} catch (_error) {
return;
}
if (message.notification && this.listeners(message.notification).length) {
if (!Object.keys(message.params).length)
return this.emit(message.notification);
const args = [message.notification];
if (message.params.constructor === Object) args.push(message.params);
else
for (let i = 0; i < message.params.length; i++)
args.push(message.params[i]);
return Promise.resolve().then(() => {
this.emit.apply(this, args);
});
}
if (!this.queue[message.id]) {
if (message.method) {
return Promise.resolve().then(() => {
this.emit(message.method, message?.params);
});
}
return;
}
if ("error" in message === "result" in message)
this.queue[message.id].promise[1](
new Error(
'Server response malformed. Response must include either "result" or "error", but not both.'
)
);
if (this.queue[message.id].timeout)
clearTimeout(this.queue[message.id].timeout);
if (message.error) this.queue[message.id].promise[1](message.error);
else this.queue[message.id].promise[0](message.result);
delete this.queue[message.id];
});
this.socket.addEventListener("error", (error) => this.emit("error", error));
this.socket.addEventListener("close", ({ code, reason }) => {
if (this.ready)
setTimeout(() => this.emit("close", code, reason), 0);
this.ready = false;
this.socket = void 0;
if (code === 1e3) return;
this.current_reconnects++;
if (this.reconnect && (this.max_reconnects > this.current_reconnects || this.max_reconnects === 0))
this.reconnect_timer_id = setTimeout(
() => this._connect(address, options),
this.reconnect_interval
);
else if (this.reconnect && this.max_reconnects > 0 && this.current_reconnects >= this.max_reconnects) {
setTimeout(() => this.emit("max_reconnects_reached", code, reason), 1);
}
});
}
};
var Server = class extends eventemitter3.EventEmitter {
namespaces;
dataPack;
wss;
/**
* Instantiate a Server class.
* @constructor
* @param {Object} options - ws constructor's parameters with rpc
* @param {DataPack} dataPack - data pack contains encoder and decoder
* @return {Server} - returns a new Server instance
*/
constructor(options, dataPack) {
super();
this.namespaces = {};
if (!dataPack) this.dataPack = new DefaultDataPack();
else this.dataPack = dataPack;
this.wss = new WebSocketImpl.WebSocketServer(options);
this.wss.on("listening", () => this.emit("listening"));
this.wss.on("connection", (socket, request) => {
const u = url__default.default.parse(request.url, true);
const ns = u.pathname;
if (u.query.socket_id) socket._id = u.query.socket_id;
else socket._id = uuid.v1();
socket["_authenticated"] = false;
socket.on("error", (error) => this.emit("socket-error", socket, error));
socket.on("close", () => {
this.namespaces[ns].clients.delete(socket._id);
for (const event of Object.keys(this.namespaces[ns].events)) {
const index = this.namespaces[ns].events[event].sockets.indexOf(
socket._id
);
if (index >= 0)
this.namespaces[ns].events[event].sockets.splice(index, 1);
}
this.emit("disconnection", socket);
});
if (!this.namespaces[ns]) this._generateNamespace(ns);
this.namespaces[ns].clients.set(socket._id, socket);
this.emit("connection", socket, request);
return this._handleRPC(socket, ns);
});
this.wss.on("error", (error) => this.emit("error", error));
}
/**
* Registers an RPC method.
* @method
* @param {String} name - method name
* @param {Function} fn - a callee function
* @param {String} ns - namespace identifier
* @throws {TypeError}
* @return {Object} - returns an IMethod object
*/
register(name, fn, ns = "/") {
if (!this.namespaces[ns]) this._generateNamespace(ns);
this.namespaces[ns].rpc_methods[name] = {
fn,
protected: false
};
return {
protected: () => this._makeProtectedMethod(name, ns),
public: () => this._makePublicMethod(name, ns)
};
}
/**
* Sets an auth method.
* @method
* @param {Function} fn - an arbitrary auth method
* @param {String} ns - namespace identifier
* @throws {TypeError}
* @return {Undefined}
*/
setAuth(fn, ns = "/") {
this.register("rpc.login", fn, ns);
}
/**
* Marks an RPC method as protected.
* @method
* @param {String} name - method name
* @param {String} ns - namespace identifier
* @return {Undefined}
*/
_makeProtectedMethod(name, ns = "/") {
this.namespaces[ns].rpc_methods[name].protected = true;
}
/**
* Marks an RPC method as public.
* @method
* @param {String} name - method name
* @param {String} ns - namespace identifier
* @return {Undefined}
*/
_makePublicMethod(name, ns = "/") {
this.namespaces[ns].rpc_methods[name].protected = false;
}
/**
* Marks an event as protected.
* @method
* @param {String} name - event name
* @param {String} ns - namespace identifier
* @return {Undefined}
*/
_makeProtectedEvent(name, ns = "/") {
this.namespaces[ns].events[name].protected = true;
}
/**
* Marks an event as public.
* @method
* @param {String} name - event name
* @param {String} ns - namespace identifier
* @return {Undefined}
*/
_makePublicEvent(name, ns = "/") {
this.namespaces[ns].events[name].protected = false;
}
/**
* Removes a namespace and closes all connections
* @method
* @param {String} ns - namespace identifier
* @throws {TypeError}
* @return {Undefined}
*/
closeNamespace(ns) {
const namespace = this.namespaces[ns];
if (namespace) {
delete namespace.rpc_methods;
delete namespace.events;
for (const socket of namespace.clients.values()) socket.close();
delete this.namespaces[ns];
}
}
/**
* Creates a new event that can be emitted to clients.
* @method
* @param {String} name - event name
* @param {String} ns - namespace identifier
* @throws {TypeError}
* @return {Object} - returns an IEvent object
*/
event(name, ns = "/") {
if (!this.namespaces[ns]) this._generateNamespace(ns);
else {
const index = this.namespaces[ns].events[name];
if (index !== void 0)
throw new Error(`Already registered event ${ns}${name}`);
}
this.namespaces[ns].events[name] = {
sockets: [],
protected: false
};
this.on(name, (...params) => {
if (params.length === 1 && params[0] instanceof Object)
params = params[0];
for (const socket_id of this.namespaces[ns].events[name].sockets) {
const socket = this.namespaces[ns].clients.get(socket_id);
if (!socket) continue;
socket.send(
this.dataPack.encode({
notification: name,
params
})
);
}
});
return {
protected: () => this._makeProtectedEvent(name, ns),
public: () => this._makePublicEvent(name, ns)
};
}
/**
* Returns a requested namespace object
* @method
* @param {String} name - namespace identifier
* @throws {TypeError}
* @return {Object} - namespace object
*/
of(name) {
if (!this.namespaces[name]) this._generateNamespace(name);
const self = this;
return {
// self.register convenience method
register(fn_name, fn) {
if (arguments.length !== 2)
throw new Error("must provide exactly two arguments");
if (typeof fn_name !== "string")
throw new Error("name must be a string");
if (typeof fn !== "function")
throw new Error("handler must be a function");
return self.register(fn_name, fn, name);
},
// self.event convenience method
event(ev_name) {
if (arguments.length !== 1)
throw new Error("must provide exactly one argument");
if (typeof ev_name !== "string")
throw new Error("name must be a string");
return self.event(ev_name, name);
},
// self.eventList convenience method
get eventList() {
return Object.keys(self.namespaces[name].events);
},
/**
* Emits a specified event to this namespace.
* @inner
* @method
* @param {String} event - event name
* @param {Array} params - event parameters
* @return {Undefined}
*/
emit(event, ...params) {
const nsEvent = self.namespaces[name].events[event];
if (nsEvent)
for (const socket_id of nsEvent.sockets) {
const socket = self.namespaces[name].clients.get(socket_id);
if (!socket) continue;
socket.send(
self.dataPack.encode({
notification: event,
params
})
);
}
},
/**
* Returns a name of this namespace.
* @inner
* @method
* @kind constant
* @return {String}
*/
get name() {
return name;
},
/**
* Returns a hash of websocket objects connected to this namespace.
* @inner
* @method
* @return {Object}
*/
connected() {
const socket_ids = [...self.namespaces[name].clients.keys()];
return socket_ids.reduce(
(acc, curr) => ({
...acc,
[curr]: self.namespaces[name].clients.get(curr)
}),
{}
);
},
/**
* Returns a list of client unique identifiers connected to this namespace.
* @inner
* @method
* @return {Array}
*/
clients() {
return self.namespaces[name];
}
};
}
/**
* Lists all created events in a given namespace. Defaults to "/".
* @method
* @param {String} ns - namespaces identifier
* @readonly
* @return {Array} - returns a list of created events
*/
eventList(ns = "/") {
if (!this.namespaces[ns]) return [];
return Object.keys(this.namespaces[ns].events);
}
/**
* Creates a JSON-RPC 2.0 compliant error
* @method
* @param {Number} code - indicates the error type that occurred
* @param {String} message - provides a short description of the error
* @param {String|Object} data - details containing additional information about the error
* @return {Object}
*/
createError(code, message, data) {
return {
code,
message,
data: data || null
};
}
/**
* Closes the server and terminates all clients.
* @method
* @return {Promise}
*/
close() {
return new Promise((resolve, reject) => {
try {
this.wss.close();
this.emit("close");
resolve();
} catch (error) {
reject(error);
}
});
}
/**
* Handles all WebSocket JSON RPC 2.0 requests.
* @private
* @param {Object} socket - ws socket instance
* @param {String} ns - namespaces identifier
* @return {Undefined}
*/
_handleRPC(socket, ns = "/") {
socket.on("message", async (data) => {
const msg_options = {};
if (data instanceof ArrayBuffer) {
msg_options.binary = true;
data = Buffer.from(data).toString();
}
if (socket.readyState !== 1) return;
let parsedData;
try {
parsedData = this.dataPack.decode(data);
} catch (error) {
return socket.send(
this.dataPack.encode({
jsonrpc: "2.0",
error: createError(-32700, error.toString()),
id: null
}),
msg_options
);
}
if (Array.isArray(parsedData)) {
if (!parsedData.length)
return socket.send(
this.dataPack.encode({
jsonrpc: "2.0",
error: createError(-32600, "Invalid array"),
id: null
}),
msg_options
);
const responses = [];
for (const message of parsedData) {
const response2 = await this._runMethod(message, socket._id, ns);
if (!response2) continue;
responses.push(response2);
}
if (!responses.length) return;
return socket.send(this.dataPack.encode(responses), msg_options);
}
const response = await this._runMethod(parsedData, socket._id, ns);
if (!response) return;
return socket.send(this.dataPack.encode(response), msg_options);
});
}
/**
* Runs a defined RPC method.
* @private
* @param {Object} message - a message received
* @param {Object} socket_id - user's socket id
* @param {String} ns - namespaces identifier
* @return {Object|undefined}
*/
async _runMethod(message, socket_id, ns = "/") {
if (typeof message !== "object" || message === null)
return {
jsonrpc: "2.0",
error: createError(-32600),
id: null
};
if (message.jsonrpc !== "2.0")
return {
jsonrpc: "2.0",
error: createError(-32600, "Invalid JSON RPC version"),
id: message.id || null
};
if (!message.method)
return {
jsonrpc: "2.0",
error: createError(-32602, "Method not specified"),
id: message.id || null
};
if (typeof message.method !== "string")
return {
jsonrpc: "2.0",
error: createError(-32600, "Invalid method name"),
id: message.id || null
};
if (message.params && typeof message.params === "string")
return {
jsonrpc: "2.0",
error: createError(-32600),
id: message.id || null
};
if (message.method === "rpc.on") {
if (!message.params)
return {
jsonrpc: "2.0",
error: createError(-32e3),
id: message.id || null
};
const results = {};
const event_names = Object.keys(this.namespaces[ns].events);
for (const name of message.params) {
const index = event_names.indexOf(name);
const namespace = this.namespaces[ns];
if (index === -1) {
results[name] = "provided event invalid";
continue;
}
if (namespace.events[event_names[index]].protected === true && namespace.clients.get(socket_id)["_authenticated"] === false) {
return {
jsonrpc: "2.0",
error: createError(-32606),
id: message.id || null
};
}
const socket_index = namespace.events[event_names[index]].sockets.indexOf(socket_id);
if (socket_index >= 0) {
results[name] = "socket has already been subscribed to event";
continue;
}
namespace.events[event_names[index]].sockets.push(socket_id);
results[name] = "ok";
}
return {
jsonrpc: "2.0",
result: results,
id: message.id || null
};
} else if (message.method === "rpc.off") {
if (!message.params)
return {
jsonrpc: "2.0",
error: createError(-32e3),
id: message.id || null
};
const results = {};
for (const name of message.params) {
if (!this.namespaces[ns].events[name]) {
results[name] = "provided event invalid";
continue;
}
const index = this.namespaces[ns].events[name].sockets.indexOf(socket_id);
if (index === -1) {
results[name] = "not subscribed";
continue;
}
this.namespaces[ns].events[name].sockets.splice(index, 1);
results[name] = "ok";
}
return {
jsonrpc: "2.0",
result: results,
id: message.id || null
};
} else if (message.method === "rpc.login") {
if (!message.params)
return {
jsonrpc: "2.0",
error: createError(-32604),
id: message.id || null
};
}
if (!this.namespaces[ns].rpc_methods[message.method]) {
return {
jsonrpc: "2.0",
error: createError(-32601),
id: message.id || null
};
}
let response = null;
if (this.namespaces[ns].rpc_methods[message.method].protected === true && this.namespaces[ns].clients.get(socket_id)["_authenticated"] === false) {
return {
jsonrpc: "2.0",
error: createError(-32605),
id: message.id || null
};
}
try {
response = await this.namespaces[ns].rpc_methods[message.method].fn(
message.params,
socket_id
);
} catch (error) {
if (!message.id) return;
if (error instanceof Error)
return {
jsonrpc: "2.0",
error: {
code: -32e3,
message: error.name,
data: error.message
},
id: message.id
};
return {
jsonrpc: "2.0",
error,
id: message.id
};
}
if (!message.id) return;
if (message.method === "rpc.login" && response === true) {
const s = this.namespaces[ns].clients.get(socket_id);
if (s) {
s["_authenticated"] = true;
this.namespaces[ns].clients.set(socket_id, s);
}
}
return {
jsonrpc: "2.0",
result: response,
id: message.id
};
}
/**
* Generate a new namespace store.
* Also preregister some special namespace methods.
* @private
* @param {String} name - namespaces identifier
* @return {undefined}
*/
_generateNamespace(name) {
this.namespaces[name] = {
rpc_methods: {
__listMethods: {
fn: () => Object.keys(this.namespaces[name].rpc_methods),
protected: false
}
},
clients: /* @__PURE__ */ new Map(),
events: {}
};
}
};
var RPC_ERRORS = /* @__PURE__ */ new Map([
[-32e3, "Event not provided"],
[-32600, "Invalid Request"],
[-32601, "Method not found"],
[-32602, "Invalid params"],
[-32603, "Internal error"],
[-32604, "Params not found"],
[-32605, "Method forbidden"],
[-32606, "Event forbidden"],
[-32700, "Parse error"]
]);
function createError(code, details) {
const error = {
code,
message: RPC_ERRORS.get(code) || "Internal Server Error"
};
if (details) error["data"] = details;
return error;
}
// src/index.ts
var Client = class extends CommonClient {
constructor(address = "ws://localhost:8080", {
autoconnect = true,
reconnect = true,
reconnect_interval = 1e3,
max_reconnects = 5,
...rest_options
} = {}, generate_request_id) {
super(
WebSocket,
address,
{
autoconnect,
reconnect,
reconnect_interval,
max_reconnects,
...rest_options
},
generate_request_id
);
}
};
exports.Client = Client;
exports.CommonClient = CommonClient;
exports.DefaultDataPack = DefaultDataPack;
exports.Server = Server;
exports.WebSocket = WebSocket;
exports.createError = createError;
//# sourceMappingURL=index.cjs.map
//# sourceMappingURL=index.cjs.map

1
node_modules/rpc-websockets/dist/index.cjs.map generated vendored Normal file

File diff suppressed because one or more lines are too long

452
node_modules/rpc-websockets/dist/index.d.mts generated vendored Normal file
View File

@@ -0,0 +1,452 @@
import { EventEmitter } from 'eventemitter3';
import NodeWebSocket, { WebSocketServer } from 'ws';
type BrowserWebSocketType = InstanceType<typeof WebSocket>;
type NodeWebSocketType = InstanceType<typeof NodeWebSocket>;
type NodeWebSocketTypeOptions = NodeWebSocket.ClientOptions;
interface IWSClientAdditionalOptions {
autoconnect?: boolean;
reconnect?: boolean;
reconnect_interval?: number;
max_reconnects?: number;
}
interface ICommonWebSocketFactory {
(address: string, options: IWSClientAdditionalOptions): ICommonWebSocket;
}
interface ICommonWebSocket {
send: (data: Parameters<BrowserWebSocketType["send"]>[0], optionsOrCallback: ((error?: Error) => void) | Parameters<NodeWebSocketType["send"]>[1], callback?: (error?: Error) => void) => void;
close: (code?: number, reason?: string) => void;
addEventListener<K extends keyof WebSocketEventMap>(type: K, listener: (ev: WebSocketEventMap[K]) => any, options?: boolean | AddEventListenerOptions): void;
}
interface DataPack<T, R extends string | ArrayBufferLike | Blob | ArrayBufferView> {
encode(value: T): R;
decode(value: R): T;
}
declare class DefaultDataPack implements DataPack<Object, string> {
encode(value: Object): string;
decode(value: string): Object;
}
/**
* "Client" wraps "ws" or a browser-implemented "WebSocket" library
* according to the environment providing JSON RPC 2.0 support on top.
* @module Client
*/
interface IQueueElement {
promise: [
Parameters<ConstructorParameters<typeof Promise>[0]>[0],
Parameters<ConstructorParameters<typeof Promise>[0]>[1]
];
timeout?: ReturnType<typeof setTimeout>;
}
interface IQueue {
[x: number | string]: IQueueElement;
}
interface IWSRequestParams {
[x: string]: any;
[x: number]: any;
}
declare class CommonClient extends EventEmitter {
private address;
private rpc_id;
private queue;
private options;
private autoconnect;
private ready;
private reconnect;
private reconnect_timer_id;
private reconnect_interval;
private max_reconnects;
private rest_options;
private current_reconnects;
private generate_request_id;
private socket;
private webSocketFactory;
private dataPack;
/**
* Instantiate a Client class.
* @constructor
* @param {webSocketFactory} webSocketFactory - factory method for WebSocket
* @param {String} address - url to a websocket server
* @param {Object} options - ws options object with reconnect parameters
* @param {Function} generate_request_id - custom generation request Id
* @param {DataPack} dataPack - data pack contains encoder and decoder
* @return {CommonClient}
*/
constructor(webSocketFactory: ICommonWebSocketFactory, address?: string, { autoconnect, reconnect, reconnect_interval, max_reconnects, ...rest_options }?: {
autoconnect?: boolean;
reconnect?: boolean;
reconnect_interval?: number;
max_reconnects?: number;
}, generate_request_id?: (method: string, params: object | Array<any>) => number | string, dataPack?: DataPack<object, string>);
/**
* Connects to a defined server if not connected already.
* @method
* @return {Undefined}
*/
connect(): void;
/**
* Calls a registered RPC method on server.
* @method
* @param {String} method - RPC method name
* @param {Object|Array} params - optional method parameters
* @param {Number} timeout - RPC reply timeout value
* @param {Object} ws_opts - options passed to ws
* @return {Promise}
*/
call(method: string, params?: IWSRequestParams, timeout?: number, ws_opts?: Parameters<NodeWebSocketType["send"]>[1]): Promise<unknown>;
/**
* Logins with the other side of the connection.
* @method
* @param {Object} params - Login credentials object
* @return {Promise}
*/
login(params: IWSRequestParams): Promise<unknown>;
/**
* Fetches a list of client's methods registered on server.
* @method
* @return {Array}
*/
listMethods(): Promise<unknown>;
/**
* Sends a JSON-RPC 2.0 notification to server.
* @method
* @param {String} method - RPC method name
* @param {Object} params - optional method parameters
* @return {Promise}
*/
notify(method: string, params?: IWSRequestParams): Promise<void>;
/**
* Subscribes for a defined event.
* @method
* @param {String|Array} event - event name
* @return {Undefined}
* @throws {Error}
*/
subscribe(event: string | Array<string>): Promise<unknown>;
/**
* Unsubscribes from a defined event.
* @method
* @param {String|Array} event - event name
* @return {Undefined}
* @throws {Error}
*/
unsubscribe(event: string | Array<string>): Promise<unknown>;
/**
* Closes a WebSocket connection gracefully.
* @method
* @param {Number} code - socket close code
* @param {String} data - optional data to be sent before closing
* @return {Undefined}
*/
close(code?: number, data?: string): void;
/**
* Enable / disable automatic reconnection.
* @method
* @param {Boolean} reconnect - enable / disable reconnection
* @return {Undefined}
*/
setAutoReconnect(reconnect: boolean): void;
/**
* Set the interval between reconnection attempts.
* @method
* @param {Number} interval - reconnection interval in milliseconds
* @return {Undefined}
*/
setReconnectInterval(interval: number): void;
/**
* Set the maximum number of reconnection attempts.
* @method
* @param {Number} max_reconnects - maximum reconnection attempts
* @return {Undefined}
*/
setMaxReconnects(max_reconnects: number): void;
/**
* Get the current number of reconnection attempts made.
* @method
* @return {Number} current reconnection attempts
*/
getCurrentReconnects(): number;
/**
* Get the maximum number of reconnection attempts.
* @method
* @return {Number} maximum reconnection attempts
*/
getMaxReconnects(): number;
/**
* Check if the client is currently attempting to reconnect.
* @method
* @return {Boolean} true if reconnection is in progress
*/
isReconnecting(): boolean;
/**
* Check if the client will attempt to reconnect on the next close event.
* @method
* @return {Boolean} true if reconnection will be attempted
*/
willReconnect(): boolean;
/**
* Connection/Message handler.
* @method
* @private
* @param {String} address - WebSocket API address
* @param {Object} options - ws options object
* @return {Undefined}
*/
private _connect;
}
/**
* factory method for common WebSocket instance
* @method
* @param {String} address - url to a websocket server
* @param {(Object)} options - websocket options
* @return {Undefined}
*/
declare function WebSocket$1(address: string, options: IWSClientAdditionalOptions & NodeWebSocket.ClientOptions): NodeWebSocket;
/**
* "Server" wraps the "ws" library providing JSON RPC 2.0 support on top.
* @module Server
*/
interface INamespaceEvent {
[x: string]: {
sockets: Array<string>;
protected: boolean;
};
}
interface IMethod {
public: () => void;
protected: () => void;
}
interface IEvent {
public: () => void;
protected: () => void;
}
interface IRPCError {
code: number;
message: string;
data?: string;
}
interface IRPCMethodParams {
[x: string]: any;
}
interface IRPCMethod {
[x: string]: {
fn: (params: IRPCMethodParams, socket_id: string) => any;
protected: boolean;
};
}
interface IClientWebSocket extends NodeWebSocket {
_id: string;
_authenticated: boolean;
}
declare class Server extends EventEmitter {
private namespaces;
private dataPack;
wss: InstanceType<typeof WebSocketServer>;
/**
* Instantiate a Server class.
* @constructor
* @param {Object} options - ws constructor's parameters with rpc
* @param {DataPack} dataPack - data pack contains encoder and decoder
* @return {Server} - returns a new Server instance
*/
constructor(options: NodeWebSocket.ServerOptions, dataPack?: DataPack<object, string>);
/**
* Registers an RPC method.
* @method
* @param {String} name - method name
* @param {Function} fn - a callee function
* @param {String} ns - namespace identifier
* @throws {TypeError}
* @return {Object} - returns an IMethod object
*/
register(name: string, fn: (params: IRPCMethodParams, socket_id: string) => void, ns?: string): IMethod;
/**
* Sets an auth method.
* @method
* @param {Function} fn - an arbitrary auth method
* @param {String} ns - namespace identifier
* @throws {TypeError}
* @return {Undefined}
*/
setAuth(fn: (params: IRPCMethodParams, socket_id: string) => Promise<boolean>, ns?: string): void;
/**
* Marks an RPC method as protected.
* @method
* @param {String} name - method name
* @param {String} ns - namespace identifier
* @return {Undefined}
*/
private _makeProtectedMethod;
/**
* Marks an RPC method as public.
* @method
* @param {String} name - method name
* @param {String} ns - namespace identifier
* @return {Undefined}
*/
private _makePublicMethod;
/**
* Marks an event as protected.
* @method
* @param {String} name - event name
* @param {String} ns - namespace identifier
* @return {Undefined}
*/
private _makeProtectedEvent;
/**
* Marks an event as public.
* @method
* @param {String} name - event name
* @param {String} ns - namespace identifier
* @return {Undefined}
*/
private _makePublicEvent;
/**
* Removes a namespace and closes all connections
* @method
* @param {String} ns - namespace identifier
* @throws {TypeError}
* @return {Undefined}
*/
closeNamespace(ns: string): void;
/**
* Creates a new event that can be emitted to clients.
* @method
* @param {String} name - event name
* @param {String} ns - namespace identifier
* @throws {TypeError}
* @return {Object} - returns an IEvent object
*/
event(name: string, ns?: string): IEvent;
/**
* Returns a requested namespace object
* @method
* @param {String} name - namespace identifier
* @throws {TypeError}
* @return {Object} - namespace object
*/
of(name: string): {
register(fn_name: string, fn: (params: IRPCMethodParams) => void): IMethod;
event(ev_name: string): IEvent;
readonly eventList: string[];
/**
* Emits a specified event to this namespace.
* @inner
* @method
* @param {String} event - event name
* @param {Array} params - event parameters
* @return {Undefined}
*/
emit(event: string, ...params: Array<string>): void;
/**
* Returns a name of this namespace.
* @inner
* @method
* @kind constant
* @return {String}
*/
readonly name: string;
/**
* Returns a hash of websocket objects connected to this namespace.
* @inner
* @method
* @return {Object}
*/
connected(): {};
/**
* Returns a list of client unique identifiers connected to this namespace.
* @inner
* @method
* @return {Array}
*/
clients(): {
rpc_methods: IRPCMethod;
clients: Map<string, IClientWebSocket>;
events: INamespaceEvent;
};
};
/**
* Lists all created events in a given namespace. Defaults to "/".
* @method
* @param {String} ns - namespaces identifier
* @readonly
* @return {Array} - returns a list of created events
*/
eventList(ns?: string): string[];
/**
* Creates a JSON-RPC 2.0 compliant error
* @method
* @param {Number} code - indicates the error type that occurred
* @param {String} message - provides a short description of the error
* @param {String|Object} data - details containing additional information about the error
* @return {Object}
*/
createError(code: number, message: string, data: string | object): {
code: number;
message: string;
data: string | object;
};
/**
* Closes the server and terminates all clients.
* @method
* @return {Promise}
*/
close(): Promise<void>;
/**
* Handles all WebSocket JSON RPC 2.0 requests.
* @private
* @param {Object} socket - ws socket instance
* @param {String} ns - namespaces identifier
* @return {Undefined}
*/
private _handleRPC;
/**
* Runs a defined RPC method.
* @private
* @param {Object} message - a message received
* @param {Object} socket_id - user's socket id
* @param {String} ns - namespaces identifier
* @return {Object|undefined}
*/
private _runMethod;
/**
* Generate a new namespace store.
* Also preregister some special namespace methods.
* @private
* @param {String} name - namespaces identifier
* @return {undefined}
*/
private _generateNamespace;
}
/**
* Creates a JSON-RPC 2.0-compliant error.
* @param {Number} code - error code
* @param {String} details - error details
* @return {Object}
*/
declare function createError(code: number, details?: string): IRPCError;
/**
* WebSocket implements a browser-side WebSocket specification.
* @module Client
*/
type WebSocketBrowserOptions = {
/**
* One or more protocols passed to the websocket constructor
* @link https://developer.mozilla.org/en-US/docs/Web/API/WebSocket/WebSocket
*/
protocols?: string | string[];
};
declare class Client extends CommonClient {
constructor(address?: string, { autoconnect, reconnect, reconnect_interval, max_reconnects, ...rest_options }?: IWSClientAdditionalOptions & NodeWebSocketTypeOptions, generate_request_id?: (method: string, params: object | Array<any>) => number | string);
}
export { type BrowserWebSocketType, Client, CommonClient, type DataPack, DefaultDataPack, type ICommonWebSocket, type ICommonWebSocketFactory, type IQueue, type IWSClientAdditionalOptions, type IWSRequestParams, type NodeWebSocketType, type NodeWebSocketTypeOptions, Server, WebSocket$1 as WebSocket, type WebSocketBrowserOptions, createError };

452
node_modules/rpc-websockets/dist/index.d.ts generated vendored Normal file
View File

@@ -0,0 +1,452 @@
import { EventEmitter } from 'eventemitter3';
import NodeWebSocket, { WebSocketServer } from 'ws';
type BrowserWebSocketType = InstanceType<typeof WebSocket>;
type NodeWebSocketType = InstanceType<typeof NodeWebSocket>;
type NodeWebSocketTypeOptions = NodeWebSocket.ClientOptions;
interface IWSClientAdditionalOptions {
autoconnect?: boolean;
reconnect?: boolean;
reconnect_interval?: number;
max_reconnects?: number;
}
interface ICommonWebSocketFactory {
(address: string, options: IWSClientAdditionalOptions): ICommonWebSocket;
}
interface ICommonWebSocket {
send: (data: Parameters<BrowserWebSocketType["send"]>[0], optionsOrCallback: ((error?: Error) => void) | Parameters<NodeWebSocketType["send"]>[1], callback?: (error?: Error) => void) => void;
close: (code?: number, reason?: string) => void;
addEventListener<K extends keyof WebSocketEventMap>(type: K, listener: (ev: WebSocketEventMap[K]) => any, options?: boolean | AddEventListenerOptions): void;
}
interface DataPack<T, R extends string | ArrayBufferLike | Blob | ArrayBufferView> {
encode(value: T): R;
decode(value: R): T;
}
declare class DefaultDataPack implements DataPack<Object, string> {
encode(value: Object): string;
decode(value: string): Object;
}
/**
* "Client" wraps "ws" or a browser-implemented "WebSocket" library
* according to the environment providing JSON RPC 2.0 support on top.
* @module Client
*/
interface IQueueElement {
promise: [
Parameters<ConstructorParameters<typeof Promise>[0]>[0],
Parameters<ConstructorParameters<typeof Promise>[0]>[1]
];
timeout?: ReturnType<typeof setTimeout>;
}
interface IQueue {
[x: number | string]: IQueueElement;
}
interface IWSRequestParams {
[x: string]: any;
[x: number]: any;
}
declare class CommonClient extends EventEmitter {
private address;
private rpc_id;
private queue;
private options;
private autoconnect;
private ready;
private reconnect;
private reconnect_timer_id;
private reconnect_interval;
private max_reconnects;
private rest_options;
private current_reconnects;
private generate_request_id;
private socket;
private webSocketFactory;
private dataPack;
/**
* Instantiate a Client class.
* @constructor
* @param {webSocketFactory} webSocketFactory - factory method for WebSocket
* @param {String} address - url to a websocket server
* @param {Object} options - ws options object with reconnect parameters
* @param {Function} generate_request_id - custom generation request Id
* @param {DataPack} dataPack - data pack contains encoder and decoder
* @return {CommonClient}
*/
constructor(webSocketFactory: ICommonWebSocketFactory, address?: string, { autoconnect, reconnect, reconnect_interval, max_reconnects, ...rest_options }?: {
autoconnect?: boolean;
reconnect?: boolean;
reconnect_interval?: number;
max_reconnects?: number;
}, generate_request_id?: (method: string, params: object | Array<any>) => number | string, dataPack?: DataPack<object, string>);
/**
* Connects to a defined server if not connected already.
* @method
* @return {Undefined}
*/
connect(): void;
/**
* Calls a registered RPC method on server.
* @method
* @param {String} method - RPC method name
* @param {Object|Array} params - optional method parameters
* @param {Number} timeout - RPC reply timeout value
* @param {Object} ws_opts - options passed to ws
* @return {Promise}
*/
call(method: string, params?: IWSRequestParams, timeout?: number, ws_opts?: Parameters<NodeWebSocketType["send"]>[1]): Promise<unknown>;
/**
* Logins with the other side of the connection.
* @method
* @param {Object} params - Login credentials object
* @return {Promise}
*/
login(params: IWSRequestParams): Promise<unknown>;
/**
* Fetches a list of client's methods registered on server.
* @method
* @return {Array}
*/
listMethods(): Promise<unknown>;
/**
* Sends a JSON-RPC 2.0 notification to server.
* @method
* @param {String} method - RPC method name
* @param {Object} params - optional method parameters
* @return {Promise}
*/
notify(method: string, params?: IWSRequestParams): Promise<void>;
/**
* Subscribes for a defined event.
* @method
* @param {String|Array} event - event name
* @return {Undefined}
* @throws {Error}
*/
subscribe(event: string | Array<string>): Promise<unknown>;
/**
* Unsubscribes from a defined event.
* @method
* @param {String|Array} event - event name
* @return {Undefined}
* @throws {Error}
*/
unsubscribe(event: string | Array<string>): Promise<unknown>;
/**
* Closes a WebSocket connection gracefully.
* @method
* @param {Number} code - socket close code
* @param {String} data - optional data to be sent before closing
* @return {Undefined}
*/
close(code?: number, data?: string): void;
/**
* Enable / disable automatic reconnection.
* @method
* @param {Boolean} reconnect - enable / disable reconnection
* @return {Undefined}
*/
setAutoReconnect(reconnect: boolean): void;
/**
* Set the interval between reconnection attempts.
* @method
* @param {Number} interval - reconnection interval in milliseconds
* @return {Undefined}
*/
setReconnectInterval(interval: number): void;
/**
* Set the maximum number of reconnection attempts.
* @method
* @param {Number} max_reconnects - maximum reconnection attempts
* @return {Undefined}
*/
setMaxReconnects(max_reconnects: number): void;
/**
* Get the current number of reconnection attempts made.
* @method
* @return {Number} current reconnection attempts
*/
getCurrentReconnects(): number;
/**
* Get the maximum number of reconnection attempts.
* @method
* @return {Number} maximum reconnection attempts
*/
getMaxReconnects(): number;
/**
* Check if the client is currently attempting to reconnect.
* @method
* @return {Boolean} true if reconnection is in progress
*/
isReconnecting(): boolean;
/**
* Check if the client will attempt to reconnect on the next close event.
* @method
* @return {Boolean} true if reconnection will be attempted
*/
willReconnect(): boolean;
/**
* Connection/Message handler.
* @method
* @private
* @param {String} address - WebSocket API address
* @param {Object} options - ws options object
* @return {Undefined}
*/
private _connect;
}
/**
* factory method for common WebSocket instance
* @method
* @param {String} address - url to a websocket server
* @param {(Object)} options - websocket options
* @return {Undefined}
*/
declare function WebSocket$1(address: string, options: IWSClientAdditionalOptions & NodeWebSocket.ClientOptions): NodeWebSocket;
/**
* "Server" wraps the "ws" library providing JSON RPC 2.0 support on top.
* @module Server
*/
interface INamespaceEvent {
[x: string]: {
sockets: Array<string>;
protected: boolean;
};
}
interface IMethod {
public: () => void;
protected: () => void;
}
interface IEvent {
public: () => void;
protected: () => void;
}
interface IRPCError {
code: number;
message: string;
data?: string;
}
interface IRPCMethodParams {
[x: string]: any;
}
interface IRPCMethod {
[x: string]: {
fn: (params: IRPCMethodParams, socket_id: string) => any;
protected: boolean;
};
}
interface IClientWebSocket extends NodeWebSocket {
_id: string;
_authenticated: boolean;
}
declare class Server extends EventEmitter {
private namespaces;
private dataPack;
wss: InstanceType<typeof WebSocketServer>;
/**
* Instantiate a Server class.
* @constructor
* @param {Object} options - ws constructor's parameters with rpc
* @param {DataPack} dataPack - data pack contains encoder and decoder
* @return {Server} - returns a new Server instance
*/
constructor(options: NodeWebSocket.ServerOptions, dataPack?: DataPack<object, string>);
/**
* Registers an RPC method.
* @method
* @param {String} name - method name
* @param {Function} fn - a callee function
* @param {String} ns - namespace identifier
* @throws {TypeError}
* @return {Object} - returns an IMethod object
*/
register(name: string, fn: (params: IRPCMethodParams, socket_id: string) => void, ns?: string): IMethod;
/**
* Sets an auth method.
* @method
* @param {Function} fn - an arbitrary auth method
* @param {String} ns - namespace identifier
* @throws {TypeError}
* @return {Undefined}
*/
setAuth(fn: (params: IRPCMethodParams, socket_id: string) => Promise<boolean>, ns?: string): void;
/**
* Marks an RPC method as protected.
* @method
* @param {String} name - method name
* @param {String} ns - namespace identifier
* @return {Undefined}
*/
private _makeProtectedMethod;
/**
* Marks an RPC method as public.
* @method
* @param {String} name - method name
* @param {String} ns - namespace identifier
* @return {Undefined}
*/
private _makePublicMethod;
/**
* Marks an event as protected.
* @method
* @param {String} name - event name
* @param {String} ns - namespace identifier
* @return {Undefined}
*/
private _makeProtectedEvent;
/**
* Marks an event as public.
* @method
* @param {String} name - event name
* @param {String} ns - namespace identifier
* @return {Undefined}
*/
private _makePublicEvent;
/**
* Removes a namespace and closes all connections
* @method
* @param {String} ns - namespace identifier
* @throws {TypeError}
* @return {Undefined}
*/
closeNamespace(ns: string): void;
/**
* Creates a new event that can be emitted to clients.
* @method
* @param {String} name - event name
* @param {String} ns - namespace identifier
* @throws {TypeError}
* @return {Object} - returns an IEvent object
*/
event(name: string, ns?: string): IEvent;
/**
* Returns a requested namespace object
* @method
* @param {String} name - namespace identifier
* @throws {TypeError}
* @return {Object} - namespace object
*/
of(name: string): {
register(fn_name: string, fn: (params: IRPCMethodParams) => void): IMethod;
event(ev_name: string): IEvent;
readonly eventList: string[];
/**
* Emits a specified event to this namespace.
* @inner
* @method
* @param {String} event - event name
* @param {Array} params - event parameters
* @return {Undefined}
*/
emit(event: string, ...params: Array<string>): void;
/**
* Returns a name of this namespace.
* @inner
* @method
* @kind constant
* @return {String}
*/
readonly name: string;
/**
* Returns a hash of websocket objects connected to this namespace.
* @inner
* @method
* @return {Object}
*/
connected(): {};
/**
* Returns a list of client unique identifiers connected to this namespace.
* @inner
* @method
* @return {Array}
*/
clients(): {
rpc_methods: IRPCMethod;
clients: Map<string, IClientWebSocket>;
events: INamespaceEvent;
};
};
/**
* Lists all created events in a given namespace. Defaults to "/".
* @method
* @param {String} ns - namespaces identifier
* @readonly
* @return {Array} - returns a list of created events
*/
eventList(ns?: string): string[];
/**
* Creates a JSON-RPC 2.0 compliant error
* @method
* @param {Number} code - indicates the error type that occurred
* @param {String} message - provides a short description of the error
* @param {String|Object} data - details containing additional information about the error
* @return {Object}
*/
createError(code: number, message: string, data: string | object): {
code: number;
message: string;
data: string | object;
};
/**
* Closes the server and terminates all clients.
* @method
* @return {Promise}
*/
close(): Promise<void>;
/**
* Handles all WebSocket JSON RPC 2.0 requests.
* @private
* @param {Object} socket - ws socket instance
* @param {String} ns - namespaces identifier
* @return {Undefined}
*/
private _handleRPC;
/**
* Runs a defined RPC method.
* @private
* @param {Object} message - a message received
* @param {Object} socket_id - user's socket id
* @param {String} ns - namespaces identifier
* @return {Object|undefined}
*/
private _runMethod;
/**
* Generate a new namespace store.
* Also preregister some special namespace methods.
* @private
* @param {String} name - namespaces identifier
* @return {undefined}
*/
private _generateNamespace;
}
/**
* Creates a JSON-RPC 2.0-compliant error.
* @param {Number} code - error code
* @param {String} details - error details
* @return {Object}
*/
declare function createError(code: number, details?: string): IRPCError;
/**
* WebSocket implements a browser-side WebSocket specification.
* @module Client
*/
type WebSocketBrowserOptions = {
/**
* One or more protocols passed to the websocket constructor
* @link https://developer.mozilla.org/en-US/docs/Web/API/WebSocket/WebSocket
*/
protocols?: string | string[];
};
declare class Client extends CommonClient {
constructor(address?: string, { autoconnect, reconnect, reconnect_interval, max_reconnects, ...rest_options }?: IWSClientAdditionalOptions & NodeWebSocketTypeOptions, generate_request_id?: (method: string, params: object | Array<any>) => number | string);
}
export { type BrowserWebSocketType, Client, CommonClient, type DataPack, DefaultDataPack, type ICommonWebSocket, type ICommonWebSocketFactory, type IQueue, type IWSClientAdditionalOptions, type IWSRequestParams, type NodeWebSocketType, type NodeWebSocketTypeOptions, Server, WebSocket$1 as WebSocket, type WebSocketBrowserOptions, createError };

926
node_modules/rpc-websockets/dist/index.mjs generated vendored Normal file
View File

@@ -0,0 +1,926 @@
import WebSocketImpl, { WebSocketServer } from 'ws';
import { EventEmitter } from 'eventemitter3';
import url from 'url';
import { v1 } from 'uuid';
// src/lib/client/websocket.ts
function WebSocket(address, options) {
return new WebSocketImpl(address, options);
}
// src/lib/utils.ts
var DefaultDataPack = class {
encode(value) {
return JSON.stringify(value);
}
decode(value) {
return JSON.parse(value);
}
};
// src/lib/client.ts
var CommonClient = class extends EventEmitter {
address;
rpc_id;
queue;
options;
autoconnect;
ready;
reconnect;
reconnect_timer_id;
reconnect_interval;
max_reconnects;
rest_options;
current_reconnects;
generate_request_id;
socket;
webSocketFactory;
dataPack;
/**
* Instantiate a Client class.
* @constructor
* @param {webSocketFactory} webSocketFactory - factory method for WebSocket
* @param {String} address - url to a websocket server
* @param {Object} options - ws options object with reconnect parameters
* @param {Function} generate_request_id - custom generation request Id
* @param {DataPack} dataPack - data pack contains encoder and decoder
* @return {CommonClient}
*/
constructor(webSocketFactory, address = "ws://localhost:8080", {
autoconnect = true,
reconnect = true,
reconnect_interval = 1e3,
max_reconnects = 5,
...rest_options
} = {}, generate_request_id, dataPack) {
super();
this.webSocketFactory = webSocketFactory;
this.queue = {};
this.rpc_id = 0;
this.address = address;
this.autoconnect = autoconnect;
this.ready = false;
this.reconnect = reconnect;
this.reconnect_timer_id = void 0;
this.reconnect_interval = reconnect_interval;
this.max_reconnects = max_reconnects;
this.rest_options = rest_options;
this.current_reconnects = 0;
this.generate_request_id = generate_request_id || (() => typeof this.rpc_id === "number" ? ++this.rpc_id : Number(this.rpc_id) + 1);
if (!dataPack) this.dataPack = new DefaultDataPack();
else this.dataPack = dataPack;
if (this.autoconnect)
this._connect(this.address, {
autoconnect: this.autoconnect,
reconnect: this.reconnect,
reconnect_interval: this.reconnect_interval,
max_reconnects: this.max_reconnects,
...this.rest_options
});
}
/**
* Connects to a defined server if not connected already.
* @method
* @return {Undefined}
*/
connect() {
if (this.socket) return;
this._connect(this.address, {
autoconnect: this.autoconnect,
reconnect: this.reconnect,
reconnect_interval: this.reconnect_interval,
max_reconnects: this.max_reconnects,
...this.rest_options
});
}
/**
* Calls a registered RPC method on server.
* @method
* @param {String} method - RPC method name
* @param {Object|Array} params - optional method parameters
* @param {Number} timeout - RPC reply timeout value
* @param {Object} ws_opts - options passed to ws
* @return {Promise}
*/
call(method, params, timeout, ws_opts) {
if (!ws_opts && "object" === typeof timeout) {
ws_opts = timeout;
timeout = null;
}
return new Promise((resolve, reject) => {
if (!this.ready) return reject(new Error("socket not ready"));
const rpc_id = this.generate_request_id(method, params);
const message = {
jsonrpc: "2.0",
method,
params: params || void 0,
id: rpc_id
};
this.socket.send(this.dataPack.encode(message), ws_opts, (error) => {
if (error) return reject(error);
this.queue[rpc_id] = { promise: [resolve, reject] };
if (timeout) {
this.queue[rpc_id].timeout = setTimeout(() => {
delete this.queue[rpc_id];
reject(new Error("reply timeout"));
}, timeout);
}
});
});
}
/**
* Logins with the other side of the connection.
* @method
* @param {Object} params - Login credentials object
* @return {Promise}
*/
async login(params) {
const resp = await this.call("rpc.login", params);
if (!resp) throw new Error("authentication failed");
return resp;
}
/**
* Fetches a list of client's methods registered on server.
* @method
* @return {Array}
*/
async listMethods() {
return await this.call("__listMethods");
}
/**
* Sends a JSON-RPC 2.0 notification to server.
* @method
* @param {String} method - RPC method name
* @param {Object} params - optional method parameters
* @return {Promise}
*/
notify(method, params) {
return new Promise((resolve, reject) => {
if (!this.ready) return reject(new Error("socket not ready"));
const message = {
jsonrpc: "2.0",
method,
params
};
this.socket.send(this.dataPack.encode(message), (error) => {
if (error) return reject(error);
resolve();
});
});
}
/**
* Subscribes for a defined event.
* @method
* @param {String|Array} event - event name
* @return {Undefined}
* @throws {Error}
*/
async subscribe(event) {
if (typeof event === "string") event = [event];
const result = await this.call("rpc.on", event);
if (typeof event === "string" && result[event] !== "ok")
throw new Error(
"Failed subscribing to an event '" + event + "' with: " + result[event]
);
return result;
}
/**
* Unsubscribes from a defined event.
* @method
* @param {String|Array} event - event name
* @return {Undefined}
* @throws {Error}
*/
async unsubscribe(event) {
if (typeof event === "string") event = [event];
const result = await this.call("rpc.off", event);
if (typeof event === "string" && result[event] !== "ok")
throw new Error("Failed unsubscribing from an event with: " + result);
return result;
}
/**
* Closes a WebSocket connection gracefully.
* @method
* @param {Number} code - socket close code
* @param {String} data - optional data to be sent before closing
* @return {Undefined}
*/
close(code, data) {
if (this.socket) this.socket.close(code || 1e3, data);
}
/**
* Enable / disable automatic reconnection.
* @method
* @param {Boolean} reconnect - enable / disable reconnection
* @return {Undefined}
*/
setAutoReconnect(reconnect) {
this.reconnect = reconnect;
}
/**
* Set the interval between reconnection attempts.
* @method
* @param {Number} interval - reconnection interval in milliseconds
* @return {Undefined}
*/
setReconnectInterval(interval) {
this.reconnect_interval = interval;
}
/**
* Set the maximum number of reconnection attempts.
* @method
* @param {Number} max_reconnects - maximum reconnection attempts
* @return {Undefined}
*/
setMaxReconnects(max_reconnects) {
this.max_reconnects = max_reconnects;
}
/**
* Get the current number of reconnection attempts made.
* @method
* @return {Number} current reconnection attempts
*/
getCurrentReconnects() {
return this.current_reconnects;
}
/**
* Get the maximum number of reconnection attempts.
* @method
* @return {Number} maximum reconnection attempts
*/
getMaxReconnects() {
return this.max_reconnects;
}
/**
* Check if the client is currently attempting to reconnect.
* @method
* @return {Boolean} true if reconnection is in progress
*/
isReconnecting() {
return this.reconnect_timer_id !== void 0;
}
/**
* Check if the client will attempt to reconnect on the next close event.
* @method
* @return {Boolean} true if reconnection will be attempted
*/
willReconnect() {
return this.reconnect && (this.max_reconnects === 0 || this.current_reconnects < this.max_reconnects);
}
/**
* Connection/Message handler.
* @method
* @private
* @param {String} address - WebSocket API address
* @param {Object} options - ws options object
* @return {Undefined}
*/
_connect(address, options) {
clearTimeout(this.reconnect_timer_id);
this.socket = this.webSocketFactory(address, options);
this.socket.addEventListener("open", () => {
this.ready = true;
this.emit("open");
this.current_reconnects = 0;
});
this.socket.addEventListener("message", ({ data: message }) => {
if (message instanceof ArrayBuffer)
message = Buffer.from(message).toString();
try {
message = this.dataPack.decode(message);
} catch (_error) {
return;
}
if (message.notification && this.listeners(message.notification).length) {
if (!Object.keys(message.params).length)
return this.emit(message.notification);
const args = [message.notification];
if (message.params.constructor === Object) args.push(message.params);
else
for (let i = 0; i < message.params.length; i++)
args.push(message.params[i]);
return Promise.resolve().then(() => {
this.emit.apply(this, args);
});
}
if (!this.queue[message.id]) {
if (message.method) {
return Promise.resolve().then(() => {
this.emit(message.method, message?.params);
});
}
return;
}
if ("error" in message === "result" in message)
this.queue[message.id].promise[1](
new Error(
'Server response malformed. Response must include either "result" or "error", but not both.'
)
);
if (this.queue[message.id].timeout)
clearTimeout(this.queue[message.id].timeout);
if (message.error) this.queue[message.id].promise[1](message.error);
else this.queue[message.id].promise[0](message.result);
delete this.queue[message.id];
});
this.socket.addEventListener("error", (error) => this.emit("error", error));
this.socket.addEventListener("close", ({ code, reason }) => {
if (this.ready)
setTimeout(() => this.emit("close", code, reason), 0);
this.ready = false;
this.socket = void 0;
if (code === 1e3) return;
this.current_reconnects++;
if (this.reconnect && (this.max_reconnects > this.current_reconnects || this.max_reconnects === 0))
this.reconnect_timer_id = setTimeout(
() => this._connect(address, options),
this.reconnect_interval
);
else if (this.reconnect && this.max_reconnects > 0 && this.current_reconnects >= this.max_reconnects) {
setTimeout(() => this.emit("max_reconnects_reached", code, reason), 1);
}
});
}
};
var Server = class extends EventEmitter {
namespaces;
dataPack;
wss;
/**
* Instantiate a Server class.
* @constructor
* @param {Object} options - ws constructor's parameters with rpc
* @param {DataPack} dataPack - data pack contains encoder and decoder
* @return {Server} - returns a new Server instance
*/
constructor(options, dataPack) {
super();
this.namespaces = {};
if (!dataPack) this.dataPack = new DefaultDataPack();
else this.dataPack = dataPack;
this.wss = new WebSocketServer(options);
this.wss.on("listening", () => this.emit("listening"));
this.wss.on("connection", (socket, request) => {
const u = url.parse(request.url, true);
const ns = u.pathname;
if (u.query.socket_id) socket._id = u.query.socket_id;
else socket._id = v1();
socket["_authenticated"] = false;
socket.on("error", (error) => this.emit("socket-error", socket, error));
socket.on("close", () => {
this.namespaces[ns].clients.delete(socket._id);
for (const event of Object.keys(this.namespaces[ns].events)) {
const index = this.namespaces[ns].events[event].sockets.indexOf(
socket._id
);
if (index >= 0)
this.namespaces[ns].events[event].sockets.splice(index, 1);
}
this.emit("disconnection", socket);
});
if (!this.namespaces[ns]) this._generateNamespace(ns);
this.namespaces[ns].clients.set(socket._id, socket);
this.emit("connection", socket, request);
return this._handleRPC(socket, ns);
});
this.wss.on("error", (error) => this.emit("error", error));
}
/**
* Registers an RPC method.
* @method
* @param {String} name - method name
* @param {Function} fn - a callee function
* @param {String} ns - namespace identifier
* @throws {TypeError}
* @return {Object} - returns an IMethod object
*/
register(name, fn, ns = "/") {
if (!this.namespaces[ns]) this._generateNamespace(ns);
this.namespaces[ns].rpc_methods[name] = {
fn,
protected: false
};
return {
protected: () => this._makeProtectedMethod(name, ns),
public: () => this._makePublicMethod(name, ns)
};
}
/**
* Sets an auth method.
* @method
* @param {Function} fn - an arbitrary auth method
* @param {String} ns - namespace identifier
* @throws {TypeError}
* @return {Undefined}
*/
setAuth(fn, ns = "/") {
this.register("rpc.login", fn, ns);
}
/**
* Marks an RPC method as protected.
* @method
* @param {String} name - method name
* @param {String} ns - namespace identifier
* @return {Undefined}
*/
_makeProtectedMethod(name, ns = "/") {
this.namespaces[ns].rpc_methods[name].protected = true;
}
/**
* Marks an RPC method as public.
* @method
* @param {String} name - method name
* @param {String} ns - namespace identifier
* @return {Undefined}
*/
_makePublicMethod(name, ns = "/") {
this.namespaces[ns].rpc_methods[name].protected = false;
}
/**
* Marks an event as protected.
* @method
* @param {String} name - event name
* @param {String} ns - namespace identifier
* @return {Undefined}
*/
_makeProtectedEvent(name, ns = "/") {
this.namespaces[ns].events[name].protected = true;
}
/**
* Marks an event as public.
* @method
* @param {String} name - event name
* @param {String} ns - namespace identifier
* @return {Undefined}
*/
_makePublicEvent(name, ns = "/") {
this.namespaces[ns].events[name].protected = false;
}
/**
* Removes a namespace and closes all connections
* @method
* @param {String} ns - namespace identifier
* @throws {TypeError}
* @return {Undefined}
*/
closeNamespace(ns) {
const namespace = this.namespaces[ns];
if (namespace) {
delete namespace.rpc_methods;
delete namespace.events;
for (const socket of namespace.clients.values()) socket.close();
delete this.namespaces[ns];
}
}
/**
* Creates a new event that can be emitted to clients.
* @method
* @param {String} name - event name
* @param {String} ns - namespace identifier
* @throws {TypeError}
* @return {Object} - returns an IEvent object
*/
event(name, ns = "/") {
if (!this.namespaces[ns]) this._generateNamespace(ns);
else {
const index = this.namespaces[ns].events[name];
if (index !== void 0)
throw new Error(`Already registered event ${ns}${name}`);
}
this.namespaces[ns].events[name] = {
sockets: [],
protected: false
};
this.on(name, (...params) => {
if (params.length === 1 && params[0] instanceof Object)
params = params[0];
for (const socket_id of this.namespaces[ns].events[name].sockets) {
const socket = this.namespaces[ns].clients.get(socket_id);
if (!socket) continue;
socket.send(
this.dataPack.encode({
notification: name,
params
})
);
}
});
return {
protected: () => this._makeProtectedEvent(name, ns),
public: () => this._makePublicEvent(name, ns)
};
}
/**
* Returns a requested namespace object
* @method
* @param {String} name - namespace identifier
* @throws {TypeError}
* @return {Object} - namespace object
*/
of(name) {
if (!this.namespaces[name]) this._generateNamespace(name);
const self = this;
return {
// self.register convenience method
register(fn_name, fn) {
if (arguments.length !== 2)
throw new Error("must provide exactly two arguments");
if (typeof fn_name !== "string")
throw new Error("name must be a string");
if (typeof fn !== "function")
throw new Error("handler must be a function");
return self.register(fn_name, fn, name);
},
// self.event convenience method
event(ev_name) {
if (arguments.length !== 1)
throw new Error("must provide exactly one argument");
if (typeof ev_name !== "string")
throw new Error("name must be a string");
return self.event(ev_name, name);
},
// self.eventList convenience method
get eventList() {
return Object.keys(self.namespaces[name].events);
},
/**
* Emits a specified event to this namespace.
* @inner
* @method
* @param {String} event - event name
* @param {Array} params - event parameters
* @return {Undefined}
*/
emit(event, ...params) {
const nsEvent = self.namespaces[name].events[event];
if (nsEvent)
for (const socket_id of nsEvent.sockets) {
const socket = self.namespaces[name].clients.get(socket_id);
if (!socket) continue;
socket.send(
self.dataPack.encode({
notification: event,
params
})
);
}
},
/**
* Returns a name of this namespace.
* @inner
* @method
* @kind constant
* @return {String}
*/
get name() {
return name;
},
/**
* Returns a hash of websocket objects connected to this namespace.
* @inner
* @method
* @return {Object}
*/
connected() {
const socket_ids = [...self.namespaces[name].clients.keys()];
return socket_ids.reduce(
(acc, curr) => ({
...acc,
[curr]: self.namespaces[name].clients.get(curr)
}),
{}
);
},
/**
* Returns a list of client unique identifiers connected to this namespace.
* @inner
* @method
* @return {Array}
*/
clients() {
return self.namespaces[name];
}
};
}
/**
* Lists all created events in a given namespace. Defaults to "/".
* @method
* @param {String} ns - namespaces identifier
* @readonly
* @return {Array} - returns a list of created events
*/
eventList(ns = "/") {
if (!this.namespaces[ns]) return [];
return Object.keys(this.namespaces[ns].events);
}
/**
* Creates a JSON-RPC 2.0 compliant error
* @method
* @param {Number} code - indicates the error type that occurred
* @param {String} message - provides a short description of the error
* @param {String|Object} data - details containing additional information about the error
* @return {Object}
*/
createError(code, message, data) {
return {
code,
message,
data: data || null
};
}
/**
* Closes the server and terminates all clients.
* @method
* @return {Promise}
*/
close() {
return new Promise((resolve, reject) => {
try {
this.wss.close();
this.emit("close");
resolve();
} catch (error) {
reject(error);
}
});
}
/**
* Handles all WebSocket JSON RPC 2.0 requests.
* @private
* @param {Object} socket - ws socket instance
* @param {String} ns - namespaces identifier
* @return {Undefined}
*/
_handleRPC(socket, ns = "/") {
socket.on("message", async (data) => {
const msg_options = {};
if (data instanceof ArrayBuffer) {
msg_options.binary = true;
data = Buffer.from(data).toString();
}
if (socket.readyState !== 1) return;
let parsedData;
try {
parsedData = this.dataPack.decode(data);
} catch (error) {
return socket.send(
this.dataPack.encode({
jsonrpc: "2.0",
error: createError(-32700, error.toString()),
id: null
}),
msg_options
);
}
if (Array.isArray(parsedData)) {
if (!parsedData.length)
return socket.send(
this.dataPack.encode({
jsonrpc: "2.0",
error: createError(-32600, "Invalid array"),
id: null
}),
msg_options
);
const responses = [];
for (const message of parsedData) {
const response2 = await this._runMethod(message, socket._id, ns);
if (!response2) continue;
responses.push(response2);
}
if (!responses.length) return;
return socket.send(this.dataPack.encode(responses), msg_options);
}
const response = await this._runMethod(parsedData, socket._id, ns);
if (!response) return;
return socket.send(this.dataPack.encode(response), msg_options);
});
}
/**
* Runs a defined RPC method.
* @private
* @param {Object} message - a message received
* @param {Object} socket_id - user's socket id
* @param {String} ns - namespaces identifier
* @return {Object|undefined}
*/
async _runMethod(message, socket_id, ns = "/") {
if (typeof message !== "object" || message === null)
return {
jsonrpc: "2.0",
error: createError(-32600),
id: null
};
if (message.jsonrpc !== "2.0")
return {
jsonrpc: "2.0",
error: createError(-32600, "Invalid JSON RPC version"),
id: message.id || null
};
if (!message.method)
return {
jsonrpc: "2.0",
error: createError(-32602, "Method not specified"),
id: message.id || null
};
if (typeof message.method !== "string")
return {
jsonrpc: "2.0",
error: createError(-32600, "Invalid method name"),
id: message.id || null
};
if (message.params && typeof message.params === "string")
return {
jsonrpc: "2.0",
error: createError(-32600),
id: message.id || null
};
if (message.method === "rpc.on") {
if (!message.params)
return {
jsonrpc: "2.0",
error: createError(-32e3),
id: message.id || null
};
const results = {};
const event_names = Object.keys(this.namespaces[ns].events);
for (const name of message.params) {
const index = event_names.indexOf(name);
const namespace = this.namespaces[ns];
if (index === -1) {
results[name] = "provided event invalid";
continue;
}
if (namespace.events[event_names[index]].protected === true && namespace.clients.get(socket_id)["_authenticated"] === false) {
return {
jsonrpc: "2.0",
error: createError(-32606),
id: message.id || null
};
}
const socket_index = namespace.events[event_names[index]].sockets.indexOf(socket_id);
if (socket_index >= 0) {
results[name] = "socket has already been subscribed to event";
continue;
}
namespace.events[event_names[index]].sockets.push(socket_id);
results[name] = "ok";
}
return {
jsonrpc: "2.0",
result: results,
id: message.id || null
};
} else if (message.method === "rpc.off") {
if (!message.params)
return {
jsonrpc: "2.0",
error: createError(-32e3),
id: message.id || null
};
const results = {};
for (const name of message.params) {
if (!this.namespaces[ns].events[name]) {
results[name] = "provided event invalid";
continue;
}
const index = this.namespaces[ns].events[name].sockets.indexOf(socket_id);
if (index === -1) {
results[name] = "not subscribed";
continue;
}
this.namespaces[ns].events[name].sockets.splice(index, 1);
results[name] = "ok";
}
return {
jsonrpc: "2.0",
result: results,
id: message.id || null
};
} else if (message.method === "rpc.login") {
if (!message.params)
return {
jsonrpc: "2.0",
error: createError(-32604),
id: message.id || null
};
}
if (!this.namespaces[ns].rpc_methods[message.method]) {
return {
jsonrpc: "2.0",
error: createError(-32601),
id: message.id || null
};
}
let response = null;
if (this.namespaces[ns].rpc_methods[message.method].protected === true && this.namespaces[ns].clients.get(socket_id)["_authenticated"] === false) {
return {
jsonrpc: "2.0",
error: createError(-32605),
id: message.id || null
};
}
try {
response = await this.namespaces[ns].rpc_methods[message.method].fn(
message.params,
socket_id
);
} catch (error) {
if (!message.id) return;
if (error instanceof Error)
return {
jsonrpc: "2.0",
error: {
code: -32e3,
message: error.name,
data: error.message
},
id: message.id
};
return {
jsonrpc: "2.0",
error,
id: message.id
};
}
if (!message.id) return;
if (message.method === "rpc.login" && response === true) {
const s = this.namespaces[ns].clients.get(socket_id);
if (s) {
s["_authenticated"] = true;
this.namespaces[ns].clients.set(socket_id, s);
}
}
return {
jsonrpc: "2.0",
result: response,
id: message.id
};
}
/**
* Generate a new namespace store.
* Also preregister some special namespace methods.
* @private
* @param {String} name - namespaces identifier
* @return {undefined}
*/
_generateNamespace(name) {
this.namespaces[name] = {
rpc_methods: {
__listMethods: {
fn: () => Object.keys(this.namespaces[name].rpc_methods),
protected: false
}
},
clients: /* @__PURE__ */ new Map(),
events: {}
};
}
};
var RPC_ERRORS = /* @__PURE__ */ new Map([
[-32e3, "Event not provided"],
[-32600, "Invalid Request"],
[-32601, "Method not found"],
[-32602, "Invalid params"],
[-32603, "Internal error"],
[-32604, "Params not found"],
[-32605, "Method forbidden"],
[-32606, "Event forbidden"],
[-32700, "Parse error"]
]);
function createError(code, details) {
const error = {
code,
message: RPC_ERRORS.get(code) || "Internal Server Error"
};
if (details) error["data"] = details;
return error;
}
// src/index.ts
var Client = class extends CommonClient {
constructor(address = "ws://localhost:8080", {
autoconnect = true,
reconnect = true,
reconnect_interval = 1e3,
max_reconnects = 5,
...rest_options
} = {}, generate_request_id) {
super(
WebSocket,
address,
{
autoconnect,
reconnect,
reconnect_interval,
max_reconnects,
...rest_options
},
generate_request_id
);
}
};
export { Client, CommonClient, DefaultDataPack, Server, WebSocket, createError };
//# sourceMappingURL=index.mjs.map
//# sourceMappingURL=index.mjs.map

1
node_modules/rpc-websockets/dist/index.mjs.map generated vendored Normal file

File diff suppressed because one or more lines are too long