diff --git a/mocha.setup.mjs b/mocha.setup.mjs index 0f8fca40..d96d86ab 100644 --- a/mocha.setup.mjs +++ b/mocha.setup.mjs @@ -2,7 +2,6 @@ import { dirname, join } from 'node:path'; import { fileURLToPath } from 'node:url'; import { use } from 'chai'; import chaiAsPromised from 'chai-as-promised'; -import { reset } from 'testdouble'; use(chaiAsPromised); @@ -17,10 +16,6 @@ process.env = { /** @type {import('mocha').RootHookObject} */ export const mochaHooks = { - /** @returns {void} */ - afterEach() { - reset(); - }, afterAll() { process.env = { ...env }; }, diff --git a/package-lock.json b/package-lock.json index 3e7a9ec0..c4d7c599 100644 --- a/package-lock.json +++ b/package-lock.json @@ -13,16 +13,15 @@ "@myrotvorets/express-microservice-middlewares": "^2.2.0", "@myrotvorets/express-request-logger": "^1.2.0", "@myrotvorets/oav-installer": "^5.0.0", - "@myrotvorets/opentelemetry-configurator": "^7.0.0", - "@myrotvorets/otel-utils": "^0.0.10", + "@myrotvorets/opentelemetry-configurator": "^7.1.0", + "@myrotvorets/otel-utils": "^1.0.0", "@opentelemetry/api": "^1.6.0", "@opentelemetry/core": "^1.17.1", "@opentelemetry/semantic-conventions": "^1.17.1", "awilix": "^9.0.0", "envalid": "^8.0.0", "express": "^4.18.2", - "express-openapi-validator": "^5.0.6", - "maxmind": "^4.3.16" + "mmdb-lib": "^2.0.2" }, "devDependencies": { "@myrotvorets/eslint-config-myrotvorets-ts": "^2.22.5", @@ -47,7 +46,6 @@ "nodemon": "^3.0.1", "rimraf": "^5.0.5", "supertest": "^6.3.3", - "testdouble": "^3.20.0", "ts-node": "^10.9.1", "typescript": "^5.2.2" } @@ -86,6 +84,7 @@ "version": "9.1.2", "resolved": "https://registry.npmjs.org/@apidevtools/json-schema-ref-parser/-/json-schema-ref-parser-9.1.2.tgz", "integrity": "sha512-r1w81DpR+KyRWd3f+rk6TNqMgedmAxZP5v5KWlXQWlgMUUtyEJch0DKEci1SorPMiSeM8XPl7MZ3miJ60JIpQg==", + "peer": true, "dependencies": { "@jsdevtools/ono": "^7.1.3", "@types/json-schema": "^7.0.6", @@ -143,9 +142,9 @@ } }, "node_modules/@eslint-community/regexpp": { - "version": "4.9.1", - "resolved": "https://registry.npmjs.org/@eslint-community/regexpp/-/regexpp-4.9.1.tgz", - "integrity": "sha512-Y27x+MBLjXa+0JWDhykM3+JE+il3kHKAEqabfEWq3SDhZjLYb6/BHL/JKFnH3fe207JaXkyDo685Oc2Glt6ifA==", + "version": "4.10.0", + "resolved": "https://registry.npmjs.org/@eslint-community/regexpp/-/regexpp-4.10.0.tgz", + "integrity": "sha512-Cu96Sd2By9mCNTx2iyKOmq10v22jUVQv0lQnlGNy16oE9589yE+QADPbrMGCkA51cKZSg3Pu/aTJVTGfL/qjUA==", "dev": true, "peer": true, "engines": { @@ -196,9 +195,9 @@ } }, "node_modules/@grpc/grpc-js": { - "version": "1.9.7", - "resolved": "https://registry.npmjs.org/@grpc/grpc-js/-/grpc-js-1.9.7.tgz", - "integrity": "sha512-yMaA/cIsRhGzW3ymCNpdlPcInXcovztlgu/rirThj2b87u3RzWUszliOqZ/pldy7yhmJPS8uwog+kZSTa4A0PQ==", + "version": "1.9.8", + "resolved": "https://registry.npmjs.org/@grpc/grpc-js/-/grpc-js-1.9.8.tgz", + "integrity": "sha512-FFPzDS333Vw8hvf+1FaEsaCYVPBdNdUCw7zArTiF7+6gOzln967b4GBCBekKGqoKEgna8d3Ayxv8t+IvazXG3g==", "dependencies": { "@grpc/proto-loader": "^0.7.8", "@types/node": ">=12.12.47" @@ -393,12 +392,13 @@ "node_modules/@jsdevtools/ono": { "version": "7.1.3", "resolved": "https://registry.npmjs.org/@jsdevtools/ono/-/ono-7.1.3.tgz", - "integrity": "sha512-4JQNk+3mVzK3xh2rqd6RB4J46qUR19azEHBneZyTZM+c456qOrbbM/5xcR8huNCCcbVt7+UmizG6GuUvPvKUYg==" + "integrity": "sha512-4JQNk+3mVzK3xh2rqd6RB4J46qUR19azEHBneZyTZM+c456qOrbbM/5xcR8huNCCcbVt7+UmizG6GuUvPvKUYg==", + "peer": true }, "node_modules/@myrotvorets/create-server": { - "version": "2.2.0", - "resolved": "https://npm.pkg.github.com/download/@myrotvorets/create-server/2.2.0/aa007ed074d41592e4e49bc4a14f07dff639cc3e", - "integrity": "sha512-Ho8kLyguXlrsG+wmR3jJ5ofyv7dqgwJ6KPeSyQp+TPmB6fXkgueBO7TL8Ajfvb94zeTd/advyrCUk9BL9ZaYfA==", + "version": "3.1.0", + "resolved": "https://npm.pkg.github.com/download/@myrotvorets/create-server/3.1.0/fba32470c797f851c53706923261e76fadae5198", + "integrity": "sha512-iGwK0tIXsVziMXFLEsVAYANluJy38gVw1pWdyyd4I66kfVBirWRvGWXEBUIkax+3OzVQFfTKC+G7PazWwN9QUA==", "license": "MIT", "peerDependencies": { "envalid": "^6.0.0 || ^7.0.0 || ^8.0.0" @@ -454,9 +454,9 @@ } }, "node_modules/@myrotvorets/opentelemetry-configurator": { - "version": "7.0.0", - "resolved": "https://npm.pkg.github.com/download/@myrotvorets/opentelemetry-configurator/7.0.0/9456292eadcc8f728cff7bb2d322a21496712846", - "integrity": "sha512-1Zs9mefGFrcxx3N9X1XqPSWjihlLs10tgdaGz/Uyx/JDCIu6qo9q6hDatysz+she6NzJ0IrfeANp+uu+3nNjtQ==", + "version": "7.1.0", + "resolved": "https://npm.pkg.github.com/download/@myrotvorets/opentelemetry-configurator/7.1.0/faad8996a3738d9c9d0fb63aa98fd490825130ca", + "integrity": "sha512-23cpfdKnUTlgglLIYYyZLAwqH6yUGKSceDcUl3K4/KIHzHugPF8b5f8D9dAP+qhR5k5C0axFU0w3jEBIfQYl4Q==", "license": "MIT", "dependencies": { "@myrotvorets/opentelemetry-resource-detectors": "^1.0.1", @@ -491,12 +491,12 @@ } }, "node_modules/@myrotvorets/otel-utils": { - "version": "0.0.10", - "resolved": "https://npm.pkg.github.com/download/@myrotvorets/otel-utils/0.0.10/c4a88d023db5334adc92439a113bbe0b96e484b2", - "integrity": "sha512-1s5cpfplVjKUUrJxm30+ZC5E5mH291APDtatt+KRd6Mje3yzsEQ49GWGDppg6ObjZK5/DtfBFlNF8vjGMIwwxA==", + "version": "1.0.0", + "resolved": "https://npm.pkg.github.com/download/@myrotvorets/otel-utils/1.0.0/c03c0d4716c85c3df5f3e32278df764464ee2fc2", + "integrity": "sha512-PjLl1QXT3/GF9mkwdtgBPspc7Rhe6BZ+a5wwLA1o7c3RolQ6cDW4zkN0If5HZ+EybhuM/06lMLDWi45UgMHUXw==", "license": "MIT", "dependencies": { - "@myrotvorets/create-server": "^2.2.0" + "@myrotvorets/create-server": "^3.0.0" }, "peerDependencies": { "@opentelemetry/api": "^1.6.0", @@ -1274,7 +1274,8 @@ "node_modules/@types/json-schema": { "version": "7.0.14", "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.14.tgz", - "integrity": "sha512-U3PUjAudAdJBeC2pgN8uTIKgxrb4nlDF3SF0++EldXQvQBGkpFZMSnwQiIoDU77tv45VgNkl/L4ouD+rEomujw==" + "integrity": "sha512-U3PUjAudAdJBeC2pgN8uTIKgxrb4nlDF3SF0++EldXQvQBGkpFZMSnwQiIoDU77tv45VgNkl/L4ouD+rEomujw==", + "peer": true }, "node_modules/@types/json5": { "version": "0.0.29", @@ -1371,17 +1372,17 @@ } }, "node_modules/@typescript-eslint/eslint-plugin": { - "version": "6.8.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-6.8.0.tgz", - "integrity": "sha512-GosF4238Tkes2SHPQ1i8f6rMtG6zlKwMEB0abqSJ3Npvos+doIlc/ATG+vX1G9coDF3Ex78zM3heXHLyWEwLUw==", + "version": "6.9.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-6.9.0.tgz", + "integrity": "sha512-lgX7F0azQwRPB7t7WAyeHWVfW1YJ9NIgd9mvGhfQpRY56X6AVf8mwM8Wol+0z4liE7XX3QOt8MN1rUKCfSjRIA==", "dev": true, "peer": true, "dependencies": { "@eslint-community/regexpp": "^4.5.1", - "@typescript-eslint/scope-manager": "6.8.0", - "@typescript-eslint/type-utils": "6.8.0", - "@typescript-eslint/utils": "6.8.0", - "@typescript-eslint/visitor-keys": "6.8.0", + "@typescript-eslint/scope-manager": "6.9.0", + "@typescript-eslint/type-utils": "6.9.0", + "@typescript-eslint/utils": "6.9.0", + "@typescript-eslint/visitor-keys": "6.9.0", "debug": "^4.3.4", "graphemer": "^1.4.0", "ignore": "^5.2.4", @@ -1407,15 +1408,15 @@ } }, "node_modules/@typescript-eslint/parser": { - "version": "6.8.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-6.8.0.tgz", - "integrity": "sha512-5tNs6Bw0j6BdWuP8Fx+VH4G9fEPDxnVI7yH1IAPkQH5RUtvKwRoqdecAPdQXv4rSOADAaz1LFBZvZG7VbXivSg==", + "version": "6.9.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-6.9.0.tgz", + "integrity": "sha512-GZmjMh4AJ/5gaH4XF2eXA8tMnHWP+Pm1mjQR2QN4Iz+j/zO04b9TOvJYOX2sCNIQHtRStKTxRY1FX7LhpJT4Gw==", "dev": true, "dependencies": { - "@typescript-eslint/scope-manager": "6.8.0", - "@typescript-eslint/types": "6.8.0", - "@typescript-eslint/typescript-estree": "6.8.0", - "@typescript-eslint/visitor-keys": "6.8.0", + "@typescript-eslint/scope-manager": "6.9.0", + "@typescript-eslint/types": "6.9.0", + "@typescript-eslint/typescript-estree": "6.9.0", + "@typescript-eslint/visitor-keys": "6.9.0", "debug": "^4.3.4" }, "engines": { @@ -1435,13 +1436,13 @@ } }, "node_modules/@typescript-eslint/scope-manager": { - "version": "6.8.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-6.8.0.tgz", - "integrity": "sha512-xe0HNBVwCph7rak+ZHcFD6A+q50SMsFwcmfdjs9Kz4qDh5hWhaPhFjRs/SODEhroBI5Ruyvyz9LfwUJ624O40g==", + "version": "6.9.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-6.9.0.tgz", + "integrity": "sha512-1R8A9Mc39n4pCCz9o79qRO31HGNDvC7UhPhv26TovDsWPBDx+Sg3rOZdCELIA3ZmNoWAuxaMOT7aWtGRSYkQxw==", "dev": true, "dependencies": { - "@typescript-eslint/types": "6.8.0", - "@typescript-eslint/visitor-keys": "6.8.0" + "@typescript-eslint/types": "6.9.0", + "@typescript-eslint/visitor-keys": "6.9.0" }, "engines": { "node": "^16.0.0 || >=18.0.0" @@ -1452,14 +1453,14 @@ } }, "node_modules/@typescript-eslint/type-utils": { - "version": "6.8.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-6.8.0.tgz", - "integrity": "sha512-RYOJdlkTJIXW7GSldUIHqc/Hkto8E+fZN96dMIFhuTJcQwdRoGN2rEWA8U6oXbLo0qufH7NPElUb+MceHtz54g==", + "version": "6.9.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-6.9.0.tgz", + "integrity": "sha512-XXeahmfbpuhVbhSOROIzJ+b13krFmgtc4GlEuu1WBT+RpyGPIA4Y/eGnXzjbDj5gZLzpAXO/sj+IF/x2GtTMjQ==", "dev": true, "peer": true, "dependencies": { - "@typescript-eslint/typescript-estree": "6.8.0", - "@typescript-eslint/utils": "6.8.0", + "@typescript-eslint/typescript-estree": "6.9.0", + "@typescript-eslint/utils": "6.9.0", "debug": "^4.3.4", "ts-api-utils": "^1.0.1" }, @@ -1480,9 +1481,9 @@ } }, "node_modules/@typescript-eslint/types": { - "version": "6.8.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-6.8.0.tgz", - "integrity": "sha512-p5qOxSum7W3k+llc7owEStXlGmSl8FcGvhYt8Vjy7FqEnmkCVlM3P57XQEGj58oqaBWDQXbJDZxwUWMS/EAPNQ==", + "version": "6.9.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-6.9.0.tgz", + "integrity": "sha512-+KB0lbkpxBkBSiVCuQvduqMJy+I1FyDbdwSpM3IoBS7APl4Bu15lStPjgBIdykdRqQNYqYNMa8Kuidax6phaEw==", "dev": true, "engines": { "node": "^16.0.0 || >=18.0.0" @@ -1493,13 +1494,13 @@ } }, "node_modules/@typescript-eslint/typescript-estree": { - "version": "6.8.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-6.8.0.tgz", - "integrity": "sha512-ISgV0lQ8XgW+mvv5My/+iTUdRmGspducmQcDw5JxznasXNnZn3SKNrTRuMsEXv+V/O+Lw9AGcQCfVaOPCAk/Zg==", + "version": "6.9.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-6.9.0.tgz", + "integrity": "sha512-NJM2BnJFZBEAbCfBP00zONKXvMqihZCrmwCaik0UhLr0vAgb6oguXxLX1k00oQyD+vZZ+CJn3kocvv2yxm4awQ==", "dev": true, "dependencies": { - "@typescript-eslint/types": "6.8.0", - "@typescript-eslint/visitor-keys": "6.8.0", + "@typescript-eslint/types": "6.9.0", + "@typescript-eslint/visitor-keys": "6.9.0", "debug": "^4.3.4", "globby": "^11.1.0", "is-glob": "^4.0.3", @@ -1520,18 +1521,18 @@ } }, "node_modules/@typescript-eslint/utils": { - "version": "6.8.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-6.8.0.tgz", - "integrity": "sha512-dKs1itdE2qFG4jr0dlYLQVppqTE+Itt7GmIf/vX6CSvsW+3ov8PbWauVKyyfNngokhIO9sKZeRGCUo1+N7U98Q==", + "version": "6.9.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-6.9.0.tgz", + "integrity": "sha512-5Wf+Jsqya7WcCO8me504FBigeQKVLAMPmUzYgDbWchINNh1KJbxCgVya3EQ2MjvJMVeXl3pofRmprqX6mfQkjQ==", "dev": true, "peer": true, "dependencies": { "@eslint-community/eslint-utils": "^4.4.0", "@types/json-schema": "^7.0.12", "@types/semver": "^7.5.0", - "@typescript-eslint/scope-manager": "6.8.0", - "@typescript-eslint/types": "6.8.0", - "@typescript-eslint/typescript-estree": "6.8.0", + "@typescript-eslint/scope-manager": "6.9.0", + "@typescript-eslint/types": "6.9.0", + "@typescript-eslint/typescript-estree": "6.9.0", "semver": "^7.5.4" }, "engines": { @@ -1546,12 +1547,12 @@ } }, "node_modules/@typescript-eslint/visitor-keys": { - "version": "6.8.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-6.8.0.tgz", - "integrity": "sha512-oqAnbA7c+pgOhW2OhGvxm0t1BULX5peQI/rLsNDpGM78EebV3C9IGbX5HNZabuZ6UQrYveCLjKo8Iy/lLlBkkg==", + "version": "6.9.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-6.9.0.tgz", + "integrity": "sha512-dGtAfqjV6RFOtIP8I0B4ZTBRrlTT8NHHlZZSchQx3qReaoDeXhYM++M4So2AgFK9ZB0emRPA6JI1HkafzA2Ibg==", "dev": true, "dependencies": { - "@typescript-eslint/types": "6.8.0", + "@typescript-eslint/types": "6.9.0", "eslint-visitor-keys": "^3.4.1" }, "engines": { @@ -1597,9 +1598,9 @@ } }, "node_modules/acorn": { - "version": "8.10.0", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.10.0.tgz", - "integrity": "sha512-F0SAmZ8iUtS//m8DmCTA0jlh6TDKkHQyK6xc6V4KDTyZKA9dnvX9/3sRTVQrWm79glUAZbnmmNcdYwUIHWVybw==", + "version": "8.11.2", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.11.2.tgz", + "integrity": "sha512-nc0Axzp/0FILLEVsm4fNwLCwMttvhEI263QtVPQcbpfZZ3ts0hLsZGOpE6czNlid7CJ9MlyH8reXkpsf3YUY4w==", "bin": { "acorn": "bin/acorn" }, @@ -1626,9 +1627,9 @@ } }, "node_modules/acorn-walk": { - "version": "8.2.0", - "resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-8.2.0.tgz", - "integrity": "sha512-k+iyHEuPgSw6SbuDpGQM+06HQUa04DZ3o+F6CSzXMvvI5KMvnaEqXe+YVe555R9nn6GPt404fos4wcgpw12SDA==", + "version": "8.3.0", + "resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-8.3.0.tgz", + "integrity": "sha512-FS7hV565M5l1R08MXqo8odwMTB02C2UqzB17RVgu9EyuYFBqJZ3/ZY97sQD5FewVu1UyDFc1yztUDrAwT0EypA==", "dev": true, "engines": { "node": ">=0.4.0" @@ -1655,6 +1656,7 @@ "version": "2.1.1", "resolved": "https://registry.npmjs.org/ajv-formats/-/ajv-formats-2.1.1.tgz", "integrity": "sha512-Wx0Kx52hxE7C18hkMEggYlEifqWZtYaRgouJor+WMdPnQyEK13vgEWyVNup7SoeeoLMsr4kf5h6dOW11I15MUA==", + "peer": true, "dependencies": { "ajv": "^8.0.0" }, @@ -1671,6 +1673,7 @@ "version": "8.12.0", "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.12.0.tgz", "integrity": "sha512-sRu1kpcO9yLtYxBKvqfTeh9KzZEwO3STyX1HT+4CaDzC6HpTGYhIhPIzj9XuKU7KYDwnaeh5hcOwjy1QuJzBPA==", + "peer": true, "dependencies": { "fast-deep-equal": "^3.1.1", "json-schema-traverse": "^1.0.0", @@ -1685,7 +1688,8 @@ "node_modules/ajv-formats/node_modules/json-schema-traverse": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", - "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==" + "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==", + "peer": true }, "node_modules/ansi-color": { "name": "@myrotvorets/ansi-color", @@ -1741,7 +1745,8 @@ "node_modules/append-field": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/append-field/-/append-field-1.0.0.tgz", - "integrity": "sha512-klpgFSWLW1ZEs8svjfb7g4qWY0YS5imI82dTg+QahUvJ8YqAY0P10Uk8tTyh9ZGuYEZEMaeJYCF5BFuX552hsw==" + "integrity": "sha512-klpgFSWLW1ZEs8svjfb7g4qWY0YS5imI82dTg+QahUvJ8YqAY0P10Uk8tTyh9ZGuYEZEMaeJYCF5BFuX552hsw==", + "peer": true }, "node_modules/arg": { "version": "4.1.3", @@ -2032,12 +2037,13 @@ "node_modules/buffer-from": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.2.tgz", - "integrity": "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==" + "integrity": "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==", + "peer": true }, "node_modules/bufrw": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/bufrw/-/bufrw-1.3.0.tgz", - "integrity": "sha512-jzQnSbdJqhIltU9O5KUiTtljP9ccw2u5ix59McQy4pV2xGhVLhRZIndY8GIrgh5HjXa6+QJ9AQhOd2QWQizJFQ==", + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/bufrw/-/bufrw-1.4.0.tgz", + "integrity": "sha512-sWm8iPbqvL9+5SiYxXH73UOkyEbGQg7kyHQmReF89WJHQJw2eV4P/yZ0E+b71cczJ4pPobVhXxgQcmfSTgGHxQ==", "dependencies": { "ansi-color": "^0.2.1", "error": "^7.0.0", @@ -2068,6 +2074,7 @@ "version": "1.6.0", "resolved": "https://registry.npmjs.org/busboy/-/busboy-1.6.0.tgz", "integrity": "sha512-8SFQbg/0hQ9xy3UNTB0YEnsNBbWfhf7RtnzpL7TkBiTBRfrQ9Fxcnz7VJsleJpyp6rVLvXiuORqjlHi5q+PYuA==", + "peer": true, "dependencies": { "streamsearch": "^1.1.0" }, @@ -2140,7 +2147,8 @@ "node_modules/call-me-maybe": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/call-me-maybe/-/call-me-maybe-1.0.2.tgz", - "integrity": "sha512-HpX65o1Hnr9HH25ojC1YGs7HCQLq0GCOibSaWER0eNpgJ/Z1MZv2mTc7+xh6WOPxbRVcmgbv4hGU+uSQ/2xFZQ==" + "integrity": "sha512-HpX65o1Hnr9HH25ojC1YGs7HCQLq0GCOibSaWER0eNpgJ/Z1MZv2mTc7+xh6WOPxbRVcmgbv4hGU+uSQ/2xFZQ==", + "peer": true }, "node_modules/callsites": { "version": "3.1.0", @@ -2335,6 +2343,7 @@ "engines": [ "node >= 0.8" ], + "peer": true, "dependencies": { "buffer-from": "^1.0.0", "inherits": "^2.0.3", @@ -3042,27 +3051,27 @@ } }, "node_modules/eslint-plugin-import": { - "version": "2.28.1", - "resolved": "https://registry.npmjs.org/eslint-plugin-import/-/eslint-plugin-import-2.28.1.tgz", - "integrity": "sha512-9I9hFlITvOV55alzoKBI+K9q74kv0iKMeY6av5+umsNwayt59fz692daGyjR+oStBQgx6nwR9rXldDev3Clw+A==", + "version": "2.29.0", + "resolved": "https://registry.npmjs.org/eslint-plugin-import/-/eslint-plugin-import-2.29.0.tgz", + "integrity": "sha512-QPOO5NO6Odv5lpoTkddtutccQjysJuFxoPS7fAHO+9m9udNHvTCPSAMW9zGAYj8lAIdr40I8yPCdUYrncXtrwg==", "dev": true, "peer": true, "dependencies": { - "array-includes": "^3.1.6", - "array.prototype.findlastindex": "^1.2.2", - "array.prototype.flat": "^1.3.1", - "array.prototype.flatmap": "^1.3.1", + "array-includes": "^3.1.7", + "array.prototype.findlastindex": "^1.2.3", + "array.prototype.flat": "^1.3.2", + "array.prototype.flatmap": "^1.3.2", "debug": "^3.2.7", "doctrine": "^2.1.0", - "eslint-import-resolver-node": "^0.3.7", + "eslint-import-resolver-node": "^0.3.9", "eslint-module-utils": "^2.8.0", - "has": "^1.0.3", - "is-core-module": "^2.13.0", + "hasown": "^2.0.0", + "is-core-module": "^2.13.1", "is-glob": "^4.0.3", "minimatch": "^3.1.2", - "object.fromentries": "^2.0.6", - "object.groupby": "^1.0.0", - "object.values": "^1.1.6", + "object.fromentries": "^2.0.7", + "object.groupby": "^1.0.1", + "object.values": "^1.1.7", "semver": "^6.3.1", "tsconfig-paths": "^3.14.2" }, @@ -3375,6 +3384,7 @@ "version": "5.0.6", "resolved": "https://registry.npmjs.org/express-openapi-validator/-/express-openapi-validator-5.0.6.tgz", "integrity": "sha512-cvl1DmKTpidciajTWacEprW5XhvCen5eznP2J6Rtg1B+O00Z0gWiL5L+0Fh1ZLgR8vgFcv/0Rdrpl6UGnYKyaw==", + "peer": true, "dependencies": { "@apidevtools/json-schema-ref-parser": "^9.1.2", "@types/multer": "^1.4.7", @@ -3397,6 +3407,7 @@ "version": "8.12.0", "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.12.0.tgz", "integrity": "sha512-sRu1kpcO9yLtYxBKvqfTeh9KzZEwO3STyX1HT+4CaDzC6HpTGYhIhPIzj9XuKU7KYDwnaeh5hcOwjy1QuJzBPA==", + "peer": true, "dependencies": { "fast-deep-equal": "^3.1.1", "json-schema-traverse": "^1.0.0", @@ -3412,6 +3423,7 @@ "version": "1.0.0", "resolved": "https://registry.npmjs.org/ajv-draft-04/-/ajv-draft-04-1.0.0.tgz", "integrity": "sha512-mv00Te6nmYbRp5DCwclxtt7yV/joXJPGS7nM+97GdxvuttCOfgI3K4U25zboyeX0O+myI8ERluxQe5wljMmVIw==", + "peer": true, "peerDependencies": { "ajv": "^8.5.0" }, @@ -3424,12 +3436,14 @@ "node_modules/express-openapi-validator/node_modules/json-schema-traverse": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", - "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==" + "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==", + "peer": true }, "node_modules/express-openapi-validator/node_modules/path-to-regexp": { "version": "6.2.1", "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-6.2.1.tgz", - "integrity": "sha512-JLyh7xT1kizaEvcaXOQwOc2/Yhw6KZOvPf1S8401UyLk86CU79LN3vl7ztXGm/pZ+YjoyAJ4rxmHwbkBXJX+yw==" + "integrity": "sha512-JLyh7xT1kizaEvcaXOQwOc2/Yhw6KZOvPf1S8401UyLk86CU79LN3vl7ztXGm/pZ+YjoyAJ4rxmHwbkBXJX+yw==", + "peer": true }, "node_modules/express/node_modules/debug": { "version": "2.6.9", @@ -3447,7 +3461,8 @@ "node_modules/fast-deep-equal": { "version": "3.1.3", "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", - "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==" + "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==", + "peer": true }, "node_modules/fast-diff": { "version": "1.3.0", @@ -3936,16 +3951,6 @@ "dev": true, "peer": true }, - "node_modules/has": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/has/-/has-1.0.4.tgz", - "integrity": "sha512-qdSAmqLF6209RFj4VVItywPMbm3vWylknmB3nvNiUIs72xAimcM8nVYxYr7ncvZq5qzk9MKIZR8ijqD/1QuYjQ==", - "dev": true, - "peer": true, - "engines": { - "node": ">= 0.4.0" - } - }, "node_modules/has-bigints": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/has-bigints/-/has-bigints-1.0.2.tgz", @@ -4399,12 +4404,12 @@ } }, "node_modules/is-plain-obj": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-1.1.0.tgz", - "integrity": "sha512-yvkRyxmFKEOQ4pNXCmJG5AEQNlXJS5LaONXo5/cLdTZdWvsZ1ioJEonLGAosKlMWE8lwUy/bJzMjcw8az73+Fg==", + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-2.1.0.tgz", + "integrity": "sha512-YWnfyRwxL/+SsrWYfOpUtz5b3YD+nyfkHvjbcanzk8zgyO4ASD67uVMRt8k5bM4lLMDnXfriRhOpemw+NfT1eA==", "dev": true, "engines": { - "node": ">=0.10.0" + "node": ">=8" } }, "node_modules/is-regex": { @@ -4424,15 +4429,6 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/is-regexp": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-regexp/-/is-regexp-1.0.0.tgz", - "integrity": "sha512-7zjFAPO4/gwyQAAgRRmqeEeyIICSdmCqa3tsVHMdBzaXXRiqopZL4Cyghg/XulGWrtABTpbnYYzzIRffLkP4oA==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/is-shared-array-buffer": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/is-shared-array-buffer/-/is-shared-array-buffer-1.0.2.tgz", @@ -4724,12 +4720,6 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/lodash": { - "version": "4.17.21", - "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", - "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==", - "dev": true - }, "node_modules/lodash.camelcase": { "version": "4.3.0", "resolved": "https://registry.npmjs.org/lodash.camelcase/-/lodash.camelcase-4.3.0.tgz", @@ -4738,12 +4728,14 @@ "node_modules/lodash.clonedeep": { "version": "4.5.0", "resolved": "https://registry.npmjs.org/lodash.clonedeep/-/lodash.clonedeep-4.5.0.tgz", - "integrity": "sha512-H5ZhCF25riFd9uB5UCkVKo61m3S/xZk1x4wA6yp/L3RFP6Z/eHH1ymQcGLo7J3GMPfm0V/7m1tryHuGVxpqEBQ==" + "integrity": "sha512-H5ZhCF25riFd9uB5UCkVKo61m3S/xZk1x4wA6yp/L3RFP6Z/eHH1ymQcGLo7J3GMPfm0V/7m1tryHuGVxpqEBQ==", + "peer": true }, "node_modules/lodash.get": { "version": "4.4.2", "resolved": "https://registry.npmjs.org/lodash.get/-/lodash.get-4.4.2.tgz", - "integrity": "sha512-z+Uw/vLuy6gQe8cfaFWD7p0wVv8fJl3mbzXh33RS+0oW2wvUqiRXiQ69gLWSLpgB5/6sU+r6BlQR0MBILadqTQ==" + "integrity": "sha512-z+Uw/vLuy6gQe8cfaFWD7p0wVv8fJl3mbzXh33RS+0oW2wvUqiRXiQ69gLWSLpgB5/6sU+r6BlQR0MBILadqTQ==", + "peer": true }, "node_modules/lodash.merge": { "version": "4.6.2", @@ -4759,12 +4751,14 @@ "node_modules/lodash.uniq": { "version": "4.5.0", "resolved": "https://registry.npmjs.org/lodash.uniq/-/lodash.uniq-4.5.0.tgz", - "integrity": "sha512-xfBaXQd9ryd9dlSDvnvI0lvxfLJlYAZzXomUYzLKtUeOQvOP5piqAWuGtrhWeqaXK9hhoM/iyJc5AV+XfsX3HQ==" + "integrity": "sha512-xfBaXQd9ryd9dlSDvnvI0lvxfLJlYAZzXomUYzLKtUeOQvOP5piqAWuGtrhWeqaXK9hhoM/iyJc5AV+XfsX3HQ==", + "peer": true }, "node_modules/lodash.zipobject": { "version": "4.1.3", "resolved": "https://registry.npmjs.org/lodash.zipobject/-/lodash.zipobject-4.1.3.tgz", - "integrity": "sha512-A9SzX4hMKWS25MyalwcOnNoplyHbkNVsjidhTp8ru0Sj23wY9GWBKS8gAIGDSAqeWjIjvE4KBEl24XXAs+v4wQ==" + "integrity": "sha512-A9SzX4hMKWS25MyalwcOnNoplyHbkNVsjidhTp8ru0Sj23wY9GWBKS8gAIGDSAqeWjIjvE4KBEl24XXAs+v4wQ==", + "peer": true }, "node_modules/log-symbols": { "version": "4.1.0", @@ -4836,23 +4830,11 @@ "integrity": "sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw==", "dev": true }, - "node_modules/maxmind": { - "version": "4.3.16", - "resolved": "https://registry.npmjs.org/maxmind/-/maxmind-4.3.16.tgz", - "integrity": "sha512-bfmiULzt9vO3tZ0SvQOX6cMZMqPCWtncbtNUefeSspoScf8S7n6qB66uOFQN00IWaJUr9oLjtlx3d6M8/KatuQ==", - "dependencies": { - "mmdb-lib": "2.0.2", - "tiny-lru": "11.2.3" - }, - "engines": { - "node": ">=12", - "npm": ">=6" - } - }, "node_modules/media-typer": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-1.1.0.tgz", "integrity": "sha512-aisnrDP4GNe06UcKFnV5bfMNPBUw4jsLGaWwWfnH3v02GnBuXX2MCVn5RbrWo0j3pczUilYblq7fQ7Nw2t5XKw==", + "peer": true, "engines": { "node": ">= 0.8" } @@ -5161,6 +5143,7 @@ "version": "1.4.5-lts.1", "resolved": "https://registry.npmjs.org/multer/-/multer-1.4.5-lts.1.tgz", "integrity": "sha512-ywPWvcDMeH+z9gQq5qYHCCy+ethsk4goepZ45GLD63fOu0YcNecQxi64nDs3qluZB+murG3/D4dJ7+dGctcCQQ==", + "peer": true, "dependencies": { "append-field": "^1.0.0", "busboy": "^1.0.0", @@ -5178,6 +5161,7 @@ "version": "0.5.6", "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.6.tgz", "integrity": "sha512-FP+p8RB8OWpF3YZBCrP5gtADmtXApB5AMLn+vdyA+PyxCjrCs00mjyUozssO33cwDeT3wNGdLxJ5M//YqtHAJw==", + "peer": true, "dependencies": { "minimist": "^1.2.6" }, @@ -5505,6 +5489,7 @@ "version": "7.1.3", "resolved": "https://registry.npmjs.org/ono/-/ono-7.1.3.tgz", "integrity": "sha512-9jnfVriq7uJM4o5ganUY54ntUm+5EK21EGaQ5NWnkWg3zz5ywbbonlBguRcnmF1/HDiIe3zxNxXcO1YPBmPcQQ==", + "peer": true, "dependencies": { "@jsdevtools/ono": "7.1.3" } @@ -5809,6 +5794,7 @@ "version": "2.3.0", "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.0.tgz", "integrity": "sha512-rRV+zQD8tVFys26lAGR9WUuS4iUAngJScM+ZRSKtvl5tKeZ2t5bvdNFdNHBW9FWR4guGHlgmsZ1G7BSm2wTbuA==", + "peer": true, "engines": { "node": ">=6" } @@ -5846,19 +5832,6 @@ } ] }, - "node_modules/quibble": { - "version": "0.9.0", - "resolved": "https://registry.npmjs.org/quibble/-/quibble-0.9.0.tgz", - "integrity": "sha512-gpBmqaEPl0nNZuDq16sLO7g/aYcrldSIls8igHm5EYP02+Kzmn/DCNpcSGywnhTk6aNJXkUv6vrRDvrJyRJ2Xw==", - "dev": true, - "dependencies": { - "lodash": "^4.17.21", - "resolve": "^1.22.4" - }, - "engines": { - "node": ">= 0.14.0" - } - }, "node_modules/rambda": { "version": "7.5.0", "resolved": "https://registry.npmjs.org/rambda/-/rambda-7.5.0.tgz", @@ -5957,6 +5930,7 @@ "version": "2.0.2", "resolved": "https://registry.npmjs.org/require-from-string/-/require-from-string-2.0.2.tgz", "integrity": "sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==", + "peer": true, "engines": { "node": ">=0.10.0" } @@ -6500,6 +6474,7 @@ "version": "1.1.0", "resolved": "https://registry.npmjs.org/streamsearch/-/streamsearch-1.1.0.tgz", "integrity": "sha512-Mcc5wHehp9aXz1ax6bZUyY5afg9u2rv5cqQI3mRrYkGC8rW2hM02jWuwjtL++LS5qinSyhj2QfLyNsuc+VsExg==", + "peer": true, "engines": { "node": ">=10.0.0" } @@ -6598,19 +6573,6 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/stringify-object-es5": { - "version": "2.5.0", - "resolved": "https://registry.npmjs.org/stringify-object-es5/-/stringify-object-es5-2.5.0.tgz", - "integrity": "sha512-vE7Xdx9ylG4JI16zy7/ObKUB+MtxuMcWlj/WHHr3+yAlQoN6sst2stU9E+2Qs3OrlJw/Pf3loWxL1GauEHf6MA==", - "dev": true, - "dependencies": { - "is-plain-obj": "^1.0.0", - "is-regexp": "^1.0.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/strip-ansi": { "version": "6.0.1", "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", @@ -6780,33 +6742,12 @@ "node": ">=8" } }, - "node_modules/testdouble": { - "version": "3.20.0", - "resolved": "https://registry.npmjs.org/testdouble/-/testdouble-3.20.0.tgz", - "integrity": "sha512-P/wfyKF1P1AE8/VM6PXCtSQJyOgPObOg191TlVZnoSQw/hhFXvxIFM5yGJ7Bf9Hs0FX8677YCv3esVgPGSeTLg==", - "dev": true, - "dependencies": { - "lodash": "^4.17.21", - "quibble": "^0.9.0", - "stringify-object-es5": "^2.5.0", - "theredoc": "^1.0.0" - }, - "engines": { - "node": ">= 16" - } - }, "node_modules/text-table": { "version": "0.2.0", "resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz", "integrity": "sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw==", "dev": true }, - "node_modules/theredoc": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/theredoc/-/theredoc-1.0.0.tgz", - "integrity": "sha512-KU3SA3TjRRM932jpNfD3u4Ec3bSvedyo5ITPI7zgWYnKep7BwQQaxlhI9qbO+lKJoRnoAbEVfMcAHRuKVYikDA==", - "dev": true - }, "node_modules/thriftrw": { "version": "3.11.4", "resolved": "https://registry.npmjs.org/thriftrw/-/thriftrw-3.11.4.tgz", @@ -6841,14 +6782,6 @@ "xtend": "~4.0.1" } }, - "node_modules/tiny-lru": { - "version": "11.2.3", - "resolved": "https://registry.npmjs.org/tiny-lru/-/tiny-lru-11.2.3.tgz", - "integrity": "sha512-mF9jPTrvN7UHk0bekOk3RlFdFwfyS4CJYVsGc7nInL3pVgUCYj5r9X6GpZBFQgLr0TKJo8Dp+F3oRvYzxU9xiA==", - "engines": { - "node": ">=12" - } - }, "node_modules/titleize": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/titleize/-/titleize-3.0.0.tgz", @@ -7111,7 +7044,8 @@ "node_modules/typedarray": { "version": "0.0.6", "resolved": "https://registry.npmjs.org/typedarray/-/typedarray-0.0.6.tgz", - "integrity": "sha512-/aCDEGatGvZ2BIk+HmLf4ifCJFwvKFNb9/JeZPMulfgFracn9QFcAf5GO8B/mweUjSoblS5In0cWhqpfs/5PQA==" + "integrity": "sha512-/aCDEGatGvZ2BIk+HmLf4ifCJFwvKFNb9/JeZPMulfgFracn9QFcAf5GO8B/mweUjSoblS5In0cWhqpfs/5PQA==", + "peer": true }, "node_modules/typescript": { "version": "5.2.2", @@ -7149,9 +7083,9 @@ "dev": true }, "node_modules/undici": { - "version": "5.26.4", - "resolved": "https://registry.npmjs.org/undici/-/undici-5.26.4.tgz", - "integrity": "sha512-OG+QOf0fTLtazL9P9X7yqWxQ+Z0395Wk6DSkyTxtaq3wQEjIroVe7Y4asCX/vcCxYpNGMnwz8F0qbRYUoaQVMw==", + "version": "5.27.0", + "resolved": "https://registry.npmjs.org/undici/-/undici-5.27.0.tgz", + "integrity": "sha512-l3ydWhlhOJzMVOYkymLykcRRXqbUaQriERtR70B9LzNkZ4bX52Fc8wbTDneMiwo8T+AemZXvXaTx+9o5ROxrXg==", "dev": true, "dependencies": { "@fastify/busboy": "^2.0.0" @@ -7186,6 +7120,7 @@ "version": "4.4.1", "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz", "integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==", + "peer": true, "dependencies": { "punycode": "^2.1.0" } @@ -7413,15 +7348,6 @@ "node": ">=10" } }, - "node_modules/yargs-unparser/node_modules/is-plain-obj": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-2.1.0.tgz", - "integrity": "sha512-YWnfyRwxL/+SsrWYfOpUtz5b3YD+nyfkHvjbcanzk8zgyO4ASD67uVMRt8k5bM4lLMDnXfriRhOpemw+NfT1eA==", - "dev": true, - "engines": { - "node": ">=8" - } - }, "node_modules/yn": { "version": "3.1.1", "resolved": "https://registry.npmjs.org/yn/-/yn-3.1.1.tgz", diff --git a/package.json b/package.json index 6fcb8633..e38eb325 100644 --- a/package.json +++ b/package.json @@ -24,16 +24,15 @@ "@myrotvorets/express-microservice-middlewares": "^2.2.0", "@myrotvorets/express-request-logger": "^1.2.0", "@myrotvorets/oav-installer": "^5.0.0", - "@myrotvorets/opentelemetry-configurator": "^7.0.0", - "@myrotvorets/otel-utils": "^0.0.10", + "@myrotvorets/opentelemetry-configurator": "^7.1.0", + "@myrotvorets/otel-utils": "^1.0.0", "@opentelemetry/api": "^1.6.0", "@opentelemetry/core": "^1.17.1", "@opentelemetry/semantic-conventions": "^1.17.1", "awilix": "^9.0.0", "envalid": "^8.0.0", "express": "^4.18.2", - "express-openapi-validator": "^5.0.6", - "maxmind": "^4.3.16" + "mmdb-lib": "^2.0.2" }, "devDependencies": { "@myrotvorets/eslint-config-myrotvorets-ts": "^2.22.5", @@ -58,7 +57,6 @@ "nodemon": "^3.0.1", "rimraf": "^5.0.5", "supertest": "^6.3.3", - "testdouble": "^3.20.0", "ts-node": "^10.9.1", "typescript": "^5.2.2" }, diff --git a/src/lib/container.mts b/src/lib/container.mts index ed9139ac..35f053ae 100644 --- a/src/lib/container.mts +++ b/src/lib/container.mts @@ -1,15 +1,20 @@ -import { AwilixContainer, asFunction, asValue, createContainer } from 'awilix'; +import { readFileSync } from 'node:fs'; +import { AwilixContainer, asClass, asFunction, asValue, createContainer } from 'awilix'; import type { NextFunction, Request, Response } from 'express'; import { type Logger, type Tracer, getLogger, getTracer } from '@myrotvorets/otel-utils'; import { environment } from './environment.mjs'; +import type { GeoIPServiceInterface } from '../services/geoipserviceinterface.mjs'; +import type { CityResponse, IspResponse, MMDBReaderServiceInterface } from '../services/mmdbreaderserviceinterface.mjs'; import { MeteredGeoIPService } from '../services/meteredgeoipservice.mjs'; -import { GeoIPServiceInterface } from '../services/geoipserviceinterface.mjs'; +import { MMDBReaderService } from '../services/mmdbreaderservice.mjs'; export interface Container { geoIPService: GeoIPServiceInterface; environment: ReturnType; tracer: Tracer; logger: Logger; + cityReader: MMDBReaderServiceInterface; + ispReader: MMDBReaderServiceInterface; } export interface RequestContainer { @@ -39,21 +44,30 @@ function createTracer(): Tracer { return getTracer(); } -function createGeoIPService({ environment, tracer }: Container): GeoIPServiceInterface { - const service = new MeteredGeoIPService({ tracer }); - service.setCityDatabase(environment.GEOIP_CITY_FILE); - service.setISPDatabase(environment.GEOIP_ISP_FILE); - return service; +function createCityReader({ environment }: Container): MMDBReaderServiceInterface { + const reader = new MMDBReaderService(); + const buf = readFileSync(environment.GEOIP_CITY_FILE); + reader.load(buf); + return reader; +} + +function createIspReader({ environment }: Container): MMDBReaderServiceInterface { + const reader = new MMDBReaderService(); + const buf = readFileSync(environment.GEOIP_ISP_FILE); + reader.load(buf); + return reader; } export type LocalsWithContainer = Record<'container', AwilixContainer>; export function initializeContainer(): typeof container { container.register({ - geoIPService: asFunction(createGeoIPService).singleton(), + geoIPService: asClass(MeteredGeoIPService).singleton(), environment: asFunction(createEnvironment).singleton(), logger: asFunction(createLogger).scoped(), tracer: asFunction(createTracer).singleton(), + cityReader: asFunction(createCityReader).singleton(), + ispReader: asFunction(createIspReader).singleton(), }); return container; diff --git a/src/server.mts b/src/server.mts index f8d5ff66..51ce2425 100644 --- a/src/server.mts +++ b/src/server.mts @@ -52,10 +52,7 @@ export function createApp(): Express { /* c8 ignore start */ export async function run(): Promise { const app = createApp(); - const container = configureApp(app); - const env = container.resolve('environment'); - - const server = await createServer(app); - server.listen(env.PORT); + configureApp(app); + await createServer(app); } /* c8 ignore stop */ diff --git a/src/services/geoipservice.mts b/src/services/geoipservice.mts index 3b7b726e..32c87179 100644 --- a/src/services/geoipservice.mts +++ b/src/services/geoipservice.mts @@ -1,32 +1,18 @@ -import { readFileSync } from 'node:fs'; -import { type CityResponse, type IspResponse, Reader, type Response } from 'maxmind'; import type { GeoCityResponse, GeoIPServiceInterface, GeoIspResponse, GeoResponse } from './geoipserviceinterface.mjs'; +import type { CityResponse, IspResponse, MMDBReaderServiceInterface } from './mmdbreaderserviceinterface.mjs'; -export class GeoIPService implements GeoIPServiceInterface { - protected _city: Reader | undefined; - protected _isp: Reader | undefined; - - public setCityDatabase(file: string): boolean { - this._city = GeoIPService.readDatabaseSync(file); - return this._city !== undefined; - } - - public setISPDatabase(file: string): boolean { - this._isp = GeoIPService.readDatabaseSync(file); - return this._isp !== undefined; - } +export interface GeoIPServiceOptions { + cityReader: MMDBReaderServiceInterface; + ispReader: MMDBReaderServiceInterface; +} - private static readDatabaseSync(file: string): Reader | undefined { - if (file) { - try { - const buf = readFileSync(file); - return new Reader(buf); - } catch { - /* Do nothing */ - } - } +export class GeoIPService implements GeoIPServiceInterface { + protected _city: MMDBReaderServiceInterface; + protected _isp: MMDBReaderServiceInterface; - return undefined; + public constructor({ cityReader, ispReader }: GeoIPServiceOptions) { + this._city = cityReader; + this._isp = ispReader; } public geolocate(ip: string): GeoResponse { @@ -42,11 +28,11 @@ export class GeoIPService implements GeoIPServiceInterface { } protected geolocateCity(ip: string): [CityResponse | null, number] { - return this._city?.getWithPrefixLength(ip) ?? [null, 0]; + return this._city.getWithPrefixLength(ip); } protected geolocateISP(ip: string): [IspResponse | null, number] { - return this._isp?.getWithPrefixLength(ip) ?? [null, 0]; + return this._isp.getWithPrefixLength(ip); } protected adaptCityResponse(response: CityResponse | null): GeoCityResponse { diff --git a/src/services/geoipserviceinterface.mts b/src/services/geoipserviceinterface.mts index 344ddca7..8c983b2b 100644 --- a/src/services/geoipserviceinterface.mts +++ b/src/services/geoipserviceinterface.mts @@ -20,7 +20,5 @@ export interface GeoPrefixes { export type GeoResponse = GeoCityResponse & GeoIspResponse & GeoPrefixes; export interface GeoIPServiceInterface { - setCityDatabase(file: string): boolean; - setISPDatabase(file: string): boolean; geolocate(ip: string): GeoResponse; } diff --git a/src/services/meteredgeoipservice.mts b/src/services/meteredgeoipservice.mts index 388e5f85..7784eb36 100644 --- a/src/services/meteredgeoipservice.mts +++ b/src/services/meteredgeoipservice.mts @@ -1,20 +1,20 @@ -import type { CityResponse, IspResponse } from 'maxmind'; import { type Tracer, recordErrorToSpan } from '@myrotvorets/otel-utils'; import { trace } from '@opentelemetry/api'; import { cityLookupHistogram, countryCounter, ispLookupHistogram } from '../lib/metrics.mjs'; import { observe } from '../lib/utils.mjs'; -import { GeoIPService } from './geoipservice.mjs'; +import { GeoIPService, type GeoIPServiceOptions } from './geoipservice.mjs'; import type { GeoCityResponse, GeoIspResponse, GeoResponse } from './geoipserviceinterface.mjs'; -interface MeteredGeoIPServiceOptions { +interface MeteredGeoIPServiceOptions extends GeoIPServiceOptions { tracer: Tracer; } + export class MeteredGeoIPService extends GeoIPService { private readonly _tracer: Tracer; - public constructor({ tracer }: MeteredGeoIPServiceOptions) { - super(); - this._tracer = tracer; + public constructor(opts: MeteredGeoIPServiceOptions) { + super(opts); + this._tracer = opts.tracer; } public override geolocate(ip: string): GeoResponse { @@ -29,34 +29,32 @@ export class MeteredGeoIPService extends GeoIPService { }); } - protected override geolocateCity(ip: string): [CityResponse | null, number] { - let city: CityResponse | null = null; - let prefix = 0; + protected override geolocateCity(ip: string): ReturnType { + let result: ReturnType = [null, 0]; cityLookupHistogram.record( observe(() => { - [city, prefix] = super.geolocateCity(ip); + result = super.geolocateCity(ip); }), ); - return [city, prefix]; + return result; } - protected override geolocateISP(ip: string): [IspResponse | null, number] { - let isp: IspResponse | null = null; - let prefix = 0; + protected override geolocateISP(ip: string): ReturnType { + let result: ReturnType = [null, 0]; ispLookupHistogram.record( observe(() => { - [isp, prefix] = super.geolocateISP(ip); + result = super.geolocateISP(ip); }), ); - return [isp, prefix]; + return result; } - protected override adaptCityResponse(response: CityResponse | null): GeoCityResponse { - const result = super.adaptCityResponse(response); + protected override adaptCityResponse(...params: Parameters): GeoCityResponse { + const result = super.adaptCityResponse(...params); trace .getActiveSpan() /* c8 ignore next */ @@ -66,8 +64,8 @@ export class MeteredGeoIPService extends GeoIPService { return result; } - protected override adaptIspResponse(response: IspResponse | null): GeoIspResponse { - const result = super.adaptIspResponse(response); + protected override adaptIspResponse(...params: Parameters): GeoIspResponse { + const result = super.adaptIspResponse(...params); trace .getActiveSpan() /* c8 ignore start */ diff --git a/src/services/mmdbreaderservice.mts b/src/services/mmdbreaderservice.mts new file mode 100644 index 00000000..8f4c8241 --- /dev/null +++ b/src/services/mmdbreaderservice.mts @@ -0,0 +1,14 @@ +import { Reader } from 'mmdb-lib'; +import { MMDBReaderServiceInterface, Response } from './mmdbreaderserviceinterface.mjs'; + +export class MMDBReaderService implements MMDBReaderServiceInterface { + #reader: Reader | null = null; + + public load(db: Buffer): void { + this.#reader = new Reader(db); + } + + public getWithPrefixLength(ip: string): [T | null, number] { + return this.#reader?.getWithPrefixLength(ip) ?? [null, 0]; + } +} diff --git a/src/services/mmdbreaderserviceinterface.mts b/src/services/mmdbreaderserviceinterface.mts new file mode 100644 index 00000000..1e7f3a91 --- /dev/null +++ b/src/services/mmdbreaderserviceinterface.mts @@ -0,0 +1,8 @@ +import type { Response } from 'mmdb-lib'; + +export type { Response, CityResponse, IspResponse } from 'mmdb-lib'; + +export interface MMDBReaderServiceInterface { + load(db: Buffer): void; + getWithPrefixLength(ipAddress: string): [T | null, number]; +} diff --git a/test/functional/controller/geoip.test.mts b/test/functional/controller/geoip.test.mts index e77a175c..a157598b 100644 --- a/test/functional/controller/geoip.test.mts +++ b/test/functional/controller/geoip.test.mts @@ -11,7 +11,7 @@ describe('GeoIPController', function () { before(async function () { await container.dispose(); app = createApp(); - return configureApp(app); + configureApp(app); }); describe('Error handling', function () { diff --git a/test/unit/lib/container.test.mts b/test/unit/lib/container.test.mts index e4e2aede..bba14ea7 100644 --- a/test/unit/lib/container.test.mts +++ b/test/unit/lib/container.test.mts @@ -22,6 +22,9 @@ describe('Container', function () { .to.be.an('object') .that.has.property('startActiveSpan') .that.is.a('function'); + + expect(container.resolve('cityReader')).to.be.an('object').that.has.property('load').that.is.a('function'); + expect(container.resolve('ispReader')).to.be.an('object').that.has.property('load').that.is.a('function'); }); }); }); diff --git a/test/unit/services/fakemmdbreader.mts b/test/unit/services/fakemmdbreader.mts new file mode 100644 index 00000000..00f40eed --- /dev/null +++ b/test/unit/services/fakemmdbreader.mts @@ -0,0 +1,12 @@ +import { Mock, mock } from 'node:test'; +import type { MMDBReaderServiceInterface, Response } from '../../../src/services/mmdbreaderserviceinterface.mjs'; + +export class FakeMMDBReader implements MMDBReaderServiceInterface { + public load(_db: Buffer): void { + // Do nothing. + } + + public getWithPrefixLength: Mock['getWithPrefixLength']> = mock.fn< + MMDBReaderServiceInterface['getWithPrefixLength'] + >(() => [null, 0]); +} diff --git a/test/unit/services/geoipservice.test.mts b/test/unit/services/geoipservice.test.mts index e8dbc688..0a5881dd 100644 --- a/test/unit/services/geoipservice.test.mts +++ b/test/unit/services/geoipservice.test.mts @@ -1,7 +1,7 @@ -import { type TestDouble, func, matchers, replaceEsm, when } from 'testdouble'; import { expect } from 'chai'; -import type { Reader } from 'maxmind'; -import type { GeoIPService } from '../../services/geoipservice.mjs'; +import { mock } from 'node:test'; +import { GeoIPService } from '../../../src/services/geoipservice.mjs'; +import type { CityResponse, IspResponse } from '../../../src/services/mmdbreaderserviceinterface.mjs'; import { cityResponseWithCountry, cityResponseWithRegisteredCountry, @@ -11,78 +11,32 @@ import { geoResponseWithRegisteredCountry, geoResponseWithRepresentedCountry, } from './helpers.mjs'; +import { FakeMMDBReader } from './fakemmdbreader.mjs'; describe('GeoIPService', function () { - let geoip: typeof import('../../services/geoipservice.mjs'); let service: GeoIPService; - let readFileSyncMock: TestDouble; - let constructorMock: TestDouble<(...args: unknown[]) => unknown>; - let getWithPrefixLengthMock: TestDouble; + let cityReader: FakeMMDBReader; + let ispReader: FakeMMDBReader; before(function () { - readFileSyncMock = func(); - constructorMock = func<(...args: unknown[]) => unknown>(); - getWithPrefixLengthMock = func(); + cityReader = new FakeMMDBReader(); + ispReader = new FakeMMDBReader(); + service = new GeoIPService({ cityReader, ispReader }); }); - beforeEach(async function () { - const fs = await import('node:fs'); - await replaceEsm('node:fs', { - ...fs, - readFileSync: readFileSyncMock, - }); - - await replaceEsm('maxmind', { - Reader: class Reader { - public constructor(...args: unknown[]) { - constructorMock(...args); - } - public getWithPrefixLength = getWithPrefixLengthMock; - }, - }); - - when(readFileSyncMock(matchers.isA(String) as string)).thenReturn(Buffer.from('')); - - geoip = await import('../../../src/services/geoipservice.mjs'); - service = new geoip.GeoIPService(); + afterEach(function () { + mock.reset(); }); - describe('setCityDatabase()', function () { - it('should not reject on maxmind failures', function () { - when(constructorMock(matchers.isA(Buffer))).thenThrow(new Error()); - return expect(service.setCityDatabase('blah')).to.be.false; - }); - - it('should accept empty values', function () { - return expect(service.setCityDatabase('')).to.be.false; - }); - }); - - describe('setISPDatabase()', function () { - it('should not reject on maxmind failures', function () { - when(constructorMock(matchers.isA(Buffer))).thenThrow(new Error()); - return expect(service.setISPDatabase('blah')).to.be.false; - }); - - it('should accept empty values', function () { - return expect(service.setISPDatabase('')).to.be.false; - }); - }); - - describe('geolocate()', function () { - beforeEach(function () { - service.setCityDatabase('blah'); - service.setISPDatabase('blah'); - }); - + describe('#geolocate()', function () { it('should handle null responses', function () { - when(getWithPrefixLengthMock(matchers.isA(String) as string)).thenReturn([null, 0]); const actual = service.geolocate('1.2.3.4'); expect(actual).to.deep.equal(emptyGeoResponse); }); it('should handle empty responses', function () { - when(getWithPrefixLengthMock(matchers.isA(String) as string)).thenReturn([{}, 0]); + cityReader.getWithPrefixLength.mock.mockImplementationOnce(() => [{}, 0]); + ispReader.getWithPrefixLength.mock.mockImplementationOnce(() => [{}, 0]); const actual = service.geolocate('1.2.3.4'); expect(actual).to.deep.equal(emptyGeoResponse); }); @@ -94,17 +48,10 @@ describe('GeoIPService', function () { [cityResponseWithCountry, geoResponseWithCountry], ].forEach(([mock, expected]) => { it('should try records in the defined order', function () { - when(getWithPrefixLengthMock(matchers.isA(String) as string)).thenReturn([mock, 32], [null, 0]); + cityReader.getWithPrefixLength.mock.mockImplementationOnce(() => [mock, 32]); const actual = service.geolocate('1.2.3.4'); expect(actual).to.deep.equal(expected); }); }); - - it('should return empty results with no databases', function () { - return Promise.all([service.setCityDatabase(''), service.setISPDatabase('')]).then(() => { - const actual = service.geolocate('1.2.3.4'); - expect(actual).to.deep.equal(emptyGeoResponse); - }); - }); }); }); diff --git a/test/unit/services/helpers.mts b/test/unit/services/helpers.mts index 9f10c586..3c24fbe1 100644 --- a/test/unit/services/helpers.mts +++ b/test/unit/services/helpers.mts @@ -1,4 +1,4 @@ -import type { CityResponse } from 'maxmind'; +import type { CityResponse } from '../../../src/services/mmdbreaderserviceinterface.mjs'; import type { GeoResponse } from '../../../src/services/geoipserviceinterface.mjs'; export const emptyGeoResponse: GeoResponse = { diff --git a/test/unit/services/mmdbreaderservice.test.mts b/test/unit/services/mmdbreaderservice.test.mts new file mode 100644 index 00000000..4d1024de --- /dev/null +++ b/test/unit/services/mmdbreaderservice.test.mts @@ -0,0 +1,15 @@ +import { expect } from 'chai'; +import { MMDBReaderService } from '../../../src/services/mmdbreaderservice.mjs'; + +describe('MMDBReaderService', function () { + describe('#geolocate()', function () { + it('should work even without a database', function () { + const reader = new MMDBReaderService(); + + const expected = [null, 0]; + const actual = reader.getWithPrefixLength('0.0.0.0'); + + expect(actual).to.deep.equal(expected); + }); + }); +});