From b748e5a9394dc38374f57f52316e5eb5f5f5a4a6 Mon Sep 17 00:00:00 2001 From: Wang Guan Date: Fri, 27 Jun 2025 22:14:37 +0900 Subject: [PATCH 1/3] minor internal improvements --- packages/engine.io-parser/lib/commons.ts | 2 +- packages/engine.io/lib/engine.io.ts | 30 ++++--- packages/engine.io/lib/parser-v3/index.ts | 14 ++-- packages/engine.io/lib/server.ts | 83 ++++++++++++------- packages/engine.io/lib/socket.ts | 5 +- packages/engine.io/lib/transport.ts | 13 ++- .../engine.io/lib/transports-uws/polling.ts | 12 +-- packages/engine.io/lib/transports/index.ts | 6 +- packages/engine.io/lib/transports/polling.ts | 12 +-- .../engine.io/lib/transports/websocket.ts | 14 +++- .../engine.io/lib/transports/webtransport.ts | 1 + packages/engine.io/lib/userver.ts | 10 ++- .../lib/in-memory-adapter.ts | 16 +++- packages/socket.io/lib/client.ts | 13 +-- packages/socket.io/lib/index.ts | 16 ++-- packages/socket.io/lib/socket.ts | 2 +- 16 files changed, 155 insertions(+), 94 deletions(-) diff --git a/packages/engine.io-parser/lib/commons.ts b/packages/engine.io-parser/lib/commons.ts index 2562382f72..2930da8089 100644 --- a/packages/engine.io-parser/lib/commons.ts +++ b/packages/engine.io-parser/lib/commons.ts @@ -32,7 +32,7 @@ export type RawData = any; export interface Packet { type: PacketType; - options?: { compress: boolean }; + options?: { compress: boolean, wsPreEncoded?: string, wsPreEncodedFrame?: boolean }; data?: RawData; } diff --git a/packages/engine.io/lib/engine.io.ts b/packages/engine.io/lib/engine.io.ts index 3ba9e67f8f..83f87711a0 100644 --- a/packages/engine.io/lib/engine.io.ts +++ b/packages/engine.io/lib/engine.io.ts @@ -1,4 +1,4 @@ -import { createServer } from "http"; +import { createServer, Server as HttpServer } from "http"; import { Server, AttachOptions, ServerOptions } from "./server"; import transports from "./transports/index"; import * as parser from "engine.io-parser"; @@ -11,17 +11,21 @@ export { Transport } from "./transport"; export const protocol = parser.protocol; /** - * Creates an http.Server exclusively used for WS upgrades. + * Creates an http.Server exclusively used for WS upgrades, and start listening. * - * @param {Number} port - * @param {Function} callback - * @param {Object} options - * @return {Server} websocket.io server + * @param port + * @param options + * @param listenCallback callback for http.Server.listen() + * @return engine.io server */ -function listen(port, options: AttachOptions & ServerOptions, fn) { +function listen( + port: number, + options?: AttachOptions & ServerOptions, + listenCallback?: () => void, +): Server { if ("function" === typeof options) { - fn = options; + listenCallback = options; options = {}; } @@ -34,7 +38,7 @@ function listen(port, options: AttachOptions & ServerOptions, fn) { const engine = attach(server, options); engine.httpServer = server; - server.listen(port, fn); + server.listen(port, listenCallback); return engine; } @@ -42,12 +46,12 @@ function listen(port, options: AttachOptions & ServerOptions, fn) { /** * Captures upgrade requests for a http.Server. * - * @param {http.Server} server - * @param {Object} options - * @return {Server} engine server + * @param server + * @param options + * @return engine.io server */ -function attach(server, options: AttachOptions & ServerOptions) { +function attach(server: HttpServer, options: AttachOptions & ServerOptions): Server { const engine = new Server(options); engine.attach(server, options); return engine; diff --git a/packages/engine.io/lib/parser-v3/index.ts b/packages/engine.io/lib/parser-v3/index.ts index 367ae13767..8cf34dc2f2 100644 --- a/packages/engine.io/lib/parser-v3/index.ts +++ b/packages/engine.io/lib/parser-v3/index.ts @@ -59,8 +59,7 @@ const EMPTY_BUFFER = Buffer.concat([]); * * @api private */ - -export function encodePacket (packet, supportsBinary, utf8encode, callback) { +export function encodePacket (packet: any, supportsBinary?: any, utf8encode?: any, callback?: any) { if (typeof supportsBinary === 'function') { callback = supportsBinary; supportsBinary = null; @@ -86,7 +85,7 @@ export function encodePacket (packet, supportsBinary, utf8encode, callback) { } return callback('' + encoded); -}; +} /** * Encode Buffer data @@ -120,16 +119,16 @@ export function encodeBase64Packet (packet, callback){ /** * Decodes a packet. Data also available as an ArrayBuffer if requested. * - * @return {Object} with `type` and `data` (if any) + * @return {import('engine.io-parser').Packet} with `type` and `data` (if any) * @api private */ -export function decodePacket (data, binaryType, utf8decode) { +export function decodePacket (data: any, binaryType?: any, utf8decode?: any): any { if (data === undefined) { return err; } - var type; + let type: string | number; // String data if (typeof data === 'string') { @@ -147,6 +146,7 @@ export function decodePacket (data, binaryType, utf8decode) { } } + // @ts-expect-error if (Number(type) != type || !packetslist[type]) { return err; } @@ -274,7 +274,7 @@ function map(ary, each, done) { * @api public */ -export function decodePayload (data, binaryType, callback) { +export function decodePayload (data: any, binaryType?: any, callback?: any) { if (typeof data !== 'string') { return decodePayloadAsBinary(data, binaryType, callback); } diff --git a/packages/engine.io/lib/server.ts b/packages/engine.io/lib/server.ts index bf53f994ac..30cfa50dc2 100644 --- a/packages/engine.io/lib/server.ts +++ b/packages/engine.io/lib/server.ts @@ -6,7 +6,12 @@ import { EventEmitter } from "events"; import { Socket } from "./socket"; import debugModule from "debug"; import { serialize } from "cookie"; -import { Server as DEFAULT_WS_ENGINE } from "ws"; +import { + Server as DEFAULT_WS_ENGINE, + type Server as WsServer, + type PerMessageDeflateOptions, + type WebSocket as WsWebSocket, +} from "ws"; import type { IncomingMessage, Server as HttpServer, @@ -16,7 +21,7 @@ import type { CorsOptions, CorsOptionsDelegate } from "cors"; import type { Duplex } from "stream"; import { WebTransport } from "./transports/webtransport"; import { createPacketDecoderStream } from "engine.io-parser"; -import type { EngineRequest } from "./transport"; +import type { EngineRequest, Transport as TransportImpl } from "./transport"; import type { CookieSerializeOptions } from "./contrib/types.cookie"; const debug = debugModule("engine"); @@ -25,6 +30,11 @@ const kResponseHeaders = Symbol("responseHeaders"); type Transport = "polling" | "websocket" | "webtransport"; +export type ErrorCallback = ( + errorCode?: (typeof Server.errors)[keyof typeof Server.errors], + errorContext?: Record & { name?: string; message?: string }, +) => void; + export interface AttachOptions { /** * name of the path to capture @@ -100,7 +110,7 @@ export interface ServerOptions { * parameters of the WebSocket permessage-deflate extension (see ws module api docs). Set to false to disable. * @default false */ - perMessageDeflate?: boolean | object; + perMessageDeflate?: boolean | PerMessageDeflateOptions; /** * parameters of the http compression for the polling transports (see zlib api docs). Set to false to disable. * @default true @@ -113,7 +123,7 @@ export interface ServerOptions { * * @default `require("ws").Server` */ - wsEngine?: any; + wsEngine?: typeof WsServer; /** * an optional packet which will be concatenated to the handshake packet emitted by Engine.IO. */ @@ -149,7 +159,7 @@ type Middleware = ( next: (err?: any) => void, ) => void; -function parseSessionId(data: string) { +function parseSessionId(data: string): string | undefined { try { const parsed = JSON.parse(data); if (typeof parsed.sid === "string") { @@ -224,7 +234,7 @@ export abstract class BaseServer extends EventEmitter { this.init(); } - protected abstract init(); + protected abstract init(): void; /** * Compute the pathname of the requests that are handled by the server @@ -244,10 +254,8 @@ export abstract class BaseServer extends EventEmitter { /** * Returns a list of available transports for upgrade given a certain transport. - * - * @return {Array} */ - public upgrades(transport: string) { + public upgrades(transport: Transport): string[] { if (!this.opts.allowUpgrades) return []; return transports[transport].upgradesTo || []; } @@ -259,17 +267,18 @@ export abstract class BaseServer extends EventEmitter { * @param upgrade - whether it's an upgrade request * @param fn * @protected + * @return whether the request is valid */ protected verify( - req: any, + req: EngineRequest, upgrade: boolean, - fn: (errorCode?: number, errorContext?: any) => void, - ) { + fn: ErrorCallback, + ): void | boolean { // transport check const transport = req._query.transport; // WebTransport does not go through the verify() method, see the onWebTransportSession() method if ( - !~this.opts.transports.indexOf(transport) || + !~this.opts.transports.indexOf(transport as Transport) || transport === "webtransport" ) { debug('unknown transport "%s"', transport); @@ -408,7 +417,7 @@ export abstract class BaseServer extends EventEmitter { * * @param {IncomingMessage} req - the request object */ - public generateId(req: IncomingMessage) { + public generateId(req: IncomingMessage): string | PromiseLike { return base64id.generateId(); } @@ -423,8 +432,8 @@ export abstract class BaseServer extends EventEmitter { */ protected async handshake( transportName: string, - req: any, - closeConnection: (errorCode?: number, errorContext?: any) => void, + req: EngineRequest, + closeConnection: ErrorCallback, ) { const protocol = req._query.EIO === "4" ? 4 : 3; // 3rd revision by default if (protocol === 3 && !this.opts.allowEIO3) { @@ -600,7 +609,7 @@ export abstract class BaseServer extends EventEmitter { } } - protected abstract createTransport(transportName, req); + protected abstract createTransport(transportName: Transport, req: EngineRequest); /** * Protocol errors mappings. @@ -613,7 +622,7 @@ export abstract class BaseServer extends EventEmitter { BAD_REQUEST: 3, FORBIDDEN: 4, UNSUPPORTED_PROTOCOL_VERSION: 5, - }; + } as const; static errorMessages = { 0: "Transport unknown", @@ -622,7 +631,7 @@ export abstract class BaseServer extends EventEmitter { 3: "Bad request", 4: "Forbidden", 5: "Unsupported protocol version", - }; + } as const; } /** @@ -667,7 +676,7 @@ class WebSocketResponse { */ export class Server extends BaseServer { public httpServer?: HttpServer; - private ws: any; + private ws: WsServer; /** * Initialize websocket server @@ -687,7 +696,7 @@ export class Server extends BaseServer { }); if (typeof this.ws.on === "function") { - this.ws.on("headers", (headersArray, req) => { + this.ws.on("headers", (headersArray, req: EngineRequest) => { // note: 'ws' uses an array of headers, while Engine.IO uses an object (response.writeHead() accepts both formats) // we could also try to parse the array and then sync the values, but that will be error-prone const additionalHeaders = req[kResponseHeaders] || {}; @@ -730,7 +739,8 @@ export class Server extends BaseServer { } } - protected createTransport(transportName: string, req: IncomingMessage) { + protected createTransport(transportName: Transport, req: IncomingMessage) { + // @ts-expect-error 'polling' is a plain function used as constructor return new transports[transportName](req); } @@ -745,7 +755,7 @@ export class Server extends BaseServer { this.prepare(req); req.res = res; - const callback = (errorCode, errorContext) => { + const callback: ErrorCallback = (errorCode, errorContext) => { if (errorCode !== undefined) { this.emit("connection_error", { req, @@ -787,7 +797,7 @@ export class Server extends BaseServer { this.prepare(req); const res = new WebSocketResponse(req, socket); - const callback = (errorCode, errorContext) => { + const callback: ErrorCallback = (errorCode, errorContext) => { if (errorCode !== undefined) { this.emit("connection_error", { req, @@ -823,11 +833,16 @@ export class Server extends BaseServer { /** * Called upon a ws.io connection. - * - * @param {ws.Socket} websocket + * @param req + * @param socket + * @param websocket * @private */ - private onWebSocket(req, socket, websocket) { + private onWebSocket( + req: EngineRequest, + socket: Duplex, + websocket: WsWebSocket, + ) { websocket.on("error", onUpgradeError); if ( @@ -862,7 +877,11 @@ export class Server extends BaseServer { // transport error handling takes over websocket.removeListener("error", onUpgradeError); - const transport = this.createTransport(req._query.transport, req); + const transport: TransportImpl = this.createTransport( + req._query.transport, + req + ); + // @ts-expect-error this option is only for WebSocket impl transport.perMessageDeflate = this.opts.perMessageDeflate; client._maybeUpgrade(transport); } @@ -947,7 +966,11 @@ export class Server extends BaseServer { * @private */ -function abortRequest(res, errorCode, errorContext) { +function abortRequest( + res: ServerResponse, + errorCode: number, + errorContext?: { message?: string }, +) { const statusCode = errorCode === Server.errors.FORBIDDEN ? 403 : 400; const message = errorContext && errorContext.message @@ -1030,7 +1053,7 @@ const validHdrChars = [ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 // ... 255 ] -function checkInvalidHeaderChar(val) { +function checkInvalidHeaderChar(val?: string) { val += ""; if (val.length < 1) return false; if (!validHdrChars[val.charCodeAt(0)]) { diff --git a/packages/engine.io/lib/socket.ts b/packages/engine.io/lib/socket.ts index bfe6d3ba1d..0dbcccf9cf 100644 --- a/packages/engine.io/lib/socket.ts +++ b/packages/engine.io/lib/socket.ts @@ -5,6 +5,7 @@ import type { EngineRequest, Transport } from "./transport"; import type { BaseServer } from "./server"; import { setTimeout, clearTimeout } from "timers"; import type { Packet, PacketType, RawData } from "engine.io-parser"; +import type transports from "./transports"; const debug = debugModule("engine:socket"); @@ -537,9 +538,9 @@ export class Socket extends EventEmitter { */ private getAvailableUpgrades() { const availableUpgrades = []; - const allUpgrades = this.server.upgrades(this.transport.name); + const allUpgrades = this.server.upgrades(this.transport.name as keyof typeof transports); for (let i = 0; i < allUpgrades.length; ++i) { - const upg = allUpgrades[i]; + const upg = allUpgrades[i] as keyof typeof transports; if (this.server.opts.transports.indexOf(upg) !== -1) { availableUpgrades.push(upg); } diff --git a/packages/engine.io/lib/transport.ts b/packages/engine.io/lib/transport.ts index 1121e4e348..a23e6de70b 100644 --- a/packages/engine.io/lib/transport.ts +++ b/packages/engine.io/lib/transport.ts @@ -4,6 +4,7 @@ import * as parser_v3 from "./parser-v3/index"; import debugModule from "debug"; import type { IncomingMessage, ServerResponse } from "http"; import { Packet, RawData } from "engine.io-parser"; +import type { WebSocket } from "ws"; const debug = debugModule("engine:transport"); @@ -15,7 +16,11 @@ export type EngineRequest = IncomingMessage & { _query: Record; res?: ServerResponse; cleanup?: Function; - websocket?: any; + websocket?: WebSocket & { + _socket?: { + remoteAddress: string; + }; + }; }; export abstract class Transport extends EventEmitter { @@ -37,7 +42,7 @@ export abstract class Transport extends EventEmitter { * * @see https://github.com/socketio/engine.io-protocol */ - public protocol: number; + public protocol: 3 | 4; /** * The current state of the transport. @@ -53,7 +58,7 @@ export abstract class Transport extends EventEmitter { * The parser to use (depends on the revision of the {@link Transport#protocol}. * @protected */ - protected parser: any; + protected parser: typeof parser_v4 | typeof parser_v3; /** * Whether the transport supports binary payloads (else it will be base64-encoded) * @protected @@ -148,7 +153,7 @@ export abstract class Transport extends EventEmitter { /** * Called with the encoded packet data. * - * @param {String} data + * @param data * @protected */ protected onData(data: RawData) { diff --git a/packages/engine.io/lib/transports-uws/polling.ts b/packages/engine.io/lib/transports-uws/polling.ts index 090270ec2f..342d25b4e3 100644 --- a/packages/engine.io/lib/transports-uws/polling.ts +++ b/packages/engine.io/lib/transports-uws/polling.ts @@ -3,6 +3,8 @@ import { createGzip, createDeflate } from "zlib"; import * as accepts from "accepts"; import debugModule from "debug"; import { HttpRequest, HttpResponse } from "uWebSockets.js"; +import type * as parser_v4 from "engine.io-parser"; +import type * as parser_v3 from "../parser-v3/index"; const debug = debugModule("engine:polling"); @@ -228,9 +230,9 @@ export class Polling extends Transport { }; if (this.protocol === 3) { - this.parser.decodePayload(data, callback); + (this.parser as typeof parser_v3).decodePayload(data, callback); } else { - this.parser.decodePayload(data).forEach(callback); + (this.parser as typeof parser_v4).decodePayload(data).forEach(callback); } } @@ -263,7 +265,7 @@ export class Polling extends Transport { this.shouldClose = null; } - const doWrite = (data) => { + const doWrite = (data: string) => { const compress = packets.some((packet) => { return packet.options && packet.options.compress; }); @@ -271,9 +273,9 @@ export class Polling extends Transport { }; if (this.protocol === 3) { - this.parser.encodePayload(packets, this.supportsBinary, doWrite); + (this.parser as typeof parser_v3).encodePayload(packets, this.supportsBinary, doWrite); } else { - this.parser.encodePayload(packets, doWrite); + (this.parser as typeof parser_v4).encodePayload(packets, doWrite); } } diff --git a/packages/engine.io/lib/transports/index.ts b/packages/engine.io/lib/transports/index.ts index e585112bb1..6f41324801 100644 --- a/packages/engine.io/lib/transports/index.ts +++ b/packages/engine.io/lib/transports/index.ts @@ -2,9 +2,10 @@ import { Polling as XHR } from "./polling"; import { JSONP } from "./polling-jsonp"; import { WebSocket } from "./websocket"; import { WebTransport } from "./webtransport"; +import { EngineRequest } from "../transport"; export default { - polling: polling, + polling, websocket: WebSocket, webtransport: WebTransport, }; @@ -12,8 +13,7 @@ export default { /** * Polling polymorphic constructor. */ - -function polling(req) { +function polling(req: EngineRequest) { if ("string" === typeof req._query.j) { return new JSONP(req); } else { diff --git a/packages/engine.io/lib/transports/polling.ts b/packages/engine.io/lib/transports/polling.ts index 1f46335934..618f36d43a 100644 --- a/packages/engine.io/lib/transports/polling.ts +++ b/packages/engine.io/lib/transports/polling.ts @@ -4,6 +4,8 @@ import * as accepts from "accepts"; import debugModule from "debug"; import type { IncomingMessage, ServerResponse } from "http"; import type { Packet, RawData } from "engine.io-parser"; +import type * as parser_v4 from "engine.io-parser"; +import type * as parser_v3 from "../parser-v3/index"; const debug = debugModule("engine:polling"); @@ -196,9 +198,9 @@ export class Polling extends Transport { }; if (this.protocol === 3) { - this.parser.decodePayload(data, callback); + (this.parser as typeof parser_v3).decodePayload(data, callback); } else { - this.parser.decodePayload(data).forEach(callback); + (this.parser as typeof parser_v4).decodePayload(data).forEach(callback); } } @@ -225,7 +227,7 @@ export class Polling extends Transport { this.shouldClose = null; } - const doWrite = (data) => { + const doWrite = (data: string) => { const compress = packets.some((packet) => { return packet.options && packet.options.compress; }); @@ -233,9 +235,9 @@ export class Polling extends Transport { }; if (this.protocol === 3) { - this.parser.encodePayload(packets, this.supportsBinary, doWrite); + (this.parser as typeof parser_v3).encodePayload(packets, this.supportsBinary, doWrite); } else { - this.parser.encodePayload(packets, doWrite); + (this.parser as typeof parser_v4).encodePayload(packets, doWrite); } } diff --git a/packages/engine.io/lib/transports/websocket.ts b/packages/engine.io/lib/transports/websocket.ts index a95f4b0f19..fe084674fe 100644 --- a/packages/engine.io/lib/transports/websocket.ts +++ b/packages/engine.io/lib/transports/websocket.ts @@ -1,12 +1,18 @@ import { EngineRequest, Transport } from "../transport"; import debugModule from "debug"; import type { Packet, RawData } from "engine.io-parser"; +import type { PerMessageDeflateOptions, WebSocket as WsWebSocket } from 'ws'; const debug = debugModule("engine:ws"); +/** + * WebSocket object in 'ws' package + * names started with _ are not in web-WebSocket standard + */ export class WebSocket extends Transport { - protected perMessageDeflate: any; - private socket: any; + perMessageDeflate?: boolean | PerMessageDeflateOptions; + private socket: WsWebSocket; + static upgradesTo?: undefined; /** * WebSocket transport @@ -51,8 +57,8 @@ export class WebSocket extends Transport { if (this._canSendPreEncodedFrame(packet)) { // the WebSocket frame was computed with WebSocket.Sender.frame() // see https://github.com/websockets/ws/issues/617#issuecomment-283002469 + // @ts-expect-error use of untyped member this.socket._sender.sendFrame( - // @ts-ignore packet.options.wsPreEncodedFrame, isLast ? this._onSentLast : this._onSent, ); @@ -74,8 +80,8 @@ export class WebSocket extends Transport { private _canSendPreEncodedFrame(packet: Packet) { return ( !this.perMessageDeflate && + // @ts-expect-error use of untyped member typeof this.socket?._sender?.sendFrame === "function" && - // @ts-ignore packet.options?.wsPreEncodedFrame !== undefined ); } diff --git a/packages/engine.io/lib/transports/webtransport.ts b/packages/engine.io/lib/transports/webtransport.ts index f675e7c37b..1cbe69295b 100644 --- a/packages/engine.io/lib/transports/webtransport.ts +++ b/packages/engine.io/lib/transports/webtransport.ts @@ -8,6 +8,7 @@ const debug = debugModule("engine:webtransport"); * Reference: https://developer.mozilla.org/en-US/docs/Web/API/WebTransport_API */ export class WebTransport extends Transport { + static upgradesTo?: undefined; private readonly writer; constructor( diff --git a/packages/engine.io/lib/userver.ts b/packages/engine.io/lib/userver.ts index e8fb47f580..9ef754b736 100644 --- a/packages/engine.io/lib/userver.ts +++ b/packages/engine.io/lib/userver.ts @@ -2,6 +2,7 @@ import debugModule from "debug"; import { AttachOptions, BaseServer, Server } from "./server"; import { HttpRequest, HttpResponse, TemplatedApp } from "uWebSockets.js"; import transports from "./transports-uws"; +import { EngineRequest } from "./transport"; const debug = debugModule("engine:uws"); @@ -36,7 +37,7 @@ export class uServer extends BaseServer { * * @private */ - private prepare(req, res: HttpResponse) { + private prepare(req: HttpRequest & EngineRequest, res: HttpResponse) { req.method = req.getMethod().toUpperCase(); req.url = req.getUrl(); @@ -48,6 +49,7 @@ export class uServer extends BaseServer { req.headers[key] = value; }); + // @ts-expect-error req.connection = { remoteAddress: Buffer.from(res.getRemoteAddressAsText()).toString(), }; @@ -57,7 +59,7 @@ export class uServer extends BaseServer { }); } - protected createTransport(transportName, req) { + protected createTransport(transportName: string, req: EngineRequest) { return new transports[transportName](req); } @@ -238,8 +240,8 @@ export class uServer extends BaseServer { private abortRequest( res: HttpResponse | ResponseWrapper, - errorCode, - errorContext, + errorCode: number, + errorContext?: {message?: string}, ) { const statusCode = errorCode === Server.errors.FORBIDDEN diff --git a/packages/socket.io-adapter/lib/in-memory-adapter.ts b/packages/socket.io-adapter/lib/in-memory-adapter.ts index 2b78e8285e..84c338d8d9 100644 --- a/packages/socket.io-adapter/lib/in-memory-adapter.ts +++ b/packages/socket.io-adapter/lib/in-memory-adapter.ts @@ -1,6 +1,7 @@ import { EventEmitter } from "events"; import { yeast } from "./contrib/yeast"; -import WebSocket = require("ws"); +import type {Namespace, Socket} from 'socket.io'; +import * as WebSocket from 'ws'; // @ts-expect-error const canPreComputeFrame = typeof WebSocket?.Sender?.frame === "function"; @@ -51,9 +52,9 @@ export class Adapter extends EventEmitter { /** * In-memory adapter constructor. * - * @param {Namespace} nsp + * @param nsp */ - constructor(readonly nsp: any) { + constructor(readonly nsp: Namespace) { super(); this.encoder = nsp.server.encoder; } @@ -171,10 +172,13 @@ export class Adapter extends EventEmitter { const encodedPackets = this._encode(packet, packetOpts); this.apply(opts, (socket) => { + // @ts-expect-error use of private if (typeof socket.notifyOutgoingListeners === "function") { + // @ts-expect-error use of private socket.notifyOutgoingListeners(packet); } + // @ts-expect-error use of private socket.client.writeToEngine(encodedPackets, packetOpts); }); } @@ -219,12 +223,16 @@ export class Adapter extends EventEmitter { // track the total number of acknowledgements that are expected clientCount++; // call the ack callback for each client response + // @ts-expect-error use of private socket.acks.set(packet.id, ack); + // @ts-expect-error use of private if (typeof socket.notifyOutgoingListeners === "function") { + // @ts-expect-error use of private socket.notifyOutgoingListeners(packet); } + // @ts-expect-error use of private socket.client.writeToEngine(encodedPackets, packetOpts); }); @@ -330,7 +338,7 @@ export class Adapter extends EventEmitter { }); } - private apply(opts: BroadcastOptions, callback: (socket) => void): void { + private apply(opts: BroadcastOptions, callback: (socket: Socket) => void): void { const rooms = opts.rooms; const except = this.computeExceptSids(opts.except); diff --git a/packages/socket.io/lib/client.ts b/packages/socket.io/lib/client.ts index 6ca7b77818..d65f3cf075 100644 --- a/packages/socket.io/lib/client.ts +++ b/packages/socket.io/lib/client.ts @@ -1,6 +1,6 @@ import { Decoder, Encoder, Packet, PacketType } from "socket.io-parser"; -import debugModule = require("debug"); -import url = require("url"); +import debugModule from "debug"; +import url from "url"; import type { IncomingMessage } from "http"; import type { Server } from "./index"; import type { Namespace } from "./namespace"; @@ -61,12 +61,13 @@ export class Client< */ constructor( server: Server, - conn: any, + conn: RawSocket ) { this.server = server; this.conn = conn; this.encoder = server.encoder; this.decoder = new server._parser.Decoder(); + // @ts-expect-error use of private this.id = conn.id; this.setup(); } @@ -216,13 +217,13 @@ export class Client< * @param {Object} opts * @private */ - _packet(packet: Packet | any[], opts: WriteOptions = {}): void { + _packet(packet: Packet | Packet[], opts: WriteOptions = {}): void { if (this.conn.readyState !== "open") { debug("ignoring packet write %j", packet); return; } const encodedPackets = opts.preEncoded - ? (packet as any[]) // previous versions of the adapter incorrectly used socket.packet() instead of writeToEngine() + ? (packet as Packet[]) // previous versions of the adapter incorrectly used socket.packet() instead of writeToEngine() : this.encoder.encode(packet as Packet); this.writeToEngine(encodedPackets, opts); } @@ -250,7 +251,7 @@ export class Client< * * @private */ - private ondata(data): void { + private ondata(data: unknown): void { // try/catch is needed for protocol violations (GH-1880) try { this.decoder.add(data); diff --git a/packages/socket.io/lib/index.ts b/packages/socket.io/lib/index.ts index b77b8fd3fd..8ec5dcdb0d 100644 --- a/packages/socket.io/lib/index.ts +++ b/packages/socket.io/lib/index.ts @@ -1,4 +1,4 @@ -import http = require("http"); +import http from 'http'; import type { Server as HTTPSServer } from "https"; import type { Http2SecureServer, Http2Server } from "http2"; import { createReadStream } from "fs"; @@ -7,7 +7,7 @@ import accepts = require("accepts"); import { pipeline } from "stream"; import path = require("path"); import { attach, Server as Engine, uServer } from "engine.io"; -import type { ServerOptions as EngineOptions, AttachOptions } from "engine.io"; +import type { ServerOptions as EngineOptions, AttachOptions, Socket as RawSocket } from "engine.io"; import { Client } from "./client"; import { EventEmitter } from "events"; import { ExtendedError, Namespace, ServerReservedEventsMap } from "./namespace"; @@ -506,6 +506,11 @@ export class Server< return this; } + /** + * attach uServer app + * @param app + * @param opts + */ public attachApp(app /*: TemplatedApp */, opts: Partial = {}) { // merge the options passed to the Socket.IO server Object.assign(opts, this.opts); @@ -582,7 +587,7 @@ export class Server< ): void { // initialize engine debug("creating engine.io instance with opts %j", opts); - this.eio = attach(srv, opts); + this.eio = attach(srv as http.Server, opts); // attach static file serving if (this._serveClient) this.attachServe(srv); @@ -723,11 +728,12 @@ export class Server< * @return self * @private */ - private onconnection(conn): this { + private onconnection(conn: RawSocket): this { + // @ts-expect-error use of private debug("incoming connection with id %s", conn.id); const client = new Client(this, conn); if (conn.protocol === 3) { - // @ts-ignore + // @ts-expect-error use of private client.connect("/"); } return this; diff --git a/packages/socket.io/lib/socket.ts b/packages/socket.io/lib/socket.ts index 719b597e59..55131fcee7 100644 --- a/packages/socket.io/lib/socket.ts +++ b/packages/socket.io/lib/socket.ts @@ -163,7 +163,7 @@ export class Socket< ) { super(); this.server = nsp.server; - this.adapter = this.nsp.adapter; + this.adapter = nsp.adapter; if (previousSession) { this.id = previousSession.sid; this.pid = previousSession.pid; From c869af4ff774a7460f501ef77ea276ad48039ae3 Mon Sep 17 00:00:00 2001 From: Wang Guan Date: Sun, 27 Jul 2025 13:53:56 +0900 Subject: [PATCH 2/3] make tsc happy --- packages/engine.io/lib/engine.io.ts | 2 +- packages/engine.io/lib/server.ts | 4 ++-- packages/engine.io/lib/userver.ts | 14 +++++++------- .../socket.io-adapter/lib/in-memory-adapter.ts | 14 ++++++-------- packages/socket.io-cluster-engine/lib/engine.ts | 8 ++++---- 5 files changed, 20 insertions(+), 22 deletions(-) diff --git a/packages/engine.io/lib/engine.io.ts b/packages/engine.io/lib/engine.io.ts index 83f87711a0..e9653f6b0a 100644 --- a/packages/engine.io/lib/engine.io.ts +++ b/packages/engine.io/lib/engine.io.ts @@ -4,7 +4,7 @@ import transports from "./transports/index"; import * as parser from "engine.io-parser"; export { Server, transports, listen, attach, parser }; -export type { AttachOptions, ServerOptions, BaseServer } from "./server"; +export type { AttachOptions, ServerOptions, BaseServer, ErrorCallback } from "./server"; export { uServer } from "./userver"; export { Socket } from "./socket"; export { Transport } from "./transport"; diff --git a/packages/engine.io/lib/server.ts b/packages/engine.io/lib/server.ts index 30cfa50dc2..e3af2d3723 100644 --- a/packages/engine.io/lib/server.ts +++ b/packages/engine.io/lib/server.ts @@ -472,7 +472,7 @@ export abstract class BaseServer extends EventEmitter { debug('handshaking client "%s"', id); try { - var transport = this.createTransport(transportName, req); + var transport = this.createTransport(transportName as Transport, req); if ("polling" === transportName) { transport.maxHttpBufferSize = this.opts.maxHttpBufferSize; transport.httpCompression = this.opts.httpCompression; @@ -878,7 +878,7 @@ export class Server extends BaseServer { websocket.removeListener("error", onUpgradeError); const transport: TransportImpl = this.createTransport( - req._query.transport, + req._query.transport as Transport, req ); // @ts-expect-error this option is only for WebSocket impl diff --git a/packages/engine.io/lib/userver.ts b/packages/engine.io/lib/userver.ts index 9ef754b736..7dd3852230 100644 --- a/packages/engine.io/lib/userver.ts +++ b/packages/engine.io/lib/userver.ts @@ -125,7 +125,7 @@ export class uServer extends BaseServer { req: HttpRequest & { res: any; _query: any }, ) { debug('handling "%s" http request "%s"', req.getMethod(), req.getUrl()); - this.prepare(req, res); + this.prepare(req as unknown as (HttpRequest & EngineRequest), res); req.res = res; @@ -148,7 +148,7 @@ export class uServer extends BaseServer { } else { const closeConnection = (errorCode, errorContext) => this.abortRequest(res, errorCode, errorContext); - this.handshake(req._query.transport, req, closeConnection); + this.handshake(req._query.transport, req as unknown as EngineRequest, closeConnection); } }; @@ -156,7 +156,7 @@ export class uServer extends BaseServer { if (err) { callback(Server.errors.BAD_REQUEST, { name: "MIDDLEWARE_FAILURE" }); } else { - this.verify(req, false, callback); + this.verify(req as unknown as (HttpRequest & EngineRequest), false, callback); } }); } @@ -168,7 +168,7 @@ export class uServer extends BaseServer { ) { debug("on upgrade"); - this.prepare(req, res); + this.prepare(req as unknown as (HttpRequest & EngineRequest), res); req.res = res; @@ -200,13 +200,13 @@ export class uServer extends BaseServer { return res.close(); } else { debug("upgrading existing transport"); - transport = this.createTransport(req._query.transport, req); + transport = this.createTransport(req._query.transport, req as unknown as EngineRequest); client._maybeUpgrade(transport); } } else { transport = await this.handshake( req._query.transport, - req, + req as unknown as EngineRequest, (errorCode, errorContext) => this.abortRequest(res, errorCode, errorContext), ); @@ -233,7 +233,7 @@ export class uServer extends BaseServer { if (err) { callback(Server.errors.BAD_REQUEST, { name: "MIDDLEWARE_FAILURE" }); } else { - this.verify(req, true, callback); + this.verify(req as unknown as EngineRequest, true, callback); } }); } diff --git a/packages/socket.io-adapter/lib/in-memory-adapter.ts b/packages/socket.io-adapter/lib/in-memory-adapter.ts index 84c338d8d9..cd7dafaf15 100644 --- a/packages/socket.io-adapter/lib/in-memory-adapter.ts +++ b/packages/socket.io-adapter/lib/in-memory-adapter.ts @@ -1,6 +1,11 @@ import { EventEmitter } from "events"; import { yeast } from "./contrib/yeast"; -import type {Namespace, Socket} from 'socket.io'; + +// due to build order and circular dependencies, we cannot import these types directly +// import type {Namespace, Socket} from 'socket.io'; +type Namespace = any; +type Socket = any; + import * as WebSocket from 'ws'; // @ts-expect-error @@ -172,13 +177,10 @@ export class Adapter extends EventEmitter { const encodedPackets = this._encode(packet, packetOpts); this.apply(opts, (socket) => { - // @ts-expect-error use of private if (typeof socket.notifyOutgoingListeners === "function") { - // @ts-expect-error use of private socket.notifyOutgoingListeners(packet); } - // @ts-expect-error use of private socket.client.writeToEngine(encodedPackets, packetOpts); }); } @@ -223,16 +225,12 @@ export class Adapter extends EventEmitter { // track the total number of acknowledgements that are expected clientCount++; // call the ack callback for each client response - // @ts-expect-error use of private socket.acks.set(packet.id, ack); - // @ts-expect-error use of private if (typeof socket.notifyOutgoingListeners === "function") { - // @ts-expect-error use of private socket.notifyOutgoingListeners(packet); } - // @ts-expect-error use of private socket.client.writeToEngine(encodedPackets, packetOpts); }); diff --git a/packages/socket.io-cluster-engine/lib/engine.ts b/packages/socket.io-cluster-engine/lib/engine.ts index 4972f31881..7ac1369267 100644 --- a/packages/socket.io-cluster-engine/lib/engine.ts +++ b/packages/socket.io-cluster-engine/lib/engine.ts @@ -1,4 +1,4 @@ -import { Server, type ServerOptions, Socket, type Transport } from "engine.io"; +import { Server, type ServerOptions, type ErrorCallback, Socket, type Transport } from "engine.io"; import { randomBytes } from "node:crypto"; import { setTimeout, clearTimeout } from "node:timers"; import { type IncomingMessage } from "node:http"; @@ -392,9 +392,9 @@ export abstract class ClusterEngine extends Server { override verify( req: IncomingMessage & { _query: Record }, upgrade: boolean, - fn: (errorCode?: number, context?: any) => void, + fn: ErrorCallback ): void { - super.verify(req, upgrade, (errorCode: number, errorContext: any) => { + super.verify(req, upgrade, (errorCode, errorContext) => { if (errorCode !== Server.errors.UNKNOWN_SID) { return fn(errorCode, errorContext); } @@ -412,7 +412,7 @@ export abstract class ClusterEngine extends Server { req[kSenderId] = senderId; fn(); } else { - const transport = this.createTransport(transportName, req); + const transport = this.createTransport(transportName as any, req); this._hookTransport(sid, transport, lockType, senderId); transport.onRequest(req); } From 4022091871e64901614eb228348175d390dd9332 Mon Sep 17 00:00:00 2001 From: Wang Guan Date: Sun, 27 Jul 2025 14:28:00 +0900 Subject: [PATCH 3/3] make prettier happy --- packages/engine.io-parser/lib/commons.ts | 6 ++++- packages/engine.io/lib/engine.io.ts | 12 ++++++++-- packages/engine.io/lib/server.ts | 7 ++++-- packages/engine.io/lib/socket.ts | 4 +++- .../engine.io/lib/transports-uws/polling.ts | 6 ++++- packages/engine.io/lib/transports/polling.ts | 6 ++++- .../engine.io/lib/transports/websocket.ts | 2 +- packages/engine.io/lib/userver.ts | 23 ++++++++++++++----- .../lib/in-memory-adapter.ts | 7 ++++-- .../socket.io-cluster-engine/lib/engine.ts | 10 ++++++-- packages/socket.io/lib/client.ts | 2 +- packages/socket.io/lib/index.ts | 8 +++++-- 12 files changed, 71 insertions(+), 22 deletions(-) diff --git a/packages/engine.io-parser/lib/commons.ts b/packages/engine.io-parser/lib/commons.ts index 2930da8089..ab0dfc677f 100644 --- a/packages/engine.io-parser/lib/commons.ts +++ b/packages/engine.io-parser/lib/commons.ts @@ -32,7 +32,11 @@ export type RawData = any; export interface Packet { type: PacketType; - options?: { compress: boolean, wsPreEncoded?: string, wsPreEncodedFrame?: boolean }; + options?: { + compress: boolean; + wsPreEncoded?: string; + wsPreEncodedFrame?: boolean; + }; data?: RawData; } diff --git a/packages/engine.io/lib/engine.io.ts b/packages/engine.io/lib/engine.io.ts index e9653f6b0a..73f8dae68d 100644 --- a/packages/engine.io/lib/engine.io.ts +++ b/packages/engine.io/lib/engine.io.ts @@ -4,7 +4,12 @@ import transports from "./transports/index"; import * as parser from "engine.io-parser"; export { Server, transports, listen, attach, parser }; -export type { AttachOptions, ServerOptions, BaseServer, ErrorCallback } from "./server"; +export type { + AttachOptions, + ServerOptions, + BaseServer, + ErrorCallback, +} from "./server"; export { uServer } from "./userver"; export { Socket } from "./socket"; export { Transport } from "./transport"; @@ -51,7 +56,10 @@ function listen( * @return engine.io server */ -function attach(server: HttpServer, options: AttachOptions & ServerOptions): Server { +function attach( + server: HttpServer, + options: AttachOptions & ServerOptions, +): Server { const engine = new Server(options); engine.attach(server, options); return engine; diff --git a/packages/engine.io/lib/server.ts b/packages/engine.io/lib/server.ts index e3af2d3723..ba19e33248 100644 --- a/packages/engine.io/lib/server.ts +++ b/packages/engine.io/lib/server.ts @@ -609,7 +609,10 @@ export abstract class BaseServer extends EventEmitter { } } - protected abstract createTransport(transportName: Transport, req: EngineRequest); + protected abstract createTransport( + transportName: Transport, + req: EngineRequest, + ); /** * Protocol errors mappings. @@ -879,7 +882,7 @@ export class Server extends BaseServer { const transport: TransportImpl = this.createTransport( req._query.transport as Transport, - req + req, ); // @ts-expect-error this option is only for WebSocket impl transport.perMessageDeflate = this.opts.perMessageDeflate; diff --git a/packages/engine.io/lib/socket.ts b/packages/engine.io/lib/socket.ts index 0dbcccf9cf..c2efe8ebbe 100644 --- a/packages/engine.io/lib/socket.ts +++ b/packages/engine.io/lib/socket.ts @@ -538,7 +538,9 @@ export class Socket extends EventEmitter { */ private getAvailableUpgrades() { const availableUpgrades = []; - const allUpgrades = this.server.upgrades(this.transport.name as keyof typeof transports); + const allUpgrades = this.server.upgrades( + this.transport.name as keyof typeof transports, + ); for (let i = 0; i < allUpgrades.length; ++i) { const upg = allUpgrades[i] as keyof typeof transports; if (this.server.opts.transports.indexOf(upg) !== -1) { diff --git a/packages/engine.io/lib/transports-uws/polling.ts b/packages/engine.io/lib/transports-uws/polling.ts index 342d25b4e3..7463b3b3d3 100644 --- a/packages/engine.io/lib/transports-uws/polling.ts +++ b/packages/engine.io/lib/transports-uws/polling.ts @@ -273,7 +273,11 @@ export class Polling extends Transport { }; if (this.protocol === 3) { - (this.parser as typeof parser_v3).encodePayload(packets, this.supportsBinary, doWrite); + (this.parser as typeof parser_v3).encodePayload( + packets, + this.supportsBinary, + doWrite, + ); } else { (this.parser as typeof parser_v4).encodePayload(packets, doWrite); } diff --git a/packages/engine.io/lib/transports/polling.ts b/packages/engine.io/lib/transports/polling.ts index 618f36d43a..15e492a19c 100644 --- a/packages/engine.io/lib/transports/polling.ts +++ b/packages/engine.io/lib/transports/polling.ts @@ -235,7 +235,11 @@ export class Polling extends Transport { }; if (this.protocol === 3) { - (this.parser as typeof parser_v3).encodePayload(packets, this.supportsBinary, doWrite); + (this.parser as typeof parser_v3).encodePayload( + packets, + this.supportsBinary, + doWrite, + ); } else { (this.parser as typeof parser_v4).encodePayload(packets, doWrite); } diff --git a/packages/engine.io/lib/transports/websocket.ts b/packages/engine.io/lib/transports/websocket.ts index fe084674fe..98c16b17f5 100644 --- a/packages/engine.io/lib/transports/websocket.ts +++ b/packages/engine.io/lib/transports/websocket.ts @@ -1,7 +1,7 @@ import { EngineRequest, Transport } from "../transport"; import debugModule from "debug"; import type { Packet, RawData } from "engine.io-parser"; -import type { PerMessageDeflateOptions, WebSocket as WsWebSocket } from 'ws'; +import type { PerMessageDeflateOptions, WebSocket as WsWebSocket } from "ws"; const debug = debugModule("engine:ws"); diff --git a/packages/engine.io/lib/userver.ts b/packages/engine.io/lib/userver.ts index 7dd3852230..71ed616fbb 100644 --- a/packages/engine.io/lib/userver.ts +++ b/packages/engine.io/lib/userver.ts @@ -125,7 +125,7 @@ export class uServer extends BaseServer { req: HttpRequest & { res: any; _query: any }, ) { debug('handling "%s" http request "%s"', req.getMethod(), req.getUrl()); - this.prepare(req as unknown as (HttpRequest & EngineRequest), res); + this.prepare(req as unknown as HttpRequest & EngineRequest, res); req.res = res; @@ -148,7 +148,11 @@ export class uServer extends BaseServer { } else { const closeConnection = (errorCode, errorContext) => this.abortRequest(res, errorCode, errorContext); - this.handshake(req._query.transport, req as unknown as EngineRequest, closeConnection); + this.handshake( + req._query.transport, + req as unknown as EngineRequest, + closeConnection, + ); } }; @@ -156,7 +160,11 @@ export class uServer extends BaseServer { if (err) { callback(Server.errors.BAD_REQUEST, { name: "MIDDLEWARE_FAILURE" }); } else { - this.verify(req as unknown as (HttpRequest & EngineRequest), false, callback); + this.verify( + req as unknown as HttpRequest & EngineRequest, + false, + callback, + ); } }); } @@ -168,7 +176,7 @@ export class uServer extends BaseServer { ) { debug("on upgrade"); - this.prepare(req as unknown as (HttpRequest & EngineRequest), res); + this.prepare(req as unknown as HttpRequest & EngineRequest, res); req.res = res; @@ -200,7 +208,10 @@ export class uServer extends BaseServer { return res.close(); } else { debug("upgrading existing transport"); - transport = this.createTransport(req._query.transport, req as unknown as EngineRequest); + transport = this.createTransport( + req._query.transport, + req as unknown as EngineRequest, + ); client._maybeUpgrade(transport); } } else { @@ -241,7 +252,7 @@ export class uServer extends BaseServer { private abortRequest( res: HttpResponse | ResponseWrapper, errorCode: number, - errorContext?: {message?: string}, + errorContext?: { message?: string }, ) { const statusCode = errorCode === Server.errors.FORBIDDEN diff --git a/packages/socket.io-adapter/lib/in-memory-adapter.ts b/packages/socket.io-adapter/lib/in-memory-adapter.ts index cd7dafaf15..03b7c5d636 100644 --- a/packages/socket.io-adapter/lib/in-memory-adapter.ts +++ b/packages/socket.io-adapter/lib/in-memory-adapter.ts @@ -6,7 +6,7 @@ import { yeast } from "./contrib/yeast"; type Namespace = any; type Socket = any; -import * as WebSocket from 'ws'; +import * as WebSocket from "ws"; // @ts-expect-error const canPreComputeFrame = typeof WebSocket?.Sender?.frame === "function"; @@ -336,7 +336,10 @@ export class Adapter extends EventEmitter { }); } - private apply(opts: BroadcastOptions, callback: (socket: Socket) => void): void { + private apply( + opts: BroadcastOptions, + callback: (socket: Socket) => void, + ): void { const rooms = opts.rooms; const except = this.computeExceptSids(opts.except); diff --git a/packages/socket.io-cluster-engine/lib/engine.ts b/packages/socket.io-cluster-engine/lib/engine.ts index 7ac1369267..e12f643cb7 100644 --- a/packages/socket.io-cluster-engine/lib/engine.ts +++ b/packages/socket.io-cluster-engine/lib/engine.ts @@ -1,4 +1,10 @@ -import { Server, type ServerOptions, type ErrorCallback, Socket, type Transport } from "engine.io"; +import { + Server, + type ServerOptions, + type ErrorCallback, + Socket, + type Transport, +} from "engine.io"; import { randomBytes } from "node:crypto"; import { setTimeout, clearTimeout } from "node:timers"; import { type IncomingMessage } from "node:http"; @@ -392,7 +398,7 @@ export abstract class ClusterEngine extends Server { override verify( req: IncomingMessage & { _query: Record }, upgrade: boolean, - fn: ErrorCallback + fn: ErrorCallback, ): void { super.verify(req, upgrade, (errorCode, errorContext) => { if (errorCode !== Server.errors.UNKNOWN_SID) { diff --git a/packages/socket.io/lib/client.ts b/packages/socket.io/lib/client.ts index d65f3cf075..99ff42cd12 100644 --- a/packages/socket.io/lib/client.ts +++ b/packages/socket.io/lib/client.ts @@ -61,7 +61,7 @@ export class Client< */ constructor( server: Server, - conn: RawSocket + conn: RawSocket, ) { this.server = server; this.conn = conn; diff --git a/packages/socket.io/lib/index.ts b/packages/socket.io/lib/index.ts index 8ec5dcdb0d..940df34d77 100644 --- a/packages/socket.io/lib/index.ts +++ b/packages/socket.io/lib/index.ts @@ -1,4 +1,4 @@ -import http from 'http'; +import http from "http"; import type { Server as HTTPSServer } from "https"; import type { Http2SecureServer, Http2Server } from "http2"; import { createReadStream } from "fs"; @@ -7,7 +7,11 @@ import accepts = require("accepts"); import { pipeline } from "stream"; import path = require("path"); import { attach, Server as Engine, uServer } from "engine.io"; -import type { ServerOptions as EngineOptions, AttachOptions, Socket as RawSocket } from "engine.io"; +import type { + ServerOptions as EngineOptions, + AttachOptions, + Socket as RawSocket, +} from "engine.io"; import { Client } from "./client"; import { EventEmitter } from "events"; import { ExtendedError, Namespace, ServerReservedEventsMap } from "./namespace";