diff --git a/.vscode/launch.json b/.vscode/launch.json index ebd1b7a0..38de8bdd 100644 --- a/.vscode/launch.json +++ b/.vscode/launch.json @@ -9,7 +9,8 @@ "request": "launch", "name": "Launch Program", "program": "${workspaceFolder}/src/butler.js", - "runtimeVersion": "20", + // "runtimeVersion": "20", + "runtimeVersion": "18", "cwd": "${workspaceFolder}/src", "env": { "NODE_CONFIG_DIR": "${workspaceFolder}/src/config", diff --git a/package-lock.json b/package-lock.json index 763b368e..41b6b691 100644 --- a/package-lock.json +++ b/package-lock.json @@ -18,7 +18,7 @@ "@fastify/swagger": "^8.15.0", "@fastify/swagger-ui": "^4.1.0", "@keyvhq/core": "^2.1.1", - "@xstate/fsm": "^2.0.1", + "@xstate/fsm": "^2.1.0", "ajv": "^8.17.1", "ajv-keywords": "^5.1.0", "any-base": "^1.1.0", @@ -33,7 +33,7 @@ "fastify-healthcheck": "^4.4.0", "fastify-plugin": "^4.5.0", "fs-extra": "^11.2.0", - "handlebars": "^4.7.7", + "handlebars": "^4.7.8", "http-errors": "^2.0.0", "i": "^0.3.7", "influx": "^5.9.3", @@ -49,11 +49,12 @@ "ms-teams-wrapper": "^1.0.2", "nodemailer": "^6.9.15", "nodemailer-express-handlebars": "^6.1.2", + "npm-check": "^6.0.1", "os": "^0.1.2", - "posthog-node": "^4.2.0", + "posthog-node": "^4.2.1", "promise": "^8.3.0", "qrs-interact": "^6.3.1", - "rate-limiter-flexible": "^5.0.3", + "rate-limiter-flexible": "^5.0.4", "serializeapp": "^3.0.0", "systeminformation": "^5.23.5", "upath": "^2.0.1", @@ -64,9 +65,9 @@ "xstate": "^5.18.2" }, "devDependencies": { - "@babel/eslint-parser": "^7.25.7", + "@babel/eslint-parser": "^7.25.8", "@babel/plugin-syntax-import-assertions": "^7.25.7", - "@eslint/js": "^9.12.0", + "@eslint/js": "^9.13.0", "esbuild": "^0.24.0", "eslint-config-prettier": "^9.1.0", "eslint-plugin-prettier": "^5.2.1", @@ -102,7 +103,6 @@ "version": "7.23.5", "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.23.5.tgz", "integrity": "sha512-CgH3s1a96LipHCmSUmYFPwY7MNx8C3avkq7i4Wl3cfa662ldtUe4VM1TPXX70pfmrlWTb6jLqTYrZyT2ZTJBgA==", - "dev": true, "dependencies": { "@babel/highlight": "^7.23.4", "chalk": "^2.4.2" @@ -115,7 +115,6 @@ "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==", - "dev": true, "dependencies": { "color-convert": "^1.9.0" }, @@ -127,7 +126,6 @@ "version": "2.4.2", "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", - "dev": true, "dependencies": { "ansi-styles": "^3.2.1", "escape-string-regexp": "^1.0.5", @@ -141,7 +139,6 @@ "version": "1.9.3", "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", - "dev": true, "dependencies": { "color-name": "1.1.3" } @@ -149,14 +146,12 @@ "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==", - "dev": true + "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==", - "dev": true, "engines": { "node": ">=0.8.0" } @@ -165,7 +160,6 @@ "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" } @@ -174,7 +168,6 @@ "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" }, @@ -222,9 +215,9 @@ } }, "node_modules/@babel/eslint-parser": { - "version": "7.25.7", - "resolved": "https://registry.npmjs.org/@babel/eslint-parser/-/eslint-parser-7.25.7.tgz", - "integrity": "sha512-B+BO9x86VYsQHimucBAL1fxTJKF4wyKY6ZVzee9QgzdZOUfs3BaR6AQrgoGrRI+7IFS1wUz/VyQ+SoBcSpdPbw==", + "version": "7.25.8", + "resolved": "https://registry.npmjs.org/@babel/eslint-parser/-/eslint-parser-7.25.8.tgz", + "integrity": "sha512-Po3VLMN7fJtv0nsOjBDSbO1J71UhzShE9MuOSkWEV9IZQXzhZklYtzKZ8ZD/Ij3a0JBv1AG3Ny2L3jvAHQVOGg==", "dev": true, "license": "MIT", "dependencies": { @@ -253,7 +246,6 @@ "version": "7.23.6", "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.23.6.tgz", "integrity": "sha512-qrSfCYxYQB5owCmGLbl8XRpX1ytXlpueOb0N0UmQwA073KZxejgQTzAmJezxvpwQD9uGtK2shHdi55QT+MbjIw==", - "dev": true, "dependencies": { "@babel/types": "^7.23.6", "@jridgewell/gen-mapping": "^0.3.2", @@ -284,7 +276,6 @@ "version": "7.22.20", "resolved": "https://registry.npmjs.org/@babel/helper-environment-visitor/-/helper-environment-visitor-7.22.20.tgz", "integrity": "sha512-zfedSIzFhat/gFhWfHtgWvlec0nqB9YEIVrpuwjruLlXfUSnA8cJB0miHKwqDnQ7d32aKo2xt88/xZptwxbfhA==", - "dev": true, "engines": { "node": ">=6.9.0" } @@ -293,7 +284,6 @@ "version": "7.23.0", "resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.23.0.tgz", "integrity": "sha512-OErEqsrxjZTJciZ4Oo+eoZqeW9UIiOcuYKRJA4ZAgV9myA+pOXhhmpfNCKjEH/auVfEYVFJ6y1Tc4r0eIApqiw==", - "dev": true, "dependencies": { "@babel/template": "^7.22.15", "@babel/types": "^7.23.0" @@ -306,7 +296,6 @@ "version": "7.22.5", "resolved": "https://registry.npmjs.org/@babel/helper-hoist-variables/-/helper-hoist-variables-7.22.5.tgz", "integrity": "sha512-wGjk9QZVzvknA6yKIUURb8zY3grXCcOZt+/7Wcy8O2uctxhplmUPkOdlgoNhmdVee2c92JXbf1xpMtVNbfoxRw==", - "dev": true, "dependencies": { "@babel/types": "^7.22.5" }, @@ -371,7 +360,6 @@ "version": "7.22.6", "resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.22.6.tgz", "integrity": "sha512-AsUnxuLhRYsisFiaJwvp1QF+I3KjD5FOxut14q/GzovUe6orHLesW2C7d754kRm53h5gqrz6sFl6sxc4BVtE/g==", - "dev": true, "dependencies": { "@babel/types": "^7.22.5" }, @@ -380,19 +368,19 @@ } }, "node_modules/@babel/helper-string-parser": { - "version": "7.23.4", - "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.23.4.tgz", - "integrity": "sha512-803gmbQdqwdf4olxrX4AJyFBV/RTr3rSmOj0rKwesmzlfhYNDEs+/iOcznzpNWlJlIlTJC2QfPFcHB6DlzdVLQ==", - "dev": true, + "version": "7.25.7", + "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.25.7.tgz", + "integrity": "sha512-CbkjYdsJNHFk8uqpEkpCvRs3YRp9tY6FmFY7wLMSYuGYkrdUi7r2lc4/wqsvlHoMznX3WJ9IP8giGPq68T/Y6g==", + "license": "MIT", "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/helper-validator-identifier": { - "version": "7.22.20", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.22.20.tgz", - "integrity": "sha512-Y4OZ+ytlatR8AI+8KZfKuL5urKp7qey08ha31L8b3BwewJAoJamTzyvxPR/5D+KkdJCGPq/+8TukHBlY10FX9A==", - "dev": true, + "version": "7.25.7", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.25.7.tgz", + "integrity": "sha512-AM6TzwYqGChO45oiuPqwL2t20/HdMC1rTPAesnBCgPCSF1x3oN9MVUwQV2iyz4xqWrctwK5RNC8LV22kaQCNYg==", + "license": "MIT", "engines": { "node": ">=6.9.0" } @@ -424,7 +412,6 @@ "version": "7.23.4", "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.23.4.tgz", "integrity": "sha512-acGdbYSfp2WheJoJm/EBBBLh/ID8KDc64ISZ9DYtBmC8/Q204PZJLHyzeB5qMzJ5trcOkybd78M4x2KWsUq++A==", - "dev": true, "dependencies": { "@babel/helper-validator-identifier": "^7.22.20", "chalk": "^2.4.2", @@ -438,7 +425,6 @@ "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==", - "dev": true, "dependencies": { "color-convert": "^1.9.0" }, @@ -450,7 +436,6 @@ "version": "2.4.2", "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", - "dev": true, "dependencies": { "ansi-styles": "^3.2.1", "escape-string-regexp": "^1.0.5", @@ -464,7 +449,6 @@ "version": "1.9.3", "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", - "dev": true, "dependencies": { "color-name": "1.1.3" } @@ -472,14 +456,12 @@ "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==", - "dev": true + "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==", - "dev": true, "engines": { "node": ">=0.8.0" } @@ -488,7 +470,6 @@ "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" } @@ -497,7 +478,6 @@ "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" }, @@ -506,10 +486,13 @@ } }, "node_modules/@babel/parser": { - "version": "7.23.9", - "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.23.9.tgz", - "integrity": "sha512-9tcKgqKbs3xGJ+NtKF2ndOBBLVwPjl1SHxPQkd36r3Dlirw3xWUeGaTbqr7uGZcTaxkVNwc+03SVP7aCdWrTlA==", - "dev": true, + "version": "7.25.8", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.25.8.tgz", + "integrity": "sha512-HcttkxzdPucv3nNFmfOOMfFf64KgdJVqm1KaCm25dPGMLElo9nsLvXeJECQg8UzPuBGLyTSA0ZzqCtDSzKTEoQ==", + "license": "MIT", + "dependencies": { + "@babel/types": "^7.25.8" + }, "bin": { "parser": "bin/babel-parser.js" }, @@ -725,7 +708,6 @@ "version": "7.23.9", "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.23.9.tgz", "integrity": "sha512-+xrD2BWLpvHKNmX2QbpdpsBaWnRxahMwJjO+KZk2JOElj5nSmKezyS1B4u+QbHMTX69t4ukm6hh9lsYQ7GHCKA==", - "dev": true, "dependencies": { "@babel/code-frame": "^7.23.5", "@babel/parser": "^7.23.9", @@ -739,7 +721,6 @@ "version": "7.23.9", "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.23.9.tgz", "integrity": "sha512-I/4UJ9vs90OkBtY6iiiTORVMyIhJ4kAVmsKo9KFc8UOxMeUfi2hvtIBsET5u9GizXE6/GFSuKCTNfgCswuEjRg==", - "dev": true, "dependencies": { "@babel/code-frame": "^7.23.5", "@babel/generator": "^7.23.6", @@ -760,19 +741,18 @@ "version": "11.12.0", "resolved": "https://registry.npmjs.org/globals/-/globals-11.12.0.tgz", "integrity": "sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==", - "dev": true, "engines": { "node": ">=4" } }, "node_modules/@babel/types": { - "version": "7.23.9", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.23.9.tgz", - "integrity": "sha512-dQjSq/7HaSjRM43FFGnv5keM2HsxpmyV1PfaSVm0nzzjwwTmjOe6J4bC8e3+pTEIgHaHj+1ZlLThRJ2auc/w1Q==", - "dev": true, + "version": "7.25.8", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.25.8.tgz", + "integrity": "sha512-JWtuCu8VQsMladxVz/P4HzHUGCAwpuqacmowgXFs5XjxIgKuNjnLokQzuVjlTvIzODaDmpjT3oxcC48vyk9EWg==", + "license": "MIT", "dependencies": { - "@babel/helper-string-parser": "^7.23.4", - "@babel/helper-validator-identifier": "^7.22.20", + "@babel/helper-string-parser": "^7.25.7", + "@babel/helper-validator-identifier": "^7.25.7", "to-fast-properties": "^2.0.0" }, "engines": { @@ -812,6 +792,15 @@ "kuler": "^2.0.0" } }, + "node_modules/@devexpress/error-stack-parser": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/@devexpress/error-stack-parser/-/error-stack-parser-2.0.6.tgz", + "integrity": "sha512-fneVypElGUH6Be39mlRZeAu00pccTlf4oVuzf9xPJD1cdEqI8NyAiQua/EW7lZdrbMUbgyXcJmfKPefhYius3A==", + "license": "MIT", + "dependencies": { + "stackframe": "^1.1.1" + } + }, "node_modules/@esbuild/aix-ppc64": { "version": "0.24.0", "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.24.0.tgz", @@ -1297,9 +1286,9 @@ "peer": true }, "node_modules/@eslint/js": { - "version": "9.12.0", - "resolved": "https://registry.npmjs.org/@eslint/js/-/js-9.12.0.tgz", - "integrity": "sha512-eohesHH8WFRUprDNyEREgqP6beG6htMeUYeCpkEgBCieCMme5r9zFWjzAJp//9S+Kub4rqE+jXe9Cp1a7IYIIA==", + "version": "9.13.0", + "resolved": "https://registry.npmjs.org/@eslint/js/-/js-9.13.0.tgz", + "integrity": "sha512-IFLyoY4d72Z5y/6o/BazFBezupzI/taV8sGumxTAVw3lXG9A6md1Dc34T9s1FoD/an9pJH8RHbAxsaEbBed9lA==", "dev": true, "license": "MIT", "engines": { @@ -2018,7 +2007,6 @@ "version": "0.3.3", "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.3.tgz", "integrity": "sha512-HLhSWOLRi875zjjMG/r+Nv0oCW8umGb0BgEhyX3dDX3egwZtB8PqLnjz3yedt8R5StBrzcg4aBpnh8UA9D1BoQ==", - "dev": true, "dependencies": { "@jridgewell/set-array": "^1.0.1", "@jridgewell/sourcemap-codec": "^1.4.10", @@ -2032,7 +2020,6 @@ "version": "3.1.1", "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.1.tgz", "integrity": "sha512-dSYZh7HhCDtCKm4QakX0xFpsRDqjjtZf/kjI/v3T3Nwt5r8/qz/M19F9ySyOqU94SXBmeG9ttTul+YnR4LOxFA==", - "dev": true, "engines": { "node": ">=6.0.0" } @@ -2041,22 +2028,20 @@ "version": "1.1.2", "resolved": "https://registry.npmjs.org/@jridgewell/set-array/-/set-array-1.1.2.tgz", "integrity": "sha512-xnkseuNADM0gt2bs+BvhO0p78Mk762YnZdsuzFV018NoG1Sj1SCQvpSqa7XUaTam5vAGasABV9qXASMKnFMwMw==", - "dev": true, "engines": { "node": ">=6.0.0" } }, "node_modules/@jridgewell/sourcemap-codec": { - "version": "1.4.15", - "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.15.tgz", - "integrity": "sha512-eF2rxCRulEKXHTRiDrDy6erMYWqNw4LPdQ8UQA4huuxaQsVeRPFl2oM8oDGxMFhJUWZf9McpLtJasDDZb/Bpeg==", - "dev": true + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.0.tgz", + "integrity": "sha512-gv3ZRaISU3fjPAgNsriBRqGWQL6quFx04YMPW/zD8XMLsU32mhCCbfbO6KZFLjvYpCZ8zyDEgqsgf+PwPaM7GQ==", + "license": "MIT" }, "node_modules/@jridgewell/trace-mapping": { "version": "0.3.22", "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.22.tgz", "integrity": "sha512-Wf963MzWtA2sjrNt+g18IAln9lKnlRp+K2eH4jjIoF1wYeq3aMREpG09xhlhdzS0EjwU7qmUJYangWa+151vZw==", - "dev": true, "dependencies": { "@jridgewell/resolve-uri": "^3.1.0", "@jridgewell/sourcemap-codec": "^1.4.14" @@ -2116,8 +2101,6 @@ "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, - "peer": true, "dependencies": { "@nodelib/fs.stat": "2.0.5", "run-parallel": "^1.1.9" @@ -2130,8 +2113,6 @@ "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, - "peer": true, "engines": { "node": ">= 8" } @@ -2140,8 +2121,6 @@ "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, - "peer": true, "dependencies": { "@nodelib/fs.scandir": "2.1.5", "fastq": "^1.6.0" @@ -2241,6 +2220,15 @@ "integrity": "sha512-+Fj43pSMwJs4KRrH/938Uf+uAELIgVBmQzg/q1YG10djyfA3TnrU8N8XzqCh/okZdszqBQTZf96idMfE5lnwTA==", "dev": true }, + "node_modules/@sindresorhus/is": { + "version": "0.14.0", + "resolved": "https://registry.npmjs.org/@sindresorhus/is/-/is-0.14.0.tgz", + "integrity": "sha512-9NET910DNaIPngYnLLPeg+Ogzqsi9uM4mSboU5y6p8S5DzMTVEsJZrawi+BoDNUVBa2DhJqQYUFvMDfgU062LQ==", + "license": "MIT", + "engines": { + "node": ">=6" + } + }, "node_modules/@sinonjs/commons": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/@sinonjs/commons/-/commons-3.0.1.tgz", @@ -2259,6 +2247,18 @@ "@sinonjs/commons": "^3.0.0" } }, + "node_modules/@szmarczak/http-timer": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@szmarczak/http-timer/-/http-timer-1.1.2.tgz", + "integrity": "sha512-XIB2XbzHTN6ieIjfIMV9hlVcfPU26s2vafYWQcZHWXHOxiaRZYEDKEwdl129Zyg50+foYV2jCgtrqSA6qNuNSA==", + "license": "MIT", + "dependencies": { + "defer-to-connect": "^1.0.1" + }, + "engines": { + "node": ">=6" + } + }, "node_modules/@types/babel__core": { "version": "7.20.5", "resolved": "https://registry.npmjs.org/@types/babel__core/-/babel__core-7.20.5.tgz", @@ -2333,11 +2333,41 @@ "@types/istanbul-lib-report": "*" } }, + "node_modules/@types/lodash": { + "version": "4.17.12", + "resolved": "https://registry.npmjs.org/@types/lodash/-/lodash-4.17.12.tgz", + "integrity": "sha512-sviUmCE8AYdaF/KIHLDJBQgeYzPBI0vf/17NaYehBJfYD1j6/L95Slh07NlyK2iNyBNaEkb3En2jRt+a8y3xZQ==", + "license": "MIT" + }, + "node_modules/@types/minimatch": { + "version": "3.0.5", + "resolved": "https://registry.npmjs.org/@types/minimatch/-/minimatch-3.0.5.tgz", + "integrity": "sha512-Klz949h02Gz2uZCMGwDUSDS1YBlTdDDgbWHi+81l29tQALUtvz4rAYi5uoVhE5Lagoq6DeqAUlbrHvW/mXDgdQ==", + "license": "MIT" + }, + "node_modules/@types/minimist": { + "version": "1.2.5", + "resolved": "https://registry.npmjs.org/@types/minimist/-/minimist-1.2.5.tgz", + "integrity": "sha512-hov8bUuiLiyFPGyFPE1lwWhmzYbirOXQNNo40+y3zow8aFVTeyn3VWL0VFFfdNddA8S4Vf0Tc062rzyNr7Paag==", + "license": "MIT" + }, "node_modules/@types/node": { "version": "20.5.1", "resolved": "https://registry.npmjs.org/@types/node/-/node-20.5.1.tgz", "integrity": "sha512-4tT2UrL5LBqDwoed9wZ6N3umC4Yhz3W3FloMmiiG4JwmUJWpie0c7lcnUNd4gtMKuDEO4wRVS8B6Xa0uMRsMKg==" }, + "node_modules/@types/normalize-package-data": { + "version": "2.4.4", + "resolved": "https://registry.npmjs.org/@types/normalize-package-data/-/normalize-package-data-2.4.4.tgz", + "integrity": "sha512-37i+OaWTh9qeK4LSHPsyRC7NahnGotNuZvjLSgcPzblpHB3rrCJxAOgI5gCdKm7coonsaX1Of0ILiTcnZjbfxA==", + "license": "MIT" + }, + "node_modules/@types/parse-json": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/@types/parse-json/-/parse-json-4.0.2.tgz", + "integrity": "sha512-dISoDXWWQwUquiKsyZ4Ng+HX2KsPL7LyHKHQwgGFEA3IaKac4Obd+h2a/a6waisAoepJlBcx9paWqjA8/HVjCw==", + "license": "MIT" + }, "node_modules/@types/readable-stream": { "version": "4.0.15", "resolved": "https://registry.npmjs.org/@types/readable-stream/-/readable-stream-4.0.15.tgz", @@ -2393,6 +2423,62 @@ "dev": true, "peer": true }, + "node_modules/@vue/compiler-core": { + "version": "3.5.12", + "resolved": "https://registry.npmjs.org/@vue/compiler-core/-/compiler-core-3.5.12.tgz", + "integrity": "sha512-ISyBTRMmMYagUxhcpyEH0hpXRd/KqDU4ymofPgl2XAkY9ZhQ+h0ovEZJIiPop13UmR/54oA2cgMDjgroRelaEw==", + "license": "MIT", + "dependencies": { + "@babel/parser": "^7.25.3", + "@vue/shared": "3.5.12", + "entities": "^4.5.0", + "estree-walker": "^2.0.2", + "source-map-js": "^1.2.0" + } + }, + "node_modules/@vue/compiler-dom": { + "version": "3.5.12", + "resolved": "https://registry.npmjs.org/@vue/compiler-dom/-/compiler-dom-3.5.12.tgz", + "integrity": "sha512-9G6PbJ03uwxLHKQ3P42cMTi85lDRvGLB2rSGOiQqtXELat6uI4n8cNz9yjfVHRPIu+MsK6TE418Giruvgptckg==", + "license": "MIT", + "dependencies": { + "@vue/compiler-core": "3.5.12", + "@vue/shared": "3.5.12" + } + }, + "node_modules/@vue/compiler-sfc": { + "version": "3.5.12", + "resolved": "https://registry.npmjs.org/@vue/compiler-sfc/-/compiler-sfc-3.5.12.tgz", + "integrity": "sha512-2k973OGo2JuAa5+ZlekuQJtitI5CgLMOwgl94BzMCsKZCX/xiqzJYzapl4opFogKHqwJk34vfsaKpfEhd1k5nw==", + "license": "MIT", + "dependencies": { + "@babel/parser": "^7.25.3", + "@vue/compiler-core": "3.5.12", + "@vue/compiler-dom": "3.5.12", + "@vue/compiler-ssr": "3.5.12", + "@vue/shared": "3.5.12", + "estree-walker": "^2.0.2", + "magic-string": "^0.30.11", + "postcss": "^8.4.47", + "source-map-js": "^1.2.0" + } + }, + "node_modules/@vue/compiler-ssr": { + "version": "3.5.12", + "resolved": "https://registry.npmjs.org/@vue/compiler-ssr/-/compiler-ssr-3.5.12.tgz", + "integrity": "sha512-eLwc7v6bfGBSM7wZOGPmRavSWzNFF6+PdRhE+VFJhNCgHiF8AM7ccoqcv5kBXA2eWUfigD7byekvf/JsOfKvPA==", + "license": "MIT", + "dependencies": { + "@vue/compiler-dom": "3.5.12", + "@vue/shared": "3.5.12" + } + }, + "node_modules/@vue/shared": { + "version": "3.5.12", + "resolved": "https://registry.npmjs.org/@vue/shared/-/shared-3.5.12.tgz", + "integrity": "sha512-L2RPSAwUFbgZH20etwrXyVyCBu9OxRSi8T/38QsvnkJyvq2LufW2lDCOzm7t/U9C1mkhJGWYfCuFBCmIuNivrg==", + "license": "MIT" + }, "node_modules/@xstate/fsm": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/@xstate/fsm/-/fsm-2.1.0.tgz", @@ -2487,11 +2573,19 @@ "integrity": "sha512-MWipKbbYiYI0UC7cl8m/i/IWTqfC8YXsqjzybjddLsFjStroQzsHXkc73JutMvBiXmOvapk+axIl79ig5t55Bw==", "license": "MIT" }, + "node_modules/ansi-align": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/ansi-align/-/ansi-align-3.0.1.tgz", + "integrity": "sha512-IOfwwBF5iczOjp/WeY4YxyjqAFMQoZufdQWDd19SEExbVLNXqvpzSJ/M7Za4/sCPmQ0+GRquoA7bGcINcxew6w==", + "license": "ISC", + "dependencies": { + "string-width": "^4.1.0" + } + }, "node_modules/ansi-escapes": { "version": "4.3.2", "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-4.3.2.tgz", "integrity": "sha512-gKXj5ALrKWQLsYG9jlTRmR/xKluxHV+Z9QEwNIgCfM1/uwPMCuzVVnh5mwTd+OuBZcwSIMbqssNWRm1lE51QaQ==", - "dev": true, "dependencies": { "type-fest": "^0.21.3" }, @@ -2506,7 +2600,6 @@ "version": "0.21.3", "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.21.3.tgz", "integrity": "sha512-t0rzBq87m3fVcduHDUFhKmyyX+9eo6WQjZvf51Ea/M0Q7+T374Jp1aUiyUl0GKxp8M/OETVHSDvmkyPgvX+X2w==", - "dev": true, "engines": { "node": ">=10" }, @@ -2564,6 +2657,33 @@ "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==" }, + "node_modules/array-differ": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/array-differ/-/array-differ-3.0.0.tgz", + "integrity": "sha512-THtfYS6KtME/yIAhKjZ2ul7XI96lQGHRputJQHO80LAWQnuGP4iCIN8vdMRboGbIEYBwU33q8Tch1os2+X0kMg==", + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "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==", + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/arrify": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/arrify/-/arrify-1.0.1.tgz", + "integrity": "sha512-3CYzex9M9FGQjCGMGyi6/31c8GJbgb0qGyrx5HWxPd0aCwh4cB2YjMb2Xf9UuoogrMrlO9cTqnB5rI5GHZTcUA==", + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/asap": { "version": "2.0.6", "resolved": "https://registry.npmjs.org/asap/-/asap-2.0.6.tgz", @@ -2762,11 +2882,44 @@ "integrity": "sha512-d0II/GO9uf9lfUHH2BQsjxzRJZBdsjgsBiW4BvhWk/3qoKwQFjIDVN19PfX8F2D/r9PCMTtLWjYVCFrpeYUzsw==", "dev": true }, + "node_modules/boxen": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/boxen/-/boxen-5.1.2.tgz", + "integrity": "sha512-9gYgQKXx+1nP8mP7CzFyaUARhg7D3n1dF/FnErWmu9l6JvGpNUN278h0aSb+QjoiKSWG+iZ3uHrcqk0qrY9RQQ==", + "license": "MIT", + "dependencies": { + "ansi-align": "^3.0.0", + "camelcase": "^6.2.0", + "chalk": "^4.1.0", + "cli-boxes": "^2.2.1", + "string-width": "^4.2.2", + "type-fest": "^0.20.2", + "widest-line": "^3.1.0", + "wrap-ansi": "^7.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/boxen/node_modules/camelcase": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-6.3.0.tgz", + "integrity": "sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA==", + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "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" @@ -2776,7 +2929,6 @@ "version": "3.0.3", "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.3.tgz", "integrity": "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==", - "dev": true, "license": "MIT", "dependencies": { "fill-range": "^7.1.1" @@ -2854,109 +3006,345 @@ "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.2.tgz", "integrity": "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==" }, - "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": "5.3.1", - "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz", - "integrity": "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==", - "dev": true, + "node_modules/cacheable-request": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/cacheable-request/-/cacheable-request-6.1.0.tgz", + "integrity": "sha512-Oj3cAGPCqOZX7Rz64Uny2GYAZNliQSqfbePrgAQ1wKAihYmCUnraBtJtKcGR4xz7wF+LoJC+ssFZvv5BgF9Igg==", + "license": "MIT", + "dependencies": { + "clone-response": "^1.0.2", + "get-stream": "^5.1.0", + "http-cache-semantics": "^4.0.0", + "keyv": "^3.0.0", + "lowercase-keys": "^2.0.0", + "normalize-url": "^4.1.0", + "responselike": "^1.0.2" + }, "engines": { - "node": ">=6" + "node": ">=8" } }, - "node_modules/caniuse-lite": { - "version": "1.0.30001581", - "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001581.tgz", - "integrity": "sha512-whlTkwhqV2tUmP3oYhtNfaWGYHDdS3JYFQBKXxcUR9qqPWsRhFHhoISO2Xnl/g0xyKzht9mI1LZpiNWfMzHixQ==", - "dev": true, - "funding": [ - { - "type": "opencollective", - "url": "https://opencollective.com/browserslist" - }, - { - "type": "tidelift", - "url": "https://tidelift.com/funding/github/npm/caniuse-lite" - }, - { - "type": "github", - "url": "https://github.com/sponsors/ai" - } - ] - }, - "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, + "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==", + "license": "MIT", "dependencies": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" + "pump": "^3.0.0" }, "engines": { - "node": ">=10" + "node": ">=8" }, "funding": { - "url": "https://github.com/chalk/chalk?sponsor=1" + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/char-regex": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/char-regex/-/char-regex-1.0.2.tgz", - "integrity": "sha512-kWWXztvZ5SBQV+eRgKFeh8q5sLuZY2+8WUIzlxWVTg+oGwY14qylx1KbKzHd8P6ZYkAg0xyIDU9JMHhyJMZ1jw==", - "dev": true, - "engines": { - "node": ">=10" + "node_modules/cacheable-request/node_modules/json-buffer": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/json-buffer/-/json-buffer-3.0.0.tgz", + "integrity": "sha512-CuUqjv0FUZIdXkHPI8MezCnFCdaTAacej1TZYulLoAg1h/PhwkdXFN4V/gzY4g+fMBCOV2xF+rp7t2XD2ns/NQ==", + "license": "MIT" + }, + "node_modules/cacheable-request/node_modules/keyv": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/keyv/-/keyv-3.1.0.tgz", + "integrity": "sha512-9ykJ/46SN/9KPM/sichzQ7OvXyGDYKGTaDlKMGCAlg2UK8KRy4jb0d8sFc+0Tt0YYnThq8X2RZgCg74RPxgcVA==", + "license": "MIT", + "dependencies": { + "json-buffer": "3.0.0" } }, - "node_modules/ci-info": { - "version": "3.9.0", - "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-3.9.0.tgz", - "integrity": "sha512-NIxF55hv4nSqQswkAeiOi1r83xy8JldOFDTWiug55KBu9Jnblncd2U6ViHmYgHf01TPZS77NJBhBMKdWj9HQMQ==", - "dev": true, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/sibiraj-s" - } - ], + "node_modules/cacheable-request/node_modules/lowercase-keys": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/lowercase-keys/-/lowercase-keys-2.0.0.tgz", + "integrity": "sha512-tqNXrS78oMOE73NMxK4EMLQsQowWf8jKooH9g7xPavRT706R6bkQJ6DY2Te7QukaZsulxa30wQ7bk0pm4XiHmA==", + "license": "MIT", "engines": { "node": ">=8" } }, - "node_modules/cjs-module-lexer": { - "version": "1.2.3", - "resolved": "https://registry.npmjs.org/cjs-module-lexer/-/cjs-module-lexer-1.2.3.tgz", - "integrity": "sha512-0TNiGstbQmCFwt4akjjBg5pLRTSyj/PkWQ1ZoO2zntmg9yLqSRxwEa4iCfQLGjqhiqBfOJa7W/E8wfGrTDmlZQ==", - "dev": true + "node_modules/callsite": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/callsite/-/callsite-1.0.0.tgz", + "integrity": "sha512-0vdNRFXn5q+dtOqjfFtmtlI9N2eVZ7LMyEV2iKC5mEEFvSg/69Ml6b/WU2qF8W1nLRa0wiSrDT3Y5jOHZCwKPQ==", + "engines": { + "node": "*" + } }, - "node_modules/cliui": { - "version": "8.0.1", - "resolved": "https://registry.npmjs.org/cliui/-/cliui-8.0.1.tgz", - "integrity": "sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ==", - "dev": true, + "node_modules/callsite-record": { + "version": "4.1.5", + "resolved": "https://registry.npmjs.org/callsite-record/-/callsite-record-4.1.5.tgz", + "integrity": "sha512-OqeheDucGKifjQRx524URgV4z4NaKjocGhygTptDea+DLROre4ZEecA4KXDq+P7qlGCohYVNOh3qr+y5XH5Ftg==", + "license": "MIT", "dependencies": { - "string-width": "^4.2.0", - "strip-ansi": "^6.0.1", - "wrap-ansi": "^7.0.0" - }, - "engines": { - "node": ">=12" + "@devexpress/error-stack-parser": "^2.0.6", + "@types/lodash": "^4.14.72", + "callsite": "^1.0.0", + "chalk": "^2.4.0", + "highlight-es": "^1.0.0", + "lodash": "4.6.1 || ^4.16.1", + "pinkie-promise": "^2.0.0" } }, - "node_modules/co": { + "node_modules/callsite-record/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==", + "license": "MIT", + "dependencies": { + "color-convert": "^1.9.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/callsite-record/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==", + "license": "MIT", + "dependencies": { + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/callsite-record/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==", + "license": "MIT", + "dependencies": { + "color-name": "1.1.3" + } + }, + "node_modules/callsite-record/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==", + "license": "MIT" + }, + "node_modules/callsite-record/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==", + "license": "MIT", + "engines": { + "node": ">=0.8.0" + } + }, + "node_modules/callsite-record/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==", + "license": "MIT", + "engines": { + "node": ">=4" + } + }, + "node_modules/callsite-record/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==", + "license": "MIT", + "dependencies": { + "has-flag": "^3.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/callsites": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", + "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==", + "engines": { + "node": ">=6" + } + }, + "node_modules/camelcase": { + "version": "5.3.1", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz", + "integrity": "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==", + "engines": { + "node": ">=6" + } + }, + "node_modules/camelcase-keys": { + "version": "6.2.2", + "resolved": "https://registry.npmjs.org/camelcase-keys/-/camelcase-keys-6.2.2.tgz", + "integrity": "sha512-YrwaA0vEKazPBkn0ipTiMpSajYDSe+KjQfrjhcBMxJt/znbvlHd8Pw/Vamaz5EB4Wfhs3SUR3Z9mwRu/P3s3Yg==", + "license": "MIT", + "dependencies": { + "camelcase": "^5.3.1", + "map-obj": "^4.0.0", + "quick-lru": "^4.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/caniuse-lite": { + "version": "1.0.30001581", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001581.tgz", + "integrity": "sha512-whlTkwhqV2tUmP3oYhtNfaWGYHDdS3JYFQBKXxcUR9qqPWsRhFHhoISO2Xnl/g0xyKzht9mI1LZpiNWfMzHixQ==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/caniuse-lite" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ] + }, + "node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "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/char-regex": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/char-regex/-/char-regex-1.0.2.tgz", + "integrity": "sha512-kWWXztvZ5SBQV+eRgKFeh8q5sLuZY2+8WUIzlxWVTg+oGwY14qylx1KbKzHd8P6ZYkAg0xyIDU9JMHhyJMZ1jw==", + "dev": true, + "engines": { + "node": ">=10" + } + }, + "node_modules/chardet": { + "version": "0.7.0", + "resolved": "https://registry.npmjs.org/chardet/-/chardet-0.7.0.tgz", + "integrity": "sha512-mT8iDcrh03qDGRRmoA2hmBJnxpllMR+0/0qlzjqZES6NdiWDcZkCNAk4rPFZ9Q85r27unkiNNg8ZOiwZXBHwcA==", + "license": "MIT" + }, + "node_modules/ci-info": { + "version": "3.9.0", + "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-3.9.0.tgz", + "integrity": "sha512-NIxF55hv4nSqQswkAeiOi1r83xy8JldOFDTWiug55KBu9Jnblncd2U6ViHmYgHf01TPZS77NJBhBMKdWj9HQMQ==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/sibiraj-s" + } + ], + "engines": { + "node": ">=8" + } + }, + "node_modules/cjs-module-lexer": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/cjs-module-lexer/-/cjs-module-lexer-1.2.3.tgz", + "integrity": "sha512-0TNiGstbQmCFwt4akjjBg5pLRTSyj/PkWQ1ZoO2zntmg9yLqSRxwEa4iCfQLGjqhiqBfOJa7W/E8wfGrTDmlZQ==", + "dev": true + }, + "node_modules/cli-boxes": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/cli-boxes/-/cli-boxes-2.2.1.tgz", + "integrity": "sha512-y4coMcylgSCdVinjiDBuR8PCC2bLjyGTwEmPb9NHR/QaNU6EUOXcTY/s6VjGMD6ENSEaeQYHCY0GNGS5jfMwPw==", + "license": "MIT", + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/cli-cursor": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/cli-cursor/-/cli-cursor-3.1.0.tgz", + "integrity": "sha512-I/zHAwsKf9FqGoXM4WWRACob9+SNukZTd94DWF57E4toouRulbCxcUh6RKUEOQlYTHJnzkPMySvPNaaSLNfLZw==", + "license": "MIT", + "dependencies": { + "restore-cursor": "^3.1.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/cli-spinners": { + "version": "2.9.2", + "resolved": "https://registry.npmjs.org/cli-spinners/-/cli-spinners-2.9.2.tgz", + "integrity": "sha512-ywqV+5MmyL4E7ybXgKys4DugZbX0FC6LnwrhjuykIjnK9k8OQacQ7axGKnjDXWNhns0xot3bZI5h55H8yo9cJg==", + "license": "MIT", + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/cli-width": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/cli-width/-/cli-width-3.0.0.tgz", + "integrity": "sha512-FxqpkPPwu1HjuN93Omfm4h8uIanXofW0RxVEW3k5RKx+mJJYSthzNhp32Kzxxy3YAEZ/Dc/EWN1vZRY0+kOhbw==", + "license": "ISC", + "engines": { + "node": ">= 10" + } + }, + "node_modules/cliui": { + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-8.0.1.tgz", + "integrity": "sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ==", + "dev": true, + "dependencies": { + "string-width": "^4.2.0", + "strip-ansi": "^6.0.1", + "wrap-ansi": "^7.0.0" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/clone": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/clone/-/clone-1.0.4.tgz", + "integrity": "sha512-JQHZ2QMW6l3aH/j6xCqQThY/9OH4D/9ls34cgkUBiEeocRTU04tHfKPBsUK1PqZCUQM7GiA0IIXJSuXHI64Kbg==", + "license": "MIT", + "engines": { + "node": ">=0.8" + } + }, + "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==", + "license": "MIT", + "dependencies": { + "mimic-response": "^1.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/co": { "version": "4.6.0", "resolved": "https://registry.npmjs.org/co/-/co-4.6.0.tgz", "integrity": "sha512-QVb0dM5HvG+uaxitm8wONl7jltx8dqhfU33DcqtOZcLSVIKSDDLDi7+0LbAKiyI8hD9u42m2YxXSkMGWThaecQ==", - "dev": true, "engines": { "iojs": ">= 1.0.0", "node": ">= 0.12.0" @@ -3052,8 +3440,7 @@ "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 + "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==" }, "node_modules/concat-stream": { "version": "2.0.0", @@ -3094,6 +3481,50 @@ "node": ">= 10.0.0" } }, + "node_modules/configstore": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/configstore/-/configstore-5.0.1.tgz", + "integrity": "sha512-aMKprgk5YhBNyH25hj8wGt2+D52Sw1DRRIzqBwLp2Ya9mFmY8KPvvtvmna8SxVR9JMZ4kzMD68N22vlaRpkeFA==", + "license": "BSD-2-Clause", + "dependencies": { + "dot-prop": "^5.2.0", + "graceful-fs": "^4.1.2", + "make-dir": "^3.0.0", + "unique-string": "^2.0.0", + "write-file-atomic": "^3.0.0", + "xdg-basedir": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/configstore/node_modules/make-dir": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-3.1.0.tgz", + "integrity": "sha512-g3FeP20LNwhALb/6Cz6Dd4F2ngze0jz7tbzrD2wAV+o9FeNHe4rL+yK2md0J/fiSf1sa1ADhXqi5+oVwOM/eGw==", + "license": "MIT", + "dependencies": { + "semver": "^6.0.0" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/configstore/node_modules/write-file-atomic": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/write-file-atomic/-/write-file-atomic-3.0.3.tgz", + "integrity": "sha512-AvHcyZ5JnSfq3ioSyjrBkH9yW4m7Ayk8/9My/DD9onKeu/94fwrMocemO2QAJFAlnnDN+ZDS+ZjAR5ua1/PV/Q==", + "license": "ISC", + "dependencies": { + "imurmurhash": "^0.1.4", + "is-typedarray": "^1.0.0", + "signal-exit": "^3.0.2", + "typedarray-to-buffer": "^3.1.5" + } + }, "node_modules/content-disposition": { "version": "0.5.4", "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.4.tgz", @@ -3112,13 +3543,39 @@ "dev": true }, "node_modules/cookie": { - "version": "0.5.0", - "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.5.0.tgz", - "integrity": "sha512-YZ3GUyn/o8gfKJlnlX7g7xq4gyO6OSuhGPKaaGssGB2qgDUS0gPgtTvoyZLTt9Ab6dC4hfc9dV5arkvc/OCmrw==", + "version": "0.7.2", + "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.7.2.tgz", + "integrity": "sha512-yki5XnKuf750l50uGTllt6kKILY4nQ1eNIQatoXEByZ5dWgnKqbnqmTrBE5B4N7lrMJKQ2ytWMiTO2o0v6Ew/w==", + "license": "MIT", "engines": { "node": ">= 0.6" } }, + "node_modules/cosmiconfig": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-7.1.0.tgz", + "integrity": "sha512-AdmX6xUzdNASswsFtmwSt7Vj8po9IuqXm0UXz7QKPuEUmPB4XyjGfaAr2PSuELMwkRMVH1EpIkX5bTZGRB3eCA==", + "license": "MIT", + "dependencies": { + "@types/parse-json": "^4.0.0", + "import-fresh": "^3.2.1", + "parse-json": "^5.0.0", + "path-type": "^4.0.0", + "yaml": "^1.10.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/cosmiconfig/node_modules/yaml": { + "version": "1.10.2", + "resolved": "https://registry.npmjs.org/yaml/-/yaml-1.10.2.tgz", + "integrity": "sha512-r3vXyErRCYJ7wg28yvBY5VSoAF8ZvlcW9/BwUzEtUsjvX/DKs24dIkuwjtuprwJJHsbyUbLApepYTR1BN4uHrg==", + "license": "ISC", + "engines": { + "node": ">= 6" + } + }, "node_modules/create-jest": { "version": "29.7.0", "resolved": "https://registry.npmjs.org/create-jest/-/create-jest-29.7.0.tgz", @@ -3169,6 +3626,15 @@ "node": ">= 8" } }, + "node_modules/crypto-random-string": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/crypto-random-string/-/crypto-random-string-2.0.0.tgz", + "integrity": "sha512-v1plID3y9r/lPhviJ1wrXpLeyUIGAZ2SHNYTEapm7/8A9nLPoyvVp3RK/EPFqn5kEznyWgYZNsRtYYIWbuG8KA==", + "license": "MIT", + "engines": { + "node": ">=8" + } + }, "node_modules/debug": { "version": "4.3.4", "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", @@ -3190,6 +3656,52 @@ "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" }, + "node_modules/decamelize": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-1.2.0.tgz", + "integrity": "sha512-z2S+W9X73hAUUki+N+9Za2lBlun89zigOyGrsax+KUQ6wKW4ZoWpEYBkGhQjwAjjDCkWxhY0VKEhk8wzY7F5cA==", + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/decamelize-keys": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/decamelize-keys/-/decamelize-keys-1.1.1.tgz", + "integrity": "sha512-WiPxgEirIV0/eIOMcnFBA3/IJZAZqKnwAwWyvvdi4lsr1WCN22nhdf/3db3DoZcUjTV2SqfzIwNyp6y2xs3nmg==", + "license": "MIT", + "dependencies": { + "decamelize": "^1.1.0", + "map-obj": "^1.0.0" + }, + "engines": { + "node": ">=0.10.0" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/decamelize-keys/node_modules/map-obj": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/map-obj/-/map-obj-1.0.1.tgz", + "integrity": "sha512-7N/q3lyZ+LVCp7PzuxrJr4KMbBE2hW7BT7YNia330OFxIf4d3r5zVpicP2650l7CPN6RM9zOJRl3NGpqSiw3Eg==", + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/decompress-response": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/decompress-response/-/decompress-response-3.3.0.tgz", + "integrity": "sha512-BzRPQuY1ip+qDonAOz42gRm/pg9F768C+npV/4JOsxRC2sq+Rlk+Q4ZCAsOhnIaMrgarILY+RMUIvMmmX1qAEA==", + "license": "MIT", + "dependencies": { + "mimic-response": "^1.0.0" + }, + "engines": { + "node": ">=4" + } + }, "node_modules/dedent": { "version": "1.5.1", "resolved": "https://registry.npmjs.org/dedent/-/dedent-1.5.1.tgz", @@ -3204,6 +3716,15 @@ } } }, + "node_modules/deep-extend": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/deep-extend/-/deep-extend-0.6.0.tgz", + "integrity": "sha512-LOHxIOaPYdHlJRtCQfDIVZtfw/ufM8+rVj649RIHzcm/vGwQRXFt6OPqIFWsm2XEMrNIEtWR64sY1LEKD2vAOA==", + "license": "MIT", + "engines": { + "node": ">=4.0.0" + } + }, "node_modules/deep-is": { "version": "0.1.4", "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.4.tgz", @@ -3220,6 +3741,24 @@ "node": ">=0.10.0" } }, + "node_modules/defaults": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/defaults/-/defaults-1.0.4.tgz", + "integrity": "sha512-eFuaLoy/Rxalv2kr+lqMlUnrDWV+3j4pljOIJgLIhI058IQfWJ7vXhyEIHu+HtC738klGALYxOKDO0bQP3tg8A==", + "license": "MIT", + "dependencies": { + "clone": "^1.0.2" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/defer-to-connect": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/defer-to-connect/-/defer-to-connect-1.1.3.tgz", + "integrity": "sha512-0ISdNousHvZT2EiFlZeZAHBUvSxmKswVCEf8hW7KWgG4a8MVEu/3Vb6uWYozkjylyCxe0JBIiRB1jV45S70WVQ==", + "license": "MIT" + }, "node_modules/define-properties": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.2.0.tgz", @@ -3244,6 +3783,166 @@ "node": ">=0.4.0" } }, + "node_modules/depcheck": { + "version": "1.4.7", + "resolved": "https://registry.npmjs.org/depcheck/-/depcheck-1.4.7.tgz", + "integrity": "sha512-1lklS/bV5chOxwNKA/2XUUk/hPORp8zihZsXflr8x0kLwmcZ9Y9BsS6Hs3ssvA+2wUVbG0U2Ciqvm1SokNjPkA==", + "license": "MIT", + "dependencies": { + "@babel/parser": "^7.23.0", + "@babel/traverse": "^7.23.2", + "@vue/compiler-sfc": "^3.3.4", + "callsite": "^1.0.0", + "camelcase": "^6.3.0", + "cosmiconfig": "^7.1.0", + "debug": "^4.3.4", + "deps-regex": "^0.2.0", + "findup-sync": "^5.0.0", + "ignore": "^5.2.4", + "is-core-module": "^2.12.0", + "js-yaml": "^3.14.1", + "json5": "^2.2.3", + "lodash": "^4.17.21", + "minimatch": "^7.4.6", + "multimatch": "^5.0.0", + "please-upgrade-node": "^3.2.0", + "readdirp": "^3.6.0", + "require-package-name": "^2.0.1", + "resolve": "^1.22.3", + "resolve-from": "^5.0.0", + "semver": "^7.5.4", + "yargs": "^16.2.0" + }, + "bin": { + "depcheck": "bin/depcheck.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/depcheck/node_modules/argparse": { + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz", + "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==", + "license": "MIT", + "dependencies": { + "sprintf-js": "~1.0.2" + } + }, + "node_modules/depcheck/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==", + "license": "MIT", + "dependencies": { + "balanced-match": "^1.0.0" + } + }, + "node_modules/depcheck/node_modules/camelcase": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-6.3.0.tgz", + "integrity": "sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA==", + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/depcheck/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==", + "license": "ISC", + "dependencies": { + "string-width": "^4.2.0", + "strip-ansi": "^6.0.0", + "wrap-ansi": "^7.0.0" + } + }, + "node_modules/depcheck/node_modules/js-yaml": { + "version": "3.14.1", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.14.1.tgz", + "integrity": "sha512-okMH7OXXJ7YrN9Ok3/SXrnu4iX9yOk+25nqX4imS2npuvTYDmo/QEZoqwZkYaIDk3jVvBOTOIEgEhaLOynBS9g==", + "license": "MIT", + "dependencies": { + "argparse": "^1.0.7", + "esprima": "^4.0.0" + }, + "bin": { + "js-yaml": "bin/js-yaml.js" + } + }, + "node_modules/depcheck/node_modules/minimatch": { + "version": "7.4.6", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-7.4.6.tgz", + "integrity": "sha512-sBz8G/YjVniEz6lKPNpKxXwazJe4c19fEfV2GDMX6AjFz+MX9uDWIZW8XreVhkFW3fkIdTv/gxWr/Kks5FFAVw==", + "license": "ISC", + "dependencies": { + "brace-expansion": "^2.0.1" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/depcheck/node_modules/resolve-from": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-5.0.0.tgz", + "integrity": "sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==", + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/depcheck/node_modules/semver": { + "version": "7.6.3", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.6.3.tgz", + "integrity": "sha512-oVekP1cKtI+CTDvHWYFUcMtsK/00wmAEfyqKfNdARm8u1wNVhSgaX7A8d4UuIlUI5e84iEwOhs7ZPYRmzU9U6A==", + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/depcheck/node_modules/sprintf-js": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz", + "integrity": "sha512-D9cPgkvLlV3t3IzL0D0YLvGA9Ahk4PcvVwUbN0dSGr1aP0Nrt4AEnTUbuGvquEC0mA64Gqt1fzirlRs5ibXx8g==", + "license": "BSD-3-Clause" + }, + "node_modules/depcheck/node_modules/yargs": { + "version": "16.2.0", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-16.2.0.tgz", + "integrity": "sha512-D1mvvtDG0L5ft/jGWkLpG1+m0eQxOfaBvTNELraWj22wSVUMWxZUvYgJYcKh6jGGIkJFhH4IZPQhR4TKpc8mBw==", + "license": "MIT", + "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/depcheck/node_modules/yargs-parser": { + "version": "20.2.9", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-20.2.9.tgz", + "integrity": "sha512-y11nGElTIV+CT3Zv9t7VKl+Q3hTQoT9a1Qzezhhl6Rp21gJ/IVTW7Z3y9EWXhuUBC2Shnf+DX0antecpAwSP8w==", + "license": "ISC", + "engines": { + "node": ">=10" + } + }, "node_modules/depd": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz", @@ -3252,6 +3951,21 @@ "node": ">= 0.8" } }, + "node_modules/deps-regex": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/deps-regex/-/deps-regex-0.2.0.tgz", + "integrity": "sha512-PwuBojGMQAYbWkMXOY9Pd/NWCDNHVH12pnS7WHqZkTSeMESe4hwnKKRp0yR87g37113x4JPbo/oIvXY+s/f56Q==", + "license": "MIT" + }, + "node_modules/detect-file": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/detect-file/-/detect-file-1.0.0.tgz", + "integrity": "sha512-DtCOLG98P007x7wiiOmfI0fi3eIKyWiLTGJ2MDnVi/E04lWGbf+JzrRHMm0rgIIZJGtHpKpbVgLWHrv8xXpc3Q==", + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/detect-newline": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/detect-newline/-/detect-newline-3.1.0.tgz", @@ -3276,6 +3990,18 @@ "node": "^14.15.0 || ^16.10.0 || >=18.0.0" } }, + "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==", + "license": "MIT", + "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", @@ -3289,6 +4015,24 @@ "node": ">=6.0.0" } }, + "node_modules/dot-prop": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/dot-prop/-/dot-prop-5.3.0.tgz", + "integrity": "sha512-QM8q3zDe58hqUqjraQOmzZ1LIH9SWQJTlEKCH4kJ2oQvLZk7RbQXvtDM2XEq3fwkV9CCvvH4LA0AV+ogFsBM2Q==", + "license": "MIT", + "dependencies": { + "is-obj": "^2.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/duplexer3": { + "version": "0.1.5", + "resolved": "https://registry.npmjs.org/duplexer3/-/duplexer3-0.1.5.tgz", + "integrity": "sha512-1A8za6ws41LQgv9HrE/66jyC5yuSjQ3L/KOpFtoBilsAK2iA2wuS5rTt1OCzIvtS2V7nVmedsUU+DGRcjBmOYA==", + "license": "BSD-3-Clause" + }, "node_modules/eastasianwidth": { "version": "0.2.0", "resolved": "https://registry.npmjs.org/eastasianwidth/-/eastasianwidth-0.2.0.tgz", @@ -3343,11 +4087,22 @@ "resolved": "https://registry.npmjs.org/enigma.js/-/enigma.js-2.14.0.tgz", "integrity": "sha512-M84VjtO2w9+AUDK5NEn5j7FOPBdiSkwRbbgVFWxkLXxutH/z8ATGFh0Ko/4pTNwWF/9On/lEEr4BOI+ZewSw9g==" }, + "node_modules/entities": { + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/entities/-/entities-4.5.0.tgz", + "integrity": "sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw==", + "license": "BSD-2-Clause", + "engines": { + "node": ">=0.12" + }, + "funding": { + "url": "https://github.com/fb55/entities?sponsor=1" + } + }, "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==", - "dev": true, "dependencies": { "is-arrayish": "^0.2.1" } @@ -3402,11 +4157,19 @@ "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-goat": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/escape-goat/-/escape-goat-2.1.1.tgz", + "integrity": "sha512-8/uIhbG12Csjy2JEW7D9pHbreaVaS/OpN3ycnyvElTdwM5n6GY6W6e2IPemfvGZeUMqZ9A/3GqIZMgKnBhAw/Q==", + "license": "MIT", + "engines": { + "node": ">=8" + } + }, "node_modules/escape-html": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz", @@ -3612,7 +4375,6 @@ "version": "4.0.1", "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz", "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==", - "dev": true, "bin": { "esparse": "bin/esparse.js", "esvalidate": "bin/esvalidate.js" @@ -3655,6 +4417,12 @@ "node": ">=4.0" } }, + "node_modules/estree-walker": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-2.0.2.tgz", + "integrity": "sha512-Rfkk/Mp/DL7JVje3u18FxFujQlTNR2q6QfMSMB7AvCBx91NGj/ba3kCfza0f6dVDbw7YlRf/nDrn7pQrCCyQ/w==", + "license": "MIT" + }, "node_modules/esutils": { "version": "2.0.3", "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz", @@ -3685,7 +4453,6 @@ "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", @@ -3710,7 +4477,19 @@ "integrity": "sha512-Zk/eNKV2zbjpKzrsQ+n1G6poVbErQxJ0LBOJXaKZ1EViLzH+hrLu9cdXI4zw9dBQJslwBEpbQ2P1oS7nDxs6jQ==", "dev": true, "engines": { - "node": ">= 0.8.0" + "node": ">= 0.8.0" + } + }, + "node_modules/expand-tilde": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/expand-tilde/-/expand-tilde-2.0.2.tgz", + "integrity": "sha512-A5EmesHW6rfnZ9ysHQjPdJRni0SRar0tjtG5MNtm9n5TUvsYU8oozprtRD4AqHxcZWWlVuAmQo2nWKfN9oyjTw==", + "license": "MIT", + "dependencies": { + "homedir-polyfill": "^1.0.1" + }, + "engines": { + "node": ">=0.10.0" } }, "node_modules/expect": { @@ -3795,6 +4574,20 @@ "resolved": "https://registry.npmjs.org/extend/-/extend-3.0.2.tgz", "integrity": "sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==" }, + "node_modules/external-editor": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/external-editor/-/external-editor-3.1.0.tgz", + "integrity": "sha512-hMQ4CX1p1izmuLYyZqLMO/qGNw10wSv9QDCPfzXfyFrOaCSSoRfqE1Kf1s5an66J5JZC62NewG+mK49jOCtQew==", + "license": "MIT", + "dependencies": { + "chardet": "^0.7.0", + "iconv-lite": "^0.4.24", + "tmp": "^0.0.33" + }, + "engines": { + "node": ">=4" + } + }, "node_modules/fast-content-type-parse": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/fast-content-type-parse/-/fast-content-type-parse-1.1.0.tgz", @@ -3816,6 +4609,34 @@ "integrity": "sha512-VxPP4NqbUjj6MaAOafWeUn2cXWLcCtljklUtZf0Ind4XQ+QPtmA0b18zZy0jIQx+ExRVCR/ZQpBmik5lXshNsw==", "dev": true }, + "node_modules/fast-glob": { + "version": "3.3.2", + "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.3.2.tgz", + "integrity": "sha512-oX2ruAFQwf/Orj8m737Y5adxDQO0LAB7/S5MnxCdTNDd4p6BsyIVsv9JQsATbTSq8KHRpLwIHbVlUNatxd+1Ow==", + "license": "MIT", + "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==", + "license": "ISC", + "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", @@ -3936,11 +4757,6 @@ "node": ">=10" } }, - "node_modules/fastify/node_modules/process-warning": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/process-warning/-/process-warning-3.0.0.tgz", - "integrity": "sha512-mqn0kFRl0EoqhnL0GQ0veqFHyIN1yig9RHh/InzORTUiZHFRAur+aMtRkELNwGs9aNwKS6tg/An4NYBPGwvtzQ==" - }, "node_modules/fastify/node_modules/semver": { "version": "7.5.4", "resolved": "https://registry.npmjs.org/semver/-/semver-7.5.4.tgz", @@ -3982,6 +4798,30 @@ "resolved": "https://registry.npmjs.org/fecha/-/fecha-4.2.3.tgz", "integrity": "sha512-OP2IUU6HeYKJi3i0z4A19kHMQoLVs4Hc+DPqqxI2h/DPZHTm/vjsfC6P0b4jCMy14XizLBqvndQ+UilD7707Jw==" }, + "node_modules/figures": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/figures/-/figures-3.2.0.tgz", + "integrity": "sha512-yaduQFRKLXYOGgEn6AZau90j3ggSOyiqXU0F9JZfeXYhNa+Jk4X+s45A2zg5jns87GAFa34BBm2kXw4XpNcbdg==", + "license": "MIT", + "dependencies": { + "escape-string-regexp": "^1.0.5" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/figures/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==", + "license": "MIT", + "engines": { + "node": ">=0.8.0" + } + }, "node_modules/file-entry-cache": { "version": "6.0.1", "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-6.0.1.tgz", @@ -4007,7 +4847,6 @@ "version": "7.1.1", "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz", "integrity": "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==", - "dev": true, "license": "MIT", "dependencies": { "to-regex-range": "^5.0.1" @@ -4034,8 +4873,6 @@ "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, - "peer": true, "dependencies": { "locate-path": "^6.0.0", "path-exists": "^4.0.0" @@ -4047,6 +4884,31 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/find-yarn-workspace-root2": { + "version": "1.2.16", + "resolved": "https://registry.npmjs.org/find-yarn-workspace-root2/-/find-yarn-workspace-root2-1.2.16.tgz", + "integrity": "sha512-hr6hb1w8ePMpPVUK39S4RlwJzi+xPLuVuG8XlwXU3KD5Yn3qgBWVfy3AzNlDhWvE1EORCE65/Qm26rFQt3VLVA==", + "license": "Apache-2.0", + "dependencies": { + "micromatch": "^4.0.2", + "pkg-dir": "^4.2.0" + } + }, + "node_modules/findup-sync": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/findup-sync/-/findup-sync-5.0.0.tgz", + "integrity": "sha512-MzwXju70AuyflbgeOhzvQWAvvQdo1XL0A9bVvlXsYcFEBM87WR4OakL4OfZq+QRmr+duJubio+UtNQCPsVESzQ==", + "license": "MIT", + "dependencies": { + "detect-file": "^1.0.0", + "is-glob": "^4.0.3", + "micromatch": "^4.0.4", + "resolve-dir": "^1.0.1" + }, + "engines": { + "node": ">= 10.13.0" + } + }, "node_modules/flat-cache": { "version": "3.2.0", "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-3.2.0.tgz", @@ -4177,7 +5039,6 @@ "version": "1.1.2", "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz", "integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==", - "dev": true, "funding": { "url": "https://github.com/sponsors/ljharb" } @@ -4195,7 +5056,6 @@ "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.*" } @@ -4228,7 +5088,6 @@ "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" }, @@ -4236,6 +5095,15 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/giturl": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/giturl/-/giturl-1.0.3.tgz", + "integrity": "sha512-qVDEXufVtYUzYqI5hoDUONh9GCEPi0n+e35KNDafdsNt9fPxB0nvFW/kFiw7W42wkg8TUyhBqb+t24yyaoc87A==", + "license": "MIT", + "engines": { + "node": ">= 0.10.0" + } + }, "node_modules/glob": { "version": "7.2.3", "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", @@ -4319,6 +5187,68 @@ "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", "dev": true }, + "node_modules/global-dirs": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/global-dirs/-/global-dirs-3.0.1.tgz", + "integrity": "sha512-NBcGGFbBA9s1VzD41QXDG+3++t9Mn5t1FpLdhESY6oKY4gYTFpX4wO3sqGUa0Srjtbfj3szX0RnemmrVRUdULA==", + "license": "MIT", + "dependencies": { + "ini": "2.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/global-dirs/node_modules/ini": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ini/-/ini-2.0.0.tgz", + "integrity": "sha512-7PnF4oN3CvZF23ADhA5wRaYEQpJ8qygSkbtTXWBeXWXmEVRXK+1ITciHWwHhsjv1TmW0MgacIv6hEi5pX5NQdA==", + "license": "ISC", + "engines": { + "node": ">=10" + } + }, + "node_modules/global-modules": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/global-modules/-/global-modules-2.0.0.tgz", + "integrity": "sha512-NGbfmJBp9x8IxyJSd1P+otYK8vonoJactOogrVfFRIAEY1ukil8RSKDz2Yo7wh1oihl51l/r6W4epkeKJHqL8A==", + "license": "MIT", + "dependencies": { + "global-prefix": "^3.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/global-prefix": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/global-prefix/-/global-prefix-3.0.0.tgz", + "integrity": "sha512-awConJSVCHVGND6x3tmMaKcQvwXLhjdkmomy2W+Goaui8YPgYgXJZewhg3fWC+DlfqqQuWg8AwqjGTD2nAPVWg==", + "license": "MIT", + "dependencies": { + "ini": "^1.3.5", + "kind-of": "^6.0.2", + "which": "^1.3.1" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/global-prefix/node_modules/which": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/which/-/which-1.3.1.tgz", + "integrity": "sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ==", + "license": "ISC", + "dependencies": { + "isexe": "^2.0.0" + }, + "bin": { + "which": "bin/which" + } + }, "node_modules/globals": { "version": "13.24.0", "resolved": "https://registry.npmjs.org/globals/-/globals-13.24.0.tgz", @@ -4350,6 +5280,60 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/globby": { + "version": "11.1.0", + "resolved": "https://registry.npmjs.org/globby/-/globby-11.1.0.tgz", + "integrity": "sha512-jhIXaOzy1sb8IyocaruWSn1TjmnBVs8Ayhcy83rmxNJ8q2uWKCAj3CnJY+KpGSXCueAPc0i05kVvVKtP1t9S3g==", + "license": "MIT", + "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": "9.6.0", + "resolved": "https://registry.npmjs.org/got/-/got-9.6.0.tgz", + "integrity": "sha512-R7eWptXuGYxwijs0eV+v3o6+XH1IqVK8dJOEecQfTmkncw9AV4dcw/Dhxi8MdlqPthxxpZyizMzyg8RTmEsG+Q==", + "license": "MIT", + "dependencies": { + "@sindresorhus/is": "^0.14.0", + "@szmarczak/http-timer": "^1.1.2", + "cacheable-request": "^6.0.0", + "decompress-response": "^3.3.0", + "duplexer3": "^0.1.4", + "get-stream": "^4.1.0", + "lowercase-keys": "^1.0.1", + "mimic-response": "^1.0.1", + "p-cancelable": "^1.0.0", + "to-readable-stream": "^1.0.0", + "url-parse-lax": "^3.0.0" + }, + "engines": { + "node": ">=8.6" + } + }, + "node_modules/got/node_modules/get-stream": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-4.1.0.tgz", + "integrity": "sha512-GMat4EJ5161kIy2HevLlr4luNjBgvmj413KaQA7jt4V8B4RDsfpHk7WQ9GVqfYyyx8OS/L66Kox+rJRNklLK7w==", + "license": "MIT", + "dependencies": { + "pump": "^3.0.0" + }, + "engines": { + "node": ">=6" + } + }, "node_modules/graceful-fs": { "version": "4.2.11", "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz", @@ -4382,79 +5366,225 @@ "uglify-js": "^3.1.4" } }, - "node_modules/has": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz", - "integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==", - "dev": true, - "dependencies": { - "function-bind": "^1.1.1" - }, + "node_modules/hard-rejection": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/hard-rejection/-/hard-rejection-2.1.0.tgz", + "integrity": "sha512-VIZB+ibDhx7ObhAe7OVtoEbuP4h/MuOTHJ+J8h/eBXotJYl0fBgR72xDFCKgIh22OJZIOVNxBMWuhAr10r8HdA==", + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/has": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz", + "integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==", + "dev": true, + "dependencies": { + "function-bind": "^1.1.1" + }, + "engines": { + "node": ">= 0.4.0" + } + }, + "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==", + "engines": { + "node": ">=8" + } + }, + "node_modules/has-property-descriptors": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/has-property-descriptors/-/has-property-descriptors-1.0.0.tgz", + "integrity": "sha512-62DVLZGoiEBDHQyqG4w9xCuZ7eJEwNmJRWw2VY84Oedb7WFcA27fiEVe8oUQx9hAUJ4ekurquucTGwsyO1XGdQ==", + "dev": true, + "dependencies": { + "get-intrinsic": "^1.1.1" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/has-proto": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/has-proto/-/has-proto-1.0.1.tgz", + "integrity": "sha512-7qE+iP+O+bgF9clE5+UoBFzE65mlBiVj3tKCrlNQ0Ogwm0BjpT/gK4SlLYDMybDh5I3TCTKnPPa0oMG7JDYrhg==", + "dev": true, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/has-symbols": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.3.tgz", + "integrity": "sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A==", + "dev": true, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/has-yarn": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/has-yarn/-/has-yarn-2.1.0.tgz", + "integrity": "sha512-UqBRqi4ju7T+TqGNdqAO0PaSVGsDGJUBQvk9eUWNGRY1CFGDzYhLWoM7JQEemnlvVcv/YEmc2wNW8BC24EnUsw==", + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/hasown": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.0.tgz", + "integrity": "sha512-vUptKVTpIJhcczKBbgnS+RtcuYMB8+oNzPK2/Hp3hanz8JmpATdmmgLgSaadVREkDm+e2giHwY3ZRkyjSIDDFA==", + "dependencies": { + "function-bind": "^1.1.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/help-me": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/help-me/-/help-me-5.0.0.tgz", + "integrity": "sha512-7xgomUX6ADmcYzFik0HzAxh/73YlKR9bmFzf51CZwR+b6YtzU2m0u49hQCqV6SvlqIqsaxovfwdvbnsw3b/zpg==" + }, + "node_modules/highlight-es": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/highlight-es/-/highlight-es-1.0.3.tgz", + "integrity": "sha512-s/SIX6yp/5S1p8aC/NRDC1fwEb+myGIfp8/TzZz0rtAv8fzsdX7vGl3Q1TrXCsczFq8DI3CBFBCySPClfBSdbg==", + "license": "MIT", + "dependencies": { + "chalk": "^2.4.0", + "is-es2016-keyword": "^1.0.0", + "js-tokens": "^3.0.0" + } + }, + "node_modules/highlight-es/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==", + "license": "MIT", + "dependencies": { + "color-convert": "^1.9.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/highlight-es/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==", + "license": "MIT", + "dependencies": { + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/highlight-es/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==", + "license": "MIT", + "dependencies": { + "color-name": "1.1.3" + } + }, + "node_modules/highlight-es/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==", + "license": "MIT" + }, + "node_modules/highlight-es/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==", + "license": "MIT", "engines": { - "node": ">= 0.4.0" + "node": ">=0.8.0" } }, - "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, + "node_modules/highlight-es/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==", + "license": "MIT", "engines": { - "node": ">=8" + "node": ">=4" } }, - "node_modules/has-property-descriptors": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/has-property-descriptors/-/has-property-descriptors-1.0.0.tgz", - "integrity": "sha512-62DVLZGoiEBDHQyqG4w9xCuZ7eJEwNmJRWw2VY84Oedb7WFcA27fiEVe8oUQx9hAUJ4ekurquucTGwsyO1XGdQ==", - "dev": true, + "node_modules/highlight-es/node_modules/js-tokens": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-3.0.2.tgz", + "integrity": "sha512-RjTcuD4xjtthQkaWH7dFlH85L+QaVtSoOyGdZ3g6HFhS9dFNDfLyqgm2NFe2X6cQpeFmt0452FJjFG5UameExg==", + "license": "MIT" + }, + "node_modules/highlight-es/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==", + "license": "MIT", "dependencies": { - "get-intrinsic": "^1.1.1" + "has-flag": "^3.0.0" }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/has-proto": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/has-proto/-/has-proto-1.0.1.tgz", - "integrity": "sha512-7qE+iP+O+bgF9clE5+UoBFzE65mlBiVj3tKCrlNQ0Ogwm0BjpT/gK4SlLYDMybDh5I3TCTKnPPa0oMG7JDYrhg==", - "dev": true, "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" + "node": ">=4" } }, - "node_modules/has-symbols": { + "node_modules/homedir-polyfill": { "version": "1.0.3", - "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.3.tgz", - "integrity": "sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A==", - "dev": true, + "resolved": "https://registry.npmjs.org/homedir-polyfill/-/homedir-polyfill-1.0.3.tgz", + "integrity": "sha512-eSmmWE5bZTK2Nou4g0AI3zZ9rswp7GRKoKXS1BLUkvPviOqs4YTN1djQIqrXy9k5gEtdLPy86JjRwsNM9tnDcA==", + "license": "MIT", + "dependencies": { + "parse-passwd": "^1.0.0" + }, "engines": { - "node": ">= 0.4" + "node": ">=0.10.0" + } + }, + "node_modules/hosted-git-info": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-4.1.0.tgz", + "integrity": "sha512-kyCuEOWjJqZuDbRHzL8V93NzQhwIB71oFWSyzVo+KPZI+pnQPPxucdkrOZvkLRnrf5URsQM+IJ09Dw29cRALIA==", + "license": "ISC", + "dependencies": { + "lru-cache": "^6.0.0" }, - "funding": { - "url": "https://github.com/sponsors/ljharb" + "engines": { + "node": ">=10" } }, - "node_modules/hasown": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.0.tgz", - "integrity": "sha512-vUptKVTpIJhcczKBbgnS+RtcuYMB8+oNzPK2/Hp3hanz8JmpATdmmgLgSaadVREkDm+e2giHwY3ZRkyjSIDDFA==", - "dev": true, + "node_modules/hosted-git-info/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==", + "license": "ISC", "dependencies": { - "function-bind": "^1.1.2" + "yallist": "^4.0.0" }, "engines": { - "node": ">= 0.4" + "node": ">=10" } }, - "node_modules/help-me": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/help-me/-/help-me-5.0.0.tgz", - "integrity": "sha512-7xgomUX6ADmcYzFik0HzAxh/73YlKR9bmFzf51CZwR+b6YtzU2m0u49hQCqV6SvlqIqsaxovfwdvbnsw3b/zpg==" + "node_modules/hosted-git-info/node_modules/yallist": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", + "license": "ISC" }, "node_modules/html-escaper": { "version": "2.0.2", @@ -4462,6 +5592,12 @@ "integrity": "sha512-H2iMtd0I4Mt5eYiapRdIDjp+XzelXQ0tFE4JS7YFwFevXXMmOp9myNrUvCg0D6ws8iqkRPBfKHgbwig1SmlLfg==", "dev": true }, + "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==", + "license": "BSD-2-Clause" + }, "node_modules/http-errors": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-2.0.0.tgz", @@ -4481,7 +5617,6 @@ "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" } @@ -4494,6 +5629,18 @@ "node": ">=0.4" } }, + "node_modules/iconv-lite": { + "version": "0.4.24", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz", + "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==", + "license": "MIT", + "dependencies": { + "safer-buffer": ">= 2.1.2 < 3" + }, + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/ieee754": { "version": "1.2.1", "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.2.1.tgz", @@ -4517,8 +5664,6 @@ "version": "5.3.1", "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.3.1.tgz", "integrity": "sha512-5Fytz/IraMjqpwfd34ke28PTVMjZjJG2MPn5t7OE4eUCUNf8BAa7b5WUS9/Qvr6mwOQS7Mk6vdsMno5he+T8Xw==", - "dev": true, - "peer": true, "engines": { "node": ">= 4" } @@ -4527,8 +5672,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, - "peer": true, "dependencies": { "parent-module": "^1.0.0", "resolve-from": "^4.0.0" @@ -4540,6 +5683,15 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/import-lazy": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/import-lazy/-/import-lazy-2.1.0.tgz", + "integrity": "sha512-m7ZEHgtw69qOGw+jwxXkHlrlIPdTGkyh66zXZ1ajZbxkDBNjSY/LGbmjc7h0s2ELsUDTAhFr55TrPSSqJGPG0A==", + "license": "MIT", + "engines": { + "node": ">=4" + } + }, "node_modules/import-local": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/import-local/-/import-local-3.1.0.tgz", @@ -4563,11 +5715,19 @@ "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/indent-string": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/indent-string/-/indent-string-4.0.0.tgz", + "integrity": "sha512-EdDDZu4A2OyIK7Lr/2zG+w5jmbuk1DVBnEwREQvBzspBJkCEbRa8GxU1lghYcaGJCnRWibjDXlq779X1/y5xwg==", + "license": "MIT", + "engines": { + "node": ">=8" + } + }, "node_modules/inflight": { "version": "1.0.6", "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", @@ -4588,6 +5748,36 @@ "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==" }, + "node_modules/ini": { + "version": "1.3.8", + "resolved": "https://registry.npmjs.org/ini/-/ini-1.3.8.tgz", + "integrity": "sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew==", + "license": "ISC" + }, + "node_modules/inquirer": { + "version": "7.3.3", + "resolved": "https://registry.npmjs.org/inquirer/-/inquirer-7.3.3.tgz", + "integrity": "sha512-JG3eIAj5V9CwcGvuOmoo6LB9kbAYT8HXffUl6memuszlwDC/qvFAJw49XJ5NROSFNPxp3iQg1GqkFhaY/CR0IA==", + "license": "MIT", + "dependencies": { + "ansi-escapes": "^4.2.1", + "chalk": "^4.1.0", + "cli-cursor": "^3.1.0", + "cli-width": "^3.0.0", + "external-editor": "^3.0.3", + "figures": "^3.0.0", + "lodash": "^4.17.19", + "mute-stream": "0.0.8", + "run-async": "^2.4.0", + "rxjs": "^6.6.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0", + "through": "^2.3.6" + }, + "engines": { + "node": ">=8.0.0" + } + }, "node_modules/ipaddr.js": { "version": "1.9.1", "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.9.1.tgz", @@ -4599,14 +5789,30 @@ "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==", - "dev": true + "integrity": "sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg==" + }, + "node_modules/is-ci": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/is-ci/-/is-ci-2.0.0.tgz", + "integrity": "sha512-YfJT7rkpQB0updsdHLGWrvhBJfcfzNNawYDNIyQXJz0IViGf75O8EBPKSdvw2rF+LGCsX4FZ8tcr3b19LcZq4w==", + "license": "MIT", + "dependencies": { + "ci-info": "^2.0.0" + }, + "bin": { + "is-ci": "bin.js" + } + }, + "node_modules/is-ci/node_modules/ci-info": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-2.0.0.tgz", + "integrity": "sha512-5tK7EtrZ0N+OLFMthtqOj4fI2Jeb88C4CAZPu25LDVUgXJ0A3Js4PMGqrn0JU1W0Mh1/Z8wZzYPxqUrXeBboCQ==", + "license": "MIT" }, "node_modules/is-core-module": { "version": "2.13.1", "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.13.1.tgz", "integrity": "sha512-hHrIjvZsftOsvKSn2TRYl63zvxsgE0K+0mYMoH6gD4omR5IWB2KynivBQczo3+wF1cCkjzvptnI9Q0sPU66ilw==", - "dev": true, "dependencies": { "hasown": "^2.0.0" }, @@ -4614,12 +5820,16 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/is-es2016-keyword": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-es2016-keyword/-/is-es2016-keyword-1.0.0.tgz", + "integrity": "sha512-JtZWPUwjdbQ1LIo9OSZ8MdkWEve198ors27vH+RzUUvZXXZkzXCxFnlUhzWYxy5IexQSRiXVw9j2q/tHMmkVYQ==", + "license": "MIT" + }, "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, - "peer": true, "engines": { "node": ">=0.10.0" } @@ -4645,8 +5855,6 @@ "version": "4.0.3", "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", - "dev": true, - "peer": true, "dependencies": { "is-extglob": "^2.1.1" }, @@ -4654,26 +5862,78 @@ "node": ">=0.10.0" } }, + "node_modules/is-installed-globally": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/is-installed-globally/-/is-installed-globally-0.4.0.tgz", + "integrity": "sha512-iwGqO3J21aaSkC7jWnHP/difazwS7SFeIqxv6wEtLU8Y5KlzFTjyqcSIT0d8s4+dDhKytsk9PJZ2BkS5eZwQRQ==", + "license": "MIT", + "dependencies": { + "global-dirs": "^3.0.0", + "is-path-inside": "^3.0.2" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/is-interactive": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-interactive/-/is-interactive-1.0.0.tgz", + "integrity": "sha512-2HvIEKRoqS62guEC+qBjpvRubdX910WCMuJTZ+I9yvqKU2/12eSL549HMwtabb4oupdj2sMP50k+XJfB/8JE6w==", + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/is-npm": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/is-npm/-/is-npm-5.0.0.tgz", + "integrity": "sha512-WW/rQLOazUq+ST/bCAVBp/2oMERWLsR7OrKyt052dNDk4DHcDE0/7QSXITlmi+VBcV13DfIbysG3tZJm5RfdBA==", + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "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, "license": "MIT", "engines": { "node": ">=0.12.0" } }, + "node_modules/is-obj": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/is-obj/-/is-obj-2.0.0.tgz", + "integrity": "sha512-drqDG3cbczxxEJRoOXcOjtdp1J/lyp1mNn0xaznRs8+muBhgQcrnbspox5X5fOw0HnMnbfDzvnEMEtqDEJEo8w==", + "license": "MIT", + "engines": { + "node": ">=8" + } + }, "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, - "peer": 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==", + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/is-stream": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-2.0.1.tgz", @@ -4685,6 +5945,12 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/is-typedarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-typedarray/-/is-typedarray-1.0.0.tgz", + "integrity": "sha512-cyA56iCMHAh5CdzjJIa4aohJyeO1YbwLi3Jc35MmRU6poroFjIGZzUzupGiRPOjgHg9TLu43xbpwXk523fMxKA==", + "license": "MIT" + }, "node_modules/is-unc-path": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/is-unc-path/-/is-unc-path-1.0.0.tgz", @@ -4696,6 +5962,33 @@ "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==", + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/is-windows": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-windows/-/is-windows-1.0.2.tgz", + "integrity": "sha512-eXK1UInq2bPmjyX6e3VHIzMLobc4J94i4AWn+Hpq3OU5KkrRC96OAcR3PRJ/pGu6m8TRnBHP9dkXQVsT/COVIA==", + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-yarn-global": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/is-yarn-global/-/is-yarn-global-0.3.0.tgz", + "integrity": "sha512-VjSeb/lHmkoyd8ryPVIKvOCn4D1koMqY+vqyjjUfc3xyKtP4dYOxM44sZrnqQSzSds3xyOrUTLTC9LVCVgLngw==", + "license": "MIT" + }, "node_modules/isexe": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", @@ -5420,8 +6713,7 @@ "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==", - "dev": true + "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==" }, "node_modules/js-yaml": { "version": "4.1.0", @@ -5439,7 +6731,6 @@ "version": "2.5.2", "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-2.5.2.tgz", "integrity": "sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA==", - "dev": true, "bin": { "jsesc": "bin/jsesc" }, @@ -5455,8 +6746,7 @@ "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==", - "dev": true + "integrity": "sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==" }, "node_modules/json-schema-resolver": { "version": "2.0.0", @@ -5525,6 +6815,15 @@ "json-buffer": "3.0.1" } }, + "node_modules/kind-of": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.3.tgz", + "integrity": "sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==", + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/kleur": { "version": "3.0.3", "resolved": "https://registry.npmjs.org/kleur/-/kleur-3.0.3.tgz", @@ -5539,6 +6838,18 @@ "resolved": "https://registry.npmjs.org/kuler/-/kuler-2.0.0.tgz", "integrity": "sha512-Xq9nH7KlWZmXAtodXDDRE7vs6DU1gTU8zYDHDiWLSip45Egwq3plLHzPn27NgvzL2r1LMPC1vdqh98sQxtqj4A==" }, + "node_modules/latest-version": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/latest-version/-/latest-version-5.1.0.tgz", + "integrity": "sha512-weT+r0kTkRQdCdYCNtkMwWXQTMEswKrFBkm4ckQOMVhhqhIMI1UT2hMj+1iigIhgSZm5gTmrRXBNoGUgaTY1xA==", + "license": "MIT", + "dependencies": { + "package-json": "^6.3.0" + }, + "engines": { + "node": ">=8" + } + }, "node_modules/leven": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/leven/-/leven-3.1.0.tgz", @@ -5555,35 +6866,85 @@ "dev": true, "peer": true, "dependencies": { - "prelude-ls": "^1.2.1", - "type-check": "~0.4.0" + "prelude-ls": "^1.2.1", + "type-check": "~0.4.0" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/light-my-request": { + "version": "5.14.0", + "resolved": "https://registry.npmjs.org/light-my-request/-/light-my-request-5.14.0.tgz", + "integrity": "sha512-aORPWntbpH5esaYpGOOmri0OHDOe3wC5M2MQxZ9dvMLZm6DnaAn0kJlcbU9hwsQgLzmZyReKwFwwPkR+nHu5kA==", + "license": "BSD-3-Clause", + "dependencies": { + "cookie": "^0.7.0", + "process-warning": "^3.0.0", + "set-cookie-parser": "^2.4.1" + } + }, + "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/load-yaml-file": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/load-yaml-file/-/load-yaml-file-0.2.0.tgz", + "integrity": "sha512-OfCBkGEw4nN6JLtgRidPX6QxjBQGQf72q3si2uvqyFEMbycSFFHwAZeXx6cJgFM9wmLrf9zBwCP3Ivqa+LLZPw==", + "license": "MIT", + "dependencies": { + "graceful-fs": "^4.1.5", + "js-yaml": "^3.13.0", + "pify": "^4.0.1", + "strip-bom": "^3.0.0" }, "engines": { - "node": ">= 0.8.0" + "node": ">=6" } }, - "node_modules/light-my-request": { - "version": "5.11.0", - "resolved": "https://registry.npmjs.org/light-my-request/-/light-my-request-5.11.0.tgz", - "integrity": "sha512-qkFCeloXCOMpmEdZ/MV91P8AT4fjwFXWaAFz3lUeStM8RcoM1ks4J/F8r1b3r6y/H4u3ACEJ1T+Gv5bopj7oDA==", + "node_modules/load-yaml-file/node_modules/argparse": { + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz", + "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==", + "license": "MIT", "dependencies": { - "cookie": "^0.5.0", - "process-warning": "^2.0.0", - "set-cookie-parser": "^2.4.1" + "sprintf-js": "~1.0.2" } }, - "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==", - "dev": true + "node_modules/load-yaml-file/node_modules/js-yaml": { + "version": "3.14.1", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.14.1.tgz", + "integrity": "sha512-okMH7OXXJ7YrN9Ok3/SXrnu4iX9yOk+25nqX4imS2npuvTYDmo/QEZoqwZkYaIDk3jVvBOTOIEgEhaLOynBS9g==", + "license": "MIT", + "dependencies": { + "argparse": "^1.0.7", + "esprima": "^4.0.0" + }, + "bin": { + "js-yaml": "bin/js-yaml.js" + } + }, + "node_modules/load-yaml-file/node_modules/sprintf-js": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz", + "integrity": "sha512-D9cPgkvLlV3t3IzL0D0YLvGA9Ahk4PcvVwUbN0dSGr1aP0Nrt4AEnTUbuGvquEC0mA64Gqt1fzirlRs5ibXx8g==", + "license": "BSD-3-Clause" + }, + "node_modules/load-yaml-file/node_modules/strip-bom": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-3.0.0.tgz", + "integrity": "sha512-vavAMRXOgBVNF6nyEEmL3DBK19iRpDcoIwW+swQ+CbGiu7lju6t+JklA1MHweoWtadgt4ISVUsXLyDq34ddcwA==", + "license": "MIT", + "engines": { + "node": ">=4" + } }, "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, - "peer": true, "dependencies": { "p-locate": "^5.0.0" }, @@ -5606,6 +6967,22 @@ "dev": true, "peer": 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==", + "license": "MIT", + "dependencies": { + "chalk": "^4.1.0", + "is-unicode-supported": "^0.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/logform": { "version": "2.6.1", "resolved": "https://registry.npmjs.org/logform/-/logform-2.6.1.tgz", @@ -5623,6 +7000,15 @@ "node": ">= 12.0.0" } }, + "node_modules/lowercase-keys": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/lowercase-keys/-/lowercase-keys-1.0.1.tgz", + "integrity": "sha512-G2Lj61tXDnVFFOi8VZds+SoQjtQC3dgokKdDG2mTm1tx4m50NUHBOZSBwQQHyy0V12A0JTG4icfZQH+xPyh8VA==", + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/lru-cache": { "version": "5.1.1", "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-5.1.1.tgz", @@ -5640,6 +7026,15 @@ "node": ">=12" } }, + "node_modules/magic-string": { + "version": "0.30.12", + "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.12.tgz", + "integrity": "sha512-Ea8I3sQMVXr8JhN4z+H/d8zwo+tYDgHE9+5G4Wnrwhs0gaK9fXTKx0Tw5Xwsd/bCPTTZNRAdpyzvoeORe9LYpw==", + "license": "MIT", + "dependencies": { + "@jridgewell/sourcemap-codec": "^1.5.0" + } + }, "node_modules/make-dir": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-4.0.0.tgz", @@ -5697,6 +7092,18 @@ "tmpl": "1.0.5" } }, + "node_modules/map-obj": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/map-obj/-/map-obj-4.3.0.tgz", + "integrity": "sha512-hdN1wVrZbb29eBGiGjJbeP8JbKjq1urkHJ/LIP/NY48MZ1QVXUsQBV1G1zvYFHn1XE06cwjBsOI2K3Ulnj1YXQ==", + "license": "MIT", + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/matcher": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/matcher/-/matcher-3.0.0.tgz", @@ -5717,17 +7124,71 @@ "node": ">= 0.6" } }, + "node_modules/meow": { + "version": "9.0.0", + "resolved": "https://registry.npmjs.org/meow/-/meow-9.0.0.tgz", + "integrity": "sha512-+obSblOQmRhcyBt62furQqRAQpNyWXo8BuQ5bN7dG8wmwQ+vwHKp/rCFD4CrTP8CsDQD1sjoZ94K417XEUk8IQ==", + "license": "MIT", + "dependencies": { + "@types/minimist": "^1.2.0", + "camelcase-keys": "^6.2.2", + "decamelize": "^1.2.0", + "decamelize-keys": "^1.1.0", + "hard-rejection": "^2.1.0", + "minimist-options": "4.1.0", + "normalize-package-data": "^3.0.0", + "read-pkg-up": "^7.0.1", + "redent": "^3.0.0", + "trim-newlines": "^3.0.0", + "type-fest": "^0.18.0", + "yargs-parser": "^20.2.3" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/meow/node_modules/type-fest": { + "version": "0.18.1", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.18.1.tgz", + "integrity": "sha512-OIAYXk8+ISY+qTOwkHtKqzAuxchoMiD9Udx+FSGQDuiRR+PJKJHc2NJAXlbhkGwTt/4/nKZxELY1w3ReWOL8mw==", + "license": "(MIT OR CC0-1.0)", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/meow/node_modules/yargs-parser": { + "version": "20.2.9", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-20.2.9.tgz", + "integrity": "sha512-y11nGElTIV+CT3Zv9t7VKl+Q3hTQoT9a1Qzezhhl6Rp21gJ/IVTW7Z3y9EWXhuUBC2Shnf+DX0antecpAwSP8w==", + "license": "ISC", + "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 + "integrity": "sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==" + }, + "node_modules/merge2": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz", + "integrity": "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==", + "license": "MIT", + "engines": { + "node": ">= 8" + } }, "node_modules/micromatch": { "version": "4.0.8", "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.8.tgz", "integrity": "sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA==", - "dev": true, "license": "MIT", "dependencies": { "braces": "^3.0.3", @@ -5771,16 +7232,32 @@ "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==", + "license": "MIT", + "engines": { + "node": ">=4" + } + }, + "node_modules/min-indent": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/min-indent/-/min-indent-1.0.1.tgz", + "integrity": "sha512-I9jwMn07Sy/IwOj3zVkVik2JTvgpaykDZEigL6Rx6N9LbMywwUSMtxET+7lVoDLLd3O3IXwJwvuuns8UB/HeAg==", + "license": "MIT", + "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" }, @@ -5796,6 +7273,20 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/minimist-options": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/minimist-options/-/minimist-options-4.1.0.tgz", + "integrity": "sha512-Q4r8ghd80yhO/0j1O3B2BjweX3fiHg9cdOwjJd2J76Q135c+NDxGCqdYKQ1SKBuFfgWbAUzBfvYjPUEeNgqN1A==", + "license": "MIT", + "dependencies": { + "arrify": "^1.0.1", + "is-plain-obj": "^1.1.0", + "kind-of": "^6.0.3" + }, + "engines": { + "node": ">= 6" + } + }, "node_modules/minipass": { "version": "7.1.2", "resolved": "https://registry.npmjs.org/minipass/-/minipass-7.1.2.tgz", @@ -5909,6 +7400,58 @@ "node": ">=14.21.3" } }, + "node_modules/multimatch": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/multimatch/-/multimatch-5.0.0.tgz", + "integrity": "sha512-ypMKuglUrZUD99Tk2bUQ+xNQj43lPEfAeX2o9cTteAmShXy2VHDJpuwu1o0xqoKCt9jLVAvwyFKdLTPXKAfJyA==", + "license": "MIT", + "dependencies": { + "@types/minimatch": "^3.0.3", + "array-differ": "^3.0.0", + "array-union": "^2.1.0", + "arrify": "^2.0.1", + "minimatch": "^3.0.4" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/multimatch/node_modules/arrify": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/arrify/-/arrify-2.0.1.tgz", + "integrity": "sha512-3duEwti880xqi4eAMN8AyR4a0ByT90zoYdLlevfrvU43vb0YZwZVfxOgxWrLXXXpyugL0hNZc9G6BiB5B3nUug==", + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/mute-stream": { + "version": "0.0.8", + "resolved": "https://registry.npmjs.org/mute-stream/-/mute-stream-0.0.8.tgz", + "integrity": "sha512-nnbWWOkoWyUsTjKrhgD0dcz22mdkSnpYqbEjIm2nhwhuxlSkpywJmBo8h0ZqJdkp73mb90SssHkN4rsRaBAfAA==", + "license": "ISC" + }, + "node_modules/nanoid": { + "version": "3.3.7", + "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.7.tgz", + "integrity": "sha512-eSRppjcPIatRIMC1U6UngP8XFcz8MQWGQdt1MTBQ7NaAmvXDfvNxbvWV3x2y6CdEUciCSsDHDQZbhYaB8QEo2g==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "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", @@ -5920,6 +7463,15 @@ "resolved": "https://registry.npmjs.org/neo-async/-/neo-async-2.6.2.tgz", "integrity": "sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw==" }, + "node_modules/node-emoji": { + "version": "1.11.0", + "resolved": "https://registry.npmjs.org/node-emoji/-/node-emoji-1.11.0.tgz", + "integrity": "sha512-wo2DpQkQp7Sjm2A0cq+sN7EHKO6Sl0ctXeBdFZrL9T9+UywORbufTcTZxom8YqpLQt/FqNMUkOpkZrJVYSKD3A==", + "license": "MIT", + "dependencies": { + "lodash": "^4.17.21" + } + }, "node_modules/node-int64": { "version": "0.4.0", "resolved": "https://registry.npmjs.org/node-int64/-/node-int64-0.4.0.tgz", @@ -5953,6 +7505,33 @@ "nodemailer": ">= 6.0.0" } }, + "node_modules/normalize-package-data": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-3.0.3.tgz", + "integrity": "sha512-p2W1sgqij3zMMyRC067Dg16bfzVH+w7hyegmpIvZ4JNjqtGOVAIvLmjBx3yP7YTe9vKJgkoNOPjwQGogDoMXFA==", + "license": "BSD-2-Clause", + "dependencies": { + "hosted-git-info": "^4.0.1", + "is-core-module": "^2.5.0", + "semver": "^7.3.4", + "validate-npm-package-license": "^3.0.1" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/normalize-package-data/node_modules/semver": { + "version": "7.6.3", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.6.3.tgz", + "integrity": "sha512-oVekP1cKtI+CTDvHWYFUcMtsK/00wmAEfyqKfNdARm8u1wNVhSgaX7A8d4UuIlUI5e84iEwOhs7ZPYRmzU9U6A==", + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, "node_modules/normalize-path": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", @@ -5962,11 +7541,84 @@ "node": ">=0.10.0" } }, + "node_modules/normalize-url": { + "version": "4.5.1", + "resolved": "https://registry.npmjs.org/normalize-url/-/normalize-url-4.5.1.tgz", + "integrity": "sha512-9UZCFRHQdNrfTpGg8+1INIg93B6zE0aXMVFkw1WFwvO4SlZywU6aLg5Of0Ap/PgcbSw4LNxvMWXMeugwMCX0AA==", + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/npm-check": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/npm-check/-/npm-check-6.0.1.tgz", + "integrity": "sha512-tlEhXU3689VLUHYEZTS/BC61vfeN2xSSZwoWDT6WLuenZTpDmGmNT5mtl15erTR0/A15ldK06/NEKg9jYJ9OTQ==", + "license": "MIT", + "dependencies": { + "callsite-record": "^4.1.3", + "chalk": "^4.1.0", + "co": "^4.6.0", + "depcheck": "^1.3.1", + "execa": "^5.0.0", + "giturl": "^1.0.0", + "global-modules": "^2.0.0", + "globby": "^11.0.2", + "inquirer": "^7.3.3", + "is-ci": "^2.0.0", + "lodash": "^4.17.20", + "meow": "^9.0.0", + "minimatch": "^3.0.2", + "node-emoji": "^1.10.0", + "ora": "^5.3.0", + "package-json": "^6.5.0", + "path-exists": "^4.0.0", + "pkg-dir": "^5.0.0", + "preferred-pm": "^3.0.3", + "rc-config-loader": "^4.0.0", + "semver": "^7.3.4", + "semver-diff": "^3.1.1", + "strip-ansi": "^6.0.0", + "text-table": "^0.2.0", + "throat": "^6.0.1", + "update-notifier": "^5.1.0", + "xtend": "^4.0.2" + }, + "bin": { + "npm-check": "bin/cli.js" + }, + "engines": { + "node": ">=10.9.0" + } + }, + "node_modules/npm-check/node_modules/pkg-dir": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-5.0.0.tgz", + "integrity": "sha512-NPE8TDbzl/3YQYY7CSS228s3g2ollTFnc+Qi3tqmqJp9Vg2ovUpixcJEo2HJScN2Ez+kEaal6y70c0ehqJBJeA==", + "license": "MIT", + "dependencies": { + "find-up": "^5.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/npm-check/node_modules/semver": { + "version": "7.6.3", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.6.3.tgz", + "integrity": "sha512-oVekP1cKtI+CTDvHWYFUcMtsK/00wmAEfyqKfNdARm8u1wNVhSgaX7A8d4UuIlUI5e84iEwOhs7ZPYRmzU9U6A==", + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, "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" }, @@ -6028,7 +7680,6 @@ "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" }, @@ -6051,15 +7702,87 @@ "dev": true, "peer": 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" + "@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/ora": { + "version": "5.4.1", + "resolved": "https://registry.npmjs.org/ora/-/ora-5.4.1.tgz", + "integrity": "sha512-5b6Y85tPxZZ7QytO+BQzysW31HJku27cRIlkbAXaNx+BdcVi+LlRFmVXzeF6a7JCwJpyw5c4b+YSVImQIrBpuQ==", + "license": "MIT", + "dependencies": { + "bl": "^4.1.0", + "chalk": "^4.1.0", + "cli-cursor": "^3.1.0", + "cli-spinners": "^2.5.0", + "is-interactive": "^1.0.0", + "is-unicode-supported": "^0.1.0", + "log-symbols": "^4.1.0", + "strip-ansi": "^6.0.0", + "wcwidth": "^1.0.1" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/ora/node_modules/bl": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/bl/-/bl-4.1.0.tgz", + "integrity": "sha512-1W07cM9gS6DcLperZfFSj+bWLtaPGSOHWhPiGzXmvVJbRLdG82sH/Kn8EtW1VqWVA54AKf2h5k5BbnIbwF3h6w==", + "license": "MIT", + "dependencies": { + "buffer": "^5.5.0", + "inherits": "^2.0.4", + "readable-stream": "^3.4.0" + } + }, + "node_modules/ora/node_modules/buffer": { + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/buffer/-/buffer-5.7.1.tgz", + "integrity": "sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT", + "dependencies": { + "base64-js": "^1.3.1", + "ieee754": "^1.1.13" + } + }, + "node_modules/ora/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==", + "license": "MIT", + "dependencies": { + "inherits": "^2.0.3", + "string_decoder": "^1.1.1", + "util-deprecate": "^1.0.1" }, "engines": { - "node": ">= 0.8.0" + "node": ">= 6" } }, "node_modules/os": { @@ -6067,11 +7790,28 @@ "resolved": "https://registry.npmjs.org/os/-/os-0.1.2.tgz", "integrity": "sha512-ZoXJkvAnljwvc56MbvhtKVWmSkzV712k42Is2mA0+0KTSRakq5XXuXpjZjgAt9ctzl51ojhQWakQQpmOvXWfjQ==" }, + "node_modules/os-tmpdir": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/os-tmpdir/-/os-tmpdir-1.0.2.tgz", + "integrity": "sha512-D2FR03Vir7FIu45XBY20mTb+/ZSWB00sjU9jdQXt83gDrI4Ztz5Fs7/yy74g2N5SVQY4xY1qDr4rNddwYRVX0g==", + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/p-cancelable": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/p-cancelable/-/p-cancelable-1.1.0.tgz", + "integrity": "sha512-s73XxOZ4zpt1edZYZzvhqFa6uvQc1vwUa0K0BdtIZgQMAJj9IbebH+JkgKZc9h+B05PKHLOTl4ajG1BmNrVZlw==", + "license": "MIT", + "engines": { + "node": ">=6" + } + }, "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" }, @@ -6086,8 +7826,6 @@ "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, - "peer": true, "dependencies": { "p-limit": "^3.0.2" }, @@ -6102,11 +7840,25 @@ "version": "2.2.0", "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz", "integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==", - "dev": true, "engines": { "node": ">=6" } }, + "node_modules/package-json": { + "version": "6.5.0", + "resolved": "https://registry.npmjs.org/package-json/-/package-json-6.5.0.tgz", + "integrity": "sha512-k3bdm2n25tkyxcjSKzB5x8kfVxlMdgsbPr0GkZcwHsLpba6cBjqCt1KlcChKEvxHIcTB1FVMuwoijZ26xex5MQ==", + "license": "MIT", + "dependencies": { + "got": "^9.6.0", + "registry-auth-token": "^4.0.0", + "registry-url": "^5.0.0", + "semver": "^6.2.0" + }, + "engines": { + "node": ">=8" + } + }, "node_modules/package-json-from-dist": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/package-json-from-dist/-/package-json-from-dist-1.0.0.tgz", @@ -6117,8 +7869,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, - "peer": true, "dependencies": { "callsites": "^3.0.0" }, @@ -6130,7 +7880,6 @@ "version": "5.2.0", "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-5.2.0.tgz", "integrity": "sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg==", - "dev": true, "dependencies": { "@babel/code-frame": "^7.0.0", "error-ex": "^1.3.1", @@ -6144,11 +7893,19 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/parse-passwd": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/parse-passwd/-/parse-passwd-1.0.0.tgz", + "integrity": "sha512-1Y1A//QUXEZK7YKz+rD9WydcE1+EuPr6ZBgKecAB8tmoW6UFv0NREVJe1p+jRxtThkcbbKkfwIbWJe/IeE6m2Q==", + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, "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" } @@ -6173,8 +7930,7 @@ "node_modules/path-parse": { "version": "1.0.7", "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz", - "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==", - "dev": true + "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==" }, "node_modules/path-scurry": { "version": "1.11.1", @@ -6201,17 +7957,25 @@ "node": "14 || >=16.14" } }, + "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==", + "license": "MIT", + "engines": { + "node": ">=8" + } + }, "node_modules/picocolors": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.0.0.tgz", - "integrity": "sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ==", - "dev": true + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz", + "integrity": "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==", + "license": "ISC" }, "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" }, @@ -6219,6 +7983,36 @@ "url": "https://github.com/sponsors/jonschlinkert" } }, + "node_modules/pify": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/pify/-/pify-4.0.1.tgz", + "integrity": "sha512-uB80kBFb/tfd68bVleG9T5GGsGPjJrLAUpR5PZIrhBnIaRTQRjqdJSsIKkOP6OAIFbj7GOrcudc5pNjZ+geV2g==", + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/pinkie": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/pinkie/-/pinkie-2.0.4.tgz", + "integrity": "sha512-MnUuEycAemtSaeFSjXKW/aroV7akBbY+Sv+RkyqFjgAe73F+MR0TBWKBRDkmfWq/HiFmdavfZ1G7h4SPZXaCSg==", + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/pinkie-promise": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/pinkie-promise/-/pinkie-promise-2.0.1.tgz", + "integrity": "sha512-0Gni6D4UcLTbv9c57DfxDGdr41XfgUjqWZu492f0cIGr16zDU06BWP/RAEvOuo7CQ0CNjHaLlM59YJJFm3NWlw==", + "license": "MIT", + "dependencies": { + "pinkie": "^2.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/pino": { "version": "9.0.0", "resolved": "https://registry.npmjs.org/pino/-/pino-9.0.0.tgz", @@ -6254,11 +8048,6 @@ "resolved": "https://registry.npmjs.org/pino-std-serializers/-/pino-std-serializers-6.2.2.tgz", "integrity": "sha512-cHjPPsE+vhj/tnhCy/wiMh3M3z3h/j15zHQX+S9GkTBgqJuTuJzYJ4gUyACLhDaJ7kk9ba9iRDmbH2tJU03OiA==" }, - "node_modules/pino/node_modules/process-warning": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/process-warning/-/process-warning-3.0.0.tgz", - "integrity": "sha512-mqn0kFRl0EoqhnL0GQ0veqFHyIN1yig9RHh/InzORTUiZHFRAur+aMtRkELNwGs9aNwKS6tg/An4NYBPGwvtzQ==" - }, "node_modules/pirates": { "version": "4.0.6", "resolved": "https://registry.npmjs.org/pirates/-/pirates-4.0.6.tgz", @@ -6272,7 +8061,6 @@ "version": "4.2.0", "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-4.2.0.tgz", "integrity": "sha512-HRDzbaKjC+AOWVXxAU/x54COGeIv9eb+6CkDSQoNTt4XyWoIJvuPsXizxu/Fr23EiekbtZwmh1IcIG/l/a10GQ==", - "dev": true, "dependencies": { "find-up": "^4.0.0" }, @@ -6284,7 +8072,6 @@ "version": "4.1.0", "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz", "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==", - "dev": true, "dependencies": { "locate-path": "^5.0.0", "path-exists": "^4.0.0" @@ -6297,7 +8084,6 @@ "version": "5.0.0", "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz", "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==", - "dev": true, "dependencies": { "p-locate": "^4.1.0" }, @@ -6309,7 +8095,6 @@ "version": "2.3.0", "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz", "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==", - "dev": true, "dependencies": { "p-try": "^2.0.0" }, @@ -6324,7 +8109,6 @@ "version": "4.1.0", "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz", "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==", - "dev": true, "dependencies": { "p-limit": "^2.2.0" }, @@ -6332,10 +8116,48 @@ "node": ">=8" } }, + "node_modules/please-upgrade-node": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/please-upgrade-node/-/please-upgrade-node-3.2.0.tgz", + "integrity": "sha512-gQR3WpIgNIKwBMVLkpMUeR3e1/E1y42bqDQZfql+kDeXd8COYfM8PQA4X6y7a8u9Ua9FHmsrrmirW2vHs45hWg==", + "license": "MIT", + "dependencies": { + "semver-compare": "^1.0.0" + } + }, + "node_modules/postcss": { + "version": "8.4.47", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.47.tgz", + "integrity": "sha512-56rxCq7G/XfB4EkXq9Egn5GCqugWvDFjafDOThIdMBsI15iqPqR5r15TfSr1YPYeEI19YeaXMCbY6u88Y76GLQ==", + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/postcss" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "dependencies": { + "nanoid": "^3.3.7", + "picocolors": "^1.1.0", + "source-map-js": "^1.2.1" + }, + "engines": { + "node": "^10 || ^12 || >=14" + } + }, "node_modules/posthog-node": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/posthog-node/-/posthog-node-4.2.0.tgz", - "integrity": "sha512-hgyCYMyzMvuF3qWMw6JvS8gT55v7Mtp5wKWcnDrw+nu39D0Tk9BXD7I0LOBp0lGlHEPaXCEVYUtviNKrhMALGA==", + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/posthog-node/-/posthog-node-4.2.1.tgz", + "integrity": "sha512-l+fsjYEkTik3m/G0pE7gMr4qBJP84LhK779oQm6MBzhBGpd4By4qieTW+4FUAlNCyzQTynn3Nhsa50c0IELSxQ==", + "license": "MIT", "dependencies": { "axios": "^1.7.4", "rusha": "^0.8.14" @@ -6344,6 +8166,21 @@ "node": ">=15.0.0" } }, + "node_modules/preferred-pm": { + "version": "3.1.4", + "resolved": "https://registry.npmjs.org/preferred-pm/-/preferred-pm-3.1.4.tgz", + "integrity": "sha512-lEHd+yEm22jXdCphDrkvIJQU66EuLojPPtvZkpKIkiD+l0DMThF/niqZKJSoU8Vl7iuvtmzyMhir9LdVy5WMnA==", + "license": "MIT", + "dependencies": { + "find-up": "^5.0.0", + "find-yarn-workspace-root2": "1.2.16", + "path-exists": "^4.0.0", + "which-pm": "^2.2.0" + }, + "engines": { + "node": ">=10" + } + }, "node_modules/prelude-ls": { "version": "1.2.1", "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz", @@ -6354,6 +8191,15 @@ "node": ">= 0.8.0" } }, + "node_modules/prepend-http": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/prepend-http/-/prepend-http-2.0.0.tgz", + "integrity": "sha512-ravE6m9Atw9Z/jjttRUZ+clIXogdghyZAuWJ3qEzjT+jI/dL1ifAqhZeC5VHzQp1MSt1+jxKkFNemj/iO7tVUA==", + "license": "MIT", + "engines": { + "node": ">=4" + } + }, "node_modules/prettier": { "version": "3.3.3", "resolved": "https://registry.npmjs.org/prettier/-/prettier-3.3.3.tgz", @@ -6422,9 +8268,10 @@ "integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==" }, "node_modules/process-warning": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/process-warning/-/process-warning-2.3.0.tgz", - "integrity": "sha512-N6mp1+2jpQr3oCFMz6SeHRGbv6Slb20bRhj4v3xR99HqNToAcOe1MFOp4tytyzOfJn+QtN8Rf7U/h2KAn4kC6g==" + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/process-warning/-/process-warning-3.0.0.tgz", + "integrity": "sha512-mqn0kFRl0EoqhnL0GQ0veqFHyIN1yig9RHh/InzORTUiZHFRAur+aMtRkELNwGs9aNwKS6tg/An4NYBPGwvtzQ==", + "license": "MIT" }, "node_modules/promise": { "version": "8.3.0", @@ -6464,6 +8311,16 @@ "resolved": "https://registry.npmjs.org/proxy-from-env/-/proxy-from-env-1.1.0.tgz", "integrity": "sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==" }, + "node_modules/pump": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/pump/-/pump-3.0.2.tgz", + "integrity": "sha512-tUPXtzlGM8FE3P0ZL6DVs/3P58k9nk8/jZeQCurTJylQA8qFYzHFfhBJkuqyE0FifOsQ0uKWekiZ5g8wtr28cw==", + "license": "MIT", + "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", @@ -6472,6 +8329,18 @@ "node": ">=6" } }, + "node_modules/pupa": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/pupa/-/pupa-2.1.1.tgz", + "integrity": "sha512-l1jNAspIBSFqbT+y+5FosojNpVpF94nlI+wDUpqP9enwOTfHx9f0gh5nB96vl+6yTpsJsypeNrwfzPrKuHB41A==", + "license": "MIT", + "dependencies": { + "escape-goat": "^2.0.0" + }, + "engines": { + "node": ">=8" + } + }, "node_modules/pure-rand": { "version": "6.0.4", "resolved": "https://registry.npmjs.org/pure-rand/-/pure-rand-6.0.4.tgz", @@ -6501,7 +8370,6 @@ "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", @@ -6515,24 +8383,198 @@ "type": "consulting", "url": "https://feross.org/support" } - ], - "peer": true + ] }, "node_modules/quick-format-unescaped": { "version": "4.0.4", "resolved": "https://registry.npmjs.org/quick-format-unescaped/-/quick-format-unescaped-4.0.4.tgz", "integrity": "sha512-tYC1Q1hgyRuHgloV/YXs2w15unPVh8qfu/qCTfhTYamaw7fyhumKa2yGpdSo87vY32rIclj+4fWYQXUMs9EHvg==" }, + "node_modules/quick-lru": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/quick-lru/-/quick-lru-4.0.1.tgz", + "integrity": "sha512-ARhCpm70fzdcvNQfPoy49IaanKkTlRWF2JMzqhcJbhSFRZv7nPTvZJdcY7301IPmvW+/p0RgIWnQDLJxifsQ7g==", + "license": "MIT", + "engines": { + "node": ">=8" + } + }, "node_modules/rate-limiter-flexible": { - "version": "5.0.3", - "resolved": "https://registry.npmjs.org/rate-limiter-flexible/-/rate-limiter-flexible-5.0.3.tgz", - "integrity": "sha512-lWx2y8NBVlTOLPyqs+6y7dxfEpT6YFqKy3MzWbCy95sTTOhOuxufP2QvRyOHpfXpB9OUJPbVLybw3z3AVAS5fA==" + "version": "5.0.4", + "resolved": "https://registry.npmjs.org/rate-limiter-flexible/-/rate-limiter-flexible-5.0.4.tgz", + "integrity": "sha512-ftYHrIfSqWYDIJZ4yPTrgOduByAp+86gUS9iklv0JoXVM8eQCAjTnydCj1hAT4MmhmkSw86NaFEJ28m/LC1pKA==", + "license": "ISC" + }, + "node_modules/rc": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/rc/-/rc-1.2.8.tgz", + "integrity": "sha512-y3bGgqKj3QBdxLbLkomlohkvsA8gdAiUQlSBJnBhfn+BPxg4bc62d8TcBW15wavDfgexCgccckhcZvywyQYPOw==", + "license": "(BSD-2-Clause OR MIT OR Apache-2.0)", + "dependencies": { + "deep-extend": "^0.6.0", + "ini": "~1.3.0", + "minimist": "^1.2.0", + "strip-json-comments": "~2.0.1" + }, + "bin": { + "rc": "cli.js" + } + }, + "node_modules/rc-config-loader": { + "version": "4.1.3", + "resolved": "https://registry.npmjs.org/rc-config-loader/-/rc-config-loader-4.1.3.tgz", + "integrity": "sha512-kD7FqML7l800i6pS6pvLyIE2ncbk9Du8Q0gp/4hMPhJU6ZxApkoLcGD8ZeqgiAlfwZ6BlETq6qqe+12DUL207w==", + "license": "MIT", + "dependencies": { + "debug": "^4.3.4", + "js-yaml": "^4.1.0", + "json5": "^2.2.2", + "require-from-string": "^2.0.2" + } + }, + "node_modules/rc/node_modules/strip-json-comments": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-2.0.1.tgz", + "integrity": "sha512-4gB8na07fecVVkOI6Rs4e7T6NOTki5EmL7TUduTs6bu3EdnSycntVJ4re8kgZA+wx9IueI2Y11bfbgwtzuE0KQ==", + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/react-is": { + "version": "18.2.0", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-18.2.0.tgz", + "integrity": "sha512-xWGDIW6x921xtzPkhiULtthJHoJvBbF3q26fzloPCK0hsvxtPVelvftw3zjbHWSkR2km9Z+4uxbDDK/6Zw9B8w==", + "dev": true + }, + "node_modules/read-pkg": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-5.2.0.tgz", + "integrity": "sha512-Ug69mNOpfvKDAc2Q8DRpMjjzdtrnv9HcSMX+4VsZxD1aZ6ZzrIE7rlzXBtWTyhULSMKg076AW6WR5iZpD0JiOg==", + "license": "MIT", + "dependencies": { + "@types/normalize-package-data": "^2.4.0", + "normalize-package-data": "^2.5.0", + "parse-json": "^5.0.0", + "type-fest": "^0.6.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/read-pkg-up": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/read-pkg-up/-/read-pkg-up-7.0.1.tgz", + "integrity": "sha512-zK0TB7Xd6JpCLmlLmufqykGE+/TlOePD6qKClNW7hHDKFh/J7/7gCWGR7joEQEW1bKq3a3yUZSObOoWLFQ4ohg==", + "license": "MIT", + "dependencies": { + "find-up": "^4.1.0", + "read-pkg": "^5.2.0", + "type-fest": "^0.8.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/read-pkg-up/node_modules/find-up": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz", + "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==", + "license": "MIT", + "dependencies": { + "locate-path": "^5.0.0", + "path-exists": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/read-pkg-up/node_modules/locate-path": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz", + "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==", + "license": "MIT", + "dependencies": { + "p-locate": "^4.1.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/read-pkg-up/node_modules/p-limit": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz", + "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==", + "license": "MIT", + "dependencies": { + "p-try": "^2.0.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/read-pkg-up/node_modules/p-locate": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz", + "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==", + "license": "MIT", + "dependencies": { + "p-limit": "^2.2.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/read-pkg-up/node_modules/type-fest": { + "version": "0.8.1", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.8.1.tgz", + "integrity": "sha512-4dbzIzqvjtgiM5rw1k5rEHtBANKmdudhGyBEajN01fEyhaAIhsoKNy6y7+IN93IfpFtwY9iqi7kD+xwKhQsNJA==", + "license": "(MIT OR CC0-1.0)", + "engines": { + "node": ">=8" + } + }, + "node_modules/read-pkg/node_modules/hosted-git-info": { + "version": "2.8.9", + "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-2.8.9.tgz", + "integrity": "sha512-mxIDAb9Lsm6DoOJ7xH+5+X4y1LU/4Hi50L9C5sIswK3JzULS4bwk1FvjdBgvYR4bzT4tuUQiC15FE2f5HbLvYw==", + "license": "ISC" + }, + "node_modules/read-pkg/node_modules/normalize-package-data": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-2.5.0.tgz", + "integrity": "sha512-/5CMN3T0R4XTj4DcGaexo+roZSdSFW/0AOOTROrjxzCG1wrWXEsGbRKevjlIL+ZDE4sZlJr5ED4YW0yqmkK+eA==", + "license": "BSD-2-Clause", + "dependencies": { + "hosted-git-info": "^2.1.4", + "resolve": "^1.10.0", + "semver": "2 || 3 || 4 || 5", + "validate-npm-package-license": "^3.0.1" + } + }, + "node_modules/read-pkg/node_modules/semver": { + "version": "5.7.2", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.2.tgz", + "integrity": "sha512-cBznnQ9KjJqU67B52RMC65CMarK2600WFnbkcaiwWq3xy/5haFJlshgnpjovMVJ+Hff49d8GEn0b87C5pDQ10g==", + "license": "ISC", + "bin": { + "semver": "bin/semver" + } }, - "node_modules/react-is": { - "version": "18.2.0", - "resolved": "https://registry.npmjs.org/react-is/-/react-is-18.2.0.tgz", - "integrity": "sha512-xWGDIW6x921xtzPkhiULtthJHoJvBbF3q26fzloPCK0hsvxtPVelvftw3zjbHWSkR2km9Z+4uxbDDK/6Zw9B8w==", - "dev": true + "node_modules/read-pkg/node_modules/type-fest": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.6.0.tgz", + "integrity": "sha512-q+MB8nYR1KDLrgr4G5yemftpMC7/QLqVndBmEEdqzmNj5dcFOO4Oo8qlwZE3ULT3+Zim1F8Kq4cBnikNhlCMlg==", + "license": "(MIT OR CC0-1.0)", + "engines": { + "node": ">=8" + } }, "node_modules/readable-stream": { "version": "4.4.2", @@ -6549,6 +8591,18 @@ "node": "^12.22.0 || ^14.17.0 || >=16.0.0" } }, + "node_modules/readdirp": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz", + "integrity": "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==", + "license": "MIT", + "dependencies": { + "picomatch": "^2.2.1" + }, + "engines": { + "node": ">=8.10.0" + } + }, "node_modules/real-require": { "version": "0.2.0", "resolved": "https://registry.npmjs.org/real-require/-/real-require-0.2.0.tgz", @@ -6557,11 +8611,48 @@ "node": ">= 12.13.0" } }, + "node_modules/redent": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/redent/-/redent-3.0.0.tgz", + "integrity": "sha512-6tDA8g98We0zd0GvVeMT9arEOnTw9qM03L9cJXaCjrip1OO764RDBLBfrB4cwzNGDj5OA5ioymC9GkizgWJDUg==", + "license": "MIT", + "dependencies": { + "indent-string": "^4.0.0", + "strip-indent": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, "node_modules/regenerator-runtime": { "version": "0.14.1", "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.14.1.tgz", "integrity": "sha512-dYnhHh0nJoMfnkZs6GmmhFknAGRrLznOu5nc9ML+EJxGvrx6H7teuevqVqCuPcPK//3eDrrjQhehXVx9cnkGdw==" }, + "node_modules/registry-auth-token": { + "version": "4.2.2", + "resolved": "https://registry.npmjs.org/registry-auth-token/-/registry-auth-token-4.2.2.tgz", + "integrity": "sha512-PC5ZysNb42zpFME6D/XlIgtNGdTl8bBOCw90xQLVMpzuuubJKYDWFAEuUNc+Cn8Z8724tg2SDhDRrkVEsqfDMg==", + "license": "MIT", + "dependencies": { + "rc": "1.2.8" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/registry-url": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/registry-url/-/registry-url-5.1.0.tgz", + "integrity": "sha512-8acYXXTI0AkQv6RAOjE3vOaIXZkT9wo4LOFbBKYQEEnnMNBpKqdUrI6S4NT0KPIo/WVvJ5tE/X5LF/TQUf0ekw==", + "license": "MIT", + "dependencies": { + "rc": "^1.2.8" + }, + "engines": { + "node": ">=8" + } + }, "node_modules/reinterval": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/reinterval/-/reinterval-1.1.0.tgz", @@ -6571,7 +8662,6 @@ "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" } @@ -6584,11 +8674,16 @@ "node": ">=0.10.0" } }, + "node_modules/require-package-name": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/require-package-name/-/require-package-name-2.0.1.tgz", + "integrity": "sha512-uuoJ1hU/k6M0779t3VMVIYpb2VMJk05cehCaABFhXaibcbvfgR8wKiozLjVFSzJPmQMRqIcO0HMyTFqfV09V6Q==", + "license": "MIT" + }, "node_modules/resolve": { "version": "1.22.4", "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.4.tgz", "integrity": "sha512-PXNdCiPqDqeUou+w1C2eTQbNfxKSuMxqTCuvlmmMsk1NWHL5fRrhY6Pl0qEYYc6+QqGClco1Qj8XnjPego4wfg==", - "dev": true, "dependencies": { "is-core-module": "^2.13.0", "path-parse": "^1.0.7", @@ -6622,12 +8717,65 @@ "node": ">=8" } }, + "node_modules/resolve-dir": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/resolve-dir/-/resolve-dir-1.0.1.tgz", + "integrity": "sha512-R7uiTjECzvOsWSfdM0QKFNBVFcK27aHOUwdvK53BcW8zqnGdYp0Fbj82cy54+2A4P2tFM22J5kRfe1R+lM/1yg==", + "license": "MIT", + "dependencies": { + "expand-tilde": "^2.0.0", + "global-modules": "^1.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/resolve-dir/node_modules/global-modules": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/global-modules/-/global-modules-1.0.0.tgz", + "integrity": "sha512-sKzpEkf11GpOFuw0Zzjzmt4B4UZwjOcG757PPvrfhxcLFbq0wpsgpOqxpxtxFiCG4DtG93M6XRVbF2oGdev7bg==", + "license": "MIT", + "dependencies": { + "global-prefix": "^1.0.1", + "is-windows": "^1.0.1", + "resolve-dir": "^1.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/resolve-dir/node_modules/global-prefix": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/global-prefix/-/global-prefix-1.0.2.tgz", + "integrity": "sha512-5lsx1NUDHtSjfg0eHlmYvZKv8/nVqX4ckFbM+FrGcQ+04KWcWFo9P5MxPZYSzUvyzmdTbI7Eix8Q4IbELDqzKg==", + "license": "MIT", + "dependencies": { + "expand-tilde": "^2.0.2", + "homedir-polyfill": "^1.0.1", + "ini": "^1.3.4", + "is-windows": "^1.0.1", + "which": "^1.2.14" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/resolve-dir/node_modules/which": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/which/-/which-1.3.1.tgz", + "integrity": "sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ==", + "license": "ISC", + "dependencies": { + "isexe": "^2.0.0" + }, + "bin": { + "which": "bin/which" + } + }, "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, - "peer": true, "engines": { "node": ">=4" } @@ -6641,6 +8789,28 @@ "node": ">=10" } }, + "node_modules/responselike": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/responselike/-/responselike-1.0.2.tgz", + "integrity": "sha512-/Fpe5guzJk1gPqdJLJR5u7eG/gNY4nImjbRDaVWVMRhne55TCmj2i9Q+54PBRfatRC8v/rIiv9BN0pMd9OV5EQ==", + "license": "MIT", + "dependencies": { + "lowercase-keys": "^1.0.0" + } + }, + "node_modules/restore-cursor": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/restore-cursor/-/restore-cursor-3.1.0.tgz", + "integrity": "sha512-l+sSefzHpj5qimhFSE5a8nufZYAM3sBSVMAPtYkmC+4EH2anSGaEMXSD0izRQbu9nfyQ9y5JrVmp7E8oZrUjvA==", + "license": "MIT", + "dependencies": { + "onetime": "^5.1.0", + "signal-exit": "^3.0.2" + }, + "engines": { + "node": ">=8" + } + }, "node_modules/ret": { "version": "0.4.3", "resolved": "https://registry.npmjs.org/ret/-/ret-0.4.3.tgz", @@ -6697,11 +8867,19 @@ "node": ">=8.0" } }, + "node_modules/run-async": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/run-async/-/run-async-2.4.1.tgz", + "integrity": "sha512-tvVnVv01b8c1RrA6Ep7JkStj85Guv/YrMcwqYQnwjsAS2cTmmPGBBjAjpCW7RrSodNSoE2/qg9O4bceNvUuDgQ==", + "license": "MIT", + "engines": { + "node": ">=0.12.0" + } + }, "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", @@ -6716,7 +8894,6 @@ "url": "https://feross.org/support" } ], - "peer": true, "dependencies": { "queue-microtask": "^1.2.2" } @@ -6726,6 +8903,24 @@ "resolved": "https://registry.npmjs.org/rusha/-/rusha-0.8.14.tgz", "integrity": "sha512-cLgakCUf6PedEu15t8kbsjnwIFFR2D4RfL+W3iWFJ4iac7z4B0ZI8fxy4R3J956kAI68HclCFGL8MPoUVC3qVA==" }, + "node_modules/rxjs": { + "version": "6.6.7", + "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-6.6.7.tgz", + "integrity": "sha512-hTdwr+7yYNIT5n4AMYp85KA6yw2Va0FLa3Rguvbpa4W3I5xynaBZo41cM3XM+4Q6fRMj3sBYIR1VAmZMXYJvRQ==", + "license": "Apache-2.0", + "dependencies": { + "tslib": "^1.9.0" + }, + "engines": { + "npm": ">=2.0.0" + } + }, + "node_modules/rxjs/node_modules/tslib": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", + "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==", + "license": "0BSD" + }, "node_modules/safe-buffer": { "version": "5.2.1", "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", @@ -6762,6 +8957,12 @@ "node": ">=10" } }, + "node_modules/safer-buffer": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", + "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==", + "license": "MIT" + }, "node_modules/secure-json-parse": { "version": "2.7.0", "resolved": "https://registry.npmjs.org/secure-json-parse/-/secure-json-parse-2.7.0.tgz", @@ -6771,7 +8972,6 @@ "version": "6.3.1", "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", - "dev": true, "bin": { "semver": "bin/semver.js" } @@ -6779,8 +8979,19 @@ "node_modules/semver-compare": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/semver-compare/-/semver-compare-1.0.0.tgz", - "integrity": "sha512-YM3/ITh2MJ5MtzaM429anh+x2jiLVjqILF4m4oyQB18W7Ggea7BfqdH/wGMK7dDiMghv/6WG7znWMwUDzJiXow==", - "dev": true + "integrity": "sha512-YM3/ITh2MJ5MtzaM429anh+x2jiLVjqILF4m4oyQB18W7Ggea7BfqdH/wGMK7dDiMghv/6WG7znWMwUDzJiXow==" + }, + "node_modules/semver-diff": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/semver-diff/-/semver-diff-3.1.1.tgz", + "integrity": "sha512-GX0Ix/CJcHyB8c4ykpHGIAvLyOwOobtM/8d+TQkAd81/bEjgPHrfba41Vpesr7jX/t8Uh+R3EX9eAS5be+jQYg==", + "license": "MIT", + "dependencies": { + "semver": "^6.3.0" + }, + "engines": { + "node": ">=8" + } }, "node_modules/serialize-error": { "version": "7.0.1", @@ -6846,8 +9057,7 @@ "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 + "integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==" }, "node_modules/simple-swizzle": { "version": "0.2.2", @@ -6872,7 +9082,6 @@ "version": "3.0.0", "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz", "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==", - "dev": true, "engines": { "node": ">=8" } @@ -6911,6 +9120,15 @@ "node": ">=0.10.0" } }, + "node_modules/source-map-js": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.1.tgz", + "integrity": "sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==", + "license": "BSD-3-Clause", + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/source-map-support": { "version": "0.5.13", "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.13.tgz", @@ -6921,6 +9139,38 @@ "source-map": "^0.6.0" } }, + "node_modules/spdx-correct": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/spdx-correct/-/spdx-correct-3.2.0.tgz", + "integrity": "sha512-kN9dJbvnySHULIluDHy32WHRUu3Og7B9sbY7tsFLctQkIqnMh3hErYgdMjTYuqmcXX+lK5T1lnUt3G7zNswmZA==", + "license": "Apache-2.0", + "dependencies": { + "spdx-expression-parse": "^3.0.0", + "spdx-license-ids": "^3.0.0" + } + }, + "node_modules/spdx-exceptions": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/spdx-exceptions/-/spdx-exceptions-2.5.0.tgz", + "integrity": "sha512-PiU42r+xO4UbUS1buo3LPJkjlO7430Xn5SVAhdpzzsPHsjbYVflnnFdATgabnLude+Cqu25p6N+g2lw/PFsa4w==", + "license": "CC-BY-3.0" + }, + "node_modules/spdx-expression-parse": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/spdx-expression-parse/-/spdx-expression-parse-3.0.1.tgz", + "integrity": "sha512-cbqHunsQWnJNE6KhVSMsMeH5H/L9EpymbzqTQ3uLwNCLZ1Q481oWaofqH7nO6V07xlXwY6PhQdQ2IedWx/ZK4Q==", + "license": "MIT", + "dependencies": { + "spdx-exceptions": "^2.1.0", + "spdx-license-ids": "^3.0.0" + } + }, + "node_modules/spdx-license-ids": { + "version": "3.0.20", + "resolved": "https://registry.npmjs.org/spdx-license-ids/-/spdx-license-ids-3.0.20.tgz", + "integrity": "sha512-jg25NiDV/1fLtSgEgyvVyDunvaNHbuwF9lfNV17gSmPFAlYzdfNBlLtLzXTevwkPj7DhGbmN9VnmJIgLnhvaBw==", + "license": "CC0-1.0" + }, "node_modules/split2": { "version": "4.2.0", "resolved": "https://registry.npmjs.org/split2/-/split2-4.2.0.tgz", @@ -6964,6 +9214,12 @@ "node": ">=8" } }, + "node_modules/stackframe": { + "version": "1.3.4", + "resolved": "https://registry.npmjs.org/stackframe/-/stackframe-1.3.4.tgz", + "integrity": "sha512-oeVtt7eWQS+Na6F//S4kJ2K2VbRlS9D43mAlMyVpVWovy9o+jfgH8O9agzANzaiLjclA0oYzUXEM4PurhSUChw==", + "license": "MIT" + }, "node_modules/statuses": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.1.tgz", @@ -7056,11 +9312,22 @@ "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-indent": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/strip-indent/-/strip-indent-3.0.0.tgz", + "integrity": "sha512-laJTa3Jb+VQpaC6DseHhF7dXVqHTfJPCRDaEbid/drOhgitgYku/letMUqOXFoWV0zIIUbjpdH2t+tYj4bQMRQ==", + "license": "MIT", + "dependencies": { + "min-indent": "^1.0.0" + }, + "engines": { + "node": ">=8" + } + }, "node_modules/strip-json-comments": { "version": "3.1.1", "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz", @@ -7077,7 +9344,6 @@ "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" }, @@ -7089,7 +9355,6 @@ "version": "1.0.0", "resolved": "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz", "integrity": "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==", - "dev": true, "engines": { "node": ">= 0.4" }, @@ -7161,9 +9426,7 @@ "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, - "peer": true + "integrity": "sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw==" }, "node_modules/thread-stream": { "version": "2.7.0", @@ -7173,6 +9436,30 @@ "real-require": "^0.2.0" } }, + "node_modules/throat": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/throat/-/throat-6.0.2.tgz", + "integrity": "sha512-WKexMoJj3vEuK0yFEapj8y64V0A6xcuPuK9Gt1d0R+dzCSJc0lHqQytAbSB4cDAK0dWh4T0E2ETkoLE2WZ41OQ==", + "license": "MIT" + }, + "node_modules/through": { + "version": "2.3.8", + "resolved": "https://registry.npmjs.org/through/-/through-2.3.8.tgz", + "integrity": "sha512-w89qg7PI8wAdvX60bMDP+bFoD5Dvhm9oLheFp5O4a2QF0cSBGsBX4qZmadPMvVqlLJBBci+WqGGOAPvcDeNSVg==", + "license": "MIT" + }, + "node_modules/tmp": { + "version": "0.0.33", + "resolved": "https://registry.npmjs.org/tmp/-/tmp-0.0.33.tgz", + "integrity": "sha512-jRCJlojKnZ3addtTOjdIqoRuPEKBvNXcGYqzO6zWZX8KfKEpnGY5jfggJQ3EjKuu8D4bJRr0y+cYJFmYbImXGw==", + "license": "MIT", + "dependencies": { + "os-tmpdir": "~1.0.2" + }, + "engines": { + "node": ">=0.6.0" + } + }, "node_modules/tmpl": { "version": "1.0.5", "resolved": "https://registry.npmjs.org/tmpl/-/tmpl-1.0.5.tgz", @@ -7183,16 +9470,23 @@ "version": "2.0.0", "resolved": "https://registry.npmjs.org/to-fast-properties/-/to-fast-properties-2.0.0.tgz", "integrity": "sha512-/OaKK0xYrs3DmxRYqL/yDc+FxFUVYhDlXMhRmv3z915w2HF1tnN1omB354j8VUGO/hbRzyD6Y3sA7v7GS/ceog==", - "dev": true, "engines": { "node": ">=4" } }, + "node_modules/to-readable-stream": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/to-readable-stream/-/to-readable-stream-1.0.0.tgz", + "integrity": "sha512-Iq25XBt6zD5npPhlLVXGFN3/gyR2/qODcKNNyTMd4vbm39HUaOiAM4PMq0eMVC/Tkxz+Zjdsc55g9yyz+Yq00Q==", + "license": "MIT", + "engines": { + "node": ">=6" + } + }, "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, "license": "MIT", "dependencies": { "is-number": "^7.0.0" @@ -7217,6 +9511,15 @@ "node": ">=0.6" } }, + "node_modules/trim-newlines": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/trim-newlines/-/trim-newlines-3.0.1.tgz", + "integrity": "sha512-c1PTsA3tYrIsLGkJkzHF+w9F2EyxfXGo4UyJc4pFL++FMjnq0HJS69T3M7d//gKrFKwy429bouPescbjecU+Zw==", + "license": "MIT", + "engines": { + "node": ">=8" + } + }, "node_modules/triple-beam": { "version": "1.4.1", "resolved": "https://registry.npmjs.org/triple-beam/-/triple-beam-1.4.1.tgz", @@ -7256,8 +9559,6 @@ "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, - "peer": true, "engines": { "node": ">=10" }, @@ -7282,6 +9583,15 @@ "resolved": "https://registry.npmjs.org/typedarray/-/typedarray-0.0.6.tgz", "integrity": "sha512-/aCDEGatGvZ2BIk+HmLf4ifCJFwvKFNb9/JeZPMulfgFracn9QFcAf5GO8B/mweUjSoblS5In0cWhqpfs/5PQA==" }, + "node_modules/typedarray-to-buffer": { + "version": "3.1.5", + "resolved": "https://registry.npmjs.org/typedarray-to-buffer/-/typedarray-to-buffer-3.1.5.tgz", + "integrity": "sha512-zdu8XMNEDepKKR+XYOXAVPtWui0ly0NtohUscw+UmaHiAWT8hrV1rr//H6V+0DvJ3OQ19S979M0laLfX8rm82Q==", + "license": "MIT", + "dependencies": { + "is-typedarray": "^1.0.0" + } + }, "node_modules/uglify-js": { "version": "3.17.4", "resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-3.17.4.tgz", @@ -7313,6 +9623,18 @@ "node": ">=14.0" } }, + "node_modules/unique-string": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/unique-string/-/unique-string-2.0.0.tgz", + "integrity": "sha512-uNaeirEPvpZWSgzwsPGtU2zVSTrn/8L5q/IexZmH0eH6SA73CmAA5U4GwORTxQAZs95TAXLNqeLoPPNO5gZfWg==", + "license": "MIT", + "dependencies": { + "crypto-random-string": "^2.0.0" + }, + "engines": { + "node": ">=8" + } + }, "node_modules/universalify": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/universalify/-/universalify-2.0.0.tgz", @@ -7360,6 +9682,46 @@ "browserslist": ">= 4.21.0" } }, + "node_modules/update-notifier": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/update-notifier/-/update-notifier-5.1.0.tgz", + "integrity": "sha512-ItnICHbeMh9GqUy31hFPrD1kcuZ3rpxDZbf4KUDavXwS0bW5m7SLbDQpGX3UYr072cbrF5hFUs3r5tUsPwjfHw==", + "license": "BSD-2-Clause", + "dependencies": { + "boxen": "^5.0.0", + "chalk": "^4.1.0", + "configstore": "^5.0.1", + "has-yarn": "^2.1.0", + "import-lazy": "^2.1.0", + "is-ci": "^2.0.0", + "is-installed-globally": "^0.4.0", + "is-npm": "^5.0.0", + "is-yarn-global": "^0.3.0", + "latest-version": "^5.1.0", + "pupa": "^2.1.1", + "semver": "^7.3.4", + "semver-diff": "^3.1.1", + "xdg-basedir": "^4.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/yeoman/update-notifier?sponsor=1" + } + }, + "node_modules/update-notifier/node_modules/semver": { + "version": "7.6.3", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.6.3.tgz", + "integrity": "sha512-oVekP1cKtI+CTDvHWYFUcMtsK/00wmAEfyqKfNdARm8u1wNVhSgaX7A8d4UuIlUI5e84iEwOhs7ZPYRmzU9U6A==", + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, "node_modules/uri-js": { "version": "4.4.1", "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz", @@ -7368,6 +9730,18 @@ "punycode": "^2.1.0" } }, + "node_modules/url-parse-lax": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/url-parse-lax/-/url-parse-lax-3.0.0.tgz", + "integrity": "sha512-NjFKA0DidqPa5ciFcSrXnAltTtzz84ogy+NebPvfEgAck0+TNg4UJ4IN+fB7zRZfbgUf0syOo9MDxFkDSMuFaQ==", + "license": "MIT", + "dependencies": { + "prepend-http": "^2.0.0" + }, + "engines": { + "node": ">=4" + } + }, "node_modules/util-deprecate": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", @@ -7400,6 +9774,16 @@ "node": ">=10.12.0" } }, + "node_modules/validate-npm-package-license": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/validate-npm-package-license/-/validate-npm-package-license-3.0.4.tgz", + "integrity": "sha512-DpKm2Ui/xN7/HQKCtpZxoRWBhZ9Z0kqtygG8XCgNQ8ZlDnxuQmWhj566j8fN4Cu3/JmbhsDo7fcAJq4s9h27Ew==", + "license": "Apache-2.0", + "dependencies": { + "spdx-correct": "^3.0.0", + "spdx-expression-parse": "^3.0.0" + } + }, "node_modules/vary": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz", @@ -7417,6 +9801,15 @@ "makeerror": "1.0.12" } }, + "node_modules/wcwidth": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/wcwidth/-/wcwidth-1.0.1.tgz", + "integrity": "sha512-XHPEwS0q6TaxcvG85+8EYkbiCux2XtWG2mkc47Ng2A77BQu9+DqIOJldST4HgPkuea7dvKSj5VgX3P1d4rW8Tg==", + "license": "MIT", + "dependencies": { + "defaults": "^1.0.3" + } + }, "node_modules/which": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", @@ -7431,6 +9824,31 @@ "node": ">= 8" } }, + "node_modules/which-pm": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/which-pm/-/which-pm-2.2.0.tgz", + "integrity": "sha512-MOiaDbA5ZZgUjkeMWM5EkJp4loW5ZRoa5bc3/aeMox/PJelMhE6t7S/mLuiY43DBupyxH+S0U1bTui9kWUlmsw==", + "license": "MIT", + "dependencies": { + "load-yaml-file": "^0.2.0", + "path-exists": "^4.0.0" + }, + "engines": { + "node": ">=8.15" + } + }, + "node_modules/widest-line": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/widest-line/-/widest-line-3.1.0.tgz", + "integrity": "sha512-NsmoXalsWVDMGupxZ5R08ka9flZjjiLvHVAWYOKtiKM8ujtZWr9cRffak+uSE48+Ob8ObalXpwyeUiyDD6QFgg==", + "license": "MIT", + "dependencies": { + "string-width": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, "node_modules/winston": { "version": "3.15.0", "resolved": "https://registry.npmjs.org/winston/-/winston-3.15.0.tgz", @@ -7549,7 +9967,6 @@ "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", @@ -7618,6 +10035,15 @@ } } }, + "node_modules/xdg-basedir": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/xdg-basedir/-/xdg-basedir-4.0.0.tgz", + "integrity": "sha512-PSNhEJDejZYV7h50BohL09Er9VaIefr2LMAf3OEmpCkjOi34eYyQYAXUTjEQtZJTKcF0E2UKTh+osDLsgNim9Q==", + "license": "MIT", + "engines": { + "node": ">=8" + } + }, "node_modules/xstate": { "version": "5.18.2", "resolved": "https://registry.npmjs.org/xstate/-/xstate-5.18.2.tgz", @@ -7628,11 +10054,19 @@ "url": "https://opencollective.com/xstate" } }, + "node_modules/xtend": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.2.tgz", + "integrity": "sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ==", + "license": "MIT", + "engines": { + "node": ">=0.4" + } + }, "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" } @@ -7682,7 +10116,6 @@ "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" }, diff --git a/package.json b/package.json index 4e6a60b1..d6667b39 100644 --- a/package.json +++ b/package.json @@ -58,7 +58,7 @@ "@fastify/swagger": "^8.15.0", "@fastify/swagger-ui": "^4.1.0", "@keyvhq/core": "^2.1.1", - "@xstate/fsm": "^2.0.1", + "@xstate/fsm": "^2.1.0", "ajv": "^8.17.1", "ajv-keywords": "^5.1.0", "any-base": "^1.1.0", @@ -73,7 +73,7 @@ "fastify-healthcheck": "^4.4.0", "fastify-plugin": "^4.5.0", "fs-extra": "^11.2.0", - "handlebars": "^4.7.7", + "handlebars": "^4.7.8", "http-errors": "^2.0.0", "i": "^0.3.7", "influx": "^5.9.3", @@ -89,11 +89,12 @@ "ms-teams-wrapper": "^1.0.2", "nodemailer": "^6.9.15", "nodemailer-express-handlebars": "^6.1.2", + "npm-check": "^6.0.1", "os": "^0.1.2", - "posthog-node": "^4.2.0", + "posthog-node": "^4.2.1", "promise": "^8.3.0", "qrs-interact": "^6.3.1", - "rate-limiter-flexible": "^5.0.3", + "rate-limiter-flexible": "^5.0.4", "serializeapp": "^3.0.0", "systeminformation": "^5.23.5", "upath": "^2.0.1", @@ -104,9 +105,9 @@ "xstate": "^5.18.2" }, "devDependencies": { - "@babel/eslint-parser": "^7.25.7", + "@babel/eslint-parser": "^7.25.8", "@babel/plugin-syntax-import-assertions": "^7.25.7", - "@eslint/js": "^9.12.0", + "@eslint/js": "^9.13.0", "esbuild": "^0.24.0", "eslint-config-prettier": "^9.1.0", "eslint-plugin-prettier": "^5.2.1", diff --git a/release-please-config.json b/release-please-config.json index 41f2c760..0c7514f5 100644 --- a/release-please-config.json +++ b/release-please-config.json @@ -1,6 +1,4 @@ { - "release-as": "13.0.0", - "last-release-sha": "d50886dbdca6778c3323d5e59a1107b2e141412f", "release-type": "node", "prerelease": false, "draft": true, diff --git a/src/config/email_templates/aborted-reload-qseow.handlebars b/src/config/email_templates/aborted-reload-qseow.handlebars index a043c6e8..e34eab66 100644 --- a/src/config/email_templates/aborted-reload-qseow.handlebars +++ b/src/config/email_templates/aborted-reload-qseow.handlebars @@ -186,7 +186,8 @@ - The script log contains {{scriptLogSize}} rows in total. Here are the first ones: + The script log contains {{scriptLogSizeRows}} rows in total, with {{scriptLogSizeCharacters}} characters in them.
+ Here are the first {{scriptLogHeadCount}} rows: diff --git a/src/config/email_templates/failed-reload-qscloud.handlebars b/src/config/email_templates/failed-reload-qscloud.handlebars index d80a2e5b..3035a261 100644 --- a/src/config/email_templates/failed-reload-qscloud.handlebars +++ b/src/config/email_templates/failed-reload-qscloud.handlebars @@ -152,7 +152,8 @@ - The script log contains {{scriptLogSize}} rows in total. Here are the first ones: + The script log contains {{scriptLogSizeRows}} rows in total, with {{scriptLogSizeCharacters}} characters in them.
+ Here are the first {{scriptLogHeadCount}} rows: diff --git a/src/config/email_templates/failed-reload-qseow.handlebars b/src/config/email_templates/failed-reload-qseow.handlebars index 9aa4098e..6e502c29 100644 --- a/src/config/email_templates/failed-reload-qseow.handlebars +++ b/src/config/email_templates/failed-reload-qseow.handlebars @@ -186,7 +186,8 @@ - The script log contains {{scriptLogSize}} rows in total. Here are the first ones: + The script log contains {{scriptLogSizeRows}} rows in total, with {{scriptLogSizeCharacters}} characters in them.
+ Here are the first {{scriptLogHeadCount}} rows: diff --git a/src/config/slack_templates/failed-reload-qscloud.handlebars b/src/config/slack_templates/failed-reload-qscloud.handlebars index 4964c7e4..9c4158a6 100644 --- a/src/config/slack_templates/failed-reload-qscloud.handlebars +++ b/src/config/slack_templates/failed-reload-qscloud.handlebars @@ -157,7 +157,7 @@ "type": "section", "text": { "type": "mrkdwn", - "text": "The script log contains {{scriptLogSize}} rows in total. Here are the first ones:" + "text": "The script log contains {{scriptLogSizeRows}} rows in total, with {{scriptLogSizeCharacters}} characters in them. Here are the first {{scriptLogHeadCount}} rows:" } }, { diff --git a/src/config/slack_templates/failed-reload-qseow.handlebars b/src/config/slack_templates/failed-reload-qseow.handlebars index 48d9fd08..482012c6 100644 --- a/src/config/slack_templates/failed-reload-qseow.handlebars +++ b/src/config/slack_templates/failed-reload-qseow.handlebars @@ -149,7 +149,7 @@ "type": "section", "text": { "type": "mrkdwn", - "text": "The script log contains {{scriptLogSize}} characters in total. Here are the first lines:" + "text": "The script log contains {{scriptLogSizeRows}} rows in total, with {{scriptLogSizeCharacters}} characters in them. Here are the first {{scriptLogHeadCount}} rows:" } }, { @@ -163,7 +163,7 @@ "type": "section", "text": { "type": "mrkdwn", - "text": "Here are the last few lines:" + "text": "Here are the last {{scriptLogTailCount}} rows:" } }, { diff --git a/src/config/teams_templates/failed-reload-qscloud.handlebars b/src/config/teams_templates/failed-reload-qscloud.handlebars index 16859e8b..53bd1263 100644 --- a/src/config/teams_templates/failed-reload-qscloud.handlebars +++ b/src/config/teams_templates/failed-reload-qscloud.handlebars @@ -194,6 +194,31 @@ } ] }, + { + "type": "Container", + "spacing": "extraLarge", + "style": "emphasis", + "items": [ + { + "type": "TextBlock", + "size": "large", + "weight": "bolder", + "text": "Beginning of script log", + "style": "heading" + }, + { + "type": "TextBlock", + "size": "small", + "weight": "normal", + "text": "The script log contains {{scriptLogSizeRows}} rows in total, with {{scriptLogSizeCharacters}} characters in them. Here are the first {{scriptLogHeadCount}} rows:", + "style": "heading" + }, + { + "type": "CodeBlock", + "codeSnippet": "{{scriptLogHead}}" + } + ] + }, { "type": "Container", "spacing": "extraLarge", @@ -210,7 +235,7 @@ "type": "TextBlock", "size": "small", "weight": "normal", - "text": "Last {{scriptLogTailCount}} rows shown. The script log contains {{scriptLogSize}} rows in total.", + "text": "Here are the last {{scriptLogTailCount}} rows:", "style": "heading" }, { diff --git a/src/config/teams_templates/failed-reload-qseow.handlebars b/src/config/teams_templates/failed-reload-qseow.handlebars index 2ff1912d..fdc06d46 100644 --- a/src/config/teams_templates/failed-reload-qseow.handlebars +++ b/src/config/teams_templates/failed-reload-qseow.handlebars @@ -190,6 +190,31 @@ } ] }, + { + "type": "Container", + "spacing": "extraLarge", + "style": "emphasis", + "items": [ + { + "type": "TextBlock", + "size": "large", + "weight": "bolder", + "text": "Beginning of script log", + "style": "heading" + }, + { + "type": "TextBlock", + "size": "small", + "weight": "normal", + "text": "The script log contains {{scriptLogSizeRows}} rows in total, with {{scriptLogSizeCharacters}} characters in them. Here are the first {{scriptLogHeadCount}} rows:", + "style": "heading" + }, + { + "type": "CodeBlock", + "codeSnippet": "{{scriptLogHead}}" + } + ] + }, { "type": "Container", "spacing": "extraLarge", @@ -206,7 +231,7 @@ "type": "TextBlock", "size": "small", "weight": "normal", - "text": "Last {{scriptLogTailCount}} rows shown. The script log contains {{scriptLogSize}} rows in total.", + "text": "Here are the last {{scriptLogTailCount}} rows:", "style": "heading" }, { diff --git a/src/lib/incident_mgmt/new_relic.js b/src/lib/incident_mgmt/new_relic.js index f063b574..74480882 100644 --- a/src/lib/incident_mgmt/new_relic.js +++ b/src/lib/incident_mgmt/new_relic.js @@ -605,9 +605,9 @@ export async function sendReloadTaskFailureEvent(reloadParams) { .then(async (rateLimiterRes) => { try { globals.logger.info( - `TASK FAILED NEWRELIC: Rate limiting check passed for failed task event. Task name: "${params.qs_taskName}"`, + `[QSEOW] TASK FAILED NEWRELIC: Rate limiting check passed for failed task event. Task name: "${params.qs_taskName}"`, ); - globals.logger.verbose(`TASK FAILED NEWRELIC: Rate limiting details "${JSON.stringify(rateLimiterRes, null, 2)}"`); + globals.logger.verbose(`[QSEOW] TASK FAILED NEWRELIC: Rate limiting details "${JSON.stringify(rateLimiterRes, null, 2)}"`); // Get config and needed metadata const incidentConfig = getReloadFailedEventConfig(); @@ -716,16 +716,16 @@ export async function sendReloadTaskFailureEvent(reloadParams) { return null; } catch (err) { if (err.message) { - globals.logger.error(`TASK FAILED NEW RELIC 1 message: ${err.message}`); + globals.logger.error(`[QSEOW] TASK FAILED NEW RELIC 1 message: ${err.message}`); } if (err.stack) { - globals.logger.error(`TASK FAILED NEW RELIC 1 stack: ${err.stack}`); + globals.logger.error(`[QSEOW] TASK FAILED NEW RELIC 1 stack: ${err.stack}`); } // If neither message nor stack is available, just log the error object if (!err.message && !err.stack) { - globals.logger.error(`TASK FAILED NEW RELIC 1: ${JSON.stringify(err, null, 2)}`); + globals.logger.error(`[QSEOW] TASK FAILED NEW RELIC 1: ${JSON.stringify(err, null, 2)}`); } return null; @@ -733,9 +733,9 @@ export async function sendReloadTaskFailureEvent(reloadParams) { }) .catch((rateLimiterRes) => { globals.logger.verbose( - `TASK FAILED NEWRELIC: Rate limiting failed. Not sending reload failure event to New Relic for task "${params.qs_taskName}"`, + `[QSEOW] TASK FAILED NEWRELIC: Rate limiting failed. Not sending reload failure event to New Relic for task "${params.qs_taskName}"`, ); - globals.logger.verbose(`TASK FAILED NEWRELIC: Rate limiting details "${JSON.stringify(rateLimiterRes, null, 2)}"`); + globals.logger.verbose(`[QSEOW] TASK FAILED NEWRELIC: Rate limiting details "${JSON.stringify(rateLimiterRes, null, 2)}"`); }); } @@ -747,9 +747,9 @@ export async function sendReloadTaskFailureLog(reloadParams) { .then(async (rateLimiterRes) => { try { globals.logger.info( - `TASK FAILED NEWRELIC: Rate limiting check passed for failed task log entry. Task name: "${params.qs_taskName}"`, + `[QSEOW] TASK FAILED NEWRELIC: Rate limiting check passed for failed task log entry. Task name: "${params.qs_taskName}"`, ); - globals.logger.verbose(`TASK FAILED NEWRELIC: Rate limiting details "${JSON.stringify(rateLimiterRes, null, 2)}"`); + globals.logger.verbose(`[QSEOW] TASK FAILED NEWRELIC: Rate limiting details "${JSON.stringify(rateLimiterRes, null, 2)}"`); // Get config and needed metadata const incidentConfig = getReloadFailedLogConfig(); @@ -832,7 +832,7 @@ export async function sendReloadTaskFailureLog(reloadParams) { } } } catch (err) { - globals.logger.error(`SCRIPTLOG: ${err}`); + globals.logger.error(`[QSEOW] Get value of reload task custom property: ${err}`); } } @@ -856,16 +856,16 @@ export async function sendReloadTaskFailureLog(reloadParams) { return null; } catch (err) { if (err.message) { - globals.logger.error(`TASK FAILED NEW RELIC 2 message: ${err.message}`); + globals.logger.error(`[QSEOW] TASK FAILED NEW RELIC 2 message: ${err.message}`); } if (err.stack) { - globals.logger.error(`TASK FAILED NEW RELIC 2 stack: ${err.stack}`); + globals.logger.error(`[QSEOW] TASK FAILED NEW RELIC 2 stack: ${err.stack}`); } // If neither message nor stack is available, just log the error object if (!err.message && !err.stack) { - globals.logger.error(`TASK FAILED NEW RELIC 2: ${JSON.stringify(err, null, 2)}`); + globals.logger.error(`[QSEOW] TASK FAILED NEW RELIC 2: ${JSON.stringify(err, null, 2)}`); } return null; @@ -873,9 +873,9 @@ export async function sendReloadTaskFailureLog(reloadParams) { }) .catch((rateLimiterRes) => { globals.logger.verbose( - `TASK FAILED NEWRELIC: Rate limiting failed. Not sending reload failure log entry to New Relic for task "${params.qs_taskName}"`, + `[QSEOW] TASK FAILED NEWRELIC: Rate limiting failed. Not sending reload failure log entry to New Relic for task "${params.qs_taskName}"`, ); - globals.logger.verbose(`TASK FAILED NEWRELIC: Rate limiting details "${JSON.stringify(rateLimiterRes, null, 2)}"`); + globals.logger.verbose(`[QSEOW] TASK FAILED NEWRELIC: Rate limiting details "${JSON.stringify(rateLimiterRes, null, 2)}"`); }); } @@ -887,9 +887,9 @@ export function sendReloadTaskAbortedEvent(reloadParams) { .then(async (rateLimiterRes) => { try { globals.logger.info( - `TASK ABORT NEWRELIC: Rate limiting check passed for abort task event. Task name: "${params.qs_taskName}"`, + `[QSEOW] TASK ABORT NEWRELIC: Rate limiting check passed for abort task event. Task name: "${params.qs_taskName}"`, ); - globals.logger.verbose(`TASK ABORT NEWRELIC: Rate limiting details "${JSON.stringify(rateLimiterRes, null, 2)}"`); + globals.logger.verbose(`[QSEOW] TASK ABORT NEWRELIC: Rate limiting details "${JSON.stringify(rateLimiterRes, null, 2)}"`); // Get config and needed metadata const incidentConfig = getReloadAbortedEventConfig(); @@ -974,7 +974,7 @@ export function sendReloadTaskAbortedEvent(reloadParams) { } } } catch (err) { - globals.logger.error(`SCRIPTLOG: ${err}`); + globals.logger.error(`[QSEOW] Get custom property for reload task: ${err}`); } } @@ -998,16 +998,16 @@ export function sendReloadTaskAbortedEvent(reloadParams) { return null; } catch (err) { if (err.message) { - globals.logger.error(`TASK ABORT NEW RELIC 1 message: ${err.message}`); + globals.logger.error(`[QSEOW] TASK ABORT NEW RELIC 1 message: ${err.message}`); } if (err.stack) { - globals.logger.error(`TASK ABORT NEW RELIC 1 stack: ${err.stack}`); + globals.logger.error(`[QSEOW] TASK ABORT NEW RELIC 1 stack: ${err.stack}`); } // If neither message nor stack is available, just log the error object if (!err.message && !err.stack) { - globals.logger.error(`TASK ABORT NEW RELIC 1: ${JSON.stringify(err, null, 2)}`); + globals.logger.error(`[QSEOW] TASK ABORT NEW RELIC 1: ${JSON.stringify(err, null, 2)}`); } return null; @@ -1015,9 +1015,9 @@ export function sendReloadTaskAbortedEvent(reloadParams) { }) .catch((rateLimiterRes) => { globals.logger.verbose( - `TASK ABORT NEWRELIC: Rate limiting failed. Not sending reload aborted event to New Relic for task "${params.qs_taskName}"`, + `[QSEOW] TASK ABORT NEWRELIC: Rate limiting failed. Not sending reload aborted event to New Relic for task "${params.qs_taskName}"`, ); - globals.logger.verbose(`TASK ABORT NEWRELIC: Rate limiting details "${JSON.stringify(rateLimiterRes, null, 2)}"`); + globals.logger.verbose(`[QSEOW] TASK ABORT NEWRELIC: Rate limiting details "${JSON.stringify(rateLimiterRes, null, 2)}"`); }); } @@ -1029,9 +1029,9 @@ export function sendReloadTaskAbortedLog(reloadParams) { .then(async (rateLimiterRes) => { try { globals.logger.info( - `TASK ABORT NEWRELIC: Rate limiting check passed for abort task log entry. Task name: "${params.qs_taskName}"`, + `[QSEOW] TASK ABORT NEWRELIC: Rate limiting check passed for abort task log entry. Task name: "${params.qs_taskName}"`, ); - globals.logger.verbose(`TASK ABORT NEWRELIC: Rate limiting details "${JSON.stringify(rateLimiterRes, null, 2)}"`); + globals.logger.verbose(`[QSEOW] TASK ABORT NEWRELIC: Rate limiting details "${JSON.stringify(rateLimiterRes, null, 2)}"`); // Get config and needed metadata const incidentConfig = getReloadAbortedLogConfig(); @@ -1116,7 +1116,7 @@ export function sendReloadTaskAbortedLog(reloadParams) { } } } catch (err) { - globals.logger.error(`SCRIPTLOG: ${err}`); + globals.logger.error(`[QSEOW] Get custom property for reload task: ${err}`); } } @@ -1140,16 +1140,16 @@ export function sendReloadTaskAbortedLog(reloadParams) { return null; } catch (err) { if (err.message) { - globals.logger.error(`TASK ABORT NEW RELIC 2 message: ${err.message}`); + globals.logger.error(`[QSEOW] TASK ABORT NEW RELIC 2 message: ${err.message}`); } if (err.stack) { - globals.logger.error(`TASK ABORT NEW RELIC 2 stack: ${err.stack}`); + globals.logger.error(`[QSEOW] TASK ABORT NEW RELIC 2 stack: ${err.stack}`); } // If neither message nor stack is available, just log the error object if (!err.message && !err.stack) { - globals.logger.error(`TASK ABORT NEW RELIC 2: ${JSON.stringify(err, null, 2)}`); + globals.logger.error(`[QSEOW] TASK ABORT NEW RELIC 2: ${JSON.stringify(err, null, 2)}`); } return null; @@ -1157,8 +1157,8 @@ export function sendReloadTaskAbortedLog(reloadParams) { }) .catch((rateLimiterRes) => { globals.logger.verbose( - `TASK ABORT NEWRELIC: Rate limiting failed. Not sending reload abort log entry to New Relic for task "${params.qs_taskName}"`, + `[QSEOW] TASK ABORT NEWRELIC: Rate limiting failed. Not sending reload abort log entry to New Relic for task "${params.qs_taskName}"`, ); - globals.logger.verbose(`TASK ABORT NEWRELIC: Rate limiting details "${JSON.stringify(rateLimiterRes, null, 2)}"`); + globals.logger.verbose(`[QSEOW] TASK ABORT NEWRELIC: Rate limiting details "${JSON.stringify(rateLimiterRes, null, 2)}"`); }); } diff --git a/src/lib/post_to_influxdb.js b/src/lib/post_to_influxdb.js index eb727b2b..7262cec5 100755 --- a/src/lib/post_to_influxdb.js +++ b/src/lib/post_to_influxdb.js @@ -65,7 +65,7 @@ export function postButlerMemoryUsageToInfluxdb(memory) { // copyrightYearRange: "1993-2024", // } export async function postQlikSenseVersionToInfluxDB(qlikSenseVersion) { - globals.logger.verbose('INFLUXDB QLIK SENSE VERSION: Sending Qlik Sense version to InfluxDB'); + globals.logger.verbose('[QSEOW] INFLUXDB QLIK SENSE VERSION: Sending Qlik Sense version to InfluxDB'); // Get tags from config file // Stored in array Butler.qlikSenseVersion.versionMonitor.destination.influxDb.tag @@ -118,10 +118,12 @@ export async function postQlikSenseVersionToInfluxDB(qlikSenseVersion) { const deepClonedDatapoint = _.cloneDeep(datapoint); await globals.influx.writePoints(deepClonedDatapoint); - globals.logger.silly(`INFLUXDB QLIK SENSE VERSION: Influxdb datapoint for Qlik Sense version: ${JSON.stringify(datapoint, null, 2)}`); + globals.logger.silly( + `[QSEOW] INFLUXDB QLIK SENSE VERSION: Influxdb datapoint for Qlik Sense version: ${JSON.stringify(datapoint, null, 2)}`, + ); datapoint = null; - globals.logger.verbose('INFLUXDB QLIK SENSE VERSION: Sent Qlik Sense version to InfluxDB'); + globals.logger.verbose('[QSEOW] INFLUXDB QLIK SENSE VERSION: Sent Qlik Sense version to InfluxDB'); } // Function to store Qlik Sense server license status to InfluxDB @@ -133,7 +135,7 @@ export async function postQlikSenseVersionToInfluxDB(qlikSenseVersion) { // "daysUntilExpiry": , // } export async function postQlikSenseServerLicenseStatusToInfluxDB(qlikSenseServerLicenseStatus) { - globals.logger.verbose('INFLUXDB QLIK SENSE SERVER LICENSE STATUS: Sending Qlik Sense server license status to InfluxDB'); + globals.logger.verbose('[QSEOW] INFLUXDB QLIK SENSE SERVER LICENSE STATUS: Sending Qlik Sense server license status to InfluxDB'); // Get tags from config file // Stored in array Butler.qlikSenseLicense.serverLicenseMonitor.destination.influxDb.tag @@ -182,7 +184,7 @@ export async function postQlikSenseServerLicenseStatusToInfluxDB(qlikSenseServer await globals.influx.writePoints(deepClonedDatapoint); globals.logger.silly( - `INFLUXDB QLIK SENSE SERVER LICENSE STATUS: Influxdb datapoint for Qlik Sense server license status: ${JSON.stringify( + `[QSEOW] INFLUXDB QLIK SENSE SERVER LICENSE STATUS: Influxdb datapoint for Qlik Sense server license status: ${JSON.stringify( datapoint, null, 2, @@ -190,7 +192,7 @@ export async function postQlikSenseServerLicenseStatusToInfluxDB(qlikSenseServer ); datapoint = null; - globals.logger.verbose('INFLUXDB QLIK SENSE SERVER LICENSE STATUS: Sent Qlik Sense server license status to InfluxDB'); + globals.logger.verbose('[QSEOW] INFLUXDB QLIK SENSE SERVER LICENSE STATUS: Sent Qlik Sense server license status to InfluxDB'); } // Function to store Qlik Sense access license status to InfluxDB @@ -245,7 +247,7 @@ export async function postQlikSenseServerLicenseStatusToInfluxDB(qlikSenseServer // "schemaPath": "AccessTypeOverview" // } export async function postQlikSenseLicenseStatusToInfluxDB(qlikSenseLicenseStatus) { - globals.logger.verbose('INFLUXDB QLIK SENSE LICENSE STATUS: Sending Qlik Sense license status to InfluxDB'); + globals.logger.verbose('[QSEOW] INFLUXDB QLIK SENSE LICENSE STATUS: Sending Qlik Sense license status to InfluxDB'); // Get tags from config file // Stored in array Butler.qlikSenseLicense.licenseMonitor.destination.influxDb.tag @@ -396,16 +398,16 @@ export async function postQlikSenseLicenseStatusToInfluxDB(qlikSenseLicenseStatu await globals.influx.writePoints(deepClonedDatapoint); globals.logger.silly( - `INFLUXDB QLIK SENSE LICENSE STATUS: Influxdb datapoint for Qlik Sense license status: ${JSON.stringify(datapoint, null, 2)}`, + `[QSEOW] INFLUXDB QLIK SENSE LICENSE STATUS: Influxdb datapoint for Qlik Sense license status: ${JSON.stringify(datapoint, null, 2)}`, ); datapoint = null; - globals.logger.info('INFLUXDB QLIK SENSE LICENSE STATUS: Sent aggregated Qlik Sense license status to InfluxDB'); + globals.logger.info('[QSEOW] INFLUXDB QLIK SENSE LICENSE STATUS: Sent aggregated Qlik Sense license status to InfluxDB'); } // Function to store info about released Qlik Sense licenses to InfluxDB export async function postQlikSenseLicenseReleasedToInfluxDB(licenseInfo) { - globals.logger.verbose('INFLUXDB QLIK SENSE LICENSE RELEASE: Sending info on released Qlik Sense license to InfluxDB'); + globals.logger.verbose('[QSEOW] INFLUXDB QLIK SENSE LICENSE RELEASE: Sending info on released Qlik Sense license to InfluxDB'); // Get tags from config file // Stored in array Butler.qlikSenseLicense.licenseMonitor.destination.influxDb.tag @@ -453,11 +455,11 @@ export async function postQlikSenseLicenseReleasedToInfluxDB(licenseInfo) { await globals.influx.writePoints(deepClonedDatapoint); globals.logger.silly( - `INFLUXDB QLIK SENSE LICENSE RELEASE: Influxdb datapoint for released Qlik Sense license: ${JSON.stringify(datapoint, null, 2)}`, + `[QSEOW] INFLUXDB QLIK SENSE LICENSE RELEASE: Influxdb datapoint for released Qlik Sense license: ${JSON.stringify(datapoint, null, 2)}`, ); datapoint = null; - globals.logger.debug('INFLUXDB QLIK SENSE LICENSE RELEASE: Sent info on released Qlik Sense license to InfluxDB'); + globals.logger.debug('[QSEOW] INFLUXDB QLIK SENSE LICENSE RELEASE: Sent info on released Qlik Sense license to InfluxDB'); } // Function to store windows service status to InfluxDB @@ -546,7 +548,7 @@ export function postWindowsServiceStatusToInfluxDB(serviceStatus) { // Store information about successful reload tasks to InfluxDB export function postReloadTaskSuccessNotificationInfluxDb(reloadParams) { try { - globals.logger.verbose('INFLUXDB RELOAD TASK SUCCESS: Sending reload task notification to InfluxDB'); + globals.logger.verbose('[QSEOW] INFLUXDB RELOAD TASK SUCCESS: Sending reload task notification to InfluxDB'); // Add tags let tags = {}; @@ -587,7 +589,7 @@ export function postReloadTaskSuccessNotificationInfluxDb(reloadParams) { // Get task info const { taskInfo } = reloadParams; - globals.logger.debug(`INFLUXDB RELOAD TASK SUCCESS: Task info:\n${JSON.stringify(taskInfo, null, 2)}`); + globals.logger.debug(`[QSEOW] INFLUXDB RELOAD TASK SUCCESS: Task info:\n${JSON.stringify(taskInfo, null, 2)}`); // Use task info to enrich log entry sent to InfluxDB datapoint[0].tags.task_executingNodeName = taskInfo.executingNodeName; @@ -650,24 +652,26 @@ export function postReloadTaskSuccessNotificationInfluxDb(reloadParams) { .then(() => { globals.logger.silly( - `INFLUXDB RELOAD TASK SUCCESS: Influxdb datapoint for reload task notification: ${JSON.stringify(datapoint, null, 2)}`, + `[QSEOW] INFLUXDB RELOAD TASK SUCCESS: Influxdb datapoint for reload task notification: ${JSON.stringify(datapoint, null, 2)}`, ); datapoint = null; - globals.logger.verbose('INFLUXDB RELOAD TASK SUCCESS: Sent reload task notification to InfluxDB'); + globals.logger.verbose('[QSEOW] INFLUXDB RELOAD TASK SUCCESS: Sent reload task notification to InfluxDB'); }) .catch((err) => { - globals.logger.error(`INFLUXDB RELOAD TASK SUCCESS: Error saving reload task notification to InfluxDB! ${err.stack}`); + globals.logger.error( + `[QSEOW] INFLUXDB RELOAD TASK SUCCESS: Error saving reload task notification to InfluxDB! ${err.stack}`, + ); }); } catch (err) { - globals.logger.error(`INFLUXDB RELOAD TASK SUCCESS: ${err}`); + globals.logger.error(`[QSEOW] INFLUXDB RELOAD TASK SUCCESS: ${err}`); } } // Store information about failed reload tasks to InfluxDB export function postReloadTaskFailureNotificationInfluxDb(reloadParams) { try { - globals.logger.info('INFLUXDB RELOAD TASK FAILED: Sending reload task notification to InfluxDB'); + globals.logger.info('[QSEOW] INFLUXDB RELOAD TASK FAILED: Sending reload task notification to InfluxDB'); // Add tags let tags = {}; @@ -721,7 +725,7 @@ export function postReloadTaskFailureNotificationInfluxDb(reloadParams) { scriptLogData.scriptLogTail = ''; } - globals.logger.debug(`INFLUXDB RELOAD TASK FAILED: Script log data:\n${JSON.stringify(scriptLogData, null, 2)}`); + globals.logger.debug(`[QSEOW] INFLUXDB RELOAD TASK FAILED: Script log data:\n${JSON.stringify(scriptLogData, null, 2)}`); // Use script log data to enrich log entry sent to InfluxDB datapoint[0].tags.task_executingNodeName = scriptLogData.executingNodeName; @@ -793,16 +797,18 @@ export function postReloadTaskFailureNotificationInfluxDb(reloadParams) { .then(() => { globals.logger.silly( - `INFLUXDB RELOAD TASK FAILED: Influxdb datapoint for reload task notification: ${JSON.stringify(datapoint, null, 2)}`, + `[QSEOW] INFLUXDB RELOAD TASK FAILED: Influxdb datapoint for reload task notification: ${JSON.stringify(datapoint, null, 2)}`, ); datapoint = null; - globals.logger.verbose('INFLUXDB RELOAD TASK FAILED: Sent reload task notification to InfluxDB'); + globals.logger.verbose('[QSEOW] INFLUXDB RELOAD TASK FAILED: Sent reload task notification to InfluxDB'); }) .catch((err) => { - globals.logger.error(`INFLUXDB RELOAD TASK FAILED: Error saving reload task notification to InfluxDB! ${err.stack}`); + globals.logger.error( + `[QSEOW] INFLUXDB RELOAD TASK FAILED: Error saving reload task notification to InfluxDB! ${err.stack}`, + ); }); } catch (err) { - globals.logger.error(`INFLUXDB RELOAD TASK FAILED: ${err}`); + globals.logger.error(`[QSEOW] INFLUXDB RELOAD TASK FAILED: ${err}`); } } diff --git a/src/lib/qscloud/api/app.js b/src/lib/qscloud/api/app.js index 84adc517..e6cdae5d 100644 --- a/src/lib/qscloud/api/app.js +++ b/src/lib/qscloud/api/app.js @@ -1,7 +1,6 @@ -/* eslint-disable import/prefer-default-export */ import axios from 'axios'; import globals from '../../../globals.js'; -import { verifyGuid } from '../../guid_util.js'; +import { verifyGuid } from '../../guid_util.js'; // Function to get info about a specific Qlik Sense Cloud app // Parameters: @@ -10,7 +9,7 @@ export async function getQlikSenseCloudAppInfo(appId) { try { // Make sure appId is valid GUID. If not, log error and return false if (verifyGuid(appId) === false) { - globals.logger.error(`SENSE CLOUD GET APP ITEMS: Invalid appId: ${appId}`); + globals.logger.error(`[QSCLOUD] SENSE CLOUD GET APP ITEMS: Invalid appId: ${appId}`); return false; } @@ -30,7 +29,7 @@ export async function getQlikSenseCloudAppInfo(appId) { return appInfo; } catch (err) { - globals.logger.error(`SENSE CLOUD GET APP INFO: ${err}`); + globals.logger.error(`[QSCLOUD] SENSE CLOUD GET APP INFO: ${err}`); return false; } } @@ -42,7 +41,7 @@ export async function getQlikSenseCloudAppMetadata(appId) { try { // Make sure appId is valid GUID. If not, log error and return false if (verifyGuid(appId) === false) { - globals.logger.error(`SENSE CLOUD GET APP ITEMS: Invalid appId: ${appId}`); + globals.logger.error(`[QSCLOUD] SENSE CLOUD GET APP ITEMS: Invalid appId: ${appId}`); return false; } @@ -62,7 +61,7 @@ export async function getQlikSenseCloudAppMetadata(appId) { return appMetadata; } catch (err) { - globals.logger.error(`SENSE CLOUD GET APP METADATA: ${err}`); + globals.logger.error(`[QSCLOUD] SENSE CLOUD GET APP METADATA: ${err}`); return false; } } @@ -74,7 +73,7 @@ export async function getQlikSenseCloudAppItems(appId) { try { // Make sure appId is valid GUID. If not, log error and return false if (verifyGuid(appId) === false) { - globals.logger.error(`SENSE CLOUD GET APP ITEMS: Invalid appId: ${appId}`); + globals.logger.error(`[QSCLOUD] SENSE CLOUD GET APP ITEMS: Invalid appId: ${appId}`); return false; } @@ -105,7 +104,7 @@ export async function getQlikSenseCloudAppItems(appId) { return appItems; } catch (err) { - globals.logger.error(`Qlik SENSE CLOUD GET SCRIPT LOG: ${err}`); + globals.logger.error(`[QSCLOUD] Qlik SENSE CLOUD GET SCRIPT LOG: ${err}`); return false; } } diff --git a/src/lib/qscloud/api/appreloadinfo.js b/src/lib/qscloud/api/appreloadinfo.js index 7f268d43..d6fa3f89 100644 --- a/src/lib/qscloud/api/appreloadinfo.js +++ b/src/lib/qscloud/api/appreloadinfo.js @@ -26,14 +26,14 @@ export async function getQlikSenseCloudAppReloadScriptLog(appId, reloadId) { // Get number of lines in scriptLogFull const scriptLogLineCount = scriptLogFull.length; - globals.logger.verbose('QLIK SENSE CLOUD GET SCRIPT LOG: Done getting script log'); + globals.logger.verbose('[QSCLOUD] QLIK SENSE CLOUD GET SCRIPT LOG: Done getting script log'); return { scriptLogFull, scriptLogSize: scriptLogLineCount, }; } catch (err) { - globals.logger.error(`QLIK SENSE CLOUD GET SCRIPT LOG: ${err}`); + globals.logger.error(`[QSCLOUD] QLIK SENSE CLOUD GET SCRIPT LOG: ${err}`); return false; } } @@ -45,7 +45,7 @@ export async function getQlikSenseCloudAppReloadScriptLog(appId, reloadId) { export function getQlikSenseCloudAppReloadScriptLogHead(scriptLogFull, headLineCount) { if (headLineCount > 0) { const scriptLogHead = scriptLogFull.slice(0, headLineCount).join('\r\n'); - globals.logger.debug(`QLIK SENSE CLOUD GET SCRIPT LOG: Script log head:\n${scriptLogHead}`); + globals.logger.debug(`[QSCLOUD] QLIK SENSE CLOUD GET SCRIPT LOG: Script log head:\n${scriptLogHead}`); return scriptLogHead; } else { @@ -60,7 +60,7 @@ export function getQlikSenseCloudAppReloadScriptLogHead(scriptLogFull, headLineC export function getQlikSenseCloudAppReloadScriptLogTail(scriptLogFull, tailLineCount) { if (tailLineCount > 0) { const scriptLogTail = scriptLogFull.slice(Math.max(scriptLogFull.length - tailLineCount, 0)).join('\r\n'); - globals.logger.debug(`QLIK SENSE CLOUD GET SCRIPT LOG: Script log tails:\n${scriptLogTail}`); + globals.logger.debug(`[QSCLOUD] QLIK SENSE CLOUD GET SCRIPT LOG: Script log tails:\n${scriptLogTail}`); return scriptLogTail; } else { @@ -138,7 +138,7 @@ export async function getQlikSenseCloudAppReloadInfo(reloadId) { return reloadInfo; } catch (err) { - globals.logger.error(`Qlik SENSE CLOUD GET RELOAD INFO: ${err}`); + globals.logger.error(`[QSCLOUD] Qlik SENSE CLOUD GET RELOAD INFO: ${err}`); return false; } } diff --git a/src/lib/qscloud/api/user.js b/src/lib/qscloud/api/user.js index b505f7ac..7c6ea989 100644 --- a/src/lib/qscloud/api/user.js +++ b/src/lib/qscloud/api/user.js @@ -1,4 +1,3 @@ -/* eslint-disable import/prefer-default-export */ import axios from 'axios'; import globals from '../../../globals.js'; @@ -24,7 +23,7 @@ export async function getQlikSenseCloudUserInfo(userId) { return appInfo; } catch (err) { - globals.logger.error(`Qlik SENSE CLOUD GET SCRIPT LOG: ${err}`); + globals.logger.error(`[QSCLOUD] Qlik SENSE CLOUD GET SCRIPT LOG: ${err}`); return false; } } \ No newline at end of file diff --git a/src/lib/qscloud/email_notification_qscloud.js b/src/lib/qscloud/email_notification_qscloud.js index 0a4aa4de..480c375d 100644 --- a/src/lib/qscloud/email_notification_qscloud.js +++ b/src/lib/qscloud/email_notification_qscloud.js @@ -6,6 +6,7 @@ import { getQlikSenseCloudUserInfo } from './api/user.js'; import { getQlikSenseCloudAppInfo } from './api/app.js'; import { getQlikSenseCloudUrls } from './util.js'; import { sendEmail, isSmtpConfigOk } from '../qseow/smtp.js'; +import { getQlikSenseCloudAppReloadScriptLogHead, getQlikSenseCloudAppReloadScriptLogTail } from './api/appreloadinfo.js'; let rateLimiterMemoryFailedReloads; let emailConfig; @@ -27,7 +28,7 @@ function getAppReloadFailedEmailConfig() { // Is email alerts on failed reloads enabled? if (!globals.config.get('Butler.qlikSenseCloud.event.mqtt.tenant.alert.emailNotification.reloadAppFailure.enable')) { globals.logger.error( - 'EMAIL ALERT - QS CLOUD APP RELOAD FAILED: Email alerts on failed reloads are disabled in the config file.', + '[QSCLOUD] EMAIL ALERT - APP RELOAD FAILED: Email alerts on failed reloads are disabled in the config file.', ); return false; } @@ -68,7 +69,7 @@ function getAppReloadFailedEmailConfig() { ), }; } catch (err) { - globals.logger.error(`EMAIL ALERT - QS CLOUD APP RELOAD FAILED: ${err}`); + globals.logger.error(`[QSCLOUD] EMAIL ALERT - APP RELOAD FAILED: ${err}`); return false; } } @@ -77,7 +78,7 @@ function getAppReloadFailedEmailConfig() { export async function sendQlikSenseCloudAppReloadFailureNotificationEmail(reloadParams) { try { globals.logger.info( - `EMAIL ALERT - QS CLOUD APP RELOAD FAILED: Rate limiting check passed for failed task notification. App name: "${reloadParams.appName}"`, + `[QSCLOUD] EMAIL ALERT - APP RELOAD FAILED: Rate limiting check passed for failed task notification. App name: "${reloadParams.appName}"`, ); // Logic for determining if alert email should be sent or not @@ -130,7 +131,7 @@ export async function sendQlikSenseCloudAppReloadFailureNotificationEmail(reload if (appTags === undefined || appTags?.length === 0 || appHasAlertTag === undefined) { globals.logger.warn( - `EMAIL ALERT - QS CLOUD APP RELOAD FAILED: App [${reloadParams.appId}] "${reloadParams.appName}" does not have the tag "${alertTag}" set. Not sending alert email based on app tag.`, + `[QSCLOUD] EMAIL ALERT - APP RELOAD FAILED: App [${reloadParams.appId}] "${reloadParams.appName}" does not have the tag "${alertTag}" set. Not sending alert email based on app tag.`, ); } else if (appHasAlertTag !== undefined) { if (emailConfig?.globalSendList?.length > 0) { @@ -150,7 +151,7 @@ export async function sendQlikSenseCloudAppReloadFailureNotificationEmail(reload if (appOwner.email === undefined || appOwner?.email?.length === 0) { globals.logger.warn( - `EMAIL ALERT - QS CLOUD APP RELOAD FAILED: App owner email address is not set for app [${reloadParams.appId}] "${reloadParams.appName}". Not sending alert email to app owner "${appOwner.name}".`, + `[QSCLOUD] EMAIL ALERT - APP RELOAD FAILED: App owner email address is not set for app [${reloadParams.appId}] "${reloadParams.appName}". Not sending alert email to app owner "${appOwner.name}".`, ); } else { // App owner email address exists. @@ -197,7 +198,7 @@ export async function sendQlikSenseCloudAppReloadFailureNotificationEmail(reload // Check if we have any email addresses to send to if (globalSendList?.length === 0) { globals.logger.warn( - `EMAIL ALERT - QS CLOUD APP RELOAD FAILED: No email addresses found to send alert email for app [${reloadParams.appId}] "${reloadParams.appName}".`, + `[QSCLOUD] EMAIL ALERT - APP RELOAD FAILED: No email addresses found to send alert email for app [${reloadParams.appId}] "${reloadParams.appName}".`, ); return false; } @@ -213,7 +214,7 @@ export async function sendQlikSenseCloudAppReloadFailureNotificationEmail(reload if (reloadParams.scriptLog === false) { scriptLogData = { scriptLogFull: [], - scriptLogSize: 0, + scriptLogSizeRows: 0, scriptLogHead: '', scriptLogHeadCount: 0, scriptLogTail: '', @@ -229,24 +230,29 @@ export async function sendQlikSenseCloudAppReloadFailureNotificationEmail(reload ); if (reloadParams.scriptLog?.scriptLogFull?.length > 0) { - // Get length of script log (character count) - scriptLogData.scriptLogSize = reloadParams.scriptLog.scriptLogFull.length; + // Get length of script log (row count) + scriptLogData.scriptLogSizeRows = reloadParams.scriptLog.scriptLogFull.length; - // Get the first and last n lines of the script log - scriptLogData.scriptLogHead = reloadParams.scriptLog.scriptLogFull - .slice(0, reloadParams.scriptLog.scriptLogHeadCount) - .join('\r\n'); + // Get length of entire script log (character count) + scriptLogData.scriptLogSizeCharacters = reloadParams.scriptLog.scriptLogFull.join('').length; - scriptLogData.scriptLogTail = reloadParams.scriptLog.scriptLogFull - .slice(Math.max(reloadParams.scriptLog.scriptLogFull.length - reloadParams.scriptLog.scriptLogTailCount, 0)) - .join('\r\n'); + // Get the first and last rows of the script log + scriptLogData.scriptLogHead = getQlikSenseCloudAppReloadScriptLogHead( + reloadParams.scriptLog.scriptLogFull, + scriptLogData.scriptLogHeadCount, + ); + scriptLogData.scriptLogTail = getQlikSenseCloudAppReloadScriptLogTail( + reloadParams.scriptLog.scriptLogFull, + scriptLogData.scriptLogTailCount, + ); } else { scriptLogData.scriptLogHead = ''; scriptLogData.scriptLogTail = ''; - scriptLogData.scriptLogSize = 0; + scriptLogData.scriptLogSizeRows = 0; + scriptLogData.scriptLogSizeCharacters = 0; } - globals.logger.debug(`EMAIL ALERT - QS CLOUD APP RELOAD FAILED: Script log data:\n${JSON.stringify(scriptLogData, null, 2)}`); + globals.logger.debug(`[QSCLOUD] EMAIL ALERT - APP RELOAD FAILED: Script log data:\n${JSON.stringify(scriptLogData, null, 2)}`); } // Format log message line breaks to work in HTML email @@ -309,7 +315,9 @@ export async function sendQlikSenseCloudAppReloadFailureNotificationEmail(reload executionStartTime: reloadParams.reloadInfo.executionStartTime, executionStopTime: reloadParams.reloadInfo.executionStopTime, executionStatusText: reloadParams.reloadInfo.status, - scriptLogSize: scriptLogData.scriptLogSize.toLocaleString(), + scriptLogSize: scriptLogData.scriptLogSizeRows.toLocaleString(), + scriptLogSizeRows: scriptLogData.scriptLogSizeRows.toLocaleString(), + scriptLogSizeCharacters: scriptLogData.scriptLogSizeCharacters.toLocaleString(), scriptLogHead: scriptLogData.scriptLogHead, scriptLogTail: scriptLogData.scriptLogTail, scriptLogTailCount: scriptLogData.scriptLogTailCount, @@ -334,9 +342,11 @@ export async function sendQlikSenseCloudAppReloadFailureNotificationEmail(reload .then(async (rateLimiterRes) => { try { globals.logger.info( - `EMAIL ALERT - QS CLOUD: Rate limiting check passed for failed app reload notification. App name: "${reloadParams.appName}", email: "${recipientEmailAddress}"`, + `[QSCLOUD] EMAIL ALERT - QS CLOUD: Rate limiting check passed for failed app reload notification. App name: "${reloadParams.appName}", email: "${recipientEmailAddress}"`, + ); + globals.logger.debug( + `[QSCLOUD] EMAIL ALERT - QS CLOUD: Rate limiting details "${JSON.stringify(rateLimiterRes, null, 2)}"`, ); - globals.logger.debug(`EMAIL ALERT - QS CLOUD: Rate limiting details "${JSON.stringify(rateLimiterRes, null, 2)}"`); // Only send email if there is an actual email address if (recipientEmailAddress?.length > 0) { @@ -351,24 +361,24 @@ export async function sendQlikSenseCloudAppReloadFailureNotificationEmail(reload ); } else { globals.logger.warn( - `EMAIL ALERT - QS CLOUD APP RELOAD FAILED: No email address found for app [${reloadParams.appId}] "${reloadParams.appName}". Not sending alert email.`, + `[QSCLOUD] EMAIL ALERT - APP RELOAD FAILED: No email address found for app [${reloadParams.appId}] "${reloadParams.appName}". Not sending alert email.`, ); } } catch (err) { - globals.logger.error(`EMAIL ALERT - QS CLOUD APP RELOAD FAILED: ${err}`); + globals.logger.error(`[QSCLOUD] EMAIL ALERT - APP RELOAD FAILED: ${err}`); } }) .catch((err) => { globals.logger.warn( - `EMAIL ALERT - QS CLOUD APP RELOAD FAILED: Rate limiting failed. Not sending reload notification email for app [${reloadParams.appId}] "${reloadParams.appName}"`, + `[QSCLOUD] EMAIL ALERT - APP RELOAD FAILED: Rate limiting failed. Not sending reload notification email for app [${reloadParams.appId}] "${reloadParams.appName}"`, ); globals.logger.debug( - `EMAIL ALERT - QS CLOUD APP RELOAD FAILED: Rate limiting details "${JSON.stringify(err, null, 2)}"`, + `[QSCLOUD] EMAIL ALERT - APP RELOAD FAILED: Rate limiting details "${JSON.stringify(err, null, 2)}"`, ); }); } } catch (err) { - globals.logger.error(`EMAIL ALERT - QS CLOUD APP RELOAD FAILED: ${err}`); + globals.logger.error(`[QSCLOUD] EMAIL ALERT - APP RELOAD FAILED: ${err}`); } return true; diff --git a/src/lib/qscloud/mqtt_event_app_reload_finished.js b/src/lib/qscloud/mqtt_event_app_reload_finished.js index 06060f65..e91e2829 100644 --- a/src/lib/qscloud/mqtt_event_app_reload_finished.js +++ b/src/lib/qscloud/mqtt_event_app_reload_finished.js @@ -2,12 +2,7 @@ import path from 'path'; import fs from 'fs'; import globals from '../../globals.js'; -import { - getQlikSenseCloudAppReloadScriptLog, - getQlikSenseCloudAppReloadInfo, - getQlikSenseCloudAppReloadScriptLogHead, - getQlikSenseCloudAppReloadScriptLogTail, -} from './api/appreloadinfo.js'; +import { getQlikSenseCloudAppReloadScriptLog, getQlikSenseCloudAppReloadInfo } from './api/appreloadinfo.js'; import { getQlikSenseCloudAppInfo, getQlikSenseCloudAppMetadata, getQlikSenseCloudAppItems } from './api/app.js'; import { sendQlikSenseCloudAppReloadFailureNotificationTeams } from './msteams_notification_qscloud.js'; import { sendQlikSenseCloudAppReloadFailureNotificationSlack } from './slack_notification_qscloud.js'; @@ -62,7 +57,7 @@ export async function handleQlikSenseCloudAppReloadFinished(message) { // Valid tenant ID is defined in the Butler configuration file if (!monitoredTenants.some((tenant) => tenant.id === tenantId)) { logger.warn( - `QLIK SENSE CLOUD: Incoming MQTT event from Qlik Sense Cloud, but tenant ID "${tenantId}" is not defined in the Butler configuration file. Skipping event.`, + `[QSCLOUD] Incoming MQTT event from Qlik Sense Cloud, but tenant ID "${tenantId}" is not defined in the Butler configuration file. Skipping event.`, ); return false; } @@ -83,7 +78,7 @@ export async function handleQlikSenseCloudAppReloadFinished(message) { let appItems = {}; // App reload did fail. Send enabled notifications/alerts, store script log etc - logger.info(`QLIK SENSE CLOUD: App reload failed. App ID=[${appId}] name="${message.data.name}"`); + logger.info(`[QSCLOUD] App reload failed. App ID=[${appId}] name="${message.data.name}"`); // Are notifications from QS Cloud enabled? if (globals.config.get('Butler.qlikSenseCloud.enable') === true) { @@ -98,16 +93,16 @@ export async function handleQlikSenseCloudAppReloadFinished(message) { try { scriptLog = await getQlikSenseCloudAppReloadScriptLog(appId, reloadId); } catch (err) { - logger.error(`QLIK SENSE CLOUD: Could not get app reload script log. Error=${JSON.stringify(err, null, 2)}`); + logger.error(`[QSCLOUD] Could not get app reload script log. Error=${JSON.stringify(err, null, 2)}`); } // If return value is false, the script log could not be obtained if (scriptLog === false) { - logger.warn(`QLIK SENSE CLOUD: Could not get app reload script log. App ID="${appId}", reload ID="${reloadId}"`); + logger.warn(`[QSCLOUD] Could not get app reload script log. App ID="${appId}", reload ID="${reloadId}"`); } else { - logger.verbose(`QLIK SENSE CLOUD: App reload script log obtained. App ID="${appId}", reload ID="${reloadId}"`); + logger.verbose(`[QSCLOUD] App reload script log obtained. App ID="${appId}", reload ID="${reloadId}"`); } - logger.debug(`QLIK SENSE CLOUD: App reload script log: ${scriptLog}`); + logger.debug(`[QSCLOUD] App reload script log: ${scriptLog}`); // Reload info is available via "GET /v1/reloads/{reloadId}" // https://qlik.dev/apis/rest/reloads/#get-v1-reloads-reloadId @@ -115,10 +110,10 @@ export async function handleQlikSenseCloudAppReloadFinished(message) { reloadInfo = await getQlikSenseCloudAppReloadInfo(reloadId); reloadTrigger = reloadInfo.type; - logger.verbose(`QLIK SENSE CLOUD: App reload info obtained. App ID="${appId}", reload ID="${reloadId}"`); - logger.debug(`QLIK SENSE CLOUD: App reload info: ${JSON.stringify(reloadInfo, null, 2)}`); + logger.verbose(`[QSCLOUD] App reload info obtained. App ID="${appId}", reload ID="${reloadId}"`); + logger.debug(`[QSCLOUD] App reload info: ${JSON.stringify(reloadInfo, null, 2)}`); } catch (err) { - logger.error(`QLIK SENSE CLOUD: Could not get app reload info. Error=${JSON.stringify(err, null, 2)}`); + logger.error(`[QSCLOUD] Could not get app reload info. Error=${JSON.stringify(err, null, 2)}`); } // App info is available via "GET /v1/apps/{appId}" @@ -126,10 +121,10 @@ export async function handleQlikSenseCloudAppReloadFinished(message) { try { appInfo = await getQlikSenseCloudAppInfo(appId); - logger.verbose(`QLIK SENSE CLOUD: App info obtained. App ID="${appId}"`); - logger.debug(`QLIK SENSE CLOUD: App info: ${JSON.stringify(appInfo, null, 2)}`); + logger.verbose(`[QSCLOUD] App info obtained. App ID="${appId}"`); + logger.debug(`[QSCLOUD] App info: ${JSON.stringify(appInfo, null, 2)}`); } catch (err) { - logger.error(`QLIK SENSE CLOUD: Could not get app info. Error=${JSON.stringify(err, null, 2)}`); + logger.error(`[QSCLOUD] Could not get app info. Error=${JSON.stringify(err, null, 2)}`); } // App metadata is available via "GET /v1/apps/{appId}/data/metadata" @@ -137,10 +132,10 @@ export async function handleQlikSenseCloudAppReloadFinished(message) { try { appMetadata = await getQlikSenseCloudAppMetadata(appId); - logger.verbose(`QLIK SENSE CLOUD: App metadata obtained. App ID="${appId}"`); - logger.debug(`QLIK SENSE CLOUD: App metadata: ${JSON.stringify(appMetadata, null, 2)}`); + logger.verbose(`[QSCLOUD] App metadata obtained. App ID="${appId}"`); + logger.debug(`[QSCLOUD] App metadata: ${JSON.stringify(appMetadata, null, 2)}`); } catch (err) { - logger.error(`QLIK SENSE CLOUD: Could not get app metadata. Error=${JSON.stringify(err, null, 2)}`); + logger.error(`[QSCLOUD] Could not get app metadata. Error=${JSON.stringify(err, null, 2)}`); } // App items are available via "GET /v1/items" @@ -152,7 +147,7 @@ export async function handleQlikSenseCloudAppReloadFinished(message) { // error if not if (appItems?.data.length !== 1 || appItems?.data[0].resourceId !== appId) { logger.error( - `QLIK SENSE CLOUD: App items obtained, but app ID does not match. App ID="${appId}", appItems="${JSON.stringify( + `[QSCLOUD] App items obtained, but app ID does not match. App ID="${appId}", appItems="${JSON.stringify( appItems, null, 2, @@ -163,10 +158,10 @@ export async function handleQlikSenseCloudAppReloadFinished(message) { appItems = {}; } - logger.verbose(`QLIK SENSE CLOUD: App items obtained. App ID="${appId}"`); - logger.debug(`QLIK SENSE CLOUD: App items: ${JSON.stringify(appItems, null, 2)}`); + logger.verbose(`[QSCLOUD] App items obtained. App ID="${appId}"`); + logger.debug(`[QSCLOUD] App items: ${JSON.stringify(appItems, null, 2)}`); } catch (err) { - logger.error(`QLIK SENSE CLOUD: Could not get app items. Error=${JSON.stringify(err, null, 2)}`); + logger.error(`[QSCLOUD] Could not get app items. Error=${JSON.stringify(err, null, 2)}`); } // Get info from config file @@ -179,7 +174,7 @@ export async function handleQlikSenseCloudAppReloadFinished(message) { // Save script log to disk file, if enabled if (globals.config.get('Butler.scriptLog.storeOnDisk.qsCloud.appReloadFailure.enable') === true) { - logger.verbose(`QLIK SENSE CLOUD: Storing script log to disk file`); + logger.verbose(`[QSCLOUD] Storing script log to disk file`); // Get path to the directory where script logs will be stored const scriptLogDirRoot = globals.config.get('Butler.scriptLog.storeOnDisk.qsCloud.appReloadFailure.logDirectory'); @@ -190,7 +185,7 @@ export async function handleQlikSenseCloudAppReloadFinished(message) { const logDate = eventTime.slice(0, 10); const reloadLogDir = path.resolve(scriptLogDirRoot, logDate); - logger.debug(`QLIK SENSE CLOUD: Script log directory: ${reloadLogDir}`); + logger.debug(`[QSCLOUD] Script log directory: ${reloadLogDir}`); // Get error time stamp from eventTime, in format YYY-MM-DD_HH-MM-SS const logTimeStamp = eventTime.slice(0, 19).replace(/ /g, '_').replace(/:/g, '-'); @@ -202,10 +197,10 @@ export async function handleQlikSenseCloudAppReloadFinished(message) { // Write script log to disk file try { - logger.info(`QLIK SENSE CLOUD: Writing failed task script log: ${fileName}`); + logger.info(`[QSCLOUD] Writing failed task script log: ${fileName}`); fs.writeFileSync(fileName, scriptLog.scriptLogFull.join('\n')); } catch (err) { - logger.error(`QLIK SENSE CLOUD: Could not store script log to disk file. File="${fileName}", error=${err}`); + logger.error(`[QSCLOUD] Could not store script log to disk file. File="${fileName}", error=${err}`); } } @@ -214,7 +209,7 @@ export async function handleQlikSenseCloudAppReloadFinished(message) { globals.config.get('Butler.qlikSenseCloud.event.mqtt.tenant.alert.teamsNotification.reloadAppFailure.enable') === true ) { - logger.verbose(`QLIK SENSE CLOUD: Sending Teams notification about app reload failure`); + logger.verbose(`[QSCLOUD] Sending Teams notification about app reload failure`); // Should we get extended info about the event, or go with the basic info provided in the event/MQTT message? // If extended info is enabled, we need to make API calls to get the extended info @@ -222,21 +217,8 @@ export async function handleQlikSenseCloudAppReloadFinished(message) { if ( globals.config.get( 'Butler.qlikSenseCloud.event.mqtt.tenant.alert.teamsNotification.reloadAppFailure.basicContentOnly', - ) === false + ) === true ) { - const headLineCount = globals.config.get( - 'Butler.qlikSenseCloud.event.mqtt.tenant.alert.teamsNotification.reloadAppFailure.headScriptLogLines', - ); - - const tailLineCount = globals.config.get( - 'Butler.qlikSenseCloud.event.mqtt.tenant.alert.teamsNotification.reloadAppFailure.tailScriptLogLines', - ); - - scriptLog.HeadCount = headLineCount; - scriptLog.TailCount = tailLineCount; - scriptLog.scriptLogHead = getQlikSenseCloudAppReloadScriptLogHead(scriptLog.scriptLogFull, headLineCount); - scriptLog.scriptLogTail = getQlikSenseCloudAppReloadScriptLogTail(scriptLog.scriptLogFull, tailLineCount); - } else { // Use the basic info provided in the event/MQTT message scriptLog = {}; reloadInfo.appId = appId; @@ -286,7 +268,7 @@ export async function handleQlikSenseCloudAppReloadFinished(message) { globals.config.get('Butler.qlikSenseCloud.event.mqtt.tenant.alert.slackNotification.reloadAppFailure.enable') === true ) { - logger.verbose(`QLIK SENSE CLOUD: Sending Slack notification about app reload failure`); + logger.verbose(`[QSCLOUD] Sending Slack notification about app reload failure`); // Should we get extended info about the event, or go with the basic info provided in the event/MQTT message? // If extended info is enabled, we need to make API calls to get the extended info @@ -294,21 +276,8 @@ export async function handleQlikSenseCloudAppReloadFinished(message) { if ( globals.config.get( 'Butler.qlikSenseCloud.event.mqtt.tenant.alert.slackNotification.reloadAppFailure.basicContentOnly', - ) === false + ) === true ) { - const headLineCount = globals.config.get( - 'Butler.qlikSenseCloud.event.mqtt.tenant.alert.slackNotification.reloadAppFailure.headScriptLogLines', - ); - - const tailLineCount = globals.config.get( - 'Butler.qlikSenseCloud.event.mqtt.tenant.alert.slackNotification.reloadAppFailure.tailScriptLogLines', - ); - - scriptLog.HeadCount = headLineCount; - scriptLog.TailCount = tailLineCount; - scriptLog.scriptLogHead = getQlikSenseCloudAppReloadScriptLogHead(scriptLog.scriptLogFull, headLineCount); - scriptLog.scriptLogTail = getQlikSenseCloudAppReloadScriptLogTail(scriptLog.scriptLogFull, tailLineCount); - } else { // Use the basic info provided in the event/MQTT message scriptLog = {}; reloadInfo.appId = appId; @@ -359,7 +328,7 @@ export async function handleQlikSenseCloudAppReloadFinished(message) { globals.config.get('Butler.qlikSenseCloud.event.mqtt.tenant.alert.emailNotification.reloadAppFailure.enable') === true ) { - logger.verbose(`QLIK SENSE CLOUD: Sending email notification about app reload failure`); + logger.verbose(`[QSCLOUD] Sending email notification about app reload failure`); // Get extended info about the event // This includes: @@ -369,19 +338,6 @@ export async function handleQlikSenseCloudAppReloadFinished(message) { // - App metadata // - App items - const headLineCount = globals.config.get( - 'Butler.qlikSenseCloud.event.mqtt.tenant.alert.emailNotification.reloadAppFailure.headScriptLogLines', - ); - - const tailLineCount = globals.config.get( - 'Butler.qlikSenseCloud.event.mqtt.tenant.alert.emailNotification.reloadAppFailure.tailScriptLogLines', - ); - - scriptLog.HeadCount = headLineCount; - scriptLog.TailCount = tailLineCount; - scriptLog.scriptLogHead = getQlikSenseCloudAppReloadScriptLogHead(scriptLog.scriptLogFull, headLineCount); - scriptLog.scriptLogTail = getQlikSenseCloudAppReloadScriptLogTail(scriptLog.scriptLogFull, tailLineCount); - // Send email notification sendQlikSenseCloudAppReloadFailureNotificationEmail({ tenantId, @@ -426,7 +382,7 @@ export async function handleQlikSenseCloudAppReloadFinished(message) { return true; } catch (err) { - logger.error(`Qlik Sense Cloud app reload finished event handling error: ${err}`); + logger.error(`[QSCLOUD] Qlik Sense Cloud app reload finished event handling error: ${err}`); return false; } } diff --git a/src/lib/qscloud/msteams_notification_qscloud.js b/src/lib/qscloud/msteams_notification_qscloud.js index 272acfc2..69a63573 100644 --- a/src/lib/qscloud/msteams_notification_qscloud.js +++ b/src/lib/qscloud/msteams_notification_qscloud.js @@ -1,4 +1,3 @@ -/* eslint-disable import/prefer-default-export */ import fs from 'fs'; import { Webhook, SimpleTextCard } from 'ms-teams-wrapper'; @@ -9,6 +8,7 @@ import globals from '../../globals.js'; import { getQlikSenseCloudUserInfo } from './api/user.js'; import { getQlikSenseCloudAppInfo } from './api/app.js'; import { getQlikSenseCloudUrls } from './util.js'; +import { getQlikSenseCloudAppReloadScriptLogHead, getQlikSenseCloudAppReloadScriptLogTail } from './api/appreloadinfo.js'; let rateLimiterMemoryFailedReloads; @@ -29,7 +29,7 @@ function getAppReloadFailedTeamsConfig() { if (!globals.config.get('Butler.qlikSenseCloud.event.mqtt.tenant.alert.teamsNotification.reloadAppFailure.enable')) { // Teams task falure notifications are disabled globals.logger.error( - "TEAMS ALERT - QS CLOUD APP RELOAD FAILED: Reload failure Teams notifications are disabled in config file - won't send Teams message", + "[QSCLOUD] TEAMS ALERT - APP RELOAD FAILED: Reload failure Teams notifications are disabled in config file - won't send Teams message", ); return false; } @@ -42,7 +42,7 @@ function getAppReloadFailedTeamsConfig() { ) { // Invalid Teams message type globals.logger.error( - `TEAMS ALERT - QS CLOUD APP RELOAD FAILED: Invalid Teams message type: ${globals.config.get( + `[QSCLOUD] TEAMS ALERT - APP RELOAD FAILED: Invalid Teams message type: ${globals.config.get( 'Butler.qlikSenseCloud.event.mqtt.tenant.alert.teamsNotification.reloadAppFailure.messageType', )}`, ); @@ -68,7 +68,7 @@ function getAppReloadFailedTeamsConfig() { ), }; } catch (err) { - globals.logger.error(`TEAMS ALERT - QS CLOUD APP RELOAD FAILED: ${err}`); + globals.logger.error(`[QSCLOUD] TEAMS ALERT - APP RELOAD FAILED: ${err}`); return false; } } @@ -135,16 +135,24 @@ async function sendTeams(teamsWebhookUrl, teamsConfig, templateContext, msgType) if (msgType === 'reload') { // Escape any back slashes in the script logs const regExpText = /(?!\\n)\\{1}/gm; - globals.logger.debug(`TEAMS SEND: Script log head escaping: ${regExpText.exec(templateContext.scriptLogHead)}`); - globals.logger.debug(`TEAMS SEND: Script log tail escaping: ${regExpText.exec(templateContext.scriptLogTail)}`); + globals.logger.debug( + `[QSCLOUD] TEAMS SEND: Script log head escaping: ${regExpText.exec(templateContext.scriptLogHead)}`, + ); + globals.logger.debug( + `[QSCLOUD] TEAMS SEND: Script log tail escaping: ${regExpText.exec(templateContext.scriptLogTail)}`, + ); templateContext.scriptLogHead = templateContext.scriptLogHead.replace(regExpText, '\\\\'); templateContext.scriptLogTail = templateContext.scriptLogTail.replace(regExpText, '\\\\'); } else if (msgType === 'qscloud-app-reload') { // Escape any back slashes in the script logs const regExpText = /(?!\\n)\\{1}/gm; - globals.logger.debug(`TEAMS SEND: Script log head escaping: ${regExpText.exec(templateContext.scriptLogHead)}`); - globals.logger.debug(`TEAMS SEND: Script log tail escaping: ${regExpText.exec(templateContext.scriptLogTail)}`); + globals.logger.debug( + `[QSCLOUD] TEAMS SEND: Script log head escaping: ${regExpText.exec(templateContext.scriptLogHead)}`, + ); + globals.logger.debug( + `[QSCLOUD] TEAMS SEND: Script log tail escaping: ${regExpText.exec(templateContext.scriptLogTail)}`, + ); templateContext.scriptLogHead = templateContext.scriptLogHead.replace(regExpText, '\\\\'); templateContext.scriptLogTail = templateContext.scriptLogTail.replace(regExpText, '\\\\'); @@ -152,15 +160,15 @@ async function sendTeams(teamsWebhookUrl, teamsConfig, templateContext, msgType) renderedText = compiledTemplate(templateContext); - globals.logger.debug(`TEAMS SEND: Rendered message:\n${renderedText}`); + globals.logger.debug(`[QSCLOUD] TEAMS SEND: Rendered message:\n${renderedText}`); // Parse the JSON string to get rid of extra linebreaks etc. msg = JSON.parse(renderedText); } else { - globals.logger.error(`TEAMS SEND: Could not open Teams template file ${teamsConfig.templateFile}.`); + globals.logger.error(`[QSCLOUD] TEAMS SEND: Could not open Teams template file ${teamsConfig.templateFile}.`); } } catch (err) { - globals.logger.error(`TEAMS SEND: Error processing Teams template file: ${err}`); + globals.logger.error(`[QSCLOUD] TEAMS SEND: Error processing Teams template file: ${err}`); } } @@ -169,11 +177,13 @@ async function sendTeams(teamsWebhookUrl, teamsConfig, templateContext, msgType) const res = await webhook.sendMessage(); if (res !== undefined) { - globals.logger.debug(`TEAMS SEND: Result from calling TeamsApi.TeamsSend: ${res.statusText} (${res.status}): ${res.data}`); + globals.logger.debug( + `[QSCLOUD] TEAMS SEND: Result from calling TeamsApi.TeamsSend: ${res.statusText} (${res.status}): ${res.data}`, + ); } } } catch (err) { - globals.logger.error(`TEAMS SEND: ${err}`); + globals.logger.error(`[QSCLOUD] TEAMS SEND: ${err}`); } } @@ -184,10 +194,10 @@ export function sendQlikSenseCloudAppReloadFailureNotificationTeams(reloadParams .then(async (rateLimiterRes) => { try { globals.logger.info( - `TEAMS ALERT - QS CLOUD APP RELOAD FAILED: Rate limiting check passed for failed task notification. App name: "${reloadParams.appName}"`, + `[QSCLOUD] TEAMS ALERT - APP RELOAD FAILED: Rate limiting check passed for failed task notification. App name: "${reloadParams.appName}"`, ); globals.logger.verbose( - `TEAMS ALERT - QS CLOUD APP RELOAD FAILED: Rate limiting details "${JSON.stringify(rateLimiterRes, null, 2)}"`, + `[QSCLOUD] TEAMS ALERT - APP RELOAD FAILED: Rate limiting details "${JSON.stringify(rateLimiterRes, null, 2)}"`, ); // Make sure Teams sending is enabled in the config file and that we have all required settings @@ -206,14 +216,14 @@ export function sendQlikSenseCloudAppReloadFailureNotificationTeams(reloadParams if (reloadParams.scriptLog === false) { scriptLogData = { scriptLogFull: [], - scriptLogSize: 0, + scriptLogSizeRows: 0, scriptLogHead: '', scriptLogHeadCount: 0, scriptLogTail: '', scriptLogTailCount: 0, }; } else { - // Reduce script log lines to only the ones we want to send to Teams + // Reduce full script log to head and tail adapted for Teams scriptLogData.scriptLogHeadCount = globals.config.get( 'Butler.qlikSenseCloud.event.mqtt.tenant.alert.teamsNotification.reloadAppFailure.headScriptLogLines', ); @@ -222,23 +232,30 @@ export function sendQlikSenseCloudAppReloadFailureNotificationTeams(reloadParams ); if (reloadParams.scriptLog?.scriptLogFull?.length > 0) { - scriptLogData.scriptLogHead = reloadParams.scriptLog.scriptLogFull - .slice(0, reloadParams.scriptLog.scriptLogHeadCount) - .join('\r\n'); - - scriptLogData.scriptLogTail = reloadParams.scriptLog.scriptLogFull - .slice(Math.max(reloadParams.scriptLog.scriptLogFull.length - reloadParams.scriptLog.scriptLogTailCount, 0)) - .join('\r\n'); + // Get length of entire script log (character count) + scriptLogData.scriptLogSizeCharacters = reloadParams.scriptLog.scriptLogFull.join('').length; + + // Get length of script log (row count) + scriptLogData.scriptLogSizeRows = reloadParams.scriptLog.scriptLogFull.length; + + // Get the first and last rows of the script log + scriptLogData.scriptLogHead = getQlikSenseCloudAppReloadScriptLogHead( + reloadParams.scriptLog.scriptLogFull, + scriptLogData.scriptLogHeadCount, + ); + scriptLogData.scriptLogTail = getQlikSenseCloudAppReloadScriptLogTail( + reloadParams.scriptLog.scriptLogFull, + scriptLogData.scriptLogTailCount, + ); } else { scriptLogData.scriptLogHead = ''; scriptLogData.scriptLogTail = ''; + scriptLogData.scriptLogSizeRows = 0; + scriptLogData.scriptLogSizeCharacters = 0; } - // Get length of script log (character count) - scriptLogData.scriptLogSize = reloadParams.scriptLog.scriptLogFull.length; - globals.logger.debug( - `TEAMS ALERT - QS CLOUD APP RELOAD FAILED: Script log data:\n${JSON.stringify(scriptLogData, null, 2)}`, + `[QSCLOUD] TEAMS ALERT - APP RELOAD FAILED: Script log data:\n${JSON.stringify(scriptLogData, null, 2)}`, ); } @@ -299,7 +316,9 @@ export function sendQlikSenseCloudAppReloadFailureNotificationTeams(reloadParams executionStartTime: reloadParams.reloadInfo.executionStartTime, executionStopTime: reloadParams.reloadInfo.executionStopTime, executionStatusText: reloadParams.reloadInfo.status, - scriptLogSize: scriptLogData.scriptLogSize.toLocaleString(), + scriptLogSize: scriptLogData.scriptLogSizeRows.toLocaleString(), + scriptLogSizeRows: scriptLogData.scriptLogSizeRows.toLocaleString(), + scriptLogSizeCharacters: scriptLogData.scriptLogSizeCharacters.toLocaleString(), scriptLogHead: scriptLogData.scriptLogHead .replace(/([\r])/gm, '') .replace(/([\n])/gm, '\\n') @@ -373,16 +392,16 @@ export function sendQlikSenseCloudAppReloadFailureNotificationTeams(reloadParams const { webhookUrl } = teamsConfig; sendTeams(webhookUrl, teamsConfig, templateContext, 'qscloud-app-reload'); } catch (err) { - globals.logger.error(`TEAMS ALERT - QS CLOUD APP RELOAD FAILED: ${err}`); + globals.logger.error(`[QSCLOUD] TEAMS ALERT - APP RELOAD FAILED: ${err}`); } return true; }) .catch((rateLimiterRes) => { globals.logger.warn( - `TEAMS ALERT - QS CLOUD APP RELOAD FAILED: Rate limiting failed. Not sending reload notification Teams for app [${reloadParams.appId}] "${reloadParams.appName}"`, + `[QSCLOUD] TEAMS ALERT - APP RELOAD FAILED: Rate limiting failed. Not sending reload notification Teams for app [${reloadParams.appId}] "${reloadParams.appName}"`, ); globals.logger.debug( - `TEAMS ALERT - QS CLOUD APP RELOAD FAILED: Rate limiting details "${JSON.stringify(rateLimiterRes, null, 2)}"`, + `[QSCLOUD] TEAMS ALERT - APP RELOAD FAILED: Rate limiting details "${JSON.stringify(rateLimiterRes, null, 2)}"`, ); }); } diff --git a/src/lib/qscloud/slack_notification_qscloud.js b/src/lib/qscloud/slack_notification_qscloud.js index 362c611d..573b475b 100644 --- a/src/lib/qscloud/slack_notification_qscloud.js +++ b/src/lib/qscloud/slack_notification_qscloud.js @@ -7,6 +7,7 @@ import slackSend from '../slack_api.js'; import { getQlikSenseCloudUserInfo } from './api/user.js'; import { getQlikSenseCloudAppInfo } from './api/app.js'; import { getQlikSenseCloudUrls } from './util.js'; +import { getQlikSenseCloudAppReloadScriptLogHead, getQlikSenseCloudAppReloadScriptLogTail } from './api/appreloadinfo.js'; let rateLimiterMemoryFailedReloads; @@ -27,7 +28,7 @@ function getAppReloadFailedSlackConfig() { if (!globals.config.get('Butler.qlikSenseCloud.event.mqtt.tenant.alert.slackNotification.reloadAppFailure.enable')) { // Slack task falure notifications are disabled globals.logger.error( - "SLACK ALERT - QS CLOUD APP RELOAD FAILED: Reload failure Slack notifications are disabled in config file - won't send Slack message", + '[QSCLOUD] SLACK ALERT - APP RELOAD FAILED: Reload failure Slack notifications are disabled in config file - will not send Slack message', ); return false; } @@ -40,7 +41,7 @@ function getAppReloadFailedSlackConfig() { ) { // Invalid Slack message type globals.logger.error( - `SLACK ALERT - QS CLOUD APP RELOAD FAILED: Invalid Slack message type: ${globals.config.get( + `[QSCLOUD] SLACK ALERT - APP RELOAD FAILED: Invalid Slack message type: ${globals.config.get( 'Butler.qlikSenseCloud.event.mqtt.tenant.alert.slackNotification.reloadAppFailure.messageType', )}`, ); @@ -53,7 +54,7 @@ function getAppReloadFailedSlackConfig() { // Basic formatting. Make sure requried parameters are present if (!globals.config.has('Butler.qlikSenseCloud.event.mqtt.tenant.alert.slackNotification.reloadAppFailure.basicMsgTemplate')) { // No message text in config file. - globals.logger.error('SLACK ALERT - QS CLOUD APP RELOAD FAILED: No message text in config file.'); + globals.logger.error('[QSCLOUD] SLACK ALERT - APP RELOAD FAILED: No message text in config file.'); return false; } } else if ( @@ -62,7 +63,7 @@ function getAppReloadFailedSlackConfig() { ) { // Extended formatting using Slack blocks. Make sure requried parameters are present if (!globals.config.has('Butler.qlikSenseCloud.event.mqtt.tenant.alert.slackNotification.reloadAppFailure.templateFile')) { - globals.logger.error('SLACK ALERT - QS CLOUD APP RELOAD FAILED: Message template file not specified in config file.'); + globals.logger.error('[QSCLOUD] SLACK ALERT - APP RELOAD FAILED: Message template file not specified in config file.'); return false; } } @@ -89,7 +90,7 @@ function getAppReloadFailedSlackConfig() { channel: globals.config.get('Butler.qlikSenseCloud.event.mqtt.tenant.alert.slackNotification.reloadAppFailure.channel'), }; } catch (err) { - globals.logger.error(`SLACK ALERT - QS CLOUD APP RELOAD FAILED: ${err}`); + globals.logger.error(`[QSCLOUD] SLACK ALERT - APP RELOAD FAILED: ${err}`); return false; } } @@ -161,16 +162,24 @@ async function sendSlack(slackConfig, templateContext, msgType) { if (msgType === 'reload') { // Escape any back slashes in the script logs const regExpText = /(?!\\n)\\{1}/gm; - globals.logger.debug(`SLACK SEND: Script log head escaping: ${regExpText.exec(templateContext.scriptLogHead)}`); - globals.logger.debug(`SLACK SEND: Script log tail escaping: ${regExpText.exec(templateContext.scriptLogTail)}`); + globals.logger.debug( + `[QSCLOUD] SLACK SEND: Script log head escaping: ${regExpText.exec(templateContext.scriptLogHead)}`, + ); + globals.logger.debug( + `[QSCLOUD] SLACK SEND: Script log tail escaping: ${regExpText.exec(templateContext.scriptLogTail)}`, + ); templateContext.scriptLogHead = templateContext.scriptLogHead.replace(regExpText, '\\\\'); templateContext.scriptLogTail = templateContext.scriptLogTail.replace(regExpText, '\\\\'); } else if (msgType === 'qscloud-app-reload') { // Escape any back slashes in the script logs const regExpText = /(?!\\n)\\{1}/gm; - globals.logger.debug(`SLACK SEND: Script log head escaping: ${regExpText.exec(templateContext.scriptLogHead)}`); - globals.logger.debug(`SLACK SEND: Script log tail escaping: ${regExpText.exec(templateContext.scriptLogTail)}`); + globals.logger.debug( + `[QSCLOUD] SLACK SEND: Script log head escaping: ${regExpText.exec(templateContext.scriptLogHead)}`, + ); + globals.logger.debug( + `[QSCLOUD] SLACK SEND: Script log tail escaping: ${regExpText.exec(templateContext.scriptLogTail)}`, + ); templateContext.scriptLogHead = templateContext.scriptLogHead.replace(regExpText, '\\\\'); templateContext.scriptLogTail = templateContext.scriptLogTail.replace(regExpText, '\\\\'); @@ -178,12 +187,12 @@ async function sendSlack(slackConfig, templateContext, msgType) { slackMsg = compiledTemplate(templateContext); - globals.logger.debug(`SLACK SEND: Rendered message:\n${slackMsg}`); + globals.logger.debug(`[QSCLOUD] SLACK SEND: Rendered message:\n${slackMsg}`); } else { - globals.logger.error(`SLACK SEND: Could not open Slack template file ${slackConfig.templateFile}.`); + globals.logger.error(`[QSCLOUD] SLACK SEND: Could not open Slack template file ${slackConfig.templateFile}.`); } } catch (err) { - globals.logger.error(`SLACK SEND: Error processing Slack template file: ${err}`); + globals.logger.error(`[QSCLOUD] SLACK SEND: Error processing Slack template file: ${err}`); } } @@ -192,11 +201,13 @@ async function sendSlack(slackConfig, templateContext, msgType) { const res = await slackSend(slackConfig, globals.logger); if (res !== undefined) { - globals.logger.debug(`SLACK SEND: Result from calling SlackApi.SlackSend: ${res.statusText} (${res.status}): ${res.data}`); + globals.logger.debug( + `[QSCLOUD] SLACK SEND: Result from calling SlackApi.SlackSend: ${res.statusText} (${res.status}): ${res.data}`, + ); } } } catch (err) { - globals.logger.error(`SLACK SEND: ${err}`); + globals.logger.error(`[QSCLOUD] SLACK SEND: ${err}`); } } @@ -207,10 +218,10 @@ export function sendQlikSenseCloudAppReloadFailureNotificationSlack(reloadParams .then(async (rateLimiterRes) => { try { globals.logger.info( - `SLACK ALERT - QS CLOUD APP RELOAD FAILED: Rate limiting check passed for failed task notification. App name: "${reloadParams.appName}"`, + `[QSCLOUD] SLACK ALERT - APP RELOAD FAILED: Rate limiting check passed for failed task notification. App name: "${reloadParams.appName}"`, ); globals.logger.verbose( - `SLACK ALERT - QS CLOUD APP RELOAD FAILED: Rate limiting details "${JSON.stringify(rateLimiterRes, null, 2)}"`, + `[QSCLOUD] SLACK ALERT - APP RELOAD FAILED: Rate limiting details "${JSON.stringify(rateLimiterRes, null, 2)}"`, ); // Make sure Slack sending is enabled in the config file and that we have all required settings @@ -229,7 +240,7 @@ export function sendQlikSenseCloudAppReloadFailureNotificationSlack(reloadParams if (reloadParams.scriptLog === false) { scriptLogData = { scriptLogFull: [], - scriptLogSize: 0, + scriptLogSizeRows: 0, scriptLogHead: '', scriptLogHeadCount: 0, scriptLogTail: '', @@ -245,25 +256,30 @@ export function sendQlikSenseCloudAppReloadFailureNotificationSlack(reloadParams ); if (reloadParams.scriptLog?.scriptLogFull?.length > 0) { - // Get length of script log (character count) - scriptLogData.scriptLogSize = reloadParams.scriptLog.scriptLogFull.length; - - // Get the first and last n lines of the script log - scriptLogData.scriptLogHead = reloadParams.scriptLog.scriptLogFull - .slice(0, reloadParams.scriptLog.scriptLogHeadCount) - .join('\r\n'); - - scriptLogData.scriptLogTail = reloadParams.scriptLog.scriptLogFull - .slice(Math.max(reloadParams.scriptLog.scriptLogFull.length - reloadParams.scriptLog.scriptLogTailCount, 0)) - .join('\r\n'); + // Get length of entire script log (character count) + scriptLogData.scriptLogSizeCharacters = reloadParams.scriptLog.scriptLogFull.join('').length; + + // Get length of script log (row count) + scriptLogData.scriptLogSizeRows = reloadParams.scriptLog.scriptLogFull.length; + + // Get the first and last rows of the script log + scriptLogData.scriptLogHead = getQlikSenseCloudAppReloadScriptLogHead( + reloadParams.scriptLog.scriptLogFull, + scriptLogData.scriptLogHeadCount, + ); + scriptLogData.scriptLogTail = getQlikSenseCloudAppReloadScriptLogTail( + reloadParams.scriptLog.scriptLogFull, + scriptLogData.scriptLogTailCount, + ); } else { scriptLogData.scriptLogHead = ''; scriptLogData.scriptLogTail = ''; - scriptLogData.scriptLogSize = 0; + scriptLogData.scriptLogSizeRows = 0; + scriptLogData.scriptLogSizeCharacters = 0; } globals.logger.debug( - `SLACK ALERT - QS CLOUD APP RELOAD FAILED: Script log data:\n${JSON.stringify(scriptLogData, null, 2)}`, + `[QSCLOUD] SLACK ALERT - APP RELOAD FAILED: Script log data:\n${JSON.stringify(scriptLogData, null, 2)}`, ); } @@ -324,7 +340,9 @@ export function sendQlikSenseCloudAppReloadFailureNotificationSlack(reloadParams executionStartTime: reloadParams.reloadInfo.executionStartTime, executionStopTime: reloadParams.reloadInfo.executionStopTime, executionStatusText: reloadParams.reloadInfo.status, - scriptLogSize: scriptLogData.scriptLogSize.toLocaleString(), + scriptLogSize: scriptLogData.scriptLogSizeRows.toLocaleString(), + scriptLogSizeRows: scriptLogData.scriptLogSizeRows.toLocaleString(), + scriptLogSizeCharacters: scriptLogData.scriptLogSizeCharacters.toLocaleString(), scriptLogHead: scriptLogData.scriptLogHead .replace(/([\r])/gm, '') .replace(/([\n])/gm, '\\n') @@ -408,16 +426,16 @@ export function sendQlikSenseCloudAppReloadFailureNotificationSlack(reloadParams sendSlack(slackConfig, templateContext, 'qscloud-app-reload'); } catch (err) { - globals.logger.error(`SLACK ALERT - QS CLOUD APP RELOAD FAILED: ${err}`); + globals.logger.error(`[QSCLOUD] SLACK ALERT - APP RELOAD FAILED: ${err}`); } return true; }) .catch((rateLimiterRes) => { globals.logger.warn( - `SLACK ALERT - QS CLOUD APP RELOAD FAILED: Rate limiting failed. Not sending reload notification Slack for app [${reloadParams.appId}] "${reloadParams.appName}"`, + `[QSCLOUD] SLACK ALERT - APP RELOAD FAILED: Rate limiting failed. Not sending reload notification Slack for app [${reloadParams.appId}] "${reloadParams.appName}"`, ); globals.logger.debug( - `SLACK ALERT - QS CLOUD APP RELOAD FAILED: Rate limiting details "${JSON.stringify(rateLimiterRes, null, 2)}"`, + `[QSCLOUD] SLACK ALERT - APP RELOAD FAILED: Rate limiting details "${JSON.stringify(rateLimiterRes, null, 2)}"`, ); }); } diff --git a/src/lib/qseow/msteams_notification.js b/src/lib/qseow/msteams_notification.js index d1961465..dfb1fa34 100644 --- a/src/lib/qseow/msteams_notification.js +++ b/src/lib/qseow/msteams_notification.js @@ -53,7 +53,7 @@ function getTeamsReloadFailedNotificationConfigOk() { if (!globals.config.get('Butler.teamsNotification.reloadTaskFailure.enable')) { // Teams task falure notifications are disabled globals.logger.error( - "TEAMS RELOAD TASK FAILED: Reload failure Teams notifications are disabled in config file - won't send Teams message", + '[QSEOW] TEAMS RELOAD TASK FAILED: Reload failure Teams notifications are disabled in config file - will not send Teams message', ); return false; } @@ -64,7 +64,7 @@ function getTeamsReloadFailedNotificationConfigOk() { ) { // Invalid Teams message type globals.logger.error( - `TEAMS RELOAD TASK FAILED: Invalid Teams message type: ${globals.config.get( + `[QSEOW] TEAMS RELOAD TASK FAILED: Invalid Teams message type: ${globals.config.get( 'Butler.teamsNotification.reloadTaskFailure.messageType', )}`, ); @@ -75,13 +75,13 @@ function getTeamsReloadFailedNotificationConfigOk() { // Basic formatting. Make sure requried parameters are present if (!globals.config.has('Butler.teamsNotification.reloadTaskFailure.basicMsgTemplate')) { // No message text in config file. - globals.logger.error('TEAMS RELOAD TASK FAILED: No message text in config file.'); + globals.logger.error('[QSEOW] TEAMS RELOAD TASK FAILED: No message text in config file.'); return false; } } else if (globals.config.get('Butler.teamsNotification.reloadTaskFailure.messageType') === 'formatted') { // Extended formatting using Teams blocks. Make sure requried parameters are present if (!globals.config.has('Butler.teamsNotification.reloadTaskFailure.templateFile')) { - globals.logger.error('TEAMS RELOAD TASK FAILED: Message template file not specified in config file.'); + globals.logger.error('[QSEOW] TEAMS RELOAD TASK FAILED: Message template file not specified in config file.'); return false; } } @@ -105,7 +105,7 @@ function getTeamsReloadFailedNotificationConfigOk() { : '', }; } catch (err) { - globals.logger.error(`TEAMS RELOAD TASK FAILED: ${err}`); + globals.logger.error(`[QSEOW] TEAMS RELOAD TASK FAILED: ${err}`); return false; } } @@ -115,7 +115,7 @@ function getTeamsReloadAbortedNotificationConfigOk() { if (!globals.config.get('Butler.teamsNotification.reloadTaskAborted.enable')) { // Teams task aborted notifications are disabled globals.logger.error( - "TEAMS RELOAD TASK ABORTED: Reload aborted Teams notifications are disabled in config file - won't send Teams message", + '[QSEOW] TEAMS RELOAD TASK ABORTED: Reload aborted Teams notifications are disabled in config file - will not send Teams message', ); return false; } @@ -126,7 +126,7 @@ function getTeamsReloadAbortedNotificationConfigOk() { ) { // Invalid Teams message type globals.logger.error( - `TEAMS RELOAD TASK ABORTED: Invalid Teams message type: ${globals.config.get( + `[QSEOW] TEAMS RELOAD TASK ABORTED: Invalid Teams message type: ${globals.config.get( 'Butler.teamsNotification.reloadTaskAborted.messageType', )}`, ); @@ -137,13 +137,13 @@ function getTeamsReloadAbortedNotificationConfigOk() { // Basic formatting. Make sure requried parameters are present if (!globals.config.has('Butler.teamsNotification.reloadTaskAborted.basicMsgTemplate')) { // No message text in config file. - globals.logger.error('TEAMS RELOAD TASK ABORTED: No message text in config file.'); + globals.logger.error('[QSEOW] TEAMS RELOAD TASK ABORTED: No message text in config file.'); return false; } } else if (globals.config.get('Butler.teamsNotification.reloadTaskAborted.messageType') === 'formatted') { // Extended formatting using Teams blocks. Make sure requried parameters are present if (!globals.config.has('Butler.teamsNotification.reloadTaskAborted.templateFile')) { - globals.logger.error('TEAMS RELOAD TASK ABORTED: Message template file not specified in config file.'); + globals.logger.error('[QSEOW] TEAMS RELOAD TASK ABORTED: Message template file not specified in config file.'); return false; } } @@ -170,7 +170,7 @@ function getTeamsReloadAbortedNotificationConfigOk() { : '', }; } catch (err) { - globals.logger.error(`TEAMS RELOAD TASK ABORTED: ${err}`); + globals.logger.error(`[QSEOW] TEAMS RELOAD TASK ABORTED: ${err}`); return false; } } @@ -180,7 +180,7 @@ function getTeamsServiceMonitorNotificationConfig(serviceStatus) { if (!globals.config.get('Butler.serviceMonitor.alertDestination.teams.enable')) { // Teams notifications are disabled globals.logger.error( - "TEAMS SERVICE MONITOR: TEAMS SERVICE MONITOR notifications are disabled in config file - won't send Teams message", + '[QSEOW] TEAMS SERVICE MONITOR: TEAMS SERVICE MONITOR notifications are disabled in config file - will not send Teams message', ); return false; } @@ -191,7 +191,7 @@ function getTeamsServiceMonitorNotificationConfig(serviceStatus) { ) { // Invalid Teams message type globals.logger.error( - `TEAMS SERVICE MONITOR: Invalid Teams message type: ${globals.config.get( + `[QSEOW] TEAMS SERVICE MONITOR: Invalid Teams message type: ${globals.config.get( 'Butler.teamsNotification.serviceStopped.messageType', )}`, ); @@ -204,7 +204,7 @@ function getTeamsServiceMonitorNotificationConfig(serviceStatus) { ) { // Invalid Teams message type globals.logger.error( - `TEAMS SERVICE MONITOR: Invalid Teams message type: ${globals.config.get( + `[QSEOW] TEAMS SERVICE MONITOR: Invalid Teams message type: ${globals.config.get( 'Butler.teamsNotification.serviceStopped.messageType', )}`, ); @@ -215,13 +215,13 @@ function getTeamsServiceMonitorNotificationConfig(serviceStatus) { // Basic formatting. Make sure requried parameters are present if (!globals.config.has('Butler.teamsNotification.serviceStopped.basicMsgTemplate')) { // No message text in config file. - globals.logger.error('TEAMS SERVICE MONITOR: No service stopped basic message text in config file.'); + globals.logger.error('[QSEOW] TEAMS SERVICE MONITOR: No service stopped basic message text in config file.'); return false; } } else if (globals.config.get('Butler.teamsNotification.serviceStopped.messageType') === 'formatted') { // Extended formatting using Teams blocks. Make sure requried parameters are present if (!globals.config.has('Butler.teamsNotification.serviceStopped.templateFile')) { - globals.logger.error('TEAMS SERVICE MONITOR: Service stopped message template file not specified in config file.'); + globals.logger.error('[QSEOW] TEAMS SERVICE MONITOR: Service stopped message template file not specified in config file.'); return false; } } @@ -230,13 +230,13 @@ function getTeamsServiceMonitorNotificationConfig(serviceStatus) { // Basic formatting. Make sure requried parameters are present if (!globals.config.has('Butler.teamsNotification.serviceStarted.basicMsgTemplate')) { // No message text in config file. - globals.logger.error('TEAMS SERVICE MONITOR: No service started basic message text in config file.'); + globals.logger.error('[QSEOW] TEAMS SERVICE MONITOR: No service started basic message text in config file.'); return false; } } else if (globals.config.get('Butler.teamsNotification.serviceStarted.messageType') === 'formatted') { // Extended formatting using Teams blocks. Make sure requried parameters are present if (!globals.config.has('Butler.teamsNotification.serviceStarted.templateFile')) { - globals.logger.error('TEAMS SERVICE MONITOR: Service started message template file not specified in config file.'); + globals.logger.error('[QSEOW] TEAMS SERVICE MONITOR: Service started message template file not specified in config file.'); return false; } } @@ -281,7 +281,7 @@ function getTeamsServiceMonitorNotificationConfig(serviceStatus) { return result; } catch (err) { - globals.logger.error(`TEAMS SERVICE MONITOR: ${err}`); + globals.logger.error(`[QSEOW] TEAMS SERVICE MONITOR: ${err}`); return false; } } @@ -339,8 +339,12 @@ async function sendTeams(teamsWebhookUrl, teamsConfig, templateContext, msgType) if (msgType === 'reload') { // Escape any back slashes in the script logs const regExpText = /(?!\\n)\\{1}/gm; - globals.logger.debug(`TEAMS SEND: Script log head escaping: ${regExpText.exec(templateContext.scriptLogHead)}`); - globals.logger.debug(`TEAMS SEND: Script log tail escaping: ${regExpText.exec(templateContext.scriptLogTail)}`); + globals.logger.debug( + `[QSEOW] TEAMS SEND: Script log head escaping: ${regExpText.exec(templateContext.scriptLogHead)}`, + ); + globals.logger.debug( + `[QSEOW] TEAMS SEND: Script log tail escaping: ${regExpText.exec(templateContext.scriptLogTail)}`, + ); templateContext.scriptLogHead = templateContext.scriptLogHead.replace(regExpText, '\\\\'); templateContext.scriptLogTail = templateContext.scriptLogTail.replace(regExpText, '\\\\'); @@ -348,15 +352,15 @@ async function sendTeams(teamsWebhookUrl, teamsConfig, templateContext, msgType) renderedText = compiledTemplate(templateContext); - globals.logger.debug(`TEAMS SEND: Rendered message:\n${renderedText}`); + globals.logger.debug(`[QSEOW] TEAMS SEND: Rendered message:\n${renderedText}`); // Parse the JSON string to get rid of extra linebreaks etc. msg = JSON.parse(renderedText); } else { - globals.logger.error(`TEAMS SEND: Could not open Teams template file ${teamsConfig.templateFile}.`); + globals.logger.error(`[QSEOW] TEAMS SEND: Could not open Teams template file ${teamsConfig.templateFile}.`); } } catch (err) { - globals.logger.error(`TEAMS SEND: Error processing Teams template file: ${err}`); + globals.logger.error(`[QSEOW] TEAMS SEND: Error processing Teams template file: ${err}`); } } @@ -365,11 +369,13 @@ async function sendTeams(teamsWebhookUrl, teamsConfig, templateContext, msgType) const res = await webhook.sendMessage(); if (res !== undefined) { - globals.logger.debug(`TEAMS SEND: Result from calling TeamsApi.TeamsSend: ${res.statusText} (${res.status}): ${res.data}`); + globals.logger.debug( + `[QSEOW] TEAMS SEND: Result from calling TeamsApi.TeamsSend: ${res.statusText} (${res.status}): ${res.data}`, + ); } } } catch (err) { - globals.logger.error(`TEAMS SEND: ${err}`); + globals.logger.error(`[QSEOW] TEAMS SEND: ${err}`); } } @@ -379,9 +385,11 @@ export function sendReloadTaskFailureNotificationTeams(reloadParams) { .then(async (rateLimiterRes) => { try { globals.logger.info( - `TEAMS RELOAD TASK FAILED: Rate limiting check passed for failed task notification. Task name: "${reloadParams.taskName}"`, + `[QSEOW] TEAMS RELOAD TASK FAILED: Rate limiting check passed for failed task notification. Task name: "${reloadParams.taskName}"`, + ); + globals.logger.verbose( + `[QSEOW] TEAMS RELOAD TASK FAILED: Rate limiting details "${JSON.stringify(rateLimiterRes, null, 2)}"`, ); - globals.logger.verbose(`TEAMS RELOAD TASK FAILED: Rate limiting details "${JSON.stringify(rateLimiterRes, null, 2)}"`); // Make sure Teams sending is enabled in the config file and that we have all required settings const teamsConfig = getTeamsReloadFailedNotificationConfigOk(); @@ -410,7 +418,7 @@ export function sendReloadTaskFailureNotificationTeams(reloadParams) { scriptLogData.scriptLogTail = ''; } - globals.logger.debug(`TEAMS RELOAD TASK FAILED: Script log data:\n${JSON.stringify(scriptLogData, null, 2)}`); + globals.logger.debug(`[QSEOW] TEAMS RELOAD TASK FAILED: Script log data:\n${JSON.stringify(scriptLogData, null, 2)}`); // Get Sense URLs from config file. Can be used as template fields. const senseUrls = getQlikSenseUrls(); @@ -500,7 +508,7 @@ export function sendReloadTaskFailureNotificationTeams(reloadParams) { // Check if script log is longer than 3000 characters. Truncate if so. if (templateContext.scriptLogHead.length >= 3000) { globals.logger.warn( - `TEAMS: Script log head field is too long (${templateContext.scriptLogHead.length}), will truncate before posting to Teams.`, + `[QSEOW] TEAMS: Script log head field is too long (${templateContext.scriptLogHead.length}), will truncate before posting to Teams.`, ); templateContext.scriptLogHead = templateContext.scriptLogHead .replaceAll('&', '&') @@ -524,7 +532,7 @@ export function sendReloadTaskFailureNotificationTeams(reloadParams) { if (templateContext.scriptLogTail.length >= 3000) { globals.logger.warn( - `TEAMS: Script log head field is too long (${templateContext.scriptLogTail.length}), will truncate before posting to Teams.`, + `[QSEOW] TEAMS: Script log head field is too long (${templateContext.scriptLogTail.length}), will truncate before posting to Teams.`, ); templateContext.scriptLogTail = templateContext.scriptLogTail .replaceAll('&', '&') @@ -549,15 +557,15 @@ export function sendReloadTaskFailureNotificationTeams(reloadParams) { const webhookUrl = globals.config.get('Butler.teamsNotification.reloadTaskFailure.webhookURL'); sendTeams(webhookUrl, teamsConfig, templateContext, 'reload'); } catch (err) { - globals.logger.error(`TEAMS RELOAD TASK FAILED: ${err}`); + globals.logger.error(`[QSEOW] TEAMS RELOAD TASK FAILED: ${err}`); } return true; }) .catch((rateLimiterRes) => { globals.logger.warn( - `TEAMS RELOAD TASK FAILED: Rate limiting failed. Not sending reload notification Teams for task "${reloadParams.taskName}"`, + `[QSEOW] TEAMS RELOAD TASK FAILED: Rate limiting failed. Not sending reload notification Teams for task "${reloadParams.taskName}"`, ); - globals.logger.debug(`TEAMS RELOAD TASK FAILED: Rate limiting details "${JSON.stringify(rateLimiterRes, null, 2)}"`); + globals.logger.debug(`[QSEOW] TEAMS RELOAD TASK FAILED: Rate limiting details "${JSON.stringify(rateLimiterRes, null, 2)}"`); }); } @@ -567,9 +575,11 @@ export function sendReloadTaskAbortedNotificationTeams(reloadParams) { .then(async (rateLimiterRes) => { try { globals.logger.info( - `TEAMS RELOAD TASK ABORTED: Rate limiting check passed for aborted task notification. Task name: "${reloadParams.taskName}"`, + `[QSEOW] TEAMS RELOAD TASK ABORTED: Rate limiting check passed for aborted task notification. Task name: "${reloadParams.taskName}"`, + ); + globals.logger.verbose( + `[QSEOW] TEAMS RELOAD TASK ABORTED: Rate limiting details "${JSON.stringify(rateLimiterRes, null, 2)}"`, ); - globals.logger.verbose(`TEAMS RELOAD TASK ABORTED: Rate limiting details "${JSON.stringify(rateLimiterRes, null, 2)}"`); // Make sure Teams sending is enabled in the config file and that we have all required settings const teamsConfig = getTeamsReloadAbortedNotificationConfigOk(); @@ -597,7 +607,7 @@ export function sendReloadTaskAbortedNotificationTeams(reloadParams) { scriptLogData.scriptLogTail = ''; } - globals.logger.debug(`TEAMS RELOAD TASK ABORTED: Script log data:\n${JSON.stringify(scriptLogData, null, 2)}`); + globals.logger.debug(`[QSEOW] TEAMS RELOAD TASK ABORTED: Script log data:\n${JSON.stringify(scriptLogData, null, 2)}`); // Get Sense URLs from config file. Can be used as template fields. const senseUrls = getQlikSenseUrls(); @@ -665,6 +675,8 @@ export function sendReloadTaskAbortedNotificationTeams(reloadParams) { .replace(/([\n])/gm, '\\n') .replace(/([\t])/gm, '\\t'), scriptLogSize: scriptLogData.scriptLogSize, + scriptLogSizeRows: scriptLogData.scriptLogSizeRows, + scriptLogSizeCharacters: scriptLogData.scriptLogSizeCharacters, scriptLogHead: scriptLogData.scriptLogHead .replace(/([\r])/gm, '') .replace(/([\n])/gm, '\\n') @@ -687,7 +699,7 @@ export function sendReloadTaskAbortedNotificationTeams(reloadParams) { // Check if script log is longer than 3000 characters. Truncate if so. if (templateContext.scriptLogHead.length >= 3000) { globals.logger.warn( - `TEAMS: Script log head field is too long (${templateContext.scriptLogHead.length}), will truncate before posting to Teams.`, + `[QSEOW] TEAMS: Script log head field is too long (${templateContext.scriptLogHead.length}), will truncate before posting to Teams.`, ); templateContext.scriptLogHead = templateContext.scriptLogHead .replaceAll('&', '&') @@ -711,7 +723,7 @@ export function sendReloadTaskAbortedNotificationTeams(reloadParams) { if (templateContext.scriptLogTail.length >= 3000) { globals.logger.warn( - `TEAMS: Script log head field is too long (${templateContext.scriptLogTail.length}), will truncate before posting to Teams.`, + `[QSEOW] TEAMS: Script log head field is too long (${templateContext.scriptLogTail.length}), will truncate before posting to Teams.`, ); templateContext.scriptLogTail = templateContext.scriptLogTail .replaceAll('&', '&') @@ -736,15 +748,15 @@ export function sendReloadTaskAbortedNotificationTeams(reloadParams) { const webhookUrl = globals.config.get('Butler.teamsNotification.reloadTaskAborted.webhookURL'); sendTeams(webhookUrl, teamsConfig, templateContext, 'reload'); } catch (err) { - globals.logger.error(`TEAMS RELOAD TASK ABORTED: ${err}`); + globals.logger.error(`[QSEOW] TEAMS RELOAD TASK ABORTED: ${err}`); } return true; }) .catch((rateLimiterRes) => { globals.logger.verbose( - `TEAMS RELOAD TASK ABORTED: Rate limiting failed. Not sending reload notification Teams for task "${reloadParams.taskName}"`, + `[QSEOW] TEAMS RELOAD TASK ABORTED: Rate limiting failed. Not sending reload notification Teams for task "${reloadParams.taskName}"`, ); - globals.logger.verbose(`TEAMS RELOAD TASK ABORTED: Rate limiting details "${JSON.stringify(rateLimiterRes, null, 2)}"`); + globals.logger.verbose(`[QSEOW] TEAMS RELOAD TASK ABORTED: Rate limiting details "${JSON.stringify(rateLimiterRes, null, 2)}"`); }); } @@ -754,9 +766,9 @@ export function sendServiceMonitorNotificationTeams(serviceParams) { .then(async (rateLimiterRes) => { try { globals.logger.info( - `TEAMS SERVICE MONITOR: Rate limiting check passed for service monitor notification. Host: "${serviceParams.host}", service: "${serviceParams.serviceName}"`, + `[QSEOW] TEAMS SERVICE MONITOR: Rate limiting check passed for service monitor notification. Host: "${serviceParams.host}", service: "${serviceParams.serviceName}"`, ); - globals.logger.verbose(`TEAMS SERVICE MONITOR: Rate limiting details "${JSON.stringify(rateLimiterRes, null, 2)}"`); + globals.logger.verbose(`[QSEOW] TEAMS SERVICE MONITOR: Rate limiting details "${JSON.stringify(rateLimiterRes, null, 2)}"`); // Make sure Teams sending is enabled in the config file and that we have all required settings const teamsConfig = getTeamsServiceMonitorNotificationConfig(serviceParams.serviceStatus); @@ -792,14 +804,14 @@ export function sendServiceMonitorNotificationTeams(serviceParams) { sendTeams(webhookUrl, teamsConfig, templateContext, 'serviceStarted'); } } catch (err) { - globals.logger.error(`TEAMS SERVICE MONITOR: ${err}`); + globals.logger.error(`[QSEOW] TEAMS SERVICE MONITOR: ${err}`); } return true; }) .catch((rateLimiterRes) => { globals.logger.verbose( - `TEAMS SERVICE MONITOR: Rate limiting failed. Not sending service monitor notification for service "${serviceParams.serviceName}" on host "${serviceParams.host}"`, + `[QSEOW] TEAMS SERVICE MONITOR: Rate limiting failed. Not sending service monitor notification for service "${serviceParams.serviceName}" on host "${serviceParams.host}"`, ); - globals.logger.verbose(`TEAMS SERVICE MONITOR: Rate limiting details "${JSON.stringify(rateLimiterRes, null, 2)}"`); + globals.logger.verbose(`[QSEOW] TEAMS SERVICE MONITOR: Rate limiting details "${JSON.stringify(rateLimiterRes, null, 2)}"`); }); } diff --git a/src/lib/qseow/qliksense_license.js b/src/lib/qseow/qliksense_license.js index a2172296..e59b2aaf 100644 --- a/src/lib/qseow/qliksense_license.js +++ b/src/lib/qseow/qliksense_license.js @@ -7,7 +7,7 @@ import { postQlikSenseLicenseReleasedToInfluxDB, postQlikSenseServerLicenseStatusToInfluxDB, } from '../post_to_influxdb.js'; -import { callQlikSenseServerLicenseWebhook } from '../webhook_notification.js'; +import { callQlikSenseServerLicenseWebhook } from './webhook_notification.js'; // Function to check Qlik Sense server license status async function checkQlikSenseServerLicenseStatus(config, logger) { @@ -32,12 +32,12 @@ async function checkQlikSenseServerLicenseStatus(config, logger) { // Is status code 200 or body is empty? if (result.statusCode !== 200 || !result.body) { - logger.error(`QLIKSENSE SERVER LICENSE MONITOR: HTTP status code ${result.statusCode}`); + logger.error(`[QSEOW] QLIKSENSE SERVER LICENSE MONITOR: HTTP status code ${result.statusCode}`); return; } // Debug log - logger.debug(`QLIKSENSE SERVER LICENSE MONITOR: ${JSON.stringify(result.body)}`); + logger.debug(`[QSEOW] QLIKSENSE SERVER LICENSE MONITOR: ${JSON.stringify(result.body)}`); // Returned icense JSON has the following structure: // { @@ -103,14 +103,16 @@ async function checkQlikSenseServerLicenseStatus(config, logger) { // Use warn logging if days until expiry is less than value specified in config file, // otherwise use info logging if (daysUntilExpiry !== null && expiryDateStr !== null && licenseExpired !== null) { - globals.logger.info(`QLIK SENSE SERVER LICENSE: License expired: ${licenseExpired}`); + globals.logger.info(`[QSEOW] QLIK SENSE SERVER LICENSE: License expired: ${licenseExpired}`); if (daysUntilExpiry <= globals.config.get('Butler.qlikSenseLicense.serverLicenseMonitor.alert.thresholdDays')) { - globals.logger.warn(`QLIK SENSE SERVER LICENSE: Qlik Sense server license is about to expire in ${daysUntilExpiry} days!`); - globals.logger.warn(`QLIK SENSE SERVER LICENSE: Expiry date: ${expiryDate}`); + globals.logger.warn( + `[QSEOW] QLIK SENSE SERVER LICENSE: Qlik Sense server license is about to expire in ${daysUntilExpiry} days!`, + ); + globals.logger.warn(`[QSEOW] QLIK SENSE SERVER LICENSE: Expiry date: ${expiryDate}`); } else { - globals.logger.info(`QLIK SENSE SERVER LICENSE: Qlik Sense server license expiry in ${daysUntilExpiry} days`); - globals.logger.info(`QLIK SENSE SERVER LICENSE: Expiry date: ${expiryDate}`); + globals.logger.info(`[QSEOW] QLIK SENSE SERVER LICENSE: Qlik Sense server license expiry in ${daysUntilExpiry} days`); + globals.logger.info(`[QSEOW] QLIK SENSE SERVER LICENSE: Expiry date: ${expiryDate}`); } } @@ -193,9 +195,9 @@ async function checkQlikSenseServerLicenseStatus(config, logger) { } } } catch (err) { - logger.error(`QLIKSENSE SERVER LICENSE MONITOR: ${err}`); + logger.error(`[QSEOW] QLIKSENSE SERVER LICENSE MONITOR: ${err}`); if (err.stack) { - logger.error(`QLIKSENSE SERVER LICENSE MONITOR: ${err.stack}`); + logger.error(`[QSEOW] QLIKSENSE SERVER LICENSE MONITOR: ${err.stack}`); } } } @@ -223,12 +225,12 @@ async function checkQlikSenseAccessLicenseStatus(config, logger) { // Is status code 200 or body is empty? if (result1.statusCode !== 200 || !result1.body) { - logger.error(`QLIKSENSE LICENSE MONITOR: HTTP status code ${result1.statusCode}`); + logger.error(`[QSEOW] QLIKSENSE LICENSE MONITOR: HTTP status code ${result1.statusCode}`); return; } // Debug log - logger.debug(`QLIKSENSE LICENSE MONITOR: ${JSON.stringify(result1.body)}`); + logger.debug(`[QSEOW] QLIKSENSE LICENSE MONITOR: ${JSON.stringify(result1.body)}`); // To which destination should we send the license information? // Check InfluDB first @@ -240,9 +242,9 @@ async function checkQlikSenseAccessLicenseStatus(config, logger) { await postQlikSenseLicenseStatusToInfluxDB(result1.body); } } catch (err) { - logger.error(`QLIKSENSE LICENSE MONITOR: ${err}`); + logger.error(`[QSEOW] QLIKSENSE LICENSE MONITOR: ${err}`); if (err.stack) { - logger.error(`QLIKSENSE LICENSE MONITOR: ${err.stack}`); + logger.error(`[QSEOW] QLIKSENSE LICENSE MONITOR: ${err.stack}`); } } } @@ -262,25 +264,25 @@ async function licenseReleaseProfessional(config, logger, qrsInstance) { cutoffDate.setHours(23, 59, 59, 999); // verbose log, format dates as yyyy-mm-ddThh:mm:ss.sssZ - logger.verbose(`QLIKSENSE LICENSE RELEASE PROFESSIONAL: currentDate: ${currentDate.toISOString()}`); - logger.verbose(`QLIKSENSE LICENSE RELEASE PROFESSIONAL: releaseThresholdDays: ${releaseThresholdDays}`); - logger.verbose(`QLIKSENSE LICENSE RELEASE PROFESSIONAL: cutoffDate: ${cutoffDate.toISOString()}`); + logger.verbose(`[QSEOW] QLIKSENSE LICENSE RELEASE PROFESSIONAL: currentDate: ${currentDate.toISOString()}`); + logger.verbose(`[QSEOW] QLIKSENSE LICENSE RELEASE PROFESSIONAL: releaseThresholdDays: ${releaseThresholdDays}`); + logger.verbose(`[QSEOW] QLIKSENSE LICENSE RELEASE PROFESSIONAL: cutoffDate: ${cutoffDate.toISOString()}`); // Get all assigned professional licenses const url = `license/professionalaccesstype/full?filter=lastUsed le '${cutoffDate.toISOString()}'`; - logger.debug(`QLIKSENSE LICENSE RELEASE PROFESSIONAL: Query URL: ${url}`); + logger.debug(`[QSEOW] QLIKSENSE LICENSE RELEASE PROFESSIONAL: Query URL: ${url}`); const result1 = await qrsInstance.Get(url); // Is status code other than 200 or body is empty? if (result1.statusCode !== 200 || !result1.body) { logger.error( - `QLIKSENSE LICENSE RELEASE PROFESSIONAL: Could not get list of assigned professional licenses. HTTP status code ${result1.statusCode}`, + `[QSEOW] QLIKSENSE LICENSE RELEASE PROFESSIONAL: Could not get list of assigned professional licenses. HTTP status code ${result1.statusCode}`, ); return false; } // Debug log - logger.debug(`QLIKSENSE LICENSE RELEASE PROFESSIONAL: Assigned: ${JSON.stringify(result1.body)}`); + logger.debug(`[QSEOW] QLIKSENSE LICENSE RELEASE PROFESSIONAL: Assigned: ${JSON.stringify(result1.body)}`); // Determnine which allocated licenses to release. // Only release licenses that are NOT quarantined @@ -302,18 +304,18 @@ async function licenseReleaseProfessional(config, logger, qrsInstance) { const res = await qrsInstance.Get(`user/${license.user.id}`); if (res.statusCode !== 200 || !res.body) { logger.error( - `QLIKSENSE LICENSE RELEASE PROFESSIONAL: Failed getting user info for user [${license.user.id}] ${license.user.userDirectory}\\${license.user.userId}`, + `[QSEOW] QLIKSENSE LICENSE RELEASE PROFESSIONAL: Failed getting user info for user [${license.user.id}] ${license.user.userDirectory}\\${license.user.userId}`, ); return false; } currentUser = res.body; } catch (err) { logger.error( - `QLIKSENSE LICENSE RELEASE PROFESSIONAL: Failed getting user info for user [${license.user.id}] ${license.user.userDirectory}\\${license.user.userId}`, + `[QSEOW] QLIKSENSE LICENSE RELEASE PROFESSIONAL: Failed getting user info for user [${license.user.id}] ${license.user.userDirectory}\\${license.user.userId}`, ); if (err.stack) { logger.error( - `QLIKSENSE LICENSE RELEASE PROFESSIONAL: Failed getting user info for user [${license.user.id}] ${license.user.userDirectory}\\${license.user.userId}. ${err.stack}`, + `[QSEOW] QLIKSENSE LICENSE RELEASE PROFESSIONAL: Failed getting user info for user [${license.user.id}] ${license.user.userDirectory}\\${license.user.userId}. ${err.stack}`, ); } return false; @@ -470,7 +472,7 @@ async function licenseReleaseProfessional(config, logger, qrsInstance) { // Should currentUser be released? if (!doNotRelease) { logger.info( - `QLIKSENSE LICENSE RELEASE PROFESSIONAL: Adding user ${license.user.userDirectory}\\${license.user.userId} (days since last use: ${daysSinceLastUse}) to releaseProfessional array`, + `[QSEOW] QLIKSENSE LICENSE RELEASE PROFESSIONAL: Adding user ${license.user.userDirectory}\\${license.user.userId} (days since last use: ${daysSinceLastUse}) to releaseProfessional array`, ); releaseProfessional.push({ licenseId: license.id, @@ -480,14 +482,14 @@ async function licenseReleaseProfessional(config, logger, qrsInstance) { }); } else { logger.info( - `QLIKSENSE LICENSE RELEASE PROFESSIONAL: License for user ${license.user.userDirectory}\\${license.user.userId} not released because: ${doNotReleaseReason}`, + `[QSEOW] QLIKSENSE LICENSE RELEASE PROFESSIONAL: License for user ${license.user.userDirectory}\\${license.user.userId} not released because: ${doNotReleaseReason}`, ); } } } logger.verbose( - `QLIKSENSE LICENSE RELEASE PROFESSIONAL: Professional licenses to be released: ${JSON.stringify(releaseProfessional, null, 2)}`, + `[QSEOW] QLIKSENSE LICENSE RELEASE PROFESSIONAL: Professional licenses to be released: ${JSON.stringify(releaseProfessional, null, 2)}`, ); // Is license release dry-run enabled? If so, do not release any licenses @@ -498,7 +500,7 @@ async function licenseReleaseProfessional(config, logger, qrsInstance) { // eslint-disable-next-line no-restricted-syntax for (const licenseRelease of releaseProfessional) { logger.info( - `QLIKSENSE LICENSE RELEASE PROFESSIONAL: Releasing license for user ${licenseRelease.userDir}\\${licenseRelease.userId} (days since last use: ${licenseRelease.daysSinceLastUse})`, + `[QSEOW] QLIKSENSE LICENSE RELEASE PROFESSIONAL: Releasing license for user ${licenseRelease.userDir}\\${licenseRelease.userId} (days since last use: ${licenseRelease.daysSinceLastUse})`, ); // Release license @@ -507,12 +509,12 @@ async function licenseReleaseProfessional(config, logger, qrsInstance) { // Is status code 204? Error if it's nmt if (result2.statusCode !== 204) { - logger.error(`QLIKSENSE LICENSE RELEASE PROFESSIONAL: HTTP status code ${result2.statusCode}`); + logger.error(`[QSEOW] QLIKSENSE LICENSE RELEASE PROFESSIONAL: HTTP status code ${result2.statusCode}`); return false; } // Debug log - logger.debug(`QLIKSENSE LICENSE RELEASE PROFESSIONAL: ${JSON.stringify(result2.body)}`); + logger.debug(`[QSEOW] QLIKSENSE LICENSE RELEASE PROFESSIONAL: ${JSON.stringify(result2.body)}`); // Write info about released license to InfluxDB? if ( @@ -548,25 +550,25 @@ async function licenseReleaseAnalyzer(config, logger, qrsInstance) { cutoffDate.setHours(23, 59, 59, 999); // verbose log, format dates as yyyy-mm-ddThh:mm:ss.sssZ - logger.verbose(`QLIKSENSE LICENSE RELEASE ANALYZER: currentDate: ${currentDate.toISOString()}`); - logger.verbose(`QLIKSENSE LICENSE RELEASE ANALYZER: releaseThresholdDays: ${releaseThresholdDays}`); - logger.verbose(`QLIKSENSE LICENSE RELEASE ANALYZER: cutoffDate: ${cutoffDate.toISOString()}`); + logger.verbose(`[QSEOW] QLIKSENSE LICENSE RELEASE ANALYZER: currentDate: ${currentDate.toISOString()}`); + logger.verbose(`[QSEOW] QLIKSENSE LICENSE RELEASE ANALYZER: releaseThresholdDays: ${releaseThresholdDays}`); + logger.verbose(`[QSEOW] QLIKSENSE LICENSE RELEASE ANALYZER: cutoffDate: ${cutoffDate.toISOString()}`); // Get all assigned analyzer licenses const url = `license/analyzeraccesstype/full?filter=lastUsed le '${cutoffDate.toISOString()}'`; - logger.debug(`QLIKSENSE LICENSE RELEASE ANALYZER: Query URL: ${url}`); + logger.debug(`[QSEOW] QLIKSENSE LICENSE RELEASE ANALYZER: Query URL: ${url}`); const result3 = await qrsInstance.Get(url); // Is status code 200 or body is empty? if (result3.statusCode !== 200 || !result3.body) { logger.error( - `QLIKSENSE LICENSE RELEASE ANALYZER: Could not get list of assigned analyzer licenses. HTTP status code ${result3.statusCode}`, + `[QSEOW] QLIKSENSE LICENSE RELEASE ANALYZER: Could not get list of assigned analyzer licenses. HTTP status code ${result3.statusCode}`, ); return false; } // Debug log - logger.debug(`QLIKSENSE LICENSE RELEASE ANALYZER: Assigned: ${JSON.stringify(result3.body)}`); + logger.debug(`[QSEOW] QLIKSENSE LICENSE RELEASE ANALYZER: Assigned: ${JSON.stringify(result3.body)}`); // Determnine which allocated licenses to release. // Only release licenses that are NOT quarantined @@ -588,18 +590,18 @@ async function licenseReleaseAnalyzer(config, logger, qrsInstance) { const res = await qrsInstance.Get(`user/${license.user.id}`); if (res.statusCode !== 200 || !res.body) { logger.error( - `QLIKSENSE LICENSE RELEASE ANALYZER: Failed getting user info for user [${license.user.id}] ${license.user.userDirectory}\\${license.user.userId}`, + `[QSEOW] QLIKSENSE LICENSE RELEASE ANALYZER: Failed getting user info for user [${license.user.id}] ${license.user.userDirectory}\\${license.user.userId}`, ); return false; } currentUser = res.body; } catch (err) { logger.error( - `QLIKSENSE LICENSE RELEASE ANALYZER: Failed getting user info for user [${license.user.id}] ${license.user.userDirectory}\\${license.user.userId}`, + `[QSEOW] QLIKSENSE LICENSE RELEASE ANALYZER: Failed getting user info for user [${license.user.id}] ${license.user.userDirectory}\\${license.user.userId}`, ); if (err.stack) { logger.error( - `QLIKSENSE LICENSE RELEASE ANALYZER: Failed getting user info for user [${license.user.id}] ${license.user.userDirectory}\\${license.user.userId}. ${err.stack}`, + `[QSEOW] QLIKSENSE LICENSE RELEASE ANALYZER: Failed getting user info for user [${license.user.id}] ${license.user.userDirectory}\\${license.user.userId}. ${err.stack}`, ); } return false; @@ -750,7 +752,7 @@ async function licenseReleaseAnalyzer(config, logger, qrsInstance) { // Should currentUser be released? if (!doNotRelease) { logger.info( - `QLIKSENSE LICENSE RELEASE ANALYZER: Adding user ${license.user.userDirectory}\\${license.user.userId} (days since last use: ${daysSinceLastUse}) to releaseAnalyzer array`, + `[QSEOW] QLIKSENSE LICENSE RELEASE ANALYZER: Adding user ${license.user.userDirectory}\\${license.user.userId} (days since last use: ${daysSinceLastUse}) to releaseAnalyzer array`, ); releaseAnalyzer.push({ licenseId: license.id, @@ -760,23 +762,25 @@ async function licenseReleaseAnalyzer(config, logger, qrsInstance) { }); } else { logger.info( - `QLIKSENSE LICENSE RELEASE ANALYZER: License for user ${license.user.userDirectory}\\${license.user.userId} not released because: ${doNotReleaseReason}`, + `[QSEOW] QLIKSENSE LICENSE RELEASE ANALYZER: License for user ${license.user.userDirectory}\\${license.user.userId} not released because: ${doNotReleaseReason}`, ); } } } - logger.verbose(`QLIKSENSE LICENSE RELEASE ANALYZER: Analyzer licenses to be released: ${JSON.stringify(releaseAnalyzer, null, 2)}`); + logger.verbose( + `[QSEOW] QLIKSENSE LICENSE RELEASE ANALYZER: Analyzer licenses to be released: ${JSON.stringify(releaseAnalyzer, null, 2)}`, + ); // Is license release dry-run enabled? If so, do not release any licenses if (config.get('Butler.qlikSenseLicense.licenseRelease.dryRun') === true) { - logger.info('QLIKSENSE LICENSE RELEASE ANALYZER: Dry-run enabled. No licenses will be released'); + logger.info('[QSEOW] QLIKSENSE LICENSE RELEASE ANALYZER: Dry-run enabled. No licenses will be released'); } else { // Release all licenses in the releaseAnalyzer array // eslint-disable-next-line no-restricted-syntax for (const licenseRelease of releaseAnalyzer) { logger.info( - `QLIKSENSE LICENSE RELEASE ANALYZER: Releasing license for user ${licenseRelease.userDir}\\${licenseRelease.userId} (days since last use: ${licenseRelease.daysSinceLastUse})`, + `[QSEOW] QLIKSENSE LICENSE RELEASE ANALYZER: Releasing license for user ${licenseRelease.userDir}\\${licenseRelease.userId} (days since last use: ${licenseRelease.daysSinceLastUse})`, ); // Release license @@ -785,12 +789,12 @@ async function licenseReleaseAnalyzer(config, logger, qrsInstance) { // Is status code 204? Error if it's nmt if (result4.statusCode !== 204) { - logger.error(`QLIKSENSE LICENSE RELEASE ANALYZER: HTTP status code ${result4.statusCode}`); + logger.error(`[QSEOW] QLIKSENSE LICENSE RELEASE ANALYZER: HTTP status code ${result4.statusCode}`); return false; } // Debug log - logger.debug(`QLIKSENSE LICENSE RELEASE ANALYZER: ${JSON.stringify(result4.body)}`); + logger.debug(`[QSEOW] QLIKSENSE LICENSE RELEASE ANALYZER: ${JSON.stringify(result4.body)}`); // Write info about released license to InfluxDB? if ( @@ -853,9 +857,9 @@ async function checkQlikSenseLicenseRelease(config, logger) { return true; } catch (err) { - logger.error(`QLIKSENSE LICENSE RELEASE: ${err}`); + logger.error(`[QSEOW] QLIKSENSE LICENSE RELEASE: ${err}`); if (err.stack) { - logger.error(`QLIKSENSE LICENSE RELEASE: ${err.stack}`); + logger.error(`[QSEOW] QLIKSENSE LICENSE RELEASE: ${err.stack}`); } return false; } @@ -871,13 +875,13 @@ export async function setupQlikSenseAccessLicenseMonitor(config, logger) { }, sched); // Do an initial license check - logger.verbose('Doing initial Qlik Sense license check'); + logger.verbose('[QSEOW] Doing initial Qlik Sense license check'); checkQlikSenseAccessLicenseStatus(config, logger, true); } } catch (err) { - logger.error(`QLIKSENSE LICENSE MONITOR INIT: ${err}`); + logger.error(`[QSEOW] QLIKSENSE LICENSE MONITOR INIT: ${err}`); if (err.stack) { - logger.error(`QLIKSENSE LICENSE MONITOR INIT: ${err.stack}`); + logger.error(`[QSEOW] QLIKSENSE LICENSE MONITOR INIT: ${err.stack}`); } } } @@ -892,13 +896,13 @@ export async function setupQlikSenseLicenseRelease(config, logger) { }, sched); // Do an initial release - logger.verbose('Doing initial Qlik Sense license check'); + logger.verbose('[QSEOW] Doing initial Qlik Sense license check'); checkQlikSenseLicenseRelease(config, logger); } } catch (err) { - logger.error(`QLIKSENSE LICENSE RELEASE INIT: ${err}`); + logger.error(`[QSEOW] QLIKSENSE LICENSE RELEASE INIT: ${err}`); if (err.stack) { - logger.error(`QLIKSENSE LICENSE RELEASE INIT: ${err.stack}`); + logger.error(`[QSEOW] QLIKSENSE LICENSE RELEASE INIT: ${err.stack}`); } } } @@ -913,13 +917,13 @@ export async function setupQlikSenseServerLicenseMonitor(config, logger) { }, sched); // Do an initial license check - logger.verbose('Doing initial Qlik Sense server license check'); + logger.verbose('[QSEOW] Doing initial Qlik Sense server license check'); checkQlikSenseServerLicenseStatus(config, logger); } } catch (err) { - logger.error(`QLIKSENSE SERVER LICENSE MONITOR INIT: ${err}`); + logger.error(`[QSEOW] QLIKSENSE SERVER LICENSE MONITOR INIT: ${err}`); if (err.stack) { - logger.error(`QLIKSENSE SERVER LICENSE MONITOR INIT: ${err.stack}`); + logger.error(`[QSEOW] QLIKSENSE SERVER LICENSE MONITOR INIT: ${err.stack}`); } } } diff --git a/src/lib/qseow/qliksense_version.js b/src/lib/qseow/qliksense_version.js index 1494a32d..6f3da9ae 100644 --- a/src/lib/qseow/qliksense_version.js +++ b/src/lib/qseow/qliksense_version.js @@ -28,7 +28,7 @@ async function checkQlikSenseVersion(config, logger) { // Is status code 200 or body is empty? if (result.status !== 200 || !result.data) { - logger.error(`QLIKSENSE VERSION MONITOR: HTTP status code ${result.status}, "${result.statusText}"`); + logger.error(`[QSEOW] QLIKSENSE VERSION MONITOR: HTTP status code ${result.status}, "${result.statusText}"`); return; } @@ -36,10 +36,10 @@ async function checkQlikSenseVersion(config, logger) { logger.debug(`QLIKSENSE VERSION MONITOR: ${JSON.stringify(result.data)}`); // Log version info to console log - logger.info(`QLIKSENSE VERSION MONITOR: Qlik Sense product name: ${result.data.productName}`); - logger.info(`QLIKSENSE VERSION MONITOR: Qlik Sense deployment type: ${result.data.deploymentType}`); - logger.info(`QLIKSENSE VERSION MONITOR: Qlik Sense version: ${result.data.version}`); - logger.info(`QLIKSENSE VERSION MONITOR: Qlik Sense release: ${result.data.releaseLabel}`); + logger.info(`[QSEOW] QLIKSENSE VERSION MONITOR: Qlik Sense product name: ${result.data.productName}`); + logger.info(`[QSEOW] QLIKSENSE VERSION MONITOR: Qlik Sense deployment type: ${result.data.deploymentType}`); + logger.info(`[QSEOW] QLIKSENSE VERSION MONITOR: Qlik Sense version: ${result.data.version}`); + logger.info(`[QSEOW] QLIKSENSE VERSION MONITOR: Qlik Sense release: ${result.data.releaseLabel}`); // To which destination should we send the version information? // Check InfluDB first @@ -51,9 +51,9 @@ async function checkQlikSenseVersion(config, logger) { await postQlikSenseVersionToInfluxDB(result.data); } } catch (err) { - logger.error(`QLIKSENSE VERSION MONITOR: ${err}`); + logger.error(`[QSEOW] QLIKSENSE VERSION MONITOR: ${err}`); if (err.stack) { - logger.error(`QLIKSENSE VERSION MONITOR: ${err.stack}`); + logger.error(`[QSEOW] QLIKSENSE VERSION MONITOR: ${err.stack}`); } } } @@ -68,13 +68,13 @@ export async function setupQlikSenseVersionMonitor(config, logger) { }, sched); // Do an initial version check - logger.verbose('Doing initial Qlik Sense version check'); + logger.verbose('[QSEOW] Doing initial Qlik Sense version check'); checkQlikSenseVersion(config, logger, true); } } catch (err) { - logger.error(`QLIKSENSE VERSION MONITOR INIT: ${err}`); + logger.error(`[QSEOW] QLIKSENSE VERSION MONITOR INIT: ${err}`); if (err.stack) { - logger.error(`QLIKSENSE VERSION MONITOR INIT: ${err.stack}`); + logger.error(`[QSEOW] QLIKSENSE VERSION MONITOR INIT: ${err.stack}`); } } } diff --git a/src/lib/qseow/scriptlog.js b/src/lib/qseow/scriptlog.js index b2ae1e61..62cad748 100644 --- a/src/lib/qseow/scriptlog.js +++ b/src/lib/qseow/scriptlog.js @@ -59,11 +59,11 @@ export async function getReloadTaskExecutionResults(reloadTaskId) { const qrsInstance = new QrsInteract(configQRS); // Step 1 - globals.logger.debug(`GET SCRIPT LOG 1: reloadTaskId: ${reloadTaskId}`); + globals.logger.debug(`[QSEOW] GET SCRIPT LOG 1: reloadTaskId: ${reloadTaskId}`); const result1 = await qrsInstance.Get(`reloadtask/${reloadTaskId}`); - globals.logger.debug(`GET SCRIPT LOG 1: body: ${JSON.stringify(result1.body)}`); + globals.logger.debug(`[QSEOW] GET SCRIPT LOG 1: body: ${JSON.stringify(result1.body)}`); const taskInfo = { fileReferenceId: result1.body.operational.lastExecutionResult.fileReferenceID, @@ -163,7 +163,7 @@ export async function getReloadTaskExecutionResults(reloadTaskId) { return taskInfo; } catch (err) { - globals.logger.error(`GET SCRIPT LOG: ${err}`); + globals.logger.error(`[QSEOW] GET SCRIPT LOG: ${err}`); return false; } } @@ -194,9 +194,11 @@ export async function getScriptLog(reloadTaskId, headLineCount, tailLineCount) { const qrsInstance = new QrsInteract(configQRS); // Only get script log if there is a valid fileReferenceId - globals.logger.debug(`GET SCRIPT LOG 2: taskInfo.fileReferenceId: ${taskInfo.fileReferenceId}`); + globals.logger.debug(`[QSEOW] GET SCRIPT LOG 2: taskInfo.fileReferenceId: ${taskInfo.fileReferenceId}`); if (taskInfo.fileReferenceId !== '00000000-0000-0000-0000-000000000000') { - globals.logger.debug(`GET SCRIPT LOG 3: reloadtask/${reloadTaskId}/scriptlog?fileReferenceId=${taskInfo.fileReferenceId}`); + globals.logger.debug( + `[QSEOW] GET SCRIPT LOG 3: reloadtask/${reloadTaskId}/scriptlog?fileReferenceId=${taskInfo.fileReferenceId}`, + ); const result2 = await qrsInstance.Get(`reloadtask/${reloadTaskId}/scriptlog?fileReferenceId=${taskInfo.fileReferenceId}`); @@ -227,8 +229,14 @@ export async function getScriptLog(reloadTaskId, headLineCount, tailLineCount) { const result3 = await axios.request(axiosConfig); + // Get complete script log as an array of lines const scriptLogFull = result3.data.split('\r\n'); + // Get total number of rows and characters in script log + const scriptLogSizeCharacters = result3.data.length; + const scriptLogSizeRows = scriptLogFull.length; + + // Get head and tail of script log let scriptLogHead = ''; let scriptLogTail = ''; @@ -240,10 +248,10 @@ export async function getScriptLog(reloadTaskId, headLineCount, tailLineCount) { scriptLogTail = scriptLogFull.slice(Math.max(scriptLogFull.length - tailLineCount, 0)).join('\r\n'); } - globals.logger.debug(`GET SCRIPT LOG: Script log head:\n${scriptLogHead}`); - globals.logger.debug(`GET SCRIPT LOG: Script log tails:\n${scriptLogTail}`); + globals.logger.debug(`[QSEOW] GET SCRIPT LOG: Script log head:\n${scriptLogHead}`); + globals.logger.debug(`[QSEOW] GET SCRIPT LOG: Script log tails:\n${scriptLogTail}`); - globals.logger.verbose('GET SCRIPT LOG: Done getting script log'); + globals.logger.verbose('[QSEOW] GET SCRIPT LOG: Done getting script log'); return { executingNodeName: taskInfo.executingNodeName, @@ -256,6 +264,8 @@ export async function getScriptLog(reloadTaskId, headLineCount, tailLineCount) { executionStatusText: taskInfo.executionStatusText, scriptLogFull, scriptLogSize: taskInfo.scriptLogSize, + scriptLogSizeRows: scriptLogSizeRows, + scriptLogSizeCharacters: scriptLogSizeCharacters, scriptLogHead, scriptLogHeadCount: headLineCount, scriptLogTail, @@ -280,7 +290,7 @@ export async function getScriptLog(reloadTaskId, headLineCount, tailLineCount) { scriptLogTailCount: 0, }; } catch (err) { - globals.logger.error(`GET SCRIPT LOG: ${err}`); + globals.logger.error(`[QSEOW] GET SCRIPT LOG: ${err}`); return false; } } @@ -297,7 +307,7 @@ export async function failedTaskStoreLogOnDisk(reloadParams) { const logDate = reloadParams.logTimeStamp.slice(0, 10); const reloadLogDir = path.resolve(reloadLogDirRoot, logDate); - globals.logger.debug(`SCRIPTLOG STORE: Creating directory for failed task script log: ${reloadLogDir}`); + globals.logger.debug(`[QSEOW] SCRIPTLOG STORE: Creating directory for failed task script log: ${reloadLogDir}`); fs.mkdirSync(reloadLogDir, { recursive: true }); const fileName = path.resolve( @@ -307,11 +317,11 @@ export async function failedTaskStoreLogOnDisk(reloadParams) { }.log`, ); - globals.logger.info(`SCRIPTLOG STORE: Writing failed task script log: ${fileName}`); + globals.logger.info(`[QSEOW] SCRIPTLOG STORE: Writing failed task script log: ${fileName}`); fs.writeFileSync(fileName, scriptLog.scriptLogFull.join('\n')); return true; } catch (err) { - globals.logger.error(`SCRIPTLOG STORE: ${err}`); + globals.logger.error(`[QSEOW] SCRIPTLOG STORE: ${err}`); return false; } } diff --git a/src/lib/qseow/service_monitor.js b/src/lib/qseow/service_monitor.js index 0a719885..22298440 100644 --- a/src/lib/qseow/service_monitor.js +++ b/src/lib/qseow/service_monitor.js @@ -4,7 +4,7 @@ import { createMachine, createActor } from 'xstate'; import { statusAll, status, details } from './winsvc.js'; import globals from '../../globals.js'; import newRelic from '../incident_mgmt/new_relic_service_monitor.js'; -import { sendServiceMonitorWebhook } from '../webhook_notification.js'; +import { sendServiceMonitorWebhook } from './webhook_notification.js'; import { sendServiceMonitorNotificationSlack } from './slack_notification.js'; import { sendServiceMonitorNotificationTeams } from './msteams_notification.js'; import { sendServiceMonitorNotificationEmail } from './smtp.js'; @@ -116,7 +116,9 @@ const serviceMonitorMqttSend2 = (config, logger, svc) => { }; const verifyServicesExist = async (config, logger) => { - logger.info('VERIFY WIN SERVICES EXIST: Verifying that all Windows services specified in config file exist and can be reached.'); + logger.info( + 'VERIFY WIN SERVICES EXIST: Verifying that all Windows services specified in config file exist and can be reached.', + ); // Return false if one or more services do not exist or cannot be reached. // Return true if all services are reachable. @@ -195,7 +197,9 @@ const checkServiceStatus = async (config, logger, isFirstCheck = false) => { // Get status of this service const serviceStatus = await status(logger, service.name, host.host); - logger.debug(`Got reply: Service ${service.name} (="${service.friendlyName}") on host ${host.host} status: ${serviceStatus}`); + logger.debug( + `Got reply: Service ${service.name} (="${service.friendlyName}") on host ${host.host} status: ${serviceStatus}`, + ); // Get details about this service const serviceDetails = await details(logger, service.name, host.host); diff --git a/src/lib/qseow/slack_notification.js b/src/lib/qseow/slack_notification.js index 415eff6b..5b5089a6 100644 --- a/src/lib/qseow/slack_notification.js +++ b/src/lib/qseow/slack_notification.js @@ -55,7 +55,7 @@ function getSlackReloadFailedNotificationConfigOk() { if (!globals.config.get('Butler.slackNotification.reloadTaskFailure.enable')) { // Slack task falure notifications are disabled globals.logger.error( - "SLACK RELOAD TASK FAILED: Reload failure Slack notifications are disabled in config file - won't send Slack message", + '[QSEOW] SLACK RELOAD TASK FAILED: Reload failure Slack notifications are disabled in config file - will not send Slack message', ); return false; } @@ -66,7 +66,7 @@ function getSlackReloadFailedNotificationConfigOk() { ) { // Invalid Slack message type globals.logger.error( - `SLACK RELOAD TASK FAILED: Invalid Slack message type: ${globals.config.get( + `[QSEOW] SLACK RELOAD TASK FAILED: Invalid Slack message type: ${globals.config.get( 'Butler.slackNotification.reloadTaskFailure.messageType', )}`, ); @@ -77,13 +77,13 @@ function getSlackReloadFailedNotificationConfigOk() { // Basic formatting. Make sure requried parameters are present if (!globals.config.has('Butler.slackNotification.reloadTaskFailure.basicMsgTemplate')) { // No message text in config file. - globals.logger.error('SLACK RELOAD TASK FAILED: No message text in config file.'); + globals.logger.error('[QSEOW] SLACK RELOAD TASK FAILED: No message text in config file.'); return false; } } else if (globals.config.get('Butler.slackNotification.reloadTaskFailure.messageType') === 'formatted') { // Extended formatting using Slack blocks. Make sure requried parameters are present if (!globals.config.has('Butler.slackNotification.reloadTaskFailure.templateFile')) { - globals.logger.error('SLACK RELOAD TASK FAILED: Message template file not specified in config file.'); + globals.logger.error('[QSEOW] SLACK RELOAD TASK FAILED: Message template file not specified in config file.'); return false; } } @@ -116,7 +116,7 @@ function getSlackReloadFailedNotificationConfigOk() { : '', }; } catch (err) { - globals.logger.error(`SLACK RELOAD TASK FAILED: ${err}`); + globals.logger.error(`[QSEOW] SLACK RELOAD TASK FAILED: ${err}`); return false; } } @@ -126,7 +126,7 @@ function getSlackReloadAbortedNotificationConfigOk() { if (!globals.config.get('Butler.slackNotification.reloadTaskAborted.enable')) { // Slack task aborted notifications are disabled globals.logger.error( - "SLACK RELOAD TASK ABORTED: Reload aborted Slack notifications are disabled in config file - won't send Slack message", + '[QSEOW] SLACK RELOAD TASK ABORTED: Reload aborted Slack notifications are disabled in config file - will not send Slack message', ); return false; } @@ -137,7 +137,7 @@ function getSlackReloadAbortedNotificationConfigOk() { ) { // Invalid Slack message type globals.logger.error( - `SLACK RELOAD TASK ABORTED: Invalid Slack message type: ${globals.config.get( + `[QSEOW] SLACK RELOAD TASK ABORTED: Invalid Slack message type: ${globals.config.get( 'Butler.slackNotification.reloadTaskAborted.messageType', )}`, ); @@ -148,13 +148,13 @@ function getSlackReloadAbortedNotificationConfigOk() { // Basic formatting. Make sure requried parameters are present if (!globals.config.has('Butler.slackNotification.reloadTaskAborted.basicMsgTemplate')) { // No message text in config file. - globals.logger.error('SLACK RELOAD TASK ABORTED: No message text in config file.'); + globals.logger.error('[QSEOW] SLACK RELOAD TASK ABORTED: No message text in config file.'); return false; } } else if (globals.config.get('Butler.slackNotification.reloadTaskAborted.messageType') === 'formatted') { // Extended formatting using Slack blocks. Make sure requried parameters are present if (!globals.config.has('Butler.slackNotification.reloadTaskAborted.templateFile')) { - globals.logger.error('SLACK RELOAD TASK ABORTED: Message template file not specified in config file.'); + globals.logger.error('[QSEOW] SLACK RELOAD TASK ABORTED: Message template file not specified in config file.'); return false; } } @@ -187,7 +187,7 @@ function getSlackReloadAbortedNotificationConfigOk() { : '', }; } catch (err) { - globals.logger.error(`SLACK RELOAD TASK ABORTED: ${err}`); + globals.logger.error(`[QSEOW] SLACK RELOAD TASK ABORTED: ${err}`); return false; } } @@ -197,7 +197,7 @@ function getSlackServiceMonitorNotificationConfig(serviceStatus) { if (!globals.config.get('Butler.serviceMonitor.alertDestination.slack.enable')) { // Slack notifications are disabled globals.logger.error( - "SLACK SERVICE MONITOR: SLACK SERVICE MONITOR notifications are disabled in config file - won't send Slack message", + '[QSEOW] SLACK SERVICE MONITOR: SLACK SERVICE MONITOR notifications are disabled in config file - will not send Slack message', ); return false; } @@ -208,7 +208,7 @@ function getSlackServiceMonitorNotificationConfig(serviceStatus) { ) { // Invalid Slack message type globals.logger.error( - `SLACK SERVICE MONITOR: Invalid Slack message type: ${globals.config.get( + `[QSEOW] SLACK SERVICE MONITOR: Invalid Slack message type: ${globals.config.get( 'Butler.slackNotification.serviceStopped.messageType', )}`, ); @@ -221,7 +221,7 @@ function getSlackServiceMonitorNotificationConfig(serviceStatus) { ) { // Invalid Slack message type globals.logger.error( - `SLACK SERVICE MONITOR: Invalid Slack message type: ${globals.config.get( + `[QSEOW] SLACK SERVICE MONITOR: Invalid Slack message type: ${globals.config.get( 'Butler.slackNotification.serviceStarted.messageType', )}`, ); @@ -232,13 +232,13 @@ function getSlackServiceMonitorNotificationConfig(serviceStatus) { // Basic formatting. Make sure required parameters are present if (!globals.config.has('Butler.slackNotification.serviceStopped.basicMsgTemplate')) { // No message text in config file. - globals.logger.error('SLACK SERVICE MONITOR: No service stopped basic message text in config file.'); + globals.logger.error('[QSEOW] SLACK SERVICE MONITOR: No service stopped basic message text in config file.'); return false; } } else if (globals.config.get('Butler.slackNotification.serviceStopped.messageType') === 'formatted') { // Extended formatting using Slack blocks. Make sure requried parameters are present if (!globals.config.has('Butler.slackNotification.serviceStopped.templateFile')) { - globals.logger.error('SLACK SERVICE MONITOR: Service stopped message template file not specified in config file.'); + globals.logger.error('[QSEOW] SLACK SERVICE MONITOR: Service stopped message template file not specified in config file.'); return false; } } @@ -247,13 +247,13 @@ function getSlackServiceMonitorNotificationConfig(serviceStatus) { // Basic formatting. Make sure required parameters are present if (!globals.config.has('Butler.slackNotification.serviceStarted.basicMsgTemplate')) { // No message text in config file. - globals.logger.error('SLACK SERVICE MONITOR: No service started basic message text in config file.'); + globals.logger.error('[QSEOW] SLACK SERVICE MONITOR: No service started basic message text in config file.'); return false; } } else if (globals.config.get('Butler.slackNotification.serviceStarted.messageType') === 'formatted') { // Extended formatting using Slack blocks. Make sure requried parameters are present if (!globals.config.has('Butler.slackNotification.serviceStarted.templateFile')) { - globals.logger.error('SLACK SERVICE MONITOR: Service started message template file not specified in config file.'); + globals.logger.error('[QSEOW] SLACK SERVICE MONITOR: Service started message template file not specified in config file.'); return false; } } @@ -310,7 +310,7 @@ function getSlackServiceMonitorNotificationConfig(serviceStatus) { return result; } catch (err) { - globals.logger.error(`SLACK SERVICE MONITOR: ${err}`); + globals.logger.error(`[QSEOW] SLACK SERVICE MONITOR: ${err}`); return false; } } @@ -383,8 +383,12 @@ async function sendSlack(slackConfig, templateContext, msgType) { if (msgType === 'reload') { // Escape any back slashes in the script logs const regExpText = /(?!\\n)\\{1}/gm; - globals.logger.debug(`SLACK SEND: Script log head escaping: ${regExpText.exec(templateContext.scriptLogHead)}`); - globals.logger.debug(`SLACK SEND: Script log tail escaping: ${regExpText.exec(templateContext.scriptLogTail)}`); + globals.logger.debug( + `[QSEOW] SLACK SEND: Script log head escaping: ${regExpText.exec(templateContext.scriptLogHead)}`, + ); + globals.logger.debug( + `[QSEOW] SLACK SEND: Script log tail escaping: ${regExpText.exec(templateContext.scriptLogTail)}`, + ); templateContext.scriptLogHead = templateContext.scriptLogHead.replace(regExpText, '\\\\'); templateContext.scriptLogTail = templateContext.scriptLogTail.replace(regExpText, '\\\\'); @@ -393,12 +397,12 @@ async function sendSlack(slackConfig, templateContext, msgType) { // Render Slack message using template. Do not convert to < and > as Slack will not render the message correctly slackMsg = compiledTemplate(templateContext); - globals.logger.debug(`SLACK SEND: Rendered message:\n${slackMsg}`); + globals.logger.debug(`[QSEOW] SLACK SEND: Rendered message:\n${slackMsg}`); } else { - globals.logger.error(`SLACK SEND: Could not open Slack template file ${slackConfig.templateFile}.`); + globals.logger.error(`[QSEOW] SLACK SEND: Could not open Slack template file ${slackConfig.templateFile}.`); } } catch (err) { - globals.logger.error(`SLACK SEND: Error processing Slack template file: ${err}`); + globals.logger.error(`[QSEOW] SLACK SEND: Error processing Slack template file: ${err}`); } } @@ -406,11 +410,11 @@ async function sendSlack(slackConfig, templateContext, msgType) { msg.text = slackMsg; const res = await slackSend(msg, globals.logger); if (res !== undefined) { - globals.logger.debug(`SLACK SEND: Result from calling slackSend: ${res.statusText} (${res.status}): ${res.data}`); + globals.logger.debug(`[QSEOW] SLACK SEND: Result from calling slackSend: ${res.statusText} (${res.status}): ${res.data}`); } } } catch (err) { - globals.logger.error(`SLACK SEND: ${err}`); + globals.logger.error(`[QSEOW] SLACK SEND: ${err}`); } } @@ -420,9 +424,11 @@ export function sendReloadTaskFailureNotificationSlack(reloadParams) { .then(async (rateLimiterRes) => { try { globals.logger.info( - `SLACK RELOAD TASK FAILED: Rate limiting check passed for failed task notification. Task name: "${reloadParams.taskName}"`, + `[QSEOW] SLACK RELOAD TASK FAILED: Rate limiting check passed for failed task notification. Task name: "${reloadParams.taskName}"`, + ); + globals.logger.verbose( + `[QSEOW] SLACK RELOAD TASK FAILED: Rate limiting details "${JSON.stringify(rateLimiterRes, null, 2)}"`, ); - globals.logger.verbose(`SLACK RELOAD TASK FAILED: Rate limiting details "${JSON.stringify(rateLimiterRes, null, 2)}"`); // Make sure Slack sending is enabled in the config file and that we have all required settings const slackConfig = getSlackReloadFailedNotificationConfigOk(); @@ -451,7 +457,7 @@ export function sendReloadTaskFailureNotificationSlack(reloadParams) { scriptLogData.scriptLogTail = ''; } - globals.logger.debug(`SLACK RELOAD TASK FAILED: Script log data:\n${JSON.stringify(scriptLogData, null, 2)}`); + globals.logger.debug(`[QSEOW] SLACK RELOAD TASK FAILED: Script log data:\n${JSON.stringify(scriptLogData, null, 2)}`); // Get Sense URLs from config file. Can be used as template fields. const senseUrls = getQlikSenseUrls(); @@ -521,6 +527,8 @@ export function sendReloadTaskFailureNotificationSlack(reloadParams) { .replace(/([\n])/gm, '\\n') .replace(/([\t])/gm, '\\t'), scriptLogSize: scriptLogData.scriptLogSize, + scriptLogSizeRows: scriptLogData.scriptLogSizeRows, + scriptLogSizeCharacters: scriptLogData.scriptLogSizeCharacters, scriptLogHead: scriptLogData.scriptLogHead .replace(/([\r])/gm, '') .replace(/([\n])/gm, '\\n') @@ -557,7 +565,7 @@ export function sendReloadTaskFailureNotificationSlack(reloadParams) { // https://api.slack.com/reference/block-kit/blocks#section_fields if (templateContext.scriptLogHead.length >= 3000) { globals.logger.warn( - `SLACK: Script log head field is too long (${templateContext.scriptLogHead.length}), will truncate before posting to Slack.`, + `[QSEOW] SLACK: Script log head field is too long (${templateContext.scriptLogHead.length}), will truncate before posting to Slack.`, ); templateContext.scriptLogHead = templateContext.scriptLogHead .replaceAll('&', '&') @@ -581,7 +589,7 @@ export function sendReloadTaskFailureNotificationSlack(reloadParams) { if (templateContext.scriptLogTail.length >= 3000) { globals.logger.warn( - `SLACK: Script log head field is too long (${templateContext.scriptLogTail.length}), will truncate before posting to Slack.`, + `[QSEOW] SLACK: Script log head field is too long (${templateContext.scriptLogTail.length}), will truncate before posting to Slack.`, ); templateContext.scriptLogTail = templateContext.scriptLogTail .replaceAll('&', '&') @@ -605,15 +613,15 @@ export function sendReloadTaskFailureNotificationSlack(reloadParams) { sendSlack(slackConfig, templateContext, 'reload'); } catch (err) { - globals.logger.error(`SLACK RELOAD TASK FAILED: ${err}`); + globals.logger.error(`[QSEOW] SLACK RELOAD TASK FAILED: ${err}`); } return true; }) .catch((err) => { globals.logger.warn( - `SLACK RELOAD TASK FAILED: Rate limiting failed. Not sending reload notification Slack for task "${reloadParams.taskName}"`, + `[QSEOW] SLACK RELOAD TASK FAILED: Rate limiting failed. Not sending reload notification Slack for task "${reloadParams.taskName}"`, ); - globals.logger.debug(`SLACK RELOAD TASK FAILED: Rate limiting details "${JSON.stringify(err, null, 2)}"`); + globals.logger.debug(`[QSEOW] SLACK RELOAD TASK FAILED: Rate limiting details "${JSON.stringify(err, null, 2)}"`); }); } @@ -623,9 +631,11 @@ export function sendReloadTaskAbortedNotificationSlack(reloadParams) { .then(async (rateLimiterRes) => { try { globals.logger.info( - `SLACK RELOAD TASK ABORTED: Rate limiting check passed for aborted task notification. Task name: "${reloadParams.taskName}"`, + `[QSEOW] SLACK RELOAD TASK ABORTED: Rate limiting check passed for aborted task notification. Task name: "${reloadParams.taskName}"`, + ); + globals.logger.verbose( + `[QSEOW] SLACK RELOAD TASK ABORTED: Rate limiting details "${JSON.stringify(rateLimiterRes, null, 2)}"`, ); - globals.logger.verbose(`SLACK RELOAD TASK ABORTED: Rate limiting details "${JSON.stringify(rateLimiterRes, null, 2)}"`); // Make sure Slack sending is enabled in the config file and that we have all required settings const slackConfig = getSlackReloadAbortedNotificationConfigOk(); @@ -654,7 +664,7 @@ export function sendReloadTaskAbortedNotificationSlack(reloadParams) { scriptLogData.scriptLogTail = ''; } - globals.logger.debug(`SLACK RELOAD TASK ABORTED: Script log data:\n${JSON.stringify(scriptLogData, null, 2)}`); + globals.logger.debug(`[QSEOW] SLACK RELOAD TASK ABORTED: Script log data:\n${JSON.stringify(scriptLogData, null, 2)}`); // Get Sense URLs from config file. Can be used as template fields. const senseUrls = getQlikSenseUrls(); @@ -745,7 +755,7 @@ export function sendReloadTaskAbortedNotificationSlack(reloadParams) { // https://api.slack.com/reference/block-kit/blocks#section_fields if (templateContext.scriptLogHead.length >= 3000) { globals.logger.warn( - `SLACK: Script log head field is too long (${templateContext.scriptLogHead.length}), will truncate before posting to Slack.`, + `[QSEOW] SLACK: Script log head field is too long (${templateContext.scriptLogHead.length}), will truncate before posting to Slack.`, ); templateContext.scriptLogHead = templateContext.scriptLogHead .replaceAll('&', '&') @@ -769,7 +779,7 @@ export function sendReloadTaskAbortedNotificationSlack(reloadParams) { if (templateContext.scriptLogTail.length >= 3000) { globals.logger.warn( - `SLACK: Script log head field is too long (${templateContext.scriptLogTail.length}), will truncate before posting to Slack.`, + `[QSEOW] SLACK: Script log head field is too long (${templateContext.scriptLogTail.length}), will truncate before posting to Slack.`, ); templateContext.scriptLogTail = templateContext.scriptLogTail .replaceAll('&', '&') @@ -793,15 +803,15 @@ export function sendReloadTaskAbortedNotificationSlack(reloadParams) { sendSlack(slackConfig, templateContext, 'reload'); } catch (err) { - globals.logger.error(`SLACK RELOAD TASK ABORTED: ${err}`); + globals.logger.error(`[QSEOW] SLACK RELOAD TASK ABORTED: ${err}`); } return true; }) .catch((err) => { globals.logger.verbose( - `SLACK RELOAD TASK ABORTED: Rate limiting failed. Not sending reload notification Slack for task "${reloadParams.taskName}"`, + `[QSEOW] SLACK RELOAD TASK ABORTED: Rate limiting failed. Not sending reload notification Slack for task "${reloadParams.taskName}"`, ); - globals.logger.verbose(`SLACK RELOAD TASK ABORTED: Rate limiting details "${JSON.stringify(err, null, 2)}"`); + globals.logger.verbose(`[QSEOW] SLACK RELOAD TASK ABORTED: Rate limiting details "${JSON.stringify(err, null, 2)}"`); }); } @@ -811,9 +821,9 @@ export function sendServiceMonitorNotificationSlack(serviceParams) { .then(async (rateLimiterRes) => { try { globals.logger.info( - `SLACK SERVICE MONITOR: Rate limiting check passed for service monitor notification. Host: "${serviceParams.host}", service: "${serviceParams.serviceName}"`, + `[QSEOW] SLACK SERVICE MONITOR: Rate limiting check passed for service monitor notification. Host: "${serviceParams.host}", service: "${serviceParams.serviceName}"`, ); - globals.logger.verbose(`SLACK SERVICE MONITOR: Rate limiting details "${JSON.stringify(rateLimiterRes, null, 2)}"`); + globals.logger.verbose(`[QSEOW] SLACK SERVICE MONITOR: Rate limiting details "${JSON.stringify(rateLimiterRes, null, 2)}"`); // Make sure Slack sending is enabled in the config file and that we have all required settings const slackConfig = getSlackServiceMonitorNotificationConfig(serviceParams.serviceStatus); @@ -847,14 +857,14 @@ export function sendServiceMonitorNotificationSlack(serviceParams) { sendSlack(slackConfig, templateContext, 'serviceStarted'); } } catch (err) { - globals.logger.error(`SLACK SERVICE MONITOR: ${err}`); + globals.logger.error(`[QSEOW] SLACK SERVICE MONITOR: ${err}`); } return true; }) .catch((err) => { globals.logger.warn( - `SLACK SERVICE MONITOR: Rate limiting failed. Not sending service monitor notification for service "${serviceParams.serviceName}" on host "${serviceParams.host}"`, + `[QSEOW] SLACK SERVICE MONITOR: Rate limiting failed. Not sending service monitor notification for service "${serviceParams.serviceName}" on host "${serviceParams.host}"`, ); - globals.logger.debug(`SLACK SERVICE MONITOR: Rate limiting details "${JSON.stringify(err, null, 2)}"`); + globals.logger.debug(`[QSEOW] SLACK SERVICE MONITOR: Rate limiting details "${JSON.stringify(err, null, 2)}"`); }); } diff --git a/src/lib/qseow/smtp.js b/src/lib/qseow/smtp.js index 3b0e10eb..45fe00ed 100644 --- a/src/lib/qseow/smtp.js +++ b/src/lib/qseow/smtp.js @@ -57,13 +57,13 @@ export function isSmtpConfigOk() { // First make sure email sending is enabled in the config file if (!globals.config.get('Butler.emailNotification.enable')) { // SMTP is disabled - globals.logger.error("EMAIL CONFIG: SMTP notifications are disabled in config file - won't send email"); + globals.logger.error('[QSEOW] EMAIL CONFIG: SMTP notifications are disabled in config file - will not send email'); return false; } return true; } catch (err) { - globals.logger.error(`EMAIL CONFIG: ${err}`); + globals.logger.error(`[QSEOW] EMAIL CONFIG: ${err}`); return false; } } @@ -73,13 +73,15 @@ function isEmailReloadSuccessNotificationConfigOk() { // First make sure email sending is enabled in the config file if (!globals.config.get('Butler.emailNotification.reloadTaskSuccess.enable')) { // SMTP is disabled - globals.logger.error("EMAIL CONFIG: Reload success email notifications are disabled in config file - won't send email"); + globals.logger.error( + '[QSEOW] EMAIL CONFIG: Reload success email notifications are disabled in config file - will not send email', + ); return false; } return true; } catch (err) { - globals.logger.error(`EMAIL CONFIG: ${err}`); + globals.logger.error(`[QSEOW] EMAIL CONFIG: ${err}`); return false; } } @@ -89,13 +91,15 @@ function isEmailReloadFailedNotificationConfigOk() { // First make sure email sending is enabled in the config file if (!globals.config.get('Butler.emailNotification.reloadTaskFailure.enable')) { // SMTP is disabled - globals.logger.error("EMAIL CONFIG: Reload failure email notifications are disabled in config file - won't send email"); + globals.logger.error( + '[QSEOW] EMAIL CONFIG: Reload failure email notifications are disabled in config file - will not send email', + ); return false; } return true; } catch (err) { - globals.logger.error(`EMAIL CONFIG: ${err}`); + globals.logger.error(`[QSEOW] EMAIL CONFIG: ${err}`); return false; } } @@ -105,13 +109,15 @@ function isEmailReloadAbortedNotificationConfigOk() { // First make sure email sending is enabled in the config file if (!globals.config.get('Butler.emailNotification.reloadTaskAborted.enable')) { // SMTP is disabled - globals.logger.error("EMAIL CONFIG: Reload aborted email notifications are disabled in config file - won't send email"); + globals.logger.error( + '[QSEOW] EMAIL CONFIG: Reload aborted email notifications are disabled in config file - will not send email', + ); return false; } return true; } catch (err) { - globals.logger.error(`EMAIL CONFIG: ${err}`); + globals.logger.error(`[QSEOW] EMAIL CONFIG: ${err}`); return false; } } @@ -124,13 +130,15 @@ function isEmailServiceMonitorNotificationConfig() { !globals.config.get('Butler.serviceMonitor.alertDestination.email.enable') ) { // SMTP is disabled - globals.logger.error("EMAIL CONFIG: Service monitor email notifications are disabled in config file - won't send email"); + globals.logger.error( + '[QSEOW] EMAIL CONFIG: Service monitor email notifications are disabled in config file - will not send email', + ); return false; } return true; } catch (err) { - globals.logger.error(`EMAIL CONFIG: ${err}`); + globals.logger.error(`[QSEOW] EMAIL CONFIG: ${err}`); return false; } } @@ -209,22 +217,24 @@ export async function sendEmail(from, recipientsEmail, emailPriority, subjectHan // Verify SMTP configuration // eslint-disable-next-line no-await-in-loop const smtpStatus = await transporter.verify(); - globals.logger.debug(`EMAIL CONFIG: SMTP status: ${smtpStatus}`); - globals.logger.debug(`EMAIL CONFIG: Message=${JSON.stringify(message, null, 2)}`); + globals.logger.debug(`[QSEOW] EMAIL CONFIG: SMTP status: ${smtpStatus}`); + globals.logger.debug(`[QSEOW] EMAIL CONFIG: Message=${JSON.stringify(message, null, 2)}`); if (smtpStatus) { // eslint-disable-next-line no-await-in-loop const result = await transporter.sendMail(message); - globals.logger.debug(`EMAIL CONFIG: Sending reload failure notification result: ${JSON.stringify(result, null, 2)}`); + globals.logger.debug( + `[QSEOW] EMAIL CONFIG: Sending reload failure notification result: ${JSON.stringify(result, null, 2)}`, + ); } else { - globals.logger.warn('EMAIL CONFIG: SMTP transporter not ready'); + globals.logger.warn('[QSEOW] EMAIL CONFIG: SMTP transporter not ready'); } } else { - globals.logger.warn(`EMAIL CONFIG: Recipient email adress not valid: ${recipientEmail}`); + globals.logger.warn(`[QSEOW] EMAIL CONFIG: Recipient email adress not valid: ${recipientEmail}`); } } } catch (err) { - globals.logger.error(`EMAIL CONFIG: ${err}`); + globals.logger.error(`[QSEOW] EMAIL CONFIG: ${err}`); } } @@ -256,22 +266,22 @@ export async function sendEmailBasic(from, recipientsEmail, emailPriority, subje // Verify SMTP configuration // eslint-disable-next-line no-await-in-loop const smtpStatus = await transporter.verify(); - globals.logger.debug(`SMTP BASIC: SMTP status: ${smtpStatus}`); - globals.logger.debug(`SMTP BASIC: Message=${JSON.stringify(message, null, 2)}`); + globals.logger.debug(`[QSEOW] SMTP BASIC: SMTP status: ${smtpStatus}`); + globals.logger.debug(`[QSEOW] SMTP BASIC: Message=${JSON.stringify(message, null, 2)}`); if (smtpStatus) { // eslint-disable-next-line no-await-in-loop const result = await transporter.sendMail(message); - globals.logger.debug(`SMTP BASIC: Sending email result: ${JSON.stringify(result, null, 2)}`); + globals.logger.debug(`[QSEOW] SMTP BASIC: Sending email result: ${JSON.stringify(result, null, 2)}`); } else { globals.logger.warn('SMTP BASIC: SMTP transporter not ready'); } } else { - globals.logger.warn(`SMTP BASIC: Recipient email adress not valid: ${recipientEmail}`); + globals.logger.warn(`[QSEOW] SMTP BASIC: Recipient email adress not valid: ${recipientEmail}`); } } } catch (err) { - globals.logger.error(`SMTP BASIC: ${err}`); + globals.logger.error(`[QSEOW] SMTP BASIC: ${err}`); } } @@ -321,7 +331,7 @@ export async function sendReloadTaskFailureNotificationEmail(reloadParams) { if (taskSpecificAlertEmailAddresses?.length > 0) { globals.logger.debug( - `EMAIL RELOAD TASK FAILED ALERT: Added task specific send list: ${JSON.stringify(taskSpecificAlertEmailAddresses, null, 2)}`, + `[QSEOW] EMAIL RELOAD TASK FAILED ALERT: Added task specific send list: ${JSON.stringify(taskSpecificAlertEmailAddresses, null, 2)}`, ); mainSendList = mainSendList.concat(taskSpecificAlertEmailAddresses); @@ -331,11 +341,11 @@ export async function sendReloadTaskFailureNotificationEmail(reloadParams) { // 2 Should alert emails be sent for all failed reload tasks? if (globals.config.get('Butler.emailNotification.reloadTaskFailure.alertEnableByCustomProperty.enable') === false) { // 2.1 Yes: Add system-wide list of recipients to send list - globals.logger.verbose(`EMAIL RELOAD TASK FAILED ALERT: Send alert emails for all tasks`); + globals.logger.verbose(`[QSEOW] EMAIL RELOAD TASK FAILED ALERT: Send alert emails for all tasks`); if (globalSendList?.length > 0) { globals.logger.debug( - `EMAIL RELOAD TASK FAILED ALERT: Added global send list for failed task: ${JSON.stringify(globalSendList, null, 2)}`, + `[QSEOW] EMAIL RELOAD TASK FAILED ALERT: Added global send list for failed task: ${JSON.stringify(globalSendList, null, 2)}`, ); mainSendList = mainSendList.concat(globalSendList); emailRecipientsVerbose.common = emailRecipientsVerbose.common.concat(globalSendList); @@ -344,14 +354,14 @@ export async function sendReloadTaskFailureNotificationEmail(reloadParams) { // Only send alert email if the failed task has email alerts enabled // 2.2 No : Does the failed reload task have alerts turned on (using custom property)? globals.logger.verbose( - `EMAIL RELOAD TASK FAILED ALERT: Only send alert emails for tasks with email-alert-CP "${emailAlertCpName}" set`, + `[QSEOW] EMAIL RELOAD TASK FAILED ALERT: Only send alert emails for tasks with email-alert-CP "${emailAlertCpName}" set`, ); const sendAlert = await isCustomPropertyValueSet(reloadParams.taskId, emailAlertCpName, emailAlertCpEnabledValue); if (sendAlert === true) { globals.logger.debug( - `EMAIL RELOAD TASK FAILED ALERT: Added send list based on email-alert-CP: ${JSON.stringify(globalSendList, null, 2)}`, + `[QSEOW] EMAIL RELOAD TASK FAILED ALERT: Added send list based on email-alert-CP: ${JSON.stringify(globalSendList, null, 2)}`, ); // 2.2.1 Yes: Add system-wide list of recipients to send list if (globalSendList?.length > 0) { @@ -397,7 +407,7 @@ export async function sendReloadTaskFailureNotificationEmail(reloadParams) { } else { // No app owners on include list. Warn about this. globals.logger.warn( - `EMAIL RELOAD TASK FAILED ALERT: No app owners on include list for failed task. No app owners will receive notification emails.`, + `[QSEOW] EMAIL RELOAD TASK FAILED ALERT: No app owners on include list for failed task. No app owners will receive notification emails.`, ); } } @@ -426,12 +436,12 @@ export async function sendReloadTaskFailureNotificationEmail(reloadParams) { // Does the main sendlist contain any email addresses? Warn if not if (mainSendList?.length === 0) { globals.logger.warn( - `EMAIL RELOAD TASK FAILED ALERT: No email addresses defined for app owner's alert email for app "${reloadParams.appName}", ID=${reloadParams.appId}`, + `[QSEOW] EMAIL RELOAD TASK FAILED ALERT: No email addresses defined for app owner's alert email for app "${reloadParams.appName}", ID=${reloadParams.appId}`, ); } } else { globals.logger.warn( - `EMAIL RELOAD TASK FAILED ALERT: No email address for owner of app "${reloadParams.appName}", ID=${reloadParams.appId}`, + `[QSEOW] EMAIL RELOAD TASK FAILED ALERT: No email address for owner of app "${reloadParams.appName}", ID=${reloadParams.appId}`, ); } } @@ -441,15 +451,15 @@ export async function sendReloadTaskFailureNotificationEmail(reloadParams) { // Debug globals.logger.verbose( - `EMAIL RELOAD TASK FAILED ALERT: Final send list for failed task "${reloadParams.taskName}": ${JSON.stringify( + `[QSEOW] EMAIL RELOAD TASK FAILED ALERT: Final send list for failed task "${reloadParams.taskName}": ${JSON.stringify( mainSendListUnique, null, 2, )}`, ); - globals.logger.verbose(`EMAIL RELOAD TASK FAILED ALERT: App owner recipients: ${emailRecipientsVerbose.appOwner}`); - globals.logger.verbose(`EMAIL RELOAD TASK FAILED ALERT: Shared all tasks recipients: ${emailRecipientsVerbose.shared}`); - globals.logger.verbose(`EMAIL RELOAD TASK FAILED ALERT: Task specific recipients: ${emailRecipientsVerbose.taskSpecific}`); + globals.logger.verbose(`[QSEOW] EMAIL RELOAD TASK FAILED ALERT: App owner recipients: ${emailRecipientsVerbose.appOwner}`); + globals.logger.verbose(`[QSEOW] EMAIL RELOAD TASK FAILED ALERT: Shared all tasks recipients: ${emailRecipientsVerbose.shared}`); + globals.logger.verbose(`[QSEOW] EMAIL RELOAD TASK FAILED ALERT: Task specific recipients: ${emailRecipientsVerbose.taskSpecific}`); if (isSmtpConfigOk() === false) { return 1; @@ -477,7 +487,7 @@ export async function sendReloadTaskFailureNotificationEmail(reloadParams) { scriptLogData.scriptLogTail = ''; } - globals.logger.debug(`EMAIL RELOAD TASK FAILED ALERT: Script log data:\n${JSON.stringify(scriptLogData, null, 2)}`); + globals.logger.debug(`[QSEOW] EMAIL RELOAD TASK FAILED ALERT: Script log data:\n${JSON.stringify(scriptLogData, null, 2)}`); // Get Sense URLs from config file. Can be used as template fields. const senseUrls = getQlikSenseUrls(); @@ -541,6 +551,8 @@ export async function sendReloadTaskFailureNotificationEmail(reloadParams) { executionStatusText: scriptLogData.executionStatusText, executionDetails: scriptLogData.executionDetails, scriptLogSize: scriptLogData.scriptLogSize, + scriptLogSizeRows: scriptLogData.scriptLogSizeRows, + scriptLogSizeCharacters: scriptLogData.scriptLogSizeCharacters, scriptLogHead: scriptLogData.scriptLogHead, scriptLogTail: scriptLogData.scriptLogTail, scriptLogTailCount: scriptLogData.scriptLogTailCount, @@ -562,10 +574,10 @@ export async function sendReloadTaskFailureNotificationEmail(reloadParams) { .then(async (rateLimiterRes) => { try { globals.logger.info( - `EMAIL RELOAD TASK FAILED ALERT: Rate limiting check passed for failed task notification. Task name: "${reloadParams.taskName}", Recipient: "${recipientEmailAddress}"`, + `[QSEOW] EMAIL RELOAD TASK FAILED ALERT: Rate limiting check passed for failed task notification. Task name: "${reloadParams.taskName}", Recipient: "${recipientEmailAddress}"`, ); globals.logger.debug( - `EMAIL RELOAD TASK FAILED ALERT: Rate limiting details "${JSON.stringify(rateLimiterRes, null, 2)}"`, + `[QSEOW] EMAIL RELOAD TASK FAILED ALERT: Rate limiting details "${JSON.stringify(rateLimiterRes, null, 2)}"`, ); // Only send email if there is at least one recipient @@ -580,17 +592,17 @@ export async function sendReloadTaskFailureNotificationEmail(reloadParams) { templateContext, ); } else { - globals.logger.warn(`EMAIL RELOAD TASK FAILED ALERT: No recipients to send alert email to.`); + globals.logger.warn(`[QSEOW] EMAIL RELOAD TASK FAILED ALERT: No recipients to send alert email to.`); } } catch (err) { - globals.logger.error(`EMAIL RELOAD TASK FAILED ALERT: ${err}`); + globals.logger.error(`[QSEOW] EMAIL RELOAD TASK FAILED ALERT: ${err}`); } }) .catch((err) => { globals.logger.warn( - `EMAIL RELOAD TASK FAILED ALERT: Rate limiting failed. Not sending reload notification email for task "${reloadParams.taskName}" to "${recipientEmailAddress}"`, + `[QSEOW] EMAIL RELOAD TASK FAILED ALERT: Rate limiting failed. Not sending reload notification email for task "${reloadParams.taskName}" to "${recipientEmailAddress}"`, ); - globals.logger.debug(`EMAIL RELOAD TASK FAILED ALERT: Rate limiting details "${JSON.stringify(err, null, 2)}"`); + globals.logger.debug(`[QSEOW] EMAIL RELOAD TASK FAILED ALERT: Rate limiting details "${JSON.stringify(err, null, 2)}"`); }); } } @@ -640,7 +652,7 @@ export async function sendReloadTaskAbortedNotificationEmail(reloadParams) { if (taskSpecificAlertEmailAddresses?.length > 0) { globals.logger.debug( - `EMAIL RELOAD TASK ABORTED ALERT: Added task specific send list: ${JSON.stringify(taskSpecificAlertEmailAddresses, null, 2)}`, + `[QSEOW] EMAIL RELOAD TASK ABORTED ALERT: Added task specific send list: ${JSON.stringify(taskSpecificAlertEmailAddresses, null, 2)}`, ); mainSendList = mainSendList.concat(taskSpecificAlertEmailAddresses); @@ -650,11 +662,11 @@ export async function sendReloadTaskAbortedNotificationEmail(reloadParams) { // 2 Should alert emails be sent for all aborted reload tasks? if (globals.config.get('Butler.emailNotification.reloadTaskAborted.alertEnableByCustomProperty.enable') === false) { // 2.1 Yes: Add system-wide list of recipients to send list - globals.logger.verbose(`EMAIL RELOAD TASK ABORTED ALERT: Send alert emails for all tasks`); + globals.logger.verbose(`[QSEOW] EMAIL RELOAD TASK ABORTED ALERT: Send alert emails for all tasks`); if (globalSendList?.length > 0) { globals.logger.debug( - `EMAIL RELOAD TASK ABORTED ALERT: Added global send list for failed task: ${JSON.stringify(globalSendList, null, 2)}`, + `[QSEOW] EMAIL RELOAD TASK ABORTED ALERT: Added global send list for failed task: ${JSON.stringify(globalSendList, null, 2)}`, ); mainSendList = mainSendList.concat(globalSendList); emailRecipientsVerbose.common = emailRecipientsVerbose.common.concat(globalSendList); @@ -663,14 +675,14 @@ export async function sendReloadTaskAbortedNotificationEmail(reloadParams) { // Only send alert email if the aborted task has email alerts enabled // 2.2 No : Does the aborted reload task have alerts turned on (using custom property)? globals.logger.verbose( - `EMAIL RELOAD TASK ABORTED ALERT: Only send alert emails for tasks with email-alert-CP "${emailAlertCpName}" set`, + `[QSEOW] EMAIL RELOAD TASK ABORTED ALERT: Only send alert emails for tasks with email-alert-CP "${emailAlertCpName}" set`, ); const sendAlert = await isCustomPropertyValueSet(reloadParams.taskId, emailAlertCpName, emailAlertCpEnabledValue); if (sendAlert === true) { globals.logger.debug( - `EMAIL RELOAD TASK ABORTED ALERT: Added send list based on email-alert-CP: ${JSON.stringify(globalSendList, null, 2)}`, + `[QSEOW] EMAIL RELOAD TASK ABORTED ALERT: Added send list based on email-alert-CP: ${JSON.stringify(globalSendList, null, 2)}`, ); // 2.2.1 Yes: Add system-wide list of recipients to send list if (globalSendList?.length > 0) { @@ -740,12 +752,12 @@ export async function sendReloadTaskAbortedNotificationEmail(reloadParams) { // Does the main sendlist contain any email addresses? Warn if not if (mainSendList?.length === 0) { globals.logger.warn( - `EMAIL RELOAD TASK ABORTED ALERT: No email addresses defined for alert email to app "${reloadParams.appName}", ID=${reloadParams.appId}`, + `[QSEOW] EMAIL RELOAD TASK ABORTED ALERT: No email addresses defined for alert email to app "${reloadParams.appName}", ID=${reloadParams.appId}`, ); } } else { globals.logger.warn( - `EMAIL RELOAD TASK ABORTED ALERT: No email address for owner of app "${reloadParams.appName}", ID=${reloadParams.appId}`, + `[QSEOW] EMAIL RELOAD TASK ABORTED ALERT: No email address for owner of app "${reloadParams.appName}", ID=${reloadParams.appId}`, ); } } @@ -755,15 +767,15 @@ export async function sendReloadTaskAbortedNotificationEmail(reloadParams) { // Debug globals.logger.verbose( - `EMAIL RELOAD TASK ABORTED ALERT: Final send list for failed task "${reloadParams.taskName}": ${JSON.stringify( + `[QSEOW] EMAIL RELOAD TASK ABORTED ALERT: Final send list for failed task "${reloadParams.taskName}": ${JSON.stringify( mainSendListUnique, null, 2, )}`, ); - globals.logger.verbose(`EMAIL RELOAD TASK ABORTED ALERT: App owner recipients: ${emailRecipientsVerbose.appOwner}`); - globals.logger.verbose(`EMAIL RELOAD TASK ABORTED ALERT: Shared all tasks recipients: ${emailRecipientsVerbose.shared}`); - globals.logger.verbose(`EMAIL RELOAD TASK ABORTED ALERT: Task specific recipients: ${emailRecipientsVerbose.taskSpecific}`); + globals.logger.verbose(`[QSEOW] EMAIL RELOAD TASK ABORTED ALERT: App owner recipients: ${emailRecipientsVerbose.appOwner}`); + globals.logger.verbose(`[QSEOW] EMAIL RELOAD TASK ABORTED ALERT: Shared all tasks recipients: ${emailRecipientsVerbose.shared}`); + globals.logger.verbose(`[QSEOW] EMAIL RELOAD TASK ABORTED ALERT: Task specific recipients: ${emailRecipientsVerbose.taskSpecific}`); if (isSmtpConfigOk() === false) { return 1; @@ -791,7 +803,7 @@ export async function sendReloadTaskAbortedNotificationEmail(reloadParams) { scriptLogData.scriptLogTail = ''; } - globals.logger.debug(`EMAIL RELOAD TASK ABORTED ALERT: Script log data:\n${JSON.stringify(scriptLogData, null, 2)}`); + globals.logger.debug(`[QSEOW] EMAIL RELOAD TASK ABORTED ALERT: Script log data:\n${JSON.stringify(scriptLogData, null, 2)}`); // Get Sense URLs from config file. Can be used as template fields. const senseUrls = getQlikSenseUrls(); @@ -855,6 +867,8 @@ export async function sendReloadTaskAbortedNotificationEmail(reloadParams) { executionStatusText: scriptLogData.executionStatusText, executionDetails: scriptLogData.executionDetails, scriptLogSize: scriptLogData.scriptLogSize, + scriptLogSizeRows: scriptLogData.scriptLogSizeRows, + scriptLogSizeCharacters: scriptLogData.scriptLogSizeCharacters, scriptLogHead: scriptLogData.scriptLogHead, scriptLogTail: scriptLogData.scriptLogTail, scriptLogTailCount: scriptLogData.scriptLogTailCount, @@ -876,10 +890,10 @@ export async function sendReloadTaskAbortedNotificationEmail(reloadParams) { .then(async (rateLimiterRes) => { try { globals.logger.info( - `EMAIL RELOAD TASK ABORTED ALERT: Rate limiting check passed for aborted task notification. Task name: "${reloadParams.taskName}", Recipient: "${recipientEmailAddress}"`, + `[QSEOW] EMAIL RELOAD TASK ABORTED ALERT: Rate limiting check passed for aborted task notification. Task name: "${reloadParams.taskName}", Recipient: "${recipientEmailAddress}"`, ); globals.logger.debug( - `EMAIL RELOAD TASK ABORTED ALERT: Rate limiting details "${JSON.stringify(rateLimiterRes, null, 2)}"`, + `[QSEOW] EMAIL RELOAD TASK ABORTED ALERT: Rate limiting details "${JSON.stringify(rateLimiterRes, null, 2)}"`, ); // Only send email if there is at least one recipient @@ -894,17 +908,17 @@ export async function sendReloadTaskAbortedNotificationEmail(reloadParams) { templateContext, ); } else { - globals.logger.warn(`EMAIL RELOAD TASK ABORTED ALERT: No recipients to send alert email to.`); + globals.logger.warn(`[QSEOW] EMAIL RELOAD TASK ABORTED ALERT: No recipients to send alert email to.`); } } catch (err) { - globals.logger.error(`EMAIL RELOAD TASK ABORTED ALERT: ${err}`); + globals.logger.error(`[QSEOW] EMAIL RELOAD TASK ABORTED ALERT: ${err}`); } }) .catch((err) => { globals.logger.warn( - `EMAIL RELOAD TASK ABORTED ALERT: Rate limiting failed. Not sending reload notification email for task "${reloadParams.taskName}" to "${recipientEmailAddress}"`, + `[QSEOW] EMAIL RELOAD TASK ABORTED ALERT: Rate limiting failed. Not sending reload notification email for task "${reloadParams.taskName}" to "${recipientEmailAddress}"`, ); - globals.logger.debug(`EMAIL RELOAD TASK ABORTED ALERT: Rate limiting details "${JSON.stringify(err, null, 2)}"`); + globals.logger.debug(`[QSEOW] EMAIL RELOAD TASK ABORTED ALERT: Rate limiting details "${JSON.stringify(err, null, 2)}"`); }); } } @@ -948,7 +962,7 @@ export async function sendReloadTaskSuccessNotificationEmail(reloadParams) { if (taskSpecificAlertEmailAddresses?.length > 0) { globals.logger.debug( - `EMAIL RELOAD TASK SUCCESS ALERT: Added task specific send list: ${JSON.stringify(taskSpecificAlertEmailAddresses, null, 2)}`, + `[QSEOW] EMAIL RELOAD TASK SUCCESS ALERT: Added task specific send list: ${JSON.stringify(taskSpecificAlertEmailAddresses, null, 2)}`, ); mainSendList = mainSendList.concat(taskSpecificAlertEmailAddresses); @@ -958,11 +972,11 @@ export async function sendReloadTaskSuccessNotificationEmail(reloadParams) { // 2 Should alert emails be sent for all successful reload tasks? if (globals.config.get('Butler.emailNotification.reloadTaskSuccess.alertEnableByCustomProperty.enable') === false) { // 2.1 Yes: Add system-wide list of recipients to send list - globals.logger.verbose(`EMAIL RELOAD TASK SUCCESS ALERT: Send alert emails for all tasks`); + globals.logger.verbose(`[QSEOW] EMAIL RELOAD TASK SUCCESS ALERT: Send alert emails for all tasks`); if (globalSendList?.length > 0) { globals.logger.debug( - `EMAIL RELOAD TASK SUCCESS ALERT: Added global send list for succeesful task: ${JSON.stringify(globalSendList, null, 2)}`, + `[QSEOW] EMAIL RELOAD TASK SUCCESS ALERT: Added global send list for succeesful task: ${JSON.stringify(globalSendList, null, 2)}`, ); mainSendList = mainSendList.concat(globalSendList); emailRecipientsVerbose.common = emailRecipientsVerbose.common.concat(globalSendList); @@ -971,14 +985,14 @@ export async function sendReloadTaskSuccessNotificationEmail(reloadParams) { // Only send alert email if the successful task has email alerts enabled // 2.2 No : Does the failed reload task have alerts turned on (using custom property)? globals.logger.verbose( - `EMAIL RELOAD TASK SUCCESS ALERT: Only send alert emails for tasks with email-alert-CP "${emailAlertCpName}" set`, + `[QSEOW] EMAIL RELOAD TASK SUCCESS ALERT: Only send alert emails for tasks with email-alert-CP "${emailAlertCpName}" set`, ); const sendAlert = await isCustomPropertyValueSet(reloadParams.taskId, emailAlertCpName, emailAlertCpEnabledValue); if (sendAlert === true) { globals.logger.debug( - `EMAIL RELOAD TASK SUCCESS ALERT: Added send list based on email-alert-CP: ${JSON.stringify(globalSendList, null, 2)}`, + `[QSEOW] EMAIL RELOAD TASK SUCCESS ALERT: Added send list based on email-alert-CP: ${JSON.stringify(globalSendList, null, 2)}`, ); // 2.2.1 Yes: Add system-wide list of recipients to send list if (globalSendList?.length > 0) { @@ -995,14 +1009,14 @@ export async function sendReloadTaskSuccessNotificationEmail(reloadParams) { // Debug globals.logger.verbose( - `EMAIL RELOAD TASK SUCCESS ALERT: Final send list for successful task "${reloadParams.taskName}": ${JSON.stringify( + `[QSEOW] EMAIL RELOAD TASK SUCCESS ALERT: Final send list for successful task "${reloadParams.taskName}": ${JSON.stringify( mainSendListUnique, null, 2, )}`, ); - globals.logger.verbose(`EMAIL RELOAD TASK SUCCESS ALERT: Shared all tasks recipients: ${emailRecipientsVerbose.shared}`); - globals.logger.verbose(`EMAIL RELOAD TASK SUCCESS ALERT: Task specific recipients: ${emailRecipientsVerbose.taskSpecific}`); + globals.logger.verbose(`[QSEOW] EMAIL RELOAD TASK SUCCESS ALERT: Shared all tasks recipients: ${emailRecipientsVerbose.shared}`); + globals.logger.verbose(`[QSEOW] EMAIL RELOAD TASK SUCCESS ALERT: Task specific recipients: ${emailRecipientsVerbose.taskSpecific}`); if (isSmtpConfigOk() === false) { return 1; @@ -1030,8 +1044,8 @@ export async function sendReloadTaskSuccessNotificationEmail(reloadParams) { scriptLogData.scriptLogTail = ''; } - globals.logger.debug(`EMAIL RELOAD TASK SUCCESS ALERT: Script log head:\n${scriptLogData.scriptLogHead}`); - globals.logger.debug(`EMAIL RELOAD TASK SUCCESS ALERT: Script log tail:\n${scriptLogData.scriptLogTail}`); + globals.logger.debug(`[QSEOW] EMAIL RELOAD TASK SUCCESS ALERT: Script log head:\n${scriptLogData.scriptLogHead}`); + globals.logger.debug(`[QSEOW] EMAIL RELOAD TASK SUCCESS ALERT: Script log tail:\n${scriptLogData.scriptLogTail}`); // Get app owner const appOwner = await getAppOwner(reloadParams.appId); @@ -1098,6 +1112,8 @@ export async function sendReloadTaskSuccessNotificationEmail(reloadParams) { executionStatusText: scriptLogData.executionStatusText, executionDetails: scriptLogData.executionDetails, scriptLogSize: scriptLogData.scriptLogSize, + scriptLogSizeRows: scriptLogData.scriptLogSizeRows, + scriptLogSizeCharacters: scriptLogData.scriptLogSizeCharacters, scriptLogHead: scriptLogData.scriptLogHead, scriptLogTail: scriptLogData.scriptLogTail, scriptLogTailCount: scriptLogData.scriptLogTailCount, @@ -1119,10 +1135,10 @@ export async function sendReloadTaskSuccessNotificationEmail(reloadParams) { .then(async (rateLimiterRes) => { try { globals.logger.info( - `EMAIL RELOAD TASK SUCCESS ALERT: Rate limiting check passed for successful task notification. Task name: "${reloadParams.taskName}", Recipient: "${recipientEmailAddress}"`, + `[QSEOW] EMAIL RELOAD TASK SUCCESS ALERT: Rate limiting check passed for successful task notification. Task name: "${reloadParams.taskName}", Recipient: "${recipientEmailAddress}"`, ); globals.logger.debug( - `EMAIL RELOAD TASK SUCCESS ALERT: Rate limiting details "${JSON.stringify(rateLimiterRes, null, 2)}"`, + `[QSEOW] EMAIL RELOAD TASK SUCCESS ALERT: Rate limiting details "${JSON.stringify(rateLimiterRes, null, 2)}"`, ); // Only send email if there is at least one recipient @@ -1137,17 +1153,17 @@ export async function sendReloadTaskSuccessNotificationEmail(reloadParams) { templateContext, ); } else { - globals.logger.warn(`EMAIL RELOAD TASK SUCCESS ALERT: No recipients to send alert email to.`); + globals.logger.warn(`[QSEOW] EMAIL RELOAD TASK SUCCESS ALERT: No recipients to send alert email to.`); } } catch (err) { - globals.logger.error(`EMAIL RELOAD TASK SUCCESS ALERT: ${err}`); + globals.logger.error(`[QSEOW] EMAIL RELOAD TASK SUCCESS ALERT: ${err}`); } }) .catch((err) => { globals.logger.warn( - `EMAIL RELOAD TASK SUCCESS ALERT: Rate limiting failed. Not sending reload notification email for task "${reloadParams.taskName}" to "${recipientEmailAddress}"`, + `[QSEOW] EMAIL RELOAD TASK SUCCESS ALERT: Rate limiting failed. Not sending reload notification email for task "${reloadParams.taskName}" to "${recipientEmailAddress}"`, ); - globals.logger.debug(`EMAIL RELOAD TASK SUCCESS ALERT: Rate limiting details "${JSON.stringify(err, null, 2)}"`); + globals.logger.debug(`[QSEOW] EMAIL RELOAD TASK SUCCESS ALERT: Rate limiting details "${JSON.stringify(err, null, 2)}"`); }); } } @@ -1194,7 +1210,7 @@ export async function sendServiceMonitorNotificationEmail(serviceParams) { mainSendList = mainSendList.concat(globalSendList); } else { // Warn there are no recipients to send email to - globals.logger.warn(`EMAIL SERVICE MONITOR: No recipients to send alert email to.`); + globals.logger.warn(`[QSEOW] EMAIL SERVICE MONITOR: No recipients to send alert email to.`); } // Make sure send list does not contain any duplicate email addresses @@ -1208,9 +1224,11 @@ export async function sendServiceMonitorNotificationEmail(serviceParams) { .then(async (rateLimiterRes) => { try { globals.logger.info( - `EMAIL SERVICE MONITOR: Rate limiting check passed for service monitor notification. Host: "${serviceParams.host}", service: "${serviceParams.serviceName}", recipient: "${recipientEmailAddress}"`, + `[QSEOW] EMAIL SERVICE MONITOR: Rate limiting check passed for service monitor notification. Host: "${serviceParams.host}", service: "${serviceParams.serviceName}", recipient: "${recipientEmailAddress}"`, + ); + globals.logger.debug( + `[QSEOW] EMAIL SERVICE MONITOR: Rate limiting details "${JSON.stringify(rateLimiterRes, null, 2)}"`, ); - globals.logger.debug(`EMAIL SERVICE MONITOR: Rate limiting details "${JSON.stringify(rateLimiterRes, null, 2)}"`); // Only send email if there is at least one recipient if (recipientEmailAddress.length > 0) { @@ -1236,18 +1254,18 @@ export async function sendServiceMonitorNotificationEmail(serviceParams) { ); } } else { - globals.logger.warn(`EMAIL SERVICE MONITOR: No recipients to send alert email to.`); + globals.logger.warn(`[QSEOW] EMAIL SERVICE MONITOR: No recipients to send alert email to.`); } } catch (err) { - globals.logger.error(`EMAIL SERVICE MONITOR: ${err}`); + globals.logger.error(`[QSEOW] EMAIL SERVICE MONITOR: ${err}`); } }) // eslint-disable-next-line no-loop-func .catch((err) => { globals.logger.warn( - `EMAIL SERVICE MONITOR: Rate limiting failed. Not sending reload notification email for service service "${serviceParams.serviceName}" on host "${serviceParams.host}" to "${recipientEmailAddress}"`, + `[QSEOW] EMAIL SERVICE MONITOR: Rate limiting failed. Not sending reload notification email for service service "${serviceParams.serviceName}" on host "${serviceParams.host}" to "${recipientEmailAddress}"`, ); - globals.logger.debug(`EMAIL SERVICE MONITOR: Rate limiting details "${JSON.stringify(err, null, 2)}"`); + globals.logger.debug(`[QSEOW] EMAIL SERVICE MONITOR: Rate limiting details "${JSON.stringify(err, null, 2)}"`); }); } } diff --git a/src/lib/webhook_notification.js b/src/lib/qseow/webhook_notification.js similarity index 82% rename from src/lib/webhook_notification.js rename to src/lib/qseow/webhook_notification.js index 1a8c9841..9dad53ef 100644 --- a/src/lib/webhook_notification.js +++ b/src/lib/qseow/webhook_notification.js @@ -3,8 +3,8 @@ import axios from 'axios'; import fs from 'fs'; import https from 'https'; -import globals from '../globals.js'; -import getAppOwner from '../qrs_util/get_app_owner.js'; +import globals from '../../globals.js'; +import getAppOwner from '../../qrs_util/get_app_owner.js'; let rateLimiterMemoryFailedReloads; let rateLimiterMemoryAbortedReloads; @@ -84,7 +84,7 @@ function getOutgoingWebhookReloadFailedNotificationConfigOk() { ) { // Not enough info in config file globals.logger.error( - 'WEBHOOK OUT RELOAD TASK FAILED: Reload failure outgoing webhook config info missing in Butler config file', + '[QSEOW] WEBHOOKOUT RELOAD TASK FAILED: Reload failure outgoing webhook config info missing in Butler config file', ); return false; } @@ -97,7 +97,7 @@ function getOutgoingWebhookReloadFailedNotificationConfigOk() { webhooks: globals.config.get('Butler.webhookNotification.reloadTaskFailure.webhooks'), }; } catch (err) { - globals.logger.error(`WEBHOOK OUT RELOAD TASK FAILED: ${err}`); + globals.logger.error(`[QSEOW] WEBHOOKOUT RELOAD TASK FAILED: ${err}`); return false; } } @@ -111,7 +111,7 @@ function getOutgoingWebhookReloadAbortedNotificationConfigOk() { ) { // Not enough info in config file globals.logger.error( - 'WEBHOOK OUT RELOAD TASK ABORTED: Reload aborted outgoing webhook config info missing in Butler config file', + '[QSEOW] WEBHOOKOUT RELOAD TASK ABORTED: Reload aborted outgoing webhook config info missing in Butler config file', ); return false; } @@ -124,7 +124,7 @@ function getOutgoingWebhookReloadAbortedNotificationConfigOk() { webhooks: globals.config.get('Butler.webhookNotification.reloadTaskAborted.webhooks'), }; } catch (err) { - globals.logger.error(`WEBHOOK OUT RELOAD TASK ABORTED: ${err}`); + globals.logger.error(`[QSEOW] WEBHOOKOUT RELOAD TASK ABORTED: ${err}`); return false; } } @@ -185,7 +185,7 @@ function getOutgoingWebhookQlikSenseServerLicenseMonitorConfig() { webhooks: globals.config.get('Butler.webhookNotification.qlikSenseServerLicenseMonitor.webhooks'), }; } catch (err) { - globals.logger.error(`WEBHOOK OUT QLIK SENSE SERVER LICENSE MONITOR: ${err}`); + globals.logger.error(`[QSEOW] WEBHOOKOUT QLIK SENSE SERVER LICENSE MONITOR: ${err}`); return false; } } @@ -200,7 +200,7 @@ function getOutgoingWebhookQlikSenseServerLicenseExpiryAlertConfig() { webhooks: globals.config.get('Butler.webhookNotification.qlikSenseServerLicenseExpiryAlert.webhooks'), }; } catch (err) { - globals.logger.error(`WEBHOOK OUT QLIK SENSE SERVER LICENSE EXPIRY ALERT: ${err}`); + globals.logger.error(`[QSEOW] WEBHOOKOUT QLIK SENSE SERVER LICENSE EXPIRY ALERT: ${err}`); return false; } } @@ -216,8 +216,8 @@ async function sendOutgoingWebhook(webhookConfig, reloadParams) { if (webhookConfig.webhooks) { // eslint-disable-next-line no-restricted-syntax for (const webhook of webhookConfig.webhooks) { - globals.logger.info(`WEBHOOKOUT: Processing webhook "${webhook.description}"`); - globals.logger.debug(`WEBHOOKOUT: Webhook details ${JSON.stringify(webhook)}`); + globals.logger.info(`[QSEOW] WEBHOOKOUT: Processing webhook "${webhook.description}"`); + globals.logger.debug(`[QSEOW] WEBHOOKOUT: Webhook details ${JSON.stringify(webhook)}`); // Only process the webhook if all required info is available let lowercaseMethod = null; @@ -239,25 +239,27 @@ async function sendOutgoingWebhook(webhookConfig, reloadParams) { if (webhook.cert && webhook.cert.enable === true) { // Make sure webhook.cert.rejectUnauthorized is a boolean if (typeof webhook.cert.rejectUnauthorized !== 'boolean') { - throw new Error('WEBHOOKOUT: Webhook cert.rejectUnauthorized property should be a boolean '); + throw new Error('[QSEOW] WEBHOOKOUT: Webhook cert.rejectUnauthorized property should be a boolean '); } // Make sure CA cert file in webhook.cert.certCA is a string if (typeof webhook.cert.certCA !== 'string') { - throw new Error('WEBHOOKOUT: Webhook cert.certCA property should be a string'); + throw new Error('[QSEOW] WEBHOOKOUT: Webhook cert.certCA property should be a string'); } // Make sure the CA cert file exists if (!fs.existsSync(webhook.cert.certCA)) { - throw new Error(`WEBHOOKOUT: CA cert file not found: ${webhook.cert.certCA}`); + throw new Error(`[QSEOW] WEBHOOKOUT: CA cert file not found: ${webhook.cert.certCA}`); } } } catch (err) { - globals.logger.error(`WEBHOOKOUT: ${err}. Invalid outgoing webhook config: ${JSON.stringify(webhook, null, 2)}`); + globals.logger.error( + `[QSEOW] WEBHOOKOUT: ${err}. Invalid outgoing webhook config: ${JSON.stringify(webhook, null, 2)}`, + ); throw err; } - globals.logger.debug(`WEBHOOKOUT: Webhook config is valid: ${JSON.stringify(webhook)}`); + globals.logger.debug(`[QSEOW] WEBHOOKOUT: Webhook config is valid: ${JSON.stringify(webhook)}`); axiosRequest = { timeout: 10000, @@ -284,7 +286,7 @@ async function sendOutgoingWebhook(webhookConfig, reloadParams) { url.search = params.toString(); - globals.logger.silly(`WEBHOOKOUT: Final GET webhook URL: ${url.toString()}`); + globals.logger.silly(`[QSEOW] WEBHOOKOUT: Final GET webhook URL: ${url.toString()}`); axiosRequest.method = 'get'; axiosRequest.url = url.toString(); @@ -381,40 +383,40 @@ async function sendOutgoingWebhook(webhookConfig, reloadParams) { try { // eslint-disable-next-line no-await-in-loop const response = await axios.request(axiosRequest); - globals.logger.debug(`WEBHOOKOUT: Webhook response: ${response}`); + globals.logger.debug(`[QSEOW] WEBHOOKOUT: Webhook response: ${response}`); } catch (err) { if (err.message) { - globals.logger.error(`WEBHOOKOUT: Webhook call failed: ${err.message}`); + globals.logger.error(`[QSEOW] WEBHOOKOUT: Webhook call failed: ${err.message}`); // err.response.status 404 could mean that the webhook URL is incorrect if (err.response && err.response.status === 404) { - globals.logger.error(`WEBHOOKOUT: 404 error could mean that the webhook URL is incorrect`); + globals.logger.error(`[QSEOW] WEBHOOKOUT: 404 error could mean that the webhook URL is incorrect`); } - globals.logger.error(`WEBHOOKOUT: Webhook url: ${axiosRequest.url}`); - globals.logger.error(`WEBHOOKOUT: Webhook config: ${JSON.stringify(webhook, null, 2)}`); + globals.logger.error(`[QSEOW] WEBHOOKOUT: Webhook url: ${axiosRequest.url}`); + globals.logger.error(`[QSEOW] WEBHOOKOUT: Webhook config: ${JSON.stringify(webhook, null, 2)}`); } // If neither message nor stack is available, just log the error object if (!err.message && !err.stack) { - globals.logger.error(`WEBHOOKOUT: Webhook call failed: ${JSON.stringify(err, null, 2)}`); + globals.logger.error(`[QSEOW] WEBHOOKOUT: Webhook call failed: ${JSON.stringify(err, null, 2)}`); } } } } else { - globals.logger.info('WEBHOOKOUT: No outgoing webhooks to process'); + globals.logger.info('[QSEOW] WEBHOOKOUT: No outgoing webhooks to process'); } } catch (err) { if (err.message) { - globals.logger.error(`WEBHOOKOUT 1 message: ${err.message}`); + globals.logger.error(`[QSEOW] WEBHOOKOUT 1 message: ${err.message}`); } if (err.stack) { - globals.logger.error(`WEBHOOKOUT 1 stack: ${err.stack}`); + globals.logger.error(`[QSEOW] WEBHOOKOUT 1 stack: ${err.stack}`); } // If neither message nor stack is available, just log the error object if (!err.message && !err.stack) { - globals.logger.error(`WEBHOOKOUT 1: ${JSON.stringify(err, null, 2)}`); + globals.logger.error(`[QSEOW] WEBHOOKOUT 1: ${JSON.stringify(err, null, 2)}`); } } } @@ -450,17 +452,17 @@ async function sendOutgoingWebhookServiceMonitor(webhookConfig, serviceParams) { if (webhook.cert && webhook.cert.enable === true) { // Make sure webhook.cert.rejectUnauthorized is a boolean if (typeof webhook.cert.rejectUnauthorized !== 'boolean') { - throw new Error('WEBHOOKOUT: Webhook cert.rejectUnauthorized property should be a boolean '); + throw new Error('[QSEOW] WEBHOOKOUT: Webhook cert.rejectUnauthorized property should be a boolean '); } // Make sure CA cert file in webhook.cert.certCA is a string if (typeof webhook.cert.certCA !== 'string') { - throw new Error('WEBHOOKOUT: Webhook cert.certCA property should be a string'); + throw new Error('[QSEOW] WEBHOOKOUT: Webhook cert.certCA property should be a string'); } // Make sure the CA cert file exists if (!fs.existsSync(webhook.cert.certCA)) { - throw new Error(`WEBHOOKOUT: CA cert file not found: ${webhook.cert.certCA}`); + throw new Error(`[QSEOW] WEBHOOKOUT: CA cert file not found: ${webhook.cert.certCA}`); } } } catch (err) { @@ -603,8 +605,8 @@ async function sendOutgoingWebhookQlikSenseServerLicense(webhookConfig, serverLi if (webhookConfig.webhooks) { // eslint-disable-next-line no-restricted-syntax for (const webhook of webhookConfig.webhooks) { - globals.logger.info(`WEBHOOKOUT QLIK SENSE SERVER LICENSE MONITOR: Processing webhook "${webhook.description}"`); - globals.logger.debug(`WEBHOOKOUT QLIK SENSE SERVER LICENSE MONITOR: Webhook details ${JSON.stringify(webhook)}`); + globals.logger.info(`[QSEOW] WEBHOOKOUT QLIK SENSE SERVER LICENSE MONITOR: Processing webhook "${webhook.description}"`); + globals.logger.debug(`[QSEOW] WEBHOOKOUT QLIK SENSE SERVER LICENSE MONITOR: Webhook details ${JSON.stringify(webhook)}`); // Only process the webhook if all required info is available let lowercaseMethod = null; @@ -627,25 +629,27 @@ async function sendOutgoingWebhookQlikSenseServerLicense(webhookConfig, serverLi // Make sure webhook.cert.rejectUnauthorized is a boolean if (typeof webhook.cert.rejectUnauthorized !== 'boolean') { throw new Error( - 'WEBHOOKOUT QLIK SENSE SERVER LICENSE MONITOR: Webhook cert.rejectUnauthorized property should be a boolean ', + '[QSEOW] WEBHOOKOUT QLIK SENSE SERVER LICENSE MONITOR: Webhook cert.rejectUnauthorized property should be a boolean ', ); } // Make sure CA cert file in webhook.cert.certCA is a string if (typeof webhook.cert.certCA !== 'string') { throw new Error( - 'WEBHOOKOUT QLIK SENSE SERVER LICENSE MONITOR: Webhook cert.certCA property should be a string', + '[QSEOW] WEBHOOKOUT QLIK SENSE SERVER LICENSE MONITOR: Webhook cert.certCA property should be a string', ); } // Make sure the CA cert file exists if (!fs.existsSync(webhook.cert.certCA)) { - throw new Error(`WEBHOOKOUT QLIK SENSE SERVER LICENSE MONITOR: CA cert file not found: ${webhook.cert.certCA}`); + throw new Error( + `[QSEOW] WEBHOOKOUT QLIK SENSE SERVER LICENSE MONITOR: CA cert file not found: ${webhook.cert.certCA}`, + ); } } } catch (err) { globals.logger.error( - `WEBHOOKOUT QLIK SENSE SERVER LICENSE MONITOR: ${err}. Invalid outgoing webhook config: ${JSON.stringify( + `[QSEOW] WEBHOOKOUT QLIK SENSE SERVER LICENSE MONITOR: ${err}. Invalid outgoing webhook config: ${JSON.stringify( webhook, null, 2, @@ -654,7 +658,9 @@ async function sendOutgoingWebhookQlikSenseServerLicense(webhookConfig, serverLi throw err; } - globals.logger.debug(`WEBHOOKOUT QLIK SENSE SERVER LICENSE MONITOR: Webhook config is valid: ${JSON.stringify(webhook)}`); + globals.logger.debug( + `[QSEOW] WEBHOOKOUT QLIK SENSE SERVER LICENSE MONITOR: Webhook config is valid: ${JSON.stringify(webhook)}`, + ); axiosRequest = { timeout: 10000, @@ -670,7 +676,7 @@ async function sendOutgoingWebhookQlikSenseServerLicense(webhookConfig, serverLi url.search = params.toString(); - globals.logger.silly(`WEBHOOKOUT QLIK SENSE SERVER LICENSE MONITOR: Final GET webhook URL: ${url.toString()}`); + globals.logger.silly(`[QSEOW] WEBHOOKOUT QLIK SENSE SERVER LICENSE MONITOR: Final GET webhook URL: ${url.toString()}`); axiosRequest.method = 'get'; axiosRequest.url = url.toString(); @@ -743,23 +749,23 @@ async function sendOutgoingWebhookQlikSenseServerLicense(webhookConfig, serverLi // eslint-disable-next-line no-await-in-loop const response = await axios.request(axiosRequest); - globals.logger.debug(`WEBHOOKOUT QLIK SENSE SERVER LICENSE MONITOR: Webhook response: ${response}`); + globals.logger.debug(`[QSEOW] WEBHOOKOUT QLIK SENSE SERVER LICENSE MONITOR: Webhook response: ${response}`); } } else { - globals.logger.info('WEBHOOKOUT QLIK SENSE SERVER LICENSE MONITOR: No outgoing webhooks to process'); + globals.logger.info('[QSEOW] WEBHOOKOUT QLIK SENSE SERVER LICENSE MONITOR: No outgoing webhooks to process'); } } catch (err) { if (err.message) { - globals.logger.error(`WEBHOOKOUT QLIK SENSE SERVER LICENSE MONITOR 1 message: ${err.message}`); + globals.logger.error(`[QSEOW] WEBHOOKOUT QLIK SENSE SERVER LICENSE MONITOR 1 message: ${err.message}`); } if (err.stack) { - globals.logger.error(`WEBHOOKOUT QLIK SENSE SERVER LICENSE MONITOR 1 stack: ${err.stack}`); + globals.logger.error(`[QSEOW] WEBHOOKOUT QLIK SENSE SERVER LICENSE MONITOR 1 stack: ${err.stack}`); } // If neither message nor stack is available, just log the error object if (!err.message && !err.stack) { - globals.logger.error(`WEBHOOKOUT QLIK SENSE SERVER LICENSE MONITOR 1: ${JSON.stringify(err, null, 2)}`); + globals.logger.error(`[QSEOW] WEBHOOKOUT QLIK SENSE SERVER LICENSE MONITOR 1: ${JSON.stringify(err, null, 2)}`); } } } @@ -770,10 +776,10 @@ export function sendReloadTaskFailureNotificationWebhook(reloadParams) { .then(async (rateLimiterRes) => { try { globals.logger.info( - `WEBHOOK OUT RELOAD TASK FAILED: Rate limiting check passed for failed task notification. Task name: "${reloadParams.taskName}"`, + `[QSEOW] WEBHOOKOUT RELOAD TASK FAILED: Rate limiting check passed for failed task notification. Task name: "${reloadParams.taskName}"`, ); globals.logger.verbose( - `WEBHOOK OUT RELOAD TASK FAILED: Rate limiting details "${JSON.stringify(rateLimiterRes, null, 2)}"`, + `[QSEOW] WEBHOOKOUT RELOAD TASK FAILED: Rate limiting details "${JSON.stringify(rateLimiterRes, null, 2)}"`, ); // Make sure Slack sending is enabled in the config file and that we have all required settings @@ -784,15 +790,17 @@ export function sendReloadTaskFailureNotificationWebhook(reloadParams) { sendOutgoingWebhook(webhookConfig, reloadParams); } catch (err) { - globals.logger.error(`WEBHOOK OUT RELOAD TASK FAILED: ${err}`); + globals.logger.error(`[QSEOW] WEBHOOKOUT RELOAD TASK FAILED: ${err}`); } return true; }) .catch((rateLimiterRes) => { globals.logger.verbose( - `WEBHOOK OUT RELOAD TASK FAILED: Rate limiting failed. Not sending reload failure notification via outgoing webhook for task "${reloadParams.taskName}"`, + `[QSEOW] WEBHOOKOUT RELOAD TASK FAILED: Rate limiting failed. Not sending reload failure notification via outgoing webhook for task "${reloadParams.taskName}"`, + ); + globals.logger.verbose( + `[QSEOW] WEBHOOKOUT RELOAD TASK FAILED: Rate limiting details "${JSON.stringify(rateLimiterRes, null, 2)}"`, ); - globals.logger.verbose(`WEBHOOK OUT RELOAD TASK FAILED: Rate limiting details "${JSON.stringify(rateLimiterRes, null, 2)}"`); }); } @@ -802,10 +810,10 @@ export function sendReloadTaskAbortedNotificationWebhook(reloadParams) { .then(async (rateLimiterRes) => { try { globals.logger.info( - `WEBHOOK OUT RELOAD TASK ABORTED: Rate limiting check passed for aborted task notification. Task name: "${reloadParams.taskName}"`, + `[QSEOW] WEBHOOKOUT RELOAD TASK ABORTED: Rate limiting check passed for aborted task notification. Task name: "${reloadParams.taskName}"`, ); globals.logger.verbose( - `WEBHOOK OUT RELOAD TASK ABORTED: Rate limiting details "${JSON.stringify(rateLimiterRes, null, 2)}"`, + `[QSEOW] WEBHOOKOUT RELOAD TASK ABORTED: Rate limiting details "${JSON.stringify(rateLimiterRes, null, 2)}"`, ); // Make sure outgoing webhooks are enabled in the config file and that we have all required settings @@ -816,15 +824,17 @@ export function sendReloadTaskAbortedNotificationWebhook(reloadParams) { sendOutgoingWebhook(webhookConfig, reloadParams); } catch (err) { - globals.logger.error(`WEBHOOK OUT RELOAD TASK ABORTED: ${err}`); + globals.logger.error(`[QSEOW] WEBHOOKOUT RELOAD TASK ABORTED: ${err}`); } return true; }) .catch((rateLimiterRes) => { globals.logger.verbose( - `WEBHOOK OUT RELOAD TASK ABORTED: Rate limiting failed. Not sending reload aborted notification via outgoing webhook for task "${reloadParams.taskName}"`, + `[QSEOW] WEBHOOKOUT RELOAD TASK ABORTED: Rate limiting failed. Not sending reload aborted notification via outgoing webhook for task "${reloadParams.taskName}"`, + ); + globals.logger.verbose( + `[QSEOW] WEBHOOKOUT RELOAD TASK ABORTED: Rate limiting details "${JSON.stringify(rateLimiterRes, null, 2)}"`, ); - globals.logger.verbose(`WEBHOOK OUT RELOAD TASK ABORTED: Rate limiting details "${JSON.stringify(rateLimiterRes, null, 2)}"`); }); } @@ -862,9 +872,11 @@ export function sendServiceMonitorWebhook(svc) { }) .catch((rateLimiterRes) => { globals.logger.verbose( - `WEBHOOK OUT RELOAD TASK FAILED: Rate limiting failed. Not sending service monitor notification via outgoing webhook for service "${svc.serviceName}"`, + `[QSEOW] WEBHOOKOUT RELOAD TASK FAILED: Rate limiting failed. Not sending service monitor notification via outgoing webhook for service "${svc.serviceName}"`, + ); + globals.logger.verbose( + `[QSEOW] WEBHOOKOUT RELOAD TASK FAILED: Rate limiting details "${JSON.stringify(rateLimiterRes, null, 2)}"`, ); - globals.logger.verbose(`WEBHOOK OUT RELOAD TASK FAILED: Rate limiting details "${JSON.stringify(rateLimiterRes, null, 2)}"`); }); } @@ -887,10 +899,10 @@ export async function callQlikSenseServerLicenseWebhook(serverLicenseInfo) { .then(async (rateLimiterRes) => { try { globals.logger.info( - `WEBHOOK OUT QLIK SENSE SERVER LICENSE MONITOR: Rate limiting check passed for Qlik Sense server license monitor notification`, + `[QSEOW] WEBHOOKOUT QLIK SENSE SERVER LICENSE MONITOR: Rate limiting check passed for Qlik Sense server license monitor notification`, ); globals.logger.verbose( - `WEBHOOK OUT QLIK SENSE SERVER LICENSE MONITOR: Rate limiting details "${JSON.stringify(rateLimiterRes, null, 2)}"`, + `[QSEOW] WEBHOOKOUT QLIK SENSE SERVER LICENSE MONITOR: Rate limiting details "${JSON.stringify(rateLimiterRes, null, 2)}"`, ); // Make sure outgoing webhooks are enabled in the config file and that we have all required settings @@ -901,16 +913,16 @@ export async function callQlikSenseServerLicenseWebhook(serverLicenseInfo) { await sendOutgoingWebhookQlikSenseServerLicense(webhookConfig, serverLicenseInfoCopy); } catch (err) { - globals.logger.error(`WEBHOOK OUT QLIK SENSE SERVER LICENSE MONITOR: ${err}`); + globals.logger.error(`[QSEOW] WEBHOOKOUT QLIK SENSE SERVER LICENSE MONITOR: ${err}`); } return 0; }) .catch((rateLimiterRes) => { globals.logger.verbose( - `WEBHOOK OUT QLIK SENSE SERVER LICENSE MONITOR: Rate limiting failed. Not sending Qlik Sense server license monitor notification via outgoing webhook`, + `[QSEOW] WEBHOOKOUT QLIK SENSE SERVER LICENSE MONITOR: Rate limiting failed. Not sending Qlik Sense server license monitor notification via outgoing webhook`, ); globals.logger.verbose( - `WEBHOOK OUT QLIK SENSE SERVER LICENSE MONITOR: Rate limiting details "${JSON.stringify(rateLimiterRes, null, 2)}"`, + `[QSEOW] WEBHOOKOUT QLIK SENSE SERVER LICENSE MONITOR: Rate limiting details "${JSON.stringify(rateLimiterRes, null, 2)}"`, ); }); } else if ( @@ -923,10 +935,10 @@ export async function callQlikSenseServerLicenseWebhook(serverLicenseInfo) { .then(async (rateLimiterRes) => { try { globals.logger.info( - `WEBHOOK OUT QLIK SENSE SERVER LICENSE EXPIRY ALERT: Rate limiting check passed for Qlik Sense server license expiry alert`, + `[QSEOW] WEBHOOKOUT QLIK SENSE SERVER LICENSE EXPIRY ALERT: Rate limiting check passed for Qlik Sense server license expiry alert`, ); globals.logger.verbose( - `WEBHOOK OUT QLIK SENSE SERVER LICENSE EXPIRY ALERT: Rate limiting details "${JSON.stringify(rateLimiterRes, null, 2)}"`, + `[QSEOW] WEBHOOKOUT QLIK SENSE SERVER LICENSE EXPIRY ALERT: Rate limiting details "${JSON.stringify(rateLimiterRes, null, 2)}"`, ); // Make sure outgoing webhooks are enabled in the config file and that we have all required settings @@ -937,16 +949,16 @@ export async function callQlikSenseServerLicenseWebhook(serverLicenseInfo) { await sendOutgoingWebhookQlikSenseServerLicense(webhookConfig, serverLicenseInfoCopy); } catch (err) { - globals.logger.error(`WEBHOOK OUT QLIK SENSE SERVER LICENSE EXPIRY ALERT: ${err}`); + globals.logger.error(`[QSEOW] WEBHOOKOUT QLIK SENSE SERVER LICENSE EXPIRY ALERT: ${err}`); } return 0; }) .catch((rateLimiterRes) => { globals.logger.verbose( - `WEBHOOK OUT QLIK SENSE SERVER LICENSE EXPIRY ALERT: Rate limiting failed. Not sending Qlik Sense server license expiry alert via outgoing webhook`, + `[QSEOW] WEBHOOKOUT QLIK SENSE SERVER LICENSE EXPIRY ALERT: Rate limiting failed. Not sending Qlik Sense server license expiry alert via outgoing webhook`, ); globals.logger.verbose( - `WEBHOOK OUT QLIK SENSE SERVER LICENSE EXPIRY ALERT: Rate limiting details "${JSON.stringify(rateLimiterRes, null, 2)}"`, + `[QSEOW] WEBHOOKOUT QLIK SENSE SERVER LICENSE EXPIRY ALERT: Rate limiting details "${JSON.stringify(rateLimiterRes, null, 2)}"`, ); }); } diff --git a/src/lib/qseow/winsvc.js b/src/lib/qseow/winsvc.js index 8b095bae..7e18f681 100644 --- a/src/lib/qseow/winsvc.js +++ b/src/lib/qseow/winsvc.js @@ -14,22 +14,22 @@ export function all(logger, host = null) { if (host === null) { // Run command for get states of all services on local machine - logger.verbose('WINSVC ALL: Getting all services on local machine'); + logger.verbose('[QSEOW] WINSVC ALL: Getting all services on local machine'); command = 'sc.exe query state= all'; } else { // A host other that local machine is specfied - logger.verbose(`WINSVC ALL: Getting all services on host ${host}`); + logger.verbose(`[QSEOW] WINSVC ALL: Getting all services on host ${host}`); command = `sc.exe \\\\${host} query state= all`; } - logger.debug(`WINSVC ALL: Running command ${command}`); + logger.debug(`[QSEOW] WINSVC ALL: Running command ${command}`); exec(command, (err, stdout) => { // On error, reject and exit if (err) { - logger.error(`WINSVC ALL: Error while getting all services on host ${host}`); + logger.error(`[QSEOW] WINSVC ALL: Error while getting all services on host ${host}`); if (err.code) { - logger.error(`WINSVC ALL: Error code: ${err.code}`); + logger.error(`[QSEOW] WINSVC ALL: Error code: ${err.code}`); } if (stdout) { @@ -48,7 +48,7 @@ export function all(logger, host = null) { .filter((line) => line.indexOf('SERVICE_NAME') !== -1) .map((line) => line.replace('SERVICE_NAME: ', '')); - logger.verbose(`WINSVC ALL: Got all ${lines.length} services on host ${host}`); + logger.verbose(`[QSEOW] WINSVC ALL: Got all ${lines.length} services on host ${host}`); logger.debug(lines); // Resolve with array of service names @@ -70,7 +70,7 @@ export function exists(logger, serviceName, host = null) { return new Promise((resolveExists, rejectExists) => { // With invalid service name, reject if (!serviceName) { - logger.error('WINSVC EXISTS: Service name is invalid'); + logger.error('[QSEOW] WINSVC EXISTS: Service name is invalid'); rejectExists(new Error('Service name is invalid')); return; @@ -79,18 +79,18 @@ export function exists(logger, serviceName, host = null) { // Is host reachable? // Get all services - logger.verbose(`WINSVC EXISTS: Getting all services on host ${host}`); + logger.verbose(`[QSEOW] WINSVC EXISTS: Getting all services on host ${host}`); all(logger, host).then( // On success, check (allServices) => { - logger.verbose(`WINSVC EXISTS: Checking if service ${serviceName} exists on host ${host}`); + logger.verbose(`[QSEOW] WINSVC EXISTS: Checking if service ${serviceName} exists on host ${host}`); // Find provided name for (let i = 0; i < allServices.length; ) { - logger.silly(`WINSVC EXISTS: Checking if service "${serviceName}" equals "${allServices[i]}"...`); + logger.silly(`[QSEOW] WINSVC EXISTS: Checking if service "${serviceName}" equals "${allServices[i]}"...`); if (allServices[i] === serviceName) { // Found, resolve true - logger.verbose(`WINSVC EXISTS: Found! Service ${serviceName} exists on host ${host}`); + logger.verbose(`[QSEOW] WINSVC EXISTS: Found! Service ${serviceName} exists on host ${host}`); resolveExists(true); return; @@ -100,15 +100,15 @@ export function exists(logger, serviceName, host = null) { } // Not found, resolve false - logger.verbose(`WINSVC EXISTS: Not found! Service ${serviceName} does not exists on host ${host}`); + logger.verbose(`[QSEOW] WINSVC EXISTS: Not found! Service ${serviceName} does not exists on host ${host}`); resolveExists(false); }, // Reject on error (err) => { - logger.error(`WINSVC EXISTS: Error while getting all services on host ${host}`); + logger.error(`[QSEOW] WINSVC EXISTS: Error while getting all services on host ${host}`); if (err.code) { - logger.error(`WINSVC EXISTS: Error code: ${err.code}`); + logger.error(`[QSEOW] WINSVC EXISTS: Error code: ${err.code}`); } rejectExists(err); @@ -130,22 +130,22 @@ export function statusAll(logger, host = null) { if (host === null) { // Run command for get states of all services on local machine - logger.verbose('WINSVC STATUSALL: Getting status of all services on local machine'); + logger.verbose('[QSEOW] WINSVC STATUSALL: Getting status of all services on local machine'); command = 'sc.exe query state= all'; } else { // A host other that local machine is specfied - logger.verbose(`WINSVC STATUSALL: Getting status of all services on host ${host}`); + logger.verbose(`[QSEOW] WINSVC STATUSALL: Getting status of all services on host ${host}`); command = `sc.exe \\\\${host} query state= all`; } // Run command for create service with provided data - logger.debug(`WINSVC STATUSALL: Running command ${command}`); + logger.debug(`[QSEOW] WINSVC STATUSALL: Running command ${command}`); exec(command, (err, stdout) => { // On error, reject and exit if (err) { - logger.error(`WINSVC STATUSALL: Error while getting status of all services on host ${host}`); + logger.error(`[QSEOW] WINSVC STATUSALL: Error while getting status of all services on host ${host}`); if (err.code) { - logger.error(`WINSVC STATUSALL: Error code: ${err.code}`); + logger.error(`[QSEOW] WINSVC STATUSALL: Error code: ${err.code}`); } reject(err); @@ -193,7 +193,7 @@ export function statusAll(logger, host = null) { return service; }); - logger.verbose(`WINSVC STATUSALL: Got status of all services on host ${host}`); + logger.verbose(`[QSEOW] WINSVC STATUSALL: Got status of all services on host ${host}`); logger.debug(serviceStatusAll); // Resolve with array of service objects @@ -215,7 +215,7 @@ export function status(logger, serviceName, host = null) { return new Promise((resolve, reject) => { // With invalid service name, reject if (!serviceName) { - logger.error('WINSVC STATUS: Service name is invalid'); + logger.error('[QSEOW] WINSVC STATUS: Service name is invalid'); reject(new Error('Service name is invalid')); return; @@ -225,11 +225,11 @@ export function status(logger, serviceName, host = null) { // exists(logger, serviceName, host).then( // (alreadyExists) => { // // serviceName exists on host - // logger.verbose(`WINSVC STATUS: Service ${serviceName} exists on host ${host}`); + // logger.verbose(`[QSEOW] WINSVC STATUS: Service ${serviceName} exists on host ${host}`); // // If exists, reject // if (!alreadyExists) { - // logger.verbose(`WINSVC STATUS: Service ${serviceName} does not exists on host ${host}`); + // logger.verbose(`[QSEOW] WINSVC STATUS: Service ${serviceName} does not exists on host ${host}`); // reject(new Error(`Service with name '${serviceName}' does not exists`)); // return; @@ -238,22 +238,22 @@ export function status(logger, serviceName, host = null) { let command = ''; if (host === null) { // Run command for get states of all services on local machine - logger.debug(`WINSVC STATUS: Getting status of service ${serviceName} on local machine`); + logger.debug(`[QSEOW] WINSVC STATUS: Getting status of service ${serviceName} on local machine`); command = `sc.exe query "${serviceName}"`; } else { // A host other that local machine is specfied - logger.debug(`WINSVC STATUS: Getting status of service ${serviceName} on host ${host}`); + logger.debug(`[QSEOW] WINSVC STATUS: Getting status of service ${serviceName} on host ${host}`); command = `sc.exe \\\\${host} query "${serviceName}"`; } // Run command for create service with provided data - logger.debug(`WINSVC STATUS: Running command ${command}`); + logger.debug(`[QSEOW] WINSVC STATUS: Running command ${command}`); exec(command, (err, stdout) => { // On error, reject and exit if (err) { - logger.error(`WINSVC STATUS: Error while getting status of service ${serviceName} on host ${host}`); + logger.error(`[QSEOW] WINSVC STATUS: Error while getting status of service ${serviceName} on host ${host}`); if (err.code) { - logger.error(`WINSVC STATUS: Error code: ${err.code}`); + logger.error(`[QSEOW] WINSVC STATUS: Error code: ${err.code}`); } reject(err); @@ -271,16 +271,16 @@ export function status(logger, serviceName, host = null) { const stateName = lines[0].indexOf('STOPPED') !== -1 ? 'STOPPED' : 'RUNNING'; // Return state name - logger.verbose(`WINSVC STATUS: Service ${serviceName} is ${stateName} on host ${host}`); + logger.verbose(`[QSEOW] WINSVC STATUS: Service ${serviceName} is ${stateName} on host ${host}`); resolve(stateName); }); // }, // // Reject on error // (err) => { - // logger.error(`WINSVC STATUS: Error while getting status of service ${serviceName} on host ${host}`); + // logger.error(`[QSEOW] WINSVC STATUS: Error while getting status of service ${serviceName} on host ${host}`); // if (err.code) { - // logger.error(`WINSVC STATUS: Error code: ${err.code}`); + // logger.error(`[QSEOW] WINSVC STATUS: Error code: ${err.code}`); // } // reject(err); @@ -302,23 +302,23 @@ export function details(logger, serviceName, host = null) { return new Promise((resolve, reject) => { // With invalid service name, reject if (!serviceName) { - logger.error('WINSVC DETAILS: Service name is invalid'); + logger.error('[QSEOW] WINSVC DETAILS: Service name is invalid'); reject(new Error('Service name is invalid')); return; } // Run check for service existance - // logger.verbose(`WINSVC DETAILS: Checking if service ${serviceName} exists on host ${host}`); + // logger.verbose(`[QSEOW] WINSVC DETAILS: Checking if service ${serviceName} exists on host ${host}`); // exists(logger, serviceName, host).then( // // Existance check completed // (alreadyExists) => { // // Service exists - // logger.verbose(`WINSVC DETAILS: Found! Service ${serviceName} exists on host ${host}`); + // logger.verbose(`[QSEOW] WINSVC DETAILS: Found! Service ${serviceName} exists on host ${host}`); // // If exists, reject // if (!alreadyExists) { - // logger.verbose(`WINSVC DETAILS: Not found! Service ${serviceName} does not exists on host ${host}`); + // logger.verbose(`[QSEOW] WINSVC DETAILS: Not found! Service ${serviceName} does not exists on host ${host}`); // reject(new Error(`Service with name '${serviceName}' does not exists`)); // return; @@ -327,18 +327,18 @@ export function details(logger, serviceName, host = null) { let command = ''; if (host === null) { // Run command for get states of all services on local machine - logger.debug(`WINSVC DETAILS: Getting details of service ${serviceName} on local machine`); + logger.debug(`[QSEOW] WINSVC DETAILS: Getting details of service ${serviceName} on local machine`); command = `sc.exe qc "${serviceName}"`; } else { // A host other that local machine is specfied - logger.debug(`WINSVC DETAILS: Getting details of service ${serviceName} on host ${host}`); + logger.debug(`[QSEOW] WINSVC DETAILS: Getting details of service ${serviceName} on host ${host}`); command = `sc.exe \\\\${host} qc "${serviceName}"`; } // Run command to get service details with provided data - logger.debug(`WINSVC DETAILS: Running command ${command}`); + logger.debug(`[QSEOW] WINSVC DETAILS: Running command ${command}`); exec(command, (err, stdout) => { let i = 0; const startTypeRegex = /\d/; @@ -356,9 +356,9 @@ export function details(logger, serviceName, host = null) { // On error, reject and exit if (err) { - logger.error(`WINSVC DETAILS: Error while getting details of service ${serviceName} on host ${host}`); + logger.error(`[QSEOW] WINSVC DETAILS: Error while getting details of service ${serviceName} on host ${host}`); if (err.code) { - logger.error(`WINSVC DETAILS 1: Error code: ${err.code}`); + logger.error(`[QSEOW] WINSVC DETAILS 1: Error code: ${err.code}`); } reject(err); @@ -367,7 +367,7 @@ export function details(logger, serviceName, host = null) { const lines = stdout.toString().split('\r\n'); // Debug log lines - logger.debug(`WINSVC DETAILS: Lines: ${lines}`); + logger.debug(`[QSEOW] WINSVC DETAILS: Lines: ${lines}`); let startTypeName = ''; @@ -386,20 +386,20 @@ export function details(logger, serviceName, host = null) { } // Show all details that will be returned - logger.verbose(`WINSVC DETAILS: Service ${serviceName} is ${startTypeName} on host ${host}`); - logger.verbose(`WINSVC DETAILS: Service ${serviceName} has dependencies ${deps}`); + logger.verbose(`[QSEOW] WINSVC DETAILS: Service ${serviceName} is ${startTypeName} on host ${host}`); + logger.verbose(`[QSEOW] WINSVC DETAILS: Service ${serviceName} has dependencies ${deps}`); logger.verbose( - `WINSVC DETAILS: Service ${serviceName} has exe path ${lines + `[QSEOW] WINSVC DETAILS: Service ${serviceName} has exe path ${lines .find((line) => line.indexOf('BINARY_PATH_NAME') !== -1) .replace(/\s*BINARY_PATH_NAME\s*: /, '')}`, ); logger.verbose( - `WINSVC DETAILS: Service ${serviceName} has display name ${lines + `[QSEOW] WINSVC DETAILS: Service ${serviceName} has display name ${lines .find((line) => line.indexOf('DISPLAY_NAME') !== -1) .replace(/\s*DISPLAY_NAME\s*: /, '')}`, ); logger.verbose( - `WINSVC DETAILS: Service ${serviceName} has name ${lines + `[QSEOW] WINSVC DETAILS: Service ${serviceName} has name ${lines .find((line) => line.indexOf('SERVICE_NAME: ') !== -1) .replace('SERVICE_NAME: ', '')}`, ); @@ -416,9 +416,9 @@ export function details(logger, serviceName, host = null) { // // Reject on error // (err) => { - // logger.error(`WINSVC DETAILS: Error while getting details of service ${serviceName} on host ${host}`); + // logger.error(`[QSEOW] WINSVC DETAILS: Error while getting details of service ${serviceName} on host ${host}`); // if (err.code) { - // logger.error(`WINSVC DETAILS 2: Error code: ${err.code}`); + // logger.error(`[QSEOW] WINSVC DETAILS 2: Error code: ${err.code}`); // } // reject(err); diff --git a/src/qrs_util/app_metadata.js b/src/qrs_util/app_metadata.js index 82cda792..a187d2e3 100644 --- a/src/qrs_util/app_metadata.js +++ b/src/qrs_util/app_metadata.js @@ -8,7 +8,7 @@ import globals from '../globals.js'; * @returns */ async function getAppMetadata(appId) { - globals.logger.debug(`GET APP METADATA: Retrieving metadata for app ${appId}`); + globals.logger.debug(`[QSEOW] GET APP METADATA: Retrieving metadata for app ${appId}`); try { // Get http headers from Butler config file @@ -26,10 +26,10 @@ async function getAppMetadata(appId) { // Get app metadata try { - globals.logger.debug(`GET APP METADATA: app/full?filter=id eq ${appId}`); + globals.logger.debug(`[QSEOW] GET APP METADATA: app/full?filter=id eq ${appId}`); const result = await qrsInstance.Get(`app/full?filter=id eq ${appId}`); - globals.logger.debug(`GET APP METADATA: Got response: ${result.statusCode}`); + globals.logger.debug(`[QSEOW] GET APP METADATA: Got response: ${result.statusCode}`); if (result.body.length === 1) { // Yes, the app exists. Return metadata for this app @@ -39,11 +39,11 @@ async function getAppMetadata(appId) { // The task does not exist return {}; } catch (err) { - globals.logger.error(`GET APP METADATA: Error while getting app metadata: ${err.message}`); - return []; + globals.logger.error(`[QSEOW] GET APP METADATA: Error while getting app metadata: ${err.message}`); + return false; } } catch (err) { - globals.logger.error(`GET APP METADATA: Error while getting app metadata: ${err}`); + globals.logger.error(`[QSEOW] GET APP METADATA: Error while getting app metadata: ${err}`); return false; } } diff --git a/src/udp/udp_handlers.js b/src/udp/udp_handlers.js index 18416ce0..c9307cb5 100644 --- a/src/udp/udp_handlers.js +++ b/src/udp/udp_handlers.js @@ -6,7 +6,7 @@ import { sendReloadTaskSuccessNotificationEmail, } from '../lib/qseow/smtp.js'; import { sendReloadTaskFailureNotificationSlack, sendReloadTaskAbortedNotificationSlack } from '../lib/qseow/slack_notification.js'; -import { sendReloadTaskAbortedNotificationWebhook, sendReloadTaskFailureNotificationWebhook } from '../lib/webhook_notification.js'; +import { sendReloadTaskAbortedNotificationWebhook, sendReloadTaskFailureNotificationWebhook } from '../lib/qseow/webhook_notification.js'; import { sendReloadTaskFailureNotificationTeams, sendReloadTaskAbortedNotificationTeams } from '../lib/qseow/msteams_notification.js'; import { sendReloadTaskFailureNotification, sendReloadTaskAbortedNotification } from '../lib/incident_mgmt/signl4.js'; import { @@ -28,7 +28,7 @@ import getTaskMetadata from '../qrs_util/task_metadata.js'; // Handler for failed scheduler initiated reloads const schedulerAborted = async (msg) => { globals.logger.verbose( - `TASKABORTED: Received reload aborted UDP message from scheduler: UDP msg=${msg[0]}, Host=${msg[1]}, App name=${msg[3]}, Task name=${msg[2]}, Log level=${msg[8]}, Log msg=${msg[10]}`, + `[QSEOW] TASKABORTED: Received reload aborted UDP message from scheduler: UDP msg=${msg[0]}, Host=${msg[1]}, App name=${msg[3]}, Task name=${msg[2]}, Log level=${msg[8]}, Log msg=${msg[10]}`, ); // Get script log for failed reloads. @@ -42,13 +42,20 @@ const schedulerAborted = async (msg) => { ) { scriptLog = await getScriptLog(msg[5], 1, 1); - globals.logger.verbose(`Script log for aborted reload retrieved`); + globals.logger.verbose(`[QSEOW] Script log for aborted reload retrieved`); } // TOOD: Add check if task exists in QRS // Get app metadata from QRS + // Returns false if app metadata retrieval fails, JSON object if successful const appMetadata = await getAppMetadata(msg[6]); + // If we could not get app metadata from QRS, that is a problem. Log it and return + if (appMetadata === false) { + globals.logger.error(`[QSEOW] TASKABORTED: Could not get app metadata for app ${msg[6]}. Aborting further processing`); + return; + } + // Get tags for the app that failed reloading // Tags are found in appMetadata.tags, which is an array of objects with the following properties: // - id @@ -56,7 +63,7 @@ const schedulerAborted = async (msg) => { // // Create an array of tag names only const appTags = appMetadata.tags.map((tag) => tag.name); - globals.logger.verbose(`Tags for app ${msg[6]}: ${JSON.stringify(appTags, null, 2)}`); + globals.logger.verbose(`[QSEOW] Tags for app ${msg[6]}: ${JSON.stringify(appTags, null, 2)}`); // Get app custom properties // They are found in appMetadata.customProperties, which is an array of objects with the following properties: @@ -76,7 +83,7 @@ const schedulerAborted = async (msg) => { // Get tags for the task that failed reloading const taskTags = taskMetadata.tags.map((tag) => tag.name); - globals.logger.verbose(`Tags for task ${msg[5]}: ${JSON.stringify(taskTags, null, 2)}`); + globals.logger.verbose(`[QSEOW] Tags for task ${msg[5]}: ${JSON.stringify(taskTags, null, 2)}`); // Get reload task custom properties const taskCustomProperties = taskMetadata.customProperties.map((cp) => ({ @@ -268,7 +275,7 @@ const schedulerAborted = async (msg) => { globals.mqttClient.publish(globals.config.get('Butler.mqttConfig.taskAbortedTopic'), msg[2]); } else { globals.logger.warn( - `MQTT: MQTT client not connected. Unable to publish message to topic ${globals.config.get( + `[QSEOW] MQTT: MQTT client not connected. Unable to publish message to topic ${globals.config.get( 'Butler.mqttConfig.taskAbortedTopic', )}`, ); @@ -314,11 +321,11 @@ const schedulerFailed = async (msg) => { globals.config.get('Butler.emailNotification.enable') === true ) { scriptLog = await getScriptLog(msg[5], 0, 0); - globals.logger.verbose(`Script log for failed reload retrieved`); + globals.logger.verbose(`[QSEOW] Script log for failed reload retrieved`); } globals.logger.verbose( - `TASKFAILURE: Received reload failed UDP message from scheduler: UDP msg=${msg[0]}, Host=${msg[1]}, App name=${msg[3]}, Task name=${msg[2]}, Log level=${msg[8]}, Log msg=${msg[10]}`, + `[QSEOW] TASKFAILURE: Received reload failed UDP message from scheduler: UDP msg=${msg[0]}, Host=${msg[1]}, App name=${msg[3]}, Task name=${msg[2]}, Log level=${msg[8]}, Log msg=${msg[10]}`, ); // First field in message (msg[0]) is message category (this is the modern/recent message format) @@ -326,6 +333,12 @@ const schedulerFailed = async (msg) => { // Get app metadata from QRS const appMetadata = await getAppMetadata(msg[6]); + // If we could not get app metadata from QRS, that is a problem. Log it and return + if (appMetadata === false) { + globals.logger.error(`[QSEOW] TASKFAILURE: Could not get app metadata for app ${msg[6]}. Aborting further processing`); + return; + } + // Get tags for the app that failed reloading // Tags are found in appMetadata.tags, which is an array of objects with the following properties: // - id @@ -333,7 +346,7 @@ const schedulerFailed = async (msg) => { // // Create an array of tag names only const appTags = appMetadata.tags.map((tag) => tag.name); - globals.logger.verbose(`Tags for app ${msg[6]}: ${JSON.stringify(appTags, null, 2)}`); + globals.logger.verbose(`[QSEOW] Tags for app ${msg[6]}: ${JSON.stringify(appTags, null, 2)}`); // Get app custom properties // They are found in appMetadata.customProperties, which is an array of objects with the following properties: @@ -353,7 +366,7 @@ const schedulerFailed = async (msg) => { // Get tags for the task that failed reloading const taskTags = taskMetadata.tags.map((tag) => tag.name); - globals.logger.verbose(`Tags for task ${msg[5]}: ${JSON.stringify(taskTags, null, 2)}`); + globals.logger.verbose(`[QSEOW] Tags for task ${msg[5]}: ${JSON.stringify(taskTags, null, 2)}`); // Get reload task custom properties const taskCustomProperties = taskMetadata.customProperties.map((cp) => ({ @@ -591,7 +604,7 @@ const schedulerFailed = async (msg) => { globals.mqttClient.publish(globals.config.get('Butler.mqttConfig.taskFailureTopic'), msg[2]); } else { globals.logger.warn( - `MQTT: MQTT client not connected. Unable to publish message to topic ${globals.config.get( + `[QSEOW] MQTT: MQTT client not connected. Unable to publish message to topic ${globals.config.get( 'Butler.mqttConfig.taskFailureTopic', )}`, ); @@ -628,7 +641,7 @@ const schedulerFailed = async (msg) => { // -------------------------------------------------------- const schedulerReloadTaskSuccess = async (msg) => { globals.logger.verbose( - `RELOAD TASK SUCCESS: Received reload task success UDP message from scheduler: UDP msg=${msg[0]}, Host=${msg[1]}, App name=${msg[3]}, Task name=${msg[2]}, Log level=${msg[8]}, Log msg=${msg[10]}`, + `[QSEOW] RELOAD TASK SUCCESS: Received reload task success UDP message from scheduler: UDP msg=${msg[0]}, Host=${msg[1]}, App name=${msg[3]}, Task name=${msg[2]}, Log level=${msg[8]}, Log msg=${msg[10]}`, ); const reloadTaskId = msg[5]; @@ -636,7 +649,7 @@ const schedulerReloadTaskSuccess = async (msg) => { // Does task ID exist in Sense? const taskExists = await doesTaskExist(reloadTaskId); if (taskExists.exists !== true) { - globals.logger.warn(`RELOAD TASK SUCCESS: Task ID ${reloadTaskId} does not exist in Sense`); + globals.logger.warn(`[QSEOW] RELOAD TASK SUCCESS: Task ID ${reloadTaskId} does not exist in Sense`); return false; } @@ -682,12 +695,18 @@ const schedulerReloadTaskSuccess = async (msg) => { globals.config.get('Butler.emailNotification.reloadTaskSuccess.enable') === true) ) { scriptLog = await getScriptLog(reloadTaskId, 0, 0); - globals.logger.verbose(`Script log for successful reload retrieved`); + globals.logger.verbose(`[QSEOW] Script log for successful reload retrieved`); } // Get app metadata from QRS const appMetadata = await getAppMetadata(msg[6]); + // If we could not get app metadata from QRS, that is a problem. Log it and return + if (appMetadata === false) { + globals.logger.error(`[QSEOW] RELOAD TASK SUCCESS: Could not get app metadata for app ${msg[6]}. Aborting further processing`); + return; + } + // Get tags for the app that failed reloading // Tags are found in appMetadata.tags, which is an array of objects with the following properties: // - id @@ -695,7 +714,7 @@ const schedulerReloadTaskSuccess = async (msg) => { // // Create an array of tag names only const appTags = appMetadata.tags.map((tag) => tag.name); - globals.logger.verbose(`Tags for app ${msg[6]}: ${JSON.stringify(appTags, null, 2)}`); + globals.logger.verbose(`[QSEOW] Tags for app ${msg[6]}: ${JSON.stringify(appTags, null, 2)}`); // Get app custom properties // They are found in appMetadata.customProperties, which is an array of objects with the following properties: @@ -715,7 +734,7 @@ const schedulerReloadTaskSuccess = async (msg) => { // Get tags for the task that failed reloading const taskTags = taskMetadata.tags.map((tag) => tag.name); - globals.logger.verbose(`Tags for task ${msg[5]}: ${JSON.stringify(taskTags, null, 2)}`); + globals.logger.verbose(`[QSEOW] Tags for task ${msg[5]}: ${JSON.stringify(taskTags, null, 2)}`); // Get reload task custom properties const taskCustomProperties = taskMetadata.customProperties.map((cp) => ({ @@ -750,12 +769,12 @@ const schedulerReloadTaskSuccess = async (msg) => { taskInfo.executionDuration.seconds === 0 ) { globals.logger.warn( - `RELOAD TASK SUCCESS: Task info for reload task ${reloadTaskId} retrieved successfully after ${retryCount} attempts, but duration is 0 seconds. This is likely caused by the QRS not having updated the execution details yet.`, + `[QSEOW] RELOAD TASK SUCCESS: Task info for reload task ${reloadTaskId} retrieved successfully after ${retryCount} attempts, but duration is 0 seconds. This is likely caused by the QRS not having updated the execution details yet.`, ); } globals.logger.debug( - `RELOAD TASK SUCCESS: Task info for reload task ${reloadTaskId} retrieved successfully after ${retryCount} attempts`, + `[QSEOW] RELOAD TASK SUCCESS: Task info for reload task ${reloadTaskId} retrieved successfully after ${retryCount} attempts`, ); break; } @@ -763,7 +782,7 @@ const schedulerReloadTaskSuccess = async (msg) => { retryCount += 1; globals.logger.verbose( - `RELOAD TASK SUCCESS: Unable to get task info for reload task ${reloadTaskId}. Attempt ${retryCount} of 5. Waiting 1 second before trying again`, + `[QSEOW] RELOAD TASK SUCCESS: Unable to get task info for reload task ${reloadTaskId}. Attempt ${retryCount} of 5. Waiting 1 second before trying again`, ); // eslint-disable-next-line no-await-in-loop @@ -772,11 +791,13 @@ const schedulerReloadTaskSuccess = async (msg) => { if (!taskInfo) { globals.logger.warn( - `RELOAD TASK SUCCESS: Unable to get task info for reload task ${reloadTaskId}. Not storing task info in InfluxDB`, + `[QSEOW] RELOAD TASK SUCCESS: Unable to get task info for reload task ${reloadTaskId}. Not storing task info in InfluxDB`, ); return false; } - globals.logger.verbose(`RELOAD TASK SUCCESS: Task info for reload task ${reloadTaskId}: ${JSON.stringify(taskInfo, null, 2)}`); + globals.logger.verbose( + `[QSEOW] RELOAD TASK SUCCESS: Task info for reload task ${reloadTaskId}: ${JSON.stringify(taskInfo, null, 2)}`, + ); // Get app/task tags so they can be included in data sent to alert destinations let appTags = []; @@ -784,11 +805,11 @@ const schedulerReloadTaskSuccess = async (msg) => { // Get tags for the app that was reloaded appTags = await getAppTags(msg[6]); - globals.logger.verbose(`Tags for app ${msg[6]}: ${JSON.stringify(appTags, null, 2)}`); + globals.logger.verbose(`[QSEOW] Tags for app ${msg[6]}: ${JSON.stringify(appTags, null, 2)}`); // Get tags for the task that finished reloading successfully taskTags = await getTaskTags(msg[5]); - globals.logger.verbose(`Tags for task ${msg[5]}: ${JSON.stringify(taskTags, null, 2)}`); + globals.logger.verbose(`[QSEOW] Tags for task ${msg[5]}: ${JSON.stringify(taskTags, null, 2)}`); // Post to InfluxDB when a reload task has finished successfully if ( @@ -817,10 +838,10 @@ const schedulerReloadTaskSuccess = async (msg) => { qs_taskMetadata: taskMetadata, }); - globals.logger.info(`RELOAD TASK SUCCESS: Reload info for reload task ${reloadTaskId}, "${msg[2]}" stored in InfluxDB`); + globals.logger.info(`[QSEOW] RELOAD TASK SUCCESS: Reload info for reload task ${reloadTaskId}, "${msg[2]}" stored in InfluxDB`); } } else { - globals.logger.verbose(`RELOAD TASK SUCCESS: Not storing task info in InfluxDB`); + globals.logger.verbose(`[QSEOW] RELOAD TASK SUCCESS: Not storing task info in InfluxDB`); } // Should we send email notification? @@ -861,7 +882,7 @@ const udpInitTaskErrorServer = () => { globals.udpServerReloadTaskSocket.on('listening', (message, remote) => { const address = globals.udpServerReloadTaskSocket.address(); - globals.logger.info(`TASKFAILURE: UDP server listening on ${address.address}:${address.port}`); + globals.logger.info(`[QSEOW] TASKFAILURE: UDP server listening on ${address.address}:${address.port}`); // Publish MQTT message that UDP server has started if (globals.config.has('Butler.mqttConfig.enable') && globals.config.get('Butler.mqttConfig.enable') === true) { @@ -869,7 +890,7 @@ const udpInitTaskErrorServer = () => { globals.mqttClient.publish(globals.config.get('Butler.mqttConfig.taskFailureServerStatusTopic'), 'start'); } else { globals.logger.warn( - `UDP SERVER INIT: MQTT client not connected. Unable to publish message to topic ${globals.config.get( + `[QSEOW] UDP SERVER INIT: MQTT client not connected. Unable to publish message to topic ${globals.config.get( 'Butler.mqttConfig.taskFailureServerStatusTopic', )}`, ); @@ -882,7 +903,7 @@ const udpInitTaskErrorServer = () => { globals.udpServerReloadTaskSocket.on('error', (message, remote) => { try { const address = globals.udpServerReloadTaskSocket.address(); - globals.logger.error(`TASKFAILURE: UDP server error on ${address.address}:${address.port}`); + globals.logger.error(`[QSEOW] TASKFAILURE: UDP server error on ${address.address}:${address.port}`); // Publish MQTT message that UDP server has reported an error if (globals.config.has('Butler.mqttConfig.enable') && globals.config.get('Butler.mqttConfig.enable') === true) { @@ -890,14 +911,14 @@ const udpInitTaskErrorServer = () => { globals.mqttClient.publish(globals.config.get('Butler.mqttConfig.taskFailureServerStatusTopic'), 'error'); } else { globals.logger.warn( - `UDP SERVER ERROR: MQTT client not connected. Unable to publish message to topic ${globals.config.get( + `[QSEOW] UDP SERVER ERROR: MQTT client not connected. Unable to publish message to topic ${globals.config.get( 'Butler.mqttConfig.taskFailureServerStatusTopic', )}`, ); } } } catch (err) { - globals.logger.error(`TASKFAILURE: Error in UDP error handler: ${err}`); + globals.logger.error(`[QSEOW] TASKFAILURE: Error in UDP error handler: ${err}`); } }); @@ -971,7 +992,7 @@ const udpInitTaskErrorServer = () => { // mag[8] : Message try { - globals.logger.debug(`UDP HANDLER: UDP message received: ${message.toString()}`); + globals.logger.debug(`[QSEOW] UDP HANDLER: UDP message received: ${message.toString()}`); const msg = message.toString().split(';'); @@ -982,15 +1003,15 @@ const udpInitTaskErrorServer = () => { // There should be exactly 11 fields in the message if (msg.length !== 9) { globals.logger.warn( - `UDP HANDLER ENGINE RELOAD FAILED: Invalid number of fields in UDP message. Expected 9, got ${msg.length}.`, + `[QSEOW] UDP HANDLER ENGINE RELOAD FAILED: Invalid number of fields in UDP message. Expected 9, got ${msg.length}.`, ); - globals.logger.warn(`UDP HANDLER ENGINE RELOAD FAILED: Incoming log message was:\n${message.toString()}`); - globals.logger.warn(`UDP HANDLER ENGINE RELOAD FAILED: Aborting processing of this message.`); + globals.logger.warn(`[QSEOW] UDP HANDLER ENGINE RELOAD FAILED: Incoming log message was:\n${message.toString()}`); + globals.logger.warn(`[QSEOW] UDP HANDLER ENGINE RELOAD FAILED: Aborting processing of this message.`); return; } globals.logger.verbose( - `UDP HANDLER ENGINE RELOAD FAILED: Received reload failed UDP message from engine: Host=${msg[1]}, AppID=${msg[2]}, User directory=${msg[4]}, User=${msg[5]}`, + `[QSEOW] UDP HANDLER ENGINE RELOAD FAILED: Received reload failed UDP message from engine: Host=${msg[1]}, AppID=${msg[2]}, User directory=${msg[4]}, User=${msg[5]}`, ); } else if (msg[0].toLowerCase() === '/scheduler-reload-failed/') { // Scheduler log appender detecting failed scheduler-started reload @@ -999,10 +1020,10 @@ const udpInitTaskErrorServer = () => { // There should be exactly 11 fields in the message if (msg.length !== 11) { globals.logger.warn( - `UDP HANDLER SCHEDULER RELOAD FAILED: Invalid number of fields in UDP message. Expected 11, got ${msg.length}.`, + `[QSEOW] UDP HANDLER SCHEDULER RELOAD FAILED: Invalid number of fields in UDP message. Expected 11, got ${msg.length}.`, ); - globals.logger.warn(`UDP HANDLER SCHEDULER RELOAD FAILED: Incoming log message was:\n${message.toString()}`); - globals.logger.warn(`UDP HANDLER SCHEDULER RELOAD FAILED: Aborting processing of this message.`); + globals.logger.warn(`[QSEOW] UDP HANDLER SCHEDULER RELOAD FAILED: Incoming log message was:\n${message.toString()}`); + globals.logger.warn(`[QSEOW] UDP HANDLER SCHEDULER RELOAD FAILED: Aborting processing of this message.`); return; } @@ -1014,10 +1035,10 @@ const udpInitTaskErrorServer = () => { // There should be exactly 11 fields in the message if (msg.length !== 11) { globals.logger.warn( - `UDP HANDLER SCHEDULER RELOAD ABORTED: Invalid number of fields in UDP message. Expected 11, got ${msg.length}.`, + `[QSEOW] UDP HANDLER SCHEDULER RELOAD ABORTED: Invalid number of fields in UDP message. Expected 11, got ${msg.length}.`, ); - globals.logger.warn(`UDP HANDLER SCHEDULER RELOAD ABORTED: Incoming log message was:\n${message.toString()}`); - globals.logger.warn(`UDP HANDLER SCHEDULER RELOAD ABORTED: Aborting processing of this message.`); + globals.logger.warn(`[QSEOW] UDP HANDLER SCHEDULER RELOAD ABORTED: Incoming log message was:\n${message.toString()}`); + globals.logger.warn(`[QSEOW] UDP HANDLER SCHEDULER RELOAD ABORTED: Aborting processing of this message.`); return; } @@ -1029,19 +1050,21 @@ const udpInitTaskErrorServer = () => { // There should be exactly 11 fields in the message if (msg.length !== 11) { globals.logger.warn( - `UDP HANDLER SCHEDULER RELOAD TASK SUCCESS: Invalid number of fields in UDP message. Expected 11, got ${msg.length}.`, + `[QSEOW] UDP HANDLER SCHEDULER RELOAD TASK SUCCESS: Invalid number of fields in UDP message. Expected 11, got ${msg.length}.`, + ); + globals.logger.warn( + `[QSEOW] UDP HANDLER SCHEDULER RELOAD TASK SUCCESS: Incoming log message was:\n${message.toString()}`, ); - globals.logger.warn(`UDP HANDLER SCHEDULER RELOAD TASK SUCCESS: Incoming log message was:\n${message.toString()}`); - globals.logger.warn(`UDP HANDLER SCHEDULER RELOAD TASK SUCCESS: Aborting processing of this message.`); + globals.logger.warn(`[QSEOW] UDP HANDLER SCHEDULER RELOAD TASK SUCCESS: Aborting processing of this message.`); return; } schedulerReloadTaskSuccess(msg); } else { - globals.logger.warn(`UDP HANDLER: Unknown UDP message format: "${msg[0]}"`); + globals.logger.warn(`[QSEOW] UDP HANDLER: Unknown UDP message format: "${msg[0]}"`); } } catch (err) { - globals.logger.error(`UDP HANDLER: Failed processing log event. No action will be taken for this event. Error: ${err}`); - globals.logger.error(`UDP HANDLER: Incoming log message was\n${message}`); + globals.logger.error(`[QSEOW] UDP HANDLER: Failed processing log event. No action will be taken for this event. Error: ${err}`); + globals.logger.error(`[QSEOW] UDP HANDLER: Incoming log message was\n${message}`); } }); };