resolve conflicts
This commit is contained in:
commit
298018035d
12 files changed
+820
-176
No files matched your search
@@ -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
|
||||
},
|
||||
},
|
||||
|
||||
Generated
+448
-4
@@ -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",
|
||||
|
||||
+4
-1
@@ -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"
|
||||
}
|
||||
}
|
||||
@@ -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,
|
||||
|
||||
@@ -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",
|
||||
});
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
@@ -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<T> {
|
||||
|
||||
export interface INetworkService {
|
||||
readonly serviceName: string;
|
||||
requestStatus(monitor: Monitor): Promise<MonitorStatusResponse>;
|
||||
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<boolean>;
|
||||
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<string, (monitor: Monitor) => Promise<MonitorStatusResponse>>;
|
||||
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 = <T>({
|
||||
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<T>;
|
||||
}
|
||||
|
||||
return {
|
||||
@@ -111,35 +146,32 @@ class NetworkService implements INetworkService {
|
||||
expectedValue,
|
||||
extracted,
|
||||
...(overrides ?? {}),
|
||||
};
|
||||
} as MonitorStatusResponse<T>;
|
||||
};
|
||||
|
||||
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<MonitorStatusResponse> {
|
||||
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<HttpStatusPayload>(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<MonitorStatusResponse> {
|
||||
private async requestPing(monitor: Monitor): Promise<MonitorStatusResponse<PingStatusPayload>> {
|
||||
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<PingStatusPayload>({
|
||||
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<PingStatusPayload>,
|
||||
});
|
||||
|
||||
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<MonitorStatusResponse> {
|
||||
const { url, secret, id, teamId, type, ignoreTlsErrors, useAdvancedMatching, jsonPath, matchMethod, expectedValue } = monitor;
|
||||
const httpResponse = this.buildStatusResponse({
|
||||
private async requestHttp<T = unknown>(monitor: Monitor): Promise<MonitorStatusResponse<T>> {
|
||||
const { url, secret, ignoreTlsErrors, useAdvancedMatching, jsonPath, matchMethod, expectedValue } = monitor;
|
||||
const httpResponse = this.buildStatusResponse<T>({
|
||||
monitor,
|
||||
overrides: {
|
||||
status: false,
|
||||
@@ -253,7 +314,7 @@ class NetworkService implements INetworkService {
|
||||
if (!url) {
|
||||
throw new Error("Monitor URL is required");
|
||||
}
|
||||
const config: Record<string, any> = {
|
||||
const config: Record<string, unknown> = {
|
||||
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<MonitorStatusResponse> {
|
||||
private async requestPageSpeed(monitor: Monitor): Promise<MonitorStatusResponse<PageSpeedStatusPayload>> {
|
||||
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<PageSpeedStatusPayload>({
|
||||
...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<MonitorStatusResponse> {
|
||||
private async requestHardware(monitor: Monitor): Promise<MonitorStatusResponse<HardwareStatusPayload>> {
|
||||
try {
|
||||
return await this.requestHttp(monitor);
|
||||
} catch (err: any) {
|
||||
err.service = this.SERVICE_NAME;
|
||||
err.method = "requestHardware";
|
||||
throw err;
|
||||
return await this.requestHttp<HardwareStatusPayload>(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<MonitorStatusResponse> {
|
||||
private async requestDocker(monitor: Monitor): Promise<MonitorStatusResponse<DockerStatusPayload>> {
|
||||
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<DockerStatusPayload>({
|
||||
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<MonitorStatusResponse> {
|
||||
private async requestPort(monitor: Monitor): Promise<MonitorStatusResponse<PortStatusPayload>> {
|
||||
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<PortStatusPayload>({
|
||||
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<MonitorStatusResponse> {
|
||||
private async requestGame(monitor: Monitor): Promise<MonitorStatusResponse<GameStatusPayload>> {
|
||||
try {
|
||||
const { url, port, gameId } = monitor;
|
||||
|
||||
const gameResponse = this.buildStatusResponse({
|
||||
const gameResponse = this.buildStatusResponse<GameStatusPayload>({
|
||||
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<MonitorStatusResponse> {
|
||||
private async requestGrpc(monitor: Monitor): Promise<MonitorStatusResponse<GrpcStatusPayload>> {
|
||||
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<GrpcStatusPayload>({
|
||||
monitor,
|
||||
overrides: {
|
||||
status: false,
|
||||
@@ -663,24 +766,30 @@ class NetworkService implements INetworkService {
|
||||
|
||||
const { response, responseTime, error } = await this.timeRequest<GrpcStatusPayload>(() => {
|
||||
return new Promise<GrpcStatusPayload>((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,
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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<boolean>;
|
||||
handleIncidentForCheck(check: any, monitor: Monitor, action: any, errorContext?: string): Promise<void>;
|
||||
updateMonitorStatus(
|
||||
statusResponse: MonitorStatusResponse<PageSpeedStatusPayload | HardwareStatusPayload | undefined>,
|
||||
statusResponse: MonitorStatusResponse<
|
||||
| PingStatusPayload
|
||||
| HttpStatusPayload
|
||||
| PageSpeedStatusPayload
|
||||
| HardwareStatusPayload
|
||||
| DockerStatusPayload
|
||||
| PortStatusPayload
|
||||
| GameStatusPayload
|
||||
| GrpcStatusPayload
|
||||
| undefined
|
||||
>,
|
||||
check: Check
|
||||
): Promise<StatusChangeResult>;
|
||||
}
|
||||
@@ -205,7 +221,17 @@ export class StatusService implements IStatusService {
|
||||
};
|
||||
|
||||
updateMonitorStatus = async (
|
||||
statusResponse: MonitorStatusResponse<PageSpeedStatusPayload | HardwareStatusPayload | undefined>,
|
||||
statusResponse: MonitorStatusResponse<
|
||||
| PingStatusPayload
|
||||
| HttpStatusPayload
|
||||
| PageSpeedStatusPayload
|
||||
| HardwareStatusPayload
|
||||
| DockerStatusPayload
|
||||
| PortStatusPayload
|
||||
| GameStatusPayload
|
||||
| GrpcStatusPayload
|
||||
| undefined
|
||||
>,
|
||||
check: Check
|
||||
): Promise<StatusChangeResult> => {
|
||||
try {
|
||||
|
||||
@@ -14,7 +14,16 @@ import type {
|
||||
MonitorStatus,
|
||||
} from "@/types/index.js";
|
||||
|
||||
export interface MonitorStatusResponse<T = any> {
|
||||
export interface MonitorStatusResponse<
|
||||
T =
|
||||
| HttpStatusPayload
|
||||
| PingStatusPayload
|
||||
| PageSpeedStatusPayload
|
||||
| HardwareStatusPayload
|
||||
| DockerStatusPayload
|
||||
| GameStatusPayload
|
||||
| GrpcStatusPayload,
|
||||
> {
|
||||
monitorId: string;
|
||||
teamId: string;
|
||||
type: MonitorType;
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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 };
|
||||
@@ -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
|
||||
|
||||
@@ -8,6 +8,7 @@
|
||||
},
|
||||
"outDir": "./dist",
|
||||
"strict": true,
|
||||
"noImplicitAny": true,
|
||||
"esModuleInterop": true,
|
||||
"module": "nodenext",
|
||||
"moduleResolution": "nodenext",
|
||||
|
||||
Reference in new issue
Block a user