From c87eb5144d0c06bdc9344c851109efebdaeaacf2 Mon Sep 17 00:00:00 2001 From: Leonardo Venturini Date: Thu, 3 Aug 2023 13:43:29 -0400 Subject: [PATCH 01/37] add webstorm stuff --- .gitignore | 59 ++++++++++++++++++++++++++++++++++++++++++++ .idea/.gitignore | 5 ++++ .idea/modules.xml | 8 ++++++ .idea/node-agent.iml | 12 +++++++++ .idea/vcs.xml | 6 +++++ 5 files changed, 90 insertions(+) create mode 100644 .gitignore create mode 100644 .idea/.gitignore create mode 100644 .idea/modules.xml create mode 100644 .idea/node-agent.iml create mode 100644 .idea/vcs.xml diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..5d036a6 --- /dev/null +++ b/.gitignore @@ -0,0 +1,59 @@ +logs +*.log +npm-debug.log* +yarn-debug.log* +yarn-error.log* +lerna-debug.log* +.pnpm-debug.log* +report.[0-9]*.[0-9]*.[0-9]*.[0-9]*.json +pids +*.pid +*.seed +*.pid.lock +lib-cov +coverage +*.lcov +.nyc_output +.grunt +bower_components +.lock-wscript +build/Release +node_modules/ +jspm_packages/ +web_modules/ +*.tsbuildinfo +.npm +.eslintcache +.stylelintcache +.rpt2_cache/ +.rts2_cache_cjs/ +.rts2_cache_es/ +.rts2_cache_umd/ +.node_repl_history +*.tgz +.yarn-integrity +.env +.env.development.local +.env.test.local +.env.production.local +.env.local +.cache +.parcel-cache +.next +out +.nuxt +dist +.cache/ +.vuepress/dist +.temp +.docusaurus +.serverless/ +.fusebox/ +.dynamodb/ +.tern-port +.vscode-test +.yarn/cache +.yarn/unplugged +.yarn/build-state.yml +.yarn/install-state.gz +.pnp.* diff --git a/.idea/.gitignore b/.idea/.gitignore new file mode 100644 index 0000000..b58b603 --- /dev/null +++ b/.idea/.gitignore @@ -0,0 +1,5 @@ +# Default ignored files +/shelf/ +/workspace.xml +# Editor-based HTTP Client requests +/httpRequests/ diff --git a/.idea/modules.xml b/.idea/modules.xml new file mode 100644 index 0000000..8fb44bc --- /dev/null +++ b/.idea/modules.xml @@ -0,0 +1,8 @@ + + + + + + + + \ No newline at end of file diff --git a/.idea/node-agent.iml b/.idea/node-agent.iml new file mode 100644 index 0000000..24643cc --- /dev/null +++ b/.idea/node-agent.iml @@ -0,0 +1,12 @@ + + + + + + + + + + + + \ No newline at end of file diff --git a/.idea/vcs.xml b/.idea/vcs.xml new file mode 100644 index 0000000..35eb1dd --- /dev/null +++ b/.idea/vcs.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file From 5de1855b320f1599d28034d3add17e029adb9b3d Mon Sep 17 00:00:00 2001 From: Leonardo Venturini Date: Fri, 4 Aug 2023 11:12:56 -0400 Subject: [PATCH 02/37] add poc diagram --- diagrams/BOOTSTRAP.mmd | 9 +++++++++ 1 file changed, 9 insertions(+) create mode 100644 diagrams/BOOTSTRAP.mmd diff --git a/diagrams/BOOTSTRAP.mmd b/diagrams/BOOTSTRAP.mmd new file mode 100644 index 0000000..65d4d7f --- /dev/null +++ b/diagrams/BOOTSTRAP.mmd @@ -0,0 +1,9 @@ +--- +title: Bootstrap +--- +graph + A[Kadira._startInstrumenting] -- attempt to connect with env first --> B[Kadira._connectWithEnv] + A -- with settings afterwards --> C[Kadira._connectWithSettings] + + B --> D[Kadira.connect] + C -- after each the `connect` method is overridden so it throws whenever it is called again --> D \ No newline at end of file From a3e56e0df186658acfd58637705746de0836ef01 Mon Sep 17 00:00:00 2001 From: Leonardo Venturini Date: Fri, 4 Aug 2023 11:13:30 -0400 Subject: [PATCH 03/37] setup npm project --- package-lock.json | 3938 +++++++++++++++++++++++++++++++++++++++++++++ package.json | 65 + tsconfig.json | 38 + 3 files changed, 4041 insertions(+) create mode 100644 package-lock.json create mode 100644 package.json create mode 100644 tsconfig.json diff --git a/package-lock.json b/package-lock.json new file mode 100644 index 0000000..dbf3cde --- /dev/null +++ b/package-lock.json @@ -0,0 +1,3938 @@ +{ + "name": "@monti-apm/agent", + "version": "0.0.1", + "lockfileVersion": 3, + "requires": true, + "packages": { + "": { + "name": "@monti-apm/agent", + "version": "0.0.1", + "license": "MIT", + "dependencies": { + "axios": "1.4.0", + "eventemitter2": "6.4.9", + "remeda": "1.24.0", + "uuid": "9.0.0" + }, + "devDependencies": { + "@swc/cli": "^0.1.62", + "@swc/core": "^1.3.71", + "@swc/register": "^0.1.10", + "@types/backoff": "^2.5.2", + "@types/chai": "^4.3.4", + "@types/debug": "^4.1.8", + "@types/mocha": "^10.0.1", + "@types/uuid": "^9.0.2", + "@types/websocket": "^1.0.5", + "@typescript-eslint/eslint-plugin": "5.62.0", + "@typescript-eslint/parser": "5.62.0", + "chai": "4.3.7", + "eslint": "8.45.0", + "eslint-config-prettier": "8.8.0", + "eslint-plugin-prettier": "4.2.1", + "mocha": "10.2.0", + "nodemon": "2.0.21", + "prettier": "2.8.8", + "rimraf": "4.4.1", + "typescript": "4.9.5" + } + }, + "node_modules/@aashutoshrathi/word-wrap": { + "version": "1.2.6", + "resolved": "https://registry.npmjs.org/@aashutoshrathi/word-wrap/-/word-wrap-1.2.6.tgz", + "integrity": "sha512-1Yjs2SvM8TflER/OD3cOjhWWOZb58A2t7wpE2S9XfBYTiIl+XFhQG2bjy4Pu1I+EAlCNUzRDYDdFwFYUKvXcIA==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/@eslint-community/eslint-utils": { + "version": "4.4.0", + "resolved": "https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.4.0.tgz", + "integrity": "sha512-1/sA4dwrzBAyeUoQ6oxahHKmrZvsnLCg4RfxW3ZFGGmQkSNQPFNLV9CUEFQP1x9EYXHTo5p6xdhZM1Ne9p/AfA==", + "dev": true, + "dependencies": { + "eslint-visitor-keys": "^3.3.0" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "peerDependencies": { + "eslint": "^6.0.0 || ^7.0.0 || >=8.0.0" + } + }, + "node_modules/@eslint-community/regexpp": { + "version": "4.6.2", + "resolved": "https://registry.npmjs.org/@eslint-community/regexpp/-/regexpp-4.6.2.tgz", + "integrity": "sha512-pPTNuaAG3QMH+buKyBIGJs3g/S5y0caxw0ygM3YyE6yJFySwiGGSzA+mM3KJ8QQvzeLh3blwgSonkFjgQdxzMw==", + "dev": true, + "engines": { + "node": "^12.0.0 || ^14.0.0 || >=16.0.0" + } + }, + "node_modules/@eslint/eslintrc": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-2.1.1.tgz", + "integrity": "sha512-9t7ZA7NGGK8ckelF0PQCfcxIUzs1Md5rrO6U/c+FIQNanea5UZC0wqKXH4vHBccmu4ZJgZ2idtPeW7+Q2npOEA==", + "dev": true, + "dependencies": { + "ajv": "^6.12.4", + "debug": "^4.3.2", + "espree": "^9.6.0", + "globals": "^13.19.0", + "ignore": "^5.2.0", + "import-fresh": "^3.2.1", + "js-yaml": "^4.1.0", + "minimatch": "^3.1.2", + "strip-json-comments": "^3.1.1" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/@eslint/js": { + "version": "8.44.0", + "resolved": "https://registry.npmjs.org/@eslint/js/-/js-8.44.0.tgz", + "integrity": "sha512-Ag+9YM4ocKQx9AarydN0KY2j0ErMHNIocPDrVo8zAE44xLTjEtz81OdR68/cydGtk6m6jDb5Za3r2useMzYmSw==", + "dev": true, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + } + }, + "node_modules/@humanwhocodes/config-array": { + "version": "0.11.10", + "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.11.10.tgz", + "integrity": "sha512-KVVjQmNUepDVGXNuoRRdmmEjruj0KfiGSbS8LVc12LMsWDQzRXJ0qdhN8L8uUigKpfEHRhlaQFY0ib1tnUbNeQ==", + "dev": true, + "dependencies": { + "@humanwhocodes/object-schema": "^1.2.1", + "debug": "^4.1.1", + "minimatch": "^3.0.5" + }, + "engines": { + "node": ">=10.10.0" + } + }, + "node_modules/@humanwhocodes/module-importer": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@humanwhocodes/module-importer/-/module-importer-1.0.1.tgz", + "integrity": "sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA==", + "dev": true, + "engines": { + "node": ">=12.22" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/nzakas" + } + }, + "node_modules/@humanwhocodes/object-schema": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/@humanwhocodes/object-schema/-/object-schema-1.2.1.tgz", + "integrity": "sha512-ZnQMnLV4e7hDlUvw8H+U8ASL02SS2Gn6+9Ac3wGGLIe7+je2AeAOxPY+izIPJDfFDb7eDjev0Us8MO1iFRN8hA==", + "dev": true + }, + "node_modules/@mole-inc/bin-wrapper": { + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/@mole-inc/bin-wrapper/-/bin-wrapper-8.0.1.tgz", + "integrity": "sha512-sTGoeZnjI8N4KS+sW2AN95gDBErhAguvkw/tWdCjeM8bvxpz5lqrnd0vOJABA1A+Ic3zED7PYoLP/RANLgVotA==", + "dev": true, + "dependencies": { + "bin-check": "^4.1.0", + "bin-version-check": "^5.0.0", + "content-disposition": "^0.5.4", + "ext-name": "^5.0.0", + "file-type": "^17.1.6", + "filenamify": "^5.0.2", + "got": "^11.8.5", + "os-filter-obj": "^2.0.0" + }, + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + } + }, + "node_modules/@nodelib/fs.scandir": { + "version": "2.1.5", + "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", + "integrity": "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==", + "dev": true, + "dependencies": { + "@nodelib/fs.stat": "2.0.5", + "run-parallel": "^1.1.9" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/@nodelib/fs.stat": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz", + "integrity": "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==", + "dev": true, + "engines": { + "node": ">= 8" + } + }, + "node_modules/@nodelib/fs.walk": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz", + "integrity": "sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==", + "dev": true, + "dependencies": { + "@nodelib/fs.scandir": "2.1.5", + "fastq": "^1.6.0" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/@sindresorhus/is": { + "version": "4.6.0", + "resolved": "https://registry.npmjs.org/@sindresorhus/is/-/is-4.6.0.tgz", + "integrity": "sha512-t09vSN3MdfsyCHoFcTRCH/iUtG7OJ0CsjzB8cjAmKc/va/kIgeDI/TxsigdncE/4be734m0cvIYwNaV4i2XqAw==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sindresorhus/is?sponsor=1" + } + }, + "node_modules/@swc/cli": { + "version": "0.1.62", + "resolved": "https://registry.npmjs.org/@swc/cli/-/cli-0.1.62.tgz", + "integrity": "sha512-kOFLjKY3XH1DWLfXL1/B5MizeNorHR8wHKEi92S/Zi9Md/AK17KSqR8MgyRJ6C1fhKHvbBCl8wboyKAFXStkYw==", + "dev": true, + "dependencies": { + "@mole-inc/bin-wrapper": "^8.0.1", + "commander": "^7.1.0", + "fast-glob": "^3.2.5", + "semver": "^7.3.8", + "slash": "3.0.0", + "source-map": "^0.7.3" + }, + "bin": { + "spack": "bin/spack.js", + "swc": "bin/swc.js", + "swcx": "bin/swcx.js" + }, + "engines": { + "node": ">= 12.13" + }, + "peerDependencies": { + "@swc/core": "^1.2.66", + "chokidar": "^3.5.1" + }, + "peerDependenciesMeta": { + "chokidar": { + "optional": true + } + } + }, + "node_modules/@swc/core": { + "version": "1.3.74", + "resolved": "https://registry.npmjs.org/@swc/core/-/core-1.3.74.tgz", + "integrity": "sha512-P+MIExOTdWlfq8Heb1/NhBAke6UTckd4cRDuJoFcFMGBRvgoCMNWhnfP3FRRXPLI7GGg27dRZS+xHiqYyQmSrA==", + "dev": true, + "hasInstallScript": true, + "engines": { + "node": ">=10" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/swc" + }, + "optionalDependencies": { + "@swc/core-darwin-arm64": "1.3.74", + "@swc/core-darwin-x64": "1.3.74", + "@swc/core-linux-arm-gnueabihf": "1.3.74", + "@swc/core-linux-arm64-gnu": "1.3.74", + "@swc/core-linux-arm64-musl": "1.3.74", + "@swc/core-linux-x64-gnu": "1.3.74", + "@swc/core-linux-x64-musl": "1.3.74", + "@swc/core-win32-arm64-msvc": "1.3.74", + "@swc/core-win32-ia32-msvc": "1.3.74", + "@swc/core-win32-x64-msvc": "1.3.74" + }, + "peerDependencies": { + "@swc/helpers": "^0.5.0" + }, + "peerDependenciesMeta": { + "@swc/helpers": { + "optional": true + } + } + }, + "node_modules/@swc/core-darwin-arm64": { + "version": "1.3.74", + "resolved": "https://registry.npmjs.org/@swc/core-darwin-arm64/-/core-darwin-arm64-1.3.74.tgz", + "integrity": "sha512-2rMV4QxM583jXcREfo0MhV3Oj5pgRSfSh/kVrB1twL2rQxOrbzkAPT/8flmygdVoL4f2F7o1EY5lKlYxEBiIKQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=10" + } + }, + "node_modules/@swc/core-darwin-x64": { + "version": "1.3.74", + "resolved": "https://registry.npmjs.org/@swc/core-darwin-x64/-/core-darwin-x64-1.3.74.tgz", + "integrity": "sha512-KKEGE1wXneYXe15fWDRM8/oekd/Q4yAuccA0vWY/7i6nOSPqWYcSDR0nRtR030ltDxWt0rk/eCTmNkrOWrKs3A==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=10" + } + }, + "node_modules/@swc/core-linux-arm-gnueabihf": { + "version": "1.3.74", + "resolved": "https://registry.npmjs.org/@swc/core-linux-arm-gnueabihf/-/core-linux-arm-gnueabihf-1.3.74.tgz", + "integrity": "sha512-HehH5DR6r/5fIVu7tu8ZqgrHkhSCQNewf1ztFQJgcmaQWn+H4AJERBjwkjosqh4TvUJucZv8vyRTvrFeBXaCSA==", + "cpu": [ + "arm" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=10" + } + }, + "node_modules/@swc/core-linux-arm64-gnu": { + "version": "1.3.74", + "resolved": "https://registry.npmjs.org/@swc/core-linux-arm64-gnu/-/core-linux-arm64-gnu-1.3.74.tgz", + "integrity": "sha512-+xkbCRz/wczgdknoV4NwYxbRI2dD7x/qkIFcVM2buzLCq8oWLweuV8+aL4pRqu0qDh7ZSb1jcaVTUIsySCJznA==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=10" + } + }, + "node_modules/@swc/core-linux-arm64-musl": { + "version": "1.3.74", + "resolved": "https://registry.npmjs.org/@swc/core-linux-arm64-musl/-/core-linux-arm64-musl-1.3.74.tgz", + "integrity": "sha512-maKFZSCD3tQznzPV7T3V+TtiWZFEFM8YrnSS5fQNNb+K9J65sL+170uTb3M7H4cFkG+9Sm5k5yCrCIutlvV48g==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=10" + } + }, + "node_modules/@swc/core-linux-x64-gnu": { + "version": "1.3.74", + "resolved": "https://registry.npmjs.org/@swc/core-linux-x64-gnu/-/core-linux-x64-gnu-1.3.74.tgz", + "integrity": "sha512-LEXpcShF6DLTWJSiBhMSYZkLQ27UvaQ24fCFhoIV/R3dhYaUpHmIyLPPBNC82T03lB3ONUFVwrRw6fxDJ/f00A==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=10" + } + }, + "node_modules/@swc/core-linux-x64-musl": { + "version": "1.3.74", + "resolved": "https://registry.npmjs.org/@swc/core-linux-x64-musl/-/core-linux-x64-musl-1.3.74.tgz", + "integrity": "sha512-sxsFctbFMZEFmDE7CmYljG0dMumH8XBTwwtGr8s6z0fYAzXBGNq2AFPcmEh2np9rPWkt7pE1m0ByESD+dMkbxQ==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=10" + } + }, + "node_modules/@swc/core-win32-arm64-msvc": { + "version": "1.3.74", + "resolved": "https://registry.npmjs.org/@swc/core-win32-arm64-msvc/-/core-win32-arm64-msvc-1.3.74.tgz", + "integrity": "sha512-F7hY9/BjFCozA4YPFYFH5FGCyWwa44vIXHqG66F5cDwXDGFn8ZtBsYIsiPfUYcx0AeAo1ojnVWKPxokZhYNYqA==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=10" + } + }, + "node_modules/@swc/core-win32-ia32-msvc": { + "version": "1.3.74", + "resolved": "https://registry.npmjs.org/@swc/core-win32-ia32-msvc/-/core-win32-ia32-msvc-1.3.74.tgz", + "integrity": "sha512-qBAsiD1AlIdqED6wy3UNRHyAys9pWMUidX0LJ6mj24r/vfrzzTBAUrLJe5m7bzE+F1Rgi001avYJeEW1DLEJ+Q==", + "cpu": [ + "ia32" + ], + "dev": true, + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=10" + } + }, + "node_modules/@swc/core-win32-x64-msvc": { + "version": "1.3.74", + "resolved": "https://registry.npmjs.org/@swc/core-win32-x64-msvc/-/core-win32-x64-msvc-1.3.74.tgz", + "integrity": "sha512-S3YAvvLprTnPRwQuy9Dkwubb5SRLpVK3JJsqYDbGfgj8PGQyKHZcVJ5X3nfFsoWLy3j9B/3Os2nawprRSzeC5A==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=10" + } + }, + "node_modules/@swc/register": { + "version": "0.1.10", + "resolved": "https://registry.npmjs.org/@swc/register/-/register-0.1.10.tgz", + "integrity": "sha512-6STwH/q4dc3pitXLVkV7sP0Hiy+zBsU2wOF1aXpXR95pnH3RYHKIsDC+gvesfyB7jxNT9OOZgcqOp9RPxVTx9A==", + "dev": true, + "dependencies": { + "lodash.clonedeep": "^4.5.0", + "pirates": "^4.0.1", + "source-map-support": "^0.5.13" + }, + "bin": { + "swc-node": "bin/swc-node" + }, + "peerDependencies": { + "@swc/core": "^1.0.46" + } + }, + "node_modules/@szmarczak/http-timer": { + "version": "4.0.6", + "resolved": "https://registry.npmjs.org/@szmarczak/http-timer/-/http-timer-4.0.6.tgz", + "integrity": "sha512-4BAffykYOgO+5nzBWYwE3W90sBgLJoUPRWWcL8wlyiM8IB8ipJz3UMJ9KXQd1RKQXpKp8Tutn80HZtWsu2u76w==", + "dev": true, + "dependencies": { + "defer-to-connect": "^2.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/@tokenizer/token": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/@tokenizer/token/-/token-0.3.0.tgz", + "integrity": "sha512-OvjF+z51L3ov0OyAU0duzsYuvO01PH7x4t6DJx+guahgTnBHkhJdG7soQeTSFLWN3efnHyibZ4Z8l2EuWwJN3A==", + "dev": true + }, + "node_modules/@types/backoff": { + "version": "2.5.2", + "resolved": "https://registry.npmjs.org/@types/backoff/-/backoff-2.5.2.tgz", + "integrity": "sha512-oa1YvggujhVppgeIct3LBkbCVXKh97fvOFIR6VlFLxRCeswk/KBRQKg7zoX832vlCP5bGLOFqC9hY7vsDeL9AA==", + "dev": true, + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/@types/cacheable-request": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/@types/cacheable-request/-/cacheable-request-6.0.3.tgz", + "integrity": "sha512-IQ3EbTzGxIigb1I3qPZc1rWJnH0BmSKv5QYTalEwweFvyBDLSAe24zP0le/hyi7ecGfZVlIVAg4BZqb8WBwKqw==", + "dev": true, + "dependencies": { + "@types/http-cache-semantics": "*", + "@types/keyv": "^3.1.4", + "@types/node": "*", + "@types/responselike": "^1.0.0" + } + }, + "node_modules/@types/chai": { + "version": "4.3.5", + "resolved": "https://registry.npmjs.org/@types/chai/-/chai-4.3.5.tgz", + "integrity": "sha512-mEo1sAde+UCE6b2hxn332f1g1E8WfYRu6p5SvTKr2ZKC1f7gFJXk4h5PyGP9Dt6gCaG8y8XhwnXWC6Iy2cmBng==", + "dev": true + }, + "node_modules/@types/debug": { + "version": "4.1.8", + "resolved": "https://registry.npmjs.org/@types/debug/-/debug-4.1.8.tgz", + "integrity": "sha512-/vPO1EPOs306Cvhwv7KfVfYvOJqA/S/AXjaHQiJboCZzcNDb+TIJFN9/2C9DZ//ijSKWioNyUxD792QmDJ+HKQ==", + "dev": true, + "dependencies": { + "@types/ms": "*" + } + }, + "node_modules/@types/http-cache-semantics": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/@types/http-cache-semantics/-/http-cache-semantics-4.0.1.tgz", + "integrity": "sha512-SZs7ekbP8CN0txVG2xVRH6EgKmEm31BOxA07vkFaETzZz1xh+cbt8BcI0slpymvwhx5dlFnQG2rTlPVQn+iRPQ==", + "dev": true + }, + "node_modules/@types/json-schema": { + "version": "7.0.12", + "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.12.tgz", + "integrity": "sha512-Hr5Jfhc9eYOQNPYO5WLDq/n4jqijdHNlDXjuAQkkt+mWdQR+XJToOHrsD4cPaMXpn6KO7y2+wM8AZEs8VpBLVA==", + "dev": true + }, + "node_modules/@types/keyv": { + "version": "3.1.4", + "resolved": "https://registry.npmjs.org/@types/keyv/-/keyv-3.1.4.tgz", + "integrity": "sha512-BQ5aZNSCpj7D6K2ksrRCTmKRLEpnPvWDiLPfoGyhZ++8YtiK9d/3DBKPJgry359X/P1PfruyYwvnvwFjuEiEIg==", + "dev": true, + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/@types/mocha": { + "version": "10.0.1", + "resolved": "https://registry.npmjs.org/@types/mocha/-/mocha-10.0.1.tgz", + "integrity": "sha512-/fvYntiO1GeICvqbQ3doGDIP97vWmvFt83GKguJ6prmQM2iXZfFcq6YE8KteFyRtX2/h5Hf91BYvPodJKFYv5Q==", + "dev": true + }, + "node_modules/@types/ms": { + "version": "0.7.31", + "resolved": "https://registry.npmjs.org/@types/ms/-/ms-0.7.31.tgz", + "integrity": "sha512-iiUgKzV9AuaEkZqkOLDIvlQiL6ltuZd9tGcW3gwpnX8JbuiuhFlEGmmFXEXkN50Cvq7Os88IY2v0dkDqXYWVgA==", + "dev": true + }, + "node_modules/@types/node": { + "version": "20.4.7", + "resolved": "https://registry.npmjs.org/@types/node/-/node-20.4.7.tgz", + "integrity": "sha512-bUBrPjEry2QUTsnuEjzjbS7voGWCc30W0qzgMf90GPeDGFRakvrz47ju+oqDAKCXLUCe39u57/ORMl/O/04/9g==", + "dev": true + }, + "node_modules/@types/responselike": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/@types/responselike/-/responselike-1.0.0.tgz", + "integrity": "sha512-85Y2BjiufFzaMIlvJDvTTB8Fxl2xfLo4HgmHzVBz08w4wDePCTjYw66PdrolO0kzli3yam/YCgRufyo1DdQVTA==", + "dev": true, + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/@types/semver": { + "version": "7.5.0", + "resolved": "https://registry.npmjs.org/@types/semver/-/semver-7.5.0.tgz", + "integrity": "sha512-G8hZ6XJiHnuhQKR7ZmysCeJWE08o8T0AXtk5darsCaTVsYZhhgUrq53jizaR2FvsoeCwJhlmwTjkXBY5Pn/ZHw==", + "dev": true + }, + "node_modules/@types/uuid": { + "version": "9.0.2", + "resolved": "https://registry.npmjs.org/@types/uuid/-/uuid-9.0.2.tgz", + "integrity": "sha512-kNnC1GFBLuhImSnV7w4njQkUiJi0ZXUycu1rUaouPqiKlXkh77JKgdRnTAp1x5eBwcIwbtI+3otwzuIDEuDoxQ==", + "dev": true + }, + "node_modules/@types/websocket": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/@types/websocket/-/websocket-1.0.5.tgz", + "integrity": "sha512-NbsqiNX9CnEfC1Z0Vf4mE1SgAJ07JnRYcNex7AJ9zAVzmiGHmjKFEk7O4TJIsgv2B1sLEb6owKFZrACwdYngsQ==", + "dev": true, + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/@typescript-eslint/eslint-plugin": { + "version": "5.62.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-5.62.0.tgz", + "integrity": "sha512-TiZzBSJja/LbhNPvk6yc0JrX9XqhQ0hdh6M2svYfsHGejaKFIAGd9MQ+ERIMzLGlN/kZoYIgdxFV0PuljTKXag==", + "dev": true, + "dependencies": { + "@eslint-community/regexpp": "^4.4.0", + "@typescript-eslint/scope-manager": "5.62.0", + "@typescript-eslint/type-utils": "5.62.0", + "@typescript-eslint/utils": "5.62.0", + "debug": "^4.3.4", + "graphemer": "^1.4.0", + "ignore": "^5.2.0", + "natural-compare-lite": "^1.4.0", + "semver": "^7.3.7", + "tsutils": "^3.21.0" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "@typescript-eslint/parser": "^5.0.0", + "eslint": "^6.0.0 || ^7.0.0 || ^8.0.0" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/@typescript-eslint/parser": { + "version": "5.62.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-5.62.0.tgz", + "integrity": "sha512-VlJEV0fOQ7BExOsHYAGrgbEiZoi8D+Bl2+f6V2RrXerRSylnp+ZBHmPvaIa8cz0Ajx7WO7Z5RqfgYg7ED1nRhA==", + "dev": true, + "dependencies": { + "@typescript-eslint/scope-manager": "5.62.0", + "@typescript-eslint/types": "5.62.0", + "@typescript-eslint/typescript-estree": "5.62.0", + "debug": "^4.3.4" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "^6.0.0 || ^7.0.0 || ^8.0.0" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/@typescript-eslint/scope-manager": { + "version": "5.62.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-5.62.0.tgz", + "integrity": "sha512-VXuvVvZeQCQb5Zgf4HAxc04q5j+WrNAtNh9OwCsCgpKqESMTu3tF/jhZ3xG6T4NZwWl65Bg8KuS2uEvhSfLl0w==", + "dev": true, + "dependencies": { + "@typescript-eslint/types": "5.62.0", + "@typescript-eslint/visitor-keys": "5.62.0" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/@typescript-eslint/type-utils": { + "version": "5.62.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-5.62.0.tgz", + "integrity": "sha512-xsSQreu+VnfbqQpW5vnCJdq1Z3Q0U31qiWmRhr98ONQmcp/yhiPJFPq8MXiJVLiksmOKSjIldZzkebzHuCGzew==", + "dev": true, + "dependencies": { + "@typescript-eslint/typescript-estree": "5.62.0", + "@typescript-eslint/utils": "5.62.0", + "debug": "^4.3.4", + "tsutils": "^3.21.0" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "*" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/@typescript-eslint/types": { + "version": "5.62.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-5.62.0.tgz", + "integrity": "sha512-87NVngcbVXUahrRTqIK27gD2t5Cu1yuCXxbLcFtCzZGlfyVWWh8mLHkoxzjsB6DDNnvdL+fW8MiwPEJyGJQDgQ==", + "dev": true, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/@typescript-eslint/typescript-estree": { + "version": "5.62.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-5.62.0.tgz", + "integrity": "sha512-CmcQ6uY7b9y694lKdRB8FEel7JbU/40iSAPomu++SjLMntB+2Leay2LO6i8VnJk58MtE9/nQSFIH6jpyRWyYzA==", + "dev": true, + "dependencies": { + "@typescript-eslint/types": "5.62.0", + "@typescript-eslint/visitor-keys": "5.62.0", + "debug": "^4.3.4", + "globby": "^11.1.0", + "is-glob": "^4.0.3", + "semver": "^7.3.7", + "tsutils": "^3.21.0" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/@typescript-eslint/utils": { + "version": "5.62.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-5.62.0.tgz", + "integrity": "sha512-n8oxjeb5aIbPFEtmQxQYOLI0i9n5ySBEY/ZEHHZqKQSFnxio1rv6dthascc9dLuwrL0RC5mPCxB7vnAVGAYWAQ==", + "dev": true, + "dependencies": { + "@eslint-community/eslint-utils": "^4.2.0", + "@types/json-schema": "^7.0.9", + "@types/semver": "^7.3.12", + "@typescript-eslint/scope-manager": "5.62.0", + "@typescript-eslint/types": "5.62.0", + "@typescript-eslint/typescript-estree": "5.62.0", + "eslint-scope": "^5.1.1", + "semver": "^7.3.7" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "^6.0.0 || ^7.0.0 || ^8.0.0" + } + }, + "node_modules/@typescript-eslint/visitor-keys": { + "version": "5.62.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-5.62.0.tgz", + "integrity": "sha512-07ny+LHRzQXepkGg6w0mFY41fVUNBrL2Roj/++7V1txKugfjm/Ci/qSND03r2RhlJhJYMcTn9AhhSSqQp0Ysyw==", + "dev": true, + "dependencies": { + "@typescript-eslint/types": "5.62.0", + "eslint-visitor-keys": "^3.3.0" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/abbrev": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/abbrev/-/abbrev-1.1.1.tgz", + "integrity": "sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q==", + "dev": true + }, + "node_modules/acorn": { + "version": "8.10.0", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.10.0.tgz", + "integrity": "sha512-F0SAmZ8iUtS//m8DmCTA0jlh6TDKkHQyK6xc6V4KDTyZKA9dnvX9/3sRTVQrWm79glUAZbnmmNcdYwUIHWVybw==", + "dev": true, + "bin": { + "acorn": "bin/acorn" + }, + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/acorn-jsx": { + "version": "5.3.2", + "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.2.tgz", + "integrity": "sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==", + "dev": true, + "peerDependencies": { + "acorn": "^6.0.0 || ^7.0.0 || ^8.0.0" + } + }, + "node_modules/ajv": { + "version": "6.12.6", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", + "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", + "dev": true, + "dependencies": { + "fast-deep-equal": "^3.1.1", + "fast-json-stable-stringify": "^2.0.0", + "json-schema-traverse": "^0.4.1", + "uri-js": "^4.2.2" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, + "node_modules/ansi-colors": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/ansi-colors/-/ansi-colors-4.1.1.tgz", + "integrity": "sha512-JoX0apGbHaUJBNl6yF+p6JAFYZ666/hhCGKN5t9QFjbJQKUU/g8MNbFDbvfrgKXvI1QpZplPOnwIo99lX/AAmA==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/anymatch": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.3.tgz", + "integrity": "sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==", + "dev": true, + "dependencies": { + "normalize-path": "^3.0.0", + "picomatch": "^2.0.4" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/arch": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/arch/-/arch-2.2.0.tgz", + "integrity": "sha512-Of/R0wqp83cgHozfIYLbBMnej79U/SVGOOyuB3VVFv1NRM/PSFMK12x9KVtiYzJqmnU5WR2qp0Z5rHb7sWGnFQ==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ] + }, + "node_modules/argparse": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", + "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", + "dev": true + }, + "node_modules/array-union": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/array-union/-/array-union-2.1.0.tgz", + "integrity": "sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/assertion-error": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/assertion-error/-/assertion-error-1.1.0.tgz", + "integrity": "sha512-jgsaNduz+ndvGyFt3uSuWqvy4lCnIJiovtouQN5JZHOKCS2QuhEdbcQHFhVksz2N2U9hXJo8odG7ETyWlEeuDw==", + "dev": true, + "engines": { + "node": "*" + } + }, + "node_modules/asynckit": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", + "integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==" + }, + "node_modules/axios": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/axios/-/axios-1.4.0.tgz", + "integrity": "sha512-S4XCWMEmzvo64T9GfvQDOXgYRDJ/wsSZc7Jvdgx5u1sd0JwsuPLqb3SYmusag+edF6ziyMensPVqLTSc1PiSEA==", + "dependencies": { + "follow-redirects": "^1.15.0", + "form-data": "^4.0.0", + "proxy-from-env": "^1.1.0" + } + }, + "node_modules/balanced-match": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", + "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", + "dev": true + }, + "node_modules/bin-check": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/bin-check/-/bin-check-4.1.0.tgz", + "integrity": "sha512-b6weQyEUKsDGFlACWSIOfveEnImkJyK/FGW6FAG42loyoquvjdtOIqO6yBFzHyqyVVhNgNkQxxx09SFLK28YnA==", + "dev": true, + "dependencies": { + "execa": "^0.7.0", + "executable": "^4.1.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/bin-version": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/bin-version/-/bin-version-6.0.0.tgz", + "integrity": "sha512-nk5wEsP4RiKjG+vF+uG8lFsEn4d7Y6FVDamzzftSunXOoOcOOkzcWdKVlGgFFwlUQCj63SgnUkLLGF8v7lufhw==", + "dev": true, + "dependencies": { + "execa": "^5.0.0", + "find-versions": "^5.0.0" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/bin-version-check": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/bin-version-check/-/bin-version-check-5.1.0.tgz", + "integrity": "sha512-bYsvMqJ8yNGILLz1KP9zKLzQ6YpljV3ln1gqhuLkUtyfGi3qXKGuK2p+U4NAvjVFzDFiBBtOpCOSFNuYYEGZ5g==", + "dev": true, + "dependencies": { + "bin-version": "^6.0.0", + "semver": "^7.5.3", + "semver-truncate": "^3.0.0" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/bin-version/node_modules/execa": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/execa/-/execa-5.1.1.tgz", + "integrity": "sha512-8uSpZZocAZRBAPIEINJj3Lo9HyGitllczc27Eh5YYojjMFMn8yHMDMaUHE2Jqfq05D/wucwI4JGURyXt1vchyg==", + "dev": true, + "dependencies": { + "cross-spawn": "^7.0.3", + "get-stream": "^6.0.0", + "human-signals": "^2.1.0", + "is-stream": "^2.0.0", + "merge-stream": "^2.0.0", + "npm-run-path": "^4.0.1", + "onetime": "^5.1.2", + "signal-exit": "^3.0.3", + "strip-final-newline": "^2.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sindresorhus/execa?sponsor=1" + } + }, + "node_modules/bin-version/node_modules/get-stream": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-6.0.1.tgz", + "integrity": "sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/bin-version/node_modules/is-stream": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-2.0.1.tgz", + "integrity": "sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==", + "dev": true, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/bin-version/node_modules/npm-run-path": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-4.0.1.tgz", + "integrity": "sha512-S48WzZW777zhNIrn7gxOlISNAqi9ZC/uQFnRdbeIHhZhCA6UqpkOT8T1G7BvfdgP4Er8gF4sUbaS0i7QvIfCWw==", + "dev": true, + "dependencies": { + "path-key": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/binary-extensions": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.2.0.tgz", + "integrity": "sha512-jDctJ/IVQbZoJykoeHbhXpOlNBqGNcwXJKJog42E5HDPUwQTSdjCHdihjj0DlnheQ7blbT6dHOafNAiS8ooQKA==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "dev": true, + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/braces": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz", + "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==", + "dev": true, + "dependencies": { + "fill-range": "^7.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/browser-stdout": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/browser-stdout/-/browser-stdout-1.3.1.tgz", + "integrity": "sha512-qhAVI1+Av2X7qelOfAIYwXONood6XlZE/fXaBSmW/T5SzLAmCgzi+eiWE7fUvbHaeNBQH13UftjpXxsfLkMpgw==", + "dev": true + }, + "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==", + "dev": true + }, + "node_modules/cacheable-lookup": { + "version": "5.0.4", + "resolved": "https://registry.npmjs.org/cacheable-lookup/-/cacheable-lookup-5.0.4.tgz", + "integrity": "sha512-2/kNscPhpcxrOigMZzbiWF7dz8ilhb/nIHU3EyZiXWXpeq/au8qJ8VhdftMkty3n7Gj6HIGalQG8oiBNB3AJgA==", + "dev": true, + "engines": { + "node": ">=10.6.0" + } + }, + "node_modules/cacheable-request": { + "version": "7.0.4", + "resolved": "https://registry.npmjs.org/cacheable-request/-/cacheable-request-7.0.4.tgz", + "integrity": "sha512-v+p6ongsrp0yTGbJXjgxPow2+DL93DASP4kXCDKb8/bwRtt9OEF3whggkkDkGNzgcWy2XaF4a8nZglC7uElscg==", + "dev": true, + "dependencies": { + "clone-response": "^1.0.2", + "get-stream": "^5.1.0", + "http-cache-semantics": "^4.0.0", + "keyv": "^4.0.0", + "lowercase-keys": "^2.0.0", + "normalize-url": "^6.0.1", + "responselike": "^2.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/cacheable-request/node_modules/get-stream": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-5.2.0.tgz", + "integrity": "sha512-nBF+F1rAZVCu/p7rjzgA+Yb4lfYXrpl7a6VmJrU8wF9I1CKvP/QwPNZHnOlwbTkY6dvtFIzFMSyQXbLoTQPRpA==", + "dev": true, + "dependencies": { + "pump": "^3.0.0" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/callsites": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", + "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/camelcase": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-6.3.0.tgz", + "integrity": "sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/chai": { + "version": "4.3.7", + "resolved": "https://registry.npmjs.org/chai/-/chai-4.3.7.tgz", + "integrity": "sha512-HLnAzZ2iupm25PlN0xFreAlBA5zaBSv3og0DdeGA4Ar6h6rJ3A0rolRUKJhSF2V10GZKDgWF/VmAEsNWjCRB+A==", + "dev": true, + "dependencies": { + "assertion-error": "^1.1.0", + "check-error": "^1.0.2", + "deep-eql": "^4.1.2", + "get-func-name": "^2.0.0", + "loupe": "^2.3.1", + "pathval": "^1.1.1", + "type-detect": "^4.0.5" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/check-error": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/check-error/-/check-error-1.0.2.tgz", + "integrity": "sha512-BrgHpW9NURQgzoNyjfq0Wu6VFO6D7IZEmJNdtgNqpzGG8RuNFHt2jQxWlAs4HMe119chBnv+34syEZtc6IhLtA==", + "dev": true, + "engines": { + "node": "*" + } + }, + "node_modules/chokidar": { + "version": "3.5.3", + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.5.3.tgz", + "integrity": "sha512-Dr3sfKRP6oTcjf2JmUmFJfeVMvXBdegxB0iVQ5eb2V10uFJUCAS8OByZdVAyVb8xXNz3GjjTgj9kLWsZTqE6kw==", + "dev": true, + "funding": [ + { + "type": "individual", + "url": "https://paulmillr.com/funding/" + } + ], + "dependencies": { + "anymatch": "~3.1.2", + "braces": "~3.0.2", + "glob-parent": "~5.1.2", + "is-binary-path": "~2.1.0", + "is-glob": "~4.0.1", + "normalize-path": "~3.0.0", + "readdirp": "~3.6.0" + }, + "engines": { + "node": ">= 8.10.0" + }, + "optionalDependencies": { + "fsevents": "~2.3.2" + } + }, + "node_modules/chokidar/node_modules/glob-parent": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", + "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", + "dev": true, + "dependencies": { + "is-glob": "^4.0.1" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/cliui": { + "version": "7.0.4", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-7.0.4.tgz", + "integrity": "sha512-OcRE68cOsVMXp1Yvonl/fzkQOyjLSu/8bhPDfQt0e0/Eb283TKP20Fs2MqoPsr9SwA595rRCA+QMzYc9nBP+JQ==", + "dev": true, + "dependencies": { + "string-width": "^4.2.0", + "strip-ansi": "^6.0.0", + "wrap-ansi": "^7.0.0" + } + }, + "node_modules/clone-response": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/clone-response/-/clone-response-1.0.3.tgz", + "integrity": "sha512-ROoL94jJH2dUVML2Y/5PEDNaSHgeOdSDicUyS7izcF63G6sTc/FTjLub4b8Il9S8S0beOfYt0TaA5qvFK+w0wA==", + "dev": true, + "dependencies": { + "mimic-response": "^1.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true + }, + "node_modules/combined-stream": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz", + "integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==", + "dependencies": { + "delayed-stream": "~1.0.0" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/commander": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/commander/-/commander-7.2.0.tgz", + "integrity": "sha512-QrWXB+ZQSVPmIWIhtEO9H+gwHaMGYiF5ChvoJ+K9ZGHG/sVsa6yiesAD1GC/x46sET00Xlwo1u49RVVVzvcSkw==", + "dev": true, + "engines": { + "node": ">= 10" + } + }, + "node_modules/concat-map": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", + "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==", + "dev": true + }, + "node_modules/content-disposition": { + "version": "0.5.4", + "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.4.tgz", + "integrity": "sha512-FveZTNuGw04cxlAiWbzi6zTAL/lhehaWbTtgluJh4/E95DqMwTmha3KZN1aAWA8cFIhHzMZUvLevkw5Rqk+tSQ==", + "dev": true, + "dependencies": { + "safe-buffer": "5.2.1" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/cross-spawn": { + "version": "7.0.3", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz", + "integrity": "sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==", + "dev": true, + "dependencies": { + "path-key": "^3.1.0", + "shebang-command": "^2.0.0", + "which": "^2.0.1" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/debug": { + "version": "4.3.4", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", + "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", + "dev": true, + "dependencies": { + "ms": "2.1.2" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/decamelize": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-4.0.0.tgz", + "integrity": "sha512-9iE1PgSik9HeIIw2JO94IidnE3eBoQrFJ3w7sFuzSX4DpmZ3v5sZpUiV5Swcf6mQEF+Y0ru8Neo+p+nyh2J+hQ==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/decompress-response": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/decompress-response/-/decompress-response-6.0.0.tgz", + "integrity": "sha512-aW35yZM6Bb/4oJlZncMH2LCoZtJXTRxES17vE3hoRiowU2kWHaJKFkSBDnDR+cm9J+9QhXmREyIfv0pji9ejCQ==", + "dev": true, + "dependencies": { + "mimic-response": "^3.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/decompress-response/node_modules/mimic-response": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/mimic-response/-/mimic-response-3.1.0.tgz", + "integrity": "sha512-z0yWI+4FDrrweS8Zmt4Ej5HdJmky15+L2e6Wgn3+iK5fWzb6T3fhNFq2+MeTRb064c6Wr4N/wv0DzQTjNzHNGQ==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/deep-eql": { + "version": "4.1.3", + "resolved": "https://registry.npmjs.org/deep-eql/-/deep-eql-4.1.3.tgz", + "integrity": "sha512-WaEtAOpRA1MQ0eohqZjpGD8zdI0Ovsm8mmFhaDN8dvDZzyoUMcYDnf5Y6iu7HTXxf8JDS23qWa4a+hKCDyOPzw==", + "dev": true, + "dependencies": { + "type-detect": "^4.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/deep-is": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.4.tgz", + "integrity": "sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==", + "dev": true + }, + "node_modules/defer-to-connect": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/defer-to-connect/-/defer-to-connect-2.0.1.tgz", + "integrity": "sha512-4tvttepXG1VaYGrRibk5EwJd1t4udunSOVMdLSAL6mId1ix438oPwPZMALY41FCijukO1L0twNcGsdzS7dHgDg==", + "dev": true, + "engines": { + "node": ">=10" + } + }, + "node_modules/delayed-stream": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", + "integrity": "sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==", + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/diff": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/diff/-/diff-5.0.0.tgz", + "integrity": "sha512-/VTCrvm5Z0JGty/BWHljh+BAiw3IK+2j87NGMu8Nwc/f48WoDAC395uomO9ZD117ZOBaHmkX1oyLvkVM/aIT3w==", + "dev": true, + "engines": { + "node": ">=0.3.1" + } + }, + "node_modules/dir-glob": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/dir-glob/-/dir-glob-3.0.1.tgz", + "integrity": "sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA==", + "dev": true, + "dependencies": { + "path-type": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/doctrine": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-3.0.0.tgz", + "integrity": "sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w==", + "dev": true, + "dependencies": { + "esutils": "^2.0.2" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/emoji-regex": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", + "dev": true + }, + "node_modules/end-of-stream": { + "version": "1.4.4", + "resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.4.tgz", + "integrity": "sha512-+uw1inIHVPQoaVuHzRyXd21icM+cnt4CzD5rW+NC1wjOUSTOs+Te7FOv7AhN7vS9x/oIyhLP5PR1H+phQAHu5Q==", + "dev": true, + "dependencies": { + "once": "^1.4.0" + } + }, + "node_modules/escalade": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.1.tgz", + "integrity": "sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/escape-string-regexp": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", + "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/eslint": { + "version": "8.45.0", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.45.0.tgz", + "integrity": "sha512-pd8KSxiQpdYRfYa9Wufvdoct3ZPQQuVuU5O6scNgMuOMYuxvH0IGaYK0wUFjo4UYYQQCUndlXiMbnxopwvvTiw==", + "dev": true, + "dependencies": { + "@eslint-community/eslint-utils": "^4.2.0", + "@eslint-community/regexpp": "^4.4.0", + "@eslint/eslintrc": "^2.1.0", + "@eslint/js": "8.44.0", + "@humanwhocodes/config-array": "^0.11.10", + "@humanwhocodes/module-importer": "^1.0.1", + "@nodelib/fs.walk": "^1.2.8", + "ajv": "^6.10.0", + "chalk": "^4.0.0", + "cross-spawn": "^7.0.2", + "debug": "^4.3.2", + "doctrine": "^3.0.0", + "escape-string-regexp": "^4.0.0", + "eslint-scope": "^7.2.0", + "eslint-visitor-keys": "^3.4.1", + "espree": "^9.6.0", + "esquery": "^1.4.2", + "esutils": "^2.0.2", + "fast-deep-equal": "^3.1.3", + "file-entry-cache": "^6.0.1", + "find-up": "^5.0.0", + "glob-parent": "^6.0.2", + "globals": "^13.19.0", + "graphemer": "^1.4.0", + "ignore": "^5.2.0", + "imurmurhash": "^0.1.4", + "is-glob": "^4.0.0", + "is-path-inside": "^3.0.3", + "js-yaml": "^4.1.0", + "json-stable-stringify-without-jsonify": "^1.0.1", + "levn": "^0.4.1", + "lodash.merge": "^4.6.2", + "minimatch": "^3.1.2", + "natural-compare": "^1.4.0", + "optionator": "^0.9.3", + "strip-ansi": "^6.0.1", + "text-table": "^0.2.0" + }, + "bin": { + "eslint": "bin/eslint.js" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/eslint-config-prettier": { + "version": "8.8.0", + "resolved": "https://registry.npmjs.org/eslint-config-prettier/-/eslint-config-prettier-8.8.0.tgz", + "integrity": "sha512-wLbQiFre3tdGgpDv67NQKnJuTlcUVYHas3k+DZCc2U2BadthoEY4B7hLPvAxaqdyOGCzuLfii2fqGph10va7oA==", + "dev": true, + "bin": { + "eslint-config-prettier": "bin/cli.js" + }, + "peerDependencies": { + "eslint": ">=7.0.0" + } + }, + "node_modules/eslint-plugin-prettier": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/eslint-plugin-prettier/-/eslint-plugin-prettier-4.2.1.tgz", + "integrity": "sha512-f/0rXLXUt0oFYs8ra4w49wYZBG5GKZpAYsJSm6rnYL5uVDjd+zowwMwVZHnAjf4edNrKpCDYfXDgmRE/Ak7QyQ==", + "dev": true, + "dependencies": { + "prettier-linter-helpers": "^1.0.0" + }, + "engines": { + "node": ">=12.0.0" + }, + "peerDependencies": { + "eslint": ">=7.28.0", + "prettier": ">=2.0.0" + }, + "peerDependenciesMeta": { + "eslint-config-prettier": { + "optional": true + } + } + }, + "node_modules/eslint-scope": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-5.1.1.tgz", + "integrity": "sha512-2NxwbF/hZ0KpepYN0cNbo+FN6XoK7GaHlQhgx/hIZl6Va0bF45RQOOwhLIy8lQDbuCiadSLCBnH2CFYquit5bw==", + "dev": true, + "dependencies": { + "esrecurse": "^4.3.0", + "estraverse": "^4.1.1" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/eslint-visitor-keys": { + "version": "3.4.2", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.4.2.tgz", + "integrity": "sha512-8drBzUEyZ2llkpCA67iYrgEssKDUu68V8ChqqOfFupIaG/LCVPUT+CoGJpT77zJprs4T/W7p07LP7zAIMuweVw==", + "dev": true, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/eslint/node_modules/eslint-scope": { + "version": "7.2.2", + "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-7.2.2.tgz", + "integrity": "sha512-dOt21O7lTMhDM+X9mB4GX+DZrZtCUJPL/wlcTqxyrx5IvO0IYtILdtrQGQp+8n5S0gwSVmOf9NQrjMOgfQZlIg==", + "dev": true, + "dependencies": { + "esrecurse": "^4.3.0", + "estraverse": "^5.2.0" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/eslint/node_modules/estraverse": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", + "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", + "dev": true, + "engines": { + "node": ">=4.0" + } + }, + "node_modules/espree": { + "version": "9.6.1", + "resolved": "https://registry.npmjs.org/espree/-/espree-9.6.1.tgz", + "integrity": "sha512-oruZaFkjorTpF32kDSI5/75ViwGeZginGGy2NoOSg3Q9bnwlnmDm4HLnkl0RE3n+njDXR037aY1+x58Z/zFdwQ==", + "dev": true, + "dependencies": { + "acorn": "^8.9.0", + "acorn-jsx": "^5.3.2", + "eslint-visitor-keys": "^3.4.1" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/esquery": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.5.0.tgz", + "integrity": "sha512-YQLXUplAwJgCydQ78IMJywZCceoqk1oH01OERdSAJc/7U2AylwjhSCLDEtqwg811idIS/9fIU5GjG73IgjKMVg==", + "dev": true, + "dependencies": { + "estraverse": "^5.1.0" + }, + "engines": { + "node": ">=0.10" + } + }, + "node_modules/esquery/node_modules/estraverse": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", + "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", + "dev": true, + "engines": { + "node": ">=4.0" + } + }, + "node_modules/esrecurse": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.3.0.tgz", + "integrity": "sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==", + "dev": true, + "dependencies": { + "estraverse": "^5.2.0" + }, + "engines": { + "node": ">=4.0" + } + }, + "node_modules/esrecurse/node_modules/estraverse": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", + "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", + "dev": true, + "engines": { + "node": ">=4.0" + } + }, + "node_modules/estraverse": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.3.0.tgz", + "integrity": "sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==", + "dev": true, + "engines": { + "node": ">=4.0" + } + }, + "node_modules/esutils": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz", + "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/eventemitter2": { + "version": "6.4.9", + "resolved": "https://registry.npmjs.org/eventemitter2/-/eventemitter2-6.4.9.tgz", + "integrity": "sha512-JEPTiaOt9f04oa6NOkc4aH+nVp5I3wEjpHbIPqfgCdD5v5bUzy7xQqwcVO2aDQgOWhI28da57HksMrzK9HlRxg==" + }, + "node_modules/execa": { + "version": "0.7.0", + "resolved": "https://registry.npmjs.org/execa/-/execa-0.7.0.tgz", + "integrity": "sha512-RztN09XglpYI7aBBrJCPW95jEH7YF1UEPOoX9yDhUTPdp7mK+CQvnLTuD10BNXZ3byLTu2uehZ8EcKT/4CGiFw==", + "dev": true, + "dependencies": { + "cross-spawn": "^5.0.1", + "get-stream": "^3.0.0", + "is-stream": "^1.1.0", + "npm-run-path": "^2.0.0", + "p-finally": "^1.0.0", + "signal-exit": "^3.0.0", + "strip-eof": "^1.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/execa/node_modules/cross-spawn": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-5.1.0.tgz", + "integrity": "sha512-pTgQJ5KC0d2hcY8eyL1IzlBPYjTkyH72XRZPnLyKus2mBfNjQs3klqbJU2VILqZryAZUt9JOb3h/mWMy23/f5A==", + "dev": true, + "dependencies": { + "lru-cache": "^4.0.1", + "shebang-command": "^1.2.0", + "which": "^1.2.9" + } + }, + "node_modules/execa/node_modules/lru-cache": { + "version": "4.1.5", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-4.1.5.tgz", + "integrity": "sha512-sWZlbEP2OsHNkXrMl5GYk/jKk70MBng6UU4YI/qGDYbgf6YbP4EvmqISbXCoJiRKs+1bSpFHVgQxvJ17F2li5g==", + "dev": true, + "dependencies": { + "pseudomap": "^1.0.2", + "yallist": "^2.1.2" + } + }, + "node_modules/execa/node_modules/shebang-command": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-1.2.0.tgz", + "integrity": "sha512-EV3L1+UQWGor21OmnvojK36mhg+TyIKDh3iFBKBohr5xeXIhNBcx8oWdgkTEEQ+BEFFYdLRuqMfd5L84N1V5Vg==", + "dev": true, + "dependencies": { + "shebang-regex": "^1.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/execa/node_modules/shebang-regex": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-1.0.0.tgz", + "integrity": "sha512-wpoSFAxys6b2a2wHZ1XpDSgD7N9iVjg29Ph9uV/uaP9Ex/KXlkTZTeddxDPSYQpgvzKLGJke2UU0AzoGCjNIvQ==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/execa/node_modules/which": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/which/-/which-1.3.1.tgz", + "integrity": "sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ==", + "dev": true, + "dependencies": { + "isexe": "^2.0.0" + }, + "bin": { + "which": "bin/which" + } + }, + "node_modules/execa/node_modules/yallist": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-2.1.2.tgz", + "integrity": "sha512-ncTzHV7NvsQZkYe1DW7cbDLm0YpzHmZF5r/iyP3ZnQtMiJ+pjzisCiMNI+Sj+xQF5pXhSHxSB3uDbsBTzY/c2A==", + "dev": true + }, + "node_modules/executable": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/executable/-/executable-4.1.1.tgz", + "integrity": "sha512-8iA79xD3uAch729dUG8xaaBBFGaEa0wdD2VkYLFHwlqosEj/jT66AzcreRDSgV7ehnNLBW2WR5jIXwGKjVdTLg==", + "dev": true, + "dependencies": { + "pify": "^2.2.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/ext-list": { + "version": "2.2.2", + "resolved": "https://registry.npmjs.org/ext-list/-/ext-list-2.2.2.tgz", + "integrity": "sha512-u+SQgsubraE6zItfVA0tBuCBhfU9ogSRnsvygI7wht9TS510oLkBRXBsqopeUG/GBOIQyKZO9wjTqIu/sf5zFA==", + "dev": true, + "dependencies": { + "mime-db": "^1.28.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/ext-name": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/ext-name/-/ext-name-5.0.0.tgz", + "integrity": "sha512-yblEwXAbGv1VQDmow7s38W77hzAgJAO50ztBLMcUyUBfxv1HC+LGwtiEN+Co6LtlqT/5uwVOxsD4TNIilWhwdQ==", + "dev": true, + "dependencies": { + "ext-list": "^2.0.0", + "sort-keys-length": "^1.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "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==", + "dev": true + }, + "node_modules/fast-diff": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/fast-diff/-/fast-diff-1.3.0.tgz", + "integrity": "sha512-VxPP4NqbUjj6MaAOafWeUn2cXWLcCtljklUtZf0Ind4XQ+QPtmA0b18zZy0jIQx+ExRVCR/ZQpBmik5lXshNsw==", + "dev": true + }, + "node_modules/fast-glob": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.3.1.tgz", + "integrity": "sha512-kNFPyjhh5cKjrUltxs+wFx+ZkbRaxxmZ+X0ZU31SOsxCEtP9VPgtq2teZw1DebupL5GmDaNQ6yKMMVcM41iqDg==", + "dev": true, + "dependencies": { + "@nodelib/fs.stat": "^2.0.2", + "@nodelib/fs.walk": "^1.2.3", + "glob-parent": "^5.1.2", + "merge2": "^1.3.0", + "micromatch": "^4.0.4" + }, + "engines": { + "node": ">=8.6.0" + } + }, + "node_modules/fast-glob/node_modules/glob-parent": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", + "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", + "dev": true, + "dependencies": { + "is-glob": "^4.0.1" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/fast-json-stable-stringify": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz", + "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==", + "dev": true + }, + "node_modules/fast-levenshtein": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz", + "integrity": "sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==", + "dev": true + }, + "node_modules/fastq": { + "version": "1.15.0", + "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.15.0.tgz", + "integrity": "sha512-wBrocU2LCXXa+lWBt8RoIRD89Fi8OdABODa/kEnyeyjS5aZO5/GNvI5sEINADqP/h8M29UHTHUb53sUu5Ihqdw==", + "dev": true, + "dependencies": { + "reusify": "^1.0.4" + } + }, + "node_modules/file-entry-cache": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-6.0.1.tgz", + "integrity": "sha512-7Gps/XWymbLk2QLYK4NzpMOrYjMhdIxXuIvy2QBsLE6ljuodKvdkWs/cpyJJ3CVIVpH0Oi1Hvg1ovbMzLdFBBg==", + "dev": true, + "dependencies": { + "flat-cache": "^3.0.4" + }, + "engines": { + "node": "^10.12.0 || >=12.0.0" + } + }, + "node_modules/file-type": { + "version": "17.1.6", + "resolved": "https://registry.npmjs.org/file-type/-/file-type-17.1.6.tgz", + "integrity": "sha512-hlDw5Ev+9e883s0pwUsuuYNu4tD7GgpUnOvykjv1Gya0ZIjuKumthDRua90VUn6/nlRKAjcxLUnHNTIUWwWIiw==", + "dev": true, + "dependencies": { + "readable-web-to-node-stream": "^3.0.2", + "strtok3": "^7.0.0-alpha.9", + "token-types": "^5.0.0-alpha.2" + }, + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/sindresorhus/file-type?sponsor=1" + } + }, + "node_modules/filename-reserved-regex": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/filename-reserved-regex/-/filename-reserved-regex-3.0.0.tgz", + "integrity": "sha512-hn4cQfU6GOT/7cFHXBqeBg2TbrMBgdD0kcjLhvSQYYwm3s4B6cjvBfb7nBALJLAXqmU5xajSa7X2NnUud/VCdw==", + "dev": true, + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/filenamify": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/filenamify/-/filenamify-5.1.1.tgz", + "integrity": "sha512-M45CbrJLGACfrPOkrTp3j2EcO9OBkKUYME0eiqOCa7i2poaklU0jhlIaMlr8ijLorT0uLAzrn3qXOp5684CkfA==", + "dev": true, + "dependencies": { + "filename-reserved-regex": "^3.0.0", + "strip-outer": "^2.0.0", + "trim-repeated": "^2.0.0" + }, + "engines": { + "node": ">=12.20" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/fill-range": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz", + "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==", + "dev": true, + "dependencies": { + "to-regex-range": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/find-up": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz", + "integrity": "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==", + "dev": true, + "dependencies": { + "locate-path": "^6.0.0", + "path-exists": "^4.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/find-versions": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/find-versions/-/find-versions-5.1.0.tgz", + "integrity": "sha512-+iwzCJ7C5v5KgcBuueqVoNiHVoQpwiUK5XFLjf0affFTep+Wcw93tPvmb8tqujDNmzhBDPddnWV/qgWSXgq+Hg==", + "dev": true, + "dependencies": { + "semver-regex": "^4.0.5" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/flat": { + "version": "5.0.2", + "resolved": "https://registry.npmjs.org/flat/-/flat-5.0.2.tgz", + "integrity": "sha512-b6suED+5/3rTpUBdG1gupIl8MPFCAMA0QXwmljLhvCUKcUvdE4gWky9zpuGCcXHOsz4J9wPGNWq6OKpmIzz3hQ==", + "dev": true, + "bin": { + "flat": "cli.js" + } + }, + "node_modules/flat-cache": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-3.0.4.tgz", + "integrity": "sha512-dm9s5Pw7Jc0GvMYbshN6zchCA9RgQlzzEZX3vylR9IqFfS8XciblUXOKfW6SiuJ0e13eDYZoZV5wdrev7P3Nwg==", + "dev": true, + "dependencies": { + "flatted": "^3.1.0", + "rimraf": "^3.0.2" + }, + "engines": { + "node": "^10.12.0 || >=12.0.0" + } + }, + "node_modules/flat-cache/node_modules/rimraf": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz", + "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==", + "dev": true, + "dependencies": { + "glob": "^7.1.3" + }, + "bin": { + "rimraf": "bin.js" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/flatted": { + "version": "3.2.7", + "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.2.7.tgz", + "integrity": "sha512-5nqDSxl8nn5BSNxyR3n4I6eDmbolI6WT+QqR547RwxQapgjQBmtktdP+HTBb/a/zLsbzERTONyUB5pefh5TtjQ==", + "dev": true + }, + "node_modules/follow-redirects": { + "version": "1.15.2", + "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.2.tgz", + "integrity": "sha512-VQLG33o04KaQ8uYi2tVNbdrWp1QWxNNea+nmIB4EVM28v0hmP17z7aG1+wAkNzVq4KeXTq3221ye5qTJP91JwA==", + "funding": [ + { + "type": "individual", + "url": "https://github.com/sponsors/RubenVerborgh" + } + ], + "engines": { + "node": ">=4.0" + }, + "peerDependenciesMeta": { + "debug": { + "optional": true + } + } + }, + "node_modules/form-data": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.0.tgz", + "integrity": "sha512-ETEklSGi5t0QMZuiXoA/Q6vcnxcLQP5vdugSpuAyi6SVGi2clPPp+xgEhuMaHC+zGgn31Kd235W35f7Hykkaww==", + "dependencies": { + "asynckit": "^0.4.0", + "combined-stream": "^1.0.8", + "mime-types": "^2.1.12" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/fs.realpath": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", + "integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==", + "dev": true + }, + "node_modules/fsevents": { + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.2.tgz", + "integrity": "sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==", + "dev": true, + "hasInstallScript": true, + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^8.16.0 || ^10.6.0 || >=11.0.0" + } + }, + "node_modules/get-caller-file": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz", + "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==", + "dev": true, + "engines": { + "node": "6.* || 8.* || >= 10.*" + } + }, + "node_modules/get-func-name": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/get-func-name/-/get-func-name-2.0.0.tgz", + "integrity": "sha512-Hm0ixYtaSZ/V7C8FJrtZIuBBI+iSgL+1Aq82zSu8VQNB4S3Gk8e7Qs3VwBDJAhmRZcFqkl3tQu36g/Foh5I5ig==", + "dev": true, + "engines": { + "node": "*" + } + }, + "node_modules/get-stream": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-3.0.0.tgz", + "integrity": "sha512-GlhdIUuVakc8SJ6kK0zAFbiGzRFzNnY4jUuEbV9UROo4Y+0Ny4fjvcZFVTeDA4odpFyOQzaw6hXukJSq/f28sQ==", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/glob": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.0.tgz", + "integrity": "sha512-lmLf6gtyrPq8tTjSmrO94wBeQbFR3HbLHbuyD69wuyQkImp2hWqMGB47OX65FBkPffO641IP9jWa1z4ivqG26Q==", + "dev": true, + "dependencies": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.0.4", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + }, + "engines": { + "node": "*" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/glob-parent": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz", + "integrity": "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==", + "dev": true, + "dependencies": { + "is-glob": "^4.0.3" + }, + "engines": { + "node": ">=10.13.0" + } + }, + "node_modules/globals": { + "version": "13.20.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-13.20.0.tgz", + "integrity": "sha512-Qg5QtVkCy/kv3FUSlu4ukeZDVf9ee0iXLAUYX13gbR17bnejFTzr4iS9bY7kwCf1NztRNm1t91fjOiyx4CSwPQ==", + "dev": true, + "dependencies": { + "type-fest": "^0.20.2" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/globby": { + "version": "11.1.0", + "resolved": "https://registry.npmjs.org/globby/-/globby-11.1.0.tgz", + "integrity": "sha512-jhIXaOzy1sb8IyocaruWSn1TjmnBVs8Ayhcy83rmxNJ8q2uWKCAj3CnJY+KpGSXCueAPc0i05kVvVKtP1t9S3g==", + "dev": true, + "dependencies": { + "array-union": "^2.1.0", + "dir-glob": "^3.0.1", + "fast-glob": "^3.2.9", + "ignore": "^5.2.0", + "merge2": "^1.4.1", + "slash": "^3.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/got": { + "version": "11.8.6", + "resolved": "https://registry.npmjs.org/got/-/got-11.8.6.tgz", + "integrity": "sha512-6tfZ91bOr7bOXnK7PRDCGBLa1H4U080YHNaAQ2KsMGlLEzRbk44nsZF2E1IeRc3vtJHPVbKCYgdFbaGO2ljd8g==", + "dev": true, + "dependencies": { + "@sindresorhus/is": "^4.0.0", + "@szmarczak/http-timer": "^4.0.5", + "@types/cacheable-request": "^6.0.1", + "@types/responselike": "^1.0.0", + "cacheable-lookup": "^5.0.3", + "cacheable-request": "^7.0.2", + "decompress-response": "^6.0.0", + "http2-wrapper": "^1.0.0-beta.5.2", + "lowercase-keys": "^2.0.0", + "p-cancelable": "^2.0.0", + "responselike": "^2.0.0" + }, + "engines": { + "node": ">=10.19.0" + }, + "funding": { + "url": "https://github.com/sindresorhus/got?sponsor=1" + } + }, + "node_modules/graphemer": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/graphemer/-/graphemer-1.4.0.tgz", + "integrity": "sha512-EtKwoO6kxCL9WO5xipiHTZlSzBm7WLT627TqC/uVRd0HKmq8NXyebnNYxDoBi7wt8eTWrUrKXCOVaFq9x1kgag==", + "dev": true + }, + "node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/he": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/he/-/he-1.2.0.tgz", + "integrity": "sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw==", + "dev": true, + "bin": { + "he": "bin/he" + } + }, + "node_modules/http-cache-semantics": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/http-cache-semantics/-/http-cache-semantics-4.1.1.tgz", + "integrity": "sha512-er295DKPVsV82j5kw1Gjt+ADA/XYHsajl82cGNQG2eyoPkvgUhX+nDIyelzhIWbbsXP39EHcI6l5tYs2FYqYXQ==", + "dev": true + }, + "node_modules/http2-wrapper": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/http2-wrapper/-/http2-wrapper-1.0.3.tgz", + "integrity": "sha512-V+23sDMr12Wnz7iTcDeJr3O6AIxlnvT/bmaAAAP/Xda35C90p9599p0F1eHR/N1KILWSoWVAiOMFjBBXaXSMxg==", + "dev": true, + "dependencies": { + "quick-lru": "^5.1.1", + "resolve-alpn": "^1.0.0" + }, + "engines": { + "node": ">=10.19.0" + } + }, + "node_modules/human-signals": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/human-signals/-/human-signals-2.1.0.tgz", + "integrity": "sha512-B4FFZ6q/T2jhhksgkbEW3HBvWIfDW85snkQgawt07S7J5QXTk6BkNV+0yAeZrM5QpMAdYlocGoljn0sJ/WQkFw==", + "dev": true, + "engines": { + "node": ">=10.17.0" + } + }, + "node_modules/ieee754": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.2.1.tgz", + "integrity": "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ] + }, + "node_modules/ignore": { + "version": "5.2.4", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.2.4.tgz", + "integrity": "sha512-MAb38BcSbH0eHNBxn7ql2NH/kX33OkB3lZ1BNdh7ENeRChHTYsTvWrMubiIAMNS2llXEEgZ1MUOBtXChP3kaFQ==", + "dev": true, + "engines": { + "node": ">= 4" + } + }, + "node_modules/ignore-by-default": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/ignore-by-default/-/ignore-by-default-1.0.1.tgz", + "integrity": "sha512-Ius2VYcGNk7T90CppJqcIkS5ooHUZyIQK+ClZfMfMNFEF9VSE73Fq+906u/CWu92x4gzZMWOwfFYckPObzdEbA==", + "dev": true + }, + "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==", + "dev": true, + "dependencies": { + "parent-module": "^1.0.0", + "resolve-from": "^4.0.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/imurmurhash": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", + "integrity": "sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==", + "dev": true, + "engines": { + "node": ">=0.8.19" + } + }, + "node_modules/inflight": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", + "integrity": "sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==", + "dev": true, + "dependencies": { + "once": "^1.3.0", + "wrappy": "1" + } + }, + "node_modules/inherits": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", + "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", + "dev": true + }, + "node_modules/is-binary-path": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz", + "integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==", + "dev": true, + "dependencies": { + "binary-extensions": "^2.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/is-extglob": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", + "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-fullwidth-code-point": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", + "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/is-glob": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", + "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", + "dev": true, + "dependencies": { + "is-extglob": "^2.1.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-number": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", + "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", + "dev": true, + "engines": { + "node": ">=0.12.0" + } + }, + "node_modules/is-path-inside": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/is-path-inside/-/is-path-inside-3.0.3.tgz", + "integrity": "sha512-Fd4gABb+ycGAmKou8eMftCupSir5lRxqf4aD/vd0cD2qc4HL07OjCeuHMr8Ro4CoMaeCKDB0/ECBOVWjTwUvPQ==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "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==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-stream": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-1.1.0.tgz", + "integrity": "sha512-uQPm8kcs47jx38atAcWTVxyltQYoPT68y9aWYdV6yWXSyW8mzSat0TL6CiWdZeCdF3KrAvpVtnHbTv4RN+rqdQ==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-unicode-supported": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/is-unicode-supported/-/is-unicode-supported-0.1.0.tgz", + "integrity": "sha512-knxG2q4UC3u8stRGyAVJCOdxFmv5DZiRcdlIaAQXAbSfJya+OhopNotLQrstBhququ4ZpuKbDc/8S6mgXgPFPw==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/isexe": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", + "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==", + "dev": true + }, + "node_modules/js-yaml": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", + "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==", + "dev": true, + "dependencies": { + "argparse": "^2.0.1" + }, + "bin": { + "js-yaml": "bin/js-yaml.js" + } + }, + "node_modules/json-buffer": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/json-buffer/-/json-buffer-3.0.1.tgz", + "integrity": "sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ==", + "dev": true + }, + "node_modules/json-schema-traverse": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", + "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", + "dev": true + }, + "node_modules/json-stable-stringify-without-jsonify": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz", + "integrity": "sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==", + "dev": true + }, + "node_modules/keyv": { + "version": "4.5.3", + "resolved": "https://registry.npmjs.org/keyv/-/keyv-4.5.3.tgz", + "integrity": "sha512-QCiSav9WaX1PgETJ+SpNnx2PRRapJ/oRSXM4VO5OGYGSjrxbKPVFVhB3l2OCbLCk329N8qyAtsJjSjvVBWzEug==", + "dev": true, + "dependencies": { + "json-buffer": "3.0.1" + } + }, + "node_modules/levn": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz", + "integrity": "sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==", + "dev": true, + "dependencies": { + "prelude-ls": "^1.2.1", + "type-check": "~0.4.0" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/locate-path": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz", + "integrity": "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==", + "dev": true, + "dependencies": { + "p-locate": "^5.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "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==", + "dev": true + }, + "node_modules/lodash.merge": { + "version": "4.6.2", + "resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz", + "integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==", + "dev": true + }, + "node_modules/log-symbols": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-4.1.0.tgz", + "integrity": "sha512-8XPvpAA8uyhfteu8pIvQxpJZ7SYYdpUivZpGy6sFsBuKRY/7rQGavedeB8aK+Zkyq6upMFVL/9AW6vOYzfRyLg==", + "dev": true, + "dependencies": { + "chalk": "^4.1.0", + "is-unicode-supported": "^0.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/loupe": { + "version": "2.3.6", + "resolved": "https://registry.npmjs.org/loupe/-/loupe-2.3.6.tgz", + "integrity": "sha512-RaPMZKiMy8/JruncMU5Bt6na1eftNoo++R4Y+N2FrxkDVTrGvcyzFTsaGif4QTeKESheMGegbhw6iUAq+5A8zA==", + "dev": true, + "dependencies": { + "get-func-name": "^2.0.0" + } + }, + "node_modules/lowercase-keys": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/lowercase-keys/-/lowercase-keys-2.0.0.tgz", + "integrity": "sha512-tqNXrS78oMOE73NMxK4EMLQsQowWf8jKooH9g7xPavRT706R6bkQJ6DY2Te7QukaZsulxa30wQ7bk0pm4XiHmA==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/lru-cache": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", + "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", + "dev": true, + "dependencies": { + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/merge-stream": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/merge-stream/-/merge-stream-2.0.0.tgz", + "integrity": "sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==", + "dev": true + }, + "node_modules/merge2": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz", + "integrity": "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==", + "dev": true, + "engines": { + "node": ">= 8" + } + }, + "node_modules/micromatch": { + "version": "4.0.5", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.5.tgz", + "integrity": "sha512-DMy+ERcEW2q8Z2Po+WNXuw3c5YaUSFjAO5GsJqfEl7UjvtIuFKO6ZrKvcItdy98dwFI2N1tg3zNIdKaQT+aNdA==", + "dev": true, + "dependencies": { + "braces": "^3.0.2", + "picomatch": "^2.3.1" + }, + "engines": { + "node": ">=8.6" + } + }, + "node_modules/mime-db": { + "version": "1.52.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", + "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/mime-types": { + "version": "2.1.35", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz", + "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==", + "dependencies": { + "mime-db": "1.52.0" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/mimic-fn": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-2.1.0.tgz", + "integrity": "sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/mimic-response": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/mimic-response/-/mimic-response-1.0.1.tgz", + "integrity": "sha512-j5EctnkH7amfV/q5Hgmoal1g2QHFJRraOtmx0JpIqkxhBhI/lJSl1nMpQ45hVarwNETOoWEimndZ4QK0RHxuxQ==", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "dev": true, + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, + "node_modules/minipass": { + "version": "4.2.8", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-4.2.8.tgz", + "integrity": "sha512-fNzuVyifolSLFL4NzpF+wEF4qrgqaaKX0haXPQEdQ7NKAN+WecoKMHV09YcuL/DHxrUsYQOK3MiuDf7Ip2OXfQ==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/mocha": { + "version": "10.2.0", + "resolved": "https://registry.npmjs.org/mocha/-/mocha-10.2.0.tgz", + "integrity": "sha512-IDY7fl/BecMwFHzoqF2sg/SHHANeBoMMXFlS9r0OXKDssYE1M5O43wUY/9BVPeIvfH2zmEbBfseqN9gBQZzXkg==", + "dev": true, + "dependencies": { + "ansi-colors": "4.1.1", + "browser-stdout": "1.3.1", + "chokidar": "3.5.3", + "debug": "4.3.4", + "diff": "5.0.0", + "escape-string-regexp": "4.0.0", + "find-up": "5.0.0", + "glob": "7.2.0", + "he": "1.2.0", + "js-yaml": "4.1.0", + "log-symbols": "4.1.0", + "minimatch": "5.0.1", + "ms": "2.1.3", + "nanoid": "3.3.3", + "serialize-javascript": "6.0.0", + "strip-json-comments": "3.1.1", + "supports-color": "8.1.1", + "workerpool": "6.2.1", + "yargs": "16.2.0", + "yargs-parser": "20.2.4", + "yargs-unparser": "2.0.0" + }, + "bin": { + "_mocha": "bin/_mocha", + "mocha": "bin/mocha.js" + }, + "engines": { + "node": ">= 14.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/mochajs" + } + }, + "node_modules/mocha/node_modules/brace-expansion": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", + "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", + "dev": true, + "dependencies": { + "balanced-match": "^1.0.0" + } + }, + "node_modules/mocha/node_modules/minimatch": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-5.0.1.tgz", + "integrity": "sha512-nLDxIFRyhDblz3qMuq+SoRZED4+miJ/G+tdDrjkkkRnjAsBexeGpgjLEQ0blJy7rHhR2b93rhQY4SvyWu9v03g==", + "dev": true, + "dependencies": { + "brace-expansion": "^2.0.1" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/mocha/node_modules/ms": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", + "dev": true + }, + "node_modules/mocha/node_modules/supports-color": { + "version": "8.1.1", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz", + "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==", + "dev": true, + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/supports-color?sponsor=1" + } + }, + "node_modules/ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", + "dev": true + }, + "node_modules/nanoid": { + "version": "3.3.3", + "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.3.tgz", + "integrity": "sha512-p1sjXuopFs0xg+fPASzQ28agW1oHD7xDsd9Xkf3T15H3c/cifrFHVwrh74PdoklAPi+i7MdRsE47vm2r6JoB+w==", + "dev": true, + "bin": { + "nanoid": "bin/nanoid.cjs" + }, + "engines": { + "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1" + } + }, + "node_modules/natural-compare": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz", + "integrity": "sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==", + "dev": true + }, + "node_modules/natural-compare-lite": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/natural-compare-lite/-/natural-compare-lite-1.4.0.tgz", + "integrity": "sha512-Tj+HTDSJJKaZnfiuw+iaF9skdPpTo2GtEly5JHnWV/hfv2Qj/9RKsGISQtLh2ox3l5EAGw487hnBee0sIJ6v2g==", + "dev": true + }, + "node_modules/nodemon": { + "version": "2.0.21", + "resolved": "https://registry.npmjs.org/nodemon/-/nodemon-2.0.21.tgz", + "integrity": "sha512-djN/n2549DUtY33S7o1djRCd7dEm0kBnj9c7S9XVXqRUbuggN1MZH/Nqa+5RFQr63Fbefq37nFXAE9VU86yL1A==", + "dev": true, + "dependencies": { + "chokidar": "^3.5.2", + "debug": "^3.2.7", + "ignore-by-default": "^1.0.1", + "minimatch": "^3.1.2", + "pstree.remy": "^1.1.8", + "semver": "^5.7.1", + "simple-update-notifier": "^1.0.7", + "supports-color": "^5.5.0", + "touch": "^3.1.0", + "undefsafe": "^2.0.5" + }, + "bin": { + "nodemon": "bin/nodemon.js" + }, + "engines": { + "node": ">=8.10.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/nodemon" + } + }, + "node_modules/nodemon/node_modules/debug": { + "version": "3.2.7", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", + "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", + "dev": true, + "dependencies": { + "ms": "^2.1.1" + } + }, + "node_modules/nodemon/node_modules/has-flag": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", + "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/nodemon/node_modules/semver": { + "version": "5.7.2", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.2.tgz", + "integrity": "sha512-cBznnQ9KjJqU67B52RMC65CMarK2600WFnbkcaiwWq3xy/5haFJlshgnpjovMVJ+Hff49d8GEn0b87C5pDQ10g==", + "dev": true, + "bin": { + "semver": "bin/semver" + } + }, + "node_modules/nodemon/node_modules/supports-color": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", + "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", + "dev": true, + "dependencies": { + "has-flag": "^3.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/nopt": { + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/nopt/-/nopt-1.0.10.tgz", + "integrity": "sha512-NWmpvLSqUrgrAC9HCuxEvb+PSloHpqVu+FqcO4eeF2h5qYRhA7ev6KvelyQAKtegUbC6RypJnlEOhd8vloNKYg==", + "dev": true, + "dependencies": { + "abbrev": "1" + }, + "bin": { + "nopt": "bin/nopt.js" + }, + "engines": { + "node": "*" + } + }, + "node_modules/normalize-path": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", + "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/normalize-url": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/normalize-url/-/normalize-url-6.1.0.tgz", + "integrity": "sha512-DlL+XwOy3NxAQ8xuC0okPgK46iuVNAK01YN7RueYBqqFeGsBjV9XmCAzAdgt+667bCl5kPh9EqKKDwnaPG1I7A==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/npm-run-path": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-2.0.2.tgz", + "integrity": "sha512-lJxZYlT4DW/bRUtFh1MQIWqmLwQfAxnqWG4HhEdjMlkrJYnJn0Jrr2u3mgxqaWsdiBc76TYkTG/mhrnYTuzfHw==", + "dev": true, + "dependencies": { + "path-key": "^2.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/npm-run-path/node_modules/path-key": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/path-key/-/path-key-2.0.1.tgz", + "integrity": "sha512-fEHGKCSmUSDPv4uoj8AlD+joPlq3peND+HRYyxFz4KPw4z926S/b8rIuFs2FYJg3BwsxJf6A9/3eIdLaYC+9Dw==", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/once": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", + "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==", + "dev": true, + "dependencies": { + "wrappy": "1" + } + }, + "node_modules/onetime": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/onetime/-/onetime-5.1.2.tgz", + "integrity": "sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg==", + "dev": true, + "dependencies": { + "mimic-fn": "^2.1.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/optionator": { + "version": "0.9.3", + "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.3.tgz", + "integrity": "sha512-JjCoypp+jKn1ttEFExxhetCKeJt9zhAgAve5FXHixTvFDW/5aEktX9bufBKLRRMdU7bNtpLfcGu94B3cdEJgjg==", + "dev": true, + "dependencies": { + "@aashutoshrathi/word-wrap": "^1.2.3", + "deep-is": "^0.1.3", + "fast-levenshtein": "^2.0.6", + "levn": "^0.4.1", + "prelude-ls": "^1.2.1", + "type-check": "^0.4.0" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/os-filter-obj": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/os-filter-obj/-/os-filter-obj-2.0.0.tgz", + "integrity": "sha512-uksVLsqG3pVdzzPvmAHpBK0wKxYItuzZr7SziusRPoz67tGV8rL1szZ6IdeUrbqLjGDwApBtN29eEE3IqGHOjg==", + "dev": true, + "dependencies": { + "arch": "^2.1.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/p-cancelable": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/p-cancelable/-/p-cancelable-2.1.1.tgz", + "integrity": "sha512-BZOr3nRQHOntUjTrH8+Lh54smKHoHyur8We1V8DSMVrl5A2malOOwuJRnKRDjSnkoeBh4at6BwEnb5I7Jl31wg==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/p-finally": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/p-finally/-/p-finally-1.0.0.tgz", + "integrity": "sha512-LICb2p9CB7FS+0eR1oqWnHhp0FljGLZCWBE9aix0Uye9W8LTQPwMTYVGWQWIw9RdQiDg4+epXQODwIYJtSJaow==", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/p-limit": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz", + "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==", + "dev": true, + "dependencies": { + "yocto-queue": "^0.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/p-locate": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-5.0.0.tgz", + "integrity": "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==", + "dev": true, + "dependencies": { + "p-limit": "^3.0.2" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/parent-module": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz", + "integrity": "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==", + "dev": true, + "dependencies": { + "callsites": "^3.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/path-exists": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", + "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/path-is-absolute": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", + "integrity": "sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/path-key": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", + "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/path-scurry": { + "version": "1.10.1", + "resolved": "https://registry.npmjs.org/path-scurry/-/path-scurry-1.10.1.tgz", + "integrity": "sha512-MkhCqzzBEpPvxxQ71Md0b1Kk51W01lrYvlMzSUaIzNsODdd7mqhiimSZlr+VegAz5Z6Vzt9Xg2ttE//XBhH3EQ==", + "dev": true, + "dependencies": { + "lru-cache": "^9.1.1 || ^10.0.0", + "minipass": "^5.0.0 || ^6.0.2 || ^7.0.0" + }, + "engines": { + "node": ">=16 || 14 >=14.17" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/path-scurry/node_modules/lru-cache": { + "version": "10.0.0", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-10.0.0.tgz", + "integrity": "sha512-svTf/fzsKHffP42sujkO/Rjs37BCIsQVRCeNYIm9WN8rgT7ffoUnRtZCqU+6BqcSBdv8gwJeTz8knJpgACeQMw==", + "dev": true, + "engines": { + "node": "14 || >=16.14" + } + }, + "node_modules/path-scurry/node_modules/minipass": { + "version": "7.0.2", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-7.0.2.tgz", + "integrity": "sha512-eL79dXrE1q9dBbDCLg7xfn/vl7MS4F1gvJAgjJrQli/jbQWdUttuVawphqpffoIYfRdq78LHx6GP4bU/EQ2ATA==", + "dev": true, + "engines": { + "node": ">=16 || 14 >=14.17" + } + }, + "node_modules/path-type": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-type/-/path-type-4.0.0.tgz", + "integrity": "sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/pathval": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/pathval/-/pathval-1.1.1.tgz", + "integrity": "sha512-Dp6zGqpTdETdR63lehJYPeIOqpiNBNtc7BpWSLrOje7UaIsE5aY92r/AunQA7rsXvet3lrJ3JnZX29UPTKXyKQ==", + "dev": true, + "engines": { + "node": "*" + } + }, + "node_modules/peek-readable": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/peek-readable/-/peek-readable-5.0.0.tgz", + "integrity": "sha512-YtCKvLUOvwtMGmrniQPdO7MwPjgkFBtFIrmfSbYmYuq3tKDV/mcfAhBth1+C3ru7uXIZasc/pHnb+YDYNkkj4A==", + "dev": true, + "engines": { + "node": ">=14.16" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/Borewit" + } + }, + "node_modules/picomatch": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", + "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", + "dev": true, + "engines": { + "node": ">=8.6" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/pify": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz", + "integrity": "sha512-udgsAY+fTnvv7kI7aaxbqwWNb0AHiB0qBO89PZKPkoTmGOgdbrHDKD+0B2X4uTfJ/FT1R09r9gTsjUjNJotuog==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/pirates": { + "version": "4.0.6", + "resolved": "https://registry.npmjs.org/pirates/-/pirates-4.0.6.tgz", + "integrity": "sha512-saLsH7WeYYPiD25LDuLRRY/i+6HaPYr6G1OUlN39otzkSTxKnubR9RTxS3/Kk50s1g2JTgFwWQDQyplC5/SHZg==", + "dev": true, + "engines": { + "node": ">= 6" + } + }, + "node_modules/prelude-ls": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz", + "integrity": "sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==", + "dev": true, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/prettier": { + "version": "2.8.8", + "resolved": "https://registry.npmjs.org/prettier/-/prettier-2.8.8.tgz", + "integrity": "sha512-tdN8qQGvNjw4CHbY+XXk0JgCXn9QiF21a55rBe5LJAU+kDyC4WQn4+awm2Xfk2lQMk5fKup9XgzTZtGkjBdP9Q==", + "dev": true, + "bin": { + "prettier": "bin-prettier.js" + }, + "engines": { + "node": ">=10.13.0" + }, + "funding": { + "url": "https://github.com/prettier/prettier?sponsor=1" + } + }, + "node_modules/prettier-linter-helpers": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/prettier-linter-helpers/-/prettier-linter-helpers-1.0.0.tgz", + "integrity": "sha512-GbK2cP9nraSSUF9N2XwUwqfzlAFlMNYYl+ShE/V+H8a9uNl/oUqB1w2EL54Jh0OlyRSd8RfWYJ3coVS4TROP2w==", + "dev": true, + "dependencies": { + "fast-diff": "^1.1.2" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/proxy-from-env": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/proxy-from-env/-/proxy-from-env-1.1.0.tgz", + "integrity": "sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==" + }, + "node_modules/pseudomap": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/pseudomap/-/pseudomap-1.0.2.tgz", + "integrity": "sha512-b/YwNhb8lk1Zz2+bXXpS/LK9OisiZZ1SNsSLxN1x2OXVEhW2Ckr/7mWE5vrC1ZTiJlD9g19jWszTmJsB+oEpFQ==", + "dev": true + }, + "node_modules/pstree.remy": { + "version": "1.1.8", + "resolved": "https://registry.npmjs.org/pstree.remy/-/pstree.remy-1.1.8.tgz", + "integrity": "sha512-77DZwxQmxKnu3aR542U+X8FypNzbfJ+C5XQDk3uWjWxn6151aIMGthWYRXTqT1E5oJvg+ljaa2OJi+VfvCOQ8w==", + "dev": true + }, + "node_modules/pump": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/pump/-/pump-3.0.0.tgz", + "integrity": "sha512-LwZy+p3SFs1Pytd/jYct4wpv49HiYCqd9Rlc5ZVdk0V+8Yzv6jR5Blk3TRmPL1ft69TxP0IMZGJ+WPFU2BFhww==", + "dev": true, + "dependencies": { + "end-of-stream": "^1.1.0", + "once": "^1.3.1" + } + }, + "node_modules/punycode": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.0.tgz", + "integrity": "sha512-rRV+zQD8tVFys26lAGR9WUuS4iUAngJScM+ZRSKtvl5tKeZ2t5bvdNFdNHBW9FWR4guGHlgmsZ1G7BSm2wTbuA==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/queue-microtask": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz", + "integrity": "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ] + }, + "node_modules/quick-lru": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/quick-lru/-/quick-lru-5.1.1.tgz", + "integrity": "sha512-WuyALRjWPDGtt/wzJiadO5AXY+8hZ80hVpe6MyivgraREW751X3SbhRvG3eLKOYN+8VEvqLcf3wdnt44Z4S4SA==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/randombytes": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/randombytes/-/randombytes-2.1.0.tgz", + "integrity": "sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ==", + "dev": true, + "dependencies": { + "safe-buffer": "^5.1.0" + } + }, + "node_modules/readable-stream": { + "version": "3.6.2", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz", + "integrity": "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==", + "dev": true, + "dependencies": { + "inherits": "^2.0.3", + "string_decoder": "^1.1.1", + "util-deprecate": "^1.0.1" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/readable-web-to-node-stream": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/readable-web-to-node-stream/-/readable-web-to-node-stream-3.0.2.tgz", + "integrity": "sha512-ePeK6cc1EcKLEhJFt/AebMCLL+GgSKhuygrZ/GLaKZYEecIgIECf4UaUuaByiGtzckwR4ain9VzUh95T1exYGw==", + "dev": true, + "dependencies": { + "readable-stream": "^3.6.0" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/Borewit" + } + }, + "node_modules/readdirp": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz", + "integrity": "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==", + "dev": true, + "dependencies": { + "picomatch": "^2.2.1" + }, + "engines": { + "node": ">=8.10.0" + } + }, + "node_modules/remeda": { + "version": "1.24.0", + "resolved": "https://registry.npmjs.org/remeda/-/remeda-1.24.0.tgz", + "integrity": "sha512-tjLxwU4yLtvX8yHlePnE7CdQXRe2pKatlVY+AunqAQV5t9FNw1yuiIAqKpu6zevd+No5LQHEJ/HK3r3ZFK7KXg==" + }, + "node_modules/require-directory": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", + "integrity": "sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/resolve-alpn": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/resolve-alpn/-/resolve-alpn-1.2.1.tgz", + "integrity": "sha512-0a1F4l73/ZFZOakJnQ3FvkJ2+gSTQWz/r2KE5OdDY0TxPm5h4GkqkWWfM47T7HsbnOtcJVEF4epCVy6u7Q3K+g==", + "dev": true + }, + "node_modules/resolve-from": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz", + "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/responselike": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/responselike/-/responselike-2.0.1.tgz", + "integrity": "sha512-4gl03wn3hj1HP3yzgdI7d3lCkF95F21Pz4BPGvKHinyQzALR5CapwC8yIi0Rh58DEMQ/SguC03wFj2k0M/mHhw==", + "dev": true, + "dependencies": { + "lowercase-keys": "^2.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/reusify": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.0.4.tgz", + "integrity": "sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==", + "dev": true, + "engines": { + "iojs": ">=1.0.0", + "node": ">=0.10.0" + } + }, + "node_modules/rimraf": { + "version": "4.4.1", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-4.4.1.tgz", + "integrity": "sha512-Gk8NlF062+T9CqNGn6h4tls3k6T1+/nXdOcSZVikNVtlRdYpA7wRJJMoXmuvOnLW844rPjdQ7JgXCYM6PPC/og==", + "dev": true, + "dependencies": { + "glob": "^9.2.0" + }, + "bin": { + "rimraf": "dist/cjs/src/bin.js" + }, + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/rimraf/node_modules/brace-expansion": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", + "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", + "dev": true, + "dependencies": { + "balanced-match": "^1.0.0" + } + }, + "node_modules/rimraf/node_modules/glob": { + "version": "9.3.5", + "resolved": "https://registry.npmjs.org/glob/-/glob-9.3.5.tgz", + "integrity": "sha512-e1LleDykUz2Iu+MTYdkSsuWX8lvAjAcs0Xef0lNIu0S2wOAzuTxCJtcd9S3cijlwYF18EsU3rzb8jPVobxDh9Q==", + "dev": true, + "dependencies": { + "fs.realpath": "^1.0.0", + "minimatch": "^8.0.2", + "minipass": "^4.2.4", + "path-scurry": "^1.6.1" + }, + "engines": { + "node": ">=16 || 14 >=14.17" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/rimraf/node_modules/minimatch": { + "version": "8.0.4", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-8.0.4.tgz", + "integrity": "sha512-W0Wvr9HyFXZRGIDgCicunpQ299OKXs9RgZfaukz4qAW/pJhcpUfupc9c+OObPOFueNy8VSrZgEmDtk6Kh4WzDA==", + "dev": true, + "dependencies": { + "brace-expansion": "^2.0.1" + }, + "engines": { + "node": ">=16 || 14 >=14.17" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/run-parallel": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz", + "integrity": "sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "dependencies": { + "queue-microtask": "^1.2.2" + } + }, + "node_modules/safe-buffer": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", + "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ] + }, + "node_modules/semver": { + "version": "7.5.4", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.5.4.tgz", + "integrity": "sha512-1bCSESV6Pv+i21Hvpxp3Dx+pSD8lIPt8uVjRrxAUt/nbswYc+tK6Y2btiULjd4+fnq15PX+nqQDC7Oft7WkwcA==", + "dev": true, + "dependencies": { + "lru-cache": "^6.0.0" + }, + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/semver-regex": { + "version": "4.0.5", + "resolved": "https://registry.npmjs.org/semver-regex/-/semver-regex-4.0.5.tgz", + "integrity": "sha512-hunMQrEy1T6Jr2uEVjrAIqjwWcQTgOAcIM52C8MY1EZSD3DDNft04XzvYKPqjED65bNVVko0YI38nYeEHCX3yw==", + "dev": true, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/semver-truncate": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/semver-truncate/-/semver-truncate-3.0.0.tgz", + "integrity": "sha512-LJWA9kSvMolR51oDE6PN3kALBNaUdkxzAGcexw8gjMA8xr5zUqK0JiR3CgARSqanYF3Z1YHvsErb1KDgh+v7Rg==", + "dev": true, + "dependencies": { + "semver": "^7.3.5" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/serialize-javascript": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-6.0.0.tgz", + "integrity": "sha512-Qr3TosvguFt8ePWqsvRfrKyQXIiW+nGbYpy8XK24NQHE83caxWt+mIymTT19DGFbNWNLfEwsrkSmN64lVWB9ag==", + "dev": true, + "dependencies": { + "randombytes": "^2.1.0" + } + }, + "node_modules/shebang-command": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", + "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", + "dev": true, + "dependencies": { + "shebang-regex": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/shebang-regex": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", + "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/signal-exit": { + "version": "3.0.7", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz", + "integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==", + "dev": true + }, + "node_modules/simple-update-notifier": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/simple-update-notifier/-/simple-update-notifier-1.1.0.tgz", + "integrity": "sha512-VpsrsJSUcJEseSbMHkrsrAVSdvVS5I96Qo1QAQ4FxQ9wXFcB+pjj7FB7/us9+GcgfW4ziHtYMc1J0PLczb55mg==", + "dev": true, + "dependencies": { + "semver": "~7.0.0" + }, + "engines": { + "node": ">=8.10.0" + } + }, + "node_modules/simple-update-notifier/node_modules/semver": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.0.0.tgz", + "integrity": "sha512-+GB6zVA9LWh6zovYQLALHwv5rb2PHGlJi3lfiqIHxR0uuwCgefcOJc59v9fv1w8GbStwxuuqqAjI9NMAOOgq1A==", + "dev": true, + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/slash": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz", + "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/sort-keys": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/sort-keys/-/sort-keys-1.1.2.tgz", + "integrity": "sha512-vzn8aSqKgytVik0iwdBEi+zevbTYZogewTUM6dtpmGwEcdzbub/TX4bCzRhebDCRC3QzXgJsLRKB2V/Oof7HXg==", + "dev": true, + "dependencies": { + "is-plain-obj": "^1.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/sort-keys-length": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/sort-keys-length/-/sort-keys-length-1.0.1.tgz", + "integrity": "sha512-GRbEOUqCxemTAk/b32F2xa8wDTs+Z1QHOkbhJDQTvv/6G3ZkbJ+frYWsTcc7cBB3Fu4wy4XlLCuNtJuMn7Gsvw==", + "dev": true, + "dependencies": { + "sort-keys": "^1.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/source-map": { + "version": "0.7.4", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.7.4.tgz", + "integrity": "sha512-l3BikUxvPOcn5E74dZiq5BGsTb5yEwhaTSzccU6t4sDOH8NWJCstKO5QT2CvtFoK6F0saL7p9xHAqHOlCPJygA==", + "dev": true, + "engines": { + "node": ">= 8" + } + }, + "node_modules/source-map-support": { + "version": "0.5.21", + "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.21.tgz", + "integrity": "sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w==", + "dev": true, + "dependencies": { + "buffer-from": "^1.0.0", + "source-map": "^0.6.0" + } + }, + "node_modules/source-map-support/node_modules/source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/string_decoder": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz", + "integrity": "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==", + "dev": true, + "dependencies": { + "safe-buffer": "~5.2.0" + } + }, + "node_modules/string-width": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "dev": true, + "dependencies": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/strip-ansi": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "dev": true, + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/strip-eof": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/strip-eof/-/strip-eof-1.0.0.tgz", + "integrity": "sha512-7FCwGGmx8mD5xQd3RPUvnSpUXHM3BWuzjtpD4TXsfcZ9EL4azvVVUscFYwD9nx8Kh+uCBC00XBtAykoMHwTh8Q==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/strip-final-newline": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/strip-final-newline/-/strip-final-newline-2.0.0.tgz", + "integrity": "sha512-BrpvfNAE3dcvq7ll3xVumzjKjZQ5tI1sEUIKr3Uoks0XUl45St3FlatVqef9prk4jRDzhW6WZg+3bk93y6pLjA==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/strip-json-comments": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz", + "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==", + "dev": true, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/strip-outer": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/strip-outer/-/strip-outer-2.0.0.tgz", + "integrity": "sha512-A21Xsm1XzUkK0qK1ZrytDUvqsQWict2Cykhvi0fBQntGG5JSprESasEyV1EZ/4CiR5WB5KjzLTrP/bO37B0wPg==", + "dev": true, + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/strtok3": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/strtok3/-/strtok3-7.0.0.tgz", + "integrity": "sha512-pQ+V+nYQdC5H3Q7qBZAz/MO6lwGhoC2gOAjuouGf/VO0m7vQRh8QNMl2Uf6SwAtzZ9bOw3UIeBukEGNJl5dtXQ==", + "dev": true, + "dependencies": { + "@tokenizer/token": "^0.3.0", + "peek-readable": "^5.0.0" + }, + "engines": { + "node": ">=14.16" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/Borewit" + } + }, + "node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "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/to-regex-range": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", + "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", + "dev": true, + "dependencies": { + "is-number": "^7.0.0" + }, + "engines": { + "node": ">=8.0" + } + }, + "node_modules/token-types": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/token-types/-/token-types-5.0.1.tgz", + "integrity": "sha512-Y2fmSnZjQdDb9W4w4r1tswlMHylzWIeOKpx0aZH9BgGtACHhrk3OkT52AzwcuqTRBZtvvnTjDBh8eynMulu8Vg==", + "dev": true, + "dependencies": { + "@tokenizer/token": "^0.3.0", + "ieee754": "^1.2.1" + }, + "engines": { + "node": ">=14.16" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/Borewit" + } + }, + "node_modules/touch": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/touch/-/touch-3.1.0.tgz", + "integrity": "sha512-WBx8Uy5TLtOSRtIq+M03/sKDrXCLHxwDcquSP2c43Le03/9serjQBIztjRz6FkJez9D/hleyAXTBGLwwZUw9lA==", + "dev": true, + "dependencies": { + "nopt": "~1.0.10" + }, + "bin": { + "nodetouch": "bin/nodetouch.js" + } + }, + "node_modules/trim-repeated": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/trim-repeated/-/trim-repeated-2.0.0.tgz", + "integrity": "sha512-QUHBFTJGdOwmp0tbOG505xAgOp/YliZP/6UgafFXYZ26WT1bvQmSMJUvkeVSASuJJHbqsFbynTvkd5W8RBTipg==", + "dev": true, + "dependencies": { + "escape-string-regexp": "^5.0.0" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/trim-repeated/node_modules/escape-string-regexp": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-5.0.0.tgz", + "integrity": "sha512-/veY75JbMK4j1yjvuUxuVsiS/hr/4iHs9FTT6cgTexxdE0Ly/glccBAkloH/DofkjRbZU3bnoj38mOmhkZ0lHw==", + "dev": true, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/tslib": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", + "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==", + "dev": true + }, + "node_modules/tsutils": { + "version": "3.21.0", + "resolved": "https://registry.npmjs.org/tsutils/-/tsutils-3.21.0.tgz", + "integrity": "sha512-mHKK3iUXL+3UF6xL5k0PEhKRUBKPBCv/+RkEOpjRWxxx27KKRBmmA60A9pgOUvMi8GKhRMPEmjBRPzs2W7O1OA==", + "dev": true, + "dependencies": { + "tslib": "^1.8.1" + }, + "engines": { + "node": ">= 6" + }, + "peerDependencies": { + "typescript": ">=2.8.0 || >= 3.2.0-dev || >= 3.3.0-dev || >= 3.4.0-dev || >= 3.5.0-dev || >= 3.6.0-dev || >= 3.6.0-beta || >= 3.7.0-dev || >= 3.7.0-beta" + } + }, + "node_modules/type-check": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz", + "integrity": "sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==", + "dev": true, + "dependencies": { + "prelude-ls": "^1.2.1" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/type-detect": { + "version": "4.0.8", + "resolved": "https://registry.npmjs.org/type-detect/-/type-detect-4.0.8.tgz", + "integrity": "sha512-0fr/mIH1dlO+x7TlcMy+bIDqKPsw/70tVyeHW787goQjhmqaZe10uwLujubK9q9Lg6Fiho1KUKDYz0Z7k7g5/g==", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/type-fest": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.20.2.tgz", + "integrity": "sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/typescript": { + "version": "4.9.5", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.9.5.tgz", + "integrity": "sha512-1FXk9E2Hm+QzZQ7z+McJiHL4NW1F2EzMu9Nq9i3zAaGqibafqYwCVU6WyWAuyQRRzOlxou8xZSyXLEN8oKj24g==", + "dev": true, + "bin": { + "tsc": "bin/tsc", + "tsserver": "bin/tsserver" + }, + "engines": { + "node": ">=4.2.0" + } + }, + "node_modules/undefsafe": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/undefsafe/-/undefsafe-2.0.5.tgz", + "integrity": "sha512-WxONCrssBM8TSPRqN5EmsjVrsv4A8X12J4ArBiiayv3DyyG3ZlIg6yysuuSYdZsVz3TKcTg2fd//Ujd4CHV1iA==", + "dev": true + }, + "node_modules/uri-js": { + "version": "4.4.1", + "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz", + "integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==", + "dev": true, + "dependencies": { + "punycode": "^2.1.0" + } + }, + "node_modules/util-deprecate": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", + "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==", + "dev": true + }, + "node_modules/uuid": { + "version": "9.0.0", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-9.0.0.tgz", + "integrity": "sha512-MXcSTerfPa4uqyzStbRoTgt5XIe3x5+42+q1sDuy3R5MDk66URdLMOZe5aPX/SQd+kuYAh0FdP/pO28IkQyTeg==", + "bin": { + "uuid": "dist/bin/uuid" + } + }, + "node_modules/which": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", + "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", + "dev": true, + "dependencies": { + "isexe": "^2.0.0" + }, + "bin": { + "node-which": "bin/node-which" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/workerpool": { + "version": "6.2.1", + "resolved": "https://registry.npmjs.org/workerpool/-/workerpool-6.2.1.tgz", + "integrity": "sha512-ILEIE97kDZvF9Wb9f6h5aXK4swSlKGUcOEGiIYb2OOu/IrDU9iwj0fD//SsA6E5ibwJxpEvhullJY4Sl4GcpAw==", + "dev": true + }, + "node_modules/wrap-ansi": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", + "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", + "dev": true, + "dependencies": { + "ansi-styles": "^4.0.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/wrap-ansi?sponsor=1" + } + }, + "node_modules/wrappy": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", + "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==", + "dev": true + }, + "node_modules/y18n": { + "version": "5.0.8", + "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz", + "integrity": "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==", + "dev": true, + "engines": { + "node": ">=10" + } + }, + "node_modules/yallist": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", + "dev": true + }, + "node_modules/yargs": { + "version": "16.2.0", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-16.2.0.tgz", + "integrity": "sha512-D1mvvtDG0L5ft/jGWkLpG1+m0eQxOfaBvTNELraWj22wSVUMWxZUvYgJYcKh6jGGIkJFhH4IZPQhR4TKpc8mBw==", + "dev": true, + "dependencies": { + "cliui": "^7.0.2", + "escalade": "^3.1.1", + "get-caller-file": "^2.0.5", + "require-directory": "^2.1.1", + "string-width": "^4.2.0", + "y18n": "^5.0.5", + "yargs-parser": "^20.2.2" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/yargs-parser": { + "version": "20.2.4", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-20.2.4.tgz", + "integrity": "sha512-WOkpgNhPTlE73h4VFAFsOnomJVaovO8VqLDzy5saChRBFQFBoMYirowyW+Q9HB4HFF4Z7VZTiG3iSzJJA29yRA==", + "dev": true, + "engines": { + "node": ">=10" + } + }, + "node_modules/yargs-unparser": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/yargs-unparser/-/yargs-unparser-2.0.0.tgz", + "integrity": "sha512-7pRTIA9Qc1caZ0bZ6RYRGbHJthJWuakf+WmHK0rVeLkNrrGhfoabBNdue6kdINI6r4if7ocq9aD/n7xwKOdzOA==", + "dev": true, + "dependencies": { + "camelcase": "^6.0.0", + "decamelize": "^4.0.0", + "flat": "^5.0.2", + "is-plain-obj": "^2.1.0" + }, + "engines": { + "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/yocto-queue": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz", + "integrity": "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + } + } +} diff --git a/package.json b/package.json new file mode 100644 index 0000000..6483951 --- /dev/null +++ b/package.json @@ -0,0 +1,65 @@ +{ + "name": "@monti-apm/agent", + "version": "0.0.1", + "description": "Monti APM Agent", + "main": "./dist/", + "scripts": { + "clean": "rimraf dist", + "build": "swc src --out-dir=dist", + "types": "tsc --emitDeclarationOnly --declaration --outDir dist", + "lint": "eslint src --cache", + "lintfix": "eslint src --fix", + "test:dist": "mocha 'dist/**/*.test.js' --exit --watch=false", + "test": "mocha src/**/*.test.js --require=@swc/register --exit --watch=false", + "test:watch": "nodemon --exec 'npm run test' -e js --watch src", + "prepublishOnly": "npm run clean && npm run build && npm run types" + }, + "repository": { + "type": "git", + "url": "git+https://github.com/monti-apm/monti-apm-core.git" + }, + "keywords": [ + "kadira", + "monti apm", + "monti apm agent", + "node agent", + "apm" + ], + "author": "Monti APM", + "license": "MIT", + "bugs": { + "url": "https://github.com/monti-apm/node-agent/issues" + }, + "homepage": "https://github.com/monti-apm/node-agent#readme", + "devDependencies": { + "@swc/cli": "^0.1.62", + "@swc/core": "^1.3.71", + "@swc/register": "^0.1.10", + "@types/backoff": "^2.5.2", + "@types/chai": "^4.3.4", + "@types/debug": "^4.1.8", + "@types/mocha": "^10.0.1", + "@types/uuid": "^9.0.2", + "@types/websocket": "^1.0.5", + "@typescript-eslint/eslint-plugin": "5.62.0", + "@typescript-eslint/parser": "5.62.0", + "chai": "4.3.7", + "eslint": "8.45.0", + "eslint-config-prettier": "8.8.0", + "eslint-plugin-prettier": "4.2.1", + "mocha": "10.2.0", + "nodemon": "2.0.21", + "prettier": "2.8.8", + "rimraf": "4.4.1", + "typescript": "4.9.5" + }, + "dependencies": { + "axios": "1.4.0", + "eventemitter2": "6.4.9", + "remeda": "1.24.0", + "uuid": "9.0.0" + }, + "volta": { + "node": "20.5.0" + } +} diff --git a/tsconfig.json b/tsconfig.json new file mode 100644 index 0000000..e6da139 --- /dev/null +++ b/tsconfig.json @@ -0,0 +1,38 @@ +{ + "compilerOptions": { + "strict": true, + "allowJs": true, + "allowSyntheticDefaultImports": true, + "allowUnreachableCode": true, + "declaration": true, + "esModuleInterop": true, + "incremental": true, + "module": "CommonJS", + "moduleResolution": "node", + "noImplicitAny": false, + "noUnusedLocals": false, + "outDir": "./dist", + "resolveJsonModule": true, + "skipLibCheck": true, + "sourceMap": true, + "target": "ES5", + "baseUrl": ".", + "paths": { + "@/*": [ + "./src/*" + ] + }, + "typeRoots": [ + "./node_modules/@types", + "./src/@types" + ] + }, + "include": [ + "src" + ], + "exclude": [ + "src/tests", + "**/*.test.js", + "**/*.test.ts" + ] +} From ab060c6172819ba226400c172bfd312a975233b7 Mon Sep 17 00:00:00 2001 From: Leonardo Venturini Date: Fri, 4 Aug 2023 11:13:37 -0400 Subject: [PATCH 04/37] add webstorm settings file --- .editorconfig | 2 ++ .idea/git_toolbox_prj.xml | 15 +++++++++++++++ 2 files changed, 17 insertions(+) create mode 100644 .editorconfig create mode 100644 .idea/git_toolbox_prj.xml diff --git a/.editorconfig b/.editorconfig new file mode 100644 index 0000000..e9d21fd --- /dev/null +++ b/.editorconfig @@ -0,0 +1,2 @@ +[*] +indent_size = 2 \ No newline at end of file diff --git a/.idea/git_toolbox_prj.xml b/.idea/git_toolbox_prj.xml new file mode 100644 index 0000000..02b915b --- /dev/null +++ b/.idea/git_toolbox_prj.xml @@ -0,0 +1,15 @@ + + + + + + + \ No newline at end of file From 82d6c0da1439fa443fdae5e7d6a1a1e36aa0d9ca Mon Sep 17 00:00:00 2001 From: Leonardo Venturini Date: Fri, 4 Aug 2023 11:27:55 -0400 Subject: [PATCH 05/37] adjust description --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 6483951..19b18c8 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "@monti-apm/agent", "version": "0.0.1", - "description": "Monti APM Agent", + "description": "Performance Monitoring for Node.js", "main": "./dist/", "scripts": { "clean": "rimraf dist", From d426f12d338b49dd8ef27f515f697b24c5012388 Mon Sep 17 00:00:00 2001 From: Leonardo Venturini Date: Fri, 4 Aug 2023 12:42:52 -0400 Subject: [PATCH 06/37] add plan --- README.md | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/README.md b/README.md index 734a484..af0ce4a 100644 --- a/README.md +++ b/README.md @@ -1 +1,13 @@ # Node.js Agent + +What we should track: + +- [ ] Node.js version +- [ ] Node.js agent version +- [ ] Hosts +- [ ] CPU +- [ ] Memory +- [ ] Event Loop Latency +- [ ] Garbage Collection Duration + +Most of these might be shared between the Meteor Agent so probably should be in the core library. \ No newline at end of file From dbe31f2bfcf46ac2c0611847e1f81c283301fd7c Mon Sep 17 00:00:00 2001 From: Leonardo Venturini Date: Tue, 15 Aug 2023 09:15:52 -0400 Subject: [PATCH 07/37] add event loop monitor --- src/event-loop-monitor.ts | 116 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 116 insertions(+) create mode 100644 src/event-loop-monitor.ts diff --git a/src/event-loop-monitor.ts b/src/event-loop-monitor.ts new file mode 100644 index 0000000..c60c904 --- /dev/null +++ b/src/event-loop-monitor.ts @@ -0,0 +1,116 @@ +import { EventEmitter } from 'events'; + +function isNode () { + return typeof process !== 'undefined' && process.versions && process.versions.node; +} + +function polyfillNow () { + const [seconds, nanoseconds] = process.hrtime(); + + return seconds * 1000 + nanoseconds / 1000000; +} + +export class EventLoopMonitor extends EventEmitter { + timeoutMillis = 0; + _stopped = true; + _startTime: number | null = null; + _totalLag = 0; + _lastWatchTime: number | null = null; + + constructor (timeoutMillis: number) { + super(); + this.timeoutMillis = timeoutMillis; + this._watchLag = this._watchLag.bind(this); + this._stopped = true; + this._startTime = null; + this._totalLag = 0; + + this._registerNowFunc(); + } + + start () { + this._stopped = false; + this._lastWatchTime = null; + this._startTime = Date.now(); + this._totalLag = 0; + + this.on('lag', this._watchLag); + this._detectLag(); + } + + stop () { + this._stopped = true; + this.removeAllListeners('lag'); + } + + status () { + let pctBlock = 0; + let elapsedTime = 0; + if (!this._stopped && this._lastWatchTime) { + elapsedTime = this._lastWatchTime - (this._startTime as number); + pctBlock = (this._totalLag / elapsedTime) * 100; + } + + let statusObject = { + pctBlock, + elapsedTime, + totalLag: this._totalLag + }; + + this._startTime = this._lastWatchTime; + this._totalLag = 0; + + return statusObject; + } + + _watchLag (lag) { + this._lastWatchTime = Date.now(); + this._totalLag += lag; + } + + _detectLag () { + let self = this; + let start = self._now(); + + setTimeout(function () { + let end = self._now(); + let elapsedTime = end - start; + let realDiff = elapsedTime - self.timeoutMillis; + let lag = Math.max(0, realDiff); + + if (!self._stopped) { + self.emit('lag', lag); + self._detectLag(); + } + }, self.timeoutMillis); + } + + _now (): number { + throw new Error('Not Implemented'); + } + + _registerNowFunc () { + if (isNode()) { + const [major] = process.versions.node.split('.').map(Number); + + if (major < 8) { + this._now = polyfillNow; + return; + } + + const { + performance + // eslint-disable-next-line global-require + } = require('perf_hooks'); + this._now = performance.now; + return; + } + + if (typeof window !== 'undefined' && window.performance && window.performance.now) { + this._now = window.performance.now; + return; + } + + this._now = Date.now; + } +} From 93f85c8ef265fc61854951608282afc9c914422e Mon Sep 17 00:00:00 2001 From: Leonardo Venturini Date: Tue, 15 Aug 2023 09:16:04 -0400 Subject: [PATCH 08/37] add ide configs --- .editorconfig | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/.editorconfig b/.editorconfig index e9d21fd..214c188 100644 --- a/.editorconfig +++ b/.editorconfig @@ -1,2 +1,10 @@ [*] -indent_size = 2 \ No newline at end of file +indent_size = 2 +ij_any_spaces_within_braces = true +ij_javascript_spaces_within_imports = true +ij_typescript_spaces_within_imports = true +ij_javascript_import_sort_members = true +ij_typescript_import_sort_members = true +max_line_length = 80 +ij_javascript_force_semicolon_style = true +ij_typescript_force_semicolon_style = true \ No newline at end of file From a692a60db1db183963c580ac70b496f2a00e1da2 Mon Sep 17 00:00:00 2001 From: Leonardo Venturini Date: Tue, 15 Aug 2023 09:16:17 -0400 Subject: [PATCH 09/37] add gc --- src/gc.ts | 61 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 61 insertions(+) create mode 100644 src/gc.ts diff --git a/src/gc.ts b/src/gc.ts new file mode 100644 index 0000000..8a389b5 --- /dev/null +++ b/src/gc.ts @@ -0,0 +1,61 @@ +import { PerformanceObserver, constants, performance } from 'perf_hooks'; + +export class GCMetrics { + observer?: PerformanceObserver; + started: boolean = false; + metrics: Record; + + constructor () { + this.metrics = {}; + + this.reset(); + } + + start () { + if (this.started) { + return false; + } + + this.started = true; + + this.observer = new PerformanceObserver(list => { + list.getEntries().forEach(entry => { + // @ts-ignore @todo check if kind is still a thing + let metric = this._mapKindToMetric(entry.kind); + + if (!metric) { + return; + } + + this.metrics[metric] += entry.duration; + }); + }); + + this.observer.observe({ entryTypes: ['gc'], buffered: false }); + } + + _mapKindToMetric (gcKind: number): string | undefined { + switch (gcKind) { + case constants.NODE_PERFORMANCE_GC_MAJOR: + return 'gcMajor'; + case constants.NODE_PERFORMANCE_GC_MINOR: + return 'gcMinor'; + case constants.NODE_PERFORMANCE_GC_INCREMENTAL: + return 'gcIncremental'; + case constants.NODE_PERFORMANCE_GC_WEAKCB: + return 'gcWeakCB'; + default: + // no default + console.log(`Monti APM: Unrecognized GC Kind: ${gcKind}`); + } + } + + reset () { + this.metrics = { + gcMajor: 0, + gcMinor: 0, + gcIncremental: 0, + gcWeakCB: 0 + }; + } +} From e1d2ec3b98c7e824bee80437b041af03ca230e3c Mon Sep 17 00:00:00 2001 From: Leonardo Venturini Date: Tue, 15 Aug 2023 09:16:26 -0400 Subject: [PATCH 10/37] add version supported note --- README.md | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index af0ce4a..37a33ab 100644 --- a/README.md +++ b/README.md @@ -10,4 +10,8 @@ What we should track: - [ ] Event Loop Latency - [ ] Garbage Collection Duration -Most of these might be shared between the Meteor Agent so probably should be in the core library. \ No newline at end of file +Most of these might be shared between the Meteor Agent so probably should be in the core library. + +# Supported Versions + +Node.js 12 and above. \ No newline at end of file From d629fc53b9be7416138860ccd745e31552d4725b Mon Sep 17 00:00:00 2001 From: Leonardo Venturini Date: Tue, 15 Aug 2023 09:16:36 -0400 Subject: [PATCH 11/37] add packages --- package-lock.json | 42 +++++++++++++++++++++++++++++++++++++----- package.json | 3 +++ 2 files changed, 40 insertions(+), 5 deletions(-) diff --git a/package-lock.json b/package-lock.json index dbf3cde..e410297 100644 --- a/package-lock.json +++ b/package-lock.json @@ -11,6 +11,8 @@ "dependencies": { "axios": "1.4.0", "eventemitter2": "6.4.9", + "monti-apm-core": "^1.7.5", + "monti-apm-sketches-js": "^0.0.3", "remeda": "1.24.0", "uuid": "9.0.0" }, @@ -22,6 +24,7 @@ "@types/chai": "^4.3.4", "@types/debug": "^4.1.8", "@types/mocha": "^10.0.1", + "@types/node": "^20.5.0", "@types/uuid": "^9.0.2", "@types/websocket": "^1.0.5", "@typescript-eslint/eslint-plugin": "5.62.0", @@ -531,9 +534,9 @@ "dev": true }, "node_modules/@types/node": { - "version": "20.4.7", - "resolved": "https://registry.npmjs.org/@types/node/-/node-20.4.7.tgz", - "integrity": "sha512-bUBrPjEry2QUTsnuEjzjbS7voGWCc30W0qzgMf90GPeDGFRakvrz47ju+oqDAKCXLUCe39u57/ORMl/O/04/9g==", + "version": "20.5.0", + "resolved": "https://registry.npmjs.org/@types/node/-/node-20.5.0.tgz", + "integrity": "sha512-Mgq7eCtoTjT89FqNoTzzXg2XvCi5VMhRV6+I2aYanc6kQCBImeNaAYRs/DyoVqk1YEUJK5gN9VO7HRIdz4Wo3Q==", "dev": true }, "node_modules/@types/responselike": { @@ -2681,11 +2684,40 @@ "url": "https://github.com/chalk/supports-color?sponsor=1" } }, + "node_modules/monti-apm-core": { + "version": "1.7.5", + "resolved": "https://registry.npmjs.org/monti-apm-core/-/monti-apm-core-1.7.5.tgz", + "integrity": "sha512-IYHB3PF5h8HFQDQ0N2h3wyIdCo412YtkURiYgc9tgW2PAppGlMQk9U8ESBFgpi/I31yeP9ilw5Yb03Mgf1ND4Q==", + "dependencies": { + "axios": "^0.21.4", + "debug": "^3.2.6" + } + }, + "node_modules/monti-apm-core/node_modules/axios": { + "version": "0.21.4", + "resolved": "https://registry.npmjs.org/axios/-/axios-0.21.4.tgz", + "integrity": "sha512-ut5vewkiu8jjGBdqpM44XxjuCjq9LAKeHVmoVfHVzy8eHgxxq8SbAVQNovDA8mVi05kP0Ea/n/UzcSHcTJQfNg==", + "dependencies": { + "follow-redirects": "^1.14.0" + } + }, + "node_modules/monti-apm-core/node_modules/debug": { + "version": "3.2.7", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", + "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", + "dependencies": { + "ms": "^2.1.1" + } + }, + "node_modules/monti-apm-sketches-js": { + "version": "0.0.3", + "resolved": "https://registry.npmjs.org/monti-apm-sketches-js/-/monti-apm-sketches-js-0.0.3.tgz", + "integrity": "sha512-YhRbOtVoXyeWgoBIGfSy70pfxDhGj3zuiA66jH7UEAmFqgbq4u/Xfb3Zh2J87xgMJUp7JrrWkVSXgk8gg9ktuQ==" + }, "node_modules/ms": { "version": "2.1.2", "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", - "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", - "dev": true + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" }, "node_modules/nanoid": { "version": "3.3.3", diff --git a/package.json b/package.json index 19b18c8..24be0a9 100644 --- a/package.json +++ b/package.json @@ -39,6 +39,7 @@ "@types/chai": "^4.3.4", "@types/debug": "^4.1.8", "@types/mocha": "^10.0.1", + "@types/node": "^20.5.0", "@types/uuid": "^9.0.2", "@types/websocket": "^1.0.5", "@typescript-eslint/eslint-plugin": "5.62.0", @@ -56,6 +57,8 @@ "dependencies": { "axios": "1.4.0", "eventemitter2": "6.4.9", + "monti-apm-core": "^1.7.5", + "monti-apm-sketches-js": "^0.0.3", "remeda": "1.24.0", "uuid": "9.0.0" }, From 81815cd3c05a43231d58dde4593aed31a7972d43 Mon Sep 17 00:00:00 2001 From: Leonardo Venturini Date: Wed, 16 Aug 2023 09:15:31 -0400 Subject: [PATCH 12/37] add retry --- src/retry.ts | 72 ++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 72 insertions(+) create mode 100644 src/retry.ts diff --git a/src/retry.ts b/src/retry.ts new file mode 100644 index 0000000..d097dd3 --- /dev/null +++ b/src/retry.ts @@ -0,0 +1,72 @@ +import { randomBytes } from 'crypto'; + +interface RetryOptions { + baseTimeout?: number; + exponent?: number; + maxTimeout?: number; + minTimeout?: number; + minCount?: number; + fuzz?: number; +} + +export class Retry { + private baseTimeout: number; + private exponent: number; + private maxTimeout: number; + private minTimeout: number; + private minCount: number; + private fuzz: number; + private retryTimer: NodeJS.Timeout | null; + + constructor({ + baseTimeout = 1000, + exponent = 2.2, + maxTimeout = 5 * 60000, + minTimeout = 10, + minCount = 2, + fuzz = 0.5 + }: RetryOptions = {}) { + this.baseTimeout = baseTimeout; + this.exponent = exponent; + this.maxTimeout = maxTimeout; + this.minTimeout = minTimeout; + this.minCount = minCount; + this.fuzz = fuzz; + this.retryTimer = null; + } + + public clear(): void { + if (this.retryTimer) { + clearTimeout(this.retryTimer); + } + this.retryTimer = null; + } + + private _timeout(count: number): number { + if (count < this.minCount) { + return this.minTimeout; + } + + let timeout = Math.min( + this.maxTimeout, + this.baseTimeout * Math.pow(this.exponent, count) + ); + + timeout *= this.randomFraction() * this.fuzz + (1 - this.fuzz / 2); + return Math.ceil(timeout); + } + + private randomFraction(): number { + return parseInt(randomBytes(8).toString('hex'), 16) / 0xffffffffffffffff; + } + + public retryLater(count: number, fn: () => void): number { + const timeout = this._timeout(count); + if (this.retryTimer) { + clearTimeout(this.retryTimer); + } + + this.retryTimer = setTimeout(fn, timeout); + return timeout; + } +} From d7a31878fffdbfb6a7ce2d1d634eba6cb192dabd Mon Sep 17 00:00:00 2001 From: Leonardo Venturini Date: Wed, 16 Aug 2023 09:15:54 -0400 Subject: [PATCH 13/37] add environment constants --- src/environment.ts | 2 ++ 1 file changed, 2 insertions(+) create mode 100644 src/environment.ts diff --git a/src/environment.ts b/src/environment.ts new file mode 100644 index 0000000..3beb757 --- /dev/null +++ b/src/environment.ts @@ -0,0 +1,2 @@ +export const isServer = typeof window === 'undefined'; +export const isClient = !isServer; \ No newline at end of file From 251bdffe996fe1a94f6527dcbd8bdffcd8028840 Mon Sep 17 00:00:00 2001 From: Leonardo Venturini Date: Wed, 16 Aug 2023 09:16:04 -0400 Subject: [PATCH 14/37] add ntp --- package-lock.json | 49 ++++++++++++- package.json | 2 + src/ntp.ts | 179 ++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 229 insertions(+), 1 deletion(-) create mode 100644 src/ntp.ts diff --git a/package-lock.json b/package-lock.json index e410297..3920b1b 100644 --- a/package-lock.json +++ b/package-lock.json @@ -10,6 +10,8 @@ "license": "MIT", "dependencies": { "axios": "1.4.0", + "cross-fetch": "^4.0.0", + "debug": "^4.3.4", "eventemitter2": "6.4.9", "monti-apm-core": "^1.7.5", "monti-apm-sketches-js": "^0.0.3", @@ -1283,6 +1285,33 @@ "node": ">= 0.6" } }, + "node_modules/cross-fetch": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/cross-fetch/-/cross-fetch-4.0.0.tgz", + "integrity": "sha512-e4a5N8lVvuLgAWgnCrLr2PP0YyDOTHa9H/Rj54dirp61qXnNq46m82bRhNqIA5VccJtWBvPTFRV3TtvHUKPB1g==", + "dependencies": { + "node-fetch": "^2.6.12" + } + }, + "node_modules/cross-fetch/node_modules/node-fetch": { + "version": "2.6.12", + "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.12.tgz", + "integrity": "sha512-C/fGU2E8ToujUivIO0H+tpQ6HWo4eEmchoPIoXtxCrVghxdKq+QOHqEZW7tuP3KlV3bC8FRMO5nMCC7Zm1VP6g==", + "dependencies": { + "whatwg-url": "^5.0.0" + }, + "engines": { + "node": "4.x || >=6.0.0" + }, + "peerDependencies": { + "encoding": "^0.1.0" + }, + "peerDependenciesMeta": { + "encoding": { + "optional": true + } + } + }, "node_modules/cross-spawn": { "version": "7.0.3", "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz", @@ -1301,7 +1330,6 @@ "version": "4.3.4", "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", - "dev": true, "dependencies": { "ms": "2.1.2" }, @@ -3724,6 +3752,11 @@ "nodetouch": "bin/nodetouch.js" } }, + "node_modules/tr46": { + "version": "0.0.3", + "resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz", + "integrity": "sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==" + }, "node_modules/trim-repeated": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/trim-repeated/-/trim-repeated-2.0.0.tgz", @@ -3844,6 +3877,20 @@ "uuid": "dist/bin/uuid" } }, + "node_modules/webidl-conversions": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz", + "integrity": "sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==" + }, + "node_modules/whatwg-url": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-5.0.0.tgz", + "integrity": "sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==", + "dependencies": { + "tr46": "~0.0.3", + "webidl-conversions": "^3.0.0" + } + }, "node_modules/which": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", diff --git a/package.json b/package.json index 24be0a9..d2bcd1a 100644 --- a/package.json +++ b/package.json @@ -56,6 +56,8 @@ }, "dependencies": { "axios": "1.4.0", + "cross-fetch": "^4.0.0", + "debug": "^4.3.4", "eventemitter2": "6.4.9", "monti-apm-core": "^1.7.5", "monti-apm-sketches-js": "^0.0.3", diff --git a/src/ntp.ts b/src/ntp.ts new file mode 100644 index 0000000..d01651f --- /dev/null +++ b/src/ntp.ts @@ -0,0 +1,179 @@ +import { Retry } from "@/retry"; +import { isServer } from "@/environment"; +import fetch from 'cross-fetch' + +interface NtpOptions { + endpoint?: string; + disableNtp?: boolean; +} + +export class Ntp { + private isDisabled: boolean; + private readonly path: string = '/simplentp/sync'; + private endpoint = 'https://enginex.kadira.io'; + private diff: number; + private synced: boolean; + private reSyncCount: number; + private reSync: Retry; + + constructor(options?: NtpOptions) { + const { endpoint, disableNtp } = options || {}; + + this.isDisabled = disableNtp || false; + + if (endpoint) this.setEndpoint(endpoint); + + this.diff = 0; + this.synced = false; + this.reSyncCount = 0; + this.reSync = new Retry({ + baseTimeout: 1000 * 60, + maxTimeout: 1000 * 60 * 10, + minCount: 0 + }); + } + + private static _now(): number { + const now = Date.now(); + + if (typeof now === 'number') { + return now; + } + + // @ts-ignore + if (now instanceof Date) { + // @ts-ignore + return now.getTime(); + } + + return new Date().getTime(); + } + + public setEndpoint(endpoint: string): void { + this.endpoint = endpoint; + } + + public getTime(): number { + return Ntp._now() + Math.round(this.diff); + } + + public syncTime(localTime: number): number { + return localTime + Math.ceil(this.diff); + } + + public sync(): void { + if (this.endpoint === null || this.isDisabled) { + return; + } + + const logger = getLogger(); + logger('init sync'); + let retryCount = 0; + + const retry = new Retry({ + baseTimeout: 1000 * 20, + maxTimeout: 1000 * 60, + minCount: 1, + minTimeout: 0 + }); + + const syncTime = () => { + if (retryCount < 5) { + logger('attempt time sync with server', retryCount); + retry.retryLater(retryCount++, cacheDns); + } else { + logger('maximum retries reached'); + this.reSync.retryLater(this.reSyncCount++, (...args) => { + this.sync(...args); + }); + } + }; + + const cacheDns = () => { + this.getServerTime(err => { + if (!err) { + calculateTimeDiff(); + } else { + syncTime(); + } + }); + }; + + const calculateTimeDiff = () => { + const clientStartTime = new Date().getTime(); + this.getServerTime((err, serverTime) => { + if (!err && serverTime) { + const networkTime = (new Date().getTime() - clientStartTime) / 2; + const serverStartTime = serverTime - networkTime; + this.diff = serverStartTime - clientStartTime; + this.synced = true; + this.reSync.retryLater(this.reSyncCount++, (...args) => { + this.sync(...args); + }); + logger('successfully updated diff value', this.diff); + } else { + syncTime(); + } + }); + }; + + syncTime(); + } + + public getServerTime(callback: (err?: Error, serverTime?: number) => void): void { + if (this.endpoint === null) { + throw new Error('getServerTime requires the endpoint to be set'); + } + + if (this.isDisabled) { + throw new Error('getServerTime requires NTP to be enabled'); + } + + const url = `${this.endpoint}${this.path}?noCache=${new Date().getTime()}-${Math.random()}`; + + fetch(url, { + method: 'GET', + headers: { + 'Accept': 'application/json', + 'Content-Type': 'application/json' + } + }) + .then(response => { + if (!response.ok) { + throw new Error(`HTTP error! Status: ${response.status}`); + } + return response.text(); + }) + .then(content => { + const serverTime = parseInt(content, 10); + callback(undefined, serverTime); + }) + .catch(error => { + callback(error); + }); + } +} + +function getLogger(): (message?: any, ...optionalParams: any[]) => void { + if (isServer) { + return require('debug')('kadira:ntp'); + } + + return function log(message?: any, ...optionalParams: any[]) { + let canLog = false; + try { + canLog = global.localStorage.getItem('LOG_KADIRA') !== null && typeof console !== 'undefined'; + } catch (e) { } + + if (!canLog) { + return; + } + + if (message) { + message = `kadira:ntp ${message}`; + optionalParams.unshift(message); + } + + console.log(...optionalParams); + }; +} From 45d3dead3ed798a7244523f7e8d1d400f4ff1b99 Mon Sep 17 00:00:00 2001 From: Leonardo Venturini Date: Thu, 17 Aug 2023 10:19:46 -0400 Subject: [PATCH 15/37] add doc sz cache and tests --- .swcrc | 25 ++++++++ package-lock.json | 34 +++++------ package.json | 16 +++--- src/@types/chai.d.ts | 16 ++++++ src/doc-sz-cache.test.ts | 106 ++++++++++++++++++++++++++++++++++ src/doc-sz-cache.ts | 120 +++++++++++++++++++++++++++++++++++++++ src/tests/setup.ts | 3 + tsconfig.json | 10 +--- 8 files changed, 295 insertions(+), 35 deletions(-) create mode 100644 .swcrc create mode 100644 src/@types/chai.d.ts create mode 100644 src/doc-sz-cache.test.ts create mode 100644 src/doc-sz-cache.ts create mode 100644 src/tests/setup.ts diff --git a/.swcrc b/.swcrc new file mode 100644 index 0000000..09d159f --- /dev/null +++ b/.swcrc @@ -0,0 +1,25 @@ +{ + "$schema": "https://json.schemastore.org/swcrc", + "jsc": { + "parser": { + "syntax": "typescript", + "decorators": true, + "dynamicImport": true + }, + "baseUrl": "./", + "paths": { + "@/*": [ + "src/*" + ] + } + }, + "env": { + "targets": { + "node": "12" + }, + }, + "module": { + "type": "commonjs" + }, + "sourceMaps": true +} diff --git a/package-lock.json b/package-lock.json index 3920b1b..b59f1dc 100644 --- a/package-lock.json +++ b/package-lock.json @@ -13,17 +13,17 @@ "cross-fetch": "^4.0.0", "debug": "^4.3.4", "eventemitter2": "6.4.9", + "json-stringify-safe": "^5.0.1", "monti-apm-core": "^1.7.5", "monti-apm-sketches-js": "^0.0.3", "remeda": "1.24.0", - "uuid": "9.0.0" + "uuid": "^9.0.0" }, "devDependencies": { "@swc/cli": "^0.1.62", "@swc/core": "^1.3.71", "@swc/register": "^0.1.10", - "@types/backoff": "^2.5.2", - "@types/chai": "^4.3.4", + "@types/chai": "^4.3.5", "@types/debug": "^4.1.8", "@types/mocha": "^10.0.1", "@types/node": "^20.5.0", @@ -31,15 +31,15 @@ "@types/websocket": "^1.0.5", "@typescript-eslint/eslint-plugin": "5.62.0", "@typescript-eslint/parser": "5.62.0", - "chai": "4.3.7", + "chai": "^4.3.7", "eslint": "8.45.0", "eslint-config-prettier": "8.8.0", "eslint-plugin-prettier": "4.2.1", - "mocha": "10.2.0", + "mocha": "^10.2.0", "nodemon": "2.0.21", "prettier": "2.8.8", "rimraf": "4.4.1", - "typescript": "4.9.5" + "typescript": "5.1.6" } }, "node_modules/@aashutoshrathi/word-wrap": { @@ -466,15 +466,6 @@ "integrity": "sha512-OvjF+z51L3ov0OyAU0duzsYuvO01PH7x4t6DJx+guahgTnBHkhJdG7soQeTSFLWN3efnHyibZ4Z8l2EuWwJN3A==", "dev": true }, - "node_modules/@types/backoff": { - "version": "2.5.2", - "resolved": "https://registry.npmjs.org/@types/backoff/-/backoff-2.5.2.tgz", - "integrity": "sha512-oa1YvggujhVppgeIct3LBkbCVXKh97fvOFIR6VlFLxRCeswk/KBRQKg7zoX832vlCP5bGLOFqC9hY7vsDeL9AA==", - "dev": true, - "dependencies": { - "@types/node": "*" - } - }, "node_modules/@types/cacheable-request": { "version": "6.0.3", "resolved": "https://registry.npmjs.org/@types/cacheable-request/-/cacheable-request-6.0.3.tgz", @@ -2449,6 +2440,11 @@ "integrity": "sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==", "dev": true }, + "node_modules/json-stringify-safe": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz", + "integrity": "sha512-ZClg6AaYvamvYEE82d3Iyd3vSSIjQ+odgjaTzRuO3s7toCdFKczob2i0zCh7JE8kWn17yvAWhUVxvqGwUalsRA==" + }, "node_modules/keyv": { "version": "4.5.3", "resolved": "https://registry.npmjs.org/keyv/-/keyv-4.5.3.tgz", @@ -3836,16 +3832,16 @@ } }, "node_modules/typescript": { - "version": "4.9.5", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.9.5.tgz", - "integrity": "sha512-1FXk9E2Hm+QzZQ7z+McJiHL4NW1F2EzMu9Nq9i3zAaGqibafqYwCVU6WyWAuyQRRzOlxou8xZSyXLEN8oKj24g==", + "version": "5.1.6", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.1.6.tgz", + "integrity": "sha512-zaWCozRZ6DLEWAWFrVDz1H6FVXzUSfTy5FUMWsQlU8Ym5JP9eO4xkTIROFCQvhQf61z6O/G6ugw3SgAnvvm+HA==", "dev": true, "bin": { "tsc": "bin/tsc", "tsserver": "bin/tsserver" }, "engines": { - "node": ">=4.2.0" + "node": ">=14.17" } }, "node_modules/undefsafe": { diff --git a/package.json b/package.json index d2bcd1a..87abae0 100644 --- a/package.json +++ b/package.json @@ -10,13 +10,13 @@ "lint": "eslint src --cache", "lintfix": "eslint src --fix", "test:dist": "mocha 'dist/**/*.test.js' --exit --watch=false", - "test": "mocha src/**/*.test.js --require=@swc/register --exit --watch=false", + "test": "mocha --extension=ts --require=@swc/register --file=src/tests/setup.ts --exit --watch=false src/**/*.test.ts", "test:watch": "nodemon --exec 'npm run test' -e js --watch src", "prepublishOnly": "npm run clean && npm run build && npm run types" }, "repository": { "type": "git", - "url": "git+https://github.com/monti-apm/monti-apm-core.git" + "url": "git+https://github.com/monti-apm/node-agent.git" }, "keywords": [ "kadira", @@ -35,8 +35,7 @@ "@swc/cli": "^0.1.62", "@swc/core": "^1.3.71", "@swc/register": "^0.1.10", - "@types/backoff": "^2.5.2", - "@types/chai": "^4.3.4", + "@types/chai": "^4.3.5", "@types/debug": "^4.1.8", "@types/mocha": "^10.0.1", "@types/node": "^20.5.0", @@ -44,25 +43,26 @@ "@types/websocket": "^1.0.5", "@typescript-eslint/eslint-plugin": "5.62.0", "@typescript-eslint/parser": "5.62.0", - "chai": "4.3.7", + "chai": "^4.3.7", "eslint": "8.45.0", "eslint-config-prettier": "8.8.0", "eslint-plugin-prettier": "4.2.1", - "mocha": "10.2.0", + "mocha": "^10.2.0", "nodemon": "2.0.21", "prettier": "2.8.8", "rimraf": "4.4.1", - "typescript": "4.9.5" + "typescript": "5.1.6" }, "dependencies": { "axios": "1.4.0", "cross-fetch": "^4.0.0", "debug": "^4.3.4", "eventemitter2": "6.4.9", + "json-stringify-safe": "^5.0.1", "monti-apm-core": "^1.7.5", "monti-apm-sketches-js": "^0.0.3", "remeda": "1.24.0", - "uuid": "9.0.0" + "uuid": "^9.0.0" }, "volta": { "node": "20.5.0" diff --git a/src/@types/chai.d.ts b/src/@types/chai.d.ts new file mode 100644 index 0000000..0121318 --- /dev/null +++ b/src/@types/chai.d.ts @@ -0,0 +1,16 @@ +import type Chai from 'chai' +import type Mocha from 'mocha' + +declare global { + var expect: Chai.ExpectStatic; + var assert: Chai.AssertStatic; + var should: Chai.Should; + + var describe: Mocha.SuiteFunction; + var it: Mocha.TestFunction; + + var before: Mocha.HookFunction; + var after: Mocha.HookFunction; + var beforeEach: Mocha.HookFunction; + var afterEach: Mocha.HookFunction; +} diff --git a/src/doc-sz-cache.test.ts b/src/doc-sz-cache.test.ts new file mode 100644 index 0000000..441083a --- /dev/null +++ b/src/doc-sz-cache.test.ts @@ -0,0 +1,106 @@ +import { expect } from 'chai'; +import LRU from 'lru-cache'; +import {DocSzCache, DocSzCacheItem} from "./doc-sz-cache"; + +describe('DocSize Cache', () => { + describe('DocSzCache', () => { + + it('should correctly instantiate the constructor', () => { + const cache = new DocSzCache(5, 10); + expect(cache.items).to.be.instanceOf(LRU); + expect(cache.items.max).to.equal(5); + expect(cache.maxValues).to.equal(10); + expect(cache.cpuUsage).to.equal(0); + }); + + it('should correctly set CPU usage', () => { + const cache = new DocSzCache(5, 10); + cache.setPcpu(5); + expect(cache.cpuUsage).to.equal(5); + }); + + it('should correctly generate a key', () => { + const cache = new DocSzCache(5, 10); + const hash = cache.getKey('c1', 'q1', 'o1'); + expect(hash).to.be.a('string').and.equal('["c1","q1","o1"]'); + }); + + it('should generate different keys for different input combinations', () => { + const cache = new DocSzCache(5, 10); + const hash1 = cache.getKey('c1', 'q1', 'o1'); + const hash2 = cache.getKey('c1', 'q2', 'o1'); + expect(hash1).to.not.equal(hash2); + }); + + it('should correctly retrieve size', () => { + const cache = new DocSzCache(5, 3); + let size = cache.getSize('c1', 'q1', 'o1', []); + expect(size).to.equal(0); + }); + + it('should correctly score item based on CPU usage', () => { + const cache = new DocSzCache(5, 10); + let item = new DocSzCacheItem(10); + item.values = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]; + item.updated = Date.now(); + cache.cpuUsage = 100; + + let score = cache.getItemScore(item); + expect(score).to.be.within(0, 0.001); + }); + + it('should determine if an update is needed based on item score', () => { + const cache = new DocSzCache(5, 10); + let item = new DocSzCacheItem(10); + item.values = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]; + item.updated = Date.now(); + + let score = 0; + cache.getItemScore = function () { + return score; + }; + + expect(cache.needsUpdate(item)).to.be.false; + }); + + }); + + describe('DocSzCacheItem', () => { + + it('should correctly instantiate the constructor', () => { + const item = new DocSzCacheItem(10); + expect(item.maxValues).to.equal(10); + expect(item.updated).to.equal(0); + expect(item.values).to.eql([]); + }); + + it('should correctly add data in a normal situation', () => { + const item = new DocSzCacheItem(10); + const rand = Math.random(); + item.addData(rand); + expect(item.values).to.eql([rand]); + expect(Date.now() - item.updated).to.be.lessThan(100); + }); + + it('should handle data overflow correctly when adding data', () => { + const item = new DocSzCacheItem(10); + item.values = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]; + const rand = Math.random(); + item.addData(rand); + expect(item.values).to.eql([2, 3, 4, 5, 6, 7, 8, 9, 10, rand]); + expect(Date.now() - item.updated).to.be.lessThan(100); + }); + + it('should correctly retrieve the median value for even number of data points', () => { + const item = new DocSzCacheItem(10); + item.values = [2, 4, 6, 8, 1, 3, 5, 7]; + expect(item.getValue()).to.equal(4.5); + }); + + it('should correctly retrieve the median value for odd number of data points', () => { + const item = new DocSzCacheItem(10); + item.values = [2, 4, 6, 8, 1, 3, 5, 7, 9]; + expect(item.getValue()).to.equal(5); + }); + }); +}); diff --git a/src/doc-sz-cache.ts b/src/doc-sz-cache.ts new file mode 100644 index 0000000..86a97c5 --- /dev/null +++ b/src/doc-sz-cache.ts @@ -0,0 +1,120 @@ +import LRU from 'lru-cache'; +import jsonStringify from 'json-stringify-safe'; + +interface IData { + length?: number; + size?: () => number; + get?: () => any; + forEach?: (callback: (element: any) => boolean) => void; +} + +export class DocSzCache { + public items: LRU; + public maxValues: number; + cpuUsage: number; + + constructor(maxItems: number, maxValues: number) { + this.items = new LRU({ max: maxItems }); + this.maxValues = maxValues; + this.cpuUsage = 0; + } + + public setPcpu(pcpu: number): void { + this.cpuUsage = pcpu; + } + + public getSize(coll: any, query: any, opts: any, data: IData): number { + if (!(data && (data.length || (typeof data.size === 'function' && data.size())))) { + return 0; + } + + const key = this.getKey(coll, query, opts); + let item = this.items.get(key); + + if (!item) { + item = new DocSzCacheItem(this.maxValues); + this.items.set(key, item); + } + + if (this.needsUpdate(item)) { + let doc = {}; + if (typeof data.get === 'function' && data.forEach) { + // This is an IdMap + data.forEach((element: any) => { + doc = element; + return true; + }); + } else { + doc = data[0]; + } + const size = Buffer.byteLength(jsonStringify(doc), 'utf8'); + item.addData(size); + } + + return item.getValue(); + } + + public getKey(coll: any, query: any, opts: any): string { + return jsonStringify([coll, query, opts]); + } + + public getItemScore(item: DocSzCacheItem): number { + return [ + (item.maxValues - item.values.length) / item.maxValues, + (Date.now() - item.updated) / 60000, + (100 - this.cpuUsage) / 100, + ].map(score => (score > 1 ? 1 : score)) + .reduce((total, score) => total + score, 0) / 3; + } + + public needsUpdate(item: DocSzCacheItem): boolean { + if (!item.values.length) { + return true; + } + + const currentTime = Date.now(); + const timeSinceUpdate = currentTime - item.updated; + if (timeSinceUpdate > 1000 * 60) { + return true; + } + + return this.getItemScore(item) > 0.5; + } +} + +export class DocSzCacheItem { + maxValues: number; + updated: number; + values: number[]; + + constructor(maxValues: number) { + this.maxValues = maxValues; + this.updated = 0; + this.values = []; + } + + addData(value: number): void { + this.values.push(value); + this.updated = Date.now(); + + if (this.values.length > this.maxValues) { + this.values.shift(); + } + } + + getValue(): number { + const sorted = [...this.values].sort((a, b) => a - b); + let median = 0; + let idx; + + if (sorted.length % 2 === 0) { + idx = sorted.length / 2; + median = (sorted[idx] + sorted[idx - 1]) / 2; + } else { + idx = Math.floor(sorted.length / 2); + median = sorted[idx]; + } + + return median; + } +} diff --git a/src/tests/setup.ts b/src/tests/setup.ts new file mode 100644 index 0000000..be07b12 --- /dev/null +++ b/src/tests/setup.ts @@ -0,0 +1,3 @@ +import 'chai/register-expect.js'; +import 'chai/register-should.js'; +import 'chai/register-assert.js'; \ No newline at end of file diff --git a/tsconfig.json b/tsconfig.json index e6da139..0ccc3fd 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -7,7 +7,7 @@ "declaration": true, "esModuleInterop": true, "incremental": true, - "module": "CommonJS", + "module": "commonjs", "moduleResolution": "node", "noImplicitAny": false, "noUnusedLocals": false, @@ -23,16 +23,10 @@ ] }, "typeRoots": [ - "./node_modules/@types", "./src/@types" ] }, "include": [ - "src" - ], - "exclude": [ - "src/tests", - "**/*.test.js", - "**/*.test.ts" + "src/**/*" ] } From 4fa5701f7d859c919da081915dc9039f679f0976 Mon Sep 17 00:00:00 2001 From: Leonardo Venturini Date: Thu, 17 Aug 2023 10:19:57 -0400 Subject: [PATCH 16/37] add process types --- src/@types/process.d.ts | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) create mode 100644 src/@types/process.d.ts diff --git a/src/@types/process.d.ts b/src/@types/process.d.ts new file mode 100644 index 0000000..88bd197 --- /dev/null +++ b/src/@types/process.d.ts @@ -0,0 +1,23 @@ +declare global { + namespace NodeJS { + interface Process { + + /** + * @internal + * @deprecated + * It is recommended to use `process._getActiveHandles()` instead. + */ + _getActiveRequests(): any[]; + + /** + * @internal + */ + _getActiveHandles(): any[]; + + /** + * @internal + */ + _getActiveStreams(): any[]; + } + } +} \ No newline at end of file From 84d817fdf71995e1ca0ecc66759546fb945975e9 Mon Sep 17 00:00:00 2001 From: Leonardo Venturini Date: Thu, 17 Aug 2023 10:24:35 -0400 Subject: [PATCH 17/37] add tests for ntp --- src/ntp.test.ts | 29 +++++++++++++++++++++++++++++ 1 file changed, 29 insertions(+) create mode 100644 src/ntp.test.ts diff --git a/src/ntp.test.ts b/src/ntp.test.ts new file mode 100644 index 0000000..f843a3f --- /dev/null +++ b/src/ntp.test.ts @@ -0,0 +1,29 @@ +import { expect } from 'chai'; +import { Ntp } from "@/ntp"; + +describe('Ntp', () => { + describe('Ntp._now()', () => { + it('should return correct Date.now', () => { + const now = Ntp._now(); + expect(now).to.be.greaterThan(0); + expect(typeof now).to.equal('number'); + }); + + it('should handle Date.now as Date object', () => { + const oldDateNow = Date.now; + + Date.now = function(): any { + return new Date(); + }; + + // @ts-ignore + expect(typeof Date.now().getTime()).to.equal('number'); + + const now = Ntp._now(); + expect(now).to.be.greaterThan(0); + expect(typeof now).to.equal('number'); + + Date.now = oldDateNow; + }); + }); +}); From 83853da343878a91f44231cf6b8a2c2f69aba086 Mon Sep 17 00:00:00 2001 From: Leonardo Venturini Date: Thu, 17 Aug 2023 12:02:15 -0400 Subject: [PATCH 18/37] make ntp a singleton --- src/ntp.ts | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/src/ntp.ts b/src/ntp.ts index d01651f..ff1ed6d 100644 --- a/src/ntp.ts +++ b/src/ntp.ts @@ -8,7 +8,7 @@ interface NtpOptions { } export class Ntp { - private isDisabled: boolean; + private readonly isDisabled: boolean; private readonly path: string = '/simplentp/sync'; private endpoint = 'https://enginex.kadira.io'; private diff: number; @@ -33,7 +33,16 @@ export class Ntp { }); } - private static _now(): number { + static _instance: Ntp; + + static get instance() { + if (!Ntp._instance) { + Ntp._instance = new Ntp(); + } + return Ntp._instance; + } + + static _now(): number { const now = Date.now(); if (typeof now === 'number') { From 03fe903ea55665119c7e8c5611cb5112564d810e Mon Sep 17 00:00:00 2001 From: Leonardo Venturini Date: Fri, 18 Aug 2023 08:54:04 -0400 Subject: [PATCH 19/37] add packages --- package-lock.json | 52 +++++++++++++++++++++++++++++++---------------- package.json | 3 +++ 2 files changed, 38 insertions(+), 17 deletions(-) diff --git a/package-lock.json b/package-lock.json index b59f1dc..97bd2a6 100644 --- a/package-lock.json +++ b/package-lock.json @@ -14,6 +14,7 @@ "debug": "^4.3.4", "eventemitter2": "6.4.9", "json-stringify-safe": "^5.0.1", + "lru-cache": "^10.0.1", "monti-apm-core": "^1.7.5", "monti-apm-sketches-js": "^0.0.3", "remeda": "1.24.0", @@ -25,6 +26,8 @@ "@swc/register": "^0.1.10", "@types/chai": "^4.3.5", "@types/debug": "^4.1.8", + "@types/json-stringify-safe": "^5.0.0", + "@types/lru-cache": "^7.10.10", "@types/mocha": "^10.0.1", "@types/node": "^20.5.0", "@types/uuid": "^9.0.2", @@ -505,6 +508,12 @@ "integrity": "sha512-Hr5Jfhc9eYOQNPYO5WLDq/n4jqijdHNlDXjuAQkkt+mWdQR+XJToOHrsD4cPaMXpn6KO7y2+wM8AZEs8VpBLVA==", "dev": true }, + "node_modules/@types/json-stringify-safe": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/@types/json-stringify-safe/-/json-stringify-safe-5.0.0.tgz", + "integrity": "sha512-UUA1sH0RSRROdInuDOA1yoRzbi5xVFD1RHCoOvNRPTNwR8zBkJ/84PZ6NhKVDtKp0FTeIccJCdQz1X2aJPr4uw==", + "dev": true + }, "node_modules/@types/keyv": { "version": "3.1.4", "resolved": "https://registry.npmjs.org/@types/keyv/-/keyv-3.1.4.tgz", @@ -514,6 +523,16 @@ "@types/node": "*" } }, + "node_modules/@types/lru-cache": { + "version": "7.10.10", + "resolved": "https://registry.npmjs.org/@types/lru-cache/-/lru-cache-7.10.10.tgz", + "integrity": "sha512-nEpVRPWW9EBmx2SCfNn3ClYxPL7IktPX12HhIoSc/H5mMjdeW3+YsXIpseLQ2xF35+OcpwKQbEUw5VtqE4PDNA==", + "deprecated": "This is a stub types definition. lru-cache provides its own type definitions, so you do not need this installed.", + "dev": true, + "dependencies": { + "lru-cache": "*" + } + }, "node_modules/@types/mocha": { "version": "10.0.1", "resolved": "https://registry.npmjs.org/@types/mocha/-/mocha-10.0.1.tgz", @@ -2529,15 +2548,11 @@ } }, "node_modules/lru-cache": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", - "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", - "dev": true, - "dependencies": { - "yallist": "^4.0.0" - }, + "version": "10.0.1", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-10.0.1.tgz", + "integrity": "sha512-IJ4uwUTi2qCccrioU6g9g/5rvvVl13bsdczUUcqbciD9iLr095yj8DQKdObriEvuNSx325N1rV1O0sJFszx75g==", "engines": { - "node": ">=10" + "node": "14 || >=16.14" } }, "node_modules/merge-stream": { @@ -3047,15 +3062,6 @@ "url": "https://github.com/sponsors/isaacs" } }, - "node_modules/path-scurry/node_modules/lru-cache": { - "version": "10.0.0", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-10.0.0.tgz", - "integrity": "sha512-svTf/fzsKHffP42sujkO/Rjs37BCIsQVRCeNYIm9WN8rgT7ffoUnRtZCqU+6BqcSBdv8gwJeTz8knJpgACeQMw==", - "dev": true, - "engines": { - "node": "14 || >=16.14" - } - }, "node_modules/path-scurry/node_modules/minipass": { "version": "7.0.2", "resolved": "https://registry.npmjs.org/minipass/-/minipass-7.0.2.tgz", @@ -3477,6 +3483,18 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/semver/node_modules/lru-cache": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", + "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", + "dev": true, + "dependencies": { + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=10" + } + }, "node_modules/serialize-javascript": { "version": "6.0.0", "resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-6.0.0.tgz", diff --git a/package.json b/package.json index 87abae0..ff89dca 100644 --- a/package.json +++ b/package.json @@ -37,6 +37,8 @@ "@swc/register": "^0.1.10", "@types/chai": "^4.3.5", "@types/debug": "^4.1.8", + "@types/json-stringify-safe": "^5.0.0", + "@types/lru-cache": "^7.10.10", "@types/mocha": "^10.0.1", "@types/node": "^20.5.0", "@types/uuid": "^9.0.2", @@ -59,6 +61,7 @@ "debug": "^4.3.4", "eventemitter2": "6.4.9", "json-stringify-safe": "^5.0.1", + "lru-cache": "^10.0.1", "monti-apm-core": "^1.7.5", "monti-apm-sketches-js": "^0.0.3", "remeda": "1.24.0", From d6a7973b16330b72a4838f74f387164166b220b3 Mon Sep 17 00:00:00 2001 From: Leonardo Venturini Date: Fri, 18 Aug 2023 08:54:11 -0400 Subject: [PATCH 20/37] adjust types --- src/@types/process.d.ts | 34 ++++++++++++++++------------------ tsconfig.json | 1 + 2 files changed, 17 insertions(+), 18 deletions(-) diff --git a/src/@types/process.d.ts b/src/@types/process.d.ts index 88bd197..992a2cb 100644 --- a/src/@types/process.d.ts +++ b/src/@types/process.d.ts @@ -1,23 +1,21 @@ -declare global { - namespace NodeJS { - interface Process { +declare namespace NodeJS { + interface Process extends EventEmitter { - /** - * @internal - * @deprecated - * It is recommended to use `process._getActiveHandles()` instead. - */ - _getActiveRequests(): any[]; + /** + * @internal + * @deprecated + * It is recommended to use `process._getActiveHandles()` instead. + */ + _getActiveRequests(): any[]; - /** - * @internal - */ - _getActiveHandles(): any[]; + /** + * @internal + */ + _getActiveHandles(): any[]; - /** - * @internal - */ - _getActiveStreams(): any[]; - } + /** + * @internal + */ + _getActiveStreams(): any[]; } } \ No newline at end of file diff --git a/tsconfig.json b/tsconfig.json index 0ccc3fd..f9cb418 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -23,6 +23,7 @@ ] }, "typeRoots": [ + "./node_modules/@types", "./src/@types" ] }, From a968b03029e913338d0763a66a524475de449431 Mon Sep 17 00:00:00 2001 From: Leonardo Venturini Date: Fri, 18 Aug 2023 08:55:27 -0400 Subject: [PATCH 21/37] adjust import --- src/doc-sz-cache.test.ts | 195 +++++++++++++++++++-------------------- src/doc-sz-cache.ts | 6 +- 2 files changed, 100 insertions(+), 101 deletions(-) diff --git a/src/doc-sz-cache.test.ts b/src/doc-sz-cache.test.ts index 441083a..b5a8093 100644 --- a/src/doc-sz-cache.test.ts +++ b/src/doc-sz-cache.test.ts @@ -1,106 +1,105 @@ import { expect } from 'chai'; -import LRU from 'lru-cache'; -import {DocSzCache, DocSzCacheItem} from "./doc-sz-cache"; +import { LRUCache } from 'lru-cache'; +import { DocSzCache, DocSzCacheItem } from "./doc-sz-cache"; describe('DocSize Cache', () => { - describe('DocSzCache', () => { - - it('should correctly instantiate the constructor', () => { - const cache = new DocSzCache(5, 10); - expect(cache.items).to.be.instanceOf(LRU); - expect(cache.items.max).to.equal(5); - expect(cache.maxValues).to.equal(10); - expect(cache.cpuUsage).to.equal(0); - }); - - it('should correctly set CPU usage', () => { - const cache = new DocSzCache(5, 10); - cache.setPcpu(5); - expect(cache.cpuUsage).to.equal(5); - }); - - it('should correctly generate a key', () => { - const cache = new DocSzCache(5, 10); - const hash = cache.getKey('c1', 'q1', 'o1'); - expect(hash).to.be.a('string').and.equal('["c1","q1","o1"]'); - }); - - it('should generate different keys for different input combinations', () => { - const cache = new DocSzCache(5, 10); - const hash1 = cache.getKey('c1', 'q1', 'o1'); - const hash2 = cache.getKey('c1', 'q2', 'o1'); - expect(hash1).to.not.equal(hash2); - }); - - it('should correctly retrieve size', () => { - const cache = new DocSzCache(5, 3); - let size = cache.getSize('c1', 'q1', 'o1', []); - expect(size).to.equal(0); - }); - - it('should correctly score item based on CPU usage', () => { - const cache = new DocSzCache(5, 10); - let item = new DocSzCacheItem(10); - item.values = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]; - item.updated = Date.now(); - cache.cpuUsage = 100; - - let score = cache.getItemScore(item); - expect(score).to.be.within(0, 0.001); - }); - - it('should determine if an update is needed based on item score', () => { - const cache = new DocSzCache(5, 10); - let item = new DocSzCacheItem(10); - item.values = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]; - item.updated = Date.now(); - - let score = 0; - cache.getItemScore = function () { - return score; - }; - - expect(cache.needsUpdate(item)).to.be.false; - }); + describe('DocSzCache', () => { + it('should correctly instantiate the constructor', () => { + const cache = new DocSzCache(5, 10); + expect(cache.items).to.be.instanceOf(LRUCache); + expect(cache.items.max).to.equal(5); + expect(cache.maxValues).to.equal(10); + expect(cache.cpuUsage).to.equal(0); + }); + + it('should correctly set CPU usage', () => { + const cache = new DocSzCache(5, 10); + cache.setPcpu(5); + expect(cache.cpuUsage).to.equal(5); + }); + + it('should correctly generate a key', () => { + const cache = new DocSzCache(5, 10); + const hash = cache.getKey('c1', 'q1', 'o1'); + expect(hash).to.be.a('string').and.equal('["c1","q1","o1"]'); + }); + + it('should generate different keys for different input combinations', () => { + const cache = new DocSzCache(5, 10); + const hash1 = cache.getKey('c1', 'q1', 'o1'); + const hash2 = cache.getKey('c1', 'q2', 'o1'); + expect(hash1).to.not.equal(hash2); + }); + + it('should correctly retrieve size', () => { + const cache = new DocSzCache(5, 3); + let size = cache.getSize('c1', 'q1', 'o1', []); + expect(size).to.equal(0); + }); + + it('should correctly score item based on CPU usage', () => { + const cache = new DocSzCache(5, 10); + let item = new DocSzCacheItem(10); + item.values = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]; + item.updated = Date.now(); + cache.cpuUsage = 100; + + let score = cache.getItemScore(item); + expect(score).to.be.within(0, 0.001); + }); + + it('should determine if an update is needed based on item score', () => { + const cache = new DocSzCache(5, 10); + let item = new DocSzCacheItem(10); + item.values = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]; + item.updated = Date.now(); + + let score = 0; + cache.getItemScore = function () { + return score; + }; + + expect(cache.needsUpdate(item)).to.be.false; + }); + + }); + + describe('DocSzCacheItem', () => { + + it('should correctly instantiate the constructor', () => { + const item = new DocSzCacheItem(10); + expect(item.maxValues).to.equal(10); + expect(item.updated).to.equal(0); + expect(item.values).to.eql([]); + }); + + it('should correctly add data in a normal situation', () => { + const item = new DocSzCacheItem(10); + const rand = Math.random(); + item.addData(rand); + expect(item.values).to.eql([rand]); + expect(Date.now() - item.updated).to.be.lessThan(100); + }); + + it('should handle data overflow correctly when adding data', () => { + const item = new DocSzCacheItem(10); + item.values = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]; + const rand = Math.random(); + item.addData(rand); + expect(item.values).to.eql([2, 3, 4, 5, 6, 7, 8, 9, 10, rand]); + expect(Date.now() - item.updated).to.be.lessThan(100); + }); + it('should correctly retrieve the median value for even number of data points', () => { + const item = new DocSzCacheItem(10); + item.values = [2, 4, 6, 8, 1, 3, 5, 7]; + expect(item.getValue()).to.equal(4.5); }); - describe('DocSzCacheItem', () => { - - it('should correctly instantiate the constructor', () => { - const item = new DocSzCacheItem(10); - expect(item.maxValues).to.equal(10); - expect(item.updated).to.equal(0); - expect(item.values).to.eql([]); - }); - - it('should correctly add data in a normal situation', () => { - const item = new DocSzCacheItem(10); - const rand = Math.random(); - item.addData(rand); - expect(item.values).to.eql([rand]); - expect(Date.now() - item.updated).to.be.lessThan(100); - }); - - it('should handle data overflow correctly when adding data', () => { - const item = new DocSzCacheItem(10); - item.values = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]; - const rand = Math.random(); - item.addData(rand); - expect(item.values).to.eql([2, 3, 4, 5, 6, 7, 8, 9, 10, rand]); - expect(Date.now() - item.updated).to.be.lessThan(100); - }); - - it('should correctly retrieve the median value for even number of data points', () => { - const item = new DocSzCacheItem(10); - item.values = [2, 4, 6, 8, 1, 3, 5, 7]; - expect(item.getValue()).to.equal(4.5); - }); - - it('should correctly retrieve the median value for odd number of data points', () => { - const item = new DocSzCacheItem(10); - item.values = [2, 4, 6, 8, 1, 3, 5, 7, 9]; - expect(item.getValue()).to.equal(5); - }); + it('should correctly retrieve the median value for odd number of data points', () => { + const item = new DocSzCacheItem(10); + item.values = [2, 4, 6, 8, 1, 3, 5, 7, 9]; + expect(item.getValue()).to.equal(5); }); + }); }); diff --git a/src/doc-sz-cache.ts b/src/doc-sz-cache.ts index 86a97c5..9ae3477 100644 --- a/src/doc-sz-cache.ts +++ b/src/doc-sz-cache.ts @@ -1,4 +1,4 @@ -import LRU from 'lru-cache'; +import { LRUCache } from 'lru-cache'; import jsonStringify from 'json-stringify-safe'; interface IData { @@ -9,12 +9,12 @@ interface IData { } export class DocSzCache { - public items: LRU; + public items: LRUCache; public maxValues: number; cpuUsage: number; constructor(maxItems: number, maxValues: number) { - this.items = new LRU({ max: maxItems }); + this.items = new LRUCache({ max: maxItems }); this.maxValues = maxValues; this.cpuUsage = 0; } From 2bd0e10261740673c9e3d44301900256bfb1d4b4 Mon Sep 17 00:00:00 2001 From: Leonardo Venturini Date: Fri, 18 Aug 2023 08:55:45 -0400 Subject: [PATCH 22/37] commit webstorm config --- .idea/jsLibraryMappings.xml | 6 ++++++ 1 file changed, 6 insertions(+) create mode 100644 .idea/jsLibraryMappings.xml diff --git a/.idea/jsLibraryMappings.xml b/.idea/jsLibraryMappings.xml new file mode 100644 index 0000000..d23208f --- /dev/null +++ b/.idea/jsLibraryMappings.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file From 2640ca32297b55a989a0aba31a70f36b47ff5010 Mon Sep 17 00:00:00 2001 From: Leonardo Venturini Date: Fri, 18 Aug 2023 08:55:55 -0400 Subject: [PATCH 23/37] add base system class --- src/index.ts | 7 ++ src/monti-apm-agent.ts | 23 +++++ src/system.ts | 214 +++++++++++++++++++++++++++++++++++++++++ 3 files changed, 244 insertions(+) create mode 100644 src/index.ts create mode 100644 src/monti-apm-agent.ts create mode 100644 src/system.ts diff --git a/src/index.ts b/src/index.ts new file mode 100644 index 0000000..77ede62 --- /dev/null +++ b/src/index.ts @@ -0,0 +1,7 @@ +export * from './monti-apm-agent' +export * from './system' +export * from './gc' +export * from './doc-sz-cache' +export * from './ntp' +export * from './event-loop-monitor' +export * from './environment' \ No newline at end of file diff --git a/src/monti-apm-agent.ts b/src/monti-apm-agent.ts new file mode 100644 index 0000000..c2dc603 --- /dev/null +++ b/src/monti-apm-agent.ts @@ -0,0 +1,23 @@ +import { DocSzCache } from "@/doc-sz-cache"; + +export class MontiApmAgent { + static _instance: MontiApmAgent; + + static get instance() { + if (!MontiApmAgent._instance) { + MontiApmAgent._instance = new MontiApmAgent(); + } + return MontiApmAgent._instance; + } + + + docSzCache = new DocSzCache(100000, 10); + + constructor() { + console.log('MontiApmAgent constructor'); + } + + public connect(appId: string, secret: string) { + + } +} \ No newline at end of file diff --git a/src/system.ts b/src/system.ts new file mode 100644 index 0000000..8100d02 --- /dev/null +++ b/src/system.ts @@ -0,0 +1,214 @@ +import { EventLoopMonitor } from "@/event-loop-monitor"; +import { DDSketch } from "monti-apm-sketches-js"; +import {GCMetrics} from "@/gc"; +import { Ntp } from "@/ntp"; +import { MontiApmAgent } from "@/monti-apm-agent"; + +type CPUHistoryEntry = { + time: number; + usage: number; + sys: number; + user: number; +} + +type MetricPayload = { + startTime: number; + endTime: number; + sessions?: number; + memory: number; + memoryArrayBuffers: number; + memoryExternal: number; + memoryHeapUsed: number; + memoryHeapTotal: number; + newSessions: number; + activeRequests: number; + activeHandles: number; + activeStreams: number; + pctEvloopBlock: number; + evloopHistogram: any; + gcMajorDuration: number; + gcMinorDuration: number; + gcIncrementalDuration: number; + gcWeakCBDuration: number; + pcpu: number; + pcpuUser: number; + pcpuSystem: number; + cpuHistory: CPUHistoryEntry[]; +} + +export class System { + static _instance: System; + static getInstance() { + if (!System._instance) { + System._instance = new System(); + } + return System._instance; + } + + startTime: number; + newSessions: number; + sessionTimeout: number; + evloopHistogram: DDSketch; + evloopMonitor: EventLoopMonitor; + gcMetrics: GCMetrics; + cpuTime: [number, number]; + previousCpuUsage: NodeJS.CpuUsage; + cpuHistory: CPUHistoryEntry[] = [] + currentCpuUsage = 0; + + constructor() { + this.startTime = Ntp._now(); + this.newSessions = 0; + // 30 min + this.sessionTimeout = 1000 * 60 * 30; + + this.evloopHistogram = new DDSketch({ + alpha: 0.02 + }); + + this.evloopMonitor = new EventLoopMonitor(200); + this.evloopMonitor.start(); + this.evloopMonitor.on('lag', lag => { + // store as microsecond + this.evloopHistogram.add(lag * 1000); + }); + + this.gcMetrics = new GCMetrics(); + this.gcMetrics.start(); + + this.cpuTime = process.hrtime(); + this.previousCpuUsage = process.cpuUsage(); + + setInterval(() => { + this.cpuUsage(); + }, 2000); + } + + buildPayload () { + + let now = Ntp._now(); + + let metrics: MetricPayload = {} as any; + + metrics.startTime = Ntp.instance.syncTime(this.startTime); + metrics.endTime = Ntp.instance.syncTime(now); + + let memoryUsage = process.memoryUsage(); + metrics.memory = memoryUsage.rss / (1024 * 1024); + metrics.memoryArrayBuffers = (memoryUsage.arrayBuffers || 0) / (1024 * 1024); + metrics.memoryExternal = memoryUsage.external / (1024 * 1024); + metrics.memoryHeapUsed = memoryUsage.heapUsed / (1024 * 1024); + metrics.memoryHeapTotal = memoryUsage.heapTotal / (1024 * 1024); + + metrics.newSessions = this.newSessions; + this.newSessions = 0; + + metrics.activeRequests = process._getActiveRequests().length; + metrics.activeHandles = process._getActiveHandles().length; + metrics.activeStreams = process._getActiveStreams().length; + + // track eventloop metrics + metrics.pctEvloopBlock = this.evloopMonitor.status().pctBlock; + metrics.evloopHistogram = this.evloopHistogram; + this.evloopHistogram = new DDSketch({ + alpha: 0.02 + }); + + metrics.gcMajorDuration = this.gcMetrics.metrics.gcMajor; + metrics.gcMinorDuration = this.gcMetrics.metrics.gcMinor; + metrics.gcIncrementalDuration = this.gcMetrics.metrics.gcIncremental; + metrics.gcWeakCBDuration = this.gcMetrics.metrics.gcWeakCB; + + this.gcMetrics.reset(); + + metrics.pcpu = 0; + metrics.pcpuUser = 0; + metrics.pcpuSystem = 0; + + if (this.cpuHistory.length > 0) { + let lastCpuUsage = this.cpuHistory[this.cpuHistory.length - 1]; + metrics.pcpu = lastCpuUsage.usage * 100; + metrics.pcpuUser = lastCpuUsage.user * 100; + metrics.pcpuSystem = lastCpuUsage.sys * 100; + } + + metrics.cpuHistory = this.cpuHistory.map(entry => ({ + time: Ntp.instance.syncTime(entry.time), + usage: entry.usage, + sys: entry.sys, + user: entry.user + })); + + this.cpuHistory = []; + this.startTime = now; + return {systemMetrics: [metrics]}; + } + + cpuUsage () { + let elapTimeMS = hrtimeToMS(process.hrtime(this.cpuTime)); + let elapUsage = process.cpuUsage(this.previousCpuUsage); + let elapUserMS = elapUsage.user / 1000; + let elapSystMS = elapUsage.system / 1000; + let totalUsageMS = elapUserMS + elapSystMS; + let totalUsagePercent = totalUsageMS / elapTimeMS; + + this.cpuHistory.push({ + time: Ntp._now(), + usage: totalUsagePercent, + user: elapUserMS / elapTimeMS, + sys: elapSystMS / elapUsage.system + }); + + this.currentCpuUsage = totalUsagePercent * 100; + MontiApmAgent.instance.docSzCache.setPcpu(this.currentCpuUsage); + + this.cpuTime = process.hrtime(); + this.previousCpuUsage = process.cpuUsage(); + } + + handleSessionActivity (msg, session) { + if (msg.msg === 'connect' && !msg.session) { + this.countNewSession(session); + } else if (['sub', 'method'].indexOf(msg.msg) !== -1) { + if (!this.isSessionActive(session)) { + this.countNewSession(session); + } + } + session._activeAt = Date.now(); + }; + + countNewSession (session) { + if (!isLocalAddress(session.socket)) { + this.newSessions++; + } + } + + isSessionActive (session) { + let inactiveTime = Date.now() - session._activeAt; + return inactiveTime < this.sessionTimeout; + } +} + +function hrtimeToMS (hrtime) { + return hrtime[0] * 1000 + hrtime[1] / 1000000; +} + +// ------------------------------------------------------------------------- // + +// http://regex101.com/r/iF3yR3/2 +// eslint-disable-next-line no-useless-escape +let isLocalHostRegex = /^(?:.*\.local|localhost)(?:\:\d+)?|127(?:\.\d{1,3}){3}|192\.168(?:\.\d{1,3}){2}|10(?:\.\d{1,3}){3}|172\.(?:1[6-9]|2\d|3[0-1])(?:\.\d{1,3}){2}$/; + +// http://regex101.com/r/hM5gD8/1 +let isLocalAddressRegex = /^127(?:\.\d{1,3}){3}|192\.168(?:\.\d{1,3}){2}|10(?:\.\d{1,3}){3}|172\.(?:1[6-9]|2\d|3[0-1])(?:\.\d{1,3}){2}$/; + +function isLocalAddress (socket) { + let host = socket.headers['host']; + if (host) { + return isLocalHostRegex.test(host); + } + let address = socket.headers['x-forwarded-for'] || socket.remoteAddress; + if (address) { + return isLocalAddressRegex.test(address); + } +} From d1e2d2ccfbe05efe699b985083fda620e9356253 Mon Sep 17 00:00:00 2001 From: Leonardo Venturini Date: Mon, 28 Aug 2023 08:54:26 -0400 Subject: [PATCH 24/37] add config package --- config/custom-environment-variables.json | 8 ++++ config/default.json | 8 ++++ package-lock.json | 30 ++++++++++++++ package.json | 2 + src/monti-apm-agent.ts | 50 ++++++++++++++++++------ 5 files changed, 86 insertions(+), 12 deletions(-) create mode 100644 config/custom-environment-variables.json create mode 100644 config/default.json diff --git a/config/custom-environment-variables.json b/config/custom-environment-variables.json new file mode 100644 index 0000000..0c1b807 --- /dev/null +++ b/config/custom-environment-variables.json @@ -0,0 +1,8 @@ +{ + "Monti": { + "appId": "MONTI_APP_ID", + "appSecret": "MONTI_APP_SECRET", + "endpoint": "MONTI_ENDPOINT", + "hostname": "MONTI_HOSTNAME" + } +} \ No newline at end of file diff --git a/config/default.json b/config/default.json new file mode 100644 index 0000000..6e1343f --- /dev/null +++ b/config/default.json @@ -0,0 +1,8 @@ +{ + "Monti": { + "appId": "", + "appSecret": "", + "endpoint": "https://engine.montiapm.com", + "hostname": "" + } +} \ No newline at end of file diff --git a/package-lock.json b/package-lock.json index 97bd2a6..74c1499 100644 --- a/package-lock.json +++ b/package-lock.json @@ -10,6 +10,7 @@ "license": "MIT", "dependencies": { "axios": "1.4.0", + "config": "^3.3.9", "cross-fetch": "^4.0.0", "debug": "^4.3.4", "eventemitter2": "6.4.9", @@ -25,6 +26,7 @@ "@swc/core": "^1.3.71", "@swc/register": "^0.1.10", "@types/chai": "^4.3.5", + "@types/config": "^3.3.0", "@types/debug": "^4.1.8", "@types/json-stringify-safe": "^5.0.0", "@types/lru-cache": "^7.10.10", @@ -487,6 +489,12 @@ "integrity": "sha512-mEo1sAde+UCE6b2hxn332f1g1E8WfYRu6p5SvTKr2ZKC1f7gFJXk4h5PyGP9Dt6gCaG8y8XhwnXWC6Iy2cmBng==", "dev": true }, + "node_modules/@types/config": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/@types/config/-/config-3.3.0.tgz", + "integrity": "sha512-9kZSbl3/X3TVNowLCu5HFQdQmD+4287Om55avknEYkuo6R2dDrsp/EXEHUFvfYeG7m1eJ0WYGj+cbcUIhARJAQ==", + "dev": true + }, "node_modules/@types/debug": { "version": "4.1.8", "resolved": "https://registry.npmjs.org/@types/debug/-/debug-4.1.8.tgz", @@ -1283,6 +1291,17 @@ "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==", "dev": true }, + "node_modules/config": { + "version": "3.3.9", + "resolved": "https://registry.npmjs.org/config/-/config-3.3.9.tgz", + "integrity": "sha512-G17nfe+cY7kR0wVpc49NCYvNtelm/pPy8czHoFkAgtV1lkmcp7DHtWCdDu+C9Z7gb2WVqa9Tm3uF9aKaPbCfhg==", + "dependencies": { + "json5": "^2.2.3" + }, + "engines": { + "node": ">= 10.0.0" + } + }, "node_modules/content-disposition": { "version": "0.5.4", "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.4.tgz", @@ -2464,6 +2483,17 @@ "resolved": "https://registry.npmjs.org/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz", "integrity": "sha512-ZClg6AaYvamvYEE82d3Iyd3vSSIjQ+odgjaTzRuO3s7toCdFKczob2i0zCh7JE8kWn17yvAWhUVxvqGwUalsRA==" }, + "node_modules/json5": { + "version": "2.2.3", + "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.3.tgz", + "integrity": "sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==", + "bin": { + "json5": "lib/cli.js" + }, + "engines": { + "node": ">=6" + } + }, "node_modules/keyv": { "version": "4.5.3", "resolved": "https://registry.npmjs.org/keyv/-/keyv-4.5.3.tgz", diff --git a/package.json b/package.json index ff89dca..9e53d5b 100644 --- a/package.json +++ b/package.json @@ -36,6 +36,7 @@ "@swc/core": "^1.3.71", "@swc/register": "^0.1.10", "@types/chai": "^4.3.5", + "@types/config": "^3.3.0", "@types/debug": "^4.1.8", "@types/json-stringify-safe": "^5.0.0", "@types/lru-cache": "^7.10.10", @@ -57,6 +58,7 @@ }, "dependencies": { "axios": "1.4.0", + "config": "^3.3.9", "cross-fetch": "^4.0.0", "debug": "^4.3.4", "eventemitter2": "6.4.9", diff --git a/src/monti-apm-agent.ts b/src/monti-apm-agent.ts index c2dc603..1723ebc 100644 --- a/src/monti-apm-agent.ts +++ b/src/monti-apm-agent.ts @@ -1,23 +1,49 @@ import { DocSzCache } from "@/doc-sz-cache"; +import { Monti } from "monti-apm-core"; +import os from "os"; +import { version } from '../package.json'; +import config from 'config' export class MontiApmAgent { - static _instance: MontiApmAgent; - - static get instance() { - if (!MontiApmAgent._instance) { - MontiApmAgent._instance = new MontiApmAgent(); - } - return MontiApmAgent._instance; - } + static instance: MontiApmAgent; + appSecret: string; + appId: string; + core: Monti; docSzCache = new DocSzCache(100000, 10); - constructor() { - console.log('MontiApmAgent constructor'); - } + constructor( + appId: string, + appSecret: string, + endpoint: string = config.get('Monti.endpoint'), + hostname = config.get('Monti.hostname') || os.hostname(), + ) { + this.appId = appId; + this.appSecret = appSecret; - public connect(appId: string, secret: string) { + this.core = new Monti({ + appId, + appSecret, + endpoint, + hostname, + agentVersion: `node-agent@${version}` + }); + } + static connect( + appId: string, + appSecret: string, + endpoint?: string, + hostname?: string, + ) { + MontiApmAgent.instance = new MontiApmAgent(appId, appSecret, endpoint, hostname); } +} + +if (config.get('Monti.appId') && config.get('Monti.appSecret')) { + MontiApmAgent.connect( + config.get('Monti.appId'), + config.get('Monti.appSecret'), + ); } \ No newline at end of file From 3e18c8ccffd25b67ca2009782be55e7b939e9cd9 Mon Sep 17 00:00:00 2001 From: Leonardo Venturini Date: Mon, 28 Aug 2023 10:20:31 -0400 Subject: [PATCH 25/37] plug system model --- src/index.ts | 2 +- src/{ => models}/system.ts | 0 src/monti-apm-agent.ts | 23 ++++++++++++++++++++++- 3 files changed, 23 insertions(+), 2 deletions(-) rename src/{ => models}/system.ts (100%) diff --git a/src/index.ts b/src/index.ts index 77ede62..511c307 100644 --- a/src/index.ts +++ b/src/index.ts @@ -1,5 +1,5 @@ export * from './monti-apm-agent' -export * from './system' +export * from './models/system' export * from './gc' export * from './doc-sz-cache' export * from './ntp' diff --git a/src/system.ts b/src/models/system.ts similarity index 100% rename from src/system.ts rename to src/models/system.ts diff --git a/src/monti-apm-agent.ts b/src/monti-apm-agent.ts index 1723ebc..8a973f4 100644 --- a/src/monti-apm-agent.ts +++ b/src/monti-apm-agent.ts @@ -3,24 +3,32 @@ import { Monti } from "monti-apm-core"; import os from "os"; import { version } from '../package.json'; import config from 'config' +import { System } from "@/models/system"; export class MontiApmAgent { static instance: MontiApmAgent; appSecret: string; appId: string; + hostname: string; + core: Monti; docSzCache = new DocSzCache(100000, 10); + systemModel: System; + constructor( appId: string, appSecret: string, endpoint: string = config.get('Monti.endpoint'), - hostname = config.get('Monti.hostname') || os.hostname(), + hostname = config.get('Monti.hostname') as string || os.hostname(), ) { this.appId = appId; this.appSecret = appSecret; + this.hostname = hostname; + + this.systemModel = System.getInstance(); this.core = new Monti({ appId, @@ -39,6 +47,19 @@ export class MontiApmAgent { ) { MontiApmAgent.instance = new MontiApmAgent(appId, appSecret, endpoint, hostname); } + + async buildPayload() { + return { + host: this.hostname, + ... this.systemModel.buildPayload() + } + } + + async sendPayload() { + const payload = await this.buildPayload(); + + await this.core.sendData(payload) + } } if (config.get('Monti.appId') && config.get('Monti.appSecret')) { From 7daa79b5d967d4b381487c44d7c8f9a8e550ceb4 Mon Sep 17 00:00:00 2001 From: Leonardo Venturini Date: Mon, 28 Aug 2023 10:32:09 -0400 Subject: [PATCH 26/37] add eslint and prettier --- .eslintrc.js | 32 +++ .idea/codeStyles/Project.xml | 64 ++++++ .idea/codeStyles/codeStyleConfig.xml | 5 + .idea/inspectionProfiles/Project_Default.xml | 6 + .idea/jsLinters/eslint.xml | 6 + .prettierrc.js | 9 + src/@types/chai.d.ts | 22 +- src/@types/process.d.ts | 3 +- src/doc-sz-cache.test.ts | 14 +- src/doc-sz-cache.ts | 200 ++++++++++--------- src/environment.ts | 2 +- src/event-loop-monitor.ts | 50 +++-- src/gc.ts | 20 +- src/index.ts | 14 +- src/models/system.ts | 84 ++++---- src/monti-apm-agent.ts | 29 +-- src/ntp.test.ts | 4 +- src/ntp.ts | 41 ++-- src/retry.ts | 24 +-- src/tests/setup.ts | 2 +- 20 files changed, 387 insertions(+), 244 deletions(-) create mode 100644 .eslintrc.js create mode 100644 .idea/codeStyles/Project.xml create mode 100644 .idea/codeStyles/codeStyleConfig.xml create mode 100644 .idea/inspectionProfiles/Project_Default.xml create mode 100644 .idea/jsLinters/eslint.xml create mode 100644 .prettierrc.js diff --git a/.eslintrc.js b/.eslintrc.js new file mode 100644 index 0000000..e0cd363 --- /dev/null +++ b/.eslintrc.js @@ -0,0 +1,32 @@ +module.exports = { + plugins: ['prettier'], + extends: ['eslint:recommended', 'plugin:prettier/recommended'], + parser: '@typescript-eslint/parser', + root: true, + rules: { + 'no-console': 0, + 'no-inner-declarations': 0, + 'arrow-parens': ['error', 'always'], + semi: ['error', 'always'], + }, + env: { + node: true, + }, + overrides: [ + { + files: ['*.ts'], + extends: ['plugin:@typescript-eslint/recommended'], + rules: { + '@typescript-eslint/no-non-null-assertion': 0, + '@typescript-eslint/no-explicit-any': 0, + '@typescript-eslint/no-empty-interface': 0, + '@typescript-eslint/explicit-module-boundary-types': 0, + '@typescript-eslint/no-unused-vars': 0, + '@typescript-eslint/no-this-alias': 0, + '@typescript-eslint/ban-ts-comment': 0, + '@typescript-eslint/no-namespace': 0, + '@typescript-eslint/no-empty-function': 0, + }, + }, + ], +}; \ No newline at end of file diff --git a/.idea/codeStyles/Project.xml b/.idea/codeStyles/Project.xml new file mode 100644 index 0000000..1939cd0 --- /dev/null +++ b/.idea/codeStyles/Project.xml @@ -0,0 +1,64 @@ + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/.idea/codeStyles/codeStyleConfig.xml b/.idea/codeStyles/codeStyleConfig.xml new file mode 100644 index 0000000..79ee123 --- /dev/null +++ b/.idea/codeStyles/codeStyleConfig.xml @@ -0,0 +1,5 @@ + + + + \ No newline at end of file diff --git a/.idea/inspectionProfiles/Project_Default.xml b/.idea/inspectionProfiles/Project_Default.xml new file mode 100644 index 0000000..03d9549 --- /dev/null +++ b/.idea/inspectionProfiles/Project_Default.xml @@ -0,0 +1,6 @@ + + + + \ No newline at end of file diff --git a/.idea/jsLinters/eslint.xml b/.idea/jsLinters/eslint.xml new file mode 100644 index 0000000..541945b --- /dev/null +++ b/.idea/jsLinters/eslint.xml @@ -0,0 +1,6 @@ + + + + + \ No newline at end of file diff --git a/.prettierrc.js b/.prettierrc.js new file mode 100644 index 0000000..05e7bc5 --- /dev/null +++ b/.prettierrc.js @@ -0,0 +1,9 @@ +module.exports = { + semi: true, + trailingComma: "all", + singleQuote: true, + printWidth: 80, + tabWidth: 2, + bracketSpacing: true, + arrowParens: "always", +}; diff --git a/src/@types/chai.d.ts b/src/@types/chai.d.ts index 0121318..7f78a3e 100644 --- a/src/@types/chai.d.ts +++ b/src/@types/chai.d.ts @@ -1,16 +1,16 @@ -import type Chai from 'chai' -import type Mocha from 'mocha' +import type Chai from 'chai'; +import type Mocha from 'mocha'; declare global { - var expect: Chai.ExpectStatic; - var assert: Chai.AssertStatic; - var should: Chai.Should; + let expect: Chai.ExpectStatic; + let assert: Chai.AssertStatic; + let should: Chai.Should; - var describe: Mocha.SuiteFunction; - var it: Mocha.TestFunction; + let describe: Mocha.SuiteFunction; + let it: Mocha.TestFunction; - var before: Mocha.HookFunction; - var after: Mocha.HookFunction; - var beforeEach: Mocha.HookFunction; - var afterEach: Mocha.HookFunction; + let before: Mocha.HookFunction; + let after: Mocha.HookFunction; + let beforeEach: Mocha.HookFunction; + let afterEach: Mocha.HookFunction; } diff --git a/src/@types/process.d.ts b/src/@types/process.d.ts index 992a2cb..d2ce026 100644 --- a/src/@types/process.d.ts +++ b/src/@types/process.d.ts @@ -1,6 +1,5 @@ declare namespace NodeJS { interface Process extends EventEmitter { - /** * @internal * @deprecated @@ -18,4 +17,4 @@ declare namespace NodeJS { */ _getActiveStreams(): any[]; } -} \ No newline at end of file +} diff --git a/src/doc-sz-cache.test.ts b/src/doc-sz-cache.test.ts index b5a8093..abdaf06 100644 --- a/src/doc-sz-cache.test.ts +++ b/src/doc-sz-cache.test.ts @@ -1,6 +1,6 @@ import { expect } from 'chai'; import { LRUCache } from 'lru-cache'; -import { DocSzCache, DocSzCacheItem } from "./doc-sz-cache"; +import { DocSzCache, DocSzCacheItem } from './doc-sz-cache'; describe('DocSize Cache', () => { describe('DocSzCache', () => { @@ -33,39 +33,37 @@ describe('DocSize Cache', () => { it('should correctly retrieve size', () => { const cache = new DocSzCache(5, 3); - let size = cache.getSize('c1', 'q1', 'o1', []); + const size = cache.getSize('c1', 'q1', 'o1', []); expect(size).to.equal(0); }); it('should correctly score item based on CPU usage', () => { const cache = new DocSzCache(5, 10); - let item = new DocSzCacheItem(10); + const item = new DocSzCacheItem(10); item.values = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]; item.updated = Date.now(); cache.cpuUsage = 100; - let score = cache.getItemScore(item); + const score = cache.getItemScore(item); expect(score).to.be.within(0, 0.001); }); it('should determine if an update is needed based on item score', () => { const cache = new DocSzCache(5, 10); - let item = new DocSzCacheItem(10); + const item = new DocSzCacheItem(10); item.values = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]; item.updated = Date.now(); - let score = 0; + const score = 0; cache.getItemScore = function () { return score; }; expect(cache.needsUpdate(item)).to.be.false; }); - }); describe('DocSzCacheItem', () => { - it('should correctly instantiate the constructor', () => { const item = new DocSzCacheItem(10); expect(item.maxValues).to.equal(10); diff --git a/src/doc-sz-cache.ts b/src/doc-sz-cache.ts index 9ae3477..f49d982 100644 --- a/src/doc-sz-cache.ts +++ b/src/doc-sz-cache.ts @@ -2,119 +2,127 @@ import { LRUCache } from 'lru-cache'; import jsonStringify from 'json-stringify-safe'; interface IData { - length?: number; - size?: () => number; - get?: () => any; - forEach?: (callback: (element: any) => boolean) => void; + length?: number; + size?: () => number; + get?: () => any; + forEach?: (callback: (element: any) => boolean) => void; } export class DocSzCache { - public items: LRUCache; - public maxValues: number; - cpuUsage: number; - - constructor(maxItems: number, maxValues: number) { - this.items = new LRUCache({ max: maxItems }); - this.maxValues = maxValues; - this.cpuUsage = 0; + public items: LRUCache; + public maxValues: number; + cpuUsage: number; + + constructor(maxItems: number, maxValues: number) { + this.items = new LRUCache({ max: maxItems }); + this.maxValues = maxValues; + this.cpuUsage = 0; + } + + public setPcpu(pcpu: number): void { + this.cpuUsage = pcpu; + } + + public getSize(coll: any, query: any, opts: any, data: IData): number { + if ( + !( + data && + (data.length || (typeof data.size === 'function' && data.size())) + ) + ) { + return 0; } - public setPcpu(pcpu: number): void { - this.cpuUsage = pcpu; - } + const key = this.getKey(coll, query, opts); + let item = this.items.get(key); - public getSize(coll: any, query: any, opts: any, data: IData): number { - if (!(data && (data.length || (typeof data.size === 'function' && data.size())))) { - return 0; - } - - const key = this.getKey(coll, query, opts); - let item = this.items.get(key); - - if (!item) { - item = new DocSzCacheItem(this.maxValues); - this.items.set(key, item); - } - - if (this.needsUpdate(item)) { - let doc = {}; - if (typeof data.get === 'function' && data.forEach) { - // This is an IdMap - data.forEach((element: any) => { - doc = element; - return true; - }); - } else { - doc = data[0]; - } - const size = Buffer.byteLength(jsonStringify(doc), 'utf8'); - item.addData(size); - } - - return item.getValue(); + if (!item) { + item = new DocSzCacheItem(this.maxValues); + this.items.set(key, item); } - public getKey(coll: any, query: any, opts: any): string { - return jsonStringify([coll, query, opts]); + if (this.needsUpdate(item)) { + let doc = {}; + if (typeof data.get === 'function' && data.forEach) { + // This is an IdMap + data.forEach((element: any) => { + doc = element; + return true; + }); + } else { + doc = data[0]; + } + const size = Buffer.byteLength(jsonStringify(doc), 'utf8'); + item.addData(size); } - public getItemScore(item: DocSzCacheItem): number { - return [ - (item.maxValues - item.values.length) / item.maxValues, - (Date.now() - item.updated) / 60000, - (100 - this.cpuUsage) / 100, - ].map(score => (score > 1 ? 1 : score)) - .reduce((total, score) => total + score, 0) / 3; + return item.getValue(); + } + + public getKey(coll: any, query: any, opts: any): string { + return jsonStringify([coll, query, opts]); + } + + public getItemScore(item: DocSzCacheItem): number { + return ( + [ + (item.maxValues - item.values.length) / item.maxValues, + (Date.now() - item.updated) / 60000, + (100 - this.cpuUsage) / 100, + ] + .map((score) => (score > 1 ? 1 : score)) + .reduce((total, score) => total + score, 0) / 3 + ); + } + + public needsUpdate(item: DocSzCacheItem): boolean { + if (!item.values.length) { + return true; } - public needsUpdate(item: DocSzCacheItem): boolean { - if (!item.values.length) { - return true; - } - - const currentTime = Date.now(); - const timeSinceUpdate = currentTime - item.updated; - if (timeSinceUpdate > 1000 * 60) { - return true; - } - - return this.getItemScore(item) > 0.5; + const currentTime = Date.now(); + const timeSinceUpdate = currentTime - item.updated; + if (timeSinceUpdate > 1000 * 60) { + return true; } + + return this.getItemScore(item) > 0.5; + } } export class DocSzCacheItem { - maxValues: number; - updated: number; - values: number[]; - - constructor(maxValues: number) { - this.maxValues = maxValues; - this.updated = 0; - this.values = []; + maxValues: number; + updated: number; + values: number[]; + + constructor(maxValues: number) { + this.maxValues = maxValues; + this.updated = 0; + this.values = []; + } + + addData(value: number): void { + this.values.push(value); + this.updated = Date.now(); + + if (this.values.length > this.maxValues) { + this.values.shift(); } - - addData(value: number): void { - this.values.push(value); - this.updated = Date.now(); - - if (this.values.length > this.maxValues) { - this.values.shift(); - } + } + + getValue(): number { + const sorted = [...this.values].sort((a, b) => a - b); + let median = 0; + let idx; + + if (sorted.length % 2 === 0) { + idx = sorted.length / 2; + median = (sorted[idx] + sorted[idx - 1]) / 2; + } else { + idx = Math.floor(sorted.length / 2); + median = sorted[idx]; } - getValue(): number { - const sorted = [...this.values].sort((a, b) => a - b); - let median = 0; - let idx; - - if (sorted.length % 2 === 0) { - idx = sorted.length / 2; - median = (sorted[idx] + sorted[idx - 1]) / 2; - } else { - idx = Math.floor(sorted.length / 2); - median = sorted[idx]; - } - - return median; - } + return median; + } } diff --git a/src/environment.ts b/src/environment.ts index 3beb757..9fb35ad 100644 --- a/src/environment.ts +++ b/src/environment.ts @@ -1,2 +1,2 @@ export const isServer = typeof window === 'undefined'; -export const isClient = !isServer; \ No newline at end of file +export const isClient = !isServer; diff --git a/src/event-loop-monitor.ts b/src/event-loop-monitor.ts index c60c904..dca2284 100644 --- a/src/event-loop-monitor.ts +++ b/src/event-loop-monitor.ts @@ -1,10 +1,12 @@ import { EventEmitter } from 'events'; -function isNode () { - return typeof process !== 'undefined' && process.versions && process.versions.node; +function isNode() { + return ( + typeof process !== 'undefined' && process.versions && process.versions.node + ); } -function polyfillNow () { +function polyfillNow() { const [seconds, nanoseconds] = process.hrtime(); return seconds * 1000 + nanoseconds / 1000000; @@ -17,7 +19,7 @@ export class EventLoopMonitor extends EventEmitter { _totalLag = 0; _lastWatchTime: number | null = null; - constructor (timeoutMillis: number) { + constructor(timeoutMillis: number) { super(); this.timeoutMillis = timeoutMillis; this._watchLag = this._watchLag.bind(this); @@ -28,7 +30,7 @@ export class EventLoopMonitor extends EventEmitter { this._registerNowFunc(); } - start () { + start() { this._stopped = false; this._lastWatchTime = null; this._startTime = Date.now(); @@ -38,12 +40,12 @@ export class EventLoopMonitor extends EventEmitter { this._detectLag(); } - stop () { + stop() { this._stopped = true; this.removeAllListeners('lag'); } - status () { + status() { let pctBlock = 0; let elapsedTime = 0; if (!this._stopped && this._lastWatchTime) { @@ -51,10 +53,10 @@ export class EventLoopMonitor extends EventEmitter { pctBlock = (this._totalLag / elapsedTime) * 100; } - let statusObject = { + const statusObject = { pctBlock, elapsedTime, - totalLag: this._totalLag + totalLag: this._totalLag, }; this._startTime = this._lastWatchTime; @@ -63,20 +65,20 @@ export class EventLoopMonitor extends EventEmitter { return statusObject; } - _watchLag (lag) { + _watchLag(lag) { this._lastWatchTime = Date.now(); this._totalLag += lag; } - _detectLag () { - let self = this; - let start = self._now(); + _detectLag() { + const self = this; + const start = self._now(); setTimeout(function () { - let end = self._now(); - let elapsedTime = end - start; - let realDiff = elapsedTime - self.timeoutMillis; - let lag = Math.max(0, realDiff); + const end = self._now(); + const elapsedTime = end - start; + const realDiff = elapsedTime - self.timeoutMillis; + const lag = Math.max(0, realDiff); if (!self._stopped) { self.emit('lag', lag); @@ -85,11 +87,11 @@ export class EventLoopMonitor extends EventEmitter { }, self.timeoutMillis); } - _now (): number { + _now(): number { throw new Error('Not Implemented'); } - _registerNowFunc () { + _registerNowFunc() { if (isNode()) { const [major] = process.versions.node.split('.').map(Number); @@ -99,14 +101,18 @@ export class EventLoopMonitor extends EventEmitter { } const { - performance - // eslint-disable-next-line global-require + performance, + // eslint-disable-next-line @typescript-eslint/no-var-requires } = require('perf_hooks'); this._now = performance.now; return; } - if (typeof window !== 'undefined' && window.performance && window.performance.now) { + if ( + typeof window !== 'undefined' && + window.performance && + window.performance.now + ) { this._now = window.performance.now; return; } diff --git a/src/gc.ts b/src/gc.ts index 8a389b5..18cebea 100644 --- a/src/gc.ts +++ b/src/gc.ts @@ -2,26 +2,26 @@ import { PerformanceObserver, constants, performance } from 'perf_hooks'; export class GCMetrics { observer?: PerformanceObserver; - started: boolean = false; + started = false; metrics: Record; - constructor () { + constructor() { this.metrics = {}; this.reset(); } - start () { + start() { if (this.started) { return false; } this.started = true; - this.observer = new PerformanceObserver(list => { - list.getEntries().forEach(entry => { + this.observer = new PerformanceObserver((list) => { + list.getEntries().forEach((entry) => { // @ts-ignore @todo check if kind is still a thing - let metric = this._mapKindToMetric(entry.kind); + const metric = this._mapKindToMetric(entry.kind); if (!metric) { return; @@ -34,7 +34,7 @@ export class GCMetrics { this.observer.observe({ entryTypes: ['gc'], buffered: false }); } - _mapKindToMetric (gcKind: number): string | undefined { + _mapKindToMetric(gcKind: number): string | undefined { switch (gcKind) { case constants.NODE_PERFORMANCE_GC_MAJOR: return 'gcMajor'; @@ -44,18 +44,18 @@ export class GCMetrics { return 'gcIncremental'; case constants.NODE_PERFORMANCE_GC_WEAKCB: return 'gcWeakCB'; - default: + default: // no default console.log(`Monti APM: Unrecognized GC Kind: ${gcKind}`); } } - reset () { + reset() { this.metrics = { gcMajor: 0, gcMinor: 0, gcIncremental: 0, - gcWeakCB: 0 + gcWeakCB: 0, }; } } diff --git a/src/index.ts b/src/index.ts index 511c307..8142944 100644 --- a/src/index.ts +++ b/src/index.ts @@ -1,7 +1,7 @@ -export * from './monti-apm-agent' -export * from './models/system' -export * from './gc' -export * from './doc-sz-cache' -export * from './ntp' -export * from './event-loop-monitor' -export * from './environment' \ No newline at end of file +export * from './monti-apm-agent'; +export * from './models/system'; +export * from './gc'; +export * from './doc-sz-cache'; +export * from './ntp'; +export * from './event-loop-monitor'; +export * from './environment'; diff --git a/src/models/system.ts b/src/models/system.ts index 8100d02..f9baf73 100644 --- a/src/models/system.ts +++ b/src/models/system.ts @@ -1,15 +1,15 @@ -import { EventLoopMonitor } from "@/event-loop-monitor"; -import { DDSketch } from "monti-apm-sketches-js"; -import {GCMetrics} from "@/gc"; -import { Ntp } from "@/ntp"; -import { MontiApmAgent } from "@/monti-apm-agent"; +import { EventLoopMonitor } from '@/event-loop-monitor'; +import { DDSketch } from 'monti-apm-sketches-js'; +import { GCMetrics } from '@/gc'; +import { Ntp } from '@/ntp'; +import { MontiApmAgent } from '@/monti-apm-agent'; type CPUHistoryEntry = { time: number; usage: number; sys: number; user: number; -} +}; type MetricPayload = { startTime: number; @@ -34,9 +34,9 @@ type MetricPayload = { pcpuUser: number; pcpuSystem: number; cpuHistory: CPUHistoryEntry[]; -} +}; -export class System { +export class System { static _instance: System; static getInstance() { if (!System._instance) { @@ -53,7 +53,7 @@ export class System { gcMetrics: GCMetrics; cpuTime: [number, number]; previousCpuUsage: NodeJS.CpuUsage; - cpuHistory: CPUHistoryEntry[] = [] + cpuHistory: CPUHistoryEntry[] = []; currentCpuUsage = 0; constructor() { @@ -63,12 +63,12 @@ export class System { this.sessionTimeout = 1000 * 60 * 30; this.evloopHistogram = new DDSketch({ - alpha: 0.02 + alpha: 0.02, }); this.evloopMonitor = new EventLoopMonitor(200); this.evloopMonitor.start(); - this.evloopMonitor.on('lag', lag => { + this.evloopMonitor.on('lag', (lag) => { // store as microsecond this.evloopHistogram.add(lag * 1000); }); @@ -84,18 +84,18 @@ export class System { }, 2000); } - buildPayload () { + buildPayload() { + const now = Ntp._now(); - let now = Ntp._now(); - - let metrics: MetricPayload = {} as any; + const metrics: MetricPayload = {} as any; metrics.startTime = Ntp.instance.syncTime(this.startTime); metrics.endTime = Ntp.instance.syncTime(now); - let memoryUsage = process.memoryUsage(); + const memoryUsage = process.memoryUsage(); metrics.memory = memoryUsage.rss / (1024 * 1024); - metrics.memoryArrayBuffers = (memoryUsage.arrayBuffers || 0) / (1024 * 1024); + metrics.memoryArrayBuffers = + (memoryUsage.arrayBuffers || 0) / (1024 * 1024); metrics.memoryExternal = memoryUsage.external / (1024 * 1024); metrics.memoryHeapUsed = memoryUsage.heapUsed / (1024 * 1024); metrics.memoryHeapTotal = memoryUsage.heapTotal / (1024 * 1024); @@ -111,7 +111,7 @@ export class System { metrics.pctEvloopBlock = this.evloopMonitor.status().pctBlock; metrics.evloopHistogram = this.evloopHistogram; this.evloopHistogram = new DDSketch({ - alpha: 0.02 + alpha: 0.02, }); metrics.gcMajorDuration = this.gcMetrics.metrics.gcMajor; @@ -126,37 +126,37 @@ export class System { metrics.pcpuSystem = 0; if (this.cpuHistory.length > 0) { - let lastCpuUsage = this.cpuHistory[this.cpuHistory.length - 1]; + const lastCpuUsage = this.cpuHistory[this.cpuHistory.length - 1]; metrics.pcpu = lastCpuUsage.usage * 100; metrics.pcpuUser = lastCpuUsage.user * 100; metrics.pcpuSystem = lastCpuUsage.sys * 100; } - metrics.cpuHistory = this.cpuHistory.map(entry => ({ + metrics.cpuHistory = this.cpuHistory.map((entry) => ({ time: Ntp.instance.syncTime(entry.time), usage: entry.usage, sys: entry.sys, - user: entry.user + user: entry.user, })); this.cpuHistory = []; this.startTime = now; - return {systemMetrics: [metrics]}; + return { systemMetrics: [metrics] }; } - cpuUsage () { - let elapTimeMS = hrtimeToMS(process.hrtime(this.cpuTime)); - let elapUsage = process.cpuUsage(this.previousCpuUsage); - let elapUserMS = elapUsage.user / 1000; - let elapSystMS = elapUsage.system / 1000; - let totalUsageMS = elapUserMS + elapSystMS; - let totalUsagePercent = totalUsageMS / elapTimeMS; + cpuUsage() { + const elapTimeMS = hrtimeToMS(process.hrtime(this.cpuTime)); + const elapUsage = process.cpuUsage(this.previousCpuUsage); + const elapUserMS = elapUsage.user / 1000; + const elapSystMS = elapUsage.system / 1000; + const totalUsageMS = elapUserMS + elapSystMS; + const totalUsagePercent = totalUsageMS / elapTimeMS; this.cpuHistory.push({ time: Ntp._now(), usage: totalUsagePercent, user: elapUserMS / elapTimeMS, - sys: elapSystMS / elapUsage.system + sys: elapSystMS / elapUsage.system, }); this.currentCpuUsage = totalUsagePercent * 100; @@ -166,7 +166,7 @@ export class System { this.previousCpuUsage = process.cpuUsage(); } - handleSessionActivity (msg, session) { + handleSessionActivity(msg, session) { if (msg.msg === 'connect' && !msg.session) { this.countNewSession(session); } else if (['sub', 'method'].indexOf(msg.msg) !== -1) { @@ -175,21 +175,21 @@ export class System { } } session._activeAt = Date.now(); - }; + } - countNewSession (session) { + countNewSession(session) { if (!isLocalAddress(session.socket)) { this.newSessions++; } } - isSessionActive (session) { - let inactiveTime = Date.now() - session._activeAt; + isSessionActive(session) { + const inactiveTime = Date.now() - session._activeAt; return inactiveTime < this.sessionTimeout; } } -function hrtimeToMS (hrtime) { +function hrtimeToMS(hrtime) { return hrtime[0] * 1000 + hrtime[1] / 1000000; } @@ -197,17 +197,19 @@ function hrtimeToMS (hrtime) { // http://regex101.com/r/iF3yR3/2 // eslint-disable-next-line no-useless-escape -let isLocalHostRegex = /^(?:.*\.local|localhost)(?:\:\d+)?|127(?:\.\d{1,3}){3}|192\.168(?:\.\d{1,3}){2}|10(?:\.\d{1,3}){3}|172\.(?:1[6-9]|2\d|3[0-1])(?:\.\d{1,3}){2}$/; +const isLocalHostRegex = + /^(?:.*\.local|localhost)(?::\d+)?|127(?:\.\d{1,3}){3}|192\.168(?:\.\d{1,3}){2}|10(?:\.\d{1,3}){3}|172\.(?:1[6-9]|2\d|3[0-1])(?:\.\d{1,3}){2}$/; // http://regex101.com/r/hM5gD8/1 -let isLocalAddressRegex = /^127(?:\.\d{1,3}){3}|192\.168(?:\.\d{1,3}){2}|10(?:\.\d{1,3}){3}|172\.(?:1[6-9]|2\d|3[0-1])(?:\.\d{1,3}){2}$/; +const isLocalAddressRegex = + /^127(?:\.\d{1,3}){3}|192\.168(?:\.\d{1,3}){2}|10(?:\.\d{1,3}){3}|172\.(?:1[6-9]|2\d|3[0-1])(?:\.\d{1,3}){2}$/; -function isLocalAddress (socket) { - let host = socket.headers['host']; +function isLocalAddress(socket) { + const host = socket.headers['host']; if (host) { return isLocalHostRegex.test(host); } - let address = socket.headers['x-forwarded-for'] || socket.remoteAddress; + const address = socket.headers['x-forwarded-for'] || socket.remoteAddress; if (address) { return isLocalAddressRegex.test(address); } diff --git a/src/monti-apm-agent.ts b/src/monti-apm-agent.ts index 8a973f4..db35295 100644 --- a/src/monti-apm-agent.ts +++ b/src/monti-apm-agent.ts @@ -1,9 +1,9 @@ -import { DocSzCache } from "@/doc-sz-cache"; -import { Monti } from "monti-apm-core"; -import os from "os"; +import { DocSzCache } from '@/doc-sz-cache'; +import { Monti } from 'monti-apm-core'; +import os from 'os'; import { version } from '../package.json'; -import config from 'config' -import { System } from "@/models/system"; +import config from 'config'; +import { System } from '@/models/system'; export class MontiApmAgent { static instance: MontiApmAgent; @@ -22,7 +22,7 @@ export class MontiApmAgent { appId: string, appSecret: string, endpoint: string = config.get('Monti.endpoint'), - hostname = config.get('Monti.hostname') as string || os.hostname(), + hostname = (config.get('Monti.hostname') as string) || os.hostname(), ) { this.appId = appId; this.appSecret = appSecret; @@ -35,7 +35,7 @@ export class MontiApmAgent { appSecret, endpoint, hostname, - agentVersion: `node-agent@${version}` + agentVersion: `node-agent@${version}`, }); } @@ -45,20 +45,25 @@ export class MontiApmAgent { endpoint?: string, hostname?: string, ) { - MontiApmAgent.instance = new MontiApmAgent(appId, appSecret, endpoint, hostname); + MontiApmAgent.instance = new MontiApmAgent( + appId, + appSecret, + endpoint, + hostname, + ); } async buildPayload() { return { host: this.hostname, - ... this.systemModel.buildPayload() - } + ...this.systemModel.buildPayload(), + }; } async sendPayload() { const payload = await this.buildPayload(); - await this.core.sendData(payload) + await this.core.sendData(payload); } } @@ -67,4 +72,4 @@ if (config.get('Monti.appId') && config.get('Monti.appSecret')) { config.get('Monti.appId'), config.get('Monti.appSecret'), ); -} \ No newline at end of file +} diff --git a/src/ntp.test.ts b/src/ntp.test.ts index f843a3f..a2f49d1 100644 --- a/src/ntp.test.ts +++ b/src/ntp.test.ts @@ -1,5 +1,5 @@ import { expect } from 'chai'; -import { Ntp } from "@/ntp"; +import { Ntp } from '@/ntp'; describe('Ntp', () => { describe('Ntp._now()', () => { @@ -12,7 +12,7 @@ describe('Ntp', () => { it('should handle Date.now as Date object', () => { const oldDateNow = Date.now; - Date.now = function(): any { + Date.now = function (): any { return new Date(); }; diff --git a/src/ntp.ts b/src/ntp.ts index ff1ed6d..489eb42 100644 --- a/src/ntp.ts +++ b/src/ntp.ts @@ -1,6 +1,6 @@ -import { Retry } from "@/retry"; -import { isServer } from "@/environment"; -import fetch from 'cross-fetch' +import { Retry } from '@/retry'; +import { isServer } from '@/environment'; +import fetch from 'cross-fetch'; interface NtpOptions { endpoint?: string; @@ -29,7 +29,7 @@ export class Ntp { this.reSync = new Retry({ baseTimeout: 1000 * 60, maxTimeout: 1000 * 60 * 10, - minCount: 0 + minCount: 0, }); } @@ -83,7 +83,7 @@ export class Ntp { baseTimeout: 1000 * 20, maxTimeout: 1000 * 60, minCount: 1, - minTimeout: 0 + minTimeout: 0, }); const syncTime = () => { @@ -99,7 +99,7 @@ export class Ntp { }; const cacheDns = () => { - this.getServerTime(err => { + this.getServerTime((err) => { if (!err) { calculateTimeDiff(); } else { @@ -129,7 +129,9 @@ export class Ntp { syncTime(); } - public getServerTime(callback: (err?: Error, serverTime?: number) => void): void { + public getServerTime( + callback: (err?: Error, serverTime?: number) => void, + ): void { if (this.endpoint === null) { throw new Error('getServerTime requires the endpoint to be set'); } @@ -138,26 +140,28 @@ export class Ntp { throw new Error('getServerTime requires NTP to be enabled'); } - const url = `${this.endpoint}${this.path}?noCache=${new Date().getTime()}-${Math.random()}`; + const url = `${this.endpoint}${ + this.path + }?noCache=${new Date().getTime()}-${Math.random()}`; fetch(url, { method: 'GET', headers: { - 'Accept': 'application/json', - 'Content-Type': 'application/json' - } + Accept: 'application/json', + 'Content-Type': 'application/json', + }, }) - .then(response => { + .then((response) => { if (!response.ok) { throw new Error(`HTTP error! Status: ${response.status}`); } return response.text(); }) - .then(content => { + .then((content) => { const serverTime = parseInt(content, 10); callback(undefined, serverTime); }) - .catch(error => { + .catch((error) => { callback(error); }); } @@ -165,14 +169,19 @@ export class Ntp { function getLogger(): (message?: any, ...optionalParams: any[]) => void { if (isServer) { + // eslint-disable-next-line @typescript-eslint/no-var-requires return require('debug')('kadira:ntp'); } return function log(message?: any, ...optionalParams: any[]) { let canLog = false; try { - canLog = global.localStorage.getItem('LOG_KADIRA') !== null && typeof console !== 'undefined'; - } catch (e) { } + canLog = + global.localStorage.getItem('LOG_KADIRA') !== null && + typeof console !== 'undefined'; + } catch (e) { + /* empty */ + } if (!canLog) { return; diff --git a/src/retry.ts b/src/retry.ts index d097dd3..8a9dac5 100644 --- a/src/retry.ts +++ b/src/retry.ts @@ -1,5 +1,3 @@ -import { randomBytes } from 'crypto'; - interface RetryOptions { baseTimeout?: number; exponent?: number; @@ -19,13 +17,13 @@ export class Retry { private retryTimer: NodeJS.Timeout | null; constructor({ - baseTimeout = 1000, - exponent = 2.2, - maxTimeout = 5 * 60000, - minTimeout = 10, - minCount = 2, - fuzz = 0.5 - }: RetryOptions = {}) { + baseTimeout = 1000, + exponent = 2.2, + maxTimeout = 5 * 60000, + minTimeout = 10, + minCount = 2, + fuzz = 0.5, + }: RetryOptions = {}) { this.baseTimeout = baseTimeout; this.exponent = exponent; this.maxTimeout = maxTimeout; @@ -49,17 +47,13 @@ export class Retry { let timeout = Math.min( this.maxTimeout, - this.baseTimeout * Math.pow(this.exponent, count) + this.baseTimeout * Math.pow(this.exponent, count), ); - timeout *= this.randomFraction() * this.fuzz + (1 - this.fuzz / 2); + timeout *= Math.random() * this.fuzz + (1 - this.fuzz / 2); return Math.ceil(timeout); } - private randomFraction(): number { - return parseInt(randomBytes(8).toString('hex'), 16) / 0xffffffffffffffff; - } - public retryLater(count: number, fn: () => void): number { const timeout = this._timeout(count); if (this.retryTimer) { diff --git a/src/tests/setup.ts b/src/tests/setup.ts index be07b12..7758bed 100644 --- a/src/tests/setup.ts +++ b/src/tests/setup.ts @@ -1,3 +1,3 @@ import 'chai/register-expect.js'; import 'chai/register-should.js'; -import 'chai/register-assert.js'; \ No newline at end of file +import 'chai/register-assert.js'; From 88ce15b3cc551fb3c6e441797c592dbb0c0a2e80 Mon Sep 17 00:00:00 2001 From: Leonardo Venturini Date: Tue, 29 Aug 2023 09:50:50 -0400 Subject: [PATCH 27/37] add base demo app --- demo/.env.example | 3 +++ demo/.gitignore | 2 ++ demo/index.js | 8 ++++++++ demo/package-lock.json | 13 +++++++++++++ demo/package.json | 15 +++++++++++++++ 5 files changed, 41 insertions(+) create mode 100644 demo/.env.example create mode 100644 demo/.gitignore create mode 100644 demo/index.js create mode 100644 demo/package-lock.json create mode 100644 demo/package.json diff --git a/demo/.env.example b/demo/.env.example new file mode 100644 index 0000000..69deeb0 --- /dev/null +++ b/demo/.env.example @@ -0,0 +1,3 @@ +MONTI_APP_ID= +MONTI_APP_SECRET= +MONTI_APP_ENDPOINT=http://localhost:11011 \ No newline at end of file diff --git a/demo/.gitignore b/demo/.gitignore new file mode 100644 index 0000000..97aca2e --- /dev/null +++ b/demo/.gitignore @@ -0,0 +1,2 @@ +.env +node_modules \ No newline at end of file diff --git a/demo/index.js b/demo/index.js new file mode 100644 index 0000000..d5e48d5 --- /dev/null +++ b/demo/index.js @@ -0,0 +1,8 @@ +let count = 0; + +console.log(process.env.MONTI_APP_ID); + +setInterval(() => { + count += 1; + console.log(count); +}, 1000); diff --git a/demo/package-lock.json b/demo/package-lock.json new file mode 100644 index 0000000..ac89bba --- /dev/null +++ b/demo/package-lock.json @@ -0,0 +1,13 @@ +{ + "name": "demo", + "version": "1.0.0", + "lockfileVersion": 1, + "requires": true, + "dependencies": { + "dotenv": { + "version": "16.3.1", + "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-16.3.1.tgz", + "integrity": "sha512-IPzF4w4/Rd94bA9imS68tZBaYyBWSCE47V1RGuMrB94iyTOIEwRmVL2x/4An+6mETpLrKJ5hQkB8W4kFAadeIQ==" + } + } +} diff --git a/demo/package.json b/demo/package.json new file mode 100644 index 0000000..361ff4e --- /dev/null +++ b/demo/package.json @@ -0,0 +1,15 @@ +{ + "name": "demo", + "version": "1.0.0", + "description": "", + "main": "index.js", + "scripts": { + "start": "node -r dotenv/config index.js" + }, + "keywords": [], + "author": "Monti APM", + "license": "MIT", + "dependencies": { + "dotenv": "^16.3.1" + } +} From 11d75c1433af3e09dd8c74835ab1d8db38ae0601 Mon Sep 17 00:00:00 2001 From: Leonardo Venturini Date: Wed, 30 Aug 2023 09:34:54 -0400 Subject: [PATCH 28/37] use cosmiconfig and environment variables --- .idea/node-agent.iml | 1 + config/custom-environment-variables.json | 8 - config/default.json | 8 - demo/.env.example | 2 +- demo/.montirc.yaml | 1 + demo/index.js | 2 + demo/package.json | 1 + package-lock.json | 282 ++++++++++++++++++----- package.json | 6 +- src/config.ts | 15 ++ src/monti-apm-agent.ts | 15 +- 11 files changed, 255 insertions(+), 86 deletions(-) delete mode 100644 config/custom-environment-variables.json delete mode 100644 config/default.json create mode 100644 demo/.montirc.yaml create mode 100644 src/config.ts diff --git a/.idea/node-agent.iml b/.idea/node-agent.iml index 24643cc..d3f1fda 100644 --- a/.idea/node-agent.iml +++ b/.idea/node-agent.iml @@ -5,6 +5,7 @@ + diff --git a/config/custom-environment-variables.json b/config/custom-environment-variables.json deleted file mode 100644 index 0c1b807..0000000 --- a/config/custom-environment-variables.json +++ /dev/null @@ -1,8 +0,0 @@ -{ - "Monti": { - "appId": "MONTI_APP_ID", - "appSecret": "MONTI_APP_SECRET", - "endpoint": "MONTI_ENDPOINT", - "hostname": "MONTI_HOSTNAME" - } -} \ No newline at end of file diff --git a/config/default.json b/config/default.json deleted file mode 100644 index 6e1343f..0000000 --- a/config/default.json +++ /dev/null @@ -1,8 +0,0 @@ -{ - "Monti": { - "appId": "", - "appSecret": "", - "endpoint": "https://engine.montiapm.com", - "hostname": "" - } -} \ No newline at end of file diff --git a/demo/.env.example b/demo/.env.example index 69deeb0..0e4be04 100644 --- a/demo/.env.example +++ b/demo/.env.example @@ -1,3 +1,3 @@ MONTI_APP_ID= MONTI_APP_SECRET= -MONTI_APP_ENDPOINT=http://localhost:11011 \ No newline at end of file +MONTI_ENDPOINT=http://localhost:11011 \ No newline at end of file diff --git a/demo/.montirc.yaml b/demo/.montirc.yaml new file mode 100644 index 0000000..878efd9 --- /dev/null +++ b/demo/.montirc.yaml @@ -0,0 +1 @@ +hostname: 'localhost' \ No newline at end of file diff --git a/demo/index.js b/demo/index.js index d5e48d5..d7f070e 100644 --- a/demo/index.js +++ b/demo/index.js @@ -1,3 +1,5 @@ +import '@monti-apm/agent'; + let count = 0; console.log(process.env.MONTI_APP_ID); diff --git a/demo/package.json b/demo/package.json index 361ff4e..2350db4 100644 --- a/demo/package.json +++ b/demo/package.json @@ -3,6 +3,7 @@ "version": "1.0.0", "description": "", "main": "index.js", + "type": "module", "scripts": { "start": "node -r dotenv/config index.js" }, diff --git a/package-lock.json b/package-lock.json index 74c1499..6d2e6a5 100644 --- a/package-lock.json +++ b/package-lock.json @@ -10,13 +10,12 @@ "license": "MIT", "dependencies": { "axios": "1.4.0", - "config": "^3.3.9", + "cosmiconfig": "^8.2.0", "cross-fetch": "^4.0.0", "debug": "^4.3.4", "eventemitter2": "6.4.9", "json-stringify-safe": "^5.0.1", "lru-cache": "^10.0.1", - "monti-apm-core": "^1.7.5", "monti-apm-sketches-js": "^0.0.3", "remeda": "1.24.0", "uuid": "^9.0.0" @@ -56,6 +55,167 @@ "node": ">=0.10.0" } }, + "node_modules/@babel/code-frame": { + "version": "7.22.13", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.22.13.tgz", + "integrity": "sha512-XktuhWlJ5g+3TJXc5upd9Ks1HutSArik6jf2eAjYFyIOf4ej3RN+184cZbzDvbPnuTJIUhPKKJE3cIsYTiAT3w==", + "dependencies": { + "@babel/highlight": "^7.22.13", + "chalk": "^2.4.2" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/code-frame/node_modules/ansi-styles": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", + "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", + "dependencies": { + "color-convert": "^1.9.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/@babel/code-frame/node_modules/chalk": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", + "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", + "dependencies": { + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/@babel/code-frame/node_modules/color-convert": { + "version": "1.9.3", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", + "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", + "dependencies": { + "color-name": "1.1.3" + } + }, + "node_modules/@babel/code-frame/node_modules/color-name": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", + "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==" + }, + "node_modules/@babel/code-frame/node_modules/escape-string-regexp": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", + "integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==", + "engines": { + "node": ">=0.8.0" + } + }, + "node_modules/@babel/code-frame/node_modules/has-flag": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", + "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==", + "engines": { + "node": ">=4" + } + }, + "node_modules/@babel/code-frame/node_modules/supports-color": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", + "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", + "dependencies": { + "has-flag": "^3.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/@babel/helper-validator-identifier": { + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.22.5.tgz", + "integrity": "sha512-aJXu+6lErq8ltp+JhkJUfk1MTGyuA4v7f3pA+BJ5HLfNC6nAQ0Cpi9uOquUj8Hehg0aUiHzWQbOVJGao6ztBAQ==", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/highlight": { + "version": "7.22.13", + "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.22.13.tgz", + "integrity": "sha512-C/BaXcnnvBCmHTpz/VGZ8jgtE2aYlW4hxDhseJAWZb7gqGM/qtCK6iZUb0TyKFf7BOUsBH7Q7fkRsDRhg1XklQ==", + "dependencies": { + "@babel/helper-validator-identifier": "^7.22.5", + "chalk": "^2.4.2", + "js-tokens": "^4.0.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/highlight/node_modules/ansi-styles": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", + "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", + "dependencies": { + "color-convert": "^1.9.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/@babel/highlight/node_modules/chalk": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", + "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", + "dependencies": { + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/@babel/highlight/node_modules/color-convert": { + "version": "1.9.3", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", + "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", + "dependencies": { + "color-name": "1.1.3" + } + }, + "node_modules/@babel/highlight/node_modules/color-name": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", + "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==" + }, + "node_modules/@babel/highlight/node_modules/escape-string-regexp": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", + "integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==", + "engines": { + "node": ">=0.8.0" + } + }, + "node_modules/@babel/highlight/node_modules/has-flag": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", + "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==", + "engines": { + "node": ">=4" + } + }, + "node_modules/@babel/highlight/node_modules/supports-color": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", + "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", + "dependencies": { + "has-flag": "^3.0.0" + }, + "engines": { + "node": ">=4" + } + }, "node_modules/@eslint-community/eslint-utils": { "version": "4.4.0", "resolved": "https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.4.0.tgz", @@ -889,8 +1049,7 @@ "node_modules/argparse": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", - "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", - "dev": true + "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==" }, "node_modules/array-union": { "version": "2.1.0", @@ -1125,7 +1284,6 @@ "version": "3.1.0", "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==", - "dev": true, "engines": { "node": ">=6" } @@ -1291,17 +1449,6 @@ "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==", "dev": true }, - "node_modules/config": { - "version": "3.3.9", - "resolved": "https://registry.npmjs.org/config/-/config-3.3.9.tgz", - "integrity": "sha512-G17nfe+cY7kR0wVpc49NCYvNtelm/pPy8czHoFkAgtV1lkmcp7DHtWCdDu+C9Z7gb2WVqa9Tm3uF9aKaPbCfhg==", - "dependencies": { - "json5": "^2.2.3" - }, - "engines": { - "node": ">= 10.0.0" - } - }, "node_modules/content-disposition": { "version": "0.5.4", "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.4.tgz", @@ -1314,6 +1461,23 @@ "node": ">= 0.6" } }, + "node_modules/cosmiconfig": { + "version": "8.2.0", + "resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-8.2.0.tgz", + "integrity": "sha512-3rTMnFJA1tCOPwRxtgF4wd7Ab2qvDbL8jX+3smjIbS4HlZBagTlpERbdN7iAbWlrfxE3M8c27kTwTawQ7st+OQ==", + "dependencies": { + "import-fresh": "^3.2.1", + "js-yaml": "^4.1.0", + "parse-json": "^5.0.0", + "path-type": "^4.0.0" + }, + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/d-fischer" + } + }, "node_modules/cross-fetch": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/cross-fetch/-/cross-fetch-4.0.0.tgz", @@ -1493,6 +1657,14 @@ "once": "^1.4.0" } }, + "node_modules/error-ex": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.2.tgz", + "integrity": "sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g==", + "dependencies": { + "is-arrayish": "^0.2.1" + } + }, "node_modules/escalade": { "version": "3.1.1", "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.1.tgz", @@ -2315,7 +2487,6 @@ "version": "3.3.0", "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.0.tgz", "integrity": "sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw==", - "dev": true, "dependencies": { "parent-module": "^1.0.0", "resolve-from": "^4.0.0" @@ -2352,6 +2523,11 @@ "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", "dev": true }, + "node_modules/is-arrayish": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz", + "integrity": "sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg==" + }, "node_modules/is-binary-path": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz", @@ -2448,11 +2624,15 @@ "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==", "dev": true }, + "node_modules/js-tokens": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", + "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==" + }, "node_modules/js-yaml": { "version": "4.1.0", "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==", - "dev": true, "dependencies": { "argparse": "^2.0.1" }, @@ -2466,6 +2646,11 @@ "integrity": "sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ==", "dev": true }, + "node_modules/json-parse-even-better-errors": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/json-parse-even-better-errors/-/json-parse-even-better-errors-2.3.1.tgz", + "integrity": "sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==" + }, "node_modules/json-schema-traverse": { "version": "0.4.1", "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", @@ -2483,17 +2668,6 @@ "resolved": "https://registry.npmjs.org/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz", "integrity": "sha512-ZClg6AaYvamvYEE82d3Iyd3vSSIjQ+odgjaTzRuO3s7toCdFKczob2i0zCh7JE8kWn17yvAWhUVxvqGwUalsRA==" }, - "node_modules/json5": { - "version": "2.2.3", - "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.3.tgz", - "integrity": "sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==", - "bin": { - "json5": "lib/cli.js" - }, - "engines": { - "node": ">=6" - } - }, "node_modules/keyv": { "version": "4.5.3", "resolved": "https://registry.npmjs.org/keyv/-/keyv-4.5.3.tgz", @@ -2516,6 +2690,11 @@ "node": ">= 0.8.0" } }, + "node_modules/lines-and-columns": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/lines-and-columns/-/lines-and-columns-1.2.4.tgz", + "integrity": "sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==" + }, "node_modules/locate-path": { "version": "6.0.0", "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz", @@ -2753,31 +2932,6 @@ "url": "https://github.com/chalk/supports-color?sponsor=1" } }, - "node_modules/monti-apm-core": { - "version": "1.7.5", - "resolved": "https://registry.npmjs.org/monti-apm-core/-/monti-apm-core-1.7.5.tgz", - "integrity": "sha512-IYHB3PF5h8HFQDQ0N2h3wyIdCo412YtkURiYgc9tgW2PAppGlMQk9U8ESBFgpi/I31yeP9ilw5Yb03Mgf1ND4Q==", - "dependencies": { - "axios": "^0.21.4", - "debug": "^3.2.6" - } - }, - "node_modules/monti-apm-core/node_modules/axios": { - "version": "0.21.4", - "resolved": "https://registry.npmjs.org/axios/-/axios-0.21.4.tgz", - "integrity": "sha512-ut5vewkiu8jjGBdqpM44XxjuCjq9LAKeHVmoVfHVzy8eHgxxq8SbAVQNovDA8mVi05kP0Ea/n/UzcSHcTJQfNg==", - "dependencies": { - "follow-redirects": "^1.14.0" - } - }, - "node_modules/monti-apm-core/node_modules/debug": { - "version": "3.2.7", - "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", - "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", - "dependencies": { - "ms": "^2.1.1" - } - }, "node_modules/monti-apm-sketches-js": { "version": "0.0.3", "resolved": "https://registry.npmjs.org/monti-apm-sketches-js/-/monti-apm-sketches-js-0.0.3.tgz", @@ -3041,7 +3195,6 @@ "version": "1.0.1", "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz", "integrity": "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==", - "dev": true, "dependencies": { "callsites": "^3.0.0" }, @@ -3049,6 +3202,23 @@ "node": ">=6" } }, + "node_modules/parse-json": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-5.2.0.tgz", + "integrity": "sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg==", + "dependencies": { + "@babel/code-frame": "^7.0.0", + "error-ex": "^1.3.1", + "json-parse-even-better-errors": "^2.3.0", + "lines-and-columns": "^1.1.6" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/path-exists": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", @@ -3105,7 +3275,6 @@ "version": "4.0.0", "resolved": "https://registry.npmjs.org/path-type/-/path-type-4.0.0.tgz", "integrity": "sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==", - "dev": true, "engines": { "node": ">=8" } @@ -3341,7 +3510,6 @@ "version": "4.0.0", "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz", "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==", - "dev": true, "engines": { "node": ">=4" } diff --git a/package.json b/package.json index 9e53d5b..3f2c0d4 100644 --- a/package.json +++ b/package.json @@ -12,7 +12,8 @@ "test:dist": "mocha 'dist/**/*.test.js' --exit --watch=false", "test": "mocha --extension=ts --require=@swc/register --file=src/tests/setup.ts --exit --watch=false src/**/*.test.ts", "test:watch": "nodemon --exec 'npm run test' -e js --watch src", - "prepublishOnly": "npm run clean && npm run build && npm run types" + "compile": "npm run clean && npm run build && npm run types", + "prepublishOnly": "npm run compile" }, "repository": { "type": "git", @@ -58,13 +59,12 @@ }, "dependencies": { "axios": "1.4.0", - "config": "^3.3.9", + "cosmiconfig": "^8.2.0", "cross-fetch": "^4.0.0", "debug": "^4.3.4", "eventemitter2": "6.4.9", "json-stringify-safe": "^5.0.1", "lru-cache": "^10.0.1", - "monti-apm-core": "^1.7.5", "monti-apm-sketches-js": "^0.0.3", "remeda": "1.24.0", "uuid": "^9.0.0" diff --git a/src/config.ts b/src/config.ts new file mode 100644 index 0000000..c544d50 --- /dev/null +++ b/src/config.ts @@ -0,0 +1,15 @@ +import { cosmiconfigSync } from 'cosmiconfig'; + +const moduleName = 'monti'; + +const explorerSync = cosmiconfigSync(moduleName, {}); + +const search = explorerSync.search(); + +export const config = { + appId: process.env.MONTI_APP_ID || undefined, + appSecret: process.env.MONTI_APP_SECRET || undefined, + endpoint: process.env.MONTI_ENDPOINT || 'https://engine.montiapm.com', + hostname: process.env.MONTI_HOSTNAME || undefined, + ...(search ? search.config : {}), +}; diff --git a/src/monti-apm-agent.ts b/src/monti-apm-agent.ts index db35295..27ef2db 100644 --- a/src/monti-apm-agent.ts +++ b/src/monti-apm-agent.ts @@ -1,9 +1,9 @@ import { DocSzCache } from '@/doc-sz-cache'; -import { Monti } from 'monti-apm-core'; +import { Monti } from '@monti-apm/core'; import os from 'os'; import { version } from '../package.json'; -import config from 'config'; import { System } from '@/models/system'; +import { config } from '@/config'; export class MontiApmAgent { static instance: MontiApmAgent; @@ -21,8 +21,8 @@ export class MontiApmAgent { constructor( appId: string, appSecret: string, - endpoint: string = config.get('Monti.endpoint'), - hostname = (config.get('Monti.hostname') as string) || os.hostname(), + endpoint: string = config.endpoint, + hostname = config.hostname || os.hostname(), ) { this.appId = appId; this.appSecret = appSecret; @@ -67,9 +67,6 @@ export class MontiApmAgent { } } -if (config.get('Monti.appId') && config.get('Monti.appSecret')) { - MontiApmAgent.connect( - config.get('Monti.appId'), - config.get('Monti.appSecret'), - ); +if (config.appId && config.appSecret) { + MontiApmAgent.connect(config.appId, config.appSecret); } From 2d798d5792ae4d1d1a99ad14e5c72174f748344d Mon Sep 17 00:00:00 2001 From: Leonardo Venturini Date: Wed, 30 Aug 2023 10:15:24 -0400 Subject: [PATCH 29/37] schedule send payload --- src/monti-apm-agent.ts | 32 +++++++++++++++++++++++++++++++- 1 file changed, 31 insertions(+), 1 deletion(-) diff --git a/src/monti-apm-agent.ts b/src/monti-apm-agent.ts index 27ef2db..f3c5f82 100644 --- a/src/monti-apm-agent.ts +++ b/src/monti-apm-agent.ts @@ -12,6 +12,8 @@ export class MontiApmAgent { appId: string; hostname: string; + payloadTimeout: number; + core: Monti; docSzCache = new DocSzCache(100000, 10); @@ -23,11 +25,12 @@ export class MontiApmAgent { appSecret: string, endpoint: string = config.endpoint, hostname = config.hostname || os.hostname(), + payloadTimeout = 20_000, ) { this.appId = appId; this.appSecret = appSecret; this.hostname = hostname; - + this.payloadTimeout = payloadTimeout; this.systemModel = System.getInstance(); this.core = new Monti({ @@ -37,6 +40,31 @@ export class MontiApmAgent { hostname, agentVersion: `node-agent@${version}`, }); + + this.core + ._checkAuth() + .then(() => { + console.log('Monti APM: Connected'); + + // Kadira._sendAppStats(); + this.schedulePayloadSend(); + }) + .catch(function (err) { + if (err.message === 'Unauthorized') { + console.log( + 'Monti APM: Authentication failed, check your "appId" & "appSecret"', + ); + } else { + console.log(`Monti APM: Unable to connect. ${err.message}`); + } + }); + } + + schedulePayloadSend() { + setTimeout(() => { + this.schedulePayloadSend(); + this.sendPayload(); + }, this.payloadTimeout); } static connect( @@ -63,6 +91,8 @@ export class MontiApmAgent { async sendPayload() { const payload = await this.buildPayload(); + console.log('Sending payload', payload); + await this.core.sendData(payload); } } From 2f6238996d46747126dd5dbcab6219d81116cff7 Mon Sep 17 00:00:00 2001 From: Leonardo Venturini Date: Wed, 30 Aug 2023 10:28:04 -0400 Subject: [PATCH 30/37] remove non existent function call --- src/models/system.ts | 1 - 1 file changed, 1 deletion(-) diff --git a/src/models/system.ts b/src/models/system.ts index f9baf73..98c790c 100644 --- a/src/models/system.ts +++ b/src/models/system.ts @@ -105,7 +105,6 @@ export class System { metrics.activeRequests = process._getActiveRequests().length; metrics.activeHandles = process._getActiveHandles().length; - metrics.activeStreams = process._getActiveStreams().length; // track eventloop metrics metrics.pctEvloopBlock = this.evloopMonitor.status().pctBlock; From 238312016a6598633e80121314b0fc81ad4d847a Mon Sep 17 00:00:00 2001 From: Leonardo Venturini Date: Thu, 31 Aug 2023 08:33:11 -0400 Subject: [PATCH 31/37] add event loop monitor tests --- src/@types/process.d.ts | 5 --- src/event-loop-monitor.test.ts | 64 ++++++++++++++++++++++++++++++++++ src/event-loop-monitor.ts | 4 +-- src/models/system.ts | 1 - 4 files changed, 66 insertions(+), 8 deletions(-) create mode 100644 src/event-loop-monitor.test.ts diff --git a/src/@types/process.d.ts b/src/@types/process.d.ts index d2ce026..786bb1a 100644 --- a/src/@types/process.d.ts +++ b/src/@types/process.d.ts @@ -11,10 +11,5 @@ declare namespace NodeJS { * @internal */ _getActiveHandles(): any[]; - - /** - * @internal - */ - _getActiveStreams(): any[]; } } diff --git a/src/event-loop-monitor.test.ts b/src/event-loop-monitor.test.ts new file mode 100644 index 0000000..5a34134 --- /dev/null +++ b/src/event-loop-monitor.test.ts @@ -0,0 +1,64 @@ +import { expect } from 'chai'; +import crypto from 'crypto'; +import { EventLoopMonitor } from '@/event-loop-monitor'; + +function blockEventLoop() { + const start = Date.now(); + while (Date.now() - start < 100) { + const salt = crypto.randomBytes(128).toString('base64'); + crypto.pbkdf2Sync('42555', salt, 10000, 512, 'sha512'); + } +} + +describe('EventLoopMonitor', function () { + it('basic usage', function (done) { + const monitor = new EventLoopMonitor(100); + monitor.start(); + + // Saturate the event loop so that we can detect lag. + blockEventLoop(); + + setTimeout(function () { + const status = monitor.status(); + + expect(status.pctBlock).to.be.above(0); + expect(status.totalLag).to.be.above(0); + expect(status.elapsedTime).to.be.above(0); + + monitor.stop(); + done(); + }, 300); + }); + + it('usage just after created', function (done) { + const monitor = new EventLoopMonitor(100); + monitor.start(); + + const status = monitor.status(); + expect(status.pctBlock).to.equal(0); + + monitor.stop(); + done(); + }); + + it('usage just after stopped', function (done) { + const monitor = new EventLoopMonitor(100); + monitor.start(); + + // Saturate the event loop so that we can detect lag. + blockEventLoop(); + + setTimeout(function () { + let status = monitor.status(); + + expect(status.pctBlock).to.be.above(0); + + monitor.stop(); + + status = monitor.status(); + expect(status.pctBlock).to.equal(0); + + done(); + }, 200); + }); +}); diff --git a/src/event-loop-monitor.ts b/src/event-loop-monitor.ts index dca2284..a6d5136 100644 --- a/src/event-loop-monitor.ts +++ b/src/event-loop-monitor.ts @@ -104,7 +104,7 @@ export class EventLoopMonitor extends EventEmitter { performance, // eslint-disable-next-line @typescript-eslint/no-var-requires } = require('perf_hooks'); - this._now = performance.now; + this._now = performance.now.bind(performance); return; } @@ -113,7 +113,7 @@ export class EventLoopMonitor extends EventEmitter { window.performance && window.performance.now ) { - this._now = window.performance.now; + this._now = window.performance.now.bind(window.performance); return; } diff --git a/src/models/system.ts b/src/models/system.ts index 98c790c..e3ab70a 100644 --- a/src/models/system.ts +++ b/src/models/system.ts @@ -23,7 +23,6 @@ type MetricPayload = { newSessions: number; activeRequests: number; activeHandles: number; - activeStreams: number; pctEvloopBlock: number; evloopHistogram: any; gcMajorDuration: number; From 0619175fa2234cfab06c6a8a795ea72cb86c958d Mon Sep 17 00:00:00 2001 From: Leonardo Venturini Date: Thu, 31 Aug 2023 08:59:20 -0400 Subject: [PATCH 32/37] add config tests --- package.json | 2 +- src/config.test.ts | 27 +++++++++++++++++++++++++++ src/config.ts | 4 ++-- src/monti-apm-agent.ts | 6 ++++-- 4 files changed, 34 insertions(+), 5 deletions(-) create mode 100644 src/config.test.ts diff --git a/package.json b/package.json index 3f2c0d4..bc5b41f 100644 --- a/package.json +++ b/package.json @@ -11,7 +11,7 @@ "lintfix": "eslint src --fix", "test:dist": "mocha 'dist/**/*.test.js' --exit --watch=false", "test": "mocha --extension=ts --require=@swc/register --file=src/tests/setup.ts --exit --watch=false src/**/*.test.ts", - "test:watch": "nodemon --exec 'npm run test' -e js --watch src", + "test:watch": "nodemon --exec 'npm run test' -e js,ts --watch src", "compile": "npm run clean && npm run build && npm run types", "prepublishOnly": "npm run compile" }, diff --git a/src/config.test.ts b/src/config.test.ts new file mode 100644 index 0000000..d60aa76 --- /dev/null +++ b/src/config.test.ts @@ -0,0 +1,27 @@ +import { expect } from 'chai'; +import { getConfig } from '@/config'; + +describe('Config', () => { + it('default', () => { + const config = getConfig(); + + expect(config.appId).to.equal(undefined); + expect(config.appSecret).to.equal(undefined); + expect(config.endpoint).to.equal('https://engine.montiapm.com'); + expect(config.hostname).to.equal(undefined); + }); + + it('environment variables', () => { + process.env.MONTI_APP_ID = 'test-app-id'; + process.env.MONTI_APP_SECRET = 'test-app-secret'; + process.env.MONTI_ENDPOINT = 'test-endpoint'; + process.env.MONTI_HOSTNAME = 'test-hostname'; + + const config = getConfig(); + + expect(config.appId).to.equal('test-app-id'); + expect(config.appSecret).to.equal('test-app-secret'); + expect(config.endpoint).to.equal('test-endpoint'); + expect(config.hostname).to.equal('test-hostname'); + }); +}); diff --git a/src/config.ts b/src/config.ts index c544d50..84fd11a 100644 --- a/src/config.ts +++ b/src/config.ts @@ -6,10 +6,10 @@ const explorerSync = cosmiconfigSync(moduleName, {}); const search = explorerSync.search(); -export const config = { +export const getConfig = () => ({ appId: process.env.MONTI_APP_ID || undefined, appSecret: process.env.MONTI_APP_SECRET || undefined, endpoint: process.env.MONTI_ENDPOINT || 'https://engine.montiapm.com', hostname: process.env.MONTI_HOSTNAME || undefined, ...(search ? search.config : {}), -}; +}); diff --git a/src/monti-apm-agent.ts b/src/monti-apm-agent.ts index f3c5f82..1f898ca 100644 --- a/src/monti-apm-agent.ts +++ b/src/monti-apm-agent.ts @@ -3,7 +3,9 @@ import { Monti } from '@monti-apm/core'; import os from 'os'; import { version } from '../package.json'; import { System } from '@/models/system'; -import { config } from '@/config'; +import { getConfig } from '@/config'; + +const config = getConfig(); export class MontiApmAgent { static instance: MontiApmAgent; @@ -63,7 +65,7 @@ export class MontiApmAgent { schedulePayloadSend() { setTimeout(() => { this.schedulePayloadSend(); - this.sendPayload(); + this.sendPayload().catch(console.error); }, this.payloadTimeout); } From ce325c70474fb349774ec6db525f66a68e145864 Mon Sep 17 00:00:00 2001 From: Leonardo Venturini Date: Thu, 31 Aug 2023 09:10:09 -0400 Subject: [PATCH 33/37] add tests for gc --- package-lock.json | 137 ++++++++++++++++++++++++++++++++++++++++++++++ package.json | 2 + src/gc.test.ts | 75 +++++++++++++++++++++++++ src/gc.ts | 2 +- 4 files changed, 215 insertions(+), 1 deletion(-) create mode 100644 src/gc.test.ts diff --git a/package-lock.json b/package-lock.json index 6d2e6a5..aa664cb 100644 --- a/package-lock.json +++ b/package-lock.json @@ -31,6 +31,7 @@ "@types/lru-cache": "^7.10.10", "@types/mocha": "^10.0.1", "@types/node": "^20.5.0", + "@types/sinon": "^10.0.16", "@types/uuid": "^9.0.2", "@types/websocket": "^1.0.5", "@typescript-eslint/eslint-plugin": "5.62.0", @@ -43,6 +44,7 @@ "nodemon": "2.0.21", "prettier": "2.8.8", "rimraf": "4.4.1", + "sinon": "^15.2.0", "typescript": "5.1.6" } }, @@ -371,6 +373,50 @@ "url": "https://github.com/sindresorhus/is?sponsor=1" } }, + "node_modules/@sinonjs/commons": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@sinonjs/commons/-/commons-3.0.0.tgz", + "integrity": "sha512-jXBtWAF4vmdNmZgD5FoKsVLv3rPgDnLgPbU84LIJ3otV44vJlDRokVng5v8NFJdCf/da9legHcKaRuZs4L7faA==", + "dev": true, + "dependencies": { + "type-detect": "4.0.8" + } + }, + "node_modules/@sinonjs/fake-timers": { + "version": "10.3.0", + "resolved": "https://registry.npmjs.org/@sinonjs/fake-timers/-/fake-timers-10.3.0.tgz", + "integrity": "sha512-V4BG07kuYSUkTCSBHG8G8TNhM+F19jXFWnQtzj+we8DrkpSBCee9Z3Ms8yiGer/dlmhe35/Xdgyo3/0rQKg7YA==", + "dev": true, + "dependencies": { + "@sinonjs/commons": "^3.0.0" + } + }, + "node_modules/@sinonjs/samsam": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/@sinonjs/samsam/-/samsam-8.0.0.tgz", + "integrity": "sha512-Bp8KUVlLp8ibJZrnvq2foVhP0IVX2CIprMJPK0vqGqgrDa0OHVKeZyBykqskkrdxV6yKBPmGasO8LVjAKR3Gew==", + "dev": true, + "dependencies": { + "@sinonjs/commons": "^2.0.0", + "lodash.get": "^4.4.2", + "type-detect": "^4.0.8" + } + }, + "node_modules/@sinonjs/samsam/node_modules/@sinonjs/commons": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/@sinonjs/commons/-/commons-2.0.0.tgz", + "integrity": "sha512-uLa0j859mMrg2slwQYdO/AkrOfmH+X6LTVmNTS9CqexuE2IvVORIkSpJLqePAbEnKJ77aMmCwr1NUZ57120Xcg==", + "dev": true, + "dependencies": { + "type-detect": "4.0.8" + } + }, + "node_modules/@sinonjs/text-encoding": { + "version": "0.7.2", + "resolved": "https://registry.npmjs.org/@sinonjs/text-encoding/-/text-encoding-0.7.2.tgz", + "integrity": "sha512-sXXKG+uL9IrKqViTtao2Ws6dy0znu9sOaP1di/jKGW1M6VssO8vlpXCQcpZ+jisQ1tTFAC5Jo/EOzFbggBagFQ==", + "dev": true + }, "node_modules/@swc/cli": { "version": "0.1.62", "resolved": "https://registry.npmjs.org/@swc/cli/-/cli-0.1.62.tgz", @@ -734,6 +780,21 @@ "integrity": "sha512-G8hZ6XJiHnuhQKR7ZmysCeJWE08o8T0AXtk5darsCaTVsYZhhgUrq53jizaR2FvsoeCwJhlmwTjkXBY5Pn/ZHw==", "dev": true }, + "node_modules/@types/sinon": { + "version": "10.0.16", + "resolved": "https://registry.npmjs.org/@types/sinon/-/sinon-10.0.16.tgz", + "integrity": "sha512-j2Du5SYpXZjJVJtXBokASpPRj+e2z+VUhCPHmM6WMfe3dpHu6iVKJMU6AiBcMp/XTAYnEj6Wc1trJUWwZ0QaAQ==", + "dev": true, + "dependencies": { + "@types/sinonjs__fake-timers": "*" + } + }, + "node_modules/@types/sinonjs__fake-timers": { + "version": "8.1.2", + "resolved": "https://registry.npmjs.org/@types/sinonjs__fake-timers/-/sinonjs__fake-timers-8.1.2.tgz", + "integrity": "sha512-9GcLXF0/v3t80caGs5p2rRfkB+a8VBGLJZVih6CNFkx8IZ994wiKKLSRs9nuFwk1HevWs/1mnUmkApGrSGsShA==", + "dev": true + }, "node_modules/@types/uuid": { "version": "9.0.2", "resolved": "https://registry.npmjs.org/@types/uuid/-/uuid-9.0.2.tgz", @@ -2618,6 +2679,12 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/isarray": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz", + "integrity": "sha512-D2S+3GLxWH+uhrNEcoh/fnmYeP8E8/zHl644d/jdA0g2uyXvy3sb0qxotE+ne0LtccHknQzWwZEzhak7oJ0COQ==", + "dev": true + }, "node_modules/isexe": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", @@ -2668,6 +2735,12 @@ "resolved": "https://registry.npmjs.org/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz", "integrity": "sha512-ZClg6AaYvamvYEE82d3Iyd3vSSIjQ+odgjaTzRuO3s7toCdFKczob2i0zCh7JE8kWn17yvAWhUVxvqGwUalsRA==" }, + "node_modules/just-extend": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/just-extend/-/just-extend-4.2.1.tgz", + "integrity": "sha512-g3UB796vUFIY90VIv/WX3L2c8CS2MdWUww3CNrYmqza1Fg0DURc2K/O4YrnklBdQarSJ/y8JnJYDGc+1iumQjg==", + "dev": true + }, "node_modules/keyv": { "version": "4.5.3", "resolved": "https://registry.npmjs.org/keyv/-/keyv-4.5.3.tgz", @@ -2716,6 +2789,12 @@ "integrity": "sha512-H5ZhCF25riFd9uB5UCkVKo61m3S/xZk1x4wA6yp/L3RFP6Z/eHH1ymQcGLo7J3GMPfm0V/7m1tryHuGVxpqEBQ==", "dev": 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==", + "dev": true + }, "node_modules/lodash.merge": { "version": "4.6.2", "resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz", @@ -2966,6 +3045,28 @@ "integrity": "sha512-Tj+HTDSJJKaZnfiuw+iaF9skdPpTo2GtEly5JHnWV/hfv2Qj/9RKsGISQtLh2ox3l5EAGw487hnBee0sIJ6v2g==", "dev": true }, + "node_modules/nise": { + "version": "5.1.4", + "resolved": "https://registry.npmjs.org/nise/-/nise-5.1.4.tgz", + "integrity": "sha512-8+Ib8rRJ4L0o3kfmyVCL7gzrohyDe0cMFTBa2d364yIrEGMEoetznKJx899YxjybU6bL9SQkYPSBBs1gyYs8Xg==", + "dev": true, + "dependencies": { + "@sinonjs/commons": "^2.0.0", + "@sinonjs/fake-timers": "^10.0.2", + "@sinonjs/text-encoding": "^0.7.1", + "just-extend": "^4.0.2", + "path-to-regexp": "^1.7.0" + } + }, + "node_modules/nise/node_modules/@sinonjs/commons": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/@sinonjs/commons/-/commons-2.0.0.tgz", + "integrity": "sha512-uLa0j859mMrg2slwQYdO/AkrOfmH+X6LTVmNTS9CqexuE2IvVORIkSpJLqePAbEnKJ77aMmCwr1NUZ57120Xcg==", + "dev": true, + "dependencies": { + "type-detect": "4.0.8" + } + }, "node_modules/nodemon": { "version": "2.0.21", "resolved": "https://registry.npmjs.org/nodemon/-/nodemon-2.0.21.tgz", @@ -3271,6 +3372,15 @@ "node": ">=16 || 14 >=14.17" } }, + "node_modules/path-to-regexp": { + "version": "1.8.0", + "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-1.8.0.tgz", + "integrity": "sha512-n43JRhlUKUAlibEJhPeir1ncUID16QnEjNpwzNdO3Lm4ywrBpBZ5oLD0I6br9evr1Y9JTqwRtAh7JLoOzAQdVA==", + "dev": true, + "dependencies": { + "isarray": "0.0.1" + } + }, "node_modules/path-type": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/path-type/-/path-type-4.0.0.tgz", @@ -3750,6 +3860,33 @@ "semver": "bin/semver.js" } }, + "node_modules/sinon": { + "version": "15.2.0", + "resolved": "https://registry.npmjs.org/sinon/-/sinon-15.2.0.tgz", + "integrity": "sha512-nPS85arNqwBXaIsFCkolHjGIkFo+Oxu9vbgmBJizLAhqe6P2o3Qmj3KCUoRkfhHtvgDhZdWD3risLHAUJ8npjw==", + "dev": true, + "dependencies": { + "@sinonjs/commons": "^3.0.0", + "@sinonjs/fake-timers": "^10.3.0", + "@sinonjs/samsam": "^8.0.0", + "diff": "^5.1.0", + "nise": "^5.1.4", + "supports-color": "^7.2.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/sinon" + } + }, + "node_modules/sinon/node_modules/diff": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/diff/-/diff-5.1.0.tgz", + "integrity": "sha512-D+mk+qE8VC/PAUrlAU34N+VfXev0ghe5ywmpqrawphmVZc1bEfn56uo9qpyGp1p4xpzOHkSW4ztBd6L7Xx4ACw==", + "dev": true, + "engines": { + "node": ">=0.3.1" + } + }, "node_modules/slash": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz", diff --git a/package.json b/package.json index bc5b41f..56794a7 100644 --- a/package.json +++ b/package.json @@ -43,6 +43,7 @@ "@types/lru-cache": "^7.10.10", "@types/mocha": "^10.0.1", "@types/node": "^20.5.0", + "@types/sinon": "^10.0.16", "@types/uuid": "^9.0.2", "@types/websocket": "^1.0.5", "@typescript-eslint/eslint-plugin": "5.62.0", @@ -55,6 +56,7 @@ "nodemon": "2.0.21", "prettier": "2.8.8", "rimraf": "4.4.1", + "sinon": "^15.2.0", "typescript": "5.1.6" }, "dependencies": { diff --git a/src/gc.test.ts b/src/gc.test.ts new file mode 100644 index 0000000..53f87d9 --- /dev/null +++ b/src/gc.test.ts @@ -0,0 +1,75 @@ +import sinon from 'sinon'; +import { constants, PerformanceObserver } from 'perf_hooks'; +import { GCMetrics } from '@/gc'; + +describe('GCMetrics', function () { + let gcMetrics: GCMetrics; + + beforeEach(function () { + gcMetrics = new GCMetrics(); + }); + + describe('constructor', function () { + it('should initialize with empty metrics', function () { + expect(gcMetrics.metrics).to.deep.equal({ + gcMajor: 0, + gcMinor: 0, + gcIncremental: 0, + gcWeakCB: 0, + }); + }); + }); + + describe('start', function () { + let mockObserve: any; + + beforeEach(function () { + mockObserve = sinon.stub(PerformanceObserver.prototype, 'observe'); + }); + + afterEach(function () { + sinon.restore(); + }); + + it('should start observer', function () { + gcMetrics.start(); + expect(mockObserve.calledOnce).to.be.true; + expect(gcMetrics.started).to.be.true; + }); + + it('should not start observer if already started', function () { + gcMetrics.start(); + const result = gcMetrics.start(); + expect(result).to.be.false; + + expect(mockObserve.calledOnce).to.be.true; + }); + }); + + describe('_mapKindToMetric', function () { + it('should map gc kind to metric', function () { + const metric = gcMetrics._mapKindToMetric( + constants.NODE_PERFORMANCE_GC_MAJOR, + ); + expect(metric).to.equal('gcMajor'); + }); + + it('should return undefined for unknown gc kind', function () { + const metric = gcMetrics._mapKindToMetric(999); // An unknown GC kind + expect(metric).to.be.undefined; + }); + }); + + describe('reset', function () { + it('should reset metrics', function () { + gcMetrics.metrics.gcMajor = 10; + gcMetrics.reset(); + expect(gcMetrics.metrics).to.deep.equal({ + gcMajor: 0, + gcMinor: 0, + gcIncremental: 0, + gcWeakCB: 0, + }); + }); + }); +}); diff --git a/src/gc.ts b/src/gc.ts index 18cebea..bad8ce3 100644 --- a/src/gc.ts +++ b/src/gc.ts @@ -1,4 +1,4 @@ -import { PerformanceObserver, constants, performance } from 'perf_hooks'; +import { constants, PerformanceObserver } from 'perf_hooks'; export class GCMetrics { observer?: PerformanceObserver; From 7ac6d62524d15ceb6e44f76c77c28a83a43fd883 Mon Sep 17 00:00:00 2001 From: Leonardo Venturini Date: Thu, 31 Aug 2023 09:19:18 -0400 Subject: [PATCH 34/37] add tests for retry --- src/retry.test.ts | 63 +++++++++++++++++++++++++++++++++++++++++++++++ src/retry.ts | 23 ++++++++--------- 2 files changed, 75 insertions(+), 11 deletions(-) create mode 100644 src/retry.test.ts diff --git a/src/retry.test.ts b/src/retry.test.ts new file mode 100644 index 0000000..8f36428 --- /dev/null +++ b/src/retry.test.ts @@ -0,0 +1,63 @@ +import sinon from 'sinon'; +import { Retry } from '@/retry'; + +describe('Retry', () => { + let clock: sinon.SinonFakeTimers; + + beforeEach(() => { + clock = sinon.useFakeTimers(); + }); + + afterEach(() => { + clock.restore(); + }); + + it('should instantiate with default values', () => { + const retry = new Retry(); + expect(retry).to.be.instanceOf(Retry); + }); + + it('should instantiate with custom values', () => { + const retry = new Retry({ baseTimeout: 2000, maxTimeout: 50000 }); + expect(retry).to.be.instanceOf(Retry); + }); + + it('should clear existing timer', () => { + const retry = new Retry(); + const fn = sinon.fake(); + + retry.retryLater(1, fn); + retry.clear(); + + clock.tick(10000); + expect(fn.callCount).to.equal(0); + }); + + it('should calculate timeout correctly for the first call', () => { + const retry = new Retry(); + const timeout = retry.timeout(1); + + expect(timeout).to.be.at.least(10); + }); + + it('should not exceed max timeout', () => { + const retry = new Retry({ + fuzz: 0, + }); + const timeout = retry.timeout(100); + + expect(timeout).to.be.at.most(5 * 60000); + }); + + it('should call the retry function after the calculated time', () => { + const retry = new Retry(); + const fn = sinon.fake(); + const calculatedTimeout = retry.retryLater(1, fn); + + clock.tick(calculatedTimeout - 1); + expect(fn.callCount).to.equal(0); + + clock.tick(1); + expect(fn.callCount).to.equal(1); + }); +}); diff --git a/src/retry.ts b/src/retry.ts index 8a9dac5..ca1f30e 100644 --- a/src/retry.ts +++ b/src/retry.ts @@ -8,13 +8,13 @@ interface RetryOptions { } export class Retry { - private baseTimeout: number; - private exponent: number; - private maxTimeout: number; - private minTimeout: number; - private minCount: number; - private fuzz: number; - private retryTimer: NodeJS.Timeout | null; + baseTimeout: number; + exponent: number; + maxTimeout: number; + minTimeout: number; + minCount: number; + fuzz: number; + retryTimer: NodeJS.Timeout | null; constructor({ baseTimeout = 1000, @@ -33,14 +33,14 @@ export class Retry { this.retryTimer = null; } - public clear(): void { + clear(): void { if (this.retryTimer) { clearTimeout(this.retryTimer); } this.retryTimer = null; } - private _timeout(count: number): number { + timeout(count: number): number { if (count < this.minCount) { return this.minTimeout; } @@ -51,11 +51,12 @@ export class Retry { ); timeout *= Math.random() * this.fuzz + (1 - this.fuzz / 2); + return Math.ceil(timeout); } - public retryLater(count: number, fn: () => void): number { - const timeout = this._timeout(count); + retryLater(count: number, fn: () => void): number { + const timeout = this.timeout(count); if (this.retryTimer) { clearTimeout(this.retryTimer); } From 4449d15ed79790c1bb4acc24df32096150a86b30 Mon Sep 17 00:00:00 2001 From: Leonardo Venturini Date: Thu, 31 Aug 2023 11:04:33 -0400 Subject: [PATCH 35/37] remove unused code and add tests --- package.json | 2 +- src/gc.ts | 4 +- src/index.ts | 2 +- src/monti-apm-agent.ts | 2 +- src/system.test.ts | 97 ++++++++++++++++++++++++++++++++++++++ src/{models => }/system.ts | 50 +------------------- src/utils.ts | 3 ++ 7 files changed, 105 insertions(+), 55 deletions(-) create mode 100644 src/system.test.ts rename src/{models => }/system.ts (75%) create mode 100644 src/utils.ts diff --git a/package.json b/package.json index 56794a7..a66c526 100644 --- a/package.json +++ b/package.json @@ -10,7 +10,7 @@ "lint": "eslint src --cache", "lintfix": "eslint src --fix", "test:dist": "mocha 'dist/**/*.test.js' --exit --watch=false", - "test": "mocha --extension=ts --require=@swc/register --file=src/tests/setup.ts --exit --watch=false src/**/*.test.ts", + "test": "mocha --extension=ts --require=@swc/register --file=src/tests/setup.ts --exit --watch=false ./src/**/*.test.ts", "test:watch": "nodemon --exec 'npm run test' -e js,ts --watch src", "compile": "npm run clean && npm run build && npm run types", "prepublishOnly": "npm run compile" diff --git a/src/gc.ts b/src/gc.ts index bad8ce3..c09d2cd 100644 --- a/src/gc.ts +++ b/src/gc.ts @@ -3,11 +3,9 @@ import { constants, PerformanceObserver } from 'perf_hooks'; export class GCMetrics { observer?: PerformanceObserver; started = false; - metrics: Record; + metrics: Record = {}; constructor() { - this.metrics = {}; - this.reset(); } diff --git a/src/index.ts b/src/index.ts index 8142944..ad67f9b 100644 --- a/src/index.ts +++ b/src/index.ts @@ -1,5 +1,5 @@ export * from './monti-apm-agent'; -export * from './models/system'; +export * from './system'; export * from './gc'; export * from './doc-sz-cache'; export * from './ntp'; diff --git a/src/monti-apm-agent.ts b/src/monti-apm-agent.ts index 1f898ca..7ee23e4 100644 --- a/src/monti-apm-agent.ts +++ b/src/monti-apm-agent.ts @@ -2,7 +2,7 @@ import { DocSzCache } from '@/doc-sz-cache'; import { Monti } from '@monti-apm/core'; import os from 'os'; import { version } from '../package.json'; -import { System } from '@/models/system'; +import { System } from '@/system'; import { getConfig } from '@/config'; const config = getConfig(); diff --git a/src/system.test.ts b/src/system.test.ts new file mode 100644 index 0000000..f9ad3fe --- /dev/null +++ b/src/system.test.ts @@ -0,0 +1,97 @@ +import sinon from 'sinon'; +import { EventLoopMonitor } from '@/event-loop-monitor'; +import { GCMetrics } from '@/gc'; +import { Ntp } from '@/ntp'; +import { MontiApmAgent } from '@/monti-apm-agent'; +import { System } from '@/system'; + +describe('System', () => { + let sandbox: sinon.SinonSandbox; + + beforeEach(() => { + sandbox = sinon.createSandbox(); + + sandbox.stub(EventLoopMonitor.prototype, 'start'); + sandbox.stub(EventLoopMonitor.prototype, 'on'); + sandbox.stub(EventLoopMonitor.prototype, 'status').returns({ + pctBlock: 0.1, + elapsedTime: 1000, + totalLag: 100, + }); + + sandbox.stub(GCMetrics.prototype, 'start'); + sandbox.stub(GCMetrics.prototype, 'reset'); + + sandbox.stub(Ntp, '_now').returns(1629931263711); // Replace with some sample time + sandbox.stub(Ntp.instance, 'syncTime').callsFake((time) => time); + + sandbox.stub(process, 'memoryUsage').returns({ + rss: 100, + arrayBuffers: 50, + external: 25, + heapUsed: 30, + heapTotal: 60, + }); + + sandbox.stub(process, '_getActiveRequests').returns(new Array(10)); + sandbox.stub(process, '_getActiveHandles').returns(new Array(5)); + sandbox.stub(process, 'hrtime').returns([123456789, 987654321]); + sandbox.stub(process, 'cpuUsage').returns({ user: 50000, system: 50000 }); + + sandbox.stub(MontiApmAgent, 'instance').value({ + docSzCache: { + setPcpu: () => {}, + }, + }); + }); + + afterEach(() => { + // Restore all the mocks and stubs + sandbox.restore(); + }); + + it('should return a singleton instance', () => { + const instance1 = System.getInstance(); + const instance2 = System.getInstance(); + expect(instance1).to.equal(instance2); + }); + + it('should correctly initialize instance variables', () => { + const system = System.getInstance(); + + expect(system).to.have.property('startTime').to.be.a('number'); + expect(system).to.have.property('newSessions').to.equal(0); + expect(system).to.have.property('sessionTimeout').to.equal(1800000); // 1000 * 60 * 30 + expect(system).to.have.property('evloopMonitor').to.be.an('object'); + expect(system).to.have.property('gcMetrics').to.be.an('object'); + expect(system).to.have.property('cpuTime').to.be.an('array'); + expect(system).to.have.property('previousCpuUsage').to.be.an('object'); + }); + + it('should build payload correctly', () => { + const system = System.getInstance(); + const payload = system.buildPayload(); + + expect(payload).to.have.property('systemMetrics').to.be.an('array'); + expect(payload.systemMetrics[0]) + .to.have.property('startTime') + .to.be.a('number'); + expect(payload.systemMetrics[0]) + .to.have.property('endTime') + .to.be.a('number'); + expect(payload.systemMetrics[0]) + .to.have.property('memory') + .to.be.a('number'); + }); + + it('should correctly calculate CPU usage and update cpuHistory', () => { + const system = System.getInstance(); + system.cpuUsage(); + expect(system.cpuHistory).to.have.lengthOf(1); + const cpuEntry = system.cpuHistory[0]; + expect(cpuEntry).to.have.property('time').to.be.a('number'); + expect(cpuEntry).to.have.property('usage').to.be.a('number'); + expect(cpuEntry).to.have.property('user').to.be.a('number'); + expect(cpuEntry).to.have.property('sys').to.be.a('number'); + }); +}); diff --git a/src/models/system.ts b/src/system.ts similarity index 75% rename from src/models/system.ts rename to src/system.ts index e3ab70a..8e3ba64 100644 --- a/src/models/system.ts +++ b/src/system.ts @@ -3,6 +3,7 @@ import { DDSketch } from 'monti-apm-sketches-js'; import { GCMetrics } from '@/gc'; import { Ntp } from '@/ntp'; import { MontiApmAgent } from '@/monti-apm-agent'; +import { hrtimeToMS } from '@/utils'; type CPUHistoryEntry = { time: number; @@ -105,7 +106,6 @@ export class System { metrics.activeRequests = process._getActiveRequests().length; metrics.activeHandles = process._getActiveHandles().length; - // track eventloop metrics metrics.pctEvloopBlock = this.evloopMonitor.status().pctBlock; metrics.evloopHistogram = this.evloopHistogram; this.evloopHistogram = new DDSketch({ @@ -163,52 +163,4 @@ export class System { this.cpuTime = process.hrtime(); this.previousCpuUsage = process.cpuUsage(); } - - handleSessionActivity(msg, session) { - if (msg.msg === 'connect' && !msg.session) { - this.countNewSession(session); - } else if (['sub', 'method'].indexOf(msg.msg) !== -1) { - if (!this.isSessionActive(session)) { - this.countNewSession(session); - } - } - session._activeAt = Date.now(); - } - - countNewSession(session) { - if (!isLocalAddress(session.socket)) { - this.newSessions++; - } - } - - isSessionActive(session) { - const inactiveTime = Date.now() - session._activeAt; - return inactiveTime < this.sessionTimeout; - } -} - -function hrtimeToMS(hrtime) { - return hrtime[0] * 1000 + hrtime[1] / 1000000; -} - -// ------------------------------------------------------------------------- // - -// http://regex101.com/r/iF3yR3/2 -// eslint-disable-next-line no-useless-escape -const isLocalHostRegex = - /^(?:.*\.local|localhost)(?::\d+)?|127(?:\.\d{1,3}){3}|192\.168(?:\.\d{1,3}){2}|10(?:\.\d{1,3}){3}|172\.(?:1[6-9]|2\d|3[0-1])(?:\.\d{1,3}){2}$/; - -// http://regex101.com/r/hM5gD8/1 -const isLocalAddressRegex = - /^127(?:\.\d{1,3}){3}|192\.168(?:\.\d{1,3}){2}|10(?:\.\d{1,3}){3}|172\.(?:1[6-9]|2\d|3[0-1])(?:\.\d{1,3}){2}$/; - -function isLocalAddress(socket) { - const host = socket.headers['host']; - if (host) { - return isLocalHostRegex.test(host); - } - const address = socket.headers['x-forwarded-for'] || socket.remoteAddress; - if (address) { - return isLocalAddressRegex.test(address); - } } diff --git a/src/utils.ts b/src/utils.ts new file mode 100644 index 0000000..65cc0e9 --- /dev/null +++ b/src/utils.ts @@ -0,0 +1,3 @@ +export function hrtimeToMS(hrtime: number[]) { + return hrtime[0] * 1000 + hrtime[1] / 1000000; +} From 333de06d9e7861a538ae4cd43f5daad02bb521aa Mon Sep 17 00:00:00 2001 From: Leonardo Venturini Date: Fri, 1 Sep 2023 08:37:54 -0400 Subject: [PATCH 36/37] send node version --- src/monti-apm-agent.ts | 53 +++++++++++++++++++++++++++--------------- 1 file changed, 34 insertions(+), 19 deletions(-) diff --git a/src/monti-apm-agent.ts b/src/monti-apm-agent.ts index 7ee23e4..ea049cd 100644 --- a/src/monti-apm-agent.ts +++ b/src/monti-apm-agent.ts @@ -1,7 +1,7 @@ import { DocSzCache } from '@/doc-sz-cache'; import { Monti } from '@monti-apm/core'; import os from 'os'; -import { version } from '../package.json'; +import { name, version } from '../package.json'; import { System } from '@/system'; import { getConfig } from '@/config'; @@ -40,26 +40,41 @@ export class MontiApmAgent { appSecret, endpoint, hostname, - agentVersion: `node-agent@${version}`, + agentVersion: `${name}@${version}`, }); - this.core - ._checkAuth() - .then(() => { - console.log('Monti APM: Connected'); - - // Kadira._sendAppStats(); - this.schedulePayloadSend(); - }) - .catch(function (err) { - if (err.message === 'Unauthorized') { - console.log( - 'Monti APM: Authentication failed, check your "appId" & "appSecret"', - ); - } else { - console.log(`Monti APM: Unable to connect. ${err.message}`); - } - }); + this.handshake(); + } + + async sendAppStats() { + const appStats = { + nodeVersion: process.version, + protocolVersion: '1.0.0', + }; + + return this.core.sendData({ + startTime: new Date(), + appStats, + }); + } + + async handshake() { + try { + await this.core._checkAuth(); + + console.log('Monti APM: Connected'); + + this.schedulePayloadSend(); + await this.sendAppStats(); + } catch (err: any) { + if (err.message === 'Unauthorized') { + console.log( + 'Monti APM: Authentication failed, check your "appId" & "appSecret"', + ); + } else { + console.log(`Monti APM: Unable to connect. ${err.message}`); + } + } } schedulePayloadSend() { From 3032bedc16915feb7afc509075be1397d6e64ae5 Mon Sep 17 00:00:00 2001 From: Leonardo Venturini Date: Fri, 1 Sep 2023 08:41:02 -0400 Subject: [PATCH 37/37] adjust readme --- README.md | 20 +++++++++----------- 1 file changed, 9 insertions(+), 11 deletions(-) diff --git a/README.md b/README.md index 37a33ab..b869337 100644 --- a/README.md +++ b/README.md @@ -1,16 +1,14 @@ # Node.js Agent -What we should track: - -- [ ] Node.js version -- [ ] Node.js agent version -- [ ] Hosts -- [ ] CPU -- [ ] Memory -- [ ] Event Loop Latency -- [ ] Garbage Collection Duration - -Most of these might be shared between the Meteor Agent so probably should be in the core library. +What we track: + +- Node.js version +- Node.js agent version +- Hosts +- CPU +- Memory +- Event Loop Latency +- Garbage Collection Duration # Supported Versions