diff --git a/.eslintrc.json b/.eslintrc.json index a106a4247..feeefc05e 100644 --- a/.eslintrc.json +++ b/.eslintrc.json @@ -2,15 +2,16 @@ "parser": "@typescript-eslint/parser", "extends": [ "eslint:recommended", - "plugin:@typescript-eslint/eslint-recommended", - "plugin:@typescript-eslint/recommended" + "plugin:@typescript-eslint/recommended-type-checked", + "plugin:@typescript-eslint/strict-type-checked", + "plugin:@typescript-eslint/stylistic-type-checked" ], + "ignorePatterns": ["coverage", "jest.config.js", "dist", "__test__"], "env": { "node": true, "es6": true }, "parserOptions": { - "ecmaVersion": 2018, - "sourceType": "module" + "project": true } } diff --git a/__test__/models/messageQueue.spec.ts b/__test__/models/messageQueue.spec.ts index 3ae859be8..e50260a16 100644 --- a/__test__/models/messageQueue.spec.ts +++ b/__test__/models/messageQueue.spec.ts @@ -2,7 +2,7 @@ import { describe, expect, it } from "@jest/globals"; import { MessageQueue } from "../../src/models/messageQueue.ts"; import { MessageType } from "../../src/enums.ts"; -import type { IMessage } from "../../src/models/message.ts"; +import type { IMessage } from "../../src/index.js"; import { wait } from "../utils.ts"; describe("MessageQueue", () => { diff --git a/__test__/services/messagesExpire/index.spec.ts b/__test__/services/messagesExpire/index.spec.ts index 79f1df2e4..c9a016713 100644 --- a/__test__/services/messagesExpire/index.spec.ts +++ b/__test__/services/messagesExpire/index.spec.ts @@ -2,7 +2,7 @@ import { describe, expect, it } from "@jest/globals"; import { Client } from "../../../src/models/client.ts"; import { Realm } from "../../../src/models/realm.ts"; -import type { IMessage } from "../../../src/models/message.ts"; +import type { IMessage } from "../../../src/index.js"; import { MessagesExpire } from "../../../src/services/messagesExpire/index.ts"; import { MessageHandler } from "../../../src/messageHandler/index.ts"; import { MessageType } from "../../../src/enums.ts"; diff --git a/__test__/services/webSocketServer/index.spec.ts b/__test__/services/webSocketServer/index.spec.ts index 55c1bcca0..43b9e87e7 100644 --- a/__test__/services/webSocketServer/index.spec.ts +++ b/__test__/services/webSocketServer/index.spec.ts @@ -204,11 +204,11 @@ describe("WebSocketServer", () => { ws.destroy = async (): Promise => { ws.close(); - wait(10); + await wait(10); webSocketServer.destroy?.(); - wait(10); + await wait(10); ws.destroy = undefined; }; diff --git a/bin/peerjs.ts b/bin/peerjs.ts index f6a00a92d..a61d52f83 100644 --- a/bin/peerjs.ts +++ b/bin/peerjs.ts @@ -5,7 +5,7 @@ import fs from "node:fs"; const optimistUsageLength = 98; import yargs from "yargs"; import { hideBin } from "yargs/helpers"; -import { PeerServer } from "../src"; +import { PeerServer } from "../src/index.js"; import type { AddressInfo } from "node:net"; import type { CorsOptions } from "cors"; @@ -66,7 +66,7 @@ const opts = y type: "string", demandOption: false, describe: "custom path", - default: process.env["PEERSERVER_PATH"] || "/", + default: process.env["PEERSERVER_PATH"] ?? "/", }, allow_discovery: { type: "boolean", @@ -89,7 +89,9 @@ const opts = y .parseSync(); if (!opts.port) { - opts.port = parseInt(process.env["PORT"] as string); + // .port is only not set if the PORT env var is set + // eslint-disable-next-line @typescript-eslint/no-non-null-assertion + opts.port = parseInt(process.env["PORT"]!); } if (opts.cors) { opts["corsOptions"] = { @@ -97,10 +99,10 @@ if (opts.cors) { } satisfies CorsOptions; } process.on("uncaughtException", function (e) { - console.error("Error: " + e); + console.error("Error: " + e.toString()); }); -if (opts.sslkey || opts.sslcert) { +if (opts.sslkey ?? opts.sslcert) { if (opts.sslkey && opts.sslcert) { opts["ssl"] = { key: fs.readFileSync(path.resolve(opts.sslkey)), diff --git a/src/index.ts b/src/index.ts index 873e0f33d..1b5dc1036 100644 --- a/src/index.ts +++ b/src/index.ts @@ -31,6 +31,7 @@ function ExpressPeerServer( } app.on("mount", () => { + // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition if (!server) { throw new Error( "Server is not passed to constructor - " + "can't start PeerServer", diff --git a/src/instance.ts b/src/instance.ts index 65f304223..d88f0be85 100644 --- a/src/instance.ts +++ b/src/instance.ts @@ -21,6 +21,7 @@ export interface PeerServerEvents { event: "message", listener: (client: IClient, message: IMessage) => void, ): this; + // eslint-disable-next-line @typescript-eslint/unified-signatures on(event: "disconnect", listener: (client: IClient) => void): this; on(event: "error", listener: (client: Error) => void): this; } diff --git a/src/messageHandler/handlersRegistry.ts b/src/messageHandler/handlersRegistry.ts index 378de2d13..e778db18d 100644 --- a/src/messageHandler/handlersRegistry.ts +++ b/src/messageHandler/handlersRegistry.ts @@ -9,7 +9,7 @@ export interface IHandlersRegistry { } export class HandlersRegistry implements IHandlersRegistry { - private readonly handlers: Map = new Map(); + private readonly handlers = new Map(); public registerHandler(messageType: MessageType, handler: Handler): void { if (this.handlers.has(messageType)) return; diff --git a/src/models/realm.ts b/src/models/realm.ts index 512095307..ce7739798 100644 --- a/src/models/realm.ts +++ b/src/models/realm.ts @@ -25,8 +25,8 @@ export interface IRealm { } export class Realm implements IRealm { - private readonly clients: Map = new Map(); - private readonly messageQueues: Map = new Map(); + private readonly clients = new Map(); + private readonly messageQueues = new Map(); public getClientsIds(): string[] { return [...this.clients.keys()]; diff --git a/src/services/webSocketServer/index.ts b/src/services/webSocketServer/index.ts index 96610dd2d..3f32d6ec6 100644 --- a/src/services/webSocketServer/index.ts +++ b/src/services/webSocketServer/index.ts @@ -1,6 +1,5 @@ import { EventEmitter } from "node:events"; import type { IncomingMessage } from "node:http"; -import url from "node:url"; import type WebSocket from "ws"; import { Errors, MessageType } from "../../enums.ts"; import type { IClient } from "../../models/client.ts"; @@ -10,17 +9,12 @@ import type { IRealm } from "../../models/realm.ts"; import { WebSocketServer as Server } from "ws"; import type { Server as HttpServer } from "node:http"; import type { Server as HttpsServer } from "node:https"; +import { IMessage } from "../../models/message.js"; export interface IWebSocketServer extends EventEmitter { readonly path: string; } -interface IAuthParams { - id?: string; - token?: string; - key?: string; -} - type CustomConfig = Pick< IConfig, "path" | "key" | "concurrent_limit" | "createWebSocketServer" @@ -62,26 +56,33 @@ export class WebSocketServer extends EventEmitter implements IWebSocketServer { ? config.createWebSocketServer(options) : new Server(options); - this.socketServer.on("connection", (socket, req) => - this._onSocketConnection(socket, req), - ); - this.socketServer.on("error", (error: Error) => this._onSocketError(error)); + this.socketServer.on("connection", (socket, req) => { + this._onSocketConnection(socket, req); + }); + this.socketServer.on("error", (error: Error) => { + this._onSocketError(error); + }); } private _onSocketConnection(socket: WebSocket, req: IncomingMessage): void { // An unhandled socket error might crash the server. Handle it first. - socket.on("error", (error) => this._onSocketError(error)); - - const { query = {} } = url.parse(req.url ?? "", true); + socket.on("error", (error) => { + this._onSocketError(error); + }); - const { id, token, key }: IAuthParams = query; + const { searchParams } = new URL(req.url ?? ""); + const id = searchParams.get("id"); + const token = searchParams.get("token"); + const key = searchParams.get("key"); if (!id || !token || !key) { - return this._sendErrorAndClose(socket, Errors.INVALID_WS_PARAMETERS); + this._sendErrorAndClose(socket, Errors.INVALID_WS_PARAMETERS); + return; } if (key !== this.config.key) { - return this._sendErrorAndClose(socket, Errors.INVALID_KEY); + this._sendErrorAndClose(socket, Errors.INVALID_KEY); + return; } const client = this.realm.getClientById(id); @@ -96,10 +97,12 @@ export class WebSocketServer extends EventEmitter implements IWebSocketServer { }), ); - return socket.close(); + socket.close(); + return; } - return this._configureWS(socket, client); + this._configureWS(socket, client); + return; } this._registerClient({ socket, id, token }); @@ -123,7 +126,8 @@ export class WebSocketServer extends EventEmitter implements IWebSocketServer { const clientsCount = this.realm.getClientsIds().length; if (clientsCount >= this.config.concurrent_limit) { - return this._sendErrorAndClose(socket, Errors.CONNECTION_LIMIT_EXCEED); + this._sendErrorAndClose(socket, Errors.CONNECTION_LIMIT_EXCEED); + return; } const newClient: IClient = new Client({ id, token }); @@ -147,7 +151,8 @@ export class WebSocketServer extends EventEmitter implements IWebSocketServer { // Handle messages from peers. socket.on("message", (data) => { try { - const message = JSON.parse(data.toString()); + // eslint-disable-next-line @typescript-eslint/no-base-to-string + const message = JSON.parse(data.toString()) as Writable; message.src = client.getId(); @@ -171,3 +176,7 @@ export class WebSocketServer extends EventEmitter implements IWebSocketServer { socket.close(); } } + +type Writable = { + -readonly [K in keyof T]: T[K]; +}; diff --git a/tsconfig.json b/tsconfig.json index 7ab86f724..e9b9fb85e 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -7,6 +7,5 @@ "exactOptionalPropertyTypes": false, "allowImportingTsExtensions": true }, - "include": ["./src/**/*", "__test__/**/*"], - "exclude": ["test", "bin"] + "include": ["./src/**/*", "__test__/**/*", "bin/**/*"] }