diff --git a/biome.json b/biome.json new file mode 100644 index 0000000..99d3350 --- /dev/null +++ b/biome.json @@ -0,0 +1,31 @@ +{ + "$schema": "https://biomejs.dev/schemas/1.9.4/schema.json", + "vcs": { + "enabled": false, + "clientKind": "git", + "useIgnoreFile": true + }, + "files": { + "ignoreUnknown": false, + "ignore": ["dist", ".next", "public", "*.d.ts", "*.json"] + }, + "formatter": { + "enabled": true, + "indentStyle": "space", + "indentWidth": 2 + }, + "organizeImports": { + "enabled": true + }, + "linter": { + "enabled": true, + "rules": { + "recommended": true + } + }, + "javascript": { + "formatter": { + "quoteStyle": "double" + } + } +} diff --git a/build.ts b/build.ts index c3da698..b044b59 100644 --- a/build.ts +++ b/build.ts @@ -1,8 +1,8 @@ import dts from "bun-plugin-dts"; await Bun.build({ - entrypoints: ["./src/index.ts"], - outdir: "./dist", - plugins: [dts()], - target: "browser", + entrypoints: ["./src/index.ts"], + outdir: "./dist", + plugins: [dts()], + target: "browser", }); diff --git a/bun.lockb b/bun.lockb index e8b49fb..ff63894 100755 Binary files a/bun.lockb and b/bun.lockb differ diff --git a/package.json b/package.json index db12c74..516e5dc 100644 --- a/package.json +++ b/package.json @@ -15,6 +15,7 @@ ], "type": "module", "devDependencies": { + "@biomejs/biome": "^1.9.4", "@types/bun": "latest", "bun-plugin-dts": "^0.2.3" }, diff --git a/src/constants.ts b/src/constants.ts index c1ce8f3..5cc91b9 100644 --- a/src/constants.ts +++ b/src/constants.ts @@ -1,31 +1,31 @@ export enum SocketDisconnectCode { - CLOSE_NORMAL = 1000, - CLOSE_GOING_AWAY = 1001, - CLOSE_PROTOCOL_ERROR = 1002, - CLOSE_UNSUPPORTED = 1003, - CLOSE_NO_STATUS = 1005, - CLOSE_ABNORMAL = 1006, - CLOSE_TOO_LARGE = 1009, - CLOSE_EXTENSION_REQUIRED = 1010, - CLOSE_INTERNAL_ERROR = 1011, - CLOSE_SERVICE_RESTART = 1012, - CLOSE_TRY_AGAIN_LATER = 1013, - CLOSE_TLS_HANDSHAKE = 1015, + CLOSE_NORMAL = 1000, + CLOSE_GOING_AWAY = 1001, + CLOSE_PROTOCOL_ERROR = 1002, + CLOSE_UNSUPPORTED = 1003, + CLOSE_NO_STATUS = 1005, + CLOSE_ABNORMAL = 1006, + CLOSE_TOO_LARGE = 1009, + CLOSE_EXTENSION_REQUIRED = 1010, + CLOSE_INTERNAL_ERROR = 1011, + CLOSE_SERVICE_RESTART = 1012, + CLOSE_TRY_AGAIN_LATER = 1013, + CLOSE_TLS_HANDSHAKE = 1015, } export const NON_RECONNECT_CODES = [ - SocketDisconnectCode.CLOSE_NORMAL, - SocketDisconnectCode.CLOSE_GOING_AWAY, - SocketDisconnectCode.CLOSE_UNSUPPORTED, - SocketDisconnectCode.CLOSE_TOO_LARGE, - SocketDisconnectCode.CLOSE_EXTENSION_REQUIRED, - SocketDisconnectCode.CLOSE_TRY_AGAIN_LATER, - SocketDisconnectCode.CLOSE_TLS_HANDSHAKE, + SocketDisconnectCode.CLOSE_NORMAL, + SocketDisconnectCode.CLOSE_GOING_AWAY, + SocketDisconnectCode.CLOSE_UNSUPPORTED, + SocketDisconnectCode.CLOSE_TOO_LARGE, + SocketDisconnectCode.CLOSE_EXTENSION_REQUIRED, + SocketDisconnectCode.CLOSE_TRY_AGAIN_LATER, + SocketDisconnectCode.CLOSE_TLS_HANDSHAKE, ] as const; export enum ManagedSocketErrorType { - INVALID_MESSAGE_SHAPE = "Invalid message shape.", - CATOSTROPHIC_CLOSE = "Catostrophic close code", - SOCKET_ERROR = "WebSocket error", - CONNECTION_REJECTED = "Connection rejected", + INVALID_MESSAGE_SHAPE = "Invalid message shape.", + CATOSTROPHIC_CLOSE = "Catostrophic close code", + SOCKET_ERROR = "WebSocket error", + CONNECTION_REJECTED = "Connection rejected", } diff --git a/src/errors.ts b/src/errors.ts index 6acea1f..cbaa694 100644 --- a/src/errors.ts +++ b/src/errors.ts @@ -1,17 +1,17 @@ import { ManagedSocketErrorType } from "./constants"; export class ManagedSocketError extends Error { - public originalError: Error | ErrorEvent; - public type: ManagedSocketErrorType = ManagedSocketErrorType.SOCKET_ERROR; + public originalError: Error | ErrorEvent; + public type: ManagedSocketErrorType = ManagedSocketErrorType.SOCKET_ERROR; - constructor( - message: string, - originalError: Error | ErrorEvent, - type?: ManagedSocketErrorType, - ) { - super(message); - this.name = "ManagedSocketError"; - this.originalError = originalError; - this.type = type ?? this.type; - } + constructor( + message: string, + originalError: Error | ErrorEvent, + type?: ManagedSocketErrorType, + ) { + super(message); + this.name = "ManagedSocketError"; + this.originalError = originalError; + this.type = type ?? this.type; + } } diff --git a/src/index.ts b/src/index.ts index 246bf58..a0ebfc5 100644 --- a/src/index.ts +++ b/src/index.ts @@ -1,12 +1,12 @@ +import { ManagedSocketErrorType, SocketDisconnectCode } from "./constants"; import { ManagedSocketError } from "./errors"; -import { SocketSpeak } from "./messages"; -import { SocketDisconnectCode, ManagedSocketErrorType } from "./constants"; import { ManagedSocket } from "./managed-socket"; +import { SocketSpeak } from "./messages"; export { - SocketSpeak, - ManagedSocket, - ManagedSocketError, - SocketDisconnectCode, - ManagedSocketErrorType, + SocketSpeak, + ManagedSocket, + ManagedSocketError, + SocketDisconnectCode, + ManagedSocketErrorType, }; diff --git a/src/managed-socket.ts b/src/managed-socket.ts index b67a46a..f9cdc54 100644 --- a/src/managed-socket.ts +++ b/src/managed-socket.ts @@ -13,231 +13,231 @@ type SocketCloseHandler = () => void; type SocketCatostrophicErrorHandler = (error: ManagedSocketError) => void; export type ManagedSocketConnectionState = - | "connecting" - | "open" - | "closing" - | "closed" - | "reconnecting" - | "terminated"; + | "connecting" + | "open" + | "closing" + | "closed" + | "reconnecting" + | "terminated"; export class ManagedSocket { - public readonly url: string; - public state: ManagedSocketConnectionState = "connecting"; - private ws: WebSocket; + public readonly url: string; + public state: ManagedSocketConnectionState = "connecting"; + private ws: WebSocket; - private onMessageHandler: SocketDataHandler | null = null; - private onErrorHandler: SocketErrorHandler | null = null; - private onOpenHandler: SocketOpenHandler | null = null; - private onCloseHandler: SocketCloseHandler | null = null; - private onCatostrophicErrorHandler: SocketCatostrophicErrorHandler | null = - null; + private onMessageHandler: SocketDataHandler | null = null; + private onErrorHandler: SocketErrorHandler | null = null; + private onOpenHandler: SocketOpenHandler | null = null; + private onCloseHandler: SocketCloseHandler | null = null; + private onCatostrophicErrorHandler: SocketCatostrophicErrorHandler | null = + null; - private reconnectAttempts: number; - private maxReconnectDelay: number; - private heartbeatInterval: Timer | null; - private messageQueue: unknown[] = []; - private attemptReconnect = true; + private reconnectAttempts: number; + private maxReconnectDelay: number; + private heartbeatInterval: Timer | null; + private messageQueue: unknown[] = []; + private attemptReconnect = true; - private debugMode = false; + private debugMode = false; - constructor(url: string) { - this.url = url; - this.ws = this.connect(); - this.reconnectAttempts = 0; - this.maxReconnectDelay = MAX_RECONNECT_DELAY; - this.heartbeatInterval = null; - } + constructor(url: string) { + this.url = url; + this.ws = this.connect(); + this.reconnectAttempts = 0; + this.maxReconnectDelay = MAX_RECONNECT_DELAY; + this.heartbeatInterval = null; + } - get connected() { - return this.ws.readyState === WebSocket.OPEN; - } + get connected() { + return this.ws.readyState === WebSocket.OPEN; + } - get native() { - return this.ws; - } + get native() { + return this.ws; + } - set debug(value: boolean) { - this.debugMode = value; - } + set debug(value: boolean) { + this.debugMode = value; + } - debugMessage(...args: unknown[]) { - if (this.debugMode) { - const output = ["[ManagedSocketDebug]", ...args]; - console.log(...output); - } - } + debugMessage(...args: unknown[]) { + if (this.debugMode) { + const output = ["[ManagedSocketDebug]", ...args]; + console.log(...output); + } + } - private sendQueuedMessages() { - // Make a copy of the queue and clear it first. - // this way if the messages fail to send again, - // they just get requeued - const messagesToSend = [...this.messageQueue]; - this.messageQueue = []; - for (const message of messagesToSend) { - this.send(message); - } - } + private sendQueuedMessages() { + // Make a copy of the queue and clear it first. + // this way if the messages fail to send again, + // they just get requeued + const messagesToSend = [...this.messageQueue]; + this.messageQueue = []; + for (const message of messagesToSend) { + this.send(message); + } + } - private connect() { - this.ws = new WebSocket(this.url); + private connect() { + this.ws = new WebSocket(this.url); - this.ws.addEventListener("open", () => { - this.reconnectAttempts = 0; + this.ws.addEventListener("open", () => { + this.reconnectAttempts = 0; - // Announce successful reconnects - if (this.state === "reconnecting") { - this.debugMessage("Reconnected to socket server"); - } + // Announce successful reconnects + if (this.state === "reconnecting") { + this.debugMessage("Reconnected to socket server"); + } - this.onOpenHandler?.(); - this.state = "open"; - this.startHeartbeat(); - this.sendQueuedMessages(); - }); + this.onOpenHandler?.(); + this.state = "open"; + this.startHeartbeat(); + this.sendQueuedMessages(); + }); - this.ws.addEventListener("close", (event) => { - const { code } = event; - this.debugMessage(code); - this.onCloseHandler?.(); + this.ws.addEventListener("close", (event) => { + const { code } = event; + this.debugMessage(code); + this.onCloseHandler?.(); - // If the code received was catostrophic, terminate the connection - if (SocketSpeak.isCatatrophicCloseCode(code)) { - this.handleCatostophicError(code); - } + // If the code received was catostrophic, terminate the connection + if (SocketSpeak.isCatatrophicCloseCode(code)) { + this.handleCatostophicError(code); + } - this.state = "closed"; + this.state = "closed"; - if (this.attemptReconnect) { - this.debugMessage( - "Socket connection closed. Attempting reconnection...", - ); - this.stopHeartbeat(); - this.reconnect(); - } - }); + if (this.attemptReconnect) { + this.debugMessage( + "Socket connection closed. Attempting reconnection...", + ); + this.stopHeartbeat(); + this.reconnect(); + } + }); - this.ws.addEventListener("error", (error) => { - this.debugMessage("WebSocket error", error); + this.ws.addEventListener("error", (error) => { + this.debugMessage("WebSocket error", error); - const errorType = - this.state === "connecting" - ? ManagedSocketErrorType.CONNECTION_REJECTED - : ManagedSocketErrorType.SOCKET_ERROR; + const errorType = + this.state === "connecting" + ? ManagedSocketErrorType.CONNECTION_REJECTED + : ManagedSocketErrorType.SOCKET_ERROR; - const socketError = new ManagedSocketError( - errorType, - new Error(error.currentTarget?.toString()), - errorType, - ); + const socketError = new ManagedSocketError( + errorType, + new Error(error.currentTarget?.toString()), + errorType, + ); - if (this.onErrorHandler !== null) { - return this.onErrorHandler(socketError); - } + if (this.onErrorHandler !== null) { + return this.onErrorHandler(socketError); + } - throw error; - }); + throw error; + }); - this.ws.addEventListener("message", (event) => { - const message = SocketSpeak.deserialize(event.data.toString()); + this.ws.addEventListener("message", (event) => { + const message = SocketSpeak.deserialize(event.data.toString()); - // Ignore heartbeats - if (message.type === "heartbeat") { - this.debugMessage("Received heartbeat"); - return; - } + // Ignore heartbeats + if (message.type === "heartbeat") { + this.debugMessage("Received heartbeat"); + return; + } - if (message.data === undefined || message.data === null) { - this.debugMessage("Received message with no data"); - return; - } + if (message.data === undefined || message.data === null) { + this.debugMessage("Received message with no data"); + return; + } - this.debugMessage("Received message", message.data); - this.onMessageHandler?.(message.data); - }); + this.debugMessage("Received message", message.data); + this.onMessageHandler?.(message.data); + }); - return this.ws; - } + return this.ws; + } - handleCatostophicError(code: SocketDisconnectCode) { - this.state = "terminated"; - this.attemptReconnect = false; - this.debugMessage( - "Socket connection terminated due to non-reconnect close code", - ); + handleCatostophicError(code: SocketDisconnectCode) { + this.state = "terminated"; + this.attemptReconnect = false; + this.debugMessage( + "Socket connection terminated due to non-reconnect close code", + ); - const socketError = new ManagedSocketError( - "Socket connection terminated due to non-reconnect close code", - new Error(code.toString()), - ManagedSocketErrorType.CATOSTROPHIC_CLOSE, - ); + const socketError = new ManagedSocketError( + "Socket connection terminated due to non-reconnect close code", + new Error(code.toString()), + ManagedSocketErrorType.CATOSTROPHIC_CLOSE, + ); - if (this.onCatostrophicErrorHandler !== null) { - return this.onCatostrophicErrorHandler(socketError); - } + if (this.onCatostrophicErrorHandler !== null) { + return this.onCatostrophicErrorHandler(socketError); + } - throw socketError; - } + throw socketError; + } - onMessage(handler: SocketDataHandler) { - this.onMessageHandler = handler; - } + onMessage(handler: SocketDataHandler) { + this.onMessageHandler = handler; + } - onError(handler: (error: ManagedSocketError) => void) { - this.onErrorHandler = handler; - } + onError(handler: (error: ManagedSocketError) => void) { + this.onErrorHandler = handler; + } - onOpen(handler: () => void) { - this.onOpenHandler = handler; - } + onOpen(handler: () => void) { + this.onOpenHandler = handler; + } - onClose(handler: () => void) { - this.onCloseHandler = handler; - } + onClose(handler: () => void) { + this.onCloseHandler = handler; + } - reconnect() { - this.attemptReconnect = true; - this.state = "reconnecting"; - const delay = Math.min( - 1000 * 2 ** this.reconnectAttempts, - this.maxReconnectDelay, - ); - this.debugMessage(`Attempting to reconnect in ${delay}ms`); - setTimeout(() => { - this.reconnectAttempts++; - this.connect(); - }, delay); - } + reconnect() { + this.attemptReconnect = true; + this.state = "reconnecting"; + const delay = Math.min( + 1000 * 2 ** this.reconnectAttempts, + this.maxReconnectDelay, + ); + this.debugMessage(`Attempting to reconnect in ${delay}ms`); + setTimeout(() => { + this.reconnectAttempts++; + this.connect(); + }, delay); + } - close() { - this.attemptReconnect = false; - this.state = "closing"; - this.ws.close(); - } + close() { + this.attemptReconnect = false; + this.state = "closing"; + this.ws.close(); + } - private startHeartbeat() { - this.heartbeatInterval = setInterval(() => { - if (this.ws.readyState === WebSocket.OPEN) { - this.ws.send( - SocketSpeak.serialize(SocketSpeak.createHeartbeatMessage()), - ); - } - }, HEARTBEAT_INTERVAL); - } + private startHeartbeat() { + this.heartbeatInterval = setInterval(() => { + if (this.ws.readyState === WebSocket.OPEN) { + this.ws.send( + SocketSpeak.serialize(SocketSpeak.createHeartbeatMessage()), + ); + } + }, HEARTBEAT_INTERVAL); + } - private stopHeartbeat() { - if (this.heartbeatInterval !== null) { - clearInterval(this.heartbeatInterval); - this.heartbeatInterval = null; - } - } + private stopHeartbeat() { + if (this.heartbeatInterval !== null) { + clearInterval(this.heartbeatInterval); + this.heartbeatInterval = null; + } + } - send(data: T) { - if (this.ws.readyState !== WebSocket.OPEN) { - this.debugMessage("WebSocket is not open. Queuing message."); - this.messageQueue.push(data); - return; - } + send(data: T) { + if (this.ws.readyState !== WebSocket.OPEN) { + this.debugMessage("WebSocket is not open. Queuing message."); + this.messageQueue.push(data); + return; + } - this.ws.send(SocketSpeak.prepare(data)); - } + this.ws.send(SocketSpeak.prepare(data)); + } } diff --git a/src/messages.ts b/src/messages.ts index 9f433b4..8c42a16 100644 --- a/src/messages.ts +++ b/src/messages.ts @@ -1,11 +1,11 @@ import { ManagedSocketErrorType, NON_RECONNECT_CODES } from "./constants"; import { ManagedSocketError } from "./errors"; import { - parseAnyScoketMessage, - type SerializedSocketMessage, - type SocketDataMessage, - type SocketHeartbeatMessage, - type SocketMessage, + type SerializedSocketMessage, + type SocketDataMessage, + type SocketHeartbeatMessage, + type SocketMessage, + parseAnyScoketMessage, } from "./types"; /** @@ -15,10 +15,10 @@ import { * @returns An object representing the socket data message with a type of "message" and the provided data. */ function createDataMessage(data: unknown): SocketDataMessage { - return { - type: "message", - data, - }; + return { + type: "message", + data, + }; } /** @@ -27,10 +27,10 @@ function createDataMessage(data: unknown): SocketDataMessage { * @returns {SocketHeartbeatMessage} An object representing a heartbeat message with the current timestamp. */ function createHeartbeatMessage(): SocketHeartbeatMessage { - return { - type: "heartbeat", - data: new Date().toISOString(), - }; + return { + type: "heartbeat", + data: new Date().toISOString(), + }; } /** @@ -40,7 +40,7 @@ function createHeartbeatMessage(): SocketHeartbeatMessage { * @returns {SerializedSocketMessage} The serialized JSON string representation of the message. */ function serialize(message: SocketMessage): SerializedSocketMessage { - return JSON.stringify(message) as SerializedSocketMessage; + return JSON.stringify(message) as SerializedSocketMessage; } /** @@ -51,16 +51,16 @@ function serialize(message: SocketMessage): SerializedSocketMessage { * @throws {ManagedSocketError} If the JSON string cannot be parsed or if the message shape is invalid. */ function deserialize(data: string): SocketMessage { - try { - const asObj = JSON.parse(data); - return parseAnyScoketMessage(asObj); - } catch (error) { - throw new ManagedSocketError( - "Failed to parse incoming message shape", - error instanceof Error ? error : new Error("Unknown error"), - ManagedSocketErrorType.INVALID_MESSAGE_SHAPE, - ); - } + try { + const asObj = JSON.parse(data); + return parseAnyScoketMessage(asObj); + } catch (error) { + throw new ManagedSocketError( + "Failed to parse incoming message shape", + error instanceof Error ? error : new Error("Unknown error"), + ManagedSocketErrorType.INVALID_MESSAGE_SHAPE, + ); + } } /** @@ -75,7 +75,7 @@ function deserialize(data: string): SocketMessage { * @returns {SerializedSocketMessage} - The serialized socket message. */ function prepare(data: T): SerializedSocketMessage { - return serialize(createDataMessage(data)); + return serialize(createDataMessage(data)); } /** @@ -85,14 +85,14 @@ function prepare(data: T): SerializedSocketMessage { * @returns `true` if the code is in the list of non-reconnect codes, otherwise `false`. */ function isCatatrophicCloseCode(code: number) { - return (NON_RECONNECT_CODES as readonly number[]).includes(code); + return (NON_RECONNECT_CODES as readonly number[]).includes(code); } export const SocketSpeak = { - createDataMessage, - createHeartbeatMessage, - serialize, - deserialize, - isCatatrophicCloseCode, - prepare, + createDataMessage, + createHeartbeatMessage, + serialize, + deserialize, + isCatatrophicCloseCode, + prepare, }; diff --git a/src/types.ts b/src/types.ts index ae19a3b..3d6e93c 100644 --- a/src/types.ts +++ b/src/types.ts @@ -8,7 +8,7 @@ declare const serializedSocketMessageBrand: unique symbol; * This type is a branded string, ensuring type safety for serialized socket messages. */ export type SerializedSocketMessage = string & { - [serializedSocketMessageBrand]: true; + [serializedSocketMessageBrand]: true; }; /** @@ -16,16 +16,16 @@ export type SerializedSocketMessage = string & { * This message is used to indicate that the connection is still alive. */ export interface SocketHeartbeatMessage { - type: "heartbeat"; - data: string; + type: "heartbeat"; + data: string; } /** * Represents a message with data to be handled by the application */ export interface SocketDataMessage { - type: "message"; - data: unknown; + type: "message"; + data: unknown; } /** @@ -44,18 +44,18 @@ export type SocketMessageType = (typeof MESSAGE_TYPES)[number]; * @throws {ManagedSocketError} If the value is not a string or not included in `MESSAGE_TYPES`. */ export function parseMessageType(value: unknown): SocketMessageType { - if ( - typeof value !== "string" || - !(MESSAGE_TYPES as readonly string[]).includes(value) - ) { - throw new ManagedSocketError( - "Failed to parse incoming message shape", - new Error("Invalid message type"), - ManagedSocketErrorType.INVALID_MESSAGE_SHAPE, - ); - } + if ( + typeof value !== "string" || + !(MESSAGE_TYPES as readonly string[]).includes(value) + ) { + throw new ManagedSocketError( + "Failed to parse incoming message shape", + new Error("Invalid message type"), + ManagedSocketErrorType.INVALID_MESSAGE_SHAPE, + ); + } - return value as SocketMessageType; + return value as SocketMessageType; } /** @@ -66,50 +66,50 @@ export function parseMessageType(value: unknown): SocketMessageType { * @throws {ManagedSocketError} If the incoming message is not a parseable message */ export function parseAnyScoketMessage(value: unknown): SocketMessage { - if (typeof value !== "object" || value === null) { - throw new ManagedSocketError( - "Failed to parse incoming message shape: value was not an object", - new Error("Invalid message shape"), - ManagedSocketErrorType.INVALID_MESSAGE_SHAPE, - ); - } + if (typeof value !== "object" || value === null) { + throw new ManagedSocketError( + "Failed to parse incoming message shape: value was not an object", + new Error("Invalid message shape"), + ManagedSocketErrorType.INVALID_MESSAGE_SHAPE, + ); + } - if (!("type" in value) || !("data" in value)) { - throw new ManagedSocketError( - "Failed to parse incoming message shape: missing type or data", - new Error("Invalid message shape"), - ManagedSocketErrorType.INVALID_MESSAGE_SHAPE, - ); - } + if (!("type" in value) || !("data" in value)) { + throw new ManagedSocketError( + "Failed to parse incoming message shape: missing type or data", + new Error("Invalid message shape"), + ManagedSocketErrorType.INVALID_MESSAGE_SHAPE, + ); + } - const { type: incomingType, data: incomingData } = value; - const type = parseMessageType(incomingType); + const { type: incomingType, data: incomingData } = value; + const type = parseMessageType(incomingType); - if (type === "heartbeat") { - if (typeof incomingData !== "string") { - throw new ManagedSocketError( - "Failed to parse incoming message shape: heartbeat data was not a string", - new Error("Invalid message shape"), - ManagedSocketErrorType.INVALID_MESSAGE_SHAPE, - ); - } + if (type === "heartbeat") { + if (typeof incomingData !== "string") { + throw new ManagedSocketError( + "Failed to parse incoming message shape: heartbeat data was not a string", + new Error("Invalid message shape"), + ManagedSocketErrorType.INVALID_MESSAGE_SHAPE, + ); + } - return { - type, - data: incomingData, - }; - } + return { + type, + data: incomingData, + }; + } - if (type === "message") { - return { - type, - data: incomingData, - }; - } + if (type === "message") { + return { + type, + data: incomingData, + }; + } - throw new ManagedSocketError( - "Failed to parse incoming message shape", - new Error("Invalid message type"), - ManagedSocketErrorType.INVALID_MESSAGE_SHAPE, - ); + throw new ManagedSocketError( + "Failed to parse incoming message shape", + new Error("Invalid message type"), + ManagedSocketErrorType.INVALID_MESSAGE_SHAPE, + ); }