diff --git a/server/eslint.config.js b/server/eslint.config.js index 13f1fc038..c854029a0 100755 --- a/server/eslint.config.js +++ b/server/eslint.config.js @@ -1,6 +1,7 @@ import globals from "globals"; import pluginJs from "@eslint/js"; import mochaPlugin from "eslint-plugin-mocha"; +import tseslint from "typescript-eslint"; /* Please do not forget to look at the latest eslint configurations and rules. @@ -10,6 +11,9 @@ ESlint v9 configuration is different than v8. /** @type {import('eslint').Linter.Config[]} */ export default [ + { + ignores: ["dist/**", "node_modules/**", "coverage/**", "test/**"], + }, { languageOptions: { globals: { @@ -21,9 +25,19 @@ export default [ }, }, pluginJs.configs.recommended, // Core JS rules + ...tseslint.configs.recommended, // TypeScript recommended rules mochaPlugin.configs.flat.recommended, // Mocha rules { + files: ["**/*.ts", "**/*.tsx"], + languageOptions: { + parser: tseslint.parser, + parserOptions: { + projectService: true, + tsconfigRootDir: import.meta.dirname, + }, + }, rules: { + "@typescript-eslint/no-explicit-any": "warn", // Warn on 'any' types "mocha/max-top-level-suites": "warn", // Warn if there are too many top-level suites instead of failing }, }, diff --git a/server/package-lock.json b/server/package-lock.json index c6f7fc936..7412b2561 100644 --- a/server/package-lock.json +++ b/server/package-lock.json @@ -65,6 +65,8 @@ "@types/ping": "0.4.4", "@types/swagger-ui-express": "4.1.8", "@types/ws": "^8.18.1", + "@typescript-eslint/eslint-plugin": "^8.56.1", + "@typescript-eslint/parser": "^8.56.1", "c8": "10.1.3", "eslint": "^9.17.0", "eslint-plugin-mocha": "^10.5.0", @@ -78,7 +80,8 @@ "ts-node": "^10.9.2", "tsc-alias": "1.8.16", "tsx": "4.20.5", - "typescript": "5.9.2" + "typescript": "5.9.2", + "typescript-eslint": "^8.56.1" }, "engines": { "node": ">=20" @@ -2045,9 +2048,9 @@ } }, "node_modules/@eslint-community/eslint-utils": { - "version": "4.9.0", - "resolved": "https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.9.0.tgz", - "integrity": "sha512-ayVFHdtZ+hsq1t2Dy24wCmGXGe4q9Gu3smhLYALJrr473ZH27MsnSL+LKUlimp4BWJqMDMLmPpx/Q9R3OAlL4g==", + "version": "4.9.1", + "resolved": "https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.9.1.tgz", + "integrity": "sha512-phrYmNiYppR7znFEdqgfWHXR6NCkZEK7hwWDHZUjit/2/U0r6XvkDl0SYnoM51Hq7FhCGdLDT6zxCCOY1hexsQ==", "dev": true, "license": "MIT", "dependencies": { @@ -4699,6 +4702,361 @@ "dev": true, "license": "MIT" }, + "node_modules/@typescript-eslint/eslint-plugin": { + "version": "8.56.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-8.56.1.tgz", + "integrity": "sha512-Jz9ZztpB37dNC+HU2HI28Bs9QXpzCz+y/twHOwhyrIRdbuVDxSytJNDl6z/aAKlaRIwC7y8wJdkBv7FxYGgi0A==", + "dev": true, + "license": "MIT", + "dependencies": { + "@eslint-community/regexpp": "^4.12.2", + "@typescript-eslint/scope-manager": "8.56.1", + "@typescript-eslint/type-utils": "8.56.1", + "@typescript-eslint/utils": "8.56.1", + "@typescript-eslint/visitor-keys": "8.56.1", + "ignore": "^7.0.5", + "natural-compare": "^1.4.0", + "ts-api-utils": "^2.4.0" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "@typescript-eslint/parser": "^8.56.1", + "eslint": "^8.57.0 || ^9.0.0 || ^10.0.0", + "typescript": ">=4.8.4 <6.0.0" + } + }, + "node_modules/@typescript-eslint/eslint-plugin/node_modules/ignore": { + "version": "7.0.5", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-7.0.5.tgz", + "integrity": "sha512-Hs59xBNfUIunMFgWAbGX5cq6893IbWg4KnrjbYwX3tx0ztorVgTDA6B2sxf8ejHJ4wz8BqGUMYlnzNBer5NvGg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 4" + } + }, + "node_modules/@typescript-eslint/parser": { + "version": "8.56.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-8.56.1.tgz", + "integrity": "sha512-klQbnPAAiGYFyI02+znpBRLyjL4/BrBd0nyWkdC0s/6xFLkXYQ8OoRrSkqacS1ddVxf/LDyODIKbQ5TgKAf/Fg==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "@typescript-eslint/scope-manager": "8.56.1", + "@typescript-eslint/types": "8.56.1", + "@typescript-eslint/typescript-estree": "8.56.1", + "@typescript-eslint/visitor-keys": "8.56.1", + "debug": "^4.4.3" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "^8.57.0 || ^9.0.0 || ^10.0.0", + "typescript": ">=4.8.4 <6.0.0" + } + }, + "node_modules/@typescript-eslint/parser/node_modules/debug": { + "version": "4.4.3", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.3.tgz", + "integrity": "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==", + "dev": true, + "license": "MIT", + "dependencies": { + "ms": "^2.1.3" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/@typescript-eslint/project-service": { + "version": "8.56.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/project-service/-/project-service-8.56.1.tgz", + "integrity": "sha512-TAdqQTzHNNvlVFfR+hu2PDJrURiwKsUvxFn1M0h95BB8ah5jejas08jUWG4dBA68jDMI988IvtfdAI53JzEHOQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@typescript-eslint/tsconfig-utils": "^8.56.1", + "@typescript-eslint/types": "^8.56.1", + "debug": "^4.4.3" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "typescript": ">=4.8.4 <6.0.0" + } + }, + "node_modules/@typescript-eslint/project-service/node_modules/debug": { + "version": "4.4.3", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.3.tgz", + "integrity": "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==", + "dev": true, + "license": "MIT", + "dependencies": { + "ms": "^2.1.3" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/@typescript-eslint/scope-manager": { + "version": "8.56.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-8.56.1.tgz", + "integrity": "sha512-YAi4VDKcIZp0O4tz/haYKhmIDZFEUPOreKbfdAN3SzUDMcPhJ8QI99xQXqX+HoUVq8cs85eRKnD+rne2UAnj2w==", + "dev": true, + "license": "MIT", + "dependencies": { + "@typescript-eslint/types": "8.56.1", + "@typescript-eslint/visitor-keys": "8.56.1" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/@typescript-eslint/tsconfig-utils": { + "version": "8.56.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/tsconfig-utils/-/tsconfig-utils-8.56.1.tgz", + "integrity": "sha512-qOtCYzKEeyr3aR9f28mPJqBty7+DBqsdd63eO0yyDwc6vgThj2UjWfJIcsFeSucYydqcuudMOprZ+x1SpF3ZuQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "typescript": ">=4.8.4 <6.0.0" + } + }, + "node_modules/@typescript-eslint/type-utils": { + "version": "8.56.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-8.56.1.tgz", + "integrity": "sha512-yB/7dxi7MgTtGhZdaHCemf7PuwrHMenHjmzgUW1aJpO+bBU43OycnM3Wn+DdvDO/8zzA9HlhaJ0AUGuvri4oGg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@typescript-eslint/types": "8.56.1", + "@typescript-eslint/typescript-estree": "8.56.1", + "@typescript-eslint/utils": "8.56.1", + "debug": "^4.4.3", + "ts-api-utils": "^2.4.0" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "^8.57.0 || ^9.0.0 || ^10.0.0", + "typescript": ">=4.8.4 <6.0.0" + } + }, + "node_modules/@typescript-eslint/type-utils/node_modules/debug": { + "version": "4.4.3", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.3.tgz", + "integrity": "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==", + "dev": true, + "license": "MIT", + "dependencies": { + "ms": "^2.1.3" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/@typescript-eslint/types": { + "version": "8.56.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-8.56.1.tgz", + "integrity": "sha512-dbMkdIUkIkchgGDIv7KLUpa0Mda4IYjo4IAMJUZ+3xNoUXxMsk9YtKpTHSChRS85o+H9ftm51gsK1dZReY9CVw==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/@typescript-eslint/typescript-estree": { + "version": "8.56.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-8.56.1.tgz", + "integrity": "sha512-qzUL1qgalIvKWAf9C1HpvBjif+Vm6rcT5wZd4VoMb9+Km3iS3Cv9DY6dMRMDtPnwRAFyAi7YXJpTIEXLvdfPxg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@typescript-eslint/project-service": "8.56.1", + "@typescript-eslint/tsconfig-utils": "8.56.1", + "@typescript-eslint/types": "8.56.1", + "@typescript-eslint/visitor-keys": "8.56.1", + "debug": "^4.4.3", + "minimatch": "^10.2.2", + "semver": "^7.7.3", + "tinyglobby": "^0.2.15", + "ts-api-utils": "^2.4.0" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "typescript": ">=4.8.4 <6.0.0" + } + }, + "node_modules/@typescript-eslint/typescript-estree/node_modules/balanced-match": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-4.0.4.tgz", + "integrity": "sha512-BLrgEcRTwX2o6gGxGOCNyMvGSp35YofuYzw9h1IMTRmKqttAZZVU67bdb9Pr2vUHA8+j3i2tJfjO6C6+4myGTA==", + "dev": true, + "license": "MIT", + "engines": { + "node": "18 || 20 || >=22" + } + }, + "node_modules/@typescript-eslint/typescript-estree/node_modules/brace-expansion": { + "version": "5.0.4", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-5.0.4.tgz", + "integrity": "sha512-h+DEnpVvxmfVefa4jFbCf5HdH5YMDXRsmKflpf1pILZWRFlTbJpxeU55nJl4Smt5HQaGzg1o6RHFPJaOqnmBDg==", + "dev": true, + "license": "MIT", + "dependencies": { + "balanced-match": "^4.0.2" + }, + "engines": { + "node": "18 || 20 || >=22" + } + }, + "node_modules/@typescript-eslint/typescript-estree/node_modules/debug": { + "version": "4.4.3", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.3.tgz", + "integrity": "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==", + "dev": true, + "license": "MIT", + "dependencies": { + "ms": "^2.1.3" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/@typescript-eslint/typescript-estree/node_modules/minimatch": { + "version": "10.2.4", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-10.2.4.tgz", + "integrity": "sha512-oRjTw/97aTBN0RHbYCdtF1MQfvusSIBQM0IZEgzl6426+8jSC0nF1a/GmnVLpfB9yyr6g6FTqWqiZVbxrtaCIg==", + "dev": true, + "license": "BlueOak-1.0.0", + "dependencies": { + "brace-expansion": "^5.0.2" + }, + "engines": { + "node": "18 || 20 || >=22" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/@typescript-eslint/utils": { + "version": "8.56.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-8.56.1.tgz", + "integrity": "sha512-HPAVNIME3tABJ61siYlHzSWCGtOoeP2RTIaHXFMPqjrQKCGB9OgUVdiNgH7TJS2JNIQ5qQ4RsAUDuGaGme/KOA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@eslint-community/eslint-utils": "^4.9.1", + "@typescript-eslint/scope-manager": "8.56.1", + "@typescript-eslint/types": "8.56.1", + "@typescript-eslint/typescript-estree": "8.56.1" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "^8.57.0 || ^9.0.0 || ^10.0.0", + "typescript": ">=4.8.4 <6.0.0" + } + }, + "node_modules/@typescript-eslint/visitor-keys": { + "version": "8.56.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-8.56.1.tgz", + "integrity": "sha512-KiROIzYdEV85YygXw6BI/Dx4fnBlFQu6Mq4QE4MOH9fFnhohw6wX/OAvDY2/C+ut0I3RSPKenvZJIVYqJNkhEw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@typescript-eslint/types": "8.56.1", + "eslint-visitor-keys": "^5.0.0" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/@typescript-eslint/visitor-keys/node_modules/eslint-visitor-keys": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-5.0.1.tgz", + "integrity": "sha512-tD40eHxA35h0PEIZNeIjkHoDR4YjjJp34biM0mDvplBe//mB+IHCqHDGV7pxF+7MklTvighcCPPZC7ynWyjdTA==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": "^20.19.0 || ^22.13.0 || >=24" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, "node_modules/@ungap/structured-clone": { "version": "1.3.0", "resolved": "https://registry.npmjs.org/@ungap/structured-clone/-/structured-clone-1.3.0.tgz", @@ -14263,6 +14621,55 @@ "integrity": "sha512-uuVGNWzgJ4yhRaNSiubPY7OjISw4sw4E5Uv0wbjp+OzcbmVU/rsT8ujgcXJhn9ypzsgr5vlzpPqP+MBBKcGvbg==", "license": "MIT" }, + "node_modules/tinyglobby": { + "version": "0.2.15", + "resolved": "https://registry.npmjs.org/tinyglobby/-/tinyglobby-0.2.15.tgz", + "integrity": "sha512-j2Zq4NyQYG5XMST4cbs02Ak8iJUdxRM0XI5QyxXuZOzKOINmWurp3smXu3y5wDcJrptwpSjgXHzIQxR0omXljQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "fdir": "^6.5.0", + "picomatch": "^4.0.3" + }, + "engines": { + "node": ">=12.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/SuperchupuDev" + } + }, + "node_modules/tinyglobby/node_modules/fdir": { + "version": "6.5.0", + "resolved": "https://registry.npmjs.org/fdir/-/fdir-6.5.0.tgz", + "integrity": "sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12.0.0" + }, + "peerDependencies": { + "picomatch": "^3 || ^4" + }, + "peerDependenciesMeta": { + "picomatch": { + "optional": true + } + } + }, + "node_modules/tinyglobby/node_modules/picomatch": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.3.tgz", + "integrity": "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==", + "dev": true, + "license": "MIT", + "peer": true, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, "node_modules/tldts": { "version": "6.1.86", "resolved": "https://registry.npmjs.org/tldts/-/tldts-6.1.86.tgz", @@ -14352,6 +14759,19 @@ "node": ">= 14.0.0" } }, + "node_modules/ts-api-utils": { + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/ts-api-utils/-/ts-api-utils-2.4.0.tgz", + "integrity": "sha512-3TaVTaAv2gTiMB35i3FiGJaRfwb3Pyn/j3m/bfAvGe8FB7CF6u+LMYqYlDh7reQf7UNvoTvdfAqHGmPGOSsPmA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18.12" + }, + "peerDependencies": { + "typescript": ">=4.8.4" + } + }, "node_modules/ts-jest": { "version": "29.4.6", "resolved": "https://registry.npmjs.org/ts-jest/-/ts-jest-29.4.6.tgz", @@ -14583,6 +15003,30 @@ "node": ">=14.17" } }, + "node_modules/typescript-eslint": { + "version": "8.56.1", + "resolved": "https://registry.npmjs.org/typescript-eslint/-/typescript-eslint-8.56.1.tgz", + "integrity": "sha512-U4lM6pjmBX7J5wk4szltF7I1cGBHXZopnAXCMXb3+fZ3B/0Z3hq3wS/CCUB2NZBNAExK92mCU2tEohWuwVMsDQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@typescript-eslint/eslint-plugin": "8.56.1", + "@typescript-eslint/parser": "8.56.1", + "@typescript-eslint/typescript-estree": "8.56.1", + "@typescript-eslint/utils": "8.56.1" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "^8.57.0 || ^9.0.0 || ^10.0.0", + "typescript": ">=4.8.4 <6.0.0" + } + }, "node_modules/uglify-js": { "version": "3.19.3", "resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-3.19.3.tgz", diff --git a/server/package.json b/server/package.json index 40a3d8494..4ad85e644 100755 --- a/server/package.json +++ b/server/package.json @@ -80,6 +80,8 @@ "@types/ping": "0.4.4", "@types/swagger-ui-express": "4.1.8", "@types/ws": "^8.18.1", + "@typescript-eslint/eslint-plugin": "^8.56.1", + "@typescript-eslint/parser": "^8.56.1", "c8": "10.1.3", "eslint": "^9.17.0", "eslint-plugin-mocha": "^10.5.0", @@ -93,6 +95,7 @@ "ts-node": "^10.9.2", "tsc-alias": "1.8.16", "tsx": "4.20.5", - "typescript": "5.9.2" + "typescript": "5.9.2", + "typescript-eslint": "^8.56.1" } } diff --git a/server/src/config/services.ts b/server/src/config/services.ts index 1e08d0950..b2ea1c8bd 100644 --- a/server/src/config/services.ts +++ b/server/src/config/services.ts @@ -29,7 +29,6 @@ import { NotificationMessageBuilder, INotificationMessageBuilder } from "../serv import axios from "axios"; import got from "got"; import ping from "ping"; -import http from "http"; import https from "https"; import Docker from "dockerode"; import net from "net"; @@ -151,7 +150,9 @@ export const initializeServices = async ({ got, https, jmespath, - GameDig, + GameDig as unknown as { + query: (options: { type: string; host: string; port?: number }) => Promise<{ ping?: number } & { [key: string]: unknown }>; + }, ping, logger, Docker, diff --git a/server/src/service/infrastructure/SuperSimpleQueue/SuperSimpleQueue.ts b/server/src/service/infrastructure/SuperSimpleQueue/SuperSimpleQueue.ts index f9d0fd86e..0eb645cb7 100644 --- a/server/src/service/infrastructure/SuperSimpleQueue/SuperSimpleQueue.ts +++ b/server/src/service/infrastructure/SuperSimpleQueue/SuperSimpleQueue.ts @@ -282,7 +282,11 @@ class SuperSimpleQueue implements ISuperSimpleQueue { }; obliterate = async () => { - console.log("obliterate not implemented"); + this.logger.warn({ + message: "obliterate method not implemented", + service: SERVICE_NAME, + method: "obliterate", + }); }; } diff --git a/server/src/service/infrastructure/networkService.ts b/server/src/service/infrastructure/networkService.ts index c76556b58..c02eff792 100644 --- a/server/src/service/infrastructure/networkService.ts +++ b/server/src/service/infrastructure/networkService.ts @@ -1,6 +1,17 @@ import { HTTPError, RequestError } from "got"; import type { Got, Response } from "got"; -import type { Monitor, MonitorStatusResponse, GrpcStatusPayload } from "@/types/index.js"; +import type { + Monitor, + MonitorStatusResponse, + GrpcStatusPayload, + PageSpeedStatusPayload, + HttpStatusPayload, + HardwareStatusPayload, + PingStatusPayload, + DockerStatusPayload, + PortStatusPayload, + GameStatusPayload, +} from "@/types/index.js"; import type { AxiosStatic } from "axios"; import { AppError } from "@/utils/AppError.js"; import path from "path"; @@ -27,8 +38,25 @@ interface BuildStatusResponseArgs { export interface INetworkService { readonly serviceName: string; - requestStatus(monitor: Monitor): Promise; - requestWebhook(type: string, url: string, body: any): Promise<{ type: string; status: boolean; code: number; message: string; payload?: unknown }>; + requestStatus( + monitor: Monitor + ): Promise< + MonitorStatusResponse< + | PingStatusPayload + | HttpStatusPayload + | PageSpeedStatusPayload + | HardwareStatusPayload + | DockerStatusPayload + | PortStatusPayload + | GameStatusPayload + | GrpcStatusPayload + > + >; + requestWebhook( + type: string, + url: string, + body: unknown + ): Promise<{ type: string; status: boolean; code: number; message: string; payload?: unknown }>; requestPagerDuty(args: { message: string; routingKey: string; monitorUrl: string }): Promise; requestMatrix(args: { homeserverUrl: string; accessToken: string; roomId: string; message: string }): Promise<{ status: boolean; @@ -41,24 +69,31 @@ export interface INetworkService { class NetworkService implements INetworkService { static SERVICE_NAME = SERVICE_NAME; - private typeHandlers!: Record Promise>; + private TYPE_PING: string; + private TYPE_HTTP: string; + private TYPE_PAGESPEED: string; + private TYPE_HARDWARE: string; + private TYPE_DOCKER: string; + private TYPE_PORT: string; + private TYPE_GAME: string; + private TYPE_GRPC: string; private SERVICE_NAME: string; private NETWORK_ERROR: number; private PING_ERROR: number; private axios: AxiosStatic; private got: Got; - private https: any; - private jmespath: any; - private GameDig: any; - private ping: any; + private https: typeof import("https"); + private jmespath: { search: (data: unknown, expression: string) => unknown }; + private GameDig: { query: (options: { type: string; host: string; port?: number }) => Promise<{ ping?: number } & { [key: string]: unknown }> }; + private ping: typeof import("ping"); private logger: ILogger; - private Docker: any; - private net: any; + private Docker: typeof import("dockerode"); + private net: typeof import("net"); private settingsService: ISettingsService; - private grpc: any; - private protoLoader: any; private WebSocket: any; + private grpc: typeof import("@grpc/grpc-js"); + private protoLoader: typeof import("@grpc/proto-loader"); private buildStatusResponse = ({ monitor, @@ -93,7 +128,7 @@ class NetworkService implements INetworkService { statusResponse.responseTime = error.timings?.phases?.total ?? 0; statusResponse.timings = error.timings; } - return { ...statusResponse, ...(overrides ?? {}) }; + return { ...statusResponse, ...(overrides ?? {}) } as MonitorStatusResponse; } return { @@ -111,35 +146,32 @@ class NetworkService implements INetworkService { expectedValue, extracted, ...(overrides ?? {}), - }; + } as MonitorStatusResponse; }; constructor( axios: AxiosStatic, got: Got, - https: any, - jmespath: any, - GameDig: any, - ping: any, + https: typeof import("https"), + jmespath: { search: (data: unknown, expression: string) => unknown }, + GameDig: { query: (options: { type: string; host: string; port?: number }) => Promise<{ ping?: number } & { [key: string]: unknown }> }, + ping: typeof import("ping"), logger: ILogger, - Docker: any, - net: any, + Docker: typeof import("dockerode"), + net: typeof import("net"), settingsService: ISettingsService, - grpc: any, - protoLoader: any, - WebSocket: any + WebSocket: any, + grpc: typeof import("@grpc/grpc-js"), + protoLoader: typeof import("@grpc/proto-loader") ) { - this.typeHandlers = { - ping: (m) => this.requestPing(m), - http: (m) => this.requestHttp(m), - pagespeed: (m) => this.requestPageSpeed(m), - hardware: (m) => this.requestHardware(m), - docker: (m) => this.requestDocker(m), - port: (m) => this.requestPort(m), - game: (m) => this.requestGame(m), - grpc: (m) => this.requestGrpc(m), - websocket: (m) => this.requestWebSocket(m), - }; + this.TYPE_PING = "ping"; + this.TYPE_HTTP = "http"; + this.TYPE_PAGESPEED = "pagespeed"; + this.TYPE_HARDWARE = "hardware"; + this.TYPE_DOCKER = "docker"; + this.TYPE_PORT = "port"; + this.TYPE_GAME = "game"; + this.TYPE_GRPC = "grpc"; this.SERVICE_NAME = SERVICE_NAME; this.NETWORK_ERROR = 5000; this.PING_ERROR = 5001; @@ -185,13 +217,45 @@ class NetworkService implements INetworkService { } // Main entry point - async requestStatus(monitor: Monitor): Promise { + async requestStatus( + monitor: Monitor + ): Promise< + MonitorStatusResponse< + | PingStatusPayload + | HttpStatusPayload + | PageSpeedStatusPayload + | HardwareStatusPayload + | DockerStatusPayload + | PortStatusPayload + | GameStatusPayload + | GrpcStatusPayload + > + > { const type = monitor?.type || "unknown"; - const handler = this.typeHandlers[type]; - return handler ? handler(monitor) : this.handleUnsupportedType(type); + + switch (type) { + case this.TYPE_PING: + return await this.requestPing(monitor); + case this.TYPE_HTTP: + return await this.requestHttp(monitor); + case this.TYPE_PAGESPEED: + return await this.requestPageSpeed(monitor); + case this.TYPE_HARDWARE: + return await this.requestHardware(monitor); + case this.TYPE_DOCKER: + return await this.requestDocker(monitor); + case this.TYPE_PORT: + return await this.requestPort(monitor); + case this.TYPE_GAME: + return await this.requestGame(monitor); + case this.TYPE_GRPC: + return await this.requestGrpc(monitor); + default: + return this.handleUnsupportedType(type); + } } - private async requestPing(monitor: Monitor): Promise { + private async requestPing(monitor: Monitor): Promise> { try { if (!monitor?.url) { throw new Error("Monitor URL is required"); @@ -211,36 +275,33 @@ class NetworkService implements INetworkService { throw new Error("Ping failed - no result returned"); } - const pingResponse = this.buildStatusResponse({ + const pingResponse = this.buildStatusResponse({ monitor, - payload: response, + payload: response as PingStatusPayload, overrides: { status: (response as { alive?: boolean })?.alive ?? false, code: 200, message: "Success", responseTime: (response as { time?: number })?.time ?? 0, - payload: response, - }, + payload: response as PingStatusPayload, + } as MonitorStatusResponseOverrides, }); - if (error) { - pingResponse.status = false; - pingResponse.code = this.PING_ERROR; - pingResponse.message = "Ping failed"; - return pingResponse; - } - return pingResponse; - } catch (err: any) { - err.service = this.SERVICE_NAME; - err.method = "requestPing"; - throw err; + } catch (err: unknown) { + const originalMessage = err instanceof Error ? err.message : String(err); + throw new AppError({ + message: originalMessage || "Error performing ping", + service: this.SERVICE_NAME, + method: "requestPing", + details: { url: monitor.url }, + }); } } - private async requestHttp(monitor: Monitor): Promise { - const { url, secret, id, teamId, type, ignoreTlsErrors, useAdvancedMatching, jsonPath, matchMethod, expectedValue } = monitor; - const httpResponse = this.buildStatusResponse({ + private async requestHttp(monitor: Monitor): Promise> { + const { url, secret, ignoreTlsErrors, useAdvancedMatching, jsonPath, matchMethod, expectedValue } = monitor; + const httpResponse = this.buildStatusResponse({ monitor, overrides: { status: false, @@ -253,7 +314,7 @@ class NetworkService implements INetworkService { if (!url) { throw new Error("Monitor URL is required"); } - const config: Record = { + const config: Record = { headers: secret ? { Authorization: `Bearer ${secret}` } : undefined, }; @@ -267,7 +328,7 @@ class NetworkService implements INetworkService { const response = await this.got(url, config); - let payload: any; + let payload: T | string | undefined; const contentType = response.headers["content-type"]; if (contentType && contentType.includes("application/json")) { @@ -355,23 +416,27 @@ class NetworkService implements INetworkService { } } return httpResponse; - } catch (err: any) { - if (err.name === "HTTPError" || err.name === "RequestError") { - httpResponse.code = err?.response?.statusCode || this.NETWORK_ERROR; + } catch (err: unknown) { + if (err instanceof HTTPError || err instanceof RequestError) { + httpResponse.code = err.response?.statusCode || this.NETWORK_ERROR; httpResponse.status = false; - httpResponse.message = err?.response?.statusCode || err.message; - httpResponse.responseTime = err?.timings?.phases?.total || 0; + httpResponse.message = String(err.response?.statusCode) || err.message; + httpResponse.responseTime = err.timings?.phases?.total || 0; httpResponse.payload = null; - httpResponse.timings = err?.timings || {}; + httpResponse.timings = err.timings || undefined; return httpResponse; } - err.service = this.SERVICE_NAME; - err.method = "requestHttp"; - throw err; + const originalMessage = err instanceof Error ? err.message : String(err); + throw new AppError({ + message: originalMessage || "Error performing HTTP request", + service: this.SERVICE_NAME, + method: "requestHttp", + details: { url: monitor.url }, + }); } } - private async requestPageSpeed(monitor: Monitor): Promise { + private async requestPageSpeed(monitor: Monitor): Promise> { try { const url = monitor.url; if (!url) { @@ -389,28 +454,36 @@ class NetworkService implements INetworkService { details: { url }, }); } - return await this.requestHttp({ + return await this.requestHttp({ ...monitor, url: pageSpeedUrl, }); - } catch (err: any) { - err.service = this.SERVICE_NAME; - err.method = "requestPageSpeed"; - throw err; + } catch (err: unknown) { + const originalMessage = err instanceof Error ? err.message : String(err); + throw new AppError({ + message: originalMessage || "Error performing PageSpeed request", + service: this.SERVICE_NAME, + method: "requestPageSpeed", + details: { url: monitor.url }, + }); } } - private async requestHardware(monitor: Monitor): Promise { + private async requestHardware(monitor: Monitor): Promise> { try { - return await this.requestHttp(monitor); - } catch (err: any) { - err.service = this.SERVICE_NAME; - err.method = "requestHardware"; - throw err; + return await this.requestHttp(monitor); + } catch (err: unknown) { + const originalMessage = err instanceof Error ? err.message : String(err); + throw new AppError({ + message: originalMessage || "Error performing hardware request", + service: this.SERVICE_NAME, + method: "requestHardware", + details: { url: monitor.url }, + }); } } - private async requestDocker(monitor: Monitor): Promise { + private async requestDocker(monitor: Monitor): Promise> { try { if (!monitor.url) { throw new Error("Monitor URL is required"); @@ -420,7 +493,7 @@ class NetworkService implements INetworkService { socketPath: "/var/run/docker.sock", }); - const dockerResponse = this.buildStatusResponse({ + const dockerResponse = this.buildStatusResponse({ monitor, overrides: { status: false, @@ -436,10 +509,10 @@ class NetworkService implements INetworkService { // Priority-based matching to avoid ambiguity: // 1. Exact full ID match (64-char) - let exactIdMatch = containers.find((c: any) => c.Id.toLowerCase() === normalizedInput); + const exactIdMatch = containers.find((c) => c.Id.toLowerCase() === normalizedInput); // 2. Exact container name match (case-insensitive) - let exactNameMatch = containers.find((c: any) => + const exactNameMatch = containers.find((c) => c.Names.some((name: string) => { const cleanName = name.replace(/^\/+/, "").toLowerCase(); return cleanName === normalizedInput; @@ -447,10 +520,10 @@ class NetworkService implements INetworkService { ); // 3. Partial ID match (fallback for backwards compatibility) - let partialIdMatch = containers.find((c: any) => c.Id.toLowerCase().startsWith(normalizedInput)); + const partialIdMatch = containers.find((c) => c.Id.toLowerCase().startsWith(normalizedInput)); // Select container based on priority - let targetContainer = exactIdMatch || exactNameMatch || partialIdMatch; + const targetContainer = exactIdMatch || exactNameMatch || partialIdMatch; // Return negative response if no container if (!targetContainer) { @@ -486,9 +559,8 @@ class NetworkService implements INetworkService { } const container = docker.getContainer(targetContainer.Id); - const { response, responseTime, error }: { response?: any; responseTime?: number; error?: any } = await this.timeRequest(() => - container.inspect() - ); + const { response, responseTime, error }: { response?: { State: { Status: string } } | null; responseTime: number; error: unknown } = + await this.timeRequest(() => container.inspect()); dockerResponse.responseTime = responseTime; dockerResponse.status = response?.State?.Status === "running" ? true : false; @@ -497,20 +569,28 @@ class NetworkService implements INetworkService { if (error) { dockerResponse.status = false; - dockerResponse.code = error.statusCode || this.NETWORK_ERROR; - dockerResponse.message = error.reason || "Failed to fetch Docker container information"; + dockerResponse.code = + (error && typeof error === "object" && "statusCode" in error ? (error as { statusCode?: number }).statusCode : undefined) || + this.NETWORK_ERROR; + dockerResponse.message = + (error && typeof error === "object" && "reason" in error ? (error as { reason?: string }).reason : undefined) || + "Failed to fetch Docker container information"; return dockerResponse; } return dockerResponse; - } catch (err: any) { - err.service = this.SERVICE_NAME; - err.method = "requestDocker"; - throw err; + } catch (err: unknown) { + const originalMessage = err instanceof Error ? err.message : String(err); + throw new AppError({ + message: originalMessage || "Error performing Docker request", + service: this.SERVICE_NAME, + method: "requestDocker", + details: { url: monitor.url }, + }); } } - private async requestPort(monitor: Monitor): Promise { + private async requestPort(monitor: Monitor): Promise> { try { const { url, port } = monitor; if (!port) { @@ -537,14 +617,14 @@ class NetworkService implements INetworkService { reject(new Error("Connection timeout")); }); - socket.on("error", (err: any) => { + socket.on("error", (err: unknown) => { socket.destroy(); reject(err); }); }); }); - const portResponse = this.buildStatusResponse({ + const portResponse = this.buildStatusResponse({ monitor, overrides: { code: 200, @@ -562,18 +642,22 @@ class NetworkService implements INetworkService { } return portResponse; - } catch (error: any) { - error.service = this.SERVICE_NAME; - error.method = "requestTCP"; - throw error; + } catch (err: unknown) { + const originalMessage = err instanceof Error ? err.message : String(err); + throw new AppError({ + message: originalMessage || "Error performing port check", + service: this.SERVICE_NAME, + method: "requestPort", + details: { url: monitor.url, port: monitor.port }, + }); } } - private async requestGame(monitor: Monitor): Promise { + private async requestGame(monitor: Monitor): Promise> { try { const { url, port, gameId } = monitor; - const gameResponse = this.buildStatusResponse({ + const gameResponse = this.buildStatusResponse({ monitor, overrides: { code: 200, @@ -586,13 +670,14 @@ class NetworkService implements INetworkService { type: gameId ?? "unknown", host: url, port: port ?? 0, - }).catch((error: any) => { + }).catch((error: unknown): undefined => { this.logger.warn({ - message: error.message, + message: error instanceof Error ? error.message : String(error), service: this.SERVICE_NAME, method: "requestGame", details: { url, port, gameId }, }); + return undefined; }); if (!state) { @@ -602,16 +687,20 @@ class NetworkService implements INetworkService { return gameResponse; } - gameResponse.responseTime = state.ping; - gameResponse.payload = state; + gameResponse.responseTime = state.ping ?? 0; + gameResponse.payload = state as GameStatusPayload; return gameResponse; - } catch (error: any) { - error.service = this.SERVICE_NAME; - error.method = "requestPing"; - throw error; + } catch (err: unknown) { + const originalMessage = err instanceof Error ? err.message : String(err); + throw new AppError({ + message: originalMessage || "Error performing game server check", + service: this.SERVICE_NAME, + method: "requestGame", + details: { url: monitor.url, port: monitor.port, gameId: monitor.gameId }, + }); } } - private async requestGrpc(monitor: Monitor): Promise { + private async requestGrpc(monitor: Monitor): Promise> { try { const { url, port, ignoreTlsErrors } = monitor; const grpcServiceName = monitor.grpcServiceName || ""; @@ -635,7 +724,21 @@ class NetworkService implements INetworkService { defaults: true, oneofs: true, }); - const grpcObject = this.grpc.loadPackageDefinition(packageDefinition); + const grpcObject = this.grpc.loadPackageDefinition(packageDefinition) as unknown as { + grpc: { + health: { + v1: { + Health: new ( + target: string, + credentials: unknown + ) => { + Check: (request: { service: string }, options: { deadline: Date }, callback: (err: unknown, response: unknown) => void) => void; + close: () => void; + }; + }; + }; + }; + }; const healthService = grpcObject.grpc.health.v1.Health; let credentials; @@ -652,7 +755,7 @@ class NetworkService implements INetworkService { const TIMEOUT_MS = 10000; const deadline = new Date(Date.now() + TIMEOUT_MS); - const grpcResponse = this.buildStatusResponse({ + const grpcResponse = this.buildStatusResponse({ monitor, overrides: { status: false, @@ -663,24 +766,30 @@ class NetworkService implements INetworkService { const { response, responseTime, error } = await this.timeRequest(() => { return new Promise((resolve, reject) => { - client.Check({ service: grpcServiceName }, { deadline }, (err: any, response: any) => { + client.Check({ service: grpcServiceName }, { deadline }, (err: unknown, response: unknown) => { client.close(); if (err) { + const grpcErr = err as { code?: number; details?: string; message?: string }; const payload: GrpcStatusPayload = { - grpcStatusCode: err.code ?? -1, - grpcStatusName: this.getGrpcStatusName(err.code), + grpcStatusCode: grpcErr.code ?? -1, + grpcStatusName: this.getGrpcStatusName(grpcErr.code ?? -1), serviceName: grpcServiceName, servingStatus: "UNKNOWN", }; - const grpcError = new AppError({ message: err.details || err.message, service: this.SERVICE_NAME, method: "requestGrpc" }); - (grpcError as any).grpcPayload = payload; - (grpcError as any).grpcCode = err.code; + const grpcError = new AppError({ + message: grpcErr.details || grpcErr.message || "gRPC error", + service: this.SERVICE_NAME, + method: "requestGrpc", + }) as AppError & { grpcPayload?: GrpcStatusPayload; grpcCode?: number }; + grpcError.grpcPayload = payload; + grpcError.grpcCode = grpcErr.code; reject(grpcError); return; } - const servingStatus = response?.status || "UNKNOWN"; + const resp = response as { status?: string } | undefined; + const servingStatus = resp?.status ?? "UNKNOWN"; resolve({ grpcStatusCode: 0, grpcStatusName: "OK", @@ -692,13 +801,13 @@ class NetworkService implements INetworkService { }); if (error) { - const grpcError = error as any; - const payload = grpcError.grpcPayload as GrpcStatusPayload | undefined; + const grpcError = error as AppError & { grpcPayload?: GrpcStatusPayload; grpcCode?: number }; + const payload = grpcError.grpcPayload; grpcResponse.status = false; grpcResponse.code = grpcError.grpcCode ?? this.NETWORK_ERROR; - grpcResponse.message = grpcError.message || "gRPC health check failed"; + grpcResponse.message = grpcError.message ?? "gRPC health check failed"; grpcResponse.responseTime = responseTime; - grpcResponse.payload = payload || null; + grpcResponse.payload = payload ?? null; return grpcResponse; } @@ -714,10 +823,14 @@ class NetworkService implements INetworkService { grpcResponse.payload = grpcPayload; return grpcResponse; - } catch (err: any) { - err.service = this.SERVICE_NAME; - err.method = "requestGrpc"; - throw err; + } catch (err: unknown) { + const originalMessage = err instanceof Error ? err.message : String(err); + throw new AppError({ + message: originalMessage || "Error performing gRPC health check", + service: this.SERVICE_NAME, + method: "requestGrpc", + details: { url: monitor.url, port: monitor.port, grpcServiceName: monitor.grpcServiceName }, + }); } } @@ -822,7 +935,7 @@ class NetworkService implements INetworkService { } // Other network requests unrelated to monitoring: - async requestWebhook(type: string, url: string, body: any) { + async requestWebhook(type: string, url: string, body: unknown) { try { const response = await this.axios.post(url, body, { headers: { @@ -837,19 +950,29 @@ class NetworkService implements INetworkService { message: `Successfully sent ${type} notification`, payload: response.data, }; - } catch (error: any) { + } catch (err: unknown) { this.logger.warn({ - message: error.message, + message: err instanceof Error ? err.message : String(err), service: this.SERVICE_NAME, method: "requestWebhook", }); + if (err && typeof err === "object" && "response" in err) { + const axiosError = err as { response?: { status?: number; data?: unknown } }; + return { + type: "webhook", + status: false, + code: axiosError.response?.status ?? this.NETWORK_ERROR, + message: `Failed to send ${type} notification`, + payload: axiosError.response?.data, + }; + } + return { type: "webhook", status: false, - code: error.response?.status || this.NETWORK_ERROR, + code: this.NETWORK_ERROR, message: `Failed to send ${type} notification`, - payload: error.response?.data, }; } } @@ -869,11 +992,17 @@ class NetworkService implements INetworkService { if (response?.data?.status !== "success") return false; return true; - } catch (error: any) { - error.details = error.response?.data; - error.service = this.SERVICE_NAME; - error.method = "requestPagerDuty"; - throw error; + } catch (err: unknown) { + const originalMessage = err instanceof Error ? err.message : String(err); + + throw new AppError({ + message: originalMessage || "Error sending PagerDuty notification", + service: this.SERVICE_NAME, + method: "requestPagerDuty", + details: { + responseData: err && typeof err === "object" && "response" in err ? (err as { response?: { data?: unknown } }).response?.data : undefined, + }, + }); } } @@ -907,18 +1036,35 @@ class NetworkService implements INetworkService { code: response.status, message: "Successfully sent Matrix notification", }; - } catch (error: any) { + } catch (err: unknown) { + if (err instanceof Error) { + this.logger.warn({ + message: err.message, + service: this.SERVICE_NAME, + method: "requestMatrix", + }); + + if (err && typeof err === "object" && "response" in err) { + const axiosError = err as { response?: { status?: number; data?: unknown } }; + return { + status: false, + code: axiosError.response?.status || this.NETWORK_ERROR, + message: "Failed to send Matrix notification", + payload: axiosError.response?.data, + }; + } + } + this.logger.warn({ - message: error.message, + message: String(err), service: this.SERVICE_NAME, method: "requestMatrix", }); return { status: false, - code: error.response?.status || this.NETWORK_ERROR, + code: this.NETWORK_ERROR, message: "Failed to send Matrix notification", - payload: error.response?.data, }; } } diff --git a/server/src/service/infrastructure/statusService.ts b/server/src/service/infrastructure/statusService.ts index 37657cb79..12cd3a77f 100755 --- a/server/src/service/infrastructure/statusService.ts +++ b/server/src/service/infrastructure/statusService.ts @@ -7,6 +7,12 @@ import type { Check, HardwareStatusPayload, PageSpeedStatusPayload, + PingStatusPayload, + HttpStatusPayload, + DockerStatusPayload, + PortStatusPayload, + GameStatusPayload, + GrpcStatusPayload, CheckSnapshot, MonitorStats, } from "@/types/index.js"; @@ -17,7 +23,17 @@ export interface IStatusService { updateRunningStats({ monitor, networkResponse }: { monitor: Monitor; networkResponse: any }): Promise; handleIncidentForCheck(check: any, monitor: Monitor, action: any, errorContext?: string): Promise; updateMonitorStatus( - statusResponse: MonitorStatusResponse, + statusResponse: MonitorStatusResponse< + | PingStatusPayload + | HttpStatusPayload + | PageSpeedStatusPayload + | HardwareStatusPayload + | DockerStatusPayload + | PortStatusPayload + | GameStatusPayload + | GrpcStatusPayload + | undefined + >, check: Check ): Promise; } @@ -205,7 +221,17 @@ export class StatusService implements IStatusService { }; updateMonitorStatus = async ( - statusResponse: MonitorStatusResponse, + statusResponse: MonitorStatusResponse< + | PingStatusPayload + | HttpStatusPayload + | PageSpeedStatusPayload + | HardwareStatusPayload + | DockerStatusPayload + | PortStatusPayload + | GameStatusPayload + | GrpcStatusPayload + | undefined + >, check: Check ): Promise => { try { diff --git a/server/src/types/network.ts b/server/src/types/network.ts index 9573712b1..208ab1305 100644 --- a/server/src/types/network.ts +++ b/server/src/types/network.ts @@ -14,7 +14,16 @@ import type { MonitorStatus, } from "@/types/index.js"; -export interface MonitorStatusResponse { +export interface MonitorStatusResponse< + T = + | HttpStatusPayload + | PingStatusPayload + | PageSpeedStatusPayload + | HardwareStatusPayload + | DockerStatusPayload + | GameStatusPayload + | GrpcStatusPayload, +> { monitorId: string; teamId: string; type: MonitorType; diff --git a/server/src/utils/AppError.ts b/server/src/utils/AppError.ts index 93baeb78e..c19f726f2 100644 --- a/server/src/utils/AppError.ts +++ b/server/src/utils/AppError.ts @@ -3,14 +3,14 @@ export interface AppErrorConfig { status?: number; service?: string | null; method?: string | null; - details?: any; + details?: unknown; } export class AppError extends Error { private status: number; private service: string | null; private method: string | null; - private details: any; + private details: unknown; constructor({ message, status = 500, service = null, method = null, details = null }: AppErrorConfig) { super(message); diff --git a/server/src/utils/imageProcessing.ts b/server/src/utils/imageProcessing.ts index 442f0d6da..02d10534c 100755 --- a/server/src/utils/imageProcessing.ts +++ b/server/src/utils/imageProcessing.ts @@ -1,22 +1,18 @@ import sharp from "sharp"; const GenerateAvatarImage = async (file: Express.Multer.File) => { - try { - // Resize to target 64 * 64 - let resizedImageBuffer = await sharp(file.buffer) - .resize({ - width: 64, - height: 64, - fit: "cover", - }) - .toBuffer(); + // Resize to target 64 * 64 + const resizedImageBuffer = await sharp(file.buffer) + .resize({ + width: 64, + height: 64, + fit: "cover", + }) + .toBuffer(); - //Get b64 string - const base64Image = resizedImageBuffer.toString("base64"); - return base64Image; - } catch (error) { - throw error; - } + //Get b64 string + const base64Image = resizedImageBuffer.toString("base64"); + return base64Image; }; export { GenerateAvatarImage }; diff --git a/server/src/utils/logger.ts b/server/src/utils/logger.ts index 4053f4a82..e3c0db169 100755 --- a/server/src/utils/logger.ts +++ b/server/src/utils/logger.ts @@ -44,7 +44,7 @@ class Logger implements ILogger { this.maxCacheSize = 1000; const consoleFormat = format.printf((info: Logform.TransformableInfo) => { const { level, service, method, details, timestamp, stack } = info; - let message = info.message as string; + const message = info.message as string; let formattedMessage: string = message; let formattedDetails: string | undefined; @@ -57,10 +57,10 @@ class Logger implements ILogger { } let msg = `${timestamp} ${level}:`; - service && (msg += ` [${service}]`); - method && (msg += `(${method})`); - formattedMessage && (msg += ` ${formattedMessage}`); - formattedDetails && (msg += ` (details: ${formattedDetails})`); + if (service) msg += ` [${service}]`; + if (method) msg += `(${method})`; + if (formattedMessage) msg += ` ${formattedMessage}`; + if (formattedDetails) msg += ` (details: ${formattedDetails})`; if (typeof stack === "string") { const stackTrace = stack diff --git a/server/tsconfig.json b/server/tsconfig.json index bdb3a7b0e..34deaf8de 100644 --- a/server/tsconfig.json +++ b/server/tsconfig.json @@ -8,6 +8,7 @@ }, "outDir": "./dist", "strict": true, + "noImplicitAny": true, "esModuleInterop": true, "module": "nodenext", "moduleResolution": "nodenext",