@akala/json-rpc-ws
Version:
json-rpc websocket transport
132 lines (131 loc) • 5.68 kB
TypeScript
import { type Error as ConnectionError, type ErrorTypes } from './errors.js';
import type { EventListener, SerializableObject, SocketAdapter, SocketAdapterAkalaEventMap, SocketAdapterEventMap, Subscription } from '@akala/core';
import { SocketProtocolAdapter } from '@akala/core';
export type PayloadDataType<T> = number | SerializableObject | SerializableObject[] | boolean | boolean[] | number[] | string | string[] | null | undefined | void | {
event: string;
isBuffer: boolean;
data: string | SerializedBuffer;
} | T;
export type SerializedBuffer = {
type: 'Buffer';
data: Uint8Array | number[];
};
export type Payload<T> = SerializablePayload | StreamPayload<T>;
export declare class JsonRpcSocketAdapter<TStreamable> extends SocketProtocolAdapter<Payload<TStreamable> | Payload<TStreamable>[]> implements SocketAdapter<Payload<TStreamable>> {
constructor(socket: SocketAdapter);
}
interface CommonPayload {
jsonrpc?: '2.0';
id?: string | number;
method?: string;
error?: ConnectionError;
}
export interface SerializablePayload extends CommonPayload {
params?: PayloadDataType<void>;
result?: PayloadDataType<void>;
stream?: false;
}
export interface StreamPayload<T> extends CommonPayload {
params?: T;
result?: PayloadDataType<T>;
stream?: true;
}
export type Handler<TConnection extends Connection<TStreamable>, TStreamable, ParamType extends PayloadDataType<TStreamable>, ParamCallbackType extends PayloadDataType<TStreamable>> = (this: TConnection, params: ParamType, reply: ReplyCallback<ParamCallbackType>) => void;
export type ReplyCallback<ParamType> = (error: ConnectionError, params?: ParamType) => void;
export interface Parent<TStreamable, TConnection extends Connection<TStreamable>> {
type: string;
getHandler: (method: string) => Handler<TConnection, TStreamable, PayloadDataType<TStreamable>, PayloadDataType<TStreamable>>;
disconnected: (connection: TConnection) => void;
}
/**
* json-rpc-ws connection
*
* @constructor
* @param {SocketAdapter} socket - socket adapter for this connection
* @param {Object} parent - parent that controls this connection
*/
export declare abstract class Connection<TStreamable> {
readonly socket: SocketAdapter<Payload<TStreamable>>;
readonly parent: Parent<TStreamable, Connection<TStreamable>>;
sub: Subscription;
/**
*
*/
constructor(socket: SocketAdapter<Payload<TStreamable>>, parent: Parent<TStreamable, Connection<TStreamable>>);
on<K extends keyof SocketAdapterEventMap>(event: K, handler: EventListener<SocketAdapterAkalaEventMap<Payload<TStreamable>>[K]>): Subscription;
once<K extends keyof SocketAdapterEventMap>(event: K, handler: EventListener<SocketAdapterAkalaEventMap<Payload<TStreamable>>[K]>): Subscription;
readonly id: `${string}-${string}-${string}-${string}-${string}`;
protected readonly responseHandlers: {
[messageId: string]: ReplyCallback<unknown>;
};
/**
* Send json payload to the socket connection
*
* @param {Object} payload - data to be stringified
* @private
* @todo validate payload
* @todo make sure this.connection exists, is connected
* @todo if we're not connected look up the response handler from payload.id
*/
sendRaw(payload: Payload<TStreamable>): void;
/**
* Validate payload as valid jsonrpc 2.0
* http://www.jsonrpc.org/specification
* Reply or delegate as needed
*
* @param {Object} payload - payload coming in to be validated
* @returns {void}
*/
processPayload(payload: Payload<TStreamable>): void;
protected abstract buildStream(id: string | number, result: PayloadDataType<TStreamable>): TStreamable;
protected abstract sendStream(id: string | number, result: TStreamable): Promise<void> | void;
protected abstract isStream(result: PayloadDataType<TStreamable>): result is TStreamable;
/**
* Send a result message
*
* @param {String} id - id for the message
* @param {Object} error - error for the message
* @param {String|Object|Array|Number} result - result for the message
* @public
*
*/
sendResult(id: string | number | undefined, error: ConnectionError | undefined, result?: PayloadDataType<TStreamable>, isStream?: boolean): void;
/**
* Send a method message
*
* @param {String} method - method for the message
* @param {Array|Object|null} params - params for the message
* @param {function} callback - optional callback for a reply from the message
* @public
*/
sendMethod<TParamType extends PayloadDataType<TStreamable>, TReplyType extends PayloadDataType<TStreamable>>(method: string, params?: TParamType, callback?: ReplyCallback<TReplyType>): void;
/**
* Send an error message
*
* @param {Object} error - json-rpc error object (See Connection.errors)
* @param {String|Number|null} id - Optional id for reply
* @param {Any} data - Optional value for data portion of reply
* @public
*/
sendError(error: ErrorTypes, id: number | string | undefined, data?: SerializableObject): void;
/**
* Called when socket gets 'close' event
*
* @param {ConnectionError} error - optional error object of close wasn't expected
* @private
*/
close(error?: ConnectionError | 1000 | Error | Event): void;
/**
* Hang up the current socket
*/
hangup(): Promise<CloseEvent>;
/**
* Incoming message handler
*
* @param {String} data - message from the websocket
* @returns {void}
* @private
*/
private message;
}
export {};