/** * Represents an object providing methods to serialize (format) and deserialize * (parse) message payloads. * * @see MessageFormatter * @see MessageParser */ export interface MessageFormat { formatter: MessageFormatter; parser: MessageParser; } /** * Serializes message payload into a binary or text format that can be sent * over the WebSocket. */ export type MessageFormatter = ( message: TSend, ) => string | ArrayBufferLike | Blob | ArrayBufferView; export type RecvIgnore = typeof recvIgnoreTag; /** * Parses message payload. If parser throws, the `recverror` event is * dispatched by the WebSocketClient. If parser returns * {@link recvIgnore `recvIgnore()`} special value, the message is ignored and * no `message` event is dispatched. Any other value returned by the parser is * considered a message payload. */ export type MessageParser = (data: any) => TRecv | RecvIgnore; export interface SendOptions { ws: WebSocket; format: Pick, "formatter">; } export function send(message: TSend, options: SendOptions): void { const data = options.format.formatter(message); options.ws.send(data); } export interface RecvOptions { format: Pick, "parser">; } export type RecvResult = | { type: "message"; message: TRecv } | { type: "ignore" } | { type: "error"; error: any }; export function recv( event: MessageEvent, options: RecvOptions, ): RecvResult { try { const message = options.format.parser(event.data); return message !== recvIgnoreTag ? { type: "message", message } : { type: "ignore" }; } catch (err) { return { type: "error", error: err }; } } const recvIgnoreTag: unique symbol = Symbol("recvIgnoreTag"); /** * Special value that can be returned by parser to prevent the `message` event * from being dispatched. Useful for creating lenient parsers that skip * unparseable payloads: * * ```ts * const parser: MessageParser = (data) => { * if (typeof data === 'string') { * const parsed = Number.parseInt(data, 10); * return Number.isFinite(parsed) ? parsed : recvIgnore(); * } * * return recvIgnore(); * } * ``` */ export function recvIgnore(): typeof recvIgnoreTag { return recvIgnoreTag; }