From 10fdf2bdf0d01019bbe868e425a22bf15a9ca878 Mon Sep 17 00:00:00 2001 From: Michele Azzolari Date: Tue, 11 Mar 2025 15:10:31 +0100 Subject: [PATCH 1/2] chore: update deps --- package-lock.json | 311 +++++++++++++++++++++++++--------------------- package.json | 28 +++-- 2 files changed, 184 insertions(+), 155 deletions(-) diff --git a/package-lock.json b/package-lock.json index f084c4a..3f8e225 100644 --- a/package-lock.json +++ b/package-lock.json @@ -9,21 +9,24 @@ "version": "0.1.0", "license": "ISC", "devDependencies": { - "@eslint/js": "9.18.0", + "@eslint/js": "9.22.0", "@types/jest": "29.5.14", - "@typescript-eslint/eslint-plugin": "8.19.1", - "@typescript-eslint/parser": "8.19.1", - "eslint": "9.18.0", - "eslint-config-prettier": "9.1.0", - "eslint-plugin-n": "17.15.1", - "eslint-plugin-prettier": "5.2.1", - "globals": "14.0.0", + "@typescript-eslint/eslint-plugin": "8.26.1", + "@typescript-eslint/parser": "8.26.1", + "eslint": "9.22.0", + "eslint-config-prettier": "10.1.1", + "eslint-plugin-n": "17.16.2", + "eslint-plugin-prettier": "5.2.3", + "globals": "16.0.0", "jest": "29.7.0", - "prettier": "3.4.2", - "ts-jest": "29.2.5", + "prettier": "3.5.3", + "ts-jest": "29.2.6", "ts-node": "10.9.2", - "typescript": "5.7.3", - "typescript-eslint": "8.19.1" + "typescript": "5.8.2", + "typescript-eslint": "8.26.1" + }, + "engines": { + "node": ">=20" } }, "node_modules/@ampproject/remapping": { @@ -610,13 +613,13 @@ } }, "node_modules/@eslint/config-array": { - "version": "0.19.1", - "resolved": "https://registry.npmjs.org/@eslint/config-array/-/config-array-0.19.1.tgz", - "integrity": "sha512-fo6Mtm5mWyKjA/Chy1BYTdn5mGJoDNjC7C64ug20ADsRDGrA85bN3uK3MaKbeRkRuuIEAR5N33Jr1pbm411/PA==", + "version": "0.19.2", + "resolved": "https://registry.npmjs.org/@eslint/config-array/-/config-array-0.19.2.tgz", + "integrity": "sha512-GNKqxfHG2ySmJOBSHg7LxeUx4xpuCoFjacmlCoYWEbaPXLwvfIjixRI12xCQZeULksQb23uiA8F40w5TojpV7w==", "dev": true, "license": "Apache-2.0", "dependencies": { - "@eslint/object-schema": "^2.1.5", + "@eslint/object-schema": "^2.1.6", "debug": "^4.3.1", "minimatch": "^3.1.2" }, @@ -648,10 +651,20 @@ "node": "*" } }, + "node_modules/@eslint/config-helpers": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/@eslint/config-helpers/-/config-helpers-0.1.0.tgz", + "integrity": "sha512-kLrdPDJE1ckPo94kmPPf9Hfd0DU0Jw6oKYrhe+pwSC0iTUInmTa+w6fw8sGgcfkFJGNdWOUeOaDM4quW4a7OkA==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + } + }, "node_modules/@eslint/core": { - "version": "0.10.0", - "resolved": "https://registry.npmjs.org/@eslint/core/-/core-0.10.0.tgz", - "integrity": "sha512-gFHJ+xBOo4G3WRlR1e/3G8A6/KZAH6zcE/hkLRCZTi/B9avAG365QhFA8uOGzTMqgTghpn7/fSnscW++dpMSAw==", + "version": "0.12.0", + "resolved": "https://registry.npmjs.org/@eslint/core/-/core-0.12.0.tgz", + "integrity": "sha512-cmrR6pytBuSMTaBweKoGMwu3EiHiEC+DoyupPmlZ0HxBJBtIxwe+j/E4XPIKNx+Q74c8lXKPwYawBf5glsTkHg==", "dev": true, "license": "Apache-2.0", "dependencies": { @@ -662,9 +675,9 @@ } }, "node_modules/@eslint/eslintrc": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-3.2.0.tgz", - "integrity": "sha512-grOjVNN8P3hjJn/eIETF1wwd12DdnwFDoyceUJLYYdkpbwq3nLi+4fqrTAONx7XDALqlL220wC/RHSC/QTI/0w==", + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-3.3.0.tgz", + "integrity": "sha512-yaVPAiNAalnCZedKLdR21GOGILMLKPyqSLWaAjQFvYA2i/ciDi8ArYVr69Anohb6cH2Ukhqti4aFnYyPm8wdwQ==", "dev": true, "license": "MIT", "dependencies": { @@ -696,6 +709,19 @@ "concat-map": "0.0.1" } }, + "node_modules/@eslint/eslintrc/node_modules/globals": { + "version": "14.0.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-14.0.0.tgz", + "integrity": "sha512-oahGvuMGQlPw/ivIYBjVSrWAfWLBeku5tpPE2fOPLi+WHffIWbuh2tCjhyQhTBPMf5E9jDEH4FOmTYgYwbKwtQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/@eslint/eslintrc/node_modules/minimatch": { "version": "3.1.2", "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", @@ -710,9 +736,9 @@ } }, "node_modules/@eslint/js": { - "version": "9.18.0", - "resolved": "https://registry.npmjs.org/@eslint/js/-/js-9.18.0.tgz", - "integrity": "sha512-fK6L7rxcq6/z+AaQMtiFTkvbHkBLNlwyRxHpKawP0x3u9+NC6MQTnFW+AdpwC6gfHTW0051cokQgtTN2FqlxQA==", + "version": "9.22.0", + "resolved": "https://registry.npmjs.org/@eslint/js/-/js-9.22.0.tgz", + "integrity": "sha512-vLFajx9o8d1/oL2ZkpMYbkLv8nDB6yaIwFNt7nI4+I80U/z03SxmfOMsLbvWr3p7C+Wnoh//aOu2pQW8cS0HCQ==", "dev": true, "license": "MIT", "engines": { @@ -720,9 +746,9 @@ } }, "node_modules/@eslint/object-schema": { - "version": "2.1.5", - "resolved": "https://registry.npmjs.org/@eslint/object-schema/-/object-schema-2.1.5.tgz", - "integrity": "sha512-o0bhxnL89h5Bae5T318nFoFzGy+YE5i/gGkoPAgkmTVdRKTiv3p8JHevPiPaMwoloKfEiiaHlawCqaZMqRm+XQ==", + "version": "2.1.6", + "resolved": "https://registry.npmjs.org/@eslint/object-schema/-/object-schema-2.1.6.tgz", + "integrity": "sha512-RBMg5FRL0I0gs51M/guSAj5/e14VQ4tpZnQNWwuDT66P14I43ItmPfIZRhO9fUVIPOAQXU47atlywZ/czoqFPA==", "dev": true, "license": "Apache-2.0", "engines": { @@ -730,13 +756,13 @@ } }, "node_modules/@eslint/plugin-kit": { - "version": "0.2.5", - "resolved": "https://registry.npmjs.org/@eslint/plugin-kit/-/plugin-kit-0.2.5.tgz", - "integrity": "sha512-lB05FkqEdUg2AA0xEbUz0SnkXT1LcCTa438W4IWTUh4hdOnVbQyOJ81OrDXsJk/LSiJHubgGEFoR5EHq1NsH1A==", + "version": "0.2.7", + "resolved": "https://registry.npmjs.org/@eslint/plugin-kit/-/plugin-kit-0.2.7.tgz", + "integrity": "sha512-JubJ5B2pJ4k4yGxaNLdbjrnk9d/iDz6/q8wOilpIowd6PJPgaxCuHBnBszq7Ce2TyMrywm5r4PnKm6V3iiZF+g==", "dev": true, "license": "Apache-2.0", "dependencies": { - "@eslint/core": "^0.10.0", + "@eslint/core": "^0.12.0", "levn": "^0.4.1" }, "engines": { @@ -796,9 +822,9 @@ } }, "node_modules/@humanwhocodes/retry": { - "version": "0.4.1", - "resolved": "https://registry.npmjs.org/@humanwhocodes/retry/-/retry-0.4.1.tgz", - "integrity": "sha512-c7hNEllBlenFTHBky65mhq8WD2kbN9Q6gk0bTk8lSBvc554jpXSkST1iePudpt7+A/AQvuHs9EMqjHDXMY1lrA==", + "version": "0.4.2", + "resolved": "https://registry.npmjs.org/@humanwhocodes/retry/-/retry-0.4.2.tgz", + "integrity": "sha512-xeO57FpIu4p1Ri3Jq/EXq4ClRm86dVF2z/+kvFnyqVYRavTZmaFaUBbWCOuuTh0o/g7DSsk6kc2vrS4Vl5oPOQ==", "dev": true, "license": "Apache-2.0", "engines": { @@ -1519,21 +1545,21 @@ "license": "MIT" }, "node_modules/@typescript-eslint/eslint-plugin": { - "version": "8.19.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-8.19.1.tgz", - "integrity": "sha512-tJzcVyvvb9h/PB96g30MpxACd9IrunT7GF9wfA9/0TJ1LxGOJx1TdPzSbBBnNED7K9Ka8ybJsnEpiXPktolTLg==", + "version": "8.26.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-8.26.1.tgz", + "integrity": "sha512-2X3mwqsj9Bd3Ciz508ZUtoQQYpOhU/kWoUqIf49H8Z0+Vbh6UF/y0OEYp0Q0axOGzaBGs7QxRwq0knSQ8khQNA==", "dev": true, "license": "MIT", "dependencies": { "@eslint-community/regexpp": "^4.10.0", - "@typescript-eslint/scope-manager": "8.19.1", - "@typescript-eslint/type-utils": "8.19.1", - "@typescript-eslint/utils": "8.19.1", - "@typescript-eslint/visitor-keys": "8.19.1", + "@typescript-eslint/scope-manager": "8.26.1", + "@typescript-eslint/type-utils": "8.26.1", + "@typescript-eslint/utils": "8.26.1", + "@typescript-eslint/visitor-keys": "8.26.1", "graphemer": "^1.4.0", "ignore": "^5.3.1", "natural-compare": "^1.4.0", - "ts-api-utils": "^2.0.0" + "ts-api-utils": "^2.0.1" }, "engines": { "node": "^18.18.0 || ^20.9.0 || >=21.1.0" @@ -1545,20 +1571,20 @@ "peerDependencies": { "@typescript-eslint/parser": "^8.0.0 || ^8.0.0-alpha.0", "eslint": "^8.57.0 || ^9.0.0", - "typescript": ">=4.8.4 <5.8.0" + "typescript": ">=4.8.4 <5.9.0" } }, "node_modules/@typescript-eslint/parser": { - "version": "8.19.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-8.19.1.tgz", - "integrity": "sha512-67gbfv8rAwawjYx3fYArwldTQKoYfezNUT4D5ioWetr/xCrxXxvleo3uuiFuKfejipvq+og7mjz3b0G2bVyUCw==", + "version": "8.26.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-8.26.1.tgz", + "integrity": "sha512-w6HZUV4NWxqd8BdeFf81t07d7/YV9s7TCWrQQbG5uhuvGUAW+fq1usZ1Hmz9UPNLniFnD8GLSsDpjP0hm1S4lQ==", "dev": true, "license": "MIT", "dependencies": { - "@typescript-eslint/scope-manager": "8.19.1", - "@typescript-eslint/types": "8.19.1", - "@typescript-eslint/typescript-estree": "8.19.1", - "@typescript-eslint/visitor-keys": "8.19.1", + "@typescript-eslint/scope-manager": "8.26.1", + "@typescript-eslint/types": "8.26.1", + "@typescript-eslint/typescript-estree": "8.26.1", + "@typescript-eslint/visitor-keys": "8.26.1", "debug": "^4.3.4" }, "engines": { @@ -1570,18 +1596,18 @@ }, "peerDependencies": { "eslint": "^8.57.0 || ^9.0.0", - "typescript": ">=4.8.4 <5.8.0" + "typescript": ">=4.8.4 <5.9.0" } }, "node_modules/@typescript-eslint/scope-manager": { - "version": "8.19.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-8.19.1.tgz", - "integrity": "sha512-60L9KIuN/xgmsINzonOcMDSB8p82h95hoBfSBtXuO4jlR1R9L1xSkmVZKgCPVfavDlXihh4ARNjXhh1gGnLC7Q==", + "version": "8.26.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-8.26.1.tgz", + "integrity": "sha512-6EIvbE5cNER8sqBu6V7+KeMZIC1664d2Yjt+B9EWUXrsyWpxx4lEZrmvxgSKRC6gX+efDL/UY9OpPZ267io3mg==", "dev": true, "license": "MIT", "dependencies": { - "@typescript-eslint/types": "8.19.1", - "@typescript-eslint/visitor-keys": "8.19.1" + "@typescript-eslint/types": "8.26.1", + "@typescript-eslint/visitor-keys": "8.26.1" }, "engines": { "node": "^18.18.0 || ^20.9.0 || >=21.1.0" @@ -1592,16 +1618,16 @@ } }, "node_modules/@typescript-eslint/type-utils": { - "version": "8.19.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-8.19.1.tgz", - "integrity": "sha512-Rp7k9lhDKBMRJB/nM9Ksp1zs4796wVNyihG9/TU9R6KCJDNkQbc2EOKjrBtLYh3396ZdpXLtr/MkaSEmNMtykw==", + "version": "8.26.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-8.26.1.tgz", + "integrity": "sha512-Kcj/TagJLwoY/5w9JGEFV0dclQdyqw9+VMndxOJKtoFSjfZhLXhYjzsQEeyza03rwHx2vFEGvrJWJBXKleRvZg==", "dev": true, "license": "MIT", "dependencies": { - "@typescript-eslint/typescript-estree": "8.19.1", - "@typescript-eslint/utils": "8.19.1", + "@typescript-eslint/typescript-estree": "8.26.1", + "@typescript-eslint/utils": "8.26.1", "debug": "^4.3.4", - "ts-api-utils": "^2.0.0" + "ts-api-utils": "^2.0.1" }, "engines": { "node": "^18.18.0 || ^20.9.0 || >=21.1.0" @@ -1612,13 +1638,13 @@ }, "peerDependencies": { "eslint": "^8.57.0 || ^9.0.0", - "typescript": ">=4.8.4 <5.8.0" + "typescript": ">=4.8.4 <5.9.0" } }, "node_modules/@typescript-eslint/types": { - "version": "8.19.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-8.19.1.tgz", - "integrity": "sha512-JBVHMLj7B1K1v1051ZaMMgLW4Q/jre5qGK0Ew6UgXz1Rqh+/xPzV1aW581OM00X6iOfyr1be+QyW8LOUf19BbA==", + "version": "8.26.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-8.26.1.tgz", + "integrity": "sha512-n4THUQW27VmQMx+3P+B0Yptl7ydfceUj4ON/AQILAASwgYdZ/2dhfymRMh5egRUrvK5lSmaOm77Ry+lmXPOgBQ==", "dev": true, "license": "MIT", "engines": { @@ -1630,20 +1656,20 @@ } }, "node_modules/@typescript-eslint/typescript-estree": { - "version": "8.19.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-8.19.1.tgz", - "integrity": "sha512-jk/TZwSMJlxlNnqhy0Eod1PNEvCkpY6MXOXE/WLlblZ6ibb32i2We4uByoKPv1d0OD2xebDv4hbs3fm11SMw8Q==", + "version": "8.26.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-8.26.1.tgz", + "integrity": "sha512-yUwPpUHDgdrv1QJ7YQal3cMVBGWfnuCdKbXw1yyjArax3353rEJP1ZA+4F8nOlQ3RfS2hUN/wze3nlY+ZOhvoA==", "dev": true, "license": "MIT", "dependencies": { - "@typescript-eslint/types": "8.19.1", - "@typescript-eslint/visitor-keys": "8.19.1", + "@typescript-eslint/types": "8.26.1", + "@typescript-eslint/visitor-keys": "8.26.1", "debug": "^4.3.4", "fast-glob": "^3.3.2", "is-glob": "^4.0.3", "minimatch": "^9.0.4", "semver": "^7.6.0", - "ts-api-utils": "^2.0.0" + "ts-api-utils": "^2.0.1" }, "engines": { "node": "^18.18.0 || ^20.9.0 || >=21.1.0" @@ -1653,20 +1679,20 @@ "url": "https://opencollective.com/typescript-eslint" }, "peerDependencies": { - "typescript": ">=4.8.4 <5.8.0" + "typescript": ">=4.8.4 <5.9.0" } }, "node_modules/@typescript-eslint/utils": { - "version": "8.19.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-8.19.1.tgz", - "integrity": "sha512-IxG5gLO0Ne+KaUc8iW1A+XuKLd63o4wlbI1Zp692n1xojCl/THvgIKXJXBZixTh5dd5+yTJ/VXH7GJaaw21qXA==", + "version": "8.26.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-8.26.1.tgz", + "integrity": "sha512-V4Urxa/XtSUroUrnI7q6yUTD3hDtfJ2jzVfeT3VK0ciizfK2q/zGC0iDh1lFMUZR8cImRrep6/q0xd/1ZGPQpg==", "dev": true, "license": "MIT", "dependencies": { "@eslint-community/eslint-utils": "^4.4.0", - "@typescript-eslint/scope-manager": "8.19.1", - "@typescript-eslint/types": "8.19.1", - "@typescript-eslint/typescript-estree": "8.19.1" + "@typescript-eslint/scope-manager": "8.26.1", + "@typescript-eslint/types": "8.26.1", + "@typescript-eslint/typescript-estree": "8.26.1" }, "engines": { "node": "^18.18.0 || ^20.9.0 || >=21.1.0" @@ -1677,17 +1703,17 @@ }, "peerDependencies": { "eslint": "^8.57.0 || ^9.0.0", - "typescript": ">=4.8.4 <5.8.0" + "typescript": ">=4.8.4 <5.9.0" } }, "node_modules/@typescript-eslint/visitor-keys": { - "version": "8.19.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-8.19.1.tgz", - "integrity": "sha512-fzmjU8CHK853V/avYZAvuVut3ZTfwN5YtMaoi+X9Y9MA9keaWNHC3zEQ9zvyX/7Hj+5JkNyK1l7TOR2hevHB6Q==", + "version": "8.26.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-8.26.1.tgz", + "integrity": "sha512-AjOC3zfnxd6S4Eiy3jwktJPclqhFHNyd8L6Gycf9WUPoKZpgM5PjkxY1X7uSy61xVpiJDhhk7XT2NVsN3ALTWg==", "dev": true, "license": "MIT", "dependencies": { - "@typescript-eslint/types": "8.19.1", + "@typescript-eslint/types": "8.26.1", "eslint-visitor-keys": "^4.2.0" }, "engines": { @@ -2433,22 +2459,23 @@ } }, "node_modules/eslint": { - "version": "9.18.0", - "resolved": "https://registry.npmjs.org/eslint/-/eslint-9.18.0.tgz", - "integrity": "sha512-+waTfRWQlSbpt3KWE+CjrPPYnbq9kfZIYUqapc0uBXyjTp8aYXZDsUH16m39Ryq3NjAVP4tjuF7KaukeqoCoaA==", + "version": "9.22.0", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-9.22.0.tgz", + "integrity": "sha512-9V/QURhsRN40xuHXWjV64yvrzMjcz7ZyNoF2jJFmy9j/SLk0u1OLSZgXi28MrXjymnjEGSR80WCdab3RGMDveQ==", "dev": true, "license": "MIT", "dependencies": { "@eslint-community/eslint-utils": "^4.2.0", "@eslint-community/regexpp": "^4.12.1", - "@eslint/config-array": "^0.19.0", - "@eslint/core": "^0.10.0", - "@eslint/eslintrc": "^3.2.0", - "@eslint/js": "9.18.0", - "@eslint/plugin-kit": "^0.2.5", + "@eslint/config-array": "^0.19.2", + "@eslint/config-helpers": "^0.1.0", + "@eslint/core": "^0.12.0", + "@eslint/eslintrc": "^3.3.0", + "@eslint/js": "9.22.0", + "@eslint/plugin-kit": "^0.2.7", "@humanfs/node": "^0.16.6", "@humanwhocodes/module-importer": "^1.0.1", - "@humanwhocodes/retry": "^0.4.1", + "@humanwhocodes/retry": "^0.4.2", "@types/estree": "^1.0.6", "@types/json-schema": "^7.0.15", "ajv": "^6.12.4", @@ -2456,7 +2483,7 @@ "cross-spawn": "^7.0.6", "debug": "^4.3.2", "escape-string-regexp": "^4.0.0", - "eslint-scope": "^8.2.0", + "eslint-scope": "^8.3.0", "eslint-visitor-keys": "^4.2.0", "espree": "^10.3.0", "esquery": "^1.5.0", @@ -2509,9 +2536,9 @@ } }, "node_modules/eslint-config-prettier": { - "version": "9.1.0", - "resolved": "https://registry.npmjs.org/eslint-config-prettier/-/eslint-config-prettier-9.1.0.tgz", - "integrity": "sha512-NSWl5BFQWEPi1j4TjVNItzYV7dZXZ+wP6I6ZhrBGpChQhZRUaElihE9uRRkcbRnNb76UMKDF3r+WTmNcGPKsqw==", + "version": "10.1.1", + "resolved": "https://registry.npmjs.org/eslint-config-prettier/-/eslint-config-prettier-10.1.1.tgz", + "integrity": "sha512-4EQQr6wXwS+ZJSzaR5ZCrYgLxqvUjdXctaEtBqHcbkW944B1NQyO4qpdHQbXBONfwxXdkAY81HH4+LUfrg+zPw==", "dev": true, "license": "MIT", "bin": { @@ -2544,9 +2571,9 @@ } }, "node_modules/eslint-plugin-n": { - "version": "17.15.1", - "resolved": "https://registry.npmjs.org/eslint-plugin-n/-/eslint-plugin-n-17.15.1.tgz", - "integrity": "sha512-KFw7x02hZZkBdbZEFQduRGH4VkIH4MW97ClsbAM4Y4E6KguBJWGfWG1P4HEIpZk2bkoWf0bojpnjNAhYQP8beA==", + "version": "17.16.2", + "resolved": "https://registry.npmjs.org/eslint-plugin-n/-/eslint-plugin-n-17.16.2.tgz", + "integrity": "sha512-iQM5Oj+9o0KaeLoObJC/uxNGpktZCkYiTTBo8PkRWq3HwNcRxwpvSDFjBhQ5+HLJzBTy+CLDC5+bw0Z5GyhlOQ==", "dev": true, "license": "MIT", "dependencies": { @@ -2583,9 +2610,9 @@ } }, "node_modules/eslint-plugin-prettier": { - "version": "5.2.1", - "resolved": "https://registry.npmjs.org/eslint-plugin-prettier/-/eslint-plugin-prettier-5.2.1.tgz", - "integrity": "sha512-gH3iR3g4JfF+yYPaJYkN7jEl9QbweL/YfkoRlNnuIEHEz1vHVlCmWOS+eGGiRuzHQXdJFCOTxRgvju9b8VUmrw==", + "version": "5.2.3", + "resolved": "https://registry.npmjs.org/eslint-plugin-prettier/-/eslint-plugin-prettier-5.2.3.tgz", + "integrity": "sha512-qJ+y0FfCp/mQYQ/vWQ3s7eUlFEL4PyKfAJxsnYTJ4YT73nsJBWqmEpFryxV9OeUiqmsTsYJ5Y+KDNaeP31wrRw==", "dev": true, "license": "MIT", "dependencies": { @@ -2614,9 +2641,9 @@ } }, "node_modules/eslint-scope": { - "version": "8.2.0", - "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-8.2.0.tgz", - "integrity": "sha512-PHlWUfG6lvPc3yvP5A4PNyBL1W8fkDUccmI21JUu/+GKZBoH/W5u6usENXUrWFRsyoW5ACUjFGgAFQp5gUlb/A==", + "version": "8.3.0", + "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-8.3.0.tgz", + "integrity": "sha512-pUNxi75F8MJ/GdeKtVLSbYg4ZI34J6C0C7sbL4YOp2exGwen7ZsuBqKzUhXd0qMQ362yET3z+uPwKeg/0C2XCQ==", "dev": true, "license": "BSD-2-Clause", "dependencies": { @@ -2880,9 +2907,9 @@ "license": "MIT" }, "node_modules/fastq": { - "version": "1.18.0", - "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.18.0.tgz", - "integrity": "sha512-QKHXPW0hD8g4UET03SdOdunzSouc9N4AuHdsX8XNcTsuz+yYFILVNIX4l9yHABMhiEI9Db0JTTIpu0wB+Y1QQw==", + "version": "1.19.1", + "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.19.1.tgz", + "integrity": "sha512-GwLTyxkCXjXbxqIhTsMI2Nui8huMPtnxg7krajPJAjnEG/iiOS7i+zCtWGZR9G0NBKbXKh6X9m9UIsYX/N6vvQ==", "dev": true, "license": "ISC", "dependencies": { @@ -3134,9 +3161,9 @@ } }, "node_modules/globals": { - "version": "14.0.0", - "resolved": "https://registry.npmjs.org/globals/-/globals-14.0.0.tgz", - "integrity": "sha512-oahGvuMGQlPw/ivIYBjVSrWAfWLBeku5tpPE2fOPLi+WHffIWbuh2tCjhyQhTBPMf5E9jDEH4FOmTYgYwbKwtQ==", + "version": "16.0.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-16.0.0.tgz", + "integrity": "sha512-iInW14XItCXET01CQFqudPOWP2jYMl7T+QRQT+UNcR/iQncN/F0UNpgd76iFkBPgNQb4+X3LV9tLJYzwh+Gl3A==", "dev": true, "license": "MIT", "engines": { @@ -3211,9 +3238,9 @@ } }, "node_modules/import-fresh": { - "version": "3.3.0", - "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.0.tgz", - "integrity": "sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw==", + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.1.tgz", + "integrity": "sha512-TR3KfrTZTYLPB6jUjfx6MF9WcWrHL9su5TObK4ZkYgBdWKPOFoSoQIdEuTuR82pmtxH2spWG9h6etwfr1pLBqQ==", "dev": true, "license": "MIT", "dependencies": { @@ -4640,9 +4667,9 @@ } }, "node_modules/prettier": { - "version": "3.4.2", - "resolved": "https://registry.npmjs.org/prettier/-/prettier-3.4.2.tgz", - "integrity": "sha512-e9MewbtFo+Fevyuxn/4rrcDAaq0IYxPGLvObpQjiZBMAzB9IGmzlnG9RZy3FFas+eBMu2vA0CszMeduow5dIuQ==", + "version": "3.5.3", + "resolved": "https://registry.npmjs.org/prettier/-/prettier-3.5.3.tgz", + "integrity": "sha512-QQtaxnoDJeAkDvDKWCLiwIXkTgRhwYDEQCghU9Z6q03iyek/rxRh/2lC3HB7P8sWT2xC/y5JDctPLBIGzHKbhw==", "dev": true, "license": "MIT", "bin": { @@ -4850,9 +4877,9 @@ } }, "node_modules/reusify": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.0.4.tgz", - "integrity": "sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==", + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.1.0.tgz", + "integrity": "sha512-g6QUff04oZpHs0eG5p83rFLhHeV00ug/Yf9nZM6fLeUrPguBTkTQOdpAWWspMh55TZfVQDPaN3NQJfbVRAxdIw==", "dev": true, "license": "MIT", "engines": { @@ -4885,9 +4912,9 @@ } }, "node_modules/semver": { - "version": "7.6.3", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.6.3.tgz", - "integrity": "sha512-oVekP1cKtI+CTDvHWYFUcMtsK/00wmAEfyqKfNdARm8u1wNVhSgaX7A8d4UuIlUI5e84iEwOhs7ZPYRmzU9U6A==", + "version": "7.7.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.1.tgz", + "integrity": "sha512-hlq8tAfn0m/61p4BVRcPzIGr6LKiMwo4VM6dGi6pt4qcRkmNzTcWq6eCEjEh+qXjkMDvPlOFFSGwQjoEa6gyMA==", "dev": true, "license": "ISC", "bin": { @@ -5183,9 +5210,9 @@ } }, "node_modules/ts-api-utils": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ts-api-utils/-/ts-api-utils-2.0.0.tgz", - "integrity": "sha512-xCt/TOAc+EOHS1XPnijD3/yzpH6qg2xppZO1YDqGoVsNXfQfzHpOdNuXwrwOU8u4ITXJyDCTyt8w5g1sZv9ynQ==", + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/ts-api-utils/-/ts-api-utils-2.0.1.tgz", + "integrity": "sha512-dnlgjFSVetynI8nzgJ+qF62efpglpWRk8isUEWZGWlJYySCTD6aKvbUDu+zbPeDakk3bg5H4XpitHukgfL1m9w==", "dev": true, "license": "MIT", "engines": { @@ -5196,9 +5223,9 @@ } }, "node_modules/ts-jest": { - "version": "29.2.5", - "resolved": "https://registry.npmjs.org/ts-jest/-/ts-jest-29.2.5.tgz", - "integrity": "sha512-KD8zB2aAZrcKIdGk4OwpJggeLcH1FgrICqDSROWqlnJXGCXK4Mn6FcdK2B6670Xr73lHMG1kHw8R87A0ecZ+vA==", + "version": "29.2.6", + "resolved": "https://registry.npmjs.org/ts-jest/-/ts-jest-29.2.6.tgz", + "integrity": "sha512-yTNZVZqc8lSixm+QGVFcPe6+yj7+TWZwIesuOWvfcn4B9bz5x4NDzVCQQjOs7Hfouu36aEqfEbo9Qpo+gq8dDg==", "dev": true, "license": "MIT", "dependencies": { @@ -5209,7 +5236,7 @@ "json5": "^2.2.3", "lodash.memoize": "^4.1.2", "make-error": "^1.3.6", - "semver": "^7.6.3", + "semver": "^7.7.1", "yargs-parser": "^21.1.1" }, "bin": { @@ -5332,9 +5359,9 @@ } }, "node_modules/typescript": { - "version": "5.7.3", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.7.3.tgz", - "integrity": "sha512-84MVSjMEHP+FQRPy3pX9sTVV/INIex71s9TL2Gm5FG/WG1SqXeKyZ0k7/blY/4FdOzI12CBy1vGc4og/eus0fw==", + "version": "5.8.2", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.8.2.tgz", + "integrity": "sha512-aJn6wq13/afZp/jT9QZmwEjDqqvSGp1VT5GVg+f/t6/oVyrgXM6BY1h9BRh/O5p3PlUPAe+WuiEZOmb/49RqoQ==", "dev": true, "license": "Apache-2.0", "bin": { @@ -5346,15 +5373,15 @@ } }, "node_modules/typescript-eslint": { - "version": "8.19.1", - "resolved": "https://registry.npmjs.org/typescript-eslint/-/typescript-eslint-8.19.1.tgz", - "integrity": "sha512-LKPUQpdEMVOeKluHi8md7rwLcoXHhwvWp3x+sJkMuq3gGm9yaYJtPo8sRZSblMFJ5pcOGCAak/scKf1mvZDlQw==", + "version": "8.26.1", + "resolved": "https://registry.npmjs.org/typescript-eslint/-/typescript-eslint-8.26.1.tgz", + "integrity": "sha512-t/oIs9mYyrwZGRpDv3g+3K6nZ5uhKEMt2oNmAPwaY4/ye0+EH4nXIPYNtkYFS6QHm+1DFg34DbglYBz5P9Xysg==", "dev": true, "license": "MIT", "dependencies": { - "@typescript-eslint/eslint-plugin": "8.19.1", - "@typescript-eslint/parser": "8.19.1", - "@typescript-eslint/utils": "8.19.1" + "@typescript-eslint/eslint-plugin": "8.26.1", + "@typescript-eslint/parser": "8.26.1", + "@typescript-eslint/utils": "8.26.1" }, "engines": { "node": "^18.18.0 || ^20.9.0 || >=21.1.0" @@ -5365,7 +5392,7 @@ }, "peerDependencies": { "eslint": "^8.57.0 || ^9.0.0", - "typescript": ">=4.8.4 <5.8.0" + "typescript": ">=4.8.4 <5.9.0" } }, "node_modules/undici-types": { diff --git a/package.json b/package.json index ecf51e5..016b547 100644 --- a/package.json +++ b/package.json @@ -19,27 +19,29 @@ }, "keywords": [ "server", - "healthz" + "healthz", + "livenessProbe", + "readinessProbe" ], "author": "Michele (macno) Azzolari", "license": "ISC", "description": "Simple http server to expose an healthz endpoint", "devDependencies": { - "@eslint/js": "9.18.0", + "@eslint/js": "9.22.0", "@types/jest": "29.5.14", - "@typescript-eslint/eslint-plugin": "8.19.1", - "@typescript-eslint/parser": "8.19.1", - "eslint": "9.18.0", - "eslint-config-prettier": "9.1.0", - "eslint-plugin-n": "17.15.1", - "eslint-plugin-prettier": "5.2.1", - "globals": "14.0.0", + "@typescript-eslint/eslint-plugin": "8.26.1", + "@typescript-eslint/parser": "8.26.1", + "eslint": "9.22.0", + "eslint-config-prettier": "10.1.1", + "eslint-plugin-n": "17.16.2", + "eslint-plugin-prettier": "5.2.3", + "globals": "16.0.0", "jest": "29.7.0", - "prettier": "3.4.2", - "ts-jest": "29.2.5", + "prettier": "3.5.3", + "ts-jest": "29.2.6", "ts-node": "10.9.2", - "typescript": "5.7.3", - "typescript-eslint": "8.19.1" + "typescript": "5.8.2", + "typescript-eslint": "8.26.1" }, "files": [ "build/esm/**/*.js", From c05eee6a13fafee8e456728f41d88aeb59dff41d Mon Sep 17 00:00:00 2001 From: Michele Azzolari Date: Tue, 11 Mar 2025 15:18:21 +0100 Subject: [PATCH 2/2] feat: now support readiness endpoint --- src/index.ts | 123 ++++++++++++++++++++++++++++++++------------ src/types.ts | 7 ++- tests/index.test.ts | 120 +++++++++++++++++++++++++++++++++++++++--- 3 files changed, 209 insertions(+), 41 deletions(-) diff --git a/src/index.ts b/src/index.ts index bff7473..4d978cd 100644 --- a/src/index.ts +++ b/src/index.ts @@ -14,8 +14,8 @@ * limitations under the License. */ -import { createServer, Server } from 'http'; -import { AddressInfo, checkFunction, HealthzServerOptions } from './types'; +import { createServer, Server, ServerResponse } from 'http'; +import { AddressInfo, healthCheckFunction, HealthzServerOptions, readinessCheckFunction } from './types'; const healthServerSymbol = Symbol.for('Fw.HealthzServer'); @@ -26,53 +26,105 @@ type FWGlobal = { const _global = global as unknown as FWGlobal; const defaultOptions: HealthzServerOptions = { - path: '/healthz', + healthzPath: '/healthz', + readinessPath: '/', address: '0.0.0.0', port: 8282 }; export class HealthzServer { + private static ready = false; + + private static _healthCheck(res: ServerResponse, healthCheck?: healthCheckFunction): void { + if (!healthCheck) { + res.end('OK'); + return; + } + try { + const check = healthCheck(); + if (check instanceof Promise) { + check + .then(() => { + res.end('OK'); + }) + .catch(e => { + res.writeHead(500, { 'x-error': e.message }); + res.end('KO'); + }); + } else { + res.end('OK'); + } + } catch (e) { + res.writeHead(500, { 'x-error': e.message }); + res.end('KO'); + } + } + + private static _readinessCheck(res: ServerResponse, readinessCheck?: readinessCheckFunction): void { + function reply(ready: boolean) { + if (ready) { + res.end('OK'); + } else { + res.writeHead(503, { 'x-error': 'Not ready' }); + res.end('KO'); + } + } + if (!readinessCheck) { + reply(HealthzServer.ready); + return; + } + try { + const check = readinessCheck(); + if (check instanceof Promise) { + check + .then(ready => { + reply(ready); + }) + .catch(e => { + res.writeHead(500, { 'x-error': e.message }); + res.end('KO'); + }); + } else { + reply(check); + } + } catch (e) { + res.writeHead(500, { 'x-error': e.message }); + res.end('KO'); + } + } + static async start( - opts?: HealthzServerOptions | checkFunction, - healthCheck?: checkFunction + opts?: HealthzServerOptions, + healthCheck?: healthCheckFunction, + readinessCheck?: readinessCheckFunction ): Promise { - if (typeof opts === 'function') { - healthCheck = opts; - opts = {}; - } if (healthCheck) { if (typeof healthCheck !== 'function') { throw new Error('healthCheck must be a function'); } } - const { path: PATH, address: ADDRESS, port: PORT } = Object.assign({}, defaultOptions, opts); + if (readinessCheck) { + if (typeof readinessCheck !== 'function') { + throw new Error('readinessCheck must be a function'); + } + } + + const { + path: OLD_PATH, + healthzPath, + readinessPath, + address: ADDRESS, + port: PORT + } = Object.assign({}, defaultOptions, opts); + const HEALTHZ_PATH = OLD_PATH ?? healthzPath; if (_global[healthServerSymbol]) { return Promise.resolve(null); } _global[healthServerSymbol] = createServer((req, res) => { - if (req.url === PATH) { - if (!healthCheck) { - res.end('OK'); - return; - } - try { - const check = healthCheck(); - if (check instanceof Promise) { - check - .then(() => { - res.end('OK'); - }) - .catch(e => { - res.writeHead(500, { 'x-error': e.message }); - res.end('KO'); - }); - } else { - res.end('OK'); - } - } catch (e) { - res.writeHead(500, { 'x-error': e.message }); - res.end('KO'); - } + if (req.url === HEALTHZ_PATH) { + HealthzServer._healthCheck(res, healthCheck); + } else if (req.url === readinessPath) { + HealthzServer._readinessCheck(res, readinessCheck); } else { res.writeHead(404); res.end('Not Found'); @@ -95,9 +147,14 @@ export class HealthzServer { }); } + static setReady(ready: boolean) { + HealthzServer.ready = ready; + } + static async stop() { process.off('SIGTERM', HealthzServer.stop); process.off('SIGINT', HealthzServer.stop); + HealthzServer.ready = false; return new Promise(resolve => { if (_global[healthServerSymbol]) { _global[healthServerSymbol].close(() => { diff --git a/src/types.ts b/src/types.ts index 7eb0683..5b7a84f 100644 --- a/src/types.ts +++ b/src/types.ts @@ -15,12 +15,17 @@ */ export interface HealthzServerOptions { + // @deprecated in favor of healthzPath path?: string; + healthzPath?: string; + readinessPath?: string; port?: number; address?: string; } -export type checkFunction = () => void | Promise; +export type healthCheckFunction = () => void | Promise; + +export type readinessCheckFunction = () => boolean | Promise; export interface AddressInfo { port: number; diff --git a/tests/index.test.ts b/tests/index.test.ts index 0298fb7..e747692 100644 --- a/tests/index.test.ts +++ b/tests/index.test.ts @@ -32,7 +32,19 @@ describe('HealthServer', () => { assert.equal(d, undefined); }); - it('should start HealthServer without check', async () => { + it('should throw error if start is called with wrong argument (healthzCheck)', async () => { + // @ts-expect-error testing wrong argument + await expect(() => HealthzServer.start({ port: 0 }, {})).rejects.toThrow('healthCheck must be a function'); + }); + + it('should throw error if start is called with wrong argument (readinessCheck)', async () => { + // @ts-expect-error testing wrong argument + await expect(() => HealthzServer.start({ port: 0 }, undefined, {})).rejects.toThrow( + 'readinessCheck must be a function' + ); + }); + + it('should start HealthServer with default options', async () => { const addressInfo = await HealthzServer.start({ port: 0 }); assert.ok(addressInfo); const { port } = addressInfo; @@ -42,9 +54,15 @@ describe('HealthServer', () => { const e = await fetch(`http://localhost:${port}/xxxx`); assert.equal(e.status, 404); assert.equal(await e.text(), 'Not Found'); + // by default readinessPath is / and server not ready + let r = await fetch(`http://localhost:${port}/`, fetchOptions); + assert.equal(r.status, 503); + HealthzServer.setReady(true); + r = await fetch(`http://localhost:${port}/`, fetchOptions); + assert.equal(r.status, 200); }); - it('should start HealthServer with check', async () => { + it('should start HealthServer with healthCheck custom function', async () => { let cbCalled = false; const addressInfo = await HealthzServer.start({ port: 0 }, () => { cbCalled = true; @@ -57,7 +75,7 @@ describe('HealthServer', () => { assert.ok(cbCalled); }); - it('should start HealthServer with check Error', async () => { + it('should start HealthServer with healthCheck custom function (Error)', async () => { let cbCalled = false; const addressInfo = await HealthzServer.start({ port: 0 }, () => { cbCalled = true; @@ -71,7 +89,7 @@ describe('HealthServer', () => { assert.ok(cbCalled); }); - it('should start HealthServer with check (promise)', async () => { + it('should start HealthServer with healthCheck custom function (promise)', async () => { let checkCalled = false; const addressInfo = await HealthzServer.start({ port: 0 }, async () => { await setTimeout(100); @@ -85,7 +103,7 @@ describe('HealthServer', () => { assert.ok(checkCalled); }); - it('should start HealthServer with check Error (promise)', async () => { + it('should start HealthServer with healthCheck custom function (promise)(Error)', async () => { let checkCalled = false; const addressInfo = await HealthzServer.start({ port: 0 }, async () => { await setTimeout(100); @@ -100,8 +118,89 @@ describe('HealthServer', () => { assert.ok(checkCalled); }); - it('should start HealthServer with options', async () => { - const addressInfo = await HealthzServer.start({ port: 0, path: '/healthz2' }); + it('should start HealthServer with readinessCheck custom function (ready) (promise)', async () => { + let checkCalled = false; + const addressInfo = await HealthzServer.start({ port: 0 }, undefined, async () => { + await setTimeout(100); + checkCalled = true; + return true; + }); + assert.ok(addressInfo); + const { port } = addressInfo; + const f = await fetch(`http://localhost:${port}/`, fetchOptions); + assert.equal(f.status, 200); + assert.ok(checkCalled); + }); + + it('should start HealthServer with readinessCheck custom function (not ready) (promise)', async () => { + let checkCalled = false; + const addressInfo = await HealthzServer.start({ port: 0 }, undefined, async () => { + await setTimeout(100); + checkCalled = true; + return false; + }); + assert.ok(addressInfo); + const { port } = addressInfo; + const f = await fetch(`http://localhost:${port}/`, fetchOptions); + assert.equal(f.status, 503); + assert.ok(checkCalled); + }); + + it('should start HealthServer with readinessCheck custom function (error) (promise)', async () => { + let checkCalled = false; + const addressInfo = await HealthzServer.start({ port: 0 }, undefined, async () => { + await setTimeout(100); + checkCalled = true; + throw new Error('Error'); + }); + assert.ok(addressInfo); + const { port } = addressInfo; + const f = await fetch(`http://localhost:${port}/`, fetchOptions); + assert.equal(f.status, 500); + assert.ok(checkCalled); + }); + + it('should start HealthServer with readinessCheck custom function (ready)', async () => { + let checkCalled = false; + const addressInfo = await HealthzServer.start({ port: 0 }, undefined, () => { + checkCalled = true; + return true; + }); + assert.ok(addressInfo); + const { port } = addressInfo; + const f = await fetch(`http://localhost:${port}/`, fetchOptions); + assert.equal(f.status, 200); + assert.ok(checkCalled); + }); + + it('should start HealthServer with readinessCheck custom function (not ready)', async () => { + let checkCalled = false; + const addressInfo = await HealthzServer.start({ port: 0 }, undefined, () => { + checkCalled = true; + return false; + }); + assert.ok(addressInfo); + const { port } = addressInfo; + const f = await fetch(`http://localhost:${port}/`, fetchOptions); + assert.equal(f.status, 503); + assert.ok(checkCalled); + }); + + it('should start HealthServer with readinessCheck custom function (error)', async () => { + let checkCalled = false; + const addressInfo = await HealthzServer.start({ port: 0 }, undefined, () => { + checkCalled = true; + throw new Error('Error'); + }); + assert.ok(addressInfo); + const { port } = addressInfo; + const f = await fetch(`http://localhost:${port}/`, fetchOptions); + assert.equal(f.status, 500); + assert.ok(checkCalled); + }); + + it('should start HealthServer with custom options', async () => { + const addressInfo = await HealthzServer.start({ port: 0, healthzPath: '/healthz2', readinessPath: '/readiness' }); assert.ok(addressInfo); const { port } = addressInfo; const f = await fetch(`http://localhost:${port}/healthz2`, fetchOptions); @@ -110,5 +209,12 @@ describe('HealthServer', () => { const e = await fetch(`http://localhost:${port}/healthz`); assert.equal(e.status, 404); assert.equal(await e.text(), 'Not Found'); + let r = await fetch(`http://localhost:${port}/`); + assert.equal(r.status, 404); + r = await fetch(`http://localhost:${port}/readiness`); + assert.equal(r.status, 503); + HealthzServer.setReady(true); + r = await fetch(`http://localhost:${port}/readiness`); + assert.equal(r.status, 200); }); });