diff --git a/package-lock.json b/package-lock.json index 82d34f95..ea80eff9 100644 --- a/package-lock.json +++ b/package-lock.json @@ -10,6 +10,9 @@ "license": "MIT", "dependencies": { "@breejs/later": "^4.2.0", + "@fastify/rate-limit": "^9.1.0", + "@fastify/sensible": "^5.6.0", + "@fastify/static": "^7.0.4", "@influxdata/influxdb-client": "^1.35.0", "@influxdata/influxdb-client-apis": "^1.35.0", "axios": "^1.7.4", @@ -19,6 +22,7 @@ "fastify-healthcheck": "^4.4.0", "fastify-metrics": "^11.0.0", "fs-extra": "^11.2.0", + "handlebars": "^4.7.7", "influx": "^5.9.3", "js-yaml": "^4.1.0", "lodash.clonedeep": "^4.5.0", @@ -600,6 +604,15 @@ "node": "^18.18.0 || ^20.9.0 || >=21.1.0" } }, + "node_modules/@fastify/accept-negotiator": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@fastify/accept-negotiator/-/accept-negotiator-1.1.0.tgz", + "integrity": "sha512-OIHZrb2ImZ7XG85HXOONLcJWGosv7sIvM2ifAPQVhg9Lv7qdmMBNVaai4QTdyuaqbKM5eO6sLSQOYI7wEQeCJQ==", + "license": "MIT", + "engines": { + "node": ">=14" + } + }, "node_modules/@fastify/ajv-compiler": { "version": "3.5.0", "resolved": "https://registry.npmjs.org/@fastify/ajv-compiler/-/ajv-compiler-3.5.0.tgz", @@ -648,6 +661,59 @@ "fast-json-stringify": "^5.7.0" } }, + "node_modules/@fastify/rate-limit": { + "version": "9.1.0", + "resolved": "https://registry.npmjs.org/@fastify/rate-limit/-/rate-limit-9.1.0.tgz", + "integrity": "sha512-h5dZWCkuZXN0PxwqaFQLxeln8/LNwQwH9popywmDCFdKfgpi4b/HoMH1lluy6P+30CG9yzzpSpwTCIPNB9T1JA==", + "license": "MIT", + "dependencies": { + "@lukeed/ms": "^2.0.1", + "fastify-plugin": "^4.0.0", + "toad-cache": "^3.3.1" + } + }, + "node_modules/@fastify/send": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/@fastify/send/-/send-2.1.0.tgz", + "integrity": "sha512-yNYiY6sDkexoJR0D8IDy3aRP3+L4wdqCpvx5WP+VtEU58sn7USmKynBzDQex5X42Zzvw2gNzzYgP90UfWShLFA==", + "license": "MIT", + "dependencies": { + "@lukeed/ms": "^2.0.1", + "escape-html": "~1.0.3", + "fast-decode-uri-component": "^1.0.1", + "http-errors": "2.0.0", + "mime": "^3.0.0" + } + }, + "node_modules/@fastify/sensible": { + "version": "5.6.0", + "resolved": "https://registry.npmjs.org/@fastify/sensible/-/sensible-5.6.0.tgz", + "integrity": "sha512-Vq6Z2ZQy10GDqON+hvLF52K99s9et5gVVxTul5n3SIAf0Kq5QjPRUKkAMT3zPAiiGvoHtS3APa/3uaxfDgCODQ==", + "license": "MIT", + "dependencies": { + "@lukeed/ms": "^2.0.1", + "fast-deep-equal": "^3.1.1", + "fastify-plugin": "^4.0.0", + "forwarded": "^0.2.0", + "http-errors": "^2.0.0", + "type-is": "^1.6.18", + "vary": "^1.1.2" + } + }, + "node_modules/@fastify/static": { + "version": "7.0.4", + "resolved": "https://registry.npmjs.org/@fastify/static/-/static-7.0.4.tgz", + "integrity": "sha512-p2uKtaf8BMOZWLs6wu+Ihg7bWNBdjNgCwDza4MJtTqg+5ovKmcbgbR9Xs5/smZ1YISfzKOCNYmZV8LaCj+eJ1Q==", + "license": "MIT", + "dependencies": { + "@fastify/accept-negotiator": "^1.0.0", + "@fastify/send": "^2.0.0", + "content-disposition": "^0.5.3", + "fastify-plugin": "^4.0.0", + "fastq": "^1.17.0", + "glob": "^10.3.4" + } + }, "node_modules/@fastify/under-pressure": { "version": "8.3.0", "resolved": "https://registry.npmjs.org/@fastify/under-pressure/-/under-pressure-8.3.0.tgz", @@ -699,6 +765,82 @@ "@influxdata/influxdb-client": "*" } }, + "node_modules/@isaacs/cliui": { + "version": "8.0.2", + "resolved": "https://registry.npmjs.org/@isaacs/cliui/-/cliui-8.0.2.tgz", + "integrity": "sha512-O8jcjabXaleOG9DQ0+ARXWZBTfnP4WNAqzuiJK7ll44AmxGKv/J2M4TPjxjY3znBCfvBXFzucm1twdyFybFqEA==", + "license": "ISC", + "dependencies": { + "string-width": "^5.1.2", + "string-width-cjs": "npm:string-width@^4.2.0", + "strip-ansi": "^7.0.1", + "strip-ansi-cjs": "npm:strip-ansi@^6.0.1", + "wrap-ansi": "^8.1.0", + "wrap-ansi-cjs": "npm:wrap-ansi@^7.0.0" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/@isaacs/cliui/node_modules/ansi-regex": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.0.1.tgz", + "integrity": "sha512-n5M855fKb2SsfMIiFFoVrABHJC8QtHwVx+mHWP3QcEqBHYienj5dHSgjbxtC0WEZXYt4wcD6zrQElDPhFuZgfA==", + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "/~https://github.com/chalk/ansi-regex?sponsor=1" + } + }, + "node_modules/@isaacs/cliui/node_modules/emoji-regex": { + "version": "9.2.2", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-9.2.2.tgz", + "integrity": "sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==", + "license": "MIT" + }, + "node_modules/@isaacs/cliui/node_modules/string-width": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-5.1.2.tgz", + "integrity": "sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA==", + "license": "MIT", + "dependencies": { + "eastasianwidth": "^0.2.0", + "emoji-regex": "^9.2.2", + "strip-ansi": "^7.0.1" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "/~https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@isaacs/cliui/node_modules/strip-ansi": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.1.0.tgz", + "integrity": "sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ==", + "license": "MIT", + "dependencies": { + "ansi-regex": "^6.0.1" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "/~https://github.com/chalk/strip-ansi?sponsor=1" + } + }, + "node_modules/@lukeed/ms": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/@lukeed/ms/-/ms-2.0.2.tgz", + "integrity": "sha512-9I2Zn6+NJLfaGoz9jN3lpwDgAYvfGeNYdbAIjJOqzs4Tpc+VU3Jqq4IofSUBKajiDS8k9fZIg18/z13mpk1bsA==", + "license": "MIT", + "engines": { + "node": ">=8" + } + }, "node_modules/@nodelib/fs.scandir": { "version": "2.1.5", "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", @@ -742,6 +884,16 @@ "node": ">=8.0.0" } }, + "node_modules/@pkgjs/parseargs": { + "version": "0.11.0", + "resolved": "https://registry.npmjs.org/@pkgjs/parseargs/-/parseargs-0.11.0.tgz", + "integrity": "sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg==", + "license": "MIT", + "optional": true, + "engines": { + "node": ">=14" + } + }, "node_modules/@pkgr/core": { "version": "0.1.1", "resolved": "https://registry.npmjs.org/@pkgr/core/-/core-0.1.1.tgz", @@ -981,7 +1133,6 @@ "version": "5.0.1", "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", - "dev": true, "engines": { "node": ">=8" } @@ -990,7 +1141,6 @@ "version": "4.3.0", "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "dev": true, "dependencies": { "color-convert": "^2.0.1" }, @@ -1063,8 +1213,7 @@ "node_modules/balanced-match": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", - "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", - "dev": true + "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==" }, "node_modules/base64-js": { "version": "1.5.1", @@ -1191,7 +1340,6 @@ "version": "2.0.1", "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "dev": true, "dependencies": { "color-name": "~1.1.4" }, @@ -1307,6 +1455,18 @@ "node": ">= 10.0.0" } }, + "node_modules/content-disposition": { + "version": "0.5.4", + "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.4.tgz", + "integrity": "sha512-FveZTNuGw04cxlAiWbzi6zTAL/lhehaWbTtgluJh4/E95DqMwTmha3KZN1aAWA8cFIhHzMZUvLevkw5Rqk+tSQ==", + "license": "MIT", + "dependencies": { + "safe-buffer": "5.2.1" + }, + "engines": { + "node": ">= 0.6" + } + }, "node_modules/cookie": { "version": "0.5.0", "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.5.0.tgz", @@ -1319,7 +1479,6 @@ "version": "7.0.3", "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz", "integrity": "sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==", - "dev": true, "dependencies": { "path-key": "^3.1.0", "shebang-command": "^2.0.0", @@ -1375,17 +1534,31 @@ "node": ">=0.4.0" } }, + "node_modules/depd": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz", + "integrity": "sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==", + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, "node_modules/detect-node": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/detect-node/-/detect-node-2.1.0.tgz", "integrity": "sha512-T0NIuQpnTvFDATNuHN5roPwSBG83rFsuO+MXXH9/3N1eFbn4wcPjttvjMLEPWJ0RGUYgQE7cGgS3tNxbqCGM7g==", "dev": true }, + "node_modules/eastasianwidth": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/eastasianwidth/-/eastasianwidth-0.2.0.tgz", + "integrity": "sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==", + "license": "MIT" + }, "node_modules/emoji-regex": { "version": "8.0.0", "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", - "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", - "dev": true + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==" }, "node_modules/enabled": { "version": "2.0.0", @@ -1438,6 +1611,12 @@ "@esbuild/win32-x64": "0.23.1" } }, + "node_modules/escape-html": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz", + "integrity": "sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow==", + "license": "MIT" + }, "node_modules/escape-string-regexp": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", @@ -2005,6 +2184,22 @@ } } }, + "node_modules/foreground-child": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/foreground-child/-/foreground-child-3.3.0.tgz", + "integrity": "sha512-Ld2g8rrAyMYFXBhEqMz8ZAHBi4J4uS1i/CxGMDnjyFWddMXLVcDp051DZfu+t7+ab7Wv6SMqpWmyFIj5UbfFvg==", + "license": "ISC", + "dependencies": { + "cross-spawn": "^7.0.0", + "signal-exit": "^4.0.1" + }, + "engines": { + "node": ">=14" + }, + "funding": { + "url": "/~https://github.com/sponsors/isaacs" + } + }, "node_modules/form-data": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.0.tgz", @@ -2063,6 +2258,26 @@ "url": "/~https://github.com/sponsors/ljharb" } }, + "node_modules/glob": { + "version": "10.4.5", + "resolved": "https://registry.npmjs.org/glob/-/glob-10.4.5.tgz", + "integrity": "sha512-7Bv8RF0k6xjo7d4A/PxYLbUCfb6c+Vpd2/mB2yRDlew7Jb5hEXiCD9ibfO7wpk8i4sevK6DFny9h7EYbM3/sHg==", + "license": "ISC", + "dependencies": { + "foreground-child": "^3.1.0", + "jackspeak": "^3.1.2", + "minimatch": "^9.0.4", + "minipass": "^7.1.2", + "package-json-from-dist": "^1.0.0", + "path-scurry": "^1.11.1" + }, + "bin": { + "glob": "dist/esm/bin.mjs" + }, + "funding": { + "url": "/~https://github.com/sponsors/isaacs" + } + }, "node_modules/glob-parent": { "version": "6.0.2", "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz", @@ -2075,6 +2290,30 @@ "node": ">=10.13.0" } }, + "node_modules/glob/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/glob/node_modules/minimatch": { + "version": "9.0.5", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.5.tgz", + "integrity": "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==", + "license": "ISC", + "dependencies": { + "brace-expansion": "^2.0.1" + }, + "engines": { + "node": ">=16 || 14 >=14.17" + }, + "funding": { + "url": "/~https://github.com/sponsors/isaacs" + } + }, "node_modules/global-agent": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/global-agent/-/global-agent-3.0.0.tgz", @@ -2152,6 +2391,27 @@ "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz", "integrity": "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==" }, + "node_modules/handlebars": { + "version": "4.7.8", + "resolved": "https://registry.npmjs.org/handlebars/-/handlebars-4.7.8.tgz", + "integrity": "sha512-vafaFqs8MZkRrSX7sFVUdo3ap/eNiLnb4IakshzvP56X5Nr1iGKAIqdX6tMlm6HcNRIkr6AxO5jFEoJzzpT8aQ==", + "license": "MIT", + "dependencies": { + "minimist": "^1.2.5", + "neo-async": "^2.6.2", + "source-map": "^0.6.1", + "wordwrap": "^1.0.0" + }, + "bin": { + "handlebars": "bin/handlebars" + }, + "engines": { + "node": ">=0.4.7" + }, + "optionalDependencies": { + "uglify-js": "^3.1.4" + } + }, "node_modules/has": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz", @@ -2215,6 +2475,22 @@ "integrity": "sha512-7xgomUX6ADmcYzFik0HzAxh/73YlKR9bmFzf51CZwR+b6YtzU2m0u49hQCqV6SvlqIqsaxovfwdvbnsw3b/zpg==", "license": "MIT" }, + "node_modules/http-errors": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-2.0.0.tgz", + "integrity": "sha512-FtwrG/euBzaEjYeRqOgly7G0qviiXoJWnvEH2Z1plBdXgbyjv34pHTSb9zoeHMyDy33+DWy5Wt9Wo+TURtOYSQ==", + "license": "MIT", + "dependencies": { + "depd": "2.0.0", + "inherits": "2.0.4", + "setprototypeof": "1.2.0", + "statuses": "2.0.1", + "toidentifier": "1.0.1" + }, + "engines": { + "node": ">= 0.8" + } + }, "node_modules/https-proxy-agent": { "version": "5.0.1", "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-5.0.1.tgz", @@ -2319,7 +2595,6 @@ "version": "3.0.0", "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", - "dev": true, "engines": { "node": ">=8" } @@ -2348,8 +2623,22 @@ "node_modules/isexe": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", - "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==", - "dev": true + "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==" + }, + "node_modules/jackspeak": { + "version": "3.4.3", + "resolved": "https://registry.npmjs.org/jackspeak/-/jackspeak-3.4.3.tgz", + "integrity": "sha512-OGlZQpz2yfahA/Rd1Y8Cd9SIEsqvXkLVoSw/cgwhnhFMDbsQFeZYoJJ7bIZBS9BcamUW96asq/npPWugM+RQBw==", + "license": "BlueOak-1.0.0", + "dependencies": { + "@isaacs/cliui": "^8.0.2" + }, + "funding": { + "url": "/~https://github.com/sponsors/isaacs" + }, + "optionalDependencies": { + "@pkgjs/parseargs": "^0.11.0" + } }, "node_modules/js-sdsl": { "version": "4.3.0", @@ -2540,6 +2829,27 @@ "node": ">=10" } }, + "node_modules/media-typer": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz", + "integrity": "sha512-dq+qelQ9akHpcOl/gUVRTxVIOkAJ1wR3QAvb4RsVjS8oVoFjDGTc679wJYmUmknUF5HwMLOgb5O+a3KxfWapPQ==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/mime": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/mime/-/mime-3.0.0.tgz", + "integrity": "sha512-jSCU7/VB1loIWBZe14aEYHU/+1UMEHoaO7qxCOVJOw9GgH72VAWppxNcjU+x9a2k3GSIBXNKxXQFqRvvZ7vr3A==", + "license": "MIT", + "bin": { + "mime": "cli.js" + }, + "engines": { + "node": ">=10.0.0" + } + }, "node_modules/mime-db": { "version": "1.52.0", "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", @@ -2579,6 +2889,15 @@ "url": "/~https://github.com/sponsors/ljharb" } }, + "node_modules/minipass": { + "version": "7.1.2", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-7.1.2.tgz", + "integrity": "sha512-qOOzS1cBTWYF4BH8fVePDBOO9iptMnGUEZwNc/cMWnTV2nVLZ7VoNWEPHkYczZA0pdoA7dl6e7FL659nX9S2aw==", + "license": "ISC", + "engines": { + "node": ">=16 || 14 >=14.17" + } + }, "node_modules/moment": { "version": "2.29.4", "resolved": "https://registry.npmjs.org/moment/-/moment-2.29.4.tgz", @@ -2641,6 +2960,12 @@ "integrity": "sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==", "dev": true }, + "node_modules/neo-async": { + "version": "2.6.2", + "resolved": "https://registry.npmjs.org/neo-async/-/neo-async-2.6.2.tgz", + "integrity": "sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw==", + "license": "MIT" + }, "node_modules/number-allocator": { "version": "1.0.14", "resolved": "https://registry.npmjs.org/number-allocator/-/number-allocator-1.0.14.tgz", @@ -2731,6 +3056,12 @@ "url": "/~https://github.com/sponsors/sindresorhus" } }, + "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", + "integrity": "sha512-dATvCeZN/8wQsGywez1mzHtTlP22H8OEfPrVMLNr4/eGa+ijtLn/6M5f0dY8UKNrC2O9UCU6SSoG3qRKnt7STw==", + "license": "BlueOak-1.0.0" + }, "node_modules/parent-module": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz", @@ -2757,11 +3088,26 @@ "version": "3.1.1", "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", - "dev": true, "engines": { "node": ">=8" } }, + "node_modules/path-scurry": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/path-scurry/-/path-scurry-1.11.1.tgz", + "integrity": "sha512-Xa4Nw17FS9ApQFJ9umLiJS4orGjm7ZzwUrwamcGQuHSzDyth9boKDaycYdDcZDuqYATXw4HFXgaqWTctW/v1HA==", + "license": "BlueOak-1.0.0", + "dependencies": { + "lru-cache": "^10.2.0", + "minipass": "^5.0.0 || ^6.0.2 || ^7.0.0" + }, + "engines": { + "node": ">=16 || 14 >=14.18" + }, + "funding": { + "url": "/~https://github.com/sponsors/isaacs" + } + }, "node_modules/pg": { "version": "8.12.0", "resolved": "https://registry.npmjs.org/pg/-/pg-8.12.0.tgz", @@ -3259,11 +3605,16 @@ "resolved": "https://registry.npmjs.org/set-cookie-parser/-/set-cookie-parser-2.6.0.tgz", "integrity": "sha512-RVnVQxTXuerk653XfuliOxBP81Sf0+qfQE73LIYKcyMYHG94AuH0kgrQpRDuTZnSmjpysHmzxJXKNfa6PjFhyQ==" }, + "node_modules/setprototypeof": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.2.0.tgz", + "integrity": "sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==", + "license": "ISC" + }, "node_modules/shebang-command": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", - "dev": true, "dependencies": { "shebang-regex": "^3.0.0" }, @@ -3275,11 +3626,22 @@ "version": "3.0.0", "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", - "dev": true, "engines": { "node": ">=8" } }, + "node_modules/signal-exit": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-4.1.0.tgz", + "integrity": "sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==", + "license": "ISC", + "engines": { + "node": ">=14" + }, + "funding": { + "url": "/~https://github.com/sponsors/isaacs" + } + }, "node_modules/simple-swizzle": { "version": "0.2.2", "resolved": "https://registry.npmjs.org/simple-swizzle/-/simple-swizzle-0.2.2.tgz", @@ -3331,6 +3693,15 @@ "atomic-sleep": "^1.0.0" } }, + "node_modules/source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "license": "BSD-3-Clause", + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/split2": { "version": "4.2.0", "resolved": "https://registry.npmjs.org/split2/-/split2-4.2.0.tgz", @@ -3353,6 +3724,15 @@ "node": "*" } }, + "node_modules/statuses": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.1.tgz", + "integrity": "sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ==", + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, "node_modules/string_decoder": { "version": "1.3.0", "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz", @@ -3365,7 +3745,21 @@ "version": "4.2.3", "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", - "dev": true, + "dependencies": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/string-width-cjs": { + "name": "string-width", + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "license": "MIT", "dependencies": { "emoji-regex": "^8.0.0", "is-fullwidth-code-point": "^3.0.0", @@ -3379,7 +3773,19 @@ "version": "6.0.1", "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", - "dev": true, + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/strip-ansi-cjs": { + "name": "strip-ansi", + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "license": "MIT", "dependencies": { "ansi-regex": "^5.0.1" }, @@ -3521,13 +3927,23 @@ } }, "node_modules/toad-cache": { - "version": "3.3.0", - "resolved": "https://registry.npmjs.org/toad-cache/-/toad-cache-3.3.0.tgz", - "integrity": "sha512-3oDzcogWGHZdkwrHyvJVpPjA7oNzY6ENOV3PsWJY9XYPZ6INo94Yd47s5may1U+nleBPwDhrRiTPMIvKaa3MQg==", + "version": "3.7.0", + "resolved": "https://registry.npmjs.org/toad-cache/-/toad-cache-3.7.0.tgz", + "integrity": "sha512-/m8M+2BJUpoJdgAHoG+baCwBT+tf2VraSfkBgl0Y00qIWt41DJ8R5B8nsEw0I58YwF5IZH6z24/2TobDKnqSWw==", + "license": "MIT", "engines": { "node": ">=12" } }, + "node_modules/toidentifier": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.1.tgz", + "integrity": "sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA==", + "license": "MIT", + "engines": { + "node": ">=0.6" + } + }, "node_modules/triple-beam": { "version": "1.4.1", "resolved": "https://registry.npmjs.org/triple-beam/-/triple-beam-1.4.1.tgz", @@ -3553,6 +3969,19 @@ "node": ">= 0.8.0" } }, + "node_modules/type-is": { + "version": "1.6.18", + "resolved": "https://registry.npmjs.org/type-is/-/type-is-1.6.18.tgz", + "integrity": "sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g==", + "license": "MIT", + "dependencies": { + "media-typer": "0.3.0", + "mime-types": "~2.1.24" + }, + "engines": { + "node": ">= 0.6" + } + }, "node_modules/typedarray": { "version": "0.0.6", "resolved": "https://registry.npmjs.org/typedarray/-/typedarray-0.0.6.tgz", @@ -3581,6 +4010,19 @@ "node": "*" } }, + "node_modules/uglify-js": { + "version": "3.19.2", + "resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-3.19.2.tgz", + "integrity": "sha512-S8KA6DDI47nQXJSi2ctQ629YzwOVs+bQML6DAtvy0wgNdpi+0ySpQK0g2pxBq2xfF2z3YCscu7NNA8nXT9PlIQ==", + "license": "BSD-2-Clause", + "optional": true, + "bin": { + "uglifyjs": "bin/uglifyjs" + }, + "engines": { + "node": ">=0.8.0" + } + }, "node_modules/undici-types": { "version": "6.18.2", "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-6.18.2.tgz", @@ -3621,11 +4063,19 @@ "uuid": "dist/bin/uuid" } }, + "node_modules/vary": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz", + "integrity": "sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg==", + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, "node_modules/which": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", - "dev": true, "dependencies": { "isexe": "^2.0.0" }, @@ -3725,6 +4175,12 @@ "node": ">= 6" } }, + "node_modules/wordwrap": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/wordwrap/-/wordwrap-1.0.0.tgz", + "integrity": "sha512-gvVzJFlPycKc5dZN4yPkP8w7Dc37BtP1yczEneOb4uq34pXZcvrtRTmWV8W+Ume+XCxKgbjM+nevkyFPMybd4Q==", + "license": "MIT" + }, "node_modules/worker-timers": { "version": "7.1.8", "resolved": "https://registry.npmjs.org/worker-timers/-/worker-timers-7.1.8.tgz", @@ -3759,6 +4215,103 @@ "tslib": "^2.6.2" } }, + "node_modules/wrap-ansi": { + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-8.1.0.tgz", + "integrity": "sha512-si7QWI6zUMq56bESFvagtmzMdGOtoxfR+Sez11Mobfc7tm+VkUckk9bW2UeffTGVUbOksxmSw0AA2gs8g71NCQ==", + "license": "MIT", + "dependencies": { + "ansi-styles": "^6.1.0", + "string-width": "^5.0.1", + "strip-ansi": "^7.0.1" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "/~https://github.com/chalk/wrap-ansi?sponsor=1" + } + }, + "node_modules/wrap-ansi-cjs": { + "name": "wrap-ansi", + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", + "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", + "license": "MIT", + "dependencies": { + "ansi-styles": "^4.0.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "/~https://github.com/chalk/wrap-ansi?sponsor=1" + } + }, + "node_modules/wrap-ansi/node_modules/ansi-regex": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.0.1.tgz", + "integrity": "sha512-n5M855fKb2SsfMIiFFoVrABHJC8QtHwVx+mHWP3QcEqBHYienj5dHSgjbxtC0WEZXYt4wcD6zrQElDPhFuZgfA==", + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "/~https://github.com/chalk/ansi-regex?sponsor=1" + } + }, + "node_modules/wrap-ansi/node_modules/ansi-styles": { + "version": "6.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-6.2.1.tgz", + "integrity": "sha512-bN798gFfQX+viw3R7yrGWRqnrN2oRkEkUjjl4JNn4E8GxxbjtG3FbrEIIY3l8/hrwUwIeCZvi4QuOTP4MErVug==", + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "/~https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/wrap-ansi/node_modules/emoji-regex": { + "version": "9.2.2", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-9.2.2.tgz", + "integrity": "sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==", + "license": "MIT" + }, + "node_modules/wrap-ansi/node_modules/string-width": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-5.1.2.tgz", + "integrity": "sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA==", + "license": "MIT", + "dependencies": { + "eastasianwidth": "^0.2.0", + "emoji-regex": "^9.2.2", + "strip-ansi": "^7.0.1" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "/~https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/wrap-ansi/node_modules/strip-ansi": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.1.0.tgz", + "integrity": "sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ==", + "license": "MIT", + "dependencies": { + "ansi-regex": "^6.0.1" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "/~https://github.com/chalk/strip-ansi?sponsor=1" + } + }, "node_modules/ws": { "version": "8.18.0", "resolved": "https://registry.npmjs.org/ws/-/ws-8.18.0.tgz", diff --git a/package.json b/package.json index 7a170459..e0d6579a 100644 --- a/package.json +++ b/package.json @@ -31,6 +31,9 @@ "type": "module", "dependencies": { "@breejs/later": "^4.2.0", + "@fastify/rate-limit": "^9.1.0", + "@fastify/sensible": "^5.6.0", + "@fastify/static": "^7.0.4", "@influxdata/influxdb-client": "^1.35.0", "@influxdata/influxdb-client-apis": "^1.35.0", "axios": "^1.7.4", @@ -40,6 +43,7 @@ "fastify-healthcheck": "^4.4.0", "fastify-metrics": "^11.0.0", "fs-extra": "^11.2.0", + "handlebars": "^4.7.7", "influx": "^5.9.3", "js-yaml": "^4.1.0", "lodash.clonedeep": "^4.5.0", diff --git a/src/butler-sos.js b/src/butler-sos.js index 03c95634..70b2aaa5 100755 --- a/src/butler-sos.js +++ b/src/butler-sos.js @@ -24,6 +24,7 @@ import { udpInitLogEventServer } from './lib/udp_handlers_log_events.js'; import { setupAnonUsageReportTimer } from './lib/telemetry.js'; import { setupPromClient } from './lib/prom-client.js'; import { verifyConfigFile } from './lib/config-file-verify.js'; +import { setupConfigVisServer } from './lib/config-visualise.js'; // Suppress experimental warnings // https://stackoverflow.com/questions/55778283/how-to-disable-warnings-when-node-is-launched-via-a-global-shell-script @@ -279,6 +280,11 @@ async function mainScript() { if (globals.config.get('Butler-SOS.appNames.enableAppNameExtract') === true) { setupAppNamesExtractTimer(); } + + // Set up config server, if enabled + if (globals.config.get('Butler-SOS.configVisualisation.enable') === true) { + await setupConfigVisServer(); + } } mainScript(); diff --git a/src/config/production_template.yaml b/src/config/production_template.yaml index 3f79675b..82e67130 100644 --- a/src/config/production_template.yaml +++ b/src/config/production_template.yaml @@ -10,6 +10,13 @@ Butler-SOS: # More info on whata data is collected: https://butler-sos.ptarmiganlabs.com/docs/about/telemetry/ # Please consider leaving this at true - it really helps future development of Butler SOS! + # Should Butler SOS start a web server that serves an obfuscated view of the Butler SOS config file? + configVisualisation: + enable: false + host: localhost # Hostname or IP address where the web server will listen. Should be localhost in most cases. + port: 3100 # Port where the web server will listen. Change if port 3100 is already in use. + obfuscate: true # Should the config file shown in the web UI be obfuscated? + # Heartbeats can be used to send "I'm alive" messages to some other tool, e.g. an infrastructure monitoring tool # The concept is simple: The remoteURL will be called at the specified frequency. The receiving tool will then know # that Butler SOS is alive. diff --git a/src/lib/config-file-schema.js b/src/lib/config-file-schema.js index 778bc0a9..82203cf9 100755 --- a/src/lib/config-file-schema.js +++ b/src/lib/config-file-schema.js @@ -4,6 +4,12 @@ export const confifgFileSchema = { fileLogging: 'boolean', logDirectory: 'string', anonTelemetry: 'boolean', + configVisualisation: { + enable: 'boolean', + host: 'string', + port: 'number', + obfuscate: 'boolean', + }, heartbeat: { enable: 'boolean', remoteURL: 'string', diff --git a/src/lib/config-obfuscate.js b/src/lib/config-obfuscate.js new file mode 100644 index 00000000..fb482801 --- /dev/null +++ b/src/lib/config-obfuscate.js @@ -0,0 +1,152 @@ +import globals from '../globals.js'; + +function configObfuscate(config) { + try { + const obfuscatedConfig = { ...config }; + + // Keep first 10 chars of remote URL, mask the rest with * + obfuscatedConfig['Butler-SOS'].heartbeat.remoteURL = obfuscatedConfig['Butler-SOS'].heartbeat.remoteURL.substring(0, 10) + '*'.repeat(10); + + // Update entries in the array obfuscatedConfig['Butler-SOS'].thirdPartyToolsCredentials.newRelic + obfuscatedConfig['Butler-SOS'].thirdPartyToolsCredentials.newRelic = obfuscatedConfig['Butler-SOS'].thirdPartyToolsCredentials.newRelic?.map( + (element) => ({ + ...element, + insertApiKey: element.insertApiKey.substring(0, 5) + '*'.repeat(10), + accountId: element.accountId.toString().substring(0, 3) + '*'.repeat(10), + }), + ); + + // Obfuscate Butler-SOS.iuserEvents.udpServerConfig.serverHost, keep first 3 chars, mask the rest with * + obfuscatedConfig['Butler-SOS'].userEvents.udpServerConfig.serverHost = + obfuscatedConfig['Butler-SOS'].userEvents.udpServerConfig.serverHost.substring(0, 3) + '*'.repeat(10); + + // Obfuscate Butler-SOS.iuserEvents.sendToMQTT.postTo.everythingTopic.topic, keep first 10 chars, mask the rest with * + obfuscatedConfig['Butler-SOS'].userEvents.sendToMQTT.postTo.everythingTopic.topic = + obfuscatedConfig['Butler-SOS'].userEvents.sendToMQTT.postTo.everythingTopic.topic.substring(0, 10) + '*'.repeat(10); + + // Obfuscate Butler-SOS.iuserEvents.sendToMQTT.postTo.sessionStartTopic.topic, keep first 10 chars, mask the rest with * + obfuscatedConfig['Butler-SOS'].userEvents.sendToMQTT.postTo.sessionStartTopic.topic = + obfuscatedConfig['Butler-SOS'].userEvents.sendToMQTT.postTo.sessionStartTopic.topic.substring(0, 10) + '*'.repeat(10); + + // Obfuscate Butler-SOS.iuserEvents.sendToMQTT.postTo.sessionStopTopic.topic, keep first 10 chars, mask the rest with * + obfuscatedConfig['Butler-SOS'].userEvents.sendToMQTT.postTo.sessionStopTopic.topic = + obfuscatedConfig['Butler-SOS'].userEvents.sendToMQTT.postTo.sessionStopTopic.topic.substring(0, 10) + '*'.repeat(10); + + // Obfuscate Butler-SOS.iuserEvents.sendToMQTT.postTo.connectionOpenTopic.topic, keep first 10 chars, mask the rest with * + obfuscatedConfig['Butler-SOS'].userEvents.sendToMQTT.postTo.connectionOpenTopic.topic = + obfuscatedConfig['Butler-SOS'].userEvents.sendToMQTT.postTo.connectionOpenTopic.topic.substring(0, 10) + '*'.repeat(10); + + // Obfuscate Butler-SOS.iuserEvents.sendToMQTT.postTo.connectionCloseTopic.topic, keep first 10 chars, mask the rest with * + obfuscatedConfig['Butler-SOS'].userEvents.sendToMQTT.postTo.connectionCloseTopic.topic = + obfuscatedConfig['Butler-SOS'].userEvents.sendToMQTT.postTo.connectionCloseTopic.topic.substring(0, 10) + '*'.repeat(10); + + // Obfuscate Butler-SOS.logEvents.udpServerConfig.serverHost, keep first 3 chars, mask the rest with * + obfuscatedConfig['Butler-SOS'].logEvents.udpServerConfig.serverHost = + obfuscatedConfig['Butler-SOS'].logEvents.udpServerConfig.serverHost.substring(0, 3) + '*'.repeat(10); + + // Obfuscate Butler-SOS.logEvents.sendToMQTT.baseTopic, keep first 10 chars, mask the rest with * + obfuscatedConfig['Butler-SOS'].logEvents.sendToMQTT.baseTopic = + obfuscatedConfig['Butler-SOS'].logEvents.sendToMQTT.baseTopic.substring(0, 10) + '*'.repeat(10); + + // Log db - may not be present in the config in future versions of Butler SOS + if (obfuscatedConfig['Butler-SOS'].logdb) { + // Obfuscate Butler-SOS.logdb.host, keep first 3 chars, mask the rest with * + obfuscatedConfig['Butler-SOS'].logdb.host = obfuscatedConfig['Butler-SOS'].logdb.host.substring(0, 3) + '*'.repeat(10); + + // Obfuscate Butler-SOS.logdb.qlogsReaderUser, keep first 3 chars, mask the rest with * + obfuscatedConfig['Butler-SOS'].logdb.qlogsReaderUser = obfuscatedConfig['Butler-SOS'].logdb.qlogsReaderUser.substring(0, 3) + '*'.repeat(10); + + // Obfuscate Butler-SOS.logdb.qlogsReaderPwdd, keep first 0 chars, mask the rest with * + obfuscatedConfig['Butler-SOS'].logdb.qlogsReaderPwdd = '*'.repeat(10); + } + + // Obfuscate Butler-SOS.cert.clientCert, keep first 10 chars, mask the rest with * + obfuscatedConfig['Butler-SOS'].cert.clientCert = obfuscatedConfig['Butler-SOS'].cert.clientCert.substring(0, 10) + '*'.repeat(10); + + // Obfuscate Butler-SOS.cert.clientCertKey, keep first 10 chars, mask the rest with * + obfuscatedConfig['Butler-SOS'].cert.clientCertKey = obfuscatedConfig['Butler-SOS'].cert.clientCertKey.substring(0, 10) + '*'.repeat(10); + + // Obfuscate Butler-SOS.cert.clientCertCA, keep first 10 chars, mask the rest with * + obfuscatedConfig['Butler-SOS'].cert.clientCertCA = obfuscatedConfig['Butler-SOS'].cert.clientCertCA.substring(0, 10) + '*'.repeat(10); + + // Obfuscate Butler-SOS.cert.clientCertPassphrase, keep first 0 chars, mask the rest with * + obfuscatedConfig['Butler-SOS'].cert.clientCertPassphrase = '*'.repeat(10); + + // Obfuscate Butler-SOS.mqttConfig.brokerHost, keep first 3 chars, mask the rest with * + obfuscatedConfig['Butler-SOS'].mqttConfig.brokerHost = obfuscatedConfig['Butler-SOS'].mqttConfig.brokerHost.substring(0, 3) + '*'.repeat(10); + + + // Obfuscate Butler-SOS.prometheus.host, keep first 3 chars, mask the rest with * + obfuscatedConfig['Butler-SOS'].prometheus.host = obfuscatedConfig['Butler-SOS'].prometheus.host.substring(0, 3) + '*'.repeat(10); + + // Obfuscate Butler-SOS.influxdbConfig.host, keep first 3 chars, mask the rest with * + obfuscatedConfig['Butler-SOS'].influxdbConfig.host = obfuscatedConfig['Butler-SOS'].influxdbConfig.host.substring(0, 3) + '*'.repeat(10); + + // Obfuscate Butler-SOS.influxdbConfig.v2Config.org, keep first 3 chars, mask the rest with * + obfuscatedConfig['Butler-SOS'].influxdbConfig.v2Config.org = obfuscatedConfig['Butler-SOS'].influxdbConfig.v2Config.org.substring(0, 3) + '*'.repeat(10); + + // Obfuscate Butler-SOS.influxdbConfig.v2Config.bucket, keep first 3 chars, mask the rest with * + obfuscatedConfig['Butler-SOS'].influxdbConfig.v2Config.bucket = obfuscatedConfig['Butler-SOS'].influxdbConfig.v2Config.bucket.substring(0, 3) + '*'.repeat(10); + + // Obfuscate Butler-SOS.influxdbConfig.v2Config.token, keep first 0 chars, mask the rest with * + obfuscatedConfig['Butler-SOS'].influxdbConfig.v2Config.token = '*'.repeat(10); + + // Obfuscate Butler-SOS.influxdbConfig.v1Config.auth.username, keep first 3 chars, mask the rest with * + obfuscatedConfig['Butler-SOS'].influxdbConfig.v1Config.auth.username = obfuscatedConfig['Butler-SOS'].influxdbConfig.v1Config.auth.username.substring(0, 3) + '*'.repeat(10); + + // Obfuscate Butler-SOS.influxdbConfig.v1Config.auth.password, keep first 0 chars, mask the rest with * + obfuscatedConfig['Butler-SOS'].influxdbConfig.v1Config.auth.password = '*'.repeat(10); + + // Obfuscate Butler-SOS.appNames.hostIP, keep first 3 chars, mask the rest with * + obfuscatedConfig['Butler-SOS'].appNames.hostIP = obfuscatedConfig['Butler-SOS'].appNames.hostIP.substring(0, 3) + '*'.repeat(10); + + + + // Obfuscate Butler-SOS.serversToMonitor.servers[].host, keep first 3 chars, mask the rest with * + obfuscatedConfig['Butler-SOS'].serversToMonitor.servers = obfuscatedConfig['Butler-SOS'].serversToMonitor.servers?.map((element) => ({ + ...element, + host: element.host.substring(0, 3) + '*'.repeat(10), + })); + + // Obfuscate Butler-SOS.serversToMonitor.servers[].logDbHost, keep first 3 chars, mask the rest with * + obfuscatedConfig['Butler-SOS'].serversToMonitor.servers = obfuscatedConfig['Butler-SOS'].serversToMonitor.servers?.map((element) => ({ + ...element, + logDbHost: element.logDbHost.substring(0, 3) + '*'.repeat(10), + })); + + // Obfuscate Butler-SOS.serversToMonitor.servers[].userSessions.host, keep first 3 chars, mask the rest with * + obfuscatedConfig['Butler-SOS'].serversToMonitor.servers = obfuscatedConfig['Butler-SOS'].serversToMonitor.servers?.map((element) => ({ + ...element, + userSessions: element.userSessions.host.substring(0, 3) + '*'.repeat(10), + })); + + // Obfuscate Butler-SOS.serversToMonitor.servers[].headers, keep first 5 chars, mask the rest with * + // Butler-SOS.serversToMonitor.servers[].headers is an object, so we need to obfuscate each key-value pair + // If the array Butler-SOS.serversToMonitor.servers[].headers is empty, no obfuscation should be done + obfuscatedConfig['Butler-SOS'].serversToMonitor.servers = obfuscatedConfig['Butler-SOS'].serversToMonitor.servers?.map((element) => { + const newHeaders = {}; + + // Is elemnt.headers an object with more than 0 key-value pairs? + if (element?.headers && Object.keys(element?.headers)?.length > 0) { + Object.entries(element?.headers).forEach(([key, value]) => { + newHeaders[key] = value.substring(0, 5) + '*'.repeat(10); + }); + } + + return { + ...element, + headers: newHeaders, + }; + }); + + return obfuscatedConfig; + } catch (err) { + globals.logger.error(`CONFIG OBFUSCATE: Error obfuscating config: ${err.message}`); + if (err.stack) { + globals.logger.error(`CONFIG OBFUSCATE: ${err.stack}`); + } + throw err; + } +} + +export default configObfuscate; diff --git a/src/lib/config-visualise.js b/src/lib/config-visualise.js new file mode 100644 index 00000000..2129c1b9 --- /dev/null +++ b/src/lib/config-visualise.js @@ -0,0 +1,138 @@ +import Fastify from 'fastify'; +import FastifyRateLimit from '@fastify/rate-limit'; +import FastifyStatic from '@fastify/static'; +import fs from 'fs'; +import path from 'path'; +import yaml from 'js-yaml'; +import handlebars from 'handlebars'; + +import globals from '../globals.js'; +import configObfuscate from './config-obfuscate.js'; + +export async function setupConfigVisServer(logger, config) { + try { + // Register rate limit for API + // 0 means no rate limit + + // This code registers the FastifyRateLimit plugin. + // The plugin limits the number of API requests that + // can be made from a given IP address within a given + // time window. + + const configVisServer = Fastify({ logger: true }); + + // Set Fastify log level based on log level in Butler config file + const currLogLevel = globals.getLoggingLevel(); + if (currLogLevel === 'debug' || currLogLevel === 'silly') { + configVisServer.log.level = 'info'; + } else { + configVisServer.log.level = 'silent'; + } + + // 30 requests per minute + await configVisServer.register(FastifyRateLimit, { + max: 300, + timeWindow: '1 minute', + }); + + // Add custom error handler for 429 errors (rate limit exceeded) + configVisServer.setErrorHandler((error, request, reply) => { + if (error.statusCode === 429) { + globals.logger.warn( + `CONFIG VIS: Rate limit exceeded for source IP address ${request.ip}. Method=${request.method}, endpoint=${request.url}`, + ); + } + reply.send(error); + }); + + // This loads all plugins defined in plugins. + // Those should be support plugins that are reused through your application + await configVisServer.register(import('../plugins/sensible.js'), { options: {} }); + await configVisServer.register(import('../plugins/support.js'), { options: {} }); + + // Create absolute path to the html directory + // dirname points to the directory where this file (app.js) is located, taking into account + // if the app is running as a packaged app or as a Node.js app. + globals.logger.verbose(`----------------2: ${globals.appBasePath}`); + + // Get directory contents of dirname + const dirContents = fs.readdirSync(globals.appBasePath); + globals.logger.verbose(`CONFIG VIS: Directory contents of "${globals.appBasePath}": ${dirContents}`); + + + const htmlDir = path.resolve(globals.appBasePath, 'static/configvis'); + globals.logger.info(`CONFIG VIS: Serving static files from ${htmlDir}`); + + await configVisServer.register(FastifyStatic, { + root: htmlDir, + constraints: {}, // optional: default {}. Example: { host: 'example.com' } + redirect: true, // Redirect to trailing '/' when the pathname is a dir + }); + + configVisServer.get('/', async (request, reply) => { + // Obfuscate the config object before sending it to the client + // First get clean copy of the config object + let newConfig = JSON.parse(JSON.stringify(globals.config)); + + if (globals.config.get('Butler-SOS.configVisualisation.obfuscate')) { + // Obfuscate config file before presenting it to the user + // This is done to avoid leaking sensitive information + // to users who should not have access to it. + // The obfuscation is done by replacing parts of the + // config file with masked strings. + newConfig = configObfuscate(newConfig); + } + + // Convert the (potentially obfuscated) config object to YAML format (=string) + const butlerConfigYaml = yaml.dump(newConfig); + + // Read index.html from disk + // dirname points to the directory where this file (app.js) is located, taking into account + // if the app is running as a packaged app or as a Node.js app. + globals.logger.verbose(`----------------3: ${globals.appBasePath}`); + const filePath = path.resolve(globals.appBasePath, 'static/configvis', 'index.html'); + const template = fs.readFileSync(filePath, 'utf8'); + + // Compile handlebars template + const compiledTemplate = handlebars.compile(template); + + // Get config as HTML encoded JSON string + const butlerConfigJsonEncoded = JSON.stringify(newConfig); + + // Render the template + const renderedText = compiledTemplate({ butlerConfigJsonEncoded, butlerConfigYaml }); + + globals.logger.debug(`CONFIG VIS: Rendered text: ${renderedText}`); + + // Send reply as HTML + reply.code(200).header('Content-Type', 'text/html; charset=utf-8').send(renderedText); + }); + + configVisServer.listen( + { + host: globals.config.get('Butler-SOS.configVisualisation.host'), + port: globals.config.get('Butler-SOS.configVisualisation.port'), + }, + (err, address) => { + if (err) { + globals.logger.error(`CONFIG VIS: Could not set up config visualisation server on ${address}`); + globals.logger.error(`CONFIG VIS: ${err.stack}`); + configVisServer.log.error(err); + process.exit(1); + } + globals.logger.info(`CONFIG VIS: Config visualisation server listening on ${address}`); + + configVisServer.ready((err2) => { + if (err2) throw err; + }); + }, + ); + } catch (err) { + globals.logger.error(`CONFIG VIS: Error setting up config visualisation server: ${err.message}`); + if (err.stack) { + globals.logger.error(`CONFIG VIS: ${err.stack}`); + } + throw err; + } +} + diff --git a/src/plugins/README.md b/src/plugins/README.md new file mode 100644 index 00000000..7d8136d6 --- /dev/null +++ b/src/plugins/README.md @@ -0,0 +1,16 @@ +# Plugins Folder + +Plugins define behavior that is common to all the routes in your +application. Authentication, caching, templates, and all the other cross +cutting concerns should be handled by plugins placed in this folder. + +Files in this folder are typically defined through the +[`fastify-plugin`](/~https://github.com/fastify/fastify-plugin) module, +making them non-encapsulated. They can define decorators and set hooks +that will then be used in the rest of your application. + +Check out: + +- [The hitchhiker's guide to plugins](https://www.fastify.io/docs/latest/Plugins-Guide/) +- [Fastify decorators](https://www.fastify.io/docs/latest/Decorators/). +- [Fastify lifecycle](https://www.fastify.io/docs/latest/Lifecycle/). diff --git a/src/plugins/sensible.js b/src/plugins/sensible.js new file mode 100644 index 00000000..a9535b2f --- /dev/null +++ b/src/plugins/sensible.js @@ -0,0 +1,14 @@ +import fp from 'fastify-plugin'; + +/** + * This plugins adds some utilities to handle http errors + * + * @see /~https://github.com/fastify/fastify-sensible + */ +// eslint-disable-next-line no-unused-vars +export default fp(async (fastify, _opts) => { + // eslint-disable-next-line global-require + await fastify.register(import('@fastify/sensible'), { + errorHandler: false, + }); +}); diff --git a/src/plugins/support.js b/src/plugins/support.js new file mode 100644 index 00000000..373fca62 --- /dev/null +++ b/src/plugins/support.js @@ -0,0 +1,12 @@ +import fp from 'fastify-plugin'; + +// the use of fastify-plugin is required to be able +// to export the decorators to the outer scope + +// eslint-disable-next-line no-unused-vars +export default fp(async (fastify, _opts) => { + // eslint-disable-next-line arrow-body-style + fastify.decorate('someSupport', () => { + return 'hugs'; + }); +}); diff --git a/static/configvis/butler.png b/static/configvis/butler.png new file mode 100644 index 00000000..5ecc6944 Binary files /dev/null and b/static/configvis/butler.png differ diff --git a/static/configvis/download-solid.svg b/static/configvis/download-solid.svg new file mode 100644 index 00000000..34fdf86d --- /dev/null +++ b/static/configvis/download-solid.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/static/configvis/index.html b/static/configvis/index.html new file mode 100644 index 00000000..7aba1a49 --- /dev/null +++ b/static/configvis/index.html @@ -0,0 +1,245 @@ + + + + + Ctrl-Q + + + + + + + + + + + + + + + + +
+

YAML configuration

+
{{butlerConfigYaml}}
+
+ +
+

JSON tree view

+
+ Your HTML. +
+
+ + + + diff --git a/static/configvis/jsontree.js b/static/configvis/jsontree.js new file mode 100644 index 00000000..cc09af64 --- /dev/null +++ b/static/configvis/jsontree.js @@ -0,0 +1,927 @@ +'use strict'; + +var Is; + +((e) => { + function t(e) { + return e !== null && e !== void 0 && e.toString() !== ''; + } + e.defined = t; + function n(e) { + return t(e) && typeof e === 'object'; + } + e.definedObject = n; + function r(e) { + return t(e) && typeof e === 'boolean'; + } + e.definedBoolean = r; + function o(e) { + return t(e) && typeof e === 'string'; + } + e.definedString = o; + function l(e) { + return t(e) && typeof e === 'function'; + } + e.definedFunction = l; + function a(e) { + return t(e) && typeof e === 'number'; + } + e.definedNumber = a; + function i(e) { + return n(e) && e instanceof Array; + } + e.definedArray = i; + function s(e) { + return n(e) && e instanceof Date; + } + e.definedDate = s; + function u(e) { + return t(e) && typeof e === 'number' && e % 1 !== 0; + } + e.definedDecimal = u; + function c(e, t = 1) { + return !i(e) || e.length < t; + } + e.invalidOptionArray = c; + function d(e) { + let t = e.length >= 2 && e.length <= 7; + if (t && e[0] === '#') { + t = isNaN(+e.substring(1, e.length - 1)); + } + return t; + } + e.hexColor = d; +})(Is || (Is = {})); + +var Default; + +((e) => { + function t(e, t) { + return typeof e === 'string' ? e : t; + } + e.getAnyString = t; + function n(e, t) { + return Is.definedString(e) ? e : t; + } + e.getString = n; + function r(e, t) { + return Is.definedBoolean(e) ? e : t; + } + e.getBoolean = r; + function o(e, t) { + return Is.definedNumber(e) ? e : t; + } + e.getNumber = o; + function l(e, t) { + return Is.definedFunction(e) ? e : t; + } + e.getFunction = l; + function a(e, t) { + return Is.definedArray(e) ? e : t; + } + e.getArray = a; + function i(e, t) { + return Is.definedObject(e) ? e : t; + } + e.getObject = i; + function s(e, t) { + let n = t; + if (Is.definedString(e)) { + const r = e.toString().split(' '); + if (r.length === 0) { + e = t; + } else { + n = r; + } + } else { + n = a(e, t); + } + return n; + } + e.getStringOrArray = s; + function u(e, t) { + var n; + const r = new RegExp(`^-?\\d+(?:.\\d{0,${t || -1}})?`); + return ((n = e.toString().match(r)) == null ? void 0 : n[0]) || ''; + } + e.getFixedDecimalPlacesValue = u; + function c(e) { + let t; + const n = e.toString().split('('); + const r = n[0].split(' '); + if (r.length === 2) { + t = r[1]; + } else { + t = r[0]; + } + t += '()'; + return t; + } + e.getFunctionName = c; +})(Default || (Default = {})); + +var DomElement; + +((e) => { + function t(e, t, n = '', r = null) { + const o = t.toLowerCase(); + const l = o === 'text'; + let a = l ? document.createTextNode('') : document.createElement(o); + if (Is.defined(n)) { + a.className = n; + } + if (Is.defined(r)) { + e.insertBefore(a, r); + } else { + e.appendChild(a); + } + return a; + } + e.create = t; + function n(e, n, r, o, l = null) { + const a = t(e, n, r, l); + a.innerHTML = o; + return a; + } + e.createWithHTML = n; + function r(e, t) { + e.classList.add(t); + } + e.addClass = r; +})(DomElement || (DomElement = {})); + +var Str; + +((e) => { + function t() { + const e = []; + for (let t = 0; t < 32; t++) { + if (t === 8 || t === 12 || t === 16 || t === 20) { + e.push('-'); + } + const n = Math.floor(Math.random() * 16).toString(16); + e.push(n); + } + return e.join(''); + } + e.newGuid = t; + function n(e, t = 1) { + const n = e.toString(); + let r = n; + if (n.length < t) { + const e = t - n.length + 1; + r = Array(e).join('0') + n; + } + return r; + } + e.padNumber = n; +})(Str || (Str = {})); + +var DateTime; + +((e) => { + function t(e) { + return e.getDay() - 1 < 0 ? 6 : e.getDay() - 1; + } + e.getWeekdayNumber = t; + function n(e, t) { + let n = e.text.thText; + if (t === 31 || t === 21 || t === 1) { + n = e.text.stText; + } else if (t === 22 || t === 2) { + n = e.text.ndText; + } else if (t === 23 || t === 3) { + n = e.text.rdText; + } + return n; + } + e.getDayOrdinal = n; + function r(e, r, o) { + let l = o; + const a = t(r); + l = l.replace('{hh}', Str.padNumber(r.getHours(), 2)); + l = l.replace('{h}', r.getHours().toString()); + l = l.replace('{MM}', Str.padNumber(r.getMinutes(), 2)); + l = l.replace('{M}', r.getMinutes().toString()); + l = l.replace('{ss}', Str.padNumber(r.getSeconds(), 2)); + l = l.replace('{s}', r.getSeconds().toString()); + l = l.replace('{dddd}', e.text.dayNames[a]); + l = l.replace('{ddd}', e.text.dayNamesAbbreviated[a]); + l = l.replace('{dd}', Str.padNumber(r.getDate())); + l = l.replace('{d}', r.getDate().toString()); + l = l.replace('{o}', n(e, r.getDate())); + l = l.replace('{mmmm}', e.text.monthNames[r.getMonth()]); + l = l.replace('{mmm}', e.text.monthNamesAbbreviated[r.getMonth()]); + l = l.replace('{mm}', Str.padNumber(r.getMonth() + 1)); + l = l.replace('{m}', (r.getMonth() + 1).toString()); + l = l.replace('{yyyy}', r.getFullYear().toString()); + l = l.replace('{yyy}', r.getFullYear().toString().substring(1)); + l = l.replace('{yy}', r.getFullYear().toString().substring(2)); + l = l.replace('{y}', Number.parseInt(r.getFullYear().toString().substring(2)).toString()); + return l; + } + e.getCustomFormattedDateText = r; +})(DateTime || (DateTime = {})); + +var Constants; + +((e) => { + e.JSONTREE_JS_ATTRIBUTE_NAME = 'data-jsontree-js'; +})(Constants || (Constants = {})); + +var Binding; + +((e) => { + let t; + ((t) => { + function n(t, n) { + const r = e.Options.get(t); + r._currentView = {}; + r._currentView.element = n; + r._currentView.dataArrayCurrentIndex = 0; + return r; + } + t.getForNewInstance = n; + function r(e) { + let t = Default.getObject(e, {}); + t.data = Default.getObject(t.data, null); + t.showCounts = Default.getBoolean(t.showCounts, true); + t.useZeroIndexingForArrays = Default.getBoolean(t.useZeroIndexingForArrays, true); + t.dateTimeFormat = Default.getString(t.dateTimeFormat, '{dd}{o} {mmmm} {yyyy} {hh}:{MM}:{ss}'); + t.showArrowToggles = Default.getBoolean(t.showArrowToggles, true); + t.showStringQuotes = Default.getBoolean(t.showStringQuotes, true); + t.showAllAsClosed = Default.getBoolean(t.showAllAsClosed, false); + t.sortPropertyNames = Default.getBoolean(t.sortPropertyNames, true); + t.sortPropertyNamesInAlphabeticalOrder = Default.getBoolean(t.sortPropertyNamesInAlphabeticalOrder, true); + t.showCommas = Default.getBoolean(t.showCommas, false); + t.reverseArrayValues = Default.getBoolean(t.reverseArrayValues, false); + t.addArrayIndexPadding = Default.getBoolean(t.addArrayIndexPadding, false); + t.showValueColors = Default.getBoolean(t.showValueColors, true); + t.maximumDecimalPlaces = Default.getNumber(t.maximumDecimalPlaces, 2); + t.maximumStringLength = Default.getNumber(t.maximumStringLength, 0); + t.showStringHexColors = Default.getBoolean(t.showStringHexColors, false); + t.showArrayItemsAsSeparateObjects = Default.getBoolean(t.showArrayItemsAsSeparateObjects, false); + t.copyOnlyCurrentPage = Default.getBoolean(t.copyOnlyCurrentPage, false); + t = o(t); + t = l(t); + t = a(t); + return t; + } + t.get = r; + function o(e) { + e.title = Default.getObject(e.title, {}); + e.title.text = Default.getString(e.title.text, 'JsonTree.js'); + e.title.show = Default.getBoolean(e.title.show, true); + e.title.showTreeControls = Default.getBoolean(e.title.showTreeControls, true); + e.title.showCopyButton = Default.getBoolean(e.title.showCopyButton, true); + return e; + } + function l(e) { + e.ignore = Default.getObject(e.ignore, {}); + e.ignore.nullValues = Default.getBoolean(e.ignore.nullValues, false); + e.ignore.functionValues = Default.getBoolean(e.ignore.functionValues, false); + e.ignore.unknownValues = Default.getBoolean(e.ignore.unknownValues, false); + e.ignore.booleanValues = Default.getBoolean(e.ignore.booleanValues, false); + e.ignore.decimalValues = Default.getBoolean(e.ignore.decimalValues, false); + e.ignore.numberValues = Default.getBoolean(e.ignore.numberValues, false); + e.ignore.stringValues = Default.getBoolean(e.ignore.stringValues, false); + e.ignore.dateValues = Default.getBoolean(e.ignore.dateValues, false); + e.ignore.objectValues = Default.getBoolean(e.ignore.objectValues, false); + e.ignore.arrayValues = Default.getBoolean(e.ignore.arrayValues, false); + return e; + } + function a(e) { + e.events = Default.getObject(e.events, {}); + e.events.onBeforeRender = Default.getFunction(e.events.onBeforeRender, null); + e.events.onRenderComplete = Default.getFunction(e.events.onRenderComplete, null); + e.events.onValueClick = Default.getFunction(e.events.onValueClick, null); + e.events.onRefresh = Default.getFunction(e.events.onRefresh, null); + e.events.onCopyAll = Default.getFunction(e.events.onCopyAll, null); + e.events.onOpenAll = Default.getFunction(e.events.onOpenAll, null); + e.events.onCloseAll = Default.getFunction(e.events.onCloseAll, null); + e.events.onDestroy = Default.getFunction(e.events.onDestroy, null); + e.events.onBooleanRender = Default.getFunction(e.events.onBooleanRender, null); + e.events.onDecimalRender = Default.getFunction(e.events.onDecimalRender, null); + e.events.onNumberRender = Default.getFunction(e.events.onNumberRender, null); + e.events.onStringRender = Default.getFunction(e.events.onStringRender, null); + e.events.onDateRender = Default.getFunction(e.events.onDateRender, null); + e.events.onFunctionRender = Default.getFunction(e.events.onFunctionRender, null); + e.events.onNullRender = Default.getFunction(e.events.onNullRender, null); + e.events.onUnknownRender = Default.getFunction(e.events.onUnknownRender, null); + return e; + } + })((t = e.Options || (e.Options = {}))); +})(Binding || (Binding = {})); + +var Config; + +((e) => { + let t; + ((e) => { + function t(e = null) { + let t = Default.getObject(e, {}); + t.safeMode = Default.getBoolean(t.safeMode, true); + t.domElementTypes = Default.getStringOrArray(t.domElementTypes, ['*']); + t = n(t); + return t; + } + e.get = t; + function n(e) { + e.text = Default.getObject(e.text, {}); + e.text.objectText = Default.getAnyString(e.text.objectText, 'object'); + e.text.arrayText = Default.getAnyString(e.text.arrayText, 'array'); + e.text.closeAllButtonText = Default.getAnyString(e.text.closeAllButtonText, 'Close All'); + e.text.openAllButtonText = Default.getAnyString(e.text.openAllButtonText, 'Open All'); + e.text.copyAllButtonText = Default.getAnyString(e.text.copyAllButtonText, 'Copy All'); + e.text.objectErrorText = Default.getAnyString(e.text.objectErrorText, 'Errors in object: {{error_1}}, {{error_2}}'); + e.text.attributeNotValidErrorText = Default.getAnyString( + e.text.attributeNotValidErrorText, + "The attribute '{{attribute_name}}' is not a valid object.", + ); + e.text.attributeNotSetErrorText = Default.getAnyString( + e.text.attributeNotSetErrorText, + "The attribute '{{attribute_name}}' has not been set correctly.", + ); + e.text.stText = Default.getAnyString(e.text.stText, 'st'); + e.text.ndText = Default.getAnyString(e.text.ndText, 'nd'); + e.text.rdText = Default.getAnyString(e.text.rdText, 'rd'); + e.text.thText = Default.getAnyString(e.text.thText, 'th'); + e.text.ellipsisText = Default.getAnyString(e.text.ellipsisText, '...'); + e.text.closeAllButtonSymbolText = Default.getAnyString(e.text.closeAllButtonSymbolText, '↑'); + e.text.openAllButtonSymbolText = Default.getAnyString(e.text.openAllButtonSymbolText, '↓'); + e.text.copyAllButtonSymbolText = Default.getAnyString(e.text.copyAllButtonSymbolText, '❐'); + e.text.backButtonText = Default.getAnyString(e.text.backButtonText, 'Back'); + e.text.nextButtonText = Default.getAnyString(e.text.nextButtonText, 'Next'); + e.text.backButtonSymbolText = Default.getAnyString(e.text.backButtonSymbolText, '←'); + e.text.nextButtonSymbolText = Default.getAnyString(e.text.nextButtonSymbolText, '→'); + if (Is.invalidOptionArray(e.text.dayNames, 7)) { + e.text.dayNames = ['Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday', 'Sunday']; + } + if (Is.invalidOptionArray(e.text.dayNamesAbbreviated, 7)) { + e.text.dayNamesAbbreviated = ['Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun']; + } + if (Is.invalidOptionArray(e.text.monthNames, 12)) { + e.text.monthNames = [ + 'January', + 'February', + 'March', + 'April', + 'May', + 'June', + 'July', + 'August', + 'September', + 'October', + 'November', + 'December', + ]; + } + if (Is.invalidOptionArray(e.text.monthNamesAbbreviated, 12)) { + e.text.monthNamesAbbreviated = ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec']; + } + return e; + } + })((t = e.Options || (e.Options = {}))); +})(Config || (Config = {})); + +var Trigger; + +((e) => { + function t(e, ...t) { + let n = null; + if (Is.definedFunction(e)) { + n = e.apply(null, [].slice.call(t, 0)); + } + return n; + } + e.customEvent = t; +})(Trigger || (Trigger = {})); + +(() => { + let _configuration = {}; + let _elements_Data = {}; + function render() { + const e = _configuration.domElementTypes; + const t = e.length; + for (let n = 0; n < t; n++) { + const t = document.getElementsByTagName(e[n]); + const r = [].slice.call(t); + const o = r.length; + for (let e = 0; e < o; e++) { + if (!renderElement(r[e])) { + break; + } + } + } + } + function renderElement(e) { + let t = true; + if (Is.defined(e) && e.hasAttribute(Constants.JSONTREE_JS_ATTRIBUTE_NAME)) { + const n = e.getAttribute(Constants.JSONTREE_JS_ATTRIBUTE_NAME); + if (Is.definedString(n)) { + const r = getObjectFromString(n); + if (r.parsed && Is.definedObject(r.object)) { + renderControl(Binding.Options.getForNewInstance(r.object, e)); + } else { + if (!_configuration.safeMode) { + console.error( + _configuration.text.attributeNotValidErrorText.replace( + '{{attribute_name}}', + Constants.JSONTREE_JS_ATTRIBUTE_NAME, + ), + ); + t = false; + } + } + } else { + if (!_configuration.safeMode) { + console.error( + _configuration.text.attributeNotSetErrorText.replace('{{attribute_name}}', Constants.JSONTREE_JS_ATTRIBUTE_NAME), + ); + t = false; + } + } + } + return t; + } + function renderControl(e) { + Trigger.customEvent(e.events.onBeforeRender, e._currentView.element); + if (!Is.definedString(e._currentView.element.id)) { + e._currentView.element.id = Str.newGuid(); + } + e._currentView.element.className = 'json-tree-js'; + e._currentView.element.removeAttribute(Constants.JSONTREE_JS_ATTRIBUTE_NAME); + if (!_elements_Data.hasOwnProperty(e._currentView.element.id)) { + _elements_Data[e._currentView.element.id] = e; + } + renderControlContainer(e); + Trigger.customEvent(e.events.onRenderComplete, e._currentView.element); + } + function renderControlContainer(e) { + let t = _elements_Data[e._currentView.element.id].data; + e._currentView.element.innerHTML = ''; + renderControlTitleBar(e, t); + if (e.showArrayItemsAsSeparateObjects) { + t = t[e._currentView.dataArrayCurrentIndex]; + } + if (Is.definedObject(t) && !Is.definedArray(t)) { + renderObject(e._currentView.element, e, t, true); + } else if (Is.definedArray(t)) { + renderArray(e._currentView.element, e, t); + } + } + function renderControlTitleBar(e, t) { + if (e.title.show || e.title.showTreeControls || e.title.showCopyButton) { + const n = DomElement.create(e._currentView.element, 'div', 'title-bar'); + const r = DomElement.create(n, 'div', 'controls'); + if (e.title.show) { + DomElement.createWithHTML(n, 'div', 'title', e.title.text, r); + } + if (e.title.showCopyButton) { + const t = DomElement.createWithHTML(r, 'button', 'copy-all', _configuration.text.copyAllButtonSymbolText); + t.title = _configuration.text.copyAllButtonText; + t.onclick = () => { + let t = null; + if (e.copyOnlyCurrentPage && e.showArrayItemsAsSeparateObjects) { + t = JSON.stringify(_elements_Data[e._currentView.element.id].data[e._currentView.dataArrayCurrentIndex], null, 2); + } else { + t = JSON.stringify(_elements_Data[e._currentView.element.id].data, null, 2); + } + navigator.clipboard.writeText(t); + Trigger.customEvent(e.events.onCopyAll, t); + }; + } + if (e.title.showTreeControls) { + const t = DomElement.createWithHTML(r, 'button', 'openAll', _configuration.text.openAllButtonSymbolText); + t.title = _configuration.text.openAllButtonText; + const n = DomElement.createWithHTML(r, 'button', 'closeAll', _configuration.text.closeAllButtonSymbolText); + n.title = _configuration.text.closeAllButtonText; + t.onclick = () => { + openAllNodes(e); + }; + n.onclick = () => { + closeAllNodes(e); + }; + } + if (e.showArrayItemsAsSeparateObjects && Is.definedArray(t) && t.length > 1) { + const n = DomElement.createWithHTML(r, 'button', 'back', _configuration.text.backButtonSymbolText); + n.title = _configuration.text.backButtonText; + if (e._currentView.dataArrayCurrentIndex > 0) { + n.onclick = () => { + e._currentView.dataArrayCurrentIndex--; + renderControlContainer(e); + }; + } else { + n.disabled = true; + } + const o = DomElement.createWithHTML(r, 'button', 'next', _configuration.text.nextButtonSymbolText); + o.title = _configuration.text.nextButtonText; + if (e._currentView.dataArrayCurrentIndex < t.length - 1) { + o.onclick = () => { + e._currentView.dataArrayCurrentIndex++; + renderControlContainer(e); + }; + } else { + o.disabled = true; + } + } else { + e.showArrayItemsAsSeparateObjects = false; + } + } + } + function openAllNodes(e) { + e.showAllAsClosed = false; + renderControlContainer(e); + Trigger.customEvent(e.events.onOpenAll, e._currentView.element); + } + function closeAllNodes(e) { + e.showAllAsClosed = true; + renderControlContainer(e); + Trigger.customEvent(e.events.onCloseAll, e._currentView.element); + } + function renderObject(e, t, n, r = false) { + const o = DomElement.create(e, 'div', 'object-type-title'); + const l = DomElement.create(e, 'div', 'object-type-contents'); + const a = t.showArrowToggles ? DomElement.create(o, 'div', 'down-arrow') : null; + const i = renderObjectValues(a, l, t, n); + const s = DomElement.createWithHTML(o, 'span', t.showValueColors ? 'object' : '', _configuration.text.objectText); + if (r && t.showArrayItemsAsSeparateObjects) { + let e = t.useZeroIndexingForArrays + ? t._currentView.dataArrayCurrentIndex.toString() + : (t._currentView.dataArrayCurrentIndex + 1).toString(); + DomElement.createWithHTML(o, 'span', t.showValueColors ? 'object data-array-index' : 'data-array-index', `[${e}]:`, s); + } + if (t.showCounts && i > 0) { + DomElement.createWithHTML(o, 'span', t.showValueColors ? 'object count' : 'count', `{${i}}`); + } + } + function renderArray(e, t, n) { + const r = DomElement.create(e, 'div', 'object-type-title'); + const o = DomElement.create(e, 'div', 'object-type-contents'); + const l = t.showArrowToggles ? DomElement.create(r, 'div', 'down-arrow') : null; + DomElement.createWithHTML(r, 'span', t.showValueColors ? 'array' : '', _configuration.text.arrayText); + renderArrayValues(l, o, t, n); + if (t.showCounts) { + DomElement.createWithHTML(r, 'span', t.showValueColors ? 'array count' : 'count', `[${n.length}]`); + } + } + function renderObjectValues(e, t, n, r) { + let o = 0; + let l = []; + for (let e in r) { + if (r.hasOwnProperty(e)) { + l.push(e); + } + } + if (n.sortPropertyNames) { + l = l.sort(); + if (!n.sortPropertyNamesInAlphabeticalOrder) { + l = l.reverse(); + } + } + const a = l.length; + for (let e = 0; e < a; e++) { + const i = l[e]; + if (r.hasOwnProperty(i)) { + renderValue(t, n, i, r[i], e === a - 1); + o++; + } + } + addArrowEvent(n, e, t); + return o; + } + function renderArrayValues(e, t, n, r) { + const o = r.length; + if (!n.reverseArrayValues) { + for (let e = 0; e < o; e++) { + renderValue(t, n, getIndexName(n, e, o), r[e], e === o - 1); + } + } else { + for (let e = o; e--; ) { + renderValue(t, n, getIndexName(n, e, o), r[e], e === 0); + } + } + addArrowEvent(n, e, t); + } + function renderValue(e, t, n, r, o) { + const l = DomElement.create(e, 'div', 'object-type-value'); + const a = t.showArrowToggles ? DomElement.create(l, 'div', 'no-arrow') : null; + let i = null; + let s = null; + let u = false; + let c = null; + let d = true; + DomElement.createWithHTML(l, 'span', 'title', n); + DomElement.createWithHTML(l, 'span', 'split', ':'); + if (!Is.defined(r)) { + if (!t.ignore.nullValues) { + i = t.showValueColors ? 'null' : ''; + s = DomElement.createWithHTML(l, 'span', i, 'null'); + d = false; + if (Is.definedFunction(t.events.onNullRender)) { + Trigger.customEvent(t.events.onNullRender, s); + } + createComma(t, l, o); + } else { + u = true; + } + } else if (Is.definedFunction(r)) { + if (!t.ignore.functionValues) { + i = t.showValueColors ? 'function' : ''; + s = DomElement.createWithHTML(l, 'span', i, Default.getFunctionName(r)); + c = 'function'; + if (Is.definedFunction(t.events.onFunctionRender)) { + Trigger.customEvent(t.events.onFunctionRender, s); + } + createComma(t, l, o); + } else { + u = true; + } + } else if (Is.definedBoolean(r)) { + if (!t.ignore.booleanValues) { + i = t.showValueColors ? 'boolean' : ''; + s = DomElement.createWithHTML(l, 'span', i, r); + c = 'boolean'; + if (Is.definedFunction(t.events.onBooleanRender)) { + Trigger.customEvent(t.events.onBooleanRender, s); + } + createComma(t, l, o); + } else { + u = true; + } + } else if (Is.definedDecimal(r)) { + if (!t.ignore.decimalValues) { + const e = Default.getFixedDecimalPlacesValue(r, t.maximumDecimalPlaces); + i = t.showValueColors ? 'decimal' : ''; + s = DomElement.createWithHTML(l, 'span', i, e); + c = 'decimal'; + if (Is.definedFunction(t.events.onDecimalRender)) { + Trigger.customEvent(t.events.onDecimalRender, s); + } + createComma(t, l, o); + } else { + u = true; + } + } else if (Is.definedNumber(r)) { + if (!t.ignore.numberValues) { + i = t.showValueColors ? 'number' : ''; + s = DomElement.createWithHTML(l, 'span', i, r); + c = 'number'; + if (Is.definedFunction(t.events.onNumberRender)) { + Trigger.customEvent(t.events.onNumberRender, s); + } + createComma(t, l, o); + } else { + u = true; + } + } else if (Is.definedString(r)) { + if (!t.ignore.stringValues) { + let e = null; + if (t.showValueColors && t.showStringHexColors && Is.hexColor(r)) { + e = r; + } else { + if (t.maximumStringLength > 0 && r.length > t.maximumStringLength) { + r = r.substring(0, t.maximumStringLength) + _configuration.text.ellipsisText; + } + } + const n = t.showStringQuotes ? `"${r}"` : r; + i = t.showValueColors ? 'string' : ''; + s = DomElement.createWithHTML(l, 'span', i, n); + c = 'string'; + if (Is.definedString(e)) { + s.style.color = e; + } + if (Is.definedFunction(t.events.onStringRender)) { + Trigger.customEvent(t.events.onStringRender, s); + } + createComma(t, l, o); + } else { + u = true; + } + } else if (Is.definedDate(r)) { + if (!t.ignore.dateValues) { + i = t.showValueColors ? 'date' : ''; + s = DomElement.createWithHTML(l, 'span', i, DateTime.getCustomFormattedDateText(_configuration, r, t.dateTimeFormat)); + c = 'date'; + if (Is.definedFunction(t.events.onDateRender)) { + Trigger.customEvent(t.events.onDateRender, s); + } + createComma(t, l, o); + } else { + u = true; + } + } else if (Is.definedObject(r) && !Is.definedArray(r)) { + if (!t.ignore.objectValues) { + const e = DomElement.create(l, 'span', t.showValueColors ? 'object' : ''); + const n = DomElement.create(l, 'div', 'object-type-contents'); + const i = renderObjectValues(a, n, t, r); + DomElement.createWithHTML(e, 'span', 'title', _configuration.text.objectText); + if (t.showCounts && i > 0) { + DomElement.createWithHTML(e, 'span', 'count', `{${i}}`); + } + createComma(t, e, o); + c = 'object'; + } else { + u = true; + } + } else if (Is.definedArray(r)) { + if (!t.ignore.arrayValues) { + const e = DomElement.create(l, 'span', t.showValueColors ? 'array' : ''); + const n = DomElement.create(l, 'div', 'object-type-contents'); + DomElement.createWithHTML(e, 'span', 'title', _configuration.text.arrayText); + if (t.showCounts) { + DomElement.createWithHTML(e, 'span', 'count', `[${r.length}]`); + } + createComma(t, e, o); + renderArrayValues(a, n, t, r); + c = 'array'; + } else { + u = true; + } + } else { + if (!t.ignore.unknownValues) { + i = t.showValueColors ? 'unknown' : ''; + s = DomElement.createWithHTML(l, 'span', i, r.toString()); + c = 'unknown'; + if (Is.definedFunction(t.events.onUnknownRender)) { + Trigger.customEvent(t.events.onUnknownRender, s); + } + createComma(t, l, o); + } else { + u = true; + } + } + if (u) { + e.removeChild(l); + } else { + if (Is.defined(s)) { + addValueClickEvent(t, s, r, c, d); + } + } + } + function addValueClickEvent(e, t, n, r, o) { + if (o && Is.definedFunction(e.events.onValueClick)) { + t.onclick = () => { + Trigger.customEvent(e.events.onValueClick, n, r); + }; + } else { + DomElement.addClass(t, 'no-hover'); + } + } + function addArrowEvent(e, t, n) { + if (Is.defined(t)) { + t.onclick = () => { + if (t.className === 'down-arrow') { + n.style.display = 'none'; + t.className = 'right-arrow'; + } else { + n.style.display = 'block'; + t.className = 'down-arrow'; + } + }; + if (e.showAllAsClosed) { + n.style.display = 'none'; + t.className = 'right-arrow'; + } else { + t.className = 'down-arrow'; + } + } + } + function createComma(e, t, n) { + if (e.showCommas && !n) { + DomElement.createWithHTML(t, 'span', 'comma', ','); + } + } + function getIndexName(e, t, n) { + let r = e.useZeroIndexingForArrays ? t.toString() : (t + 1).toString(); + if (!e.addArrayIndexPadding) { + r = Str.padNumber(parseInt(r), n.toString().length); + } + return `[${r}]`; + } + function getObjectFromString(objectString) { + const result = { + parsed: true, + object: null, + }; + try { + if (Is.definedString(objectString)) { + result.object = JSON.parse(objectString); + } + } catch (e1) { + try { + result.object = eval(`(${objectString})`); + if (Is.definedFunction(result.object)) { + result.object = result.object(); + } + } catch (e) { + if (!_configuration.safeMode) { + console.error(_configuration.text.objectErrorText.replace('{{error_1}}', e1.message).replace('{{error_2}}', e.message)); + result.parsed = false; + } + result.object = null; + } + } + return result; + } + function destroyElement(e) { + e._currentView.element.innerHTML = ''; + e._currentView.element.className = ''; + Trigger.customEvent(e.events.onDestroy, e._currentView.element); + } + const _public = { + refresh: function (e) { + if (Is.definedString(e) && _elements_Data.hasOwnProperty(e)) { + const t = _elements_Data[e]; + renderControlContainer(t); + Trigger.customEvent(t.events.onRefresh, t._currentView.element); + } + return _public; + }, + refreshAll: function () { + for (let e in _elements_Data) { + if (_elements_Data.hasOwnProperty(e)) { + const t = _elements_Data[e]; + renderControlContainer(t); + Trigger.customEvent(t.events.onRefresh, t._currentView.element); + } + } + return _public; + }, + render: function (e, t) { + if (Is.definedObject(e) && Is.definedObject(t)) { + renderControl(Binding.Options.getForNewInstance(t, e)); + } + return _public; + }, + renderAll: function () { + render(); + return _public; + }, + openAll: function (e) { + if (Is.definedString(e) && _elements_Data.hasOwnProperty(e)) { + openAllNodes(_elements_Data[e]); + } + return _public; + }, + closeAll: function (e) { + if (Is.definedString(e) && _elements_Data.hasOwnProperty(e)) { + closeAllNodes(_elements_Data[e]); + } + return _public; + }, + destroy: function (e) { + if (Is.definedString(e) && _elements_Data.hasOwnProperty(e)) { + destroyElement(_elements_Data[e]); + delete _elements_Data[e]; + } + return _public; + }, + destroyAll: function () { + for (let e in _elements_Data) { + if (_elements_Data.hasOwnProperty(e)) { + destroyElement(_elements_Data[e]); + } + } + _elements_Data = {}; + return _public; + }, + setConfiguration: function (e) { + if (Is.definedObject(e)) { + let t = false; + const n = _configuration; + for (let r in e) { + if (e.hasOwnProperty(r) && _configuration.hasOwnProperty(r) && n[r] !== e[r]) { + n[r] = e[r]; + t = true; + } + } + if (t) { + _configuration = Config.Options.get(n); + } + } + return _public; + }, + getIds: function () { + const e = []; + for (let t in _elements_Data) { + if (_elements_Data.hasOwnProperty(t)) { + e.push(t); + } + } + return e; + }, + getVersion: function () { + return '2.1.0'; + }, + }; + (() => { + _configuration = Config.Options.get(); + document.addEventListener('DOMContentLoaded', function () { + render(); + }); + if (!Is.defined(window.$jsontree)) { + window.$jsontree = _public; + } + })(); +})(); //# sourceMappingURL=jsontree.js.map diff --git a/static/configvis/jsontree.js.css b/static/configvis/jsontree.js.css new file mode 100644 index 00000000..f3d4d3d4 --- /dev/null +++ b/static/configvis/jsontree.js.css @@ -0,0 +1,330 @@ +/* + * JsonTree.js Library v2.1.0 + * + * Copyright 2024 Bunoon + * Released under the MIT License + */ +:root { + --json-tree-js-default-font: system-ui, -apple-system, 'Segoe UI', Roboto, 'Helvetica Neue', 'Noto Sans', 'Liberation Sans', Arial, + sans-serif, 'Apple Color Emoji', 'Segoe UI Emoji', 'Segoe UI Symbol', 'Noto Color Emoji'; + --json-tree-js-text-bold-weight: 400; + --json-tree-js-header-bold-weight: 900; + --json-tree-js-title-bold-weight: var(--json-tree-js-header-bold-weight); + --json-tree-js-text-bold-weight-active: var(--json-tree-js-header-bold-weight); + --json-tree-js-color-black: #3b3a3a; + --json-tree-js-color-white: #f5f5f5; + --json-tree-js-color-snow-white: #f5f5f5; + --json-tree-js-color-boolean: #ff0000; + --json-tree-js-color-decimal: #e3c868; + --json-tree-js-color-number: #666bf9; + --json-tree-js-color-string: #78b13f; + --json-tree-js-color-date: #a656f5; + --json-tree-js-color-array: #f28c28; + --json-tree-js-color-object: #c0c0c0; + --json-tree-js-color-null: #bbbbbb; + --json-tree-js-color-function: var(--json-tree-js-color-null); + --json-tree-js-color-unknown: var(--json-tree-js-color-null); + --json-tree-js-container-background-color: #22272e; + --json-tree-js-container-border-color: #454c56; + --json-tree-js-button-background-color: #2d333b; + --json-tree-js-button-border-color: var(--json-tree-js-container-border-color); + --json-tree-js-button-text-color: var(--json-tree-js-color-white); + --json-tree-js-button-background-color-hover: var(--json-tree-js-container-border-color); + --json-tree-js-button-text-color-hover: var(--json-tree-js-color-snow-white); + --json-tree-js-button-background-color-active: #616b79; + --json-tree-js-button-text-color-active: var(--json-tree-js-color-snow-white); + --json-tree-js-border-radius: 0.5rem; + --json-tree-js-border-style-scrollbar: inset 0 0 6px var(--json-tree-js-color-dark-gray); + --json-tree-js-border-size: 0.5px; + --json-tree-js-spacing: 10px; + --json-tree-js-spacing-font-size: 0.85rem; + --json-tree-js-transition: all 0.3s; +} + +/* + ------------------------------------------------------------------------- + JsonTree.js - Container + ------------------------------------------------------------------------- +*/ +div.json-tree-js { + -moz-user-select: none; + -webkit-user-select: none; + -ms-user-select: none; + -o-user-select: none; + user-select: none; + cursor: default; + box-sizing: border-box; + line-height: normal; + font-family: var(--json-tree-js-default-font) !important; + display: inline-block; + position: relative; + border-radius: var(--json-tree-js-border-radius); + background-color: var(--json-tree-js-container-background-color); + color: var(--json-tree-js-color-white); + border: var(--json-tree-js-border-size) solid var(--json-tree-js-container-border-color); + padding: var(--json-tree-js-spacing); + font-size: var(--json-tree-js-spacing-font-size); + font-weight: var(--json-tree-js-text-bold-weight); + width: auto; + overflow: hidden; + margin: 0 !important; +} +div.json-tree-js button { + font-family: var(--heat-js-default-font); +} +div.json-tree-js div.no-click { + pointer-events: none !important; +} +div.json-tree-js * { + box-sizing: border-box; + line-height: normal; +} +div.json-tree-js *::before, +div.json-tree-js *::after { + box-sizing: border-box; + line-height: normal; +} + +/* + ------------------------------------------------------------------------- + JsonTree.js - Arrows + ------------------------------------------------------------------------- +*/ +div.json-tree-js div.no-arrow { + display: inline-block; + width: 12px; + height: 8px; + margin-right: calc(var(--json-tree-js-spacing)); +} +div.json-tree-js div.down-arrow, +div.json-tree-js div.right-arrow { + display: inline-block; + width: 0; + height: 0; + margin-right: calc(var(--json-tree-js-spacing)); + cursor: pointer; + transition: var(--json-tree-js-transition); + transition-property: opacity; +} +div.json-tree-js div.down-arrow:hover, +div.json-tree-js div.right-arrow:hover { + opacity: 0.7; +} +div.json-tree-js div.down-arrow { + border-left: 6px solid transparent; + border-right: 6px solid transparent; + border-top: 8px solid var(--json-tree-js-color-white); +} +div.json-tree-js div.right-arrow { + border-top: 5px solid transparent; + border-bottom: 5px solid transparent; + border-left: 12px solid var(--json-tree-js-color-white); +} + +/* + ------------------------------------------------------------------------- + JsonTree.js - Title Bar + ------------------------------------------------------------------------- +*/ +div.json-tree-js div.title-bar { + display: flex; + margin-bottom: var(--json-tree-js-spacing); +} +div.json-tree-js div.title-bar div.title { + text-align: left; + width: auto; + font-weight: var(--json-tree-js-title-bold-weight); + font-size: 1.2rem; +} +div.json-tree-js div.title-bar div.controls { + margin-left: calc(var(--json-tree-js-spacing) * 6); + flex-grow: 1; + text-align: right; +} +@media (min-width: 768px) { + div.json-tree-js div.title-bar div.controls { + margin-left: calc(var(--json-tree-js-spacing) * 12); + } +} +div.json-tree-js div.title-bar div.controls button { + background-color: var(--json-tree-js-button-background-color); + border: var(--json-tree-js-border-size) solid var(--json-tree-js-button-border-color); + color: var(--json-tree-js-button-text-color); + border-radius: var(--json-tree-js-border-radius); + padding-top: 5px; + padding-bottom: 5px; + padding-left: 9px; + padding-right: 9px; + outline: none; + transition: var(--json-tree-js-transition); +} +div.json-tree-js div.title-bar div.controls button:disabled { + color: var(--json-tree-js-button-border-color); +} +div.json-tree-js div.title-bar div.controls button:not(.active):not(:disabled):active { + background: var(--json-tree-js-button-background-color-active) !important; + color: var(--json-tree-js-button-text-color-active) !important; +} +div.json-tree-js div.title-bar div.controls button:not(.active):not(:disabled):hover { + cursor: pointer; + background: var(--json-tree-js-button-background-color-hover); + color: var(--json-tree-js-button-text-color-hover); +} +div.json-tree-js div.title-bar div.controls button { + margin-left: calc(var(--json-tree-js-spacing) / 2) !important; +} +div.json-tree-js div.title-bar div.controls button.back { + margin-left: calc(var(--json-tree-js-spacing) * 2) !important; +} +div.json-tree-js div.title-bar div.controls button.copy-all { + display: none; +} +@media (min-width: 768px) { + div.json-tree-js div.title-bar div.controls button.copy-all { + display: inline-block; + } +} + +/* + ------------------------------------------------------------------------- + JsonTree.js - Object Type Title + ------------------------------------------------------------------------- +*/ +div.json-tree-js div.object-type-title { + font-weight: var(--json-tree-js-header-bold-weight); + text-align: left !important; +} +div.json-tree-js div.object-type-title span.array { + color: var(--json-tree-js-color-array); +} +div.json-tree-js div.object-type-title span.object { + color: var(--json-tree-js-color-object); +} +div.json-tree-js div.object-type-title span.count { + margin-left: calc(var(--json-tree-js-spacing) / 2); + font-weight: var(--json-tree-js-text-bold-weight); +} +div.json-tree-js div.object-type-title span.data-array-index { + margin-right: calc(var(--json-tree-js-spacing) / 2); + font-weight: var(--json-tree-js-text-bold-weight); +} + +/* + ------------------------------------------------------------------------- + JsonTree.js - Object Type Contents + ------------------------------------------------------------------------- +*/ +div.json-tree-js div.object-type-contents { + margin-top: calc(var(--json-tree-js-spacing) / 2); +} + +/* + ------------------------------------------------------------------------- + JsonTree.js - Object Type Contents - Values + ------------------------------------------------------------------------- +*/ +div.json-tree-js div.object-type-contents { + margin-left: calc(var(--json-tree-js-spacing) * 2); + text-align: left !important; +} +div.json-tree-js div.object-type-contents div.object-type-value { + white-space: nowrap; + overflow: hidden; + margin-top: calc(var(--json-tree-js-spacing) / 2); + margin-bottom: calc(var(--json-tree-js-spacing) / 2); +} +div.json-tree-js div.object-type-contents div.object-type-value span.split { + margin-left: calc(var(--json-tree-js-spacing) / 2); + margin-right: calc(var(--json-tree-js-spacing) / 2); +} +div.json-tree-js div.object-type-contents div.object-type-value span.boolean, +div.json-tree-js div.object-type-contents div.object-type-value span.decimal, +div.json-tree-js div.object-type-contents div.object-type-value span.number, +div.json-tree-js div.object-type-contents div.object-type-value span.string, +div.json-tree-js div.object-type-contents div.object-type-value span.date, +div.json-tree-js div.object-type-contents div.object-type-value span.null, +div.json-tree-js div.object-type-contents div.object-type-value span.function, +div.json-tree-js div.object-type-contents div.object-type-value span.unknown { + transition: var(--json-tree-js-transition); + transition-property: opacity; +} +div.json-tree-js div.object-type-contents div.object-type-value span.boolean:not(.no-hover):hover, +div.json-tree-js div.object-type-contents div.object-type-value span.decimal:not(.no-hover):hover, +div.json-tree-js div.object-type-contents div.object-type-value span.number:not(.no-hover):hover, +div.json-tree-js div.object-type-contents div.object-type-value span.string:not(.no-hover):hover, +div.json-tree-js div.object-type-contents div.object-type-value span.date:not(.no-hover):hover, +div.json-tree-js div.object-type-contents div.object-type-value span.null:not(.no-hover):hover, +div.json-tree-js div.object-type-contents div.object-type-value span.function:not(.no-hover):hover, +div.json-tree-js div.object-type-contents div.object-type-value span.unknown:not(.no-hover):hover { + cursor: pointer; + opacity: 0.7; +} +div.json-tree-js div.object-type-contents div.object-type-value span.comma { + color: var(--json-tree-js-color-white); + font-weight: var(--json-tree-js-text-bold-weight); +} +div.json-tree-js div.object-type-contents div.object-type-value span.boolean { + color: var(--json-tree-js-color-boolean); +} +div.json-tree-js div.object-type-contents div.object-type-value span.decimal { + color: var(--json-tree-js-color-decimal); +} +div.json-tree-js div.object-type-contents div.object-type-value span.number { + color: var(--json-tree-js-color-number); +} +div.json-tree-js div.object-type-contents div.object-type-value span.string { + color: var(--json-tree-js-color-string); +} +div.json-tree-js div.object-type-contents div.object-type-value span.date { + color: var(--json-tree-js-color-date); +} +div.json-tree-js div.object-type-contents div.object-type-value span.array { + font-weight: var(--json-tree-js-header-bold-weight); + color: var(--json-tree-js-color-array); +} +div.json-tree-js div.object-type-contents div.object-type-value span.object { + font-weight: var(--json-tree-js-header-bold-weight); + color: var(--json-tree-js-color-object); +} +div.json-tree-js div.object-type-contents div.object-type-value span.null { + color: var(--json-tree-js-color-null); + font-style: italic; +} +div.json-tree-js div.object-type-contents div.object-type-value span.function { + color: var(--json-tree-js-color-function); + font-style: italic; +} +div.json-tree-js div.object-type-contents div.object-type-value span.unknown { + color: var(--json-tree-js-color-unknown); + font-style: italic; +} +div.json-tree-js div.object-type-contents div.object-type-value span.count { + margin-left: calc(var(--json-tree-js-spacing) / 2); + font-weight: var(--json-tree-js-text-bold-weight); +} + +/* + ------------------------------------------------------------------------- + JsonTree.js - Custom Scroll Bar + ------------------------------------------------------------------------- +*/ +.custom-scroll-bars::-webkit-scrollbar { + width: 12px; +} +.custom-scroll-bars::-webkit-scrollbar-track { + -webkit-box-shadow: var(--json-tree-js-border-style-scrollbar); + box-shadow: var(--json-tree-js-border-style-scrollbar); +} +.custom-scroll-bars::-webkit-scrollbar-thumb { + -webkit-box-shadow: var(--json-tree-js-border-style-scrollbar); + box-shadow: var(--json-tree-js-border-style-scrollbar); + background: var(--json-tree-js-color-white); +} +.custom-scroll-bars::-webkit-scrollbar-thumb:hover { + background-color: var(--json-tree-js-color-white); +} +.custom-scroll-bars::-webkit-scrollbar-thumb:active { + background-color: var(--json-tree-js-color-lighter-gray); +} + +/*# sourceMappingURL=jsontree.js.css.map */ diff --git a/static/configvis/jsontree.js.css.map b/static/configvis/jsontree.js.css.map new file mode 100644 index 00000000..782f92e0 --- /dev/null +++ b/static/configvis/jsontree.js.css.map @@ -0,0 +1 @@ +{"version":3,"sourceRoot":"","sources":["../src/jsontree.js.scss","../src/sass/_styles.scss"],"names":[],"mappings":"AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAUA;EAEI;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;EAcA;EACA;EACA;EACA;EAGA;EACA;EACA;EAGA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EAGA;EACA;EAGA;EACA;EACA;EACA;EACA;EACA;EACA;EAGA;EACA;EACA;EAGA;EACA;EAGA;;;AAIJ;AAAA;AAAA;AAAA;AAAA;AAMA;EC9EI;EACA;EACA;EACA;EACA;EACA;EAUA;EACA;EDiEA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;;AAEA;EACI;;AAGJ;EACI;;AAGJ;ECxFA;EACA;;AD0FI;EC3FJ;EACA;;;ADkGJ;AAAA;AAAA;AAAA;AAAA;AAOI;EACI;EACA;EACA;EACA;;AAGJ;AAAA;EAEI;EACA;EACA;EACA;EACA;EACA;EACA;;AAEA;AAAA;EACI;;AAIR;EACI;EACA;EACA;;AAGJ;EACI;EACA;EACA;;;AAKR;AAAA;AAAA;AAAA;AAAA;AAOI;EACI;EACA;;AAEA;EACI;EACA;EACA;EACA;;AAGJ;EACI;EACA;EACA;;AAEA;EALJ;IAMQ;;;ACjKZ;EACI;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;;AAEA;EACI;;AAGJ;EACI;EACA;;AAGJ;EACI;EACA;EACA;;AD8IA;EACI;;AAGJ;EACI;;AAGJ;EACI;;AAEA;EAHJ;IAIQ;;;;AAQpB;AAAA;AAAA;AAAA;AAAA;AAOI;EACI;EACA;;AAEA;EACI;;AAGJ;EACI;;AAGJ;EACI;EACA;;AAGJ;EACI;EACA;;;AAKZ;AAAA;AAAA;AAAA;AAAA;AAOI;EACI;;;AAKR;AAAA;AAAA;AAAA;AAAA;AAOI;EACI;EACA;;AAEA;EACI;EACA;EACA;EACA;;AAEA;EACI;EACA;;AAGJ;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;EAQI;EACA;;AAEA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;EACI;EACA;;AAIR;EACI;EACA;;AAGJ;EACI;;AAGJ;EACI;;AAGJ;EACI;;AAGJ;EACI;;AAGJ;EACI;;AAGJ;EACI;EACA;;AAGJ;EACI;EACA;;AAGJ;EACI;EACA;;AAGJ;EACI;EACA;;AAGJ;EACI;EACA;;AAGJ;EACI;EACA;;;AAOhB;AAAA;AAAA;AAAA;AAAA;AAOI;EACI;;AAGJ;EACI;EACA;;AAGJ;EACI;EACA;EACA;;AAEA;EACI;;AAGJ;EACI","file":"jsontree.js.css"} \ No newline at end of file diff --git a/static/configvis/jsontree.js.map b/static/configvis/jsontree.js.map new file mode 100644 index 00000000..21e76574 --- /dev/null +++ b/static/configvis/jsontree.js.map @@ -0,0 +1 @@ +{"version":3,"sources":["/Users/williamtroup/Documents/GitHub%20Repos/JsonTree.js/dist/jsontree.js"],"names":["Is","Is2","defined","value","toString","definedObject","object","definedBoolean","definedString","definedFunction","definedNumber","definedArray","Array","definedDate","Date","definedDecimal","invalidOptionArray","array","minimumLength","length","hexColor","valid","isNaN","substring","Default","Default2","getAnyString","defaultValue","getString","getBoolean","getNumber","getFunction","getArray","getObject","getStringOrArray","result2","values","split","getFixedDecimalPlacesValue","decimalPlaces","_a","regExp","RegExp","match","getFunctionName","valueParts","valueNameParts","DomElement","DomElement2","create","container","type","className","beforeNode","nodeType","toLowerCase","isText","document","createTextNode","createElement","insertBefore","appendChild","createWithHTML","html","element","innerHTML","addClass","classList","add","Str","Str2","newGuid","charIndex","push","character","Math","floor","random","join","padNumber","number","numberString","numberResult","arrayLength","DateTime","DateTime2","getWeekdayNumber","date","getDay","getDayOrdinal","configuration","text","thText","stText","ndText","rdText","getCustomFormattedDateText","dateFormat","weekDayNumber","replace","getHours","getMinutes","getSeconds","dayNames","dayNamesAbbreviated","getDate","monthNames","getMonth","monthNamesAbbreviated","getFullYear","Number","parseInt","Constants","Constants2","JSONTREE_JS_ATTRIBUTE_NAME","Binding","Binding2","Options","Options2","getForNewInstance","data","bindingOptions","get","_currentView","dataArrayCurrentIndex","newOptions","options","showCounts","useZeroIndexingForArrays","dateTimeFormat","showArrowToggles","showStringQuotes","showAllAsClosed","sortPropertyNames","sortPropertyNamesInAlphabeticalOrder","showCommas","reverseArrayValues","addArrayIndexPadding","showValueColors","maximumDecimalPlaces","maximumStringLength","showStringHexColors","showArrayItemsAsSeparateObjects","copyOnlyCurrentPage","getTitle","getIgnore","getCustomTriggers","title","show","showTreeControls","showCopyButton","ignore","nullValues","functionValues","unknownValues","booleanValues","decimalValues","numberValues","stringValues","dateValues","objectValues","arrayValues","events","onBeforeRender","onRenderComplete","onValueClick","onRefresh","onCopyAll","onOpenAll","onCloseAll","onDestroy","onBooleanRender","onDecimalRender","onNumberRender","onStringRender","onDateRender","onFunctionRender","onNullRender","onUnknownRender","Config","Config2","newConfiguration","safeMode","domElementTypes","getText","objectText","arrayText","closeAllButtonText","openAllButtonText","copyAllButtonText","objectErrorText","attributeNotValidErrorText","attributeNotSetErrorText","ellipsisText","closeAllButtonSymbolText","openAllButtonSymbolText","copyAllButtonSymbolText","backButtonText","nextButtonText","backButtonSymbolText","nextButtonSymbolText","Trigger","Trigger2","customEvent","triggerFunction","args","apply","slice","call","_configuration","_elements_Data","render","tagTypes","tagTypesLength","tagTypeIndex","domElements","getElementsByTagName","elements","elementsLength","elementIndex","renderElement","hasAttribute","bindingOptionsData","getAttribute","getObjectFromString","parsed","renderControl","console","error","id","removeAttribute","hasOwnProperty","renderControlContainer","renderControlTitleBar","renderObject","renderArray","titleBar","controls","copy","onclick","copyData","JSON","stringify","navigator","clipboard","writeText","openAll","closeAll","openAllNodes","closeAllNodes","back","disabled","next","showPagingIndex","objectTypeTitle","objectTypeContents","arrow","propertyCount","renderObjectValues","titleText","dataArrayIndex","renderArrayValues","properties","key","sort","reverse","propertiesLength","propertyIndex","propertyName","renderValue","addArrowEvent","dataLength","dataIndex1","getIndexName","dataIndex2","name","isLastItem","objectTypeValue","valueClass","valueElement","ignored","addClickEvent","createComma","newValue","color","newStringValue","style","objectTitle","arrayTitle","arrayTypeContents","removeChild","addValueClickEvent","display","index","largestValue","objectString","result","parse","e1","eval","e2","message","destroyElement","_public","refresh","elementId","refreshAll","renderAll","destroy","destroyAll","setConfiguration","configurationHasChanged","newInternalConfiguration","getIds","getVersion","addEventListener","window","$jsontree"],"mappings":"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","sourcesContent":[null]} \ No newline at end of file diff --git a/static/configvis/prism.css b/static/configvis/prism.css new file mode 100644 index 00000000..5d87cd19 --- /dev/null +++ b/static/configvis/prism.css @@ -0,0 +1,174 @@ +/* PrismJS 1.29.0 +https://prismjs.com/download.html#themes=prism-twilight&languages=markup+yaml&plugins=line-numbers */ +code[class*='language-'], +pre[class*='language-'] { + color: #fff; + background: 0 0; + font-family: Consolas, Monaco, 'Andale Mono', 'Ubuntu Mono', monospace; + font-size: 1em; + text-align: left; + text-shadow: 0 -0.1em 0.2em #000; + white-space: pre; + word-spacing: normal; + word-break: normal; + word-wrap: normal; + line-height: 1.5; + -moz-tab-size: 4; + -o-tab-size: 4; + tab-size: 4; + -webkit-hyphens: none; + -moz-hyphens: none; + -ms-hyphens: none; + hyphens: none; +} +:not(pre) > code[class*='language-'], +pre[class*='language-'] { + background: #141414; +} +pre[class*='language-'] { + border-radius: 0.5em; + border: 0.3em solid #545454; + box-shadow: 1px 1px 0.5em #000 inset; + margin: 0.5em 0; + overflow: auto; + padding: 1em; +} +pre[class*='language-']::-moz-selection { + background: #27292a; +} +pre[class*='language-']::selection { + background: #27292a; +} +code[class*='language-'] ::-moz-selection, +code[class*='language-']::-moz-selection, +pre[class*='language-'] ::-moz-selection, +pre[class*='language-']::-moz-selection { + text-shadow: none; + background: hsla(0, 0%, 93%, 0.15); +} +code[class*='language-'] ::selection, +code[class*='language-']::selection, +pre[class*='language-'] ::selection, +pre[class*='language-']::selection { + text-shadow: none; + background: hsla(0, 0%, 93%, 0.15); +} +:not(pre) > code[class*='language-'] { + border-radius: 0.3em; + border: 0.13em solid #545454; + box-shadow: 1px 1px 0.3em -0.1em #000 inset; + padding: 0.15em 0.2em 0.05em; + white-space: normal; +} +.token.cdata, +.token.comment, +.token.doctype, +.token.prolog { + color: #777; +} +.token.punctuation { + opacity: 0.7; +} +.token.namespace { + opacity: 0.7; +} +.token.boolean, +.token.deleted, +.token.number, +.token.tag { + color: #ce6849; +} +.token.builtin, +.token.constant, +.token.keyword, +.token.property, +.token.selector, +.token.symbol { + color: #f9ed99; +} +.language-css .token.string, +.style .token.string, +.token.attr-name, +.token.attr-value, +.token.char, +.token.entity, +.token.inserted, +.token.operator, +.token.string, +.token.url, +.token.variable { + color: #909e6a; +} +.token.atrule { + color: #7385a5; +} +.token.important, +.token.regex { + color: #e8c062; +} +.token.bold, +.token.important { + font-weight: 700; +} +.token.italic { + font-style: italic; +} +.token.entity { + cursor: help; +} +.language-markup .token.attr-name, +.language-markup .token.punctuation, +.language-markup .token.tag { + color: #ac885c; +} +.token { + position: relative; + z-index: 1; +} +.line-highlight.line-highlight { + background: hsla(0, 0%, 33%, 0.25); + background: linear-gradient(to right, hsla(0, 0%, 33%, 0.1) 70%, hsla(0, 0%, 33%, 0)); + border-bottom: 1px dashed #545454; + border-top: 1px dashed #545454; + margin-top: 0.75em; + z-index: 0; +} +.line-highlight.line-highlight:before, +.line-highlight.line-highlight[data-end]:after { + background-color: #8693a6; + color: #f4f1ef; +} +pre[class*='language-'].line-numbers { + position: relative; + padding-left: 3.8em; + counter-reset: linenumber; +} +pre[class*='language-'].line-numbers > code { + position: relative; + white-space: inherit; +} +.line-numbers .line-numbers-rows { + position: absolute; + pointer-events: none; + top: 0; + font-size: 100%; + left: -3.8em; + width: 3em; + letter-spacing: -1px; + border-right: 1px solid #999; + -webkit-user-select: none; + -moz-user-select: none; + -ms-user-select: none; + user-select: none; +} +.line-numbers-rows > span { + display: block; + counter-increment: linenumber; +} +.line-numbers-rows > span:before { + content: counter(linenumber); + color: #999; + display: block; + padding-right: 0.8em; + text-align: right; +} diff --git a/static/configvis/prism.js b/static/configvis/prism.js new file mode 100644 index 00000000..4b96b4a7 --- /dev/null +++ b/static/configvis/prism.js @@ -0,0 +1,625 @@ +/* PrismJS 1.29.0 +https://prismjs.com/download.html#themes=prism-twilight&languages=markup+yaml&plugins=line-numbers */ +var _self = + 'undefined' != typeof window ? window : 'undefined' != typeof WorkerGlobalScope && self instanceof WorkerGlobalScope ? self : {}, + Prism = (function (e) { + var n = /(?:^|\s)lang(?:uage)?-([\w-]+)(?=\s|$)/i, + t = 0, + r = {}, + a = { + manual: e.Prism && e.Prism.manual, + disableWorkerMessageHandler: e.Prism && e.Prism.disableWorkerMessageHandler, + util: { + encode: function e(n) { + return n instanceof i + ? new i(n.type, e(n.content), n.alias) + : Array.isArray(n) + ? n.map(e) + : n + .replace(/&/g, '&') + .replace(/= g.reach); + A += w.value.length, w = w.next + ) { + var E = w.value; + if (n.length > e.length) return; + if (!(E instanceof i)) { + var P, + L = 1; + if (y) { + if (!(P = l(b, A, e, m)) || P.index >= e.length) break; + var S = P.index, + O = P.index + P[0].length, + j = A; + for (j += w.value.length; S >= j; ) j += (w = w.next).value.length; + if (((A = j -= w.value.length), w.value instanceof i)) continue; + for (var C = w; C !== n.tail && (j < O || 'string' == typeof C.value); C = C.next) + L++, (j += C.value.length); + L--, (E = e.slice(A, j)), (P.index -= A); + } else if (!(P = l(b, 0, E, m))) continue; + S = P.index; + var N = P[0], + _ = E.slice(0, S), + M = E.slice(S + N.length), + W = A + E.length; + g && W > g.reach && (g.reach = W); + var z = w.prev; + if ( + (_ && ((z = u(n, z, _)), (A += _.length)), + c(n, z, L), + (w = u(n, z, new i(f, p ? a.tokenize(N, p) : N, k, N))), + M && u(n, w, M), + L > 1) + ) { + var I = { cause: f + ',' + d, reach: W }; + o(e, n, t, w.prev, A, I), g && I.reach > g.reach && (g.reach = I.reach); + } + } + } + } + } + } + function s() { + var e = { value: null, prev: null, next: null }, + n = { value: null, prev: e, next: null }; + (e.next = n), (this.head = e), (this.tail = n), (this.length = 0); + } + function u(e, n, t) { + var r = n.next, + a = { value: t, prev: n, next: r }; + return (n.next = a), (r.prev = a), e.length++, a; + } + function c(e, n, t) { + for (var r = n.next, a = 0; a < t && r !== e.tail; a++) r = r.next; + (n.next = r), (r.prev = n), (e.length -= a); + } + if ( + ((e.Prism = a), + (i.stringify = function e(n, t) { + if ('string' == typeof n) return n; + if (Array.isArray(n)) { + var r = ''; + return ( + n.forEach(function (n) { + r += e(n, t); + }), + r + ); + } + var i = { type: n.type, content: e(n.content, t), tag: 'span', classes: ['token', n.type], attributes: {}, language: t }, + l = n.alias; + l && (Array.isArray(l) ? Array.prototype.push.apply(i.classes, l) : i.classes.push(l)), a.hooks.run('wrap', i); + var o = ''; + for (var s in i.attributes) o += ' ' + s + '="' + (i.attributes[s] || '').replace(/"/g, '"') + '"'; + return '<' + i.tag + ' class="' + i.classes.join(' ') + '"' + o + '>' + i.content + ''; + }), + !e.document) + ) + return e.addEventListener + ? (a.disableWorkerMessageHandler || + e.addEventListener( + 'message', + function (n) { + var t = JSON.parse(n.data), + r = t.language, + i = t.code, + l = t.immediateClose; + e.postMessage(a.highlight(i, a.languages[r], r)), l && e.close(); + }, + !1, + ), + a) + : a; + var g = a.util.currentScript(); + function f() { + a.manual || a.highlightAll(); + } + if ((g && ((a.filename = g.src), g.hasAttribute('data-manual') && (a.manual = !0)), !a.manual)) { + var h = document.readyState; + 'loading' === h || ('interactive' === h && g && g.defer) + ? document.addEventListener('DOMContentLoaded', f) + : window.requestAnimationFrame + ? window.requestAnimationFrame(f) + : window.setTimeout(f, 16); + } + return a; + })(_self); +'undefined' != typeof module && module.exports && (module.exports = Prism), 'undefined' != typeof global && (global.Prism = Prism); +(Prism.languages.markup = { + comment: { pattern: //, greedy: !0 }, + prolog: { pattern: /<\?[\s\S]+?\?>/, greedy: !0 }, + doctype: { + pattern: /"'[\]]|"[^"]*"|'[^']*')+(?:\[(?:[^<"'\]]|"[^"]*"|'[^']*'|<(?!!--)|)*\]\s*)?>/i, + greedy: !0, + inside: { + 'internal-subset': { pattern: /(^[^\[]*\[)[\s\S]+(?=\]>$)/, lookbehind: !0, greedy: !0, inside: null }, + string: { pattern: /"[^"]*"|'[^']*'/, greedy: !0 }, + punctuation: /^$|[[\]]/, + 'doctype-tag': /^DOCTYPE/i, + name: /[^\s<>'"]+/, + }, + }, + cdata: { pattern: //i, greedy: !0 }, + tag: { + pattern: /<\/?(?!\d)[^\s>\/=$<%]+(?:\s(?:\s*[^\s>\/=]+(?:\s*=\s*(?:"[^"]*"|'[^']*'|[^\s'">=]+(?=[\s>]))|(?=[\s/>])))+)?\s*\/?>/, + greedy: !0, + inside: { + tag: { pattern: /^<\/?[^\s>\/]+/, inside: { punctuation: /^<\/?/, namespace: /^[^\s>\/:]+:/ } }, + 'special-attr': [], + 'attr-value': { + pattern: /=\s*(?:"[^"]*"|'[^']*'|[^\s'">=]+)/, + inside: { + punctuation: [ + { pattern: /^=/, alias: 'attr-equals' }, + { pattern: /^(\s*)["']|["']$/, lookbehind: !0 }, + ], + }, + }, + punctuation: /\/?>/, + 'attr-name': { pattern: /[^\s>\/]+/, inside: { namespace: /^[^\s>\/:]+:/ } }, + }, + }, + entity: [{ pattern: /&[\da-z]{1,8};/i, alias: 'named-entity' }, /&#x?[\da-f]{1,8};/i], +}), + (Prism.languages.markup.tag.inside['attr-value'].inside.entity = Prism.languages.markup.entity), + (Prism.languages.markup.doctype.inside['internal-subset'].inside = Prism.languages.markup), + Prism.hooks.add('wrap', function (a) { + 'entity' === a.type && (a.attributes.title = a.content.replace(/&/, '&')); + }), + Object.defineProperty(Prism.languages.markup.tag, 'addInlined', { + value: function (a, e) { + var s = {}; + (s['language-' + e] = { pattern: /(^$)/i, lookbehind: !0, inside: Prism.languages[e] }), + (s.cdata = /^$/i); + var t = { 'included-cdata': { pattern: //i, inside: s } }; + t['language-' + e] = { pattern: /[\s\S]+/, inside: Prism.languages[e] }; + var n = {}; + (n[a] = { + pattern: RegExp( + '(<__[^>]*>)(?:))*\\]\\]>|(?!)'.replace( + /__/g, + function () { + return a; + }, + ), + 'i', + ), + lookbehind: !0, + greedy: !0, + inside: t, + }), + Prism.languages.insertBefore('markup', 'cdata', n); + }, + }), + Object.defineProperty(Prism.languages.markup.tag, 'addAttribute', { + value: function (a, e) { + Prism.languages.markup.tag.inside['special-attr'].push({ + pattern: RegExp('(^|["\'\\s])(?:' + a + ')\\s*=\\s*(?:"[^"]*"|\'[^\']*\'|[^\\s\'">=]+(?=[\\s>]))', 'i'), + lookbehind: !0, + inside: { + 'attr-name': /^[^\s=]+/, + 'attr-value': { + pattern: /=[\s\S]+/, + inside: { + value: { + pattern: /(^=\s*(["']|(?!["'])))\S[\s\S]*(?=\2$)/, + lookbehind: !0, + alias: [e, 'language-' + e], + inside: Prism.languages[e], + }, + punctuation: [{ pattern: /^=/, alias: 'attr-equals' }, /"|'/], + }, + }, + }, + }); + }, + }), + (Prism.languages.html = Prism.languages.markup), + (Prism.languages.mathml = Prism.languages.markup), + (Prism.languages.svg = Prism.languages.markup), + (Prism.languages.xml = Prism.languages.extend('markup', {})), + (Prism.languages.ssml = Prism.languages.xml), + (Prism.languages.atom = Prism.languages.xml), + (Prism.languages.rss = Prism.languages.xml); +!(function (e) { + var n = /[*&][^\s[\]{},]+/, + r = /!(?:<[\w\-%#;/?:@&=+$,.!~*'()[\]]+>|(?:[a-zA-Z\d-]*!)?[\w\-%#;/?:@&=+$.~*'()]+)?/, + t = '(?:' + r.source + '(?:[ \t]+' + n.source + ')?|' + n.source + '(?:[ \t]+' + r.source + ')?)', + a = + '(?:[^\\s\\x00-\\x08\\x0e-\\x1f!"#%&\'*,\\-:>?@[\\]`{|}\\x7f-\\x84\\x86-\\x9f\\ud800-\\udfff\\ufffe\\uffff]|[?:-])(?:[ \t]*(?:(?![#:])|:))*'.replace( + //g, + function () { + return '[^\\s\\x00-\\x08\\x0e-\\x1f,[\\]{}\\x7f-\\x84\\x86-\\x9f\\ud800-\\udfff\\ufffe\\uffff]'; + }, + ), + d = '"(?:[^"\\\\\r\n]|\\\\.)*"|\'(?:[^\'\\\\\r\n]|\\\\.)*\''; + function o(e, n) { + n = (n || '').replace(/m/g, '') + 'm'; + var r = '([:\\-,[{]\\s*(?:\\s<>[ \t]+)?)(?:<>)(?=[ \t]*(?:$|,|\\]|\\}|(?:[\r\n]\\s*)?#))' + .replace(/<>/g, function () { + return t; + }) + .replace(/<>/g, function () { + return e; + }); + return RegExp(r, n); + } + (e.languages.yaml = { + scalar: { + pattern: RegExp( + '([\\-:]\\s*(?:\\s<>[ \t]+)?[|>])[ \t]*(?:((?:\r?\n|\r)[ \t]+)\\S[^\r\n]*(?:\\2[^\r\n]+)*)'.replace( + /<>/g, + function () { + return t; + }, + ), + ), + lookbehind: !0, + alias: 'string', + }, + comment: /#.*/, + key: { + pattern: RegExp( + '((?:^|[:\\-,[{\r\n?])[ \t]*(?:<>[ \t]+)?)<>(?=\\s*:\\s)' + .replace(/<>/g, function () { + return t; + }) + .replace(/<>/g, function () { + return '(?:' + a + '|' + d + ')'; + }), + ), + lookbehind: !0, + greedy: !0, + alias: 'atrule', + }, + directive: { pattern: /(^[ \t]*)%.+/m, lookbehind: !0, alias: 'important' }, + datetime: { + pattern: o( + '\\d{4}-\\d\\d?-\\d\\d?(?:[tT]|[ \t]+)\\d\\d?:\\d{2}:\\d{2}(?:\\.\\d*)?(?:[ \t]*(?:Z|[-+]\\d\\d?(?::\\d{2})?))?|\\d{4}-\\d{2}-\\d{2}|\\d\\d?:\\d{2}(?::\\d{2}(?:\\.\\d*)?)?', + ), + lookbehind: !0, + alias: 'number', + }, + boolean: { pattern: o('false|true', 'i'), lookbehind: !0, alias: 'important' }, + null: { pattern: o('null|~', 'i'), lookbehind: !0, alias: 'important' }, + string: { pattern: o(d), lookbehind: !0, greedy: !0 }, + number: { + pattern: o('[+-]?(?:0x[\\da-f]+|0o[0-7]+|(?:\\d+(?:\\.\\d*)?|\\.\\d+)(?:e[+-]?\\d+)?|\\.inf|\\.nan)', 'i'), + lookbehind: !0, + }, + tag: r, + important: n, + punctuation: /---|[:[\]{}\-,|>?]|\.\.\./, + }), + (e.languages.yml = e.languages.yaml); +})(Prism); +!(function () { + if ('undefined' != typeof Prism && 'undefined' != typeof document) { + var e = 'line-numbers', + n = /\n(?!$)/g, + t = (Prism.plugins.lineNumbers = { + getLine: function (n, t) { + if ('PRE' === n.tagName && n.classList.contains(e)) { + var i = n.querySelector('.line-numbers-rows'); + if (i) { + var r = parseInt(n.getAttribute('data-start'), 10) || 1, + s = r + (i.children.length - 1); + t < r && (t = r), t > s && (t = s); + var l = t - r; + return i.children[l]; + } + } + }, + resize: function (e) { + r([e]); + }, + assumeViewportIndependence: !0, + }), + i = void 0; + window.addEventListener('resize', function () { + (t.assumeViewportIndependence && i === window.innerWidth) || + ((i = window.innerWidth), r(Array.prototype.slice.call(document.querySelectorAll('pre.line-numbers')))); + }), + Prism.hooks.add('complete', function (t) { + if (t.code) { + var i = t.element, + s = i.parentNode; + if (s && /pre/i.test(s.nodeName) && !i.querySelector('.line-numbers-rows') && Prism.util.isActive(i, e)) { + i.classList.remove(e), s.classList.add(e); + var l, + o = t.code.match(n), + a = o ? o.length + 1 : 1, + u = new Array(a + 1).join(''); + (l = document.createElement('span')).setAttribute('aria-hidden', 'true'), + (l.className = 'line-numbers-rows'), + (l.innerHTML = u), + s.hasAttribute('data-start') && + (s.style.counterReset = 'linenumber ' + (parseInt(s.getAttribute('data-start'), 10) - 1)), + t.element.appendChild(l), + r([s]), + Prism.hooks.run('line-numbers', t); + } + } + }), + Prism.hooks.add('line-numbers', function (e) { + (e.plugins = e.plugins || {}), (e.plugins.lineNumbers = !0); + }); + } + function r(e) { + if ( + 0 != + (e = e.filter(function (e) { + var n, + t = ((n = e), n ? (window.getComputedStyle ? getComputedStyle(n) : n.currentStyle || null) : null)['white-space']; + return 'pre-wrap' === t || 'pre-line' === t; + })).length + ) { + var t = e + .map(function (e) { + var t = e.querySelector('code'), + i = e.querySelector('.line-numbers-rows'); + if (t && i) { + var r = e.querySelector('.line-numbers-sizer'), + s = t.textContent.split(n); + r || (((r = document.createElement('span')).className = 'line-numbers-sizer'), t.appendChild(r)), + (r.innerHTML = '0'), + (r.style.display = 'block'); + var l = r.getBoundingClientRect().height; + return (r.innerHTML = ''), { element: e, lines: s, lineHeights: [], oneLinerHeight: l, sizer: r }; + } + }) + .filter(Boolean); + t.forEach(function (e) { + var n = e.sizer, + t = e.lines, + i = e.lineHeights, + r = e.oneLinerHeight; + (i[t.length - 1] = void 0), + t.forEach(function (e, t) { + if (e && e.length > 1) { + var s = n.appendChild(document.createElement('span')); + (s.style.display = 'block'), (s.textContent = e); + } else i[t] = r; + }); + }), + t.forEach(function (e) { + for (var n = e.sizer, t = e.lineHeights, i = 0, r = 0; r < t.length; r++) + void 0 === t[r] && (t[r] = n.children[i++].getBoundingClientRect().height); + }), + t.forEach(function (e) { + var n = e.sizer, + t = e.element.querySelector('.line-numbers-rows'); + (n.style.display = 'none'), + (n.innerHTML = ''), + e.lineHeights.forEach(function (e, n) { + t.children[n].style.height = e + 'px'; + }); + }); + } + } +})(); diff --git a/static/logo.svg b/static/logo.svg new file mode 100644 index 00000000..2e809b42 --- /dev/null +++ b/static/logo.svg @@ -0,0 +1,7 @@ + + + + + + Butler +