diff --git a/.dockerignore b/.dockerignore new file mode 100644 index 0000000..1883643 --- /dev/null +++ b/.dockerignore @@ -0,0 +1,8 @@ +/data +.dockerignore +node_modules +npm-debug.log +Dockerfile +.git +.gitignore +.npmrc diff --git a/.eslintrc.js b/.eslintrc.cjs similarity index 88% rename from .eslintrc.js rename to .eslintrc.cjs index 0a07094..d84685d 100644 --- a/.eslintrc.js +++ b/.eslintrc.cjs @@ -4,7 +4,7 @@ module.exports = { es6: true, node: true }, - extends: ['eslint:recommended', 'prettier/@typescript-eslint', 'plugin:prettier/recommended'], + extends: ['eslint:recommended', 'plugin:prettier/recommended'], globals: { NodeJS: true, BigInt: true diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 0000000..c18da52 --- /dev/null +++ b/Dockerfile @@ -0,0 +1,19 @@ +FROM node:latest AS build +RUN apt-get update && apt-get install -y --no-install-recommends dumb-init +WORKDIR /usr/src/app +COPY src /usr/src/app/ +COPY package*.json /usr/src/app/ +RUN npm ci +RUN npm run lint +RUN npm run build +RUN npm ci --production + +FROM node:16.17.0-bullseye-slim + +ENV NODE_ENV production +COPY --from=install /usr/bin/dumb-init /usr/bin/dumb-init +USER node +WORKDIR /usr/src/app +COPY --chown=node:node --from=build /usr/src/app/node_modules /usr/src/app/node_modules +COPY --chown=node:node --from=build /usr/src/app/dist /usr/src/app/dist +CMD ["dumb-init", "node", "/usr/src/app/dist/index.js"] diff --git a/data/theme.svg b/data/theme.svg index efaa2f0..7431e77 100644 --- a/data/theme.svg +++ b/data/theme.svg @@ -2,37 +2,14 @@ - =0.10.0" } }, - "node_modules/@babel/code-frame": { - "version": "7.12.11", - "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.12.11.tgz", - "integrity": "sha512-Zt1yodBx1UcyiePMSkWnU4hPqhwq7hGi2nFL1LeA3EUl+q2LQx16MISgJ0+z7dnmgvP9QtIleuETGOiOH1RcIw==", - "dev": true, - "dependencies": { - "@babel/highlight": "^7.10.4" - } - }, - "node_modules/@babel/helper-validator-identifier": { - "version": "7.22.20", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.22.20.tgz", - "integrity": "sha512-Y4OZ+ytlatR8AI+8KZfKuL5urKp7qey08ha31L8b3BwewJAoJamTzyvxPR/5D+KkdJCGPq/+8TukHBlY10FX9A==", - "dev": true, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/highlight": { - "version": "7.23.4", - "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.23.4.tgz", - "integrity": "sha512-acGdbYSfp2WheJoJm/EBBBLh/ID8KDc64ISZ9DYtBmC8/Q204PZJLHyzeB5qMzJ5trcOkybd78M4x2KWsUq++A==", - "dev": true, - "dependencies": { - "@babel/helper-validator-identifier": "^7.22.20", - "chalk": "^2.4.2", - "js-tokens": "^4.0.0" - }, - "engines": { - "node": ">=6.9.0" - } - }, "node_modules/@emnapi/runtime": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/@emnapi/runtime/-/runtime-1.1.1.tgz", @@ -83,12 +47,6 @@ "tslib": "^2.4.0" } }, - "node_modules/@emnapi/runtime/node_modules/tslib": { - "version": "2.6.2", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.6.2.tgz", - "integrity": "sha512-AEYxH93jGFPn/a2iVAwW87VuUIkR1FVUKB77NwMF7nBTDkDrrT/Hpt/IrCJ0QXhW27jTBDcf5ZY7w6RiqTMw2Q==", - "optional": true - }, "node_modules/@esbuild-kit/cjs-loader": { "version": "2.4.4", "resolved": "https://registry.npmjs.org/@esbuild-kit/cjs-loader/-/cjs-loader-2.4.4.tgz", @@ -461,75 +419,152 @@ "node": ">=12" } }, + "node_modules/@eslint-community/eslint-utils": { + "version": "4.4.0", + "resolved": "https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.4.0.tgz", + "integrity": "sha512-1/sA4dwrzBAyeUoQ6oxahHKmrZvsnLCg4RfxW3ZFGGmQkSNQPFNLV9CUEFQP1x9EYXHTo5p6xdhZM1Ne9p/AfA==", + "dev": true, + "dependencies": { + "eslint-visitor-keys": "^3.3.0" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "peerDependencies": { + "eslint": "^6.0.0 || ^7.0.0 || >=8.0.0" + } + }, + "node_modules/@eslint-community/regexpp": { + "version": "4.10.0", + "resolved": "https://registry.npmjs.org/@eslint-community/regexpp/-/regexpp-4.10.0.tgz", + "integrity": "sha512-Cu96Sd2By9mCNTx2iyKOmq10v22jUVQv0lQnlGNy16oE9589yE+QADPbrMGCkA51cKZSg3Pu/aTJVTGfL/qjUA==", + "dev": true, + "engines": { + "node": "^12.0.0 || ^14.0.0 || >=16.0.0" + } + }, "node_modules/@eslint/eslintrc": { - "version": "0.4.3", - "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-0.4.3.tgz", - "integrity": "sha512-J6KFFz5QCYUJq3pf0mjEcCJVERbzv71PUIDczuh9JkwGEzced6CO5ADLHB1rbf/+oPBtoPfMYNOpGDzCANlbXw==", + "version": "2.1.4", + "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-2.1.4.tgz", + "integrity": "sha512-269Z39MS6wVJtsoUl10L60WdkhJVdPG24Q4eZTH3nnF6lpvSShEK3wQjDX9JRWAUPvPh7COouPpU9IrqaZFvtQ==", "dev": true, "dependencies": { "ajv": "^6.12.4", - "debug": "^4.1.1", - "espree": "^7.3.0", - "globals": "^13.9.0", - "ignore": "^4.0.6", + "debug": "^4.3.2", + "espree": "^9.6.0", + "globals": "^13.19.0", + "ignore": "^5.2.0", "import-fresh": "^3.2.1", - "js-yaml": "^3.13.1", - "minimatch": "^3.0.4", + "js-yaml": "^4.1.0", + "minimatch": "^3.1.2", "strip-json-comments": "^3.1.1" }, "engines": { - "node": "^10.12.0 || >=12.0.0" + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" } }, - "node_modules/@eslint/eslintrc/node_modules/ignore": { - "version": "4.0.6", - "resolved": "https://registry.npmjs.org/ignore/-/ignore-4.0.6.tgz", - "integrity": "sha512-cyFDKrqc/YdcWFniJhzI42+AzS+gNwmUzOSFcRCQYwySuBBBy/KjuxWLZ/FHEH6Moq1NizMOBWyTcv8O4OZIMg==", + "node_modules/@eslint/js": { + "version": "8.57.0", + "resolved": "https://registry.npmjs.org/@eslint/js/-/js-8.57.0.tgz", + "integrity": "sha512-Ys+3g2TaW7gADOJzPt83SJtCDhMjndcDMFVQ/Tj9iA1BfJzFKD9mAUXT3OenpuPHbI6P/myECxRJrofUsDx/5g==", "dev": true, "engines": { - "node": ">= 4" + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" } }, "node_modules/@fastify/ajv-compiler": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/@fastify/ajv-compiler/-/ajv-compiler-1.1.0.tgz", - "integrity": "sha512-gvCOUNpXsWrIQ3A4aXCLIdblL0tDq42BG/2Xw7oxbil9h11uow10ztS2GuFazNBfjbrsZ5nl+nPl5jDSjj5TSg==", + "version": "3.5.0", + "resolved": "https://registry.npmjs.org/@fastify/ajv-compiler/-/ajv-compiler-3.5.0.tgz", + "integrity": "sha512-ebbEtlI7dxXF5ziNdr05mOY8NnDiPB1XvAlLHctRt/Rc+C3LCOVW5imUVX+mhvUhnNzmPBHewUkOFgGlCxgdAA==", "dependencies": { - "ajv": "^6.12.6" + "ajv": "^8.11.0", + "ajv-formats": "^2.1.1", + "fast-uri": "^2.0.0" + } + }, + "node_modules/@fastify/ajv-compiler/node_modules/ajv": { + "version": "8.13.0", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.13.0.tgz", + "integrity": "sha512-PRA911Blj99jR5RMeTunVbNXMF6Lp4vZXnk5GQjcnUWUTsrXtekg/pnmFFI2u/I36Y/2bITGS30GZCXei6uNkA==", + "dependencies": { + "fast-deep-equal": "^3.1.3", + "json-schema-traverse": "^1.0.0", + "require-from-string": "^2.0.2", + "uri-js": "^4.4.1" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" } }, + "node_modules/@fastify/ajv-compiler/node_modules/json-schema-traverse": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", + "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==" + }, "node_modules/@fastify/busboy": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/@fastify/busboy/-/busboy-2.1.1.tgz", "integrity": "sha512-vBZP4NlzfOlerQTnba4aqZoMhE/a9HY7HRqoOPaETQcSQuWEIyZMHGfVu6w9wGtGK5fED5qRs2DteVCjOH60sA==", - "dev": true, "engines": { "node": ">=14" } }, "node_modules/@fastify/error": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/@fastify/error/-/error-2.0.0.tgz", - "integrity": "sha512-wI3fpfDT0t7p8E6dA2eTECzzOd+bZsZCJ2Hcv+Onn2b7ZwK3RwD27uW2QDaMtQhAfWQQP+WNK7nKf0twLsBf9w==" + "version": "3.4.1", + "resolved": "https://registry.npmjs.org/@fastify/error/-/error-3.4.1.tgz", + "integrity": "sha512-wWSvph+29GR783IhmvdwWnN4bUxTD01Vm5Xad4i7i1VuAOItLvbPAb69sb0IQ2N57yprvhNIwAP5B6xfKTmjmQ==" + }, + "node_modules/@fastify/fast-json-stringify-compiler": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/@fastify/fast-json-stringify-compiler/-/fast-json-stringify-compiler-4.3.0.tgz", + "integrity": "sha512-aZAXGYo6m22Fk1zZzEUKBvut/CIIQe/BapEORnxiD5Qr0kPHqqI69NtEMCme74h+at72sPhbkb4ZrLd1W3KRLA==", + "dependencies": { + "fast-json-stringify": "^5.7.0" + } + }, + "node_modules/@fastify/merge-json-schemas": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/@fastify/merge-json-schemas/-/merge-json-schemas-0.1.1.tgz", + "integrity": "sha512-fERDVz7topgNjtXsJTTW1JKLy0rhuLRcquYqNR9rF7OcVpCa2OVW49ZPDIhaRRCaUuvVxI+N416xUoF76HNSXA==", + "dependencies": { + "fast-deep-equal": "^3.1.3" + } }, "node_modules/@humanwhocodes/config-array": { - "version": "0.5.0", - "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.5.0.tgz", - "integrity": "sha512-FagtKFz74XrTl7y6HCzQpwDfXP0yhxe9lHLD1UZxjvZIcbyRz8zTFF/yYNfSfzU414eDwZ1SrO0Qvtyf+wFMQg==", + "version": "0.11.14", + "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.11.14.tgz", + "integrity": "sha512-3T8LkOmg45BV5FICb15QQMsyUSWrQ8AygVfC7ZG32zOalnqrilm018ZVCw0eapXux8FtA33q8PSRSstjee3jSg==", "dev": true, "dependencies": { - "@humanwhocodes/object-schema": "^1.2.0", - "debug": "^4.1.1", - "minimatch": "^3.0.4" + "@humanwhocodes/object-schema": "^2.0.2", + "debug": "^4.3.1", + "minimatch": "^3.0.5" }, "engines": { "node": ">=10.10.0" } }, + "node_modules/@humanwhocodes/module-importer": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@humanwhocodes/module-importer/-/module-importer-1.0.1.tgz", + "integrity": "sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA==", + "dev": true, + "engines": { + "node": ">=12.22" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/nzakas" + } + }, "node_modules/@humanwhocodes/object-schema": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/@humanwhocodes/object-schema/-/object-schema-1.2.1.tgz", - "integrity": "sha512-ZnQMnLV4e7hDlUvw8H+U8ASL02SS2Gn6+9Ac3wGGLIe7+je2AeAOxPY+izIPJDfFDb7eDjev0Us8MO1iFRN8hA==", + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/@humanwhocodes/object-schema/-/object-schema-2.0.3.tgz", + "integrity": "sha512-93zYdMES/c1D69yZiKDBj0V24vqNzB/koF26KPaagAfd3P/4gUlh3Dys5ogAK+Exi9QyzlD8x/08Zt7wIKcDcA==", "dev": true }, "node_modules/@img/sharp-darwin-arm64": { @@ -998,32 +1033,44 @@ "node": ">= 8" } }, + "node_modules/@pkgr/core": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/@pkgr/core/-/core-0.1.1.tgz", + "integrity": "sha512-cq8o4cWH0ibXh9VGi5P20Tu9XF/0fFXl9EUinr9QfTM7a7p0oTA4iJRCQWppXR1Pg8dSM0UCItCkPwsk9qWWYA==", + "dev": true, + "engines": { + "node": "^12.20.0 || ^14.18.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/unts" + } + }, "node_modules/@resvg/resvg-js": { - "version": "2.6.0", - "resolved": "https://registry.npmjs.org/@resvg/resvg-js/-/resvg-js-2.6.0.tgz", - "integrity": "sha512-Tf3YpbBKcQn991KKcw/vg7vZf98v01seSv6CVxZBbRkL/xyjnoYB6KgrFL6zskT1A4dWC/vg77KyNOW+ePaNlA==", + "version": "2.6.2", + "resolved": "https://registry.npmjs.org/@resvg/resvg-js/-/resvg-js-2.6.2.tgz", + "integrity": "sha512-xBaJish5OeGmniDj9cW5PRa/PtmuVU3ziqrbr5xJj901ZDN4TosrVaNZpEiLZAxdfnhAe7uQ7QFWfjPe9d9K2Q==", "engines": { "node": ">= 10" }, "optionalDependencies": { - "@resvg/resvg-js-android-arm-eabi": "2.6.0", - "@resvg/resvg-js-android-arm64": "2.6.0", - "@resvg/resvg-js-darwin-arm64": "2.6.0", - "@resvg/resvg-js-darwin-x64": "2.6.0", - "@resvg/resvg-js-linux-arm-gnueabihf": "2.6.0", - "@resvg/resvg-js-linux-arm64-gnu": "2.6.0", - "@resvg/resvg-js-linux-arm64-musl": "2.6.0", - "@resvg/resvg-js-linux-x64-gnu": "2.6.0", - "@resvg/resvg-js-linux-x64-musl": "2.6.0", - "@resvg/resvg-js-win32-arm64-msvc": "2.6.0", - "@resvg/resvg-js-win32-ia32-msvc": "2.6.0", - "@resvg/resvg-js-win32-x64-msvc": "2.6.0" + "@resvg/resvg-js-android-arm-eabi": "2.6.2", + "@resvg/resvg-js-android-arm64": "2.6.2", + "@resvg/resvg-js-darwin-arm64": "2.6.2", + "@resvg/resvg-js-darwin-x64": "2.6.2", + "@resvg/resvg-js-linux-arm-gnueabihf": "2.6.2", + "@resvg/resvg-js-linux-arm64-gnu": "2.6.2", + "@resvg/resvg-js-linux-arm64-musl": "2.6.2", + "@resvg/resvg-js-linux-x64-gnu": "2.6.2", + "@resvg/resvg-js-linux-x64-musl": "2.6.2", + "@resvg/resvg-js-win32-arm64-msvc": "2.6.2", + "@resvg/resvg-js-win32-ia32-msvc": "2.6.2", + "@resvg/resvg-js-win32-x64-msvc": "2.6.2" } }, "node_modules/@resvg/resvg-js-android-arm-eabi": { - "version": "2.6.0", - "resolved": "https://registry.npmjs.org/@resvg/resvg-js-android-arm-eabi/-/resvg-js-android-arm-eabi-2.6.0.tgz", - "integrity": "sha512-lJnZ/2P5aMocrFMW7HWhVne5gH82I8xH6zsfH75MYr4+/JOaVcGCTEQ06XFohGMdYRP3v05SSPLPvTM/RHjxfA==", + "version": "2.6.2", + "resolved": "https://registry.npmjs.org/@resvg/resvg-js-android-arm-eabi/-/resvg-js-android-arm-eabi-2.6.2.tgz", + "integrity": "sha512-FrJibrAk6v29eabIPgcTUMPXiEz8ssrAk7TXxsiZzww9UTQ1Z5KAbFJs+Z0Ez+VZTYgnE5IQJqBcoSiMebtPHA==", "cpu": [ "arm" ], @@ -1036,9 +1083,9 @@ } }, "node_modules/@resvg/resvg-js-android-arm64": { - "version": "2.6.0", - "resolved": "https://registry.npmjs.org/@resvg/resvg-js-android-arm64/-/resvg-js-android-arm64-2.6.0.tgz", - "integrity": "sha512-N527f529bjMwYWShZYfBD60dXA4Fux+D695QsHQ93BDYZSHUoOh1CUGUyICevnTxs7VgEl98XpArmUWBZQVMfQ==", + "version": "2.6.2", + "resolved": "https://registry.npmjs.org/@resvg/resvg-js-android-arm64/-/resvg-js-android-arm64-2.6.2.tgz", + "integrity": "sha512-VcOKezEhm2VqzXpcIJoITuvUS/fcjIw5NA/w3tjzWyzmvoCdd+QXIqy3FBGulWdClvp4g+IfUemigrkLThSjAQ==", "cpu": [ "arm64" ], @@ -1051,9 +1098,9 @@ } }, "node_modules/@resvg/resvg-js-darwin-arm64": { - "version": "2.6.0", - "resolved": "https://registry.npmjs.org/@resvg/resvg-js-darwin-arm64/-/resvg-js-darwin-arm64-2.6.0.tgz", - "integrity": "sha512-MabUKLVayEwlPo0mIqAmMt+qESN8LltCvv5+GLgVga1avpUrkxj/fkU1TKm8kQegutUjbP/B0QuMuUr0uhF8ew==", + "version": "2.6.2", + "resolved": "https://registry.npmjs.org/@resvg/resvg-js-darwin-arm64/-/resvg-js-darwin-arm64-2.6.2.tgz", + "integrity": "sha512-nmok2LnAd6nLUKI16aEB9ydMC6Lidiiq2m1nEBDR1LaaP7FGs4AJ90qDraxX+CWlVuRlvNjyYJTNv8qFjtL9+A==", "cpu": [ "arm64" ], @@ -1066,9 +1113,9 @@ } }, "node_modules/@resvg/resvg-js-darwin-x64": { - "version": "2.6.0", - "resolved": "https://registry.npmjs.org/@resvg/resvg-js-darwin-x64/-/resvg-js-darwin-x64-2.6.0.tgz", - "integrity": "sha512-zrFetdnSw/suXjmyxSjfDV7i61hahv6DDG6kM7BYN2yJ3Es5+BZtqYZTcIWogPJedYKmzN1YTMWGd/3f0ubFiA==", + "version": "2.6.2", + "resolved": "https://registry.npmjs.org/@resvg/resvg-js-darwin-x64/-/resvg-js-darwin-x64-2.6.2.tgz", + "integrity": "sha512-GInyZLjgWDfsVT6+SHxQVRwNzV0AuA1uqGsOAW+0th56J7Nh6bHHKXHBWzUrihxMetcFDmQMAX1tZ1fZDYSRsw==", "cpu": [ "x64" ], @@ -1081,9 +1128,9 @@ } }, "node_modules/@resvg/resvg-js-linux-arm-gnueabihf": { - "version": "2.6.0", - "resolved": "https://registry.npmjs.org/@resvg/resvg-js-linux-arm-gnueabihf/-/resvg-js-linux-arm-gnueabihf-2.6.0.tgz", - "integrity": "sha512-sH4gxXt7v7dGwjGyzLwn7SFGvwZG6DQqLaZ11MmzbCwd9Zosy1TnmrMJfn6TJ7RHezmQMgBPi18bl55FZ1AT4A==", + "version": "2.6.2", + "resolved": "https://registry.npmjs.org/@resvg/resvg-js-linux-arm-gnueabihf/-/resvg-js-linux-arm-gnueabihf-2.6.2.tgz", + "integrity": "sha512-YIV3u/R9zJbpqTTNwTZM5/ocWetDKGsro0SWp70eGEM9eV2MerWyBRZnQIgzU3YBnSBQ1RcxRZvY/UxwESfZIw==", "cpu": [ "arm" ], @@ -1096,9 +1143,9 @@ } }, "node_modules/@resvg/resvg-js-linux-arm64-gnu": { - "version": "2.6.0", - "resolved": "https://registry.npmjs.org/@resvg/resvg-js-linux-arm64-gnu/-/resvg-js-linux-arm64-gnu-2.6.0.tgz", - "integrity": "sha512-fCyMncqCJtrlANADIduYF4IfnWQ295UKib7DAxFXQhBsM9PLDTpizr0qemZcCNadcwSVHnAIzL4tliZhCM8P6A==", + "version": "2.6.2", + "resolved": "https://registry.npmjs.org/@resvg/resvg-js-linux-arm64-gnu/-/resvg-js-linux-arm64-gnu-2.6.2.tgz", + "integrity": "sha512-zc2BlJSim7YR4FZDQ8OUoJg5holYzdiYMeobb9pJuGDidGL9KZUv7SbiD4E8oZogtYY42UZEap7dqkkYuA91pg==", "cpu": [ "arm64" ], @@ -1111,9 +1158,9 @@ } }, "node_modules/@resvg/resvg-js-linux-arm64-musl": { - "version": "2.6.0", - "resolved": "https://registry.npmjs.org/@resvg/resvg-js-linux-arm64-musl/-/resvg-js-linux-arm64-musl-2.6.0.tgz", - "integrity": "sha512-ouLjTgBQHQyxLht4FdMPTvuY8xzJigM9EM2Tlu0llWkN1mKyTQrvYWi6TA6XnKdzDJHy7ZLpWpjZi7F5+Pg+Vg==", + "version": "2.6.2", + "resolved": "https://registry.npmjs.org/@resvg/resvg-js-linux-arm64-musl/-/resvg-js-linux-arm64-musl-2.6.2.tgz", + "integrity": "sha512-3h3dLPWNgSsD4lQBJPb4f+kvdOSJHa5PjTYVsWHxLUzH4IFTJUAnmuWpw4KqyQ3NA5QCyhw4TWgxk3jRkQxEKg==", "cpu": [ "arm64" ], @@ -1126,9 +1173,9 @@ } }, "node_modules/@resvg/resvg-js-linux-x64-gnu": { - "version": "2.6.0", - "resolved": "https://registry.npmjs.org/@resvg/resvg-js-linux-x64-gnu/-/resvg-js-linux-x64-gnu-2.6.0.tgz", - "integrity": "sha512-n3zC8DWsvxC1AwxpKFclIPapDFibs5XdIRoV/mcIlxlh0vseW1F49b97F33BtJQRmlntsqqN6GMMqx8byB7B+Q==", + "version": "2.6.2", + "resolved": "https://registry.npmjs.org/@resvg/resvg-js-linux-x64-gnu/-/resvg-js-linux-x64-gnu-2.6.2.tgz", + "integrity": "sha512-IVUe+ckIerA7xMZ50duAZzwf1U7khQe2E0QpUxu5MBJNao5RqC0zwV/Zm965vw6D3gGFUl7j4m+oJjubBVoftw==", "cpu": [ "x64" ], @@ -1141,9 +1188,9 @@ } }, "node_modules/@resvg/resvg-js-linux-x64-musl": { - "version": "2.6.0", - "resolved": "https://registry.npmjs.org/@resvg/resvg-js-linux-x64-musl/-/resvg-js-linux-x64-musl-2.6.0.tgz", - "integrity": "sha512-n4tasK1HOlAxdTEROgYA1aCfsEKk0UOFDNd/AQTTZlTmCbHKXPq+O8npaaKlwXquxlVK8vrkcWbksbiGqbCAcw==", + "version": "2.6.2", + "resolved": "https://registry.npmjs.org/@resvg/resvg-js-linux-x64-musl/-/resvg-js-linux-x64-musl-2.6.2.tgz", + "integrity": "sha512-UOf83vqTzoYQO9SZ0fPl2ZIFtNIz/Rr/y+7X8XRX1ZnBYsQ/tTb+cj9TE+KHOdmlTFBxhYzVkP2lRByCzqi4jQ==", "cpu": [ "x64" ], @@ -1156,9 +1203,9 @@ } }, "node_modules/@resvg/resvg-js-win32-arm64-msvc": { - "version": "2.6.0", - "resolved": "https://registry.npmjs.org/@resvg/resvg-js-win32-arm64-msvc/-/resvg-js-win32-arm64-msvc-2.6.0.tgz", - "integrity": "sha512-X2+EoBJFwDI5LDVb51Sk7ldnVLitMGr9WwU/i21i3fAeAXZb3hM16k67DeTy16OYkT2dk/RfU1tP1wG+rWbz2Q==", + "version": "2.6.2", + "resolved": "https://registry.npmjs.org/@resvg/resvg-js-win32-arm64-msvc/-/resvg-js-win32-arm64-msvc-2.6.2.tgz", + "integrity": "sha512-7C/RSgCa+7vqZ7qAbItfiaAWhyRSoD4l4BQAbVDqRRsRgY+S+hgS3in0Rxr7IorKUpGE69X48q6/nOAuTJQxeQ==", "cpu": [ "arm64" ], @@ -1171,9 +1218,9 @@ } }, "node_modules/@resvg/resvg-js-win32-ia32-msvc": { - "version": "2.6.0", - "resolved": "https://registry.npmjs.org/@resvg/resvg-js-win32-ia32-msvc/-/resvg-js-win32-ia32-msvc-2.6.0.tgz", - "integrity": "sha512-L7oevWjQoUgK5W1fCKn0euSVemhDXVhrjtwqpc7MwBKKimYeiOshO1Li1pa8bBt5PESahenhWgdB6lav9O0fEg==", + "version": "2.6.2", + "resolved": "https://registry.npmjs.org/@resvg/resvg-js-win32-ia32-msvc/-/resvg-js-win32-ia32-msvc-2.6.2.tgz", + "integrity": "sha512-har4aPAlvjnLcil40AC77YDIk6loMawuJwFINEM7n0pZviwMkMvjb2W5ZirsNOZY4aDbo5tLx0wNMREp5Brk+w==", "cpu": [ "ia32" ], @@ -1186,9 +1233,9 @@ } }, "node_modules/@resvg/resvg-js-win32-x64-msvc": { - "version": "2.6.0", - "resolved": "https://registry.npmjs.org/@resvg/resvg-js-win32-x64-msvc/-/resvg-js-win32-x64-msvc-2.6.0.tgz", - "integrity": "sha512-8lJlghb+Unki5AyKgsnFbRJwkEj9r1NpwyuBG8yEJiG1W9eEGl03R3I7bsVa3haof/3J1NlWf0rzSa1G++A2iw==", + "version": "2.6.2", + "resolved": "https://registry.npmjs.org/@resvg/resvg-js-win32-x64-msvc/-/resvg-js-win32-x64-msvc-2.6.2.tgz", + "integrity": "sha512-ZXtYhtUr5SSaBrUDq7DiyjOFJqBVL/dOBN7N/qmi/pO0IgiWW/f/ue3nbvu9joWE5aAKDoIzy/CxsY0suwGosQ==", "cpu": [ "x64" ], @@ -1200,59 +1247,11 @@ "node": ">= 10" } }, - "node_modules/@types/body-parser": { - "version": "1.19.5", - "resolved": "https://registry.npmjs.org/@types/body-parser/-/body-parser-1.19.5.tgz", - "integrity": "sha512-fB3Zu92ucau0iQ0JMCFQE7b/dv8Ot07NI3KaZIkIUNXq82k4eBAqUaneXfleGY9JWskeS9y+u0nXMyspcuQrCg==", - "dev": true, - "dependencies": { - "@types/connect": "*", - "@types/node": "*" - } - }, - "node_modules/@types/connect": { - "version": "3.4.38", - "resolved": "https://registry.npmjs.org/@types/connect/-/connect-3.4.38.tgz", - "integrity": "sha512-K6uROf1LD88uDQqJCktA4yzL1YYAK6NgfsI0v/mTgyPKWsX1CnJ0XPSDhViejru1GcRkLWb8RlzFYJRqGUbaug==", - "dev": true, - "dependencies": { - "@types/node": "*" - } - }, - "node_modules/@types/express": { - "version": "4.17.21", - "resolved": "https://registry.npmjs.org/@types/express/-/express-4.17.21.tgz", - "integrity": "sha512-ejlPM315qwLpaQlQDTjPdsUFSc6ZsP4AN6AlWnogPjQ7CVi7PYF3YVz+CY3jE2pwYf7E/7HlDAN0rV2GxTG0HQ==", - "dev": true, - "dependencies": { - "@types/body-parser": "*", - "@types/express-serve-static-core": "^4.17.33", - "@types/qs": "*", - "@types/serve-static": "*" - } - }, - "node_modules/@types/express-serve-static-core": { - "version": "4.17.43", - "resolved": "https://registry.npmjs.org/@types/express-serve-static-core/-/express-serve-static-core-4.17.43.tgz", - "integrity": "sha512-oaYtiBirUOPQGSWNGPWnzyAFJ0BP3cwvN4oWZQY+zUBwpVIGsKUkpBpSztp74drYcjavs7SKFZ4DX1V2QeN8rg==", - "dev": true, - "dependencies": { - "@types/node": "*", - "@types/qs": "*", - "@types/range-parser": "*", - "@types/send": "*" - } - }, - "node_modules/@types/http-errors": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/@types/http-errors/-/http-errors-2.0.4.tgz", - "integrity": "sha512-D0CFMMtydbJAegzOyHjtiKPLlvnm3iTZyZRSZoLq2mRhDdmLfIWOCYPfQJ4cu2erKghU++QvjcUjp/5h7hESpA==", - "dev": true - }, "node_modules/@types/jsdom": { "version": "21.1.6", "resolved": "https://registry.npmjs.org/@types/jsdom/-/jsdom-21.1.6.tgz", "integrity": "sha512-/7kkMsC+/kMs7gAYmmBR9P0vGTnOoLhQhyhQJSlXGI5bzTHp6xdo0TtKWQAsz6pmSAeVqKSbqeyP6hytqr9FDw==", + "dev": true, "dependencies": { "@types/node": "*", "@types/tough-cookie": "*", @@ -1265,86 +1264,52 @@ "integrity": "sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==", "dev": true }, - "node_modules/@types/mime": { - "version": "1.3.5", - "resolved": "https://registry.npmjs.org/@types/mime/-/mime-1.3.5.tgz", - "integrity": "sha512-/pyBZWSLD2n0dcHE3hq8s8ZvcETHtEuF+3E7XVt0Ig2nvsVQXdghHVcEkIWjy9A0wKfTn97a/PSDYohKIlnP/w==", - "dev": true - }, "node_modules/@types/node": { - "version": "14.18.63", - "resolved": "https://registry.npmjs.org/@types/node/-/node-14.18.63.tgz", - "integrity": "sha512-fAtCfv4jJg+ExtXhvCkCqUKZ+4ok/JQk01qDKhL5BDDoS3AxKXhV5/MAVUZyQnSEd2GT92fkgZl0pz0Q0AzcIQ==" - }, - "node_modules/@types/qs": { - "version": "6.9.12", - "resolved": "https://registry.npmjs.org/@types/qs/-/qs-6.9.12.tgz", - "integrity": "sha512-bZcOkJ6uWrL0Qb2NAWKa7TBU+mJHPzhx9jjLL1KHF+XpzEcR7EXHvjbHlGtR/IsP1vyPrehuS6XqkmaePy//mg==", + "version": "16.18.96", + "resolved": "https://registry.npmjs.org/@types/node/-/node-16.18.96.tgz", + "integrity": "sha512-84iSqGXoO+Ha16j8pRZ/L90vDMKX04QTYMTfYeE1WrjWaZXuchBehGUZEpNgx7JnmlrIHdnABmpjrQjhCnNldQ==", "dev": true }, - "node_modules/@types/range-parser": { - "version": "1.2.7", - "resolved": "https://registry.npmjs.org/@types/range-parser/-/range-parser-1.2.7.tgz", - "integrity": "sha512-hKormJbkJqzQGhziax5PItDUTMAM9uE2XXQmM37dyd4hVM+5aVl7oVxMVUiVQn2oCQFN/LKCZdvSM0pFRqbSmQ==", - "dev": true - }, - "node_modules/@types/send": { - "version": "0.17.4", - "resolved": "https://registry.npmjs.org/@types/send/-/send-0.17.4.tgz", - "integrity": "sha512-x2EM6TJOybec7c52BX0ZspPodMsQUd5L6PRwOunVyVUhXiBSKf3AezDL8Dgvgt5o0UfKNfuA0eMLr2wLT4AiBA==", - "dev": true, - "dependencies": { - "@types/mime": "^1", - "@types/node": "*" - } - }, - "node_modules/@types/serve-static": { - "version": "1.15.5", - "resolved": "https://registry.npmjs.org/@types/serve-static/-/serve-static-1.15.5.tgz", - "integrity": "sha512-PDRk21MnK70hja/YF8AHfC7yIsiQHn1rcXx7ijCFBX/k+XQJhQT/gw3xekXKJvx+5SXaMMS8oqQy09Mzvz2TuQ==", - "dev": true, - "dependencies": { - "@types/http-errors": "*", - "@types/mime": "*", - "@types/node": "*" - } - }, - "node_modules/@types/svgdom": { - "version": "0.1.2", - "resolved": "https://registry.npmjs.org/@types/svgdom/-/svgdom-0.1.2.tgz", - "integrity": "sha512-ZFwX8cDhbz6jiv3JZdMVYq8SSWHOUchChPmRoMwdIu3lz89aCu/gVK9TdR1eeb0ARQ8+5rtjUKrk1UR8hh0dhQ==", + "node_modules/@types/semver": { + "version": "7.5.8", + "resolved": "https://registry.npmjs.org/@types/semver/-/semver-7.5.8.tgz", + "integrity": "sha512-I8EUhyrgfLrcTkzV3TSsGyl1tSuPrEDzr0yd5m90UgNxQkyDXULk3b6MlQqTCpZpNtWe1K0hzclnZkTcLBe2UQ==", "dev": true }, "node_modules/@types/tough-cookie": { "version": "4.0.5", "resolved": "https://registry.npmjs.org/@types/tough-cookie/-/tough-cookie-4.0.5.tgz", - "integrity": "sha512-/Ad8+nIOV7Rl++6f1BdKxFSMgmoqEoYbHRpPcx3JEfv8VRsQe9Z4mCXeJBzxs7mbHY/XOZZuXlRNfhpVPbs6ZA==" + "integrity": "sha512-/Ad8+nIOV7Rl++6f1BdKxFSMgmoqEoYbHRpPcx3JEfv8VRsQe9Z4mCXeJBzxs7mbHY/XOZZuXlRNfhpVPbs6ZA==", + "dev": true }, "node_modules/@typescript-eslint/eslint-plugin": { - "version": "4.33.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-4.33.0.tgz", - "integrity": "sha512-aINiAxGVdOl1eJyVjaWn/YcVAq4Gi/Yo35qHGCnqbWVz61g39D0h23veY/MA0rFFGfxK7TySg2uwDeNv+JgVpg==", - "dev": true, - "dependencies": { - "@typescript-eslint/experimental-utils": "4.33.0", - "@typescript-eslint/scope-manager": "4.33.0", - "debug": "^4.3.1", - "functional-red-black-tree": "^1.0.1", - "ignore": "^5.1.8", - "regexpp": "^3.1.0", - "semver": "^7.3.5", - "tsutils": "^3.21.0" + "version": "7.8.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-7.8.0.tgz", + "integrity": "sha512-gFTT+ezJmkwutUPmB0skOj3GZJtlEGnlssems4AjkVweUPGj7jRwwqg0Hhg7++kPGJqKtTYx+R05Ftww372aIg==", + "dev": true, + "dependencies": { + "@eslint-community/regexpp": "^4.10.0", + "@typescript-eslint/scope-manager": "7.8.0", + "@typescript-eslint/type-utils": "7.8.0", + "@typescript-eslint/utils": "7.8.0", + "@typescript-eslint/visitor-keys": "7.8.0", + "debug": "^4.3.4", + "graphemer": "^1.4.0", + "ignore": "^5.3.1", + "natural-compare": "^1.4.0", + "semver": "^7.6.0", + "ts-api-utils": "^1.3.0" }, "engines": { - "node": "^10.12.0 || >=12.0.0" + "node": "^18.18.0 || >=20.0.0" }, "funding": { "type": "opencollective", "url": "https://opencollective.com/typescript-eslint" }, "peerDependencies": { - "@typescript-eslint/parser": "^4.0.0", - "eslint": "^5.0.0 || ^6.0.0 || ^7.0.0" + "@typescript-eslint/parser": "^7.0.0", + "eslint": "^8.56.0" }, "peerDependenciesMeta": { "typescript": { @@ -1352,81 +1317,85 @@ } } }, - "node_modules/@typescript-eslint/experimental-utils": { - "version": "4.33.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/experimental-utils/-/experimental-utils-4.33.0.tgz", - "integrity": "sha512-zeQjOoES5JFjTnAhI5QY7ZviczMzDptls15GFsI6jyUOq0kOf9+WonkhtlIhh0RgHRnqj5gdNxW5j1EvAyYg6Q==", + "node_modules/@typescript-eslint/parser": { + "version": "7.8.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-7.8.0.tgz", + "integrity": "sha512-KgKQly1pv0l4ltcftP59uQZCi4HUYswCLbTqVZEJu7uLX8CTLyswqMLqLN+2QFz4jCptqWVV4SB7vdxcH2+0kQ==", "dev": true, "dependencies": { - "@types/json-schema": "^7.0.7", - "@typescript-eslint/scope-manager": "4.33.0", - "@typescript-eslint/types": "4.33.0", - "@typescript-eslint/typescript-estree": "4.33.0", - "eslint-scope": "^5.1.1", - "eslint-utils": "^3.0.0" + "@typescript-eslint/scope-manager": "7.8.0", + "@typescript-eslint/types": "7.8.0", + "@typescript-eslint/typescript-estree": "7.8.0", + "@typescript-eslint/visitor-keys": "7.8.0", + "debug": "^4.3.4" }, "engines": { - "node": "^10.12.0 || >=12.0.0" + "node": "^18.18.0 || >=20.0.0" }, "funding": { "type": "opencollective", "url": "https://opencollective.com/typescript-eslint" }, "peerDependencies": { - "eslint": "*" + "eslint": "^8.56.0" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } } }, - "node_modules/@typescript-eslint/parser": { - "version": "4.33.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-4.33.0.tgz", - "integrity": "sha512-ZohdsbXadjGBSK0/r+d87X0SBmKzOq4/S5nzK6SBgJspFo9/CUDJ7hjayuze+JK7CZQLDMroqytp7pOcFKTxZA==", + "node_modules/@typescript-eslint/scope-manager": { + "version": "7.8.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-7.8.0.tgz", + "integrity": "sha512-viEmZ1LmwsGcnr85gIq+FCYI7nO90DVbE37/ll51hjv9aG+YZMb4WDE2fyWpUR4O/UrhGRpYXK/XajcGTk2B8g==", "dev": true, "dependencies": { - "@typescript-eslint/scope-manager": "4.33.0", - "@typescript-eslint/types": "4.33.0", - "@typescript-eslint/typescript-estree": "4.33.0", - "debug": "^4.3.1" + "@typescript-eslint/types": "7.8.0", + "@typescript-eslint/visitor-keys": "7.8.0" }, "engines": { - "node": "^10.12.0 || >=12.0.0" + "node": "^18.18.0 || >=20.0.0" }, "funding": { "type": "opencollective", "url": "https://opencollective.com/typescript-eslint" - }, - "peerDependencies": { - "eslint": "^5.0.0 || ^6.0.0 || ^7.0.0" - }, - "peerDependenciesMeta": { - "typescript": { - "optional": true - } } }, - "node_modules/@typescript-eslint/scope-manager": { - "version": "4.33.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-4.33.0.tgz", - "integrity": "sha512-5IfJHpgTsTZuONKbODctL4kKuQje/bzBRkwHE8UOZ4f89Zeddg+EGZs8PD8NcN4LdM3ygHWYB3ukPAYjvl/qbQ==", + "node_modules/@typescript-eslint/type-utils": { + "version": "7.8.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-7.8.0.tgz", + "integrity": "sha512-H70R3AefQDQpz9mGv13Uhi121FNMh+WEaRqcXTX09YEDky21km4dV1ZXJIp8QjXc4ZaVkXVdohvWDzbnbHDS+A==", "dev": true, "dependencies": { - "@typescript-eslint/types": "4.33.0", - "@typescript-eslint/visitor-keys": "4.33.0" + "@typescript-eslint/typescript-estree": "7.8.0", + "@typescript-eslint/utils": "7.8.0", + "debug": "^4.3.4", + "ts-api-utils": "^1.3.0" }, "engines": { - "node": "^8.10.0 || ^10.13.0 || >=11.10.1" + "node": "^18.18.0 || >=20.0.0" }, "funding": { "type": "opencollective", "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "^8.56.0" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } } }, "node_modules/@typescript-eslint/types": { - "version": "4.33.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-4.33.0.tgz", - "integrity": "sha512-zKp7CjQzLQImXEpLt2BUw1tvOMPfNoTAfb8l51evhYbOEEzdWyQNmHWWGPR6hwKJDAi+1VXSBmnhL9kyVTTOuQ==", + "version": "7.8.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-7.8.0.tgz", + "integrity": "sha512-wf0peJ+ZGlcH+2ZS23aJbOv+ztjeeP8uQ9GgwMJGVLx/Nj9CJt17GWgWWoSmoRVKAX2X+7fzEnAjxdvK2gqCLw==", "dev": true, "engines": { - "node": "^8.10.0 || ^10.13.0 || >=11.10.1" + "node": "^18.18.0 || >=20.0.0" }, "funding": { "type": "opencollective", @@ -1434,21 +1403,22 @@ } }, "node_modules/@typescript-eslint/typescript-estree": { - "version": "4.33.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-4.33.0.tgz", - "integrity": "sha512-rkWRY1MPFzjwnEVHsxGemDzqqddw2QbTJlICPD9p9I9LfsO8fdmfQPOX3uKfUaGRDFJbfrtm/sXhVXN4E+bzCA==", + "version": "7.8.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-7.8.0.tgz", + "integrity": "sha512-5pfUCOwK5yjPaJQNy44prjCwtr981dO8Qo9J9PwYXZ0MosgAbfEMB008dJ5sNo3+/BN6ytBPuSvXUg9SAqB0dg==", "dev": true, "dependencies": { - "@typescript-eslint/types": "4.33.0", - "@typescript-eslint/visitor-keys": "4.33.0", - "debug": "^4.3.1", - "globby": "^11.0.3", - "is-glob": "^4.0.1", - "semver": "^7.3.5", - "tsutils": "^3.21.0" + "@typescript-eslint/types": "7.8.0", + "@typescript-eslint/visitor-keys": "7.8.0", + "debug": "^4.3.4", + "globby": "^11.1.0", + "is-glob": "^4.0.3", + "minimatch": "^9.0.4", + "semver": "^7.6.0", + "ts-api-utils": "^1.3.0" }, "engines": { - "node": "^10.12.0 || >=12.0.0" + "node": "^18.18.0 || >=20.0.0" }, "funding": { "type": "opencollective", @@ -1460,32 +1430,98 @@ } } }, + "node_modules/@typescript-eslint/typescript-estree/node_modules/brace-expansion": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", + "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", + "dev": true, + "dependencies": { + "balanced-match": "^1.0.0" + } + }, + "node_modules/@typescript-eslint/typescript-estree/node_modules/minimatch": { + "version": "9.0.4", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.4.tgz", + "integrity": "sha512-KqWh+VchfxcMNRAJjj2tnsSJdNbHsVgnkBhTNrW7AjVo6OvLtxw8zfT9oLw1JSohlFzJ8jCoTgaoXvJ+kHt6fw==", + "dev": true, + "dependencies": { + "brace-expansion": "^2.0.1" + }, + "engines": { + "node": ">=16 || 14 >=14.17" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/@typescript-eslint/utils": { + "version": "7.8.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-7.8.0.tgz", + "integrity": "sha512-L0yFqOCflVqXxiZyXrDr80lnahQfSOfc9ELAAZ75sqicqp2i36kEZZGuUymHNFoYOqxRT05up760b4iGsl02nQ==", + "dev": true, + "dependencies": { + "@eslint-community/eslint-utils": "^4.4.0", + "@types/json-schema": "^7.0.15", + "@types/semver": "^7.5.8", + "@typescript-eslint/scope-manager": "7.8.0", + "@typescript-eslint/types": "7.8.0", + "@typescript-eslint/typescript-estree": "7.8.0", + "semver": "^7.6.0" + }, + "engines": { + "node": "^18.18.0 || >=20.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "^8.56.0" + } + }, "node_modules/@typescript-eslint/visitor-keys": { - "version": "4.33.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-4.33.0.tgz", - "integrity": "sha512-uqi/2aSz9g2ftcHWf8uLPJA70rUv6yuMW5Bohw+bwcuzaxQIHaKFZCKGoGXIrc9vkTJ3+0txM73K0Hq3d5wgIg==", + "version": "7.8.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-7.8.0.tgz", + "integrity": "sha512-q4/gibTNBQNA0lGyYQCmWRS5D15n8rXh4QjK3KV+MBPlTYHpfBUT3D3PaPR/HeNiI9W6R7FvlkcGhNyAoP+caA==", "dev": true, "dependencies": { - "@typescript-eslint/types": "4.33.0", - "eslint-visitor-keys": "^2.0.0" + "@typescript-eslint/types": "7.8.0", + "eslint-visitor-keys": "^3.4.3" }, "engines": { - "node": "^8.10.0 || ^10.13.0 || >=11.10.1" + "node": "^18.18.0 || >=20.0.0" }, "funding": { "type": "opencollective", "url": "https://opencollective.com/typescript-eslint" } }, + "node_modules/@ungap/structured-clone": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/@ungap/structured-clone/-/structured-clone-1.2.0.tgz", + "integrity": "sha512-zuVdFrMJiuCDQUMCzQaD6KL28MjnqqN8XnAqiEq9PNm/hCPTSGfrXCOfwj1ow4LFb/tNymJPwsNbVePc1xFqrQ==", + "dev": true + }, + "node_modules/abort-controller": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/abort-controller/-/abort-controller-3.0.0.tgz", + "integrity": "sha512-h8lQ8tacZYnR3vNQTgibj+tODHI5/+l06Au2Pcriv/Gmet0eaj4TwWH41sO9wnHDiQsEj19q0drzdWdeAHtweg==", + "dependencies": { + "event-target-shim": "^5.0.0" + }, + "engines": { + "node": ">=6.5" + } + }, "node_modules/abstract-logging": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/abstract-logging/-/abstract-logging-2.0.1.tgz", "integrity": "sha512-2BjRTZxTPvheOvGbBslFSYOUkr+SjPtOnrLP33f+VIWLzezQpZcqVg7ja3L4dBXmzzgwT+a029jRx5PCi3JuiA==" }, "node_modules/acorn": { - "version": "7.4.1", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-7.4.1.tgz", - "integrity": "sha512-nQyp0o1/mNdbTO1PO6kHkwSrmgZ0MT/jCCpNiwbUjGoRN4dlBhqJtoQuCnEOKzgTVwg0ZWiCoQy6SxMebQVh8A==", + "version": "8.11.3", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.11.3.tgz", + "integrity": "sha512-Y9rRfJG5jcKOE0CLisYbojUjIrIEE7AGMzA/Sm4BslANhbS+cDMpgBdcPT91oJ7OuJ9hYJBx59RjbhxVnrF8Xg==", "dev": true, "bin": { "acorn": "bin/acorn" @@ -1518,6 +1554,7 @@ "version": "6.12.6", "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", + "dev": true, "dependencies": { "fast-deep-equal": "^3.1.1", "fast-json-stable-stringify": "^2.0.0", @@ -1529,6 +1566,42 @@ "url": "https://github.com/sponsors/epoberezkin" } }, + "node_modules/ajv-formats": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/ajv-formats/-/ajv-formats-2.1.1.tgz", + "integrity": "sha512-Wx0Kx52hxE7C18hkMEggYlEifqWZtYaRgouJor+WMdPnQyEK13vgEWyVNup7SoeeoLMsr4kf5h6dOW11I15MUA==", + "dependencies": { + "ajv": "^8.0.0" + }, + "peerDependencies": { + "ajv": "^8.0.0" + }, + "peerDependenciesMeta": { + "ajv": { + "optional": true + } + } + }, + "node_modules/ajv-formats/node_modules/ajv": { + "version": "8.13.0", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.13.0.tgz", + "integrity": "sha512-PRA911Blj99jR5RMeTunVbNXMF6Lp4vZXnk5GQjcnUWUTsrXtekg/pnmFFI2u/I36Y/2bITGS30GZCXei6uNkA==", + "dependencies": { + "fast-deep-equal": "^3.1.3", + "json-schema-traverse": "^1.0.0", + "require-from-string": "^2.0.2", + "uri-js": "^4.4.1" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, + "node_modules/ajv-formats/node_modules/json-schema-traverse": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", + "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==" + }, "node_modules/ansi-colors": { "version": "4.1.3", "resolved": "https://registry.npmjs.org/ansi-colors/-/ansi-colors-4.1.3.tgz", @@ -1547,36 +1620,16 @@ "node": ">=8" } }, - "node_modules/ansi-styles": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", - "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", - "dependencies": { - "color-convert": "^1.9.0" - }, - "engines": { - "node": ">=4" - } - }, "node_modules/archy": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/archy/-/archy-1.0.0.tgz", "integrity": "sha512-Xg+9RwCg/0p32teKdGMPTPnVXKD0w3DfHnFTficozsAgsvq2XenPJq/MYpzzQ/v8zrOyJn6Ds39VA4JIDwFfqw==" }, - "node_modules/arg": { - "version": "4.1.3", - "resolved": "https://registry.npmjs.org/arg/-/arg-4.1.3.tgz", - "integrity": "sha512-58S9QDqG0Xx27YwPSt9fJxivjYl432YCwfDMfZ+71RAqUrZef7LrKQZ3LHLOwCS4FLNBplP533Zx895SeOCHvA==", - "dev": true - }, "node_modules/argparse": { - "version": "1.0.10", - "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz", - "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==", - "dev": true, - "dependencies": { - "sprintf-js": "~1.0.2" - } + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", + "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", + "dev": true }, "node_modules/array-union": { "version": "2.1.0", @@ -1587,15 +1640,6 @@ "node": ">=8" } }, - "node_modules/astral-regex": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/astral-regex/-/astral-regex-2.0.0.tgz", - "integrity": "sha512-Z7tMw1ytTXt5jqMcOP+OQteU1VuNK9Y02uuJtKQ1Sv69jXQKKg5cibLwGJow8yzZP+eAc18EmLGPal0bp36rvQ==", - "dev": true, - "engines": { - "node": ">=8" - } - }, "node_modules/asynckit": { "version": "0.4.0", "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", @@ -1610,14 +1654,14 @@ } }, "node_modules/avvio": { - "version": "7.2.5", - "resolved": "https://registry.npmjs.org/avvio/-/avvio-7.2.5.tgz", - "integrity": "sha512-AOhBxyLVdpOad3TujtC9kL/9r3HnTkxwQ5ggOsYrvvZP1cCFvzHWJd5XxZDFuTn+IN8vkKSG5SEJrd27vCSbeA==", + "version": "8.3.0", + "resolved": "https://registry.npmjs.org/avvio/-/avvio-8.3.0.tgz", + "integrity": "sha512-VBVH0jubFr9LdFASy/vNtm5giTrnbVquWBhT0fyizuNK2rQ7e7ONU2plZQWUNqtE1EmxFEb+kbSkFRkstiaS9Q==", "dependencies": { + "@fastify/error": "^3.3.0", "archy": "^1.0.0", "debug": "^4.0.0", - "fastq": "^1.6.1", - "queue-microtask": "^1.1.2" + "fastq": "^1.17.1" } }, "node_modules/balanced-match": { @@ -1626,6 +1670,25 @@ "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", "dev": true }, + "node_modules/base64-js": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz", + "integrity": "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ] + }, "node_modules/brace-expansion": { "version": "1.1.11", "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", @@ -1648,6 +1711,29 @@ "node": ">=8" } }, + "node_modules/buffer": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/buffer/-/buffer-6.0.3.tgz", + "integrity": "sha512-FTiCpNxtwiZZHEZbcbTIcZjERVICn9yq/pDFkTl95/AxzD1naBctN7YO68riM/gLSDY7sdrMby8hofADYuuqOA==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "dependencies": { + "base64-js": "^1.3.1", + "ieee754": "^1.2.1" + } + }, "node_modules/buffer-from": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.2.tgz", @@ -1663,28 +1749,6 @@ "node": ">=6" } }, - "node_modules/cat-loggr": { - "version": "1.2.2", - "resolved": "https://registry.npmjs.org/cat-loggr/-/cat-loggr-1.2.2.tgz", - "integrity": "sha512-4CiRwzPZ4E5/1XX+zgu4cxUZ0otElnSYUjx5KZO+ZhthGUSH5ly7UrMXqcYHC/yep+pv1HhXJAP8KkCPt7G2AA==", - "dependencies": { - "chalk": "^2.4.1", - "dayjs": "^1.10.5" - } - }, - "node_modules/chalk": { - "version": "2.4.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", - "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", - "dependencies": { - "ansi-styles": "^3.2.1", - "escape-string-regexp": "^1.0.5", - "supports-color": "^5.3.0" - }, - "engines": { - "node": ">=4" - } - }, "node_modules/cliui": { "version": "8.0.1", "resolved": "https://registry.npmjs.org/cliui/-/cliui-8.0.1.tgz", @@ -1711,14 +1775,6 @@ "node": ">=12.5.0" } }, - "node_modules/color-convert": { - "version": "1.9.3", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", - "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", - "dependencies": { - "color-name": "1.1.3" - } - }, "node_modules/color-name": { "version": "1.1.3", "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", @@ -1776,19 +1832,13 @@ "dev": true }, "node_modules/cookie": { - "version": "0.5.0", - "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.5.0.tgz", - "integrity": "sha512-YZ3GUyn/o8gfKJlnlX7g7xq4gyO6OSuhGPKaaGssGB2qgDUS0gPgtTvoyZLTt9Ab6dC4hfc9dV5arkvc/OCmrw==", + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.6.0.tgz", + "integrity": "sha512-U71cyTamuh1CRNCfpGY6to28lxvNwPG4Guz/EVjgf3Jmzv0vlDp1atT9eS5dDjMYHucpHbWns6Lwf3BKz6svdw==", "engines": { "node": ">= 0.6" } }, - "node_modules/create-require": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/create-require/-/create-require-1.1.1.tgz", - "integrity": "sha512-dcKFX3jn0MpIaXjisoRvexIJVEKzaq7z2rZKxf+MSr9TkdmHmsU4m2lcLojrj/FHl8mk5VxMmYA+ftRkP/3oKQ==", - "dev": true - }, "node_modules/cross-spawn": { "version": "7.0.3", "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz", @@ -1826,11 +1876,6 @@ "node": ">=18" } }, - "node_modules/dayjs": { - "version": "1.11.10", - "resolved": "https://registry.npmjs.org/dayjs/-/dayjs-1.11.10.tgz", - "integrity": "sha512-vjAczensTgRcqDERK0SR2XMwsF/tSvnvlv6VcF2GIhg6Sx4yOIt/irsr1RDJsKiIyBzJDpCoXiWWq28MqH2cnQ==" - }, "node_modules/debug": { "version": "4.3.4", "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", @@ -1858,14 +1903,6 @@ "integrity": "sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==", "dev": true }, - "node_modules/deepmerge": { - "version": "4.3.1", - "resolved": "https://registry.npmjs.org/deepmerge/-/deepmerge-4.3.1.tgz", - "integrity": "sha512-3sUqbMEc77XqpdNO7FRyRog+eW3ph+GYCbj+rK+uYyRMuwsVy0rMiVtPn+QJlKFvWP/1PYpapqYn0Me2knFn+A==", - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/degit": { "version": "2.8.4", "resolved": "https://registry.npmjs.org/degit/-/degit-2.8.4.tgz", @@ -1894,15 +1931,6 @@ "node": ">=8" } }, - "node_modules/diff": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/diff/-/diff-4.0.2.tgz", - "integrity": "sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A==", - "dev": true, - "engines": { - "node": ">=0.3.1" - } - }, "node_modules/dir-glob": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/dir-glob/-/dir-glob-3.0.1.tgz", @@ -2014,75 +2042,65 @@ "node": ">=6" } }, - "node_modules/escape-string-regexp": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", - "integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==", - "engines": { - "node": ">=0.8.0" - } - }, "node_modules/eslint": { - "version": "7.32.0", - "resolved": "https://registry.npmjs.org/eslint/-/eslint-7.32.0.tgz", - "integrity": "sha512-VHZ8gX+EDfz+97jGcgyGCyRia/dPOd6Xh9yPv8Bl1+SoaIwD+a/vlrOmGRUyOYu7MwUhc7CxqeaDZU13S4+EpA==", - "dev": true, - "dependencies": { - "@babel/code-frame": "7.12.11", - "@eslint/eslintrc": "^0.4.3", - "@humanwhocodes/config-array": "^0.5.0", - "ajv": "^6.10.0", + "version": "8.57.0", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.57.0.tgz", + "integrity": "sha512-dZ6+mexnaTIbSBZWgou51U6OmzIhYM2VcNdtiTtI7qPNZm35Akpr0f6vtw3w1Kmn5PYo+tZVfh13WrhpS6oLqQ==", + "dev": true, + "dependencies": { + "@eslint-community/eslint-utils": "^4.2.0", + "@eslint-community/regexpp": "^4.6.1", + "@eslint/eslintrc": "^2.1.4", + "@eslint/js": "8.57.0", + "@humanwhocodes/config-array": "^0.11.14", + "@humanwhocodes/module-importer": "^1.0.1", + "@nodelib/fs.walk": "^1.2.8", + "@ungap/structured-clone": "^1.2.0", + "ajv": "^6.12.4", "chalk": "^4.0.0", "cross-spawn": "^7.0.2", - "debug": "^4.0.1", + "debug": "^4.3.2", "doctrine": "^3.0.0", - "enquirer": "^2.3.5", "escape-string-regexp": "^4.0.0", - "eslint-scope": "^5.1.1", - "eslint-utils": "^2.1.0", - "eslint-visitor-keys": "^2.0.0", - "espree": "^7.3.1", - "esquery": "^1.4.0", + "eslint-scope": "^7.2.2", + "eslint-visitor-keys": "^3.4.3", + "espree": "^9.6.1", + "esquery": "^1.4.2", "esutils": "^2.0.2", "fast-deep-equal": "^3.1.3", "file-entry-cache": "^6.0.1", - "functional-red-black-tree": "^1.0.1", - "glob-parent": "^5.1.2", - "globals": "^13.6.0", - "ignore": "^4.0.6", - "import-fresh": "^3.0.0", + "find-up": "^5.0.0", + "glob-parent": "^6.0.2", + "globals": "^13.19.0", + "graphemer": "^1.4.0", + "ignore": "^5.2.0", "imurmurhash": "^0.1.4", "is-glob": "^4.0.0", - "js-yaml": "^3.13.1", + "is-path-inside": "^3.0.3", + "js-yaml": "^4.1.0", "json-stable-stringify-without-jsonify": "^1.0.1", "levn": "^0.4.1", "lodash.merge": "^4.6.2", - "minimatch": "^3.0.4", + "minimatch": "^3.1.2", "natural-compare": "^1.4.0", - "optionator": "^0.9.1", - "progress": "^2.0.0", - "regexpp": "^3.1.0", - "semver": "^7.2.1", - "strip-ansi": "^6.0.0", - "strip-json-comments": "^3.1.0", - "table": "^6.0.9", - "text-table": "^0.2.0", - "v8-compile-cache": "^2.0.3" + "optionator": "^0.9.3", + "strip-ansi": "^6.0.1", + "text-table": "^0.2.0" }, "bin": { "eslint": "bin/eslint.js" }, "engines": { - "node": "^10.12.0 || >=12.0.0" + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" }, "funding": { "url": "https://opencollective.com/eslint" } }, "node_modules/eslint-config-prettier": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/eslint-config-prettier/-/eslint-config-prettier-7.2.0.tgz", - "integrity": "sha512-rV4Qu0C3nfJKPOAhFujFxB7RMP+URFyQqqOZW9DMRD7ZDTFyjaIlETU3xzHELt++4ugC0+Jm084HQYkkJe+Ivg==", + "version": "9.1.0", + "resolved": "https://registry.npmjs.org/eslint-config-prettier/-/eslint-config-prettier-9.1.0.tgz", + "integrity": "sha512-NSWl5BFQWEPi1j4TjVNItzYV7dZXZ+wP6I6ZhrBGpChQhZRUaElihE9uRRkcbRnNb76UMKDF3r+WTmNcGPKsqw==", "dev": true, "bin": { "eslint-config-prettier": "bin/cli.js" @@ -2092,64 +2110,61 @@ } }, "node_modules/eslint-plugin-prettier": { - "version": "3.4.1", - "resolved": "https://registry.npmjs.org/eslint-plugin-prettier/-/eslint-plugin-prettier-3.4.1.tgz", - "integrity": "sha512-htg25EUYUeIhKHXjOinK4BgCcDwtLHjqaxCDsMy5nbnUMkKFvIhMVCp+5GFUXQ4Nr8lBsPqtGAqBenbpFqAA2g==", + "version": "5.1.3", + "resolved": "https://registry.npmjs.org/eslint-plugin-prettier/-/eslint-plugin-prettier-5.1.3.tgz", + "integrity": "sha512-C9GCVAs4Eq7ZC/XFQHITLiHJxQngdtraXaM+LoUFoFp/lHNl2Zn8f3WQbe9HvTBBQ9YnKFB0/2Ajdqwo5D1EAw==", "dev": true, "dependencies": { - "prettier-linter-helpers": "^1.0.0" + "prettier-linter-helpers": "^1.0.0", + "synckit": "^0.8.6" }, "engines": { - "node": ">=6.0.0" + "node": "^14.18.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint-plugin-prettier" }, "peerDependencies": { - "eslint": ">=5.0.0", - "prettier": ">=1.13.0" + "@types/eslint": ">=8.0.0", + "eslint": ">=8.0.0", + "eslint-config-prettier": "*", + "prettier": ">=3.0.0" }, "peerDependenciesMeta": { + "@types/eslint": { + "optional": true + }, "eslint-config-prettier": { "optional": true } } }, "node_modules/eslint-scope": { - "version": "5.1.1", - "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-5.1.1.tgz", - "integrity": "sha512-2NxwbF/hZ0KpepYN0cNbo+FN6XoK7GaHlQhgx/hIZl6Va0bF45RQOOwhLIy8lQDbuCiadSLCBnH2CFYquit5bw==", + "version": "7.2.2", + "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-7.2.2.tgz", + "integrity": "sha512-dOt21O7lTMhDM+X9mB4GX+DZrZtCUJPL/wlcTqxyrx5IvO0IYtILdtrQGQp+8n5S0gwSVmOf9NQrjMOgfQZlIg==", "dev": true, "dependencies": { "esrecurse": "^4.3.0", - "estraverse": "^4.1.1" - }, - "engines": { - "node": ">=8.0.0" - } - }, - "node_modules/eslint-utils": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/eslint-utils/-/eslint-utils-3.0.0.tgz", - "integrity": "sha512-uuQC43IGctw68pJA1RgbQS8/NP7rch6Cwd4j3ZBtgo4/8Flj4eGE7ZYSZRN3iq5pVUv6GPdW5Z1RFleo84uLDA==", - "dev": true, - "dependencies": { - "eslint-visitor-keys": "^2.0.0" + "estraverse": "^5.2.0" }, "engines": { - "node": "^10.0.0 || ^12.0.0 || >= 14.0.0" + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" }, "funding": { - "url": "https://github.com/sponsors/mysticatea" - }, - "peerDependencies": { - "eslint": ">=5" + "url": "https://opencollective.com/eslint" } }, "node_modules/eslint-visitor-keys": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-2.1.0.tgz", - "integrity": "sha512-0rSmRBzXgDzIsD6mGdJgevzgezI534Cer5L/vyMX0kHzT/jiB43jRhd9YUlMGYLQy2zprNmoT8qasCGtY+QaKw==", + "version": "3.4.3", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.4.3.tgz", + "integrity": "sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==", "dev": true, "engines": { - "node": ">=10" + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" } }, "node_modules/eslint/node_modules/ansi-styles": { @@ -2213,30 +2228,6 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/eslint/node_modules/eslint-utils": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/eslint-utils/-/eslint-utils-2.1.0.tgz", - "integrity": "sha512-w94dQYoauyvlDc43XnGB8lU3Zt713vNChgt4EWwhXAP2XkBvndfxF0AgIqKOOasjPIPzj9JqgwkwbCYD0/V3Zg==", - "dev": true, - "dependencies": { - "eslint-visitor-keys": "^1.1.0" - }, - "engines": { - "node": ">=6" - }, - "funding": { - "url": "https://github.com/sponsors/mysticatea" - } - }, - "node_modules/eslint/node_modules/eslint-utils/node_modules/eslint-visitor-keys": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-1.3.0.tgz", - "integrity": "sha512-6J72N8UNa462wa/KFODt/PJ3IU60SDpC3QXC1Hjc1BXXpfL2C9R5+AU7jhe0F6GREqVMh4Juu+NY7xn+6dipUQ==", - "dev": true, - "engines": { - "node": ">=4" - } - }, "node_modules/eslint/node_modules/has-flag": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", @@ -2246,15 +2237,6 @@ "node": ">=8" } }, - "node_modules/eslint/node_modules/ignore": { - "version": "4.0.6", - "resolved": "https://registry.npmjs.org/ignore/-/ignore-4.0.6.tgz", - "integrity": "sha512-cyFDKrqc/YdcWFniJhzI42+AzS+gNwmUzOSFcRCQYwySuBBBy/KjuxWLZ/FHEH6Moq1NizMOBWyTcv8O4OZIMg==", - "dev": true, - "engines": { - "node": ">= 4" - } - }, "node_modules/eslint/node_modules/supports-color": { "version": "7.2.0", "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", @@ -2268,39 +2250,20 @@ } }, "node_modules/espree": { - "version": "7.3.1", - "resolved": "https://registry.npmjs.org/espree/-/espree-7.3.1.tgz", - "integrity": "sha512-v3JCNCE64umkFpmkFGqzVKsOT0tN1Zr+ueqLZfpV1Ob8e+CEgPWa+OxCoGH3tnhimMKIaBm4m/vaRpJ/krRz2g==", + "version": "9.6.1", + "resolved": "https://registry.npmjs.org/espree/-/espree-9.6.1.tgz", + "integrity": "sha512-oruZaFkjorTpF32kDSI5/75ViwGeZginGGy2NoOSg3Q9bnwlnmDm4HLnkl0RE3n+njDXR037aY1+x58Z/zFdwQ==", "dev": true, "dependencies": { - "acorn": "^7.4.0", - "acorn-jsx": "^5.3.1", - "eslint-visitor-keys": "^1.3.0" + "acorn": "^8.9.0", + "acorn-jsx": "^5.3.2", + "eslint-visitor-keys": "^3.4.1" }, "engines": { - "node": "^10.12.0 || >=12.0.0" - } - }, - "node_modules/espree/node_modules/eslint-visitor-keys": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-1.3.0.tgz", - "integrity": "sha512-6J72N8UNa462wa/KFODt/PJ3IU60SDpC3QXC1Hjc1BXXpfL2C9R5+AU7jhe0F6GREqVMh4Juu+NY7xn+6dipUQ==", - "dev": true, - "engines": { - "node": ">=4" - } - }, - "node_modules/esprima": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz", - "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==", - "dev": true, - "bin": { - "esparse": "bin/esparse.js", - "esvalidate": "bin/esvalidate.js" + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" }, - "engines": { - "node": ">=4" + "funding": { + "url": "https://opencollective.com/eslint" } }, "node_modules/esquery": { @@ -2315,15 +2278,6 @@ "node": ">=0.10" } }, - "node_modules/esquery/node_modules/estraverse": { - "version": "5.3.0", - "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", - "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", - "dev": true, - "engines": { - "node": ">=4.0" - } - }, "node_modules/esrecurse": { "version": "4.3.0", "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.3.0.tgz", @@ -2336,7 +2290,7 @@ "node": ">=4.0" } }, - "node_modules/esrecurse/node_modules/estraverse": { + "node_modules/estraverse": { "version": "5.3.0", "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", @@ -2345,15 +2299,6 @@ "node": ">=4.0" } }, - "node_modules/estraverse": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.3.0.tgz", - "integrity": "sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==", - "dev": true, - "engines": { - "node": ">=4.0" - } - }, "node_modules/esutils": { "version": "2.0.3", "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz", @@ -2363,11 +2308,27 @@ "node": ">=0.10.0" } }, + "node_modules/event-target-shim": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/event-target-shim/-/event-target-shim-5.0.1.tgz", + "integrity": "sha512-i/2XbnSz/uxRCU6+NdVJgKWDTM427+MqYbkQzD321DuCQJUqOuJKIA0IM2+W2xtYHdKOmZ4dR6fExsd4SXL+WQ==", + "engines": { + "node": ">=6" + } + }, "node_modules/eventemitter3": { "version": "5.0.1", "resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-5.0.1.tgz", "integrity": "sha512-GWkBvjiSZK87ELrYOSESUYeVIc9mvLLf/nXalMOS5dYrgZq9o5OVkbZAVM06CVxYsCwH9BDZFPlQTlPA1j4ahA==" }, + "node_modules/events": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/events/-/events-3.3.0.tgz", + "integrity": "sha512-mQw+2fkQbALzQ7V0MY0IqdnXNOeTtP4r0lN9z7AAawCXgqea7bDii20AYrIBrFd/Hx0M2Ocz6S111CaFkUcb0Q==", + "engines": { + "node": ">=0.8.x" + } + }, "node_modules/fast-content-type-parse": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/fast-content-type-parse/-/fast-content-type-parse-1.1.0.tgz", @@ -2405,65 +2366,132 @@ "node": ">=8.6.0" } }, + "node_modules/fast-glob/node_modules/glob-parent": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", + "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", + "dev": true, + "dependencies": { + "is-glob": "^4.0.1" + }, + "engines": { + "node": ">= 6" + } + }, "node_modules/fast-json-stable-stringify": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz", - "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==" + "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==", + "dev": true }, "node_modules/fast-json-stringify": { - "version": "2.7.13", - "resolved": "https://registry.npmjs.org/fast-json-stringify/-/fast-json-stringify-2.7.13.tgz", - "integrity": "sha512-ar+hQ4+OIurUGjSJD1anvYSDcUflywhKjfxnsW4TBTD7+u0tJufv6DKRWoQk3vI6YBOWMoz0TQtfbe7dxbQmvA==", + "version": "5.15.0", + "resolved": "https://registry.npmjs.org/fast-json-stringify/-/fast-json-stringify-5.15.0.tgz", + "integrity": "sha512-BUEAAyDKb64u+kmkINYfXUUiKjBKerSmVu/dzotfaWSHBxR44JFrOZgkhMO6VxDhDfiuAoi8mx4drd5nvNdA4Q==", "dependencies": { - "ajv": "^6.11.0", - "deepmerge": "^4.2.2", - "rfdc": "^1.2.0", - "string-similarity": "^4.0.1" + "@fastify/merge-json-schemas": "^0.1.0", + "ajv": "^8.10.0", + "ajv-formats": "^3.0.1", + "fast-deep-equal": "^3.1.3", + "fast-uri": "^2.1.0", + "json-schema-ref-resolver": "^1.0.1", + "rfdc": "^1.2.0" + } + }, + "node_modules/fast-json-stringify/node_modules/ajv": { + "version": "8.13.0", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.13.0.tgz", + "integrity": "sha512-PRA911Blj99jR5RMeTunVbNXMF6Lp4vZXnk5GQjcnUWUTsrXtekg/pnmFFI2u/I36Y/2bITGS30GZCXei6uNkA==", + "dependencies": { + "fast-deep-equal": "^3.1.3", + "json-schema-traverse": "^1.0.0", + "require-from-string": "^2.0.2", + "uri-js": "^4.4.1" }, - "engines": { - "node": ">= 10.0.0" + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" } }, + "node_modules/fast-json-stringify/node_modules/ajv-formats": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/ajv-formats/-/ajv-formats-3.0.1.tgz", + "integrity": "sha512-8iUql50EUR+uUcdRQ3HDqa6EVyo3docL8g5WJ3FNcWmu62IbkGUue/pEyLBW8VGKKucTPgqeks4fIU1DA4yowQ==", + "dependencies": { + "ajv": "^8.0.0" + }, + "peerDependencies": { + "ajv": "^8.0.0" + }, + "peerDependenciesMeta": { + "ajv": { + "optional": true + } + } + }, + "node_modules/fast-json-stringify/node_modules/json-schema-traverse": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", + "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==" + }, "node_modules/fast-levenshtein": { "version": "2.0.6", "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz", "integrity": "sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==", "dev": true }, + "node_modules/fast-querystring": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/fast-querystring/-/fast-querystring-1.1.2.tgz", + "integrity": "sha512-g6KuKWmFXc0fID8WWH0jit4g0AGBoJhCkJMb1RmbsSEUNvQ+ZC8D6CUZ+GtF8nMzSPXnhiePyyqqipzNNEnHjg==", + "dependencies": { + "fast-decode-uri-component": "^1.0.1" + } + }, "node_modules/fast-redact": { - "version": "3.3.0", - "resolved": "https://registry.npmjs.org/fast-redact/-/fast-redact-3.3.0.tgz", - "integrity": "sha512-6T5V1QK1u4oF+ATxs1lWUmlEk6P2T9HqJG3e2DnHOdVgZy2rFJBoEnrIedcTXlkAHU/zKC+7KETJ+KGGKwxgMQ==", + "version": "3.5.0", + "resolved": "https://registry.npmjs.org/fast-redact/-/fast-redact-3.5.0.tgz", + "integrity": "sha512-dwsoQlS7h9hMeYUq1W++23NDcBLV4KqONnITDV9DjfS3q1SgDGVrBdvvTLUotWtPSD7asWDV9/CmsZPy8Hf70A==", "engines": { "node": ">=6" } }, - "node_modules/fast-safe-stringify": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/fast-safe-stringify/-/fast-safe-stringify-2.1.1.tgz", - "integrity": "sha512-W+KJc2dmILlPplD/H4K9l9LcAHAfPtP6BY84uVLXQ6Evcz9Lcg33Y2z1IVblT6xdY54PXYVHEv+0Wpq8Io6zkA==" + "node_modules/fast-uri": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/fast-uri/-/fast-uri-2.3.0.tgz", + "integrity": "sha512-eel5UKGn369gGEWOqBShmFJWfq/xSJvsgDzgLYC845GneayWvXBf0lJCBn5qTABfewy1ZDPoaR5OZCP+kssfuw==" }, "node_modules/fastify": { - "version": "3.29.5", - "resolved": "https://registry.npmjs.org/fastify/-/fastify-3.29.5.tgz", - "integrity": "sha512-FBDgb1gkenZxxh4sTD6AdI6mFnZnsgckpjIXzIvfLSYCa4isfQeD8QWGPib63dxq6btnY0l1j8I0xYhMvUb+sw==", - "dependencies": { - "@fastify/ajv-compiler": "^1.0.0", - "@fastify/error": "^2.0.0", - "abstract-logging": "^2.0.0", - "avvio": "^7.1.2", - "fast-content-type-parse": "^1.0.0", - "fast-json-stringify": "^2.5.2", - "find-my-way": "^4.5.0", - "flatstr": "^1.0.12", - "light-my-request": "^4.2.0", - "pino": "^6.13.0", - "process-warning": "^1.0.0", + "version": "4.26.2", + "resolved": "https://registry.npmjs.org/fastify/-/fastify-4.26.2.tgz", + "integrity": "sha512-90pjTuPGrfVKtdpLeLzND5nyC4woXZN5VadiNQCicj/iJU4viNHKhsAnb7jmv1vu2IzkLXyBiCzdWuzeXgQ5Ug==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/fastify" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/fastify" + } + ], + "dependencies": { + "@fastify/ajv-compiler": "^3.5.0", + "@fastify/error": "^3.4.0", + "@fastify/fast-json-stringify-compiler": "^4.3.0", + "abstract-logging": "^2.0.1", + "avvio": "^8.3.0", + "fast-content-type-parse": "^1.1.0", + "fast-json-stringify": "^5.8.0", + "find-my-way": "^8.0.0", + "light-my-request": "^5.11.0", + "pino": "^8.17.0", + "process-warning": "^3.0.0", "proxy-addr": "^2.0.7", - "rfdc": "^1.1.4", - "secure-json-parse": "^2.0.0", - "semver": "^7.3.2", - "tiny-lru": "^8.0.1" + "rfdc": "^1.3.0", + "secure-json-parse": "^2.7.0", + "semver": "^7.5.4", + "toad-cache": "^3.3.0" } }, "node_modules/fastq": { @@ -2499,17 +2527,16 @@ } }, "node_modules/find-my-way": { - "version": "4.5.1", - "resolved": "https://registry.npmjs.org/find-my-way/-/find-my-way-4.5.1.tgz", - "integrity": "sha512-kE0u7sGoUFbMXcOG/xpkmz4sRLCklERnBcg7Ftuu1iAxsfEt2S46RLJ3Sq7vshsEy2wJT2hZxE58XZK27qa8kg==", + "version": "8.2.0", + "resolved": "https://registry.npmjs.org/find-my-way/-/find-my-way-8.2.0.tgz", + "integrity": "sha512-HdWXgFYc6b1BJcOBDBwjqWuHJj1WYiqrxSh25qtU4DabpMFdj/gSunNBQb83t+8Zt67D7CXEzJWTkxaShMTMOA==", "dependencies": { - "fast-decode-uri-component": "^1.0.1", "fast-deep-equal": "^3.1.3", - "safe-regex2": "^2.0.0", - "semver-store": "^0.3.0" + "fast-querystring": "^1.0.0", + "safe-regex2": "^3.1.0" }, "engines": { - "node": ">=10" + "node": ">=14" } }, "node_modules/find-up": { @@ -2542,11 +2569,6 @@ "node": "^10.12.0 || >=12.0.0" } }, - "node_modules/flatstr": { - "version": "1.0.12", - "resolved": "https://registry.npmjs.org/flatstr/-/flatstr-1.0.12.tgz", - "integrity": "sha512-4zPxDyhCyiN2wIAtSLI6gc82/EjqZc1onI4Mz/l0pWrAlsSfYH/2ZIcU+e3oA2wDwbzIWNKwa23F8rh6+DRWkw==" - }, "node_modules/flatted": { "version": "3.3.1", "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.3.1.tgz", @@ -2580,12 +2602,6 @@ "integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==", "dev": true }, - "node_modules/functional-red-black-tree": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/functional-red-black-tree/-/functional-red-black-tree-1.0.1.tgz", - "integrity": "sha512-dsKNQNdj6xA3T+QlADDA7mOSlX0qiMINjn0cgr+eGHGsbSHzTabcIogz2+p/iqP1Xs6EP/sS2SbqH+brGTbq0g==", - "dev": true - }, "node_modules/get-caller-file": { "version": "2.0.5", "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz", @@ -2628,15 +2644,15 @@ } }, "node_modules/glob-parent": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", - "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz", + "integrity": "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==", "dev": true, "dependencies": { - "is-glob": "^4.0.1" + "is-glob": "^4.0.3" }, "engines": { - "node": ">= 6" + "node": ">=10.13.0" } }, "node_modules/globals": { @@ -2674,13 +2690,11 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/has-flag": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", - "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==", - "engines": { - "node": ">=4" - } + "node_modules/graphemer": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/graphemer/-/graphemer-1.4.0.tgz", + "integrity": "sha512-EtKwoO6kxCL9WO5xipiHTZlSzBm7WLT627TqC/uVRd0HKmq8NXyebnNYxDoBi7wt8eTWrUrKXCOVaFq9x1kgag==", + "dev": true }, "node_modules/html-encoding-sniffer": { "version": "4.0.0", @@ -2728,6 +2742,25 @@ "node": ">=0.10.0" } }, + "node_modules/ieee754": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.2.1.tgz", + "integrity": "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ] + }, "node_modules/ignore": { "version": "5.3.1", "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.3.1.tgz", @@ -2830,6 +2863,15 @@ "node": ">=0.12.0" } }, + "node_modules/is-path-inside": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/is-path-inside/-/is-path-inside-3.0.3.tgz", + "integrity": "sha512-Fd4gABb+ycGAmKou8eMftCupSir5lRxqf4aD/vd0cD2qc4HL07OjCeuHMr8Ro4CoMaeCKDB0/ECBOVWjTwUvPQ==", + "dev": true, + "engines": { + "node": ">=8" + } + }, "node_modules/is-potential-custom-element-name": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/is-potential-custom-element-name/-/is-potential-custom-element-name-1.0.1.tgz", @@ -2853,20 +2895,13 @@ "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==", "dev": true }, - "node_modules/js-tokens": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", - "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==", - "dev": true - }, "node_modules/js-yaml": { - "version": "3.14.1", - "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.14.1.tgz", - "integrity": "sha512-okMH7OXXJ7YrN9Ok3/SXrnu4iX9yOk+25nqX4imS2npuvTYDmo/QEZoqwZkYaIDk3jVvBOTOIEgEhaLOynBS9g==", + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", + "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==", "dev": true, "dependencies": { - "argparse": "^1.0.7", - "esprima": "^4.0.0" + "argparse": "^2.0.1" }, "bin": { "js-yaml": "bin/js-yaml.js" @@ -2917,10 +2952,19 @@ "integrity": "sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ==", "dev": true }, + "node_modules/json-schema-ref-resolver": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/json-schema-ref-resolver/-/json-schema-ref-resolver-1.0.1.tgz", + "integrity": "sha512-EJAj1pgHc1hxF6vo2Z3s69fMjO1INq6eGHXZ8Z6wCQeldCuwxGK9Sxf4/cScGn3FZubCVUehfWtcDM/PLteCQw==", + "dependencies": { + "fast-deep-equal": "^3.1.3" + } + }, "node_modules/json-schema-traverse": { "version": "0.4.1", "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", - "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==" + "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", + "dev": true }, "node_modules/json-stable-stringify-without-jsonify": { "version": "1.0.1", @@ -2951,36 +2995,15 @@ } }, "node_modules/light-my-request": { - "version": "4.12.0", - "resolved": "https://registry.npmjs.org/light-my-request/-/light-my-request-4.12.0.tgz", - "integrity": "sha512-0y+9VIfJEsPVzK5ArSIJ8Dkxp8QMP7/aCuxCUtG/tr9a2NoOf/snATE/OUc05XUplJCEnRh6gTkH7xh9POt1DQ==", + "version": "5.13.0", + "resolved": "https://registry.npmjs.org/light-my-request/-/light-my-request-5.13.0.tgz", + "integrity": "sha512-9IjUN9ZyCS9pTG+KqTDEQo68Sui2lHsYBrfMyVUTTZ3XhH8PMZq7xO94Kr+eP9dhi/kcKsx4N41p2IXEBil1pQ==", "dependencies": { - "ajv": "^8.1.0", - "cookie": "^0.5.0", - "process-warning": "^1.0.0", + "cookie": "^0.6.0", + "process-warning": "^3.0.0", "set-cookie-parser": "^2.4.1" } }, - "node_modules/light-my-request/node_modules/ajv": { - "version": "8.12.0", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.12.0.tgz", - "integrity": "sha512-sRu1kpcO9yLtYxBKvqfTeh9KzZEwO3STyX1HT+4CaDzC6HpTGYhIhPIzj9XuKU7KYDwnaeh5hcOwjy1QuJzBPA==", - "dependencies": { - "fast-deep-equal": "^3.1.1", - "json-schema-traverse": "^1.0.0", - "require-from-string": "^2.0.2", - "uri-js": "^4.2.2" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/epoberezkin" - } - }, - "node_modules/light-my-request/node_modules/json-schema-traverse": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", - "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==" - }, "node_modules/locate-path": { "version": "6.0.0", "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz", @@ -3007,12 +3030,6 @@ "integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==", "dev": true }, - "node_modules/lodash.truncate": { - "version": "4.4.2", - "resolved": "https://registry.npmjs.org/lodash.truncate/-/lodash.truncate-4.4.2.tgz", - "integrity": "sha512-jttmRe7bRse52OsWIMDLaXxWqRAmtIUccAQ3garviCqJjafXOfNMO0yMfNpdD6zbGaTU0P5Nz7e7gAT6cKmJRw==", - "dev": true - }, "node_modules/log-symbols": { "version": "4.1.0", "resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-4.1.0.tgz", @@ -3110,12 +3127,6 @@ "node": ">=10" } }, - "node_modules/make-error": { - "version": "1.3.6", - "resolved": "https://registry.npmjs.org/make-error/-/make-error-1.3.6.tgz", - "integrity": "sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw==", - "dev": true - }, "node_modules/merge2": { "version": "1.4.1", "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz", @@ -3185,6 +3196,14 @@ "resolved": "https://registry.npmjs.org/nwsapi/-/nwsapi-2.2.7.tgz", "integrity": "sha512-ub5E4+FBPKwAZx0UwIQOjYWGHTEq5sPqHQNRN8Z9e4A7u3Tj1weLJsL59yH9vmvqEtBHaOmT6cYQKIZOxp35FQ==" }, + "node_modules/on-exit-leak-free": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/on-exit-leak-free/-/on-exit-leak-free-2.1.2.tgz", + "integrity": "sha512-0eJJY6hXLGf1udHwfNftBqH+g73EU4B504nZeKpz1sYRKafAghwxEJunB2O7rDZkL4PGfsMVnTXZ2EjibbqcsA==", + "engines": { + "node": ">=14.0.0" + } + }, "node_modules/once": { "version": "1.4.0", "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", @@ -3313,26 +3332,39 @@ } }, "node_modules/pino": { - "version": "6.14.0", - "resolved": "https://registry.npmjs.org/pino/-/pino-6.14.0.tgz", - "integrity": "sha512-iuhEDel3Z3hF9Jfe44DPXR8l07bhjuFY3GMHIXbjnY9XcafbyDDwl2sN2vw2GjMPf5Nkoe+OFao7ffn9SXaKDg==", - "dependencies": { - "fast-redact": "^3.0.0", - "fast-safe-stringify": "^2.0.8", - "flatstr": "^1.0.12", - "pino-std-serializers": "^3.1.0", - "process-warning": "^1.0.0", + "version": "8.21.0", + "resolved": "https://registry.npmjs.org/pino/-/pino-8.21.0.tgz", + "integrity": "sha512-ip4qdzjkAyDDZklUaZkcRFb2iA118H9SgRh8yzTkSQK8HilsOJF7rSY8HoW5+I0M46AZgX/pxbprf2vvzQCE0Q==", + "dependencies": { + "atomic-sleep": "^1.0.0", + "fast-redact": "^3.1.1", + "on-exit-leak-free": "^2.1.0", + "pino-abstract-transport": "^1.2.0", + "pino-std-serializers": "^6.0.0", + "process-warning": "^3.0.0", "quick-format-unescaped": "^4.0.3", - "sonic-boom": "^1.0.2" + "real-require": "^0.2.0", + "safe-stable-stringify": "^2.3.1", + "sonic-boom": "^3.7.0", + "thread-stream": "^2.6.0" }, "bin": { "pino": "bin.js" } }, + "node_modules/pino-abstract-transport": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/pino-abstract-transport/-/pino-abstract-transport-1.2.0.tgz", + "integrity": "sha512-Guhh8EZfPCfH+PMXAb6rKOjGQEoy0xlAIn+irODG5kgfYV+BQ0rGYYWTIel3P5mmyXqkYkPmdIkywsn6QKUR1Q==", + "dependencies": { + "readable-stream": "^4.0.0", + "split2": "^4.0.0" + } + }, "node_modules/pino-std-serializers": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/pino-std-serializers/-/pino-std-serializers-3.2.0.tgz", - "integrity": "sha512-EqX4pwDPrt3MuOAAUBMU0Tk5kR/YcCM5fNPEzgCO2zJ5HfX0vbiH9HbJglnyeQsN96Kznae6MWD47pZB5avTrg==" + "version": "6.2.2", + "resolved": "https://registry.npmjs.org/pino-std-serializers/-/pino-std-serializers-6.2.2.tgz", + "integrity": "sha512-cHjPPsE+vhj/tnhCy/wiMh3M3z3h/j15zHQX+S9GkTBgqJuTuJzYJ4gUyACLhDaJ7kk9ba9iRDmbH2tJU03OiA==" }, "node_modules/prelude-ls": { "version": "1.2.1", @@ -3344,15 +3376,15 @@ } }, "node_modules/prettier": { - "version": "2.8.8", - "resolved": "https://registry.npmjs.org/prettier/-/prettier-2.8.8.tgz", - "integrity": "sha512-tdN8qQGvNjw4CHbY+XXk0JgCXn9QiF21a55rBe5LJAU+kDyC4WQn4+awm2Xfk2lQMk5fKup9XgzTZtGkjBdP9Q==", + "version": "3.2.5", + "resolved": "https://registry.npmjs.org/prettier/-/prettier-3.2.5.tgz", + "integrity": "sha512-3/GWa9aOC0YeD7LUfvOG2NiDyhOWRvt1k+rcKhOuYnMY24iiCphgneUfJDyFXd6rZCAnuLBv6UeAULtrhT/F4A==", "dev": true, "bin": { - "prettier": "bin-prettier.js" + "prettier": "bin/prettier.cjs" }, "engines": { - "node": ">=10.13.0" + "node": ">=14" }, "funding": { "url": "https://github.com/prettier/prettier?sponsor=1" @@ -3370,20 +3402,19 @@ "node": ">=6.0.0" } }, - "node_modules/process-warning": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/process-warning/-/process-warning-1.0.0.tgz", - "integrity": "sha512-du4wfLyj4yCZq1VupnVSZmRsPJsNuxoDQFdCFHLaYiEbFBD7QE0a+I4D7hOxrVnh78QE/YipFAj9lXHiXocV+Q==" - }, - "node_modules/progress": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/progress/-/progress-2.0.3.tgz", - "integrity": "sha512-7PiHtLll5LdnKIMw100I+8xJXR5gW2QwWYkT6iJva0bXitZKa/XMrSbdmg3r2Xnaidz9Qumd0VPaMrZlF9V9sA==", - "dev": true, + "node_modules/process": { + "version": "0.11.10", + "resolved": "https://registry.npmjs.org/process/-/process-0.11.10.tgz", + "integrity": "sha512-cdGef/drWFoydD1JsMzuFf8100nZl+GT+yacc2bEced5f9Rjk4z+WtFUTBu9PhOi9j/jfmBPu0mMEY4wIdAF8A==", "engines": { - "node": ">=0.4.0" + "node": ">= 0.6.0" } }, + "node_modules/process-warning": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/process-warning/-/process-warning-3.0.0.tgz", + "integrity": "sha512-mqn0kFRl0EoqhnL0GQ0veqFHyIN1yig9RHh/InzORTUiZHFRAur+aMtRkELNwGs9aNwKS6tg/An4NYBPGwvtzQ==" + }, "node_modules/proxy-addr": { "version": "2.0.7", "resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.7.tgz", @@ -3418,6 +3449,7 @@ "version": "1.2.3", "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz", "integrity": "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==", + "dev": true, "funding": [ { "type": "github", @@ -3438,16 +3470,27 @@ "resolved": "https://registry.npmjs.org/quick-format-unescaped/-/quick-format-unescaped-4.0.4.tgz", "integrity": "sha512-tYC1Q1hgyRuHgloV/YXs2w15unPVh8qfu/qCTfhTYamaw7fyhumKa2yGpdSo87vY32rIclj+4fWYQXUMs9EHvg==" }, - "node_modules/regexpp": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/regexpp/-/regexpp-3.2.0.tgz", - "integrity": "sha512-pq2bWo9mVD43nbts2wGv17XLiNLya+GklZ8kaDLV2Z08gDCsGpnKn9BFMepvWuHCbyVvY7J5o5+BVvoQbmlJLg==", - "dev": true, - "engines": { - "node": ">=8" + "node_modules/readable-stream": { + "version": "4.5.2", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-4.5.2.tgz", + "integrity": "sha512-yjavECdqeZ3GLXNgRXgeQEdz9fvDDkNKyHnbHRFtOr7/LcfgBcmct7t/ET+HaCTqfh06OzoAxrkN/IfjJBVe+g==", + "dependencies": { + "abort-controller": "^3.0.0", + "buffer": "^6.0.3", + "events": "^3.3.0", + "process": "^0.11.10", + "string_decoder": "^1.3.0" }, - "funding": { - "url": "https://github.com/sponsors/mysticatea" + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + } + }, + "node_modules/real-require": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/real-require/-/real-require-0.2.0.tgz", + "integrity": "sha512-57frrGM/OCTLqLOAh0mhVA9VBMHd+9U7Zb2THMGdBUoZVOtGbJzjxsYGDJ3A9AYYCP4hn6y1TVbaOfzWtm5GFg==", + "engines": { + "node": ">= 12.13.0" } }, "node_modules/require-directory": { @@ -3491,11 +3534,11 @@ } }, "node_modules/ret": { - "version": "0.2.2", - "resolved": "https://registry.npmjs.org/ret/-/ret-0.2.2.tgz", - "integrity": "sha512-M0b3YWQs7R3Z917WRQy1HHA7Ba7D8hvZg6UE5mLykJxQVE2ju0IXbGlaHPPlkY+WN7wFP+wUMXmBFA0aV6vYGQ==", + "version": "0.4.3", + "resolved": "https://registry.npmjs.org/ret/-/ret-0.4.3.tgz", + "integrity": "sha512-0f4Memo5QP7WQyUEAYUO3esD/XjOc3Zjjg5CPsAq1p8sIu0XPeMbHJemKA0BO7tV0X7+A0FoEpbmHXWxPyD3wQ==", "engines": { - "node": ">=4" + "node": ">=10" } }, "node_modules/reusify": { @@ -3555,12 +3598,39 @@ "queue-microtask": "^1.2.2" } }, + "node_modules/safe-buffer": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", + "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ] + }, "node_modules/safe-regex2": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/safe-regex2/-/safe-regex2-2.0.0.tgz", - "integrity": "sha512-PaUSFsUaNNuKwkBijoAPHAK6/eM6VirvyPWlZ7BAQy4D+hCvh4B6lIG+nPdhbFfIbP+gTGBcrdsOaUs0F+ZBOQ==", + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/safe-regex2/-/safe-regex2-3.1.0.tgz", + "integrity": "sha512-RAAZAGbap2kBfbVhvmnTFv73NWLMvDGOITFYTZBAaY8eR+Ir4ef7Up/e7amo+y1+AH+3PtLkrt9mvcTsG9LXug==", "dependencies": { - "ret": "~0.2.0" + "ret": "~0.4.0" + } + }, + "node_modules/safe-stable-stringify": { + "version": "2.4.3", + "resolved": "https://registry.npmjs.org/safe-stable-stringify/-/safe-stable-stringify-2.4.3.tgz", + "integrity": "sha512-e2bDA2WJT0wxseVd4lsDP4+3ONX6HpMXQa1ZhFQ7SU+GjvORCmShbCMltrtIDfkYhVHrOcPtj+KhmDBdPdZD1g==", + "engines": { + "node": ">=10" } }, "node_modules/safer-buffer": { @@ -3598,11 +3668,6 @@ "node": ">=10" } }, - "node_modules/semver-store": { - "version": "0.3.0", - "resolved": "https://registry.npmjs.org/semver-store/-/semver-store-0.3.0.tgz", - "integrity": "sha512-TcZvGMMy9vodEFSse30lWinkj+JgOBvPn8wRItpQRSayhc+4ssDs335uklkfvQQJgL/WvmHLVj4Ycv2s7QCQMg==" - }, "node_modules/set-cookie-parser": { "version": "2.6.0", "resolved": "https://registry.npmjs.org/set-cookie-parser/-/set-cookie-parser-2.6.0.tgz", @@ -3686,16 +3751,17 @@ } }, "node_modules/slash-create": { - "version": "5.14.0", - "resolved": "https://registry.npmjs.org/slash-create/-/slash-create-5.14.0.tgz", - "integrity": "sha512-V+Zcvs2a9e3obm+zrWw3jr8HcoX5Jtj6cI1ByT0/henOTdEsfh1roOLLhLiLxo80poBZfkLcy3fnn5hTAwF59g==", + "version": "6.1.3", + "resolved": "https://registry.npmjs.org/slash-create/-/slash-create-6.1.3.tgz", + "integrity": "sha512-M/mh6thqQtAUnvxR7hngtCJNNJTJwrssb0xG16Ru7gM4kD/rAKheucqzCUAG2QLaf5bZ2ex0CiOtOx1+kW0AYA==", "dependencies": { "eventemitter3": "^5.0.1", "lodash.isequal": "^4.5.0", - "tweetnacl": "^1.0.3" + "tweetnacl": "^1.0.3", + "undici": "^5.28.4" }, "engines": { - "node": ">=14" + "node": ">=16" }, "funding": { "url": "https://github.com/sponsors/Snazzah" @@ -3741,93 +3807,12 @@ "url": "https://github.com/sponsors/Snazzah" } }, - "node_modules/slash-up/node_modules/slash-create": { - "version": "6.0.2", - "resolved": "https://registry.npmjs.org/slash-create/-/slash-create-6.0.2.tgz", - "integrity": "sha512-V2gqs7Ov3C8hjS2aODwzGUM/4WqpRiNXSPh69Bk3soyL7Kvkc/75HfwOgz9fTNNU+H/u5EMtvjR4hJgey0HKHA==", - "dev": true, - "dependencies": { - "eventemitter3": "^5.0.1", - "lodash.isequal": "^4.5.0", - "tweetnacl": "^1.0.3", - "undici": "^5.28.2" - }, - "engines": { - "node": ">=16" - }, - "funding": { - "url": "https://github.com/sponsors/Snazzah" - }, - "peerDependencies": { - "express": "^4", - "fastify": "^3 || ^4" - }, - "peerDependenciesMeta": { - "express": { - "optional": true - }, - "fastify": { - "optional": true - } - } - }, - "node_modules/slice-ansi": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-4.0.0.tgz", - "integrity": "sha512-qMCMfhY040cVHT43K9BFygqYbUPFZKHOg7K73mtTWJRb8pyP3fzf4Ixd5SzdEJQ6MRUg/WBnOLxghZtKKurENQ==", - "dev": true, - "dependencies": { - "ansi-styles": "^4.0.0", - "astral-regex": "^2.0.0", - "is-fullwidth-code-point": "^3.0.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/slice-ansi?sponsor=1" - } - }, - "node_modules/slice-ansi/node_modules/ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "dev": true, - "dependencies": { - "color-convert": "^2.0.1" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" - } - }, - "node_modules/slice-ansi/node_modules/color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "dev": true, - "dependencies": { - "color-name": "~1.1.4" - }, - "engines": { - "node": ">=7.0.0" - } - }, - "node_modules/slice-ansi/node_modules/color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true - }, "node_modules/sonic-boom": { - "version": "1.4.1", - "resolved": "https://registry.npmjs.org/sonic-boom/-/sonic-boom-1.4.1.tgz", - "integrity": "sha512-LRHh/A8tpW7ru89lrlkU4AszXt1dbwSjVWguGrmlxE7tawVmDBlI1PILMkXAxJTwqhgsEeTHzj36D5CmHgQmNg==", + "version": "3.8.1", + "resolved": "https://registry.npmjs.org/sonic-boom/-/sonic-boom-3.8.1.tgz", + "integrity": "sha512-y4Z8LCDBuum+PBP3lSV7RHrXscqksve/bi0as7mhwVnBW+/wUqKT/2Kb7um8yqcFy0duYbbPxzt89Zy2nOCaxg==", "dependencies": { - "atomic-sleep": "^1.0.0", - "flatstr": "^1.0.12" + "atomic-sleep": "^1.0.0" } }, "node_modules/source-map": { @@ -3849,17 +3834,21 @@ "source-map": "^0.6.0" } }, - "node_modules/sprintf-js": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz", - "integrity": "sha512-D9cPgkvLlV3t3IzL0D0YLvGA9Ahk4PcvVwUbN0dSGr1aP0Nrt4AEnTUbuGvquEC0mA64Gqt1fzirlRs5ibXx8g==", - "dev": true + "node_modules/split2": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/split2/-/split2-4.2.0.tgz", + "integrity": "sha512-UcjcJOWknrNkF6PLX83qcHM6KHgVKNkV62Y8a5uYDVv9ydGQVwAHMKqHdJje1VTWpljG0WYpCDhrCdAOYH4TWg==", + "engines": { + "node": ">= 10.x" + } }, - "node_modules/string-similarity": { - "version": "4.0.4", - "resolved": "https://registry.npmjs.org/string-similarity/-/string-similarity-4.0.4.tgz", - "integrity": "sha512-/q/8Q4Bl4ZKAPjj8WerIBJWALKkaPRfrvhfF8k/B23i4nzrlRj2/go1m90In7nG/3XDSbOo0+pu6RvCTM9RGMQ==", - "deprecated": "Package no longer supported. Contact Support at https://www.npmjs.com/support for more info." + "node_modules/string_decoder": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz", + "integrity": "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==", + "dependencies": { + "safe-buffer": "~5.2.0" + } }, "node_modules/string-width": { "version": "4.2.3", @@ -3899,72 +3888,39 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/supports-color": { - "version": "5.5.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", - "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", - "dependencies": { - "has-flag": "^3.0.0" - }, - "engines": { - "node": ">=4" - } - }, "node_modules/symbol-tree": { "version": "3.2.4", "resolved": "https://registry.npmjs.org/symbol-tree/-/symbol-tree-3.2.4.tgz", "integrity": "sha512-9QNk5KwDF+Bvz+PyObkmSYjI5ksVUYtjW7AU22r2NKcfLJcXp96hkDWU3+XndOsUb+AQ9QhfzfCT2O+CNWT5Tw==" }, - "node_modules/table": { - "version": "6.8.1", - "resolved": "https://registry.npmjs.org/table/-/table-6.8.1.tgz", - "integrity": "sha512-Y4X9zqrCftUhMeH2EptSSERdVKt/nEdijTOacGD/97EKjhQ/Qs8RTlEGABSJNNN8lac9kheH+af7yAkEWlgneA==", + "node_modules/synckit": { + "version": "0.8.8", + "resolved": "https://registry.npmjs.org/synckit/-/synckit-0.8.8.tgz", + "integrity": "sha512-HwOKAP7Wc5aRGYdKH+dw0PRRpbO841v2DENBtjnR5HFWoiNByAl7vrx3p0G/rCyYXQsrxqtX48TImFtPcIHSpQ==", "dev": true, "dependencies": { - "ajv": "^8.0.1", - "lodash.truncate": "^4.4.2", - "slice-ansi": "^4.0.0", - "string-width": "^4.2.3", - "strip-ansi": "^6.0.1" + "@pkgr/core": "^0.1.0", + "tslib": "^2.6.2" }, "engines": { - "node": ">=10.0.0" - } - }, - "node_modules/table/node_modules/ajv": { - "version": "8.12.0", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.12.0.tgz", - "integrity": "sha512-sRu1kpcO9yLtYxBKvqfTeh9KzZEwO3STyX1HT+4CaDzC6HpTGYhIhPIzj9XuKU7KYDwnaeh5hcOwjy1QuJzBPA==", - "dev": true, - "dependencies": { - "fast-deep-equal": "^3.1.1", - "json-schema-traverse": "^1.0.0", - "require-from-string": "^2.0.2", - "uri-js": "^4.2.2" + "node": "^14.18.0 || >=16.0.0" }, "funding": { - "type": "github", - "url": "https://github.com/sponsors/epoberezkin" + "url": "https://opencollective.com/unts" } }, - "node_modules/table/node_modules/json-schema-traverse": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", - "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==", - "dev": true - }, "node_modules/text-table": { "version": "0.2.0", "resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz", "integrity": "sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw==", "dev": true }, - "node_modules/tiny-lru": { - "version": "8.0.2", - "resolved": "https://registry.npmjs.org/tiny-lru/-/tiny-lru-8.0.2.tgz", - "integrity": "sha512-ApGvZ6vVvTNdsmt676grvCkUCGwzG9IqXma5Z07xJgiC5L7akUMof5U8G2JTI9Rz/ovtVhJBlY6mNhEvtjzOIg==", - "engines": { - "node": ">=6" + "node_modules/thread-stream": { + "version": "2.7.0", + "resolved": "https://registry.npmjs.org/thread-stream/-/thread-stream-2.7.0.tgz", + "integrity": "sha512-qQiRWsU/wvNolI6tbbCKd9iKaTnCXsTwVxhhKM6nctPdujTyztjlbUkUTUymidWcMnZ5pWR0ej4a0tjsW021vw==", + "dependencies": { + "real-require": "^0.2.0" } }, "node_modules/to-regex-range": { @@ -3979,6 +3935,14 @@ "node": ">=8.0" } }, + "node_modules/toad-cache": { + "version": "3.7.0", + "resolved": "https://registry.npmjs.org/toad-cache/-/toad-cache-3.7.0.tgz", + "integrity": "sha512-/m8M+2BJUpoJdgAHoG+baCwBT+tf2VraSfkBgl0Y00qIWt41DJ8R5B8nsEw0I58YwF5IZH6z24/2TobDKnqSWw==", + "engines": { + "node": ">=12" + } + }, "node_modules/tough-cookie": { "version": "4.1.3", "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-4.1.3.tgz", @@ -4004,52 +3968,23 @@ "node": ">=18" } }, - "node_modules/ts-node": { - "version": "9.1.1", - "resolved": "https://registry.npmjs.org/ts-node/-/ts-node-9.1.1.tgz", - "integrity": "sha512-hPlt7ZACERQGf03M253ytLY3dHbGNGrAq9qIHWUY9XHYl1z7wYngSr3OQ5xmui8o2AaxsONxIzjafLUiWBo1Fg==", + "node_modules/ts-api-utils": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/ts-api-utils/-/ts-api-utils-1.3.0.tgz", + "integrity": "sha512-UQMIo7pb8WRomKR1/+MFVLTroIvDVtMX3K6OUir8ynLyzB8Jeriont2bTAtmNPa1ekAgN7YPDyf6V+ygrdU+eQ==", "dev": true, - "dependencies": { - "arg": "^4.1.0", - "create-require": "^1.1.0", - "diff": "^4.0.1", - "make-error": "^1.1.1", - "source-map-support": "^0.5.17", - "yn": "3.1.1" - }, - "bin": { - "ts-node": "dist/bin.js", - "ts-node-script": "dist/bin-script.js", - "ts-node-transpile-only": "dist/bin-transpile.js", - "ts-script": "dist/bin-script-deprecated.js" - }, "engines": { - "node": ">=10.0.0" + "node": ">=16" }, "peerDependencies": { - "typescript": ">=2.7" + "typescript": ">=4.2.0" } }, "node_modules/tslib": { - "version": "1.14.1", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", - "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==", - "dev": true - }, - "node_modules/tsutils": { - "version": "3.21.0", - "resolved": "https://registry.npmjs.org/tsutils/-/tsutils-3.21.0.tgz", - "integrity": "sha512-mHKK3iUXL+3UF6xL5k0PEhKRUBKPBCv/+RkEOpjRWxxx27KKRBmmA60A9pgOUvMi8GKhRMPEmjBRPzs2W7O1OA==", - "dev": true, - "dependencies": { - "tslib": "^1.8.1" - }, - "engines": { - "node": ">= 6" - }, - "peerDependencies": { - "typescript": ">=2.8.0 || >= 3.2.0-dev || >= 3.3.0-dev || >= 3.4.0-dev || >= 3.5.0-dev || >= 3.6.0-dev || >= 3.6.0-beta || >= 3.7.0-dev || >= 3.7.0-beta" - } + "version": "2.6.2", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.6.2.tgz", + "integrity": "sha512-AEYxH93jGFPn/a2iVAwW87VuUIkR1FVUKB77NwMF7nBTDkDrrT/Hpt/IrCJ0QXhW27jTBDcf5ZY7w6RiqTMw2Q==", + "devOptional": true }, "node_modules/tweetnacl": { "version": "1.0.3", @@ -4081,23 +4016,22 @@ } }, "node_modules/typescript": { - "version": "4.9.5", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.9.5.tgz", - "integrity": "sha512-1FXk9E2Hm+QzZQ7z+McJiHL4NW1F2EzMu9Nq9i3zAaGqibafqYwCVU6WyWAuyQRRzOlxou8xZSyXLEN8oKj24g==", + "version": "5.4.5", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.4.5.tgz", + "integrity": "sha512-vcI4UpRgg81oIRUFwR0WSIHKt11nJ7SAVlYNIu+QpqeyXP+gpQJy/Z4+F0aGxSE4MqwjyXvW/TzgkLAx2AGHwQ==", "dev": true, "bin": { "tsc": "bin/tsc", "tsserver": "bin/tsserver" }, "engines": { - "node": ">=4.2.0" + "node": ">=14.17" } }, "node_modules/undici": { - "version": "5.28.3", - "resolved": "https://registry.npmjs.org/undici/-/undici-5.28.3.tgz", - "integrity": "sha512-3ItfzbrhDlINjaP0duwnNsKpDQk3acHI3gVJ1z4fmwMK31k5G9OVIAMLSIaP6w4FaGkaAkN6zaQO9LUvZ1t7VA==", - "dev": true, + "version": "5.28.4", + "resolved": "https://registry.npmjs.org/undici/-/undici-5.28.4.tgz", + "integrity": "sha512-72RFADWFqKmUb2hmmvNODKL3p9hcB6Gt2DOQMis1SEBaV6a4MH8soBvzg+95CYhCKPFedut2JY9bMfrDl9D23g==", "dependencies": { "@fastify/busboy": "^2.0.0" }, @@ -4130,12 +4064,6 @@ "requires-port": "^1.0.0" } }, - "node_modules/v8-compile-cache": { - "version": "2.4.0", - "resolved": "https://registry.npmjs.org/v8-compile-cache/-/v8-compile-cache-2.4.0.tgz", - "integrity": "sha512-ocyWc3bAHBB/guyqJQVI5o4BZkPhznPYUG2ea80Gond/BgNWpap8TOmLSeeQG7bnh2KMISxskdADG59j7zruhw==", - "dev": true - }, "node_modules/w3c-xmlserializer": { "version": "5.0.0", "resolved": "https://registry.npmjs.org/w3c-xmlserializer/-/w3c-xmlserializer-5.0.0.tgz", @@ -4305,9 +4233,9 @@ "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==" }, "node_modules/yaml": { - "version": "2.4.0", - "resolved": "https://registry.npmjs.org/yaml/-/yaml-2.4.0.tgz", - "integrity": "sha512-j9iR8g+/t0lArF4V6NE/QCfT+CO7iLqrXAHZbJdo+LfjqP1vR8Fg5bSiaq6Q2lOD1AUEVrEVIgABvBFYojJVYQ==", + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/yaml/-/yaml-2.4.2.tgz", + "integrity": "sha512-B3VqDZ+JAg1nZpaEmWtTXUlBneoGx6CPM9b0TENK6aoSu5t73dItudwdgmi6tHlIZZId4dZ9skcAQ2UbcyAeVA==", "bin": { "yaml": "bin.mjs" }, @@ -4342,15 +4270,6 @@ "node": ">=12" } }, - "node_modules/yn": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/yn/-/yn-3.1.1.tgz", - "integrity": "sha512-Ux4ygGWsu2c7isFWe8Yu1YluJmqVhxqK2cLXNQA5AcC3QfbGNpM7fu0Y8b/z16pXLnFxZYvWhd3fhBY9DLmC6Q==", - "dev": true, - "engines": { - "node": ">=6" - } - }, "node_modules/yocto-queue": { "version": "0.1.0", "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz", diff --git a/package.json b/package.json index d17db23..d608f64 100644 --- a/package.json +++ b/package.json @@ -8,33 +8,29 @@ "sync": "slash-up sync", "sync:dev": "slash-up sync -e development", "start": "cd dist && node index.js", - "build": "npx tsc", - "lint": "npx eslint --ext .ts ./src", - "lint:fix": "npx eslint --ext .ts ./src --fix" + "build": "tsc", + "lint": "eslint --ext .ts ./src", + "lint:fix": "eslint --ext .ts ./src --fix" }, "dependencies": { - "@resvg/resvg-js": "^2.6.0", - "@types/jsdom": "^21.1.6", - "cat-loggr": "^1.1.0", + "@resvg/resvg-js": "^2.6.2", "dotenv": "^16.4.5", - "fastify": "^3.9.2", + "fastify": "^4.26.2", "jsdom": "^24.0.0", - "slash-create": "^5.2.0", + "slash-create": "^6.1.3", "sharp": "^0.33.3", - "yaml": "^2.4.0" + "yaml": "^2.4.2" }, "devDependencies": { - "@types/express": "^4.17.11", - "@types/node": "^14.14.37", - "@types/svgdom": "^0.1.2", - "@typescript-eslint/eslint-plugin": "^4.19.0", - "@typescript-eslint/parser": "^4.19.0", - "eslint": "^7.15.0", - "eslint-config-prettier": "^7.0.0", - "eslint-plugin-prettier": "^3.3.0", - "prettier": "^2.2.1", - "slash-up": "^1.0.11", - "ts-node": "^9.1.1", - "typescript": "^4.2.3" + "@types/node": "^16.18.96", + "@types/jsdom": "^21.1.6", + "@typescript-eslint/eslint-plugin": "^7.8.0", + "@typescript-eslint/parser": "^7.8.0", + "eslint": "^8.57.0", + "eslint-config-prettier": "^9.1.0", + "eslint-plugin-prettier": "^5.1.3", + "prettier": "^3.2.5", + "slash-up": "^1.4.2", + "typescript": "^5.4.5" } } diff --git a/src/character.ts b/src/character.ts index 55b3d38..20853c9 100644 --- a/src/character.ts +++ b/src/character.ts @@ -1,125 +1,136 @@ -import {parse as parseYaml, stringify as stringifyYaml} from "yaml" -import {readFile, writeFile, readdir} from 'fs/promises' -import {join} from 'path' +import { parse as parseYaml, stringify as stringifyYaml } from 'yaml'; +import { readFile, writeFile, readdir } from 'fs/promises'; +import { join } from 'path'; export interface GameCharacter { - health: number - armor?: number - unstable?: boolean - luck: number - luckSpecial?: string - experience: number - - Charm?: number - Cool?: number - Sharp?: number - Tough?: number - Weird?: number - - color: number - defaultFacePath: string - additionalFaces?: GameCharacterFace[] - activeFaceSets?: string[] - moves?: GameCharacterMove[] - improvementsTaken?: string[] - improvementsAvailable?: string[] - improvementsAdvanced?: string[] + health: number; + armor?: number; + unstable?: boolean; + luck: number; + luckSpecial?: string; + experience: number; + + Charm?: number; + Cool?: number; + Sharp?: number; + Tough?: number; + Weird?: number; + + color: number; + defaultFacePath: string; + additionalFaces?: GameCharacterFace[]; + activeFaceSets?: string[]; + moves?: GameCharacterMove[]; + improvementsTaken?: string[]; + improvementsAvailable?: string[]; + improvementsAdvanced?: string[]; } export enum GameAttribute { - Charm = "Charm", - Cool = "Cool", - Sharp = "Sharp", - Tough = "Tough", - Weird = "Weird", + Charm = 'Charm', + Cool = 'Cool', + Sharp = 'Sharp', + Tough = 'Tough', + Weird = 'Weird' } -export const GameAttributes = [GameAttribute.Charm, GameAttribute.Cool, GameAttribute.Sharp, GameAttribute.Tough, GameAttribute.Weird] as const +export const GameAttributes = [ + GameAttribute.Charm, + GameAttribute.Cool, + GameAttribute.Sharp, + GameAttribute.Tough, + GameAttribute.Weird +] as const; export interface GameCharacterMoveBase { - type?: string - name: string - summary?: string - description?: string + type?: string; + name: string; + summary?: string; + description?: string; } export interface GameCharacterPassiveMove extends GameCharacterMoveBase { - type?: "passive" + type?: 'passive'; } export interface GameCharacterRollableMove extends GameCharacterMoveBase { - type: "rollable" - attribute?: GameAttribute - bonus?: number - advanced?: boolean - onAdvanced?: string - onSuccess?: string - onMixed?: string - onMiss?: string + type: 'rollable'; + attribute?: GameAttribute; + bonus?: number; + advanced?: boolean; + onAdvanced?: string; + onSuccess?: string; + onMixed?: string; + onMiss?: string; } -export type GameCharacterMove = GameCharacterPassiveMove|GameCharacterRollableMove +export type GameCharacterMove = GameCharacterPassiveMove | GameCharacterRollableMove; export interface FaceConditionBase { - type: string - negated?: boolean + type: string; + negated?: boolean; } export interface FaceConditionStability extends FaceConditionBase { - type: "stable"|"unstable"|"dead" + type: 'stable' | 'unstable' | 'dead'; } export interface FaceConditionHealth extends FaceConditionBase { - type: "hpEq"|"hpGt"|"hpLt"|"hpGtEq"|"hpLtEq" - threshold: number + type: 'hpEq' | 'hpGt' | 'hpLt' | 'hpGtEq' | 'hpLtEq'; + threshold: number; } export interface FaceConditionHealthDelta extends FaceConditionBase { - type: "beingHealed"|"beingDamaged"|"healthSteady" + type: 'beingHealed' | 'beingDamaged' | 'healthSteady'; } export interface FaceConditionSet extends FaceConditionBase { - type: "faceSetActive" - set: string + type: 'faceSetActive'; + set: string; } -export type FaceCondition = FaceConditionStability|FaceConditionHealth|FaceConditionHealthDelta|FaceConditionSet +export type FaceCondition = FaceConditionStability | FaceConditionHealth | FaceConditionHealthDelta | FaceConditionSet; export interface GameCharacterFace { - path: string - conditions: FaceCondition[] + path: string; + conditions: FaceCondition[]; } -export const FaceSetIdentifier = /^[a-z0-9_]+$/ +export const FaceSetIdentifier = /^[a-z0-9_]+$/; export async function listCharacters(dataDir: string): Promise { - const list = await readdir(join(dataDir, "characters")) - return list.filter(s => s.endsWith(".yaml")).map(s => s.substring(0, s.length - 5)) + const list = await readdir(join(dataDir, 'characters')); + return list.filter((s) => s.endsWith('.yaml')).map((s) => s.substring(0, s.length - 5)); } export async function loadCharacter(dataDir: string, name: string): Promise { - const contents = await readFile(join(dataDir, "characters", name + ".yaml"), {encoding: "utf-8"}) - return parseYaml(contents) + const contents = await readFile(join(dataDir, 'characters', name + '.yaml'), { encoding: 'utf-8' }); + return parseYaml(contents); } export async function saveCharacter(dataDir: string, name: string, character: GameCharacter): Promise { - const contents = stringifyYaml(character) - return writeFile(join(dataDir, "characters", name + ".yaml"), contents) + const contents = stringifyYaml(character); + return writeFile(join(dataDir, 'characters', name + '.yaml'), contents, { encoding: 'utf-8' }); } export interface GameParty { - defaultCharacters: Record - activeParty: string[] - keeper: string + defaultCharacters: Record; + activeParty: string[]; + keeper: string; } export interface ReadonlyGameParty { - readonly defaultCharacters: Readonly> - readonly activeParty: readonly string[] - readonly keeper: string + readonly defaultCharacters: Readonly>; + readonly activeParty: readonly string[]; + readonly keeper: string; } export async function loadParty(dataDir: string): Promise { - const contents = await readFile(join(dataDir, "party.yaml"), {encoding: "utf-8"}) - return parseYaml(contents) + const contents = await readFile(join(dataDir, 'party.yaml'), { encoding: 'utf-8' }); + return parseYaml(contents); +} + +export async function saveParty(dataDir: string, party: GameParty): Promise { + const contents = stringifyYaml(party); + return writeFile(join(dataDir, 'party.yaml'), contents, { encoding: 'utf-8' }); } diff --git a/src/commands/base.ts b/src/commands/base.ts index eb8ec6c..b5b22a4 100644 --- a/src/commands/base.ts +++ b/src/commands/base.ts @@ -1,67 +1,68 @@ import { type ApplicationCommandOption, - type ApplicationCommandOptionAutocompletable, ApplicationCommandType, - type AutocompleteContext, type CommandContext, - CommandOptionType, type Message, type MessageFile, + type ApplicationCommandOptionAutocompletable, + type AutocompleteContext, + type CommandContext, + CommandOptionType, + type Message, SlashCommand, type SlashCommandOptions, type SlashCreator -} from "slash-create"; +} from 'slash-create'; import { type GameCharacter, type GameParty, listCharacters, loadCharacter, loadParty, - type ReadonlyGameParty, saveCharacter -} from "../character.js"; -import {type GameStatus, type GameStatusWithPortrait, renderStatus} from "../renderStatus.js"; -import {readFile} from "fs/promises"; -import {join} from "path"; -import {default as Sharp} from "sharp"; + saveCharacter +} from '../character.js'; +import { type GameStatusWithPortrait, renderStatus } from '../renderStatus.js'; +import { readFile } from 'fs/promises'; +import { join } from 'path'; +import { default as Sharp } from 'sharp'; -const dataDir = "../data" +const dataDir = '../data'; export const CharacterOptionTemplate = { - name: "character", - description: "The character(s) to operate on.", + name: 'character', + description: 'The character(s) to operate on.', required: false, type: CommandOptionType.STRING, autocomplete: true, - isCharacterOption: true, -} as const satisfies ApplicationCommandOptionAutocompletable & {isCharacterOption: true} + isCharacterOption: true +} as const satisfies ApplicationCommandOptionAutocompletable & { isCharacterOption: true }; export interface CharacterDataBase { - readonly success: boolean - readonly name: string + readonly success: boolean; + readonly name: string; } export interface LoadedCharacterData extends CharacterDataBase { - readonly success: true - readonly originalData: Readonly - newData?: GameCharacter + readonly success: true; + readonly originalData: Readonly; + newData?: GameCharacter; } export interface ErrorCharacterData extends CharacterDataBase { - readonly success: false - readonly error: unknown + readonly success: false; + readonly error: unknown; } -export interface PartyData { - readonly originalData: ReadonlyGameParty - readonly newData?: GameParty -} +export type GameCharacterData = LoadedCharacterData | ErrorCharacterData; -export type GameCharacterData = LoadedCharacterData|ErrorCharacterData +export interface CharacterStatusOptions { + dataDir: string; +} -const nameDelimiter = /\s*,(?:\s*,)*\s*/g +const nameDelimiter = /\s*,(?:\s*,)*\s*/g; -const ellipses = "..." -export function ellipsizeAt(s: string, length: number): string { +const ellipses = '...'; +export function trimAt(s: string, length: number): string { if (s.length <= length) { - return s + return s; } - return ellipses + s.substring(Math.max(s.length - (length - ellipses.length), 0)) + return ellipses + s.substring(Math.max(s.length - (length - ellipses.length), 0)); } const NORMAL_STATUS_HEIGHT = 524; @@ -71,262 +72,313 @@ const NORMAL_STATUS_WIDTH = 1446; const enableStackedForTwoCharacters = false; export abstract class AbstractCharacterStatusCommand extends SlashCommand { - readonly characterOptions: (ApplicationCommandOption & {isCharacterOption: true})[] + readonly characterOptions: (ApplicationCommandOption & { isCharacterOption: true })[]; + readonly dataDir: string; - constructor(creator: SlashCreator, opts: SlashCommandOptions) { + protected constructor(creator: SlashCreator, opts: SlashCommandOptions & CharacterStatusOptions) { super(creator, opts); - this.characterOptions = - (opts.options?.filter( - s => - "isCharacterOption" in s && - (s.isCharacterOption === true) && - s.type === CommandOptionType.STRING) - ?? []) as (ApplicationCommandOption & {isCharacterOption: true})[] + + this.dataDir = opts.dataDir; + this.characterOptions = (opts.options?.filter( + (s) => 'isCharacterOption' in s && s.isCharacterOption === true && s.type === CommandOptionType.STRING + ) ?? []) as (ApplicationCommandOption & { isCharacterOption: true })[]; } async autocomplete(ctx: AutocompleteContext): Promise { - const option = - this.characterOptions.find(o => o.name === ctx.focused) + const option = this.characterOptions.find((o) => o.name === ctx.focused); if (!option) { - return ctx.sendResults([]) + return ctx.sendResults([]); } - const party = await loadParty("../data") - const defaultCharacter = party.defaultCharacters[ctx.user.id] || null - const activeParty = new Set(Array.isArray(party.activeParty) ? party.activeParty : []) - const completedNames = (ctx.options[option.name] as string).trimStart().split(nameDelimiter) - const completingName = completedNames.pop()! - const completingLowercase = completingName.toLowerCase() - const characters = (await listCharacters("../data")) - .filter(s => - !completedNames.includes(s) && s.toLowerCase().includes(completingLowercase)) + const party = await loadParty(this.dataDir); + const defaultCharacter = party.defaultCharacters[ctx.user.id] || null; + const activeParty = new Set(Array.isArray(party.activeParty) ? party.activeParty : []); + const completedNames = (ctx.options[option.name] as string).trimStart().split(nameDelimiter); + const completingName = completedNames.pop()!; + const completingLowercase = completingName.toLowerCase(); + const characters = (await listCharacters(this.dataDir)) + .filter((s) => !completedNames.includes(s) && s.toLowerCase().includes(completingLowercase)) .sort((A, B) => { if (activeParty.has(A)) { if (activeParty.has(B)) { // fall through } else { - return -1 + return -1; } } else if (activeParty.has(B)) { - return 1 + return 1; } else { // fall through } if (A === defaultCharacter) { - return -1 + return -1; } else if (B === defaultCharacter) { - return 1 + return 1; } else { // fall through } - const a = A.toLowerCase() - const b = B.toLowerCase() + const a = A.toLowerCase(); + const b = B.toLowerCase(); if (a.startsWith(completingLowercase)) { if (b.startsWith(completingLowercase)) { // fall through } else { - return -1 + return -1; } } else if (b.startsWith(completingLowercase)) { - return 1 + return 1; } else { // fall through } if (b.length === a.length) { - return a.localeCompare(b) + return a.localeCompare(b); } else { - return b.length - a.length + return b.length - a.length; } - }).slice(0, 20) + }) + .slice(0, 20); - const unselectedParty = new Set(activeParty) - completedNames.forEach(entry => entry.includes("*") || unselectedParty.delete(entry)) - const partyName = unselectedParty.size > 0 ? `* (Active Party: ${Array.from(unselectedParty).join(", ")})` : "* (Active Party)" - const selectionPrefixName = completedNames.length > 0 ? completedNames.join(", ") + ", " : "" - const selectionPrefixValue = completedNames.length > 0 ? completedNames.join(",") + "," : "" - return ctx.sendResults([ - ...characters.map(s => ({ - name: ellipsizeAt(selectionPrefixName + s, 100), - value: ellipsizeAt(selectionPrefixValue + s, 100), - })), - ...(partyName.includes(completingName) ? [{name: ellipsizeAt(selectionPrefixName + partyName, 100), value: ellipsizeAt(selectionPrefixValue + "*", 100)}] : []), - ]) + const unselectedParty = new Set(activeParty); + const selectedElements = new Set(); + completedNames.forEach((entry) => { + const trimmed = entry.trim(); + if (trimmed === '*') { + for (const partyMember of activeParty) { + selectedElements.add(partyMember); + } + unselectedParty.clear(); + } else { + unselectedParty.delete(trimmed); + } + }); + const partyName = Array.from(unselectedParty).join(','); + const selectionPrefixValue = selectedElements.size > 0 ? Array.from(selectedElements).join(',') + ',' : ''; + return ctx.sendResults( + [ + ...characters.map((s) => selectionPrefixValue + s).slice(0, 20), + ...(unselectedParty.size > 0 && (partyName.includes(completingName) || completingName.trim() === '*') + ? [selectionPrefixValue + partyName] + : []) + ] + .filter((s) => s.length <= 100) + .map((s) => ({ name: s, value: s })) + ); } - async characterNames(options: Record): Promise<[option: string, names: Set][]> { - const [party, allCharacters] = - await Promise.all([loadParty("../data"), listCharacters("../data")]) - const activeParty = new Set(Array.isArray(party.activeParty) ? party.activeParty : []) - return this.characterOptions.map( - o => - options[o.name] && typeof options[o.name] === 'string' - ? [o.name, - new Set((options[o.name] as string).trim().split(nameDelimiter) - .flatMap(item => { - if (item.includes("*")) { - return Array.from(activeParty) + async characterNames( + options: Record, + partyPromise: Promise + ): Promise<[option: string, names: Set][]> { + const [party, allCharacters] = await Promise.all([partyPromise, listCharacters(this.dataDir)]); + const activeParty = new Set(Array.isArray(party.activeParty) ? party.activeParty : []); + return this.characterOptions.map((o) => + options[o.name] && typeof options[o.name] === 'string' + ? [ + o.name, + new Set( + (options[o.name] as string) + .trim() + .split(nameDelimiter) + .flatMap((item) => { + if (item === '*') { + return Array.from(activeParty); } else if (allCharacters.includes(item)) { - return [item] + return [item]; } else { - const found = allCharacters.find(v => item.toLowerCase() === v.toLowerCase()) + const found = allCharacters.find((v) => item.toLowerCase() === v.toLowerCase()); if (found) { - return [found] + return [found]; } else { - return [item] + return [item]; } } - }))] - : [o.name, new Set()]) + }) + ) + ] + : [o.name, new Set()] + ); } - abstract process(ctx: CommandContext, characters: Map): Promise< - readonly [string, LoadedCharacterData[]] - |readonly [string, LoadedCharacterData] - |readonly LoadedCharacterData[] - |LoadedCharacterData - |string> + abstract process( + ctx: CommandContext, + data: { characters: Map; party: GameParty } + ): Promise< + | readonly [string, LoadedCharacterData[]] + | readonly [string, LoadedCharacterData] + | readonly LoadedCharacterData[] + | LoadedCharacterData + | string + >; - async run(ctx: CommandContext): Promise { - await ctx.defer() - let svg = readFile("../data/theme.svg", {encoding: "utf-8"}) + async loadCharacters(names: Iterable): Promise { + return Promise.all( + Array.from(names).map((name) => + loadCharacter(dataDir, name) + .then((c) => ({ name, success: true, originalData: c })) + .catch((e) => ({ name, success: false, error: e })) + ) + ); + } - const characterNames = await this.characterNames(ctx.options) - const neededCharacters: Set = new Set() - for (const [_, names] of characterNames) { + async run(ctx: CommandContext): Promise { + await ctx.defer(); + const svg = readFile(join(this.dataDir, 'theme.svg'), { encoding: 'utf-8' }); + const party = loadParty(this.dataDir); + const characterNames = await this.characterNames(ctx.options, party); + const neededCharacters: Set = new Set(); + for (const [, names] of characterNames) { for (const name of names) { - neededCharacters.add(name) + neededCharacters.add(name); } } - const loadedCharacters = await Promise.all(Array.from(neededCharacters).map(name => - loadCharacter(dataDir, name) - .then(c => ({name, success: true, originalData: c})) - .catch(e => ({name, success: false, error: e})))) - const characterMap = new Map() + const loadedCharacters = await this.loadCharacters(neededCharacters); + const characterMap = new Map(); for (const character of loadedCharacters) { - characterMap.set(character.name, character) + characterMap.set(character.name, character); } - const optionMap = new Map() + const optionMap = new Map(); for (const [option, names] of characterNames) { - optionMap.set(option, Array.from(names).map(x => characterMap.get(x)!)) + optionMap.set( + option, + Array.from(names).map((x) => characterMap.get(x)!) + ); } - const result = await this.process(ctx, optionMap) - let message: string|null = null, statuses: LoadedCharacterData[] = [] + const result = await this.process(ctx, { party: await party, characters: optionMap }); + let message: string | null = null, + statuses: LoadedCharacterData[] = []; if (Array.isArray(result)) { - if (result.length === 2 && typeof result[0] === "string") { - message = result[0] + if (result.length === 2 && typeof result[0] === 'string') { + message = result[0]; if (Array.isArray(result[1])) { - statuses = result[1] + statuses = result[1]; } else { - statuses = [result[1]] + statuses = [result[1]]; } } else { - statuses = result + statuses = result; } - } else if (typeof result === "string") { - message = result + } else if (typeof result === 'string') { + message = result; } else { - statuses = [result as LoadedCharacterData] + statuses = [result as LoadedCharacterData]; } - const deltas = - await Promise.all(Array.from(new Set(statuses)).filter(s => loadedCharacters.includes(s)).slice(0, 10).map(s => characterDataDelta(s))) - const images = await Promise.all(deltas.map(async s => renderStatus(await svg, s))) - const sharps = images.map(b => Sharp(b)) - const metadatas = await Promise.all(sharps.map(s => s.metadata())) - let resultImage: Buffer|null = null + const deltas = await Promise.all( + Array.from(new Set(statuses)) + .filter((s) => loadedCharacters.includes(s)) + .slice(0, 10) + .map((s) => characterDataDelta(s, this.dataDir)) + ); + const images = await Promise.all(deltas.map(async (s) => renderStatus(await svg, s))); + const sharps = images.map((b) => Sharp(b)); + const metadatas = await Promise.all(sharps.map((s) => s.metadata())); + let resultImage: Buffer | null; if (images.length === 0) { - resultImage = null + resultImage = null; } else if (images.length === 1) { - resultImage = images[0] + resultImage = images[0]; } else if (enableStackedForTwoCharacters && images.length === 2) { - const totalHeight = metadatas.reduce((x, y) => x + (y.height ?? NORMAL_STATUS_HEIGHT), 0) - const maxWidth = metadatas.reduce((x, y) => Math.max(x, y.width ?? NORMAL_STATUS_WIDTH), 0) + const totalHeight = metadatas.reduce((x, y) => x + (y.height ?? NORMAL_STATUS_HEIGHT), 0); + const maxWidth = metadatas.reduce((x, y) => Math.max(x, y.width ?? NORMAL_STATUS_WIDTH), 0); const result = Sharp({ create: { - background: "#00000000", + background: '#00000000', channels: 4, height: totalHeight, - width: maxWidth, + width: maxWidth } - }) - result.composite([{ - input: images[0], - left: 0, - top: 0, - }, { - input: images[1], - left: 0, - top: metadatas[0].height ?? NORMAL_STATUS_HEIGHT, - }]) + }); + result.composite([ + { + input: images[0], + left: 0, + top: 0 + }, + { + input: images[1], + left: 0, + top: metadatas[0].height ?? NORMAL_STATUS_HEIGHT + } + ]); - resultImage = await result.png().toBuffer() + resultImage = await result.png().toBuffer(); } else { - let maxWidth: [number, number] = [metadatas[0].width ?? NORMAL_STATUS_WIDTH, 0], + const maxWidth: [number, number] = [metadatas[0].width ?? NORMAL_STATUS_WIDTH, 0], totalHeight: [number, number] = [metadatas[0].height ?? NORMAL_STATUS_HEIGHT, 0], - lastHeight: [number, number] = [metadatas[0].height ?? NORMAL_STATUS_HEIGHT, 0] - const topCoordinates: number[] = new Array(metadatas.length) - topCoordinates[0] = 0 + lastHeight: [number, number] = [metadatas[0].height ?? NORMAL_STATUS_HEIGHT, 0]; + const topCoordinates: number[] = new Array(metadatas.length); + topCoordinates[0] = 0; for (let i = 1; i < metadatas.length; i += 1) { - const polarity = i % 2 - const reversePolarity = 1 - polarity - const width = metadatas[i].width ?? NORMAL_STATUS_WIDTH - const height = metadatas[i].height ?? NORMAL_STATUS_HEIGHT - maxWidth[polarity] = Math.max(maxWidth[polarity], width) - lastHeight[polarity] = height - const top = - Math.max(totalHeight[polarity], totalHeight[reversePolarity] - (lastHeight[reversePolarity] / 2)) - topCoordinates[i] = top - totalHeight[polarity] = top + height + const polarity = i % 2; + const reversePolarity = 1 - polarity; + const width = metadatas[i].width ?? NORMAL_STATUS_WIDTH; + const height = metadatas[i].height ?? NORMAL_STATUS_HEIGHT; + maxWidth[polarity] = Math.max(maxWidth[polarity], width); + lastHeight[polarity] = height; + const top = Math.max(totalHeight[polarity], totalHeight[reversePolarity] - lastHeight[reversePolarity] / 2); + topCoordinates[i] = top; + totalHeight[polarity] = top + height; } const result = Sharp({ create: { - background: "#00000000", + background: '#00000000', channels: 4, height: Math.max(totalHeight[0], totalHeight[1]), - width: maxWidth[0] + maxWidth[1], + width: maxWidth[0] + maxWidth[1] } - }) - result.composite(images.map((buf, i) => { - return { - input: buf, - top: topCoordinates[i], - left: i % 2 === 0 - ? maxWidth[0] - (metadatas[i].width ?? NORMAL_STATUS_WIDTH) - : maxWidth[0], - } - })); + }); + result.composite( + images.map((buf, i) => { + return { + input: buf, + top: topCoordinates[i], + left: i % 2 === 0 ? maxWidth[0] - (metadatas[i].width ?? NORMAL_STATUS_WIDTH) : maxWidth[0] + }; + }) + ); - resultImage = await result.png().toBuffer() + resultImage = await result.png().toBuffer(); } - const pendingSaves: Promise[] = [] + const pendingSaves: Promise[] = []; for (const character of loadedCharacters) { if (!character.success) { - continue + continue; } if (!character.newData) { - continue + continue; } - pendingSaves.push(saveCharacter("../data", character.name, character.newData)) + pendingSaves.push(saveCharacter(this.dataDir, character.name, character.newData)); } - await Promise.all(pendingSaves) + await Promise.all(pendingSaves); return ctx.send({ content: message ?? undefined, - attachments: resultImage ? [{ - id: 0, - name: "status.png", - description: ellipsizeAt(deltas.map(k => k.description).join(" "), 1024), - }] : [], - file: resultImage ? [{ - name: "status.png", - file: resultImage, - }] : [], - }) + attachments: resultImage + ? [ + { + id: 0, + name: 'status.png', + description: trimAt(deltas.map((k) => k.description).join(' '), 1024) + } + ] + : [], + files: resultImage + ? [ + { + name: 'status.png', + file: resultImage + } + ] + : [] + }); } } -export async function characterDataDelta(c: LoadedCharacterData): Promise { - const oldData = c.originalData - const newData = c.newData ?? oldData - const face = readFile(join("../data/images/", c.name, newData.defaultFacePath)) - const result = { +export async function characterDataDelta( + c: LoadedCharacterData, + dataDir: string +): Promise { + const oldData = c.originalData; + const newData = c.newData ?? oldData; + const face = readFile(join(dataDir, 'images', c.name, newData.defaultFacePath)); + const result = { experienceDelta: (newData.experience ?? 0) - (oldData.experience ?? 0), experience: newData.experience ?? 0, healthDelta: (newData.health ?? 8) - (oldData.health ?? 8), @@ -334,27 +386,28 @@ export async function characterDataDelta(c: LoadedCharacterData): Promise 0 ? ` after healing ${result.healthDelta} Harm` : result.healthDelta < 0 - ? ` after taking ${-result.healthDelta} Harm` : ""}; ${ - result.experience} EXP${result.experience >= 5 ? ", ready to level up" : ""}${ - result.experienceDelta > 0 - ? ` after gaining ${result.experienceDelta} EXP` - : result.experienceDelta < 0 - ? ` after losing ${-result.experienceDelta}` - : ""}; ${ - result.luck} Luck${ - result.luckDelta > 0 - ? ` after gaining ${result.luckDelta} Luck` - : result.luckDelta < 0 - ? ` after spending ${-result.luckDelta} Luck` - : ""}.` - } + ? ` after taking ${-result.healthDelta} Harm` + : '' + }; ${result.experience} EXP${result.experience >= 5 ? ', ready to level up' : ''}${ + result.experienceDelta > 0 + ? ` after gaining ${result.experienceDelta} EXP` + : result.experienceDelta < 0 + ? ` after losing ${-result.experienceDelta}` + : '' + }; ${result.luck} Luck${ + result.luckDelta > 0 + ? ` after gaining ${result.luckDelta} Luck` + : result.luckDelta < 0 + ? ` after spending ${-result.luckDelta} Luck` + : '' + }.` + }; } diff --git a/src/commands/experience.ts b/src/commands/experience.ts index 858bbd3..06ba0b0 100644 --- a/src/commands/experience.ts +++ b/src/commands/experience.ts @@ -1,65 +1,72 @@ -import { - ApplicationCommandType, - AutocompleteContext, type CommandContext, - CommandOptionType, Message, - SlashCommand, - type SlashCreator -} from "slash-create"; -import {type GameCharacter, listCharacters, loadCharacter, saveCharacter} from "../character.js"; -import {renderStatus} from "../renderStatus.js"; -import {readFile} from "fs/promises"; -import {join} from "path"; +import { ApplicationCommandType, type CommandContext, CommandOptionType, type SlashCreator } from 'slash-create'; import { AbstractCharacterStatusCommand, CharacterOptionTemplate, + type CharacterStatusOptions, type GameCharacterData, type LoadedCharacterData -} from "./base.js"; +} from './base.js'; export class ExperienceCharacterCommand extends AbstractCharacterStatusCommand { - constructor(creator: SlashCreator) { + constructor(creator: SlashCreator, opts: CharacterStatusOptions) { super(creator, { - name: "experience", - description: "Modifies the EXP total of the given character(s).", + ...opts, + name: 'experience', + description: 'Modifies the EXP total of the given character(s).', type: ApplicationCommandType.CHAT_INPUT, guildIDs: process.env.DEVELOPMENT_GUILD_ID, options: [ { ...CharacterOptionTemplate, - name: "character", - description: "The name of the character(s) to grant EXP to or remove EXP from.", - required: true, + name: 'character', + description: 'The name of the character(s) to grant EXP to or remove EXP from.', + required: true }, { type: CommandOptionType.INTEGER, - name: "delta", - description: "The amount of EXP to apply to the character(s) (default +1).", + name: 'delta', + description: 'The amount of EXP to apply to the character(s) (default +1).', max_value: 25, min_value: -25, - required: false, - }, + required: false + } ] }); } - async process(ctx: CommandContext, characters: Map): Promise { - const delta = ctx.options["delta"] ?? 1 - const description: string[] = [] - const result: LoadedCharacterData[] = [] - for (const character of characters.get("character")!) { + async process( + ctx: CommandContext, + { characters }: { characters: Map } + ): Promise< + | readonly [string, LoadedCharacterData[]] + | readonly [string, LoadedCharacterData] + | readonly LoadedCharacterData[] + | LoadedCharacterData + | string + > { + const delta = ctx.options['delta'] ?? 1; + const description: string[] = []; + const result: LoadedCharacterData[] = []; + for (const character of characters.get('character')!) { if (!character.success) { - description.push(`**${character.name}** ${delta >= 0 ? "gained" : "lost"} ${Math.abs(delta)} EXP${delta >= 0 ? "!" : "."}`) - continue + description.push( + `**${character.name}** ${delta >= 0 ? 'gained' : 'lost'} ${Math.abs(delta)} EXP${delta >= 0 ? '!' : '.'}` + ); + continue; } character.newData = { - ...character.newData ?? character.originalData - } - const oldLevels = Math.floor(character.newData.experience / 5) - character.newData.experience = Math.max(0, (character.newData.experience ?? 0) + delta) - const levels = Math.floor(character.newData.experience / 5) - result.push(character) - description.push(`**${character.name}** ${delta >= 0 ? "gained" : "lost"} ${Math.abs(delta)} EXP${delta >= 0 ? "!" : "."}${levels > oldLevels ? " ***Level up!***" : ""}`) + ...(character.newData ?? character.originalData) + }; + const oldLevels = Math.floor(character.newData.experience / 5); + character.newData.experience = Math.max(0, (character.newData.experience ?? 0) + delta); + const levels = Math.floor(character.newData.experience / 5); + result.push(character); + description.push( + `**${character.name}** ${delta >= 0 ? 'gained' : 'lost'} ${Math.abs(delta)} EXP${delta >= 0 ? '!' : '.'}${ + levels > oldLevels ? ' ***Level up!***' : '' + }` + ); } - return [description.join("\n"), result] + return [description.join('\n'), result]; } } diff --git a/src/commands/harm.ts b/src/commands/harm.ts index b32a83c..702250b 100644 --- a/src/commands/harm.ts +++ b/src/commands/harm.ts @@ -1,88 +1,95 @@ -import { - ApplicationCommandType, - AutocompleteContext, - type CommandContext, - CommandOptionType, - Message, - SlashCommand, - type SlashCreator -} from "slash-create"; -import {type GameCharacter, listCharacters, loadCharacter, saveCharacter} from "../character.js"; -import {renderStatus} from "../renderStatus.js"; -import {readFile} from "fs/promises"; -import {join} from "path"; +import { ApplicationCommandType, type CommandContext, CommandOptionType, type SlashCreator } from 'slash-create'; import { AbstractCharacterStatusCommand, CharacterOptionTemplate, + type CharacterStatusOptions, type GameCharacterData, type LoadedCharacterData -} from "./base.js"; +} from './base.js'; export class HarmCharacterCommand extends AbstractCharacterStatusCommand { - constructor(creator: SlashCreator) { + constructor(creator: SlashCreator, opts: CharacterStatusOptions) { super(creator, { - name: "harm", - description: "Harms the given character(s).", + ...opts, + name: 'harm', + description: 'Harms the given character(s).', type: ApplicationCommandType.CHAT_INPUT, guildIDs: process.env.DEVELOPMENT_GUILD_ID, options: [ { ...CharacterOptionTemplate, - description: "The name of the character(s) to harm.", - required: true, + description: 'The name of the character(s) to harm.', + required: true }, { type: CommandOptionType.INTEGER, - name: "damage", - description: "The amount of harm to deal to the character(s).", + name: 'damage', + description: 'The amount of harm to deal to the character(s).', max_value: 99, min_value: 0, - required: true, + required: true }, { type: CommandOptionType.BOOLEAN, - name: "piercing", - description: "If set, ignores any armor the character(s) may have.", + name: 'piercing', + description: 'If set, ignores any armor the character(s) may have.' }, { type: CommandOptionType.BOOLEAN, - name: "destabilize", - description: "True to force unstable, False to never set unstable. Default based on remaining health.", - required: false, + name: 'destabilize', + description: 'True to force unstable, False to never set unstable. Default based on remaining health.', + required: false } ] }); } - async process(ctx: CommandContext, characters: Map): Promise { - const baseDamage: number = ctx.options["damage"] - const piercing: boolean = ctx.options["piercing"] ?? false - const makeUnstable: boolean|null = ctx.options["destabilize"] ?? null - const description: string[] = [] - const result: LoadedCharacterData[] = [] - for (const character of characters.get("character")!) { + async process( + ctx: CommandContext, + { characters }: { characters: Map } + ): Promise< + | readonly [string, LoadedCharacterData[]] + | readonly [string, LoadedCharacterData] + | readonly LoadedCharacterData[] + | LoadedCharacterData + | string + > { + const baseDamage: number = ctx.options['damage']; + const piercing: boolean = ctx.options['piercing'] ?? false; + const makeUnstable: boolean | null = ctx.options['destabilize'] ?? null; + const description: string[] = []; + const result: LoadedCharacterData[] = []; + for (const character of characters.get('character')!) { if (!character.success) { - description.push(`**${character.name}** took ${baseDamage} Harm${piercing ? " ignore-armour" : ""}${baseDamage > 0 ? "!" : "."}${makeUnstable ? " ***Unstable!***" : ""}`) - continue + description.push( + `**${character.name}** took ${baseDamage} Harm${piercing ? ' ignore-armour' : ''}${ + baseDamage > 0 ? '!' : '.' + }${makeUnstable ? ' ***Unstable!***' : ''}` + ); + continue; } character.newData = { ...(character.newData ?? character.originalData) - } - const effectiveDamage = Math.max(0, baseDamage - (piercing ? 0 : (character.newData.armor ?? 0))) - const blocked = Math.max(0, baseDamage - effectiveDamage) - const wasUnstable = character.newData.unstable ?? false - const wasAlive = (character.newData.health ?? 8) > 0 - character.newData.health = Math.max(0, (character.newData.health ?? 8) - effectiveDamage) + }; + const effectiveDamage = Math.max(0, baseDamage - (piercing ? 0 : character.newData.armor ?? 0)); + const blocked = Math.max(0, baseDamage - effectiveDamage); + const wasUnstable = character.newData.unstable ?? false; + const wasAlive = (character.newData.health ?? 8) > 0; + character.newData.health = Math.max(0, (character.newData.health ?? 8) - effectiveDamage); if ((makeUnstable === null && character.newData.health <= 4) || makeUnstable) { - character.newData.unstable = true + character.newData.unstable = true; } - const isUnstable = character.newData.unstable ?? false - const isAlive = character.newData.health > 0 - description.push(`**${character.name}** took ${effectiveDamage} Harm${ - piercing ? " ignore-armour" : blocked > 0 ? ` (${blocked} blocked)` : ""}${effectiveDamage > 0 ? "!" : "."}${ - wasAlive && !isAlive ? " ***Defeated...***" : !wasUnstable && isUnstable ? " ***Unstable!***" : ""}`) - result.push(character) + const isUnstable = character.newData.unstable ?? false; + const isAlive = character.newData.health > 0; + description.push( + `**${character.name}** took ${effectiveDamage} Harm${ + piercing ? ' ignore-armour' : blocked > 0 ? ` (${blocked} blocked)` : '' + }${effectiveDamage > 0 ? '!' : '.'}${ + wasAlive && !isAlive ? ' ***Defeated...***' : !wasUnstable && isUnstable ? ' ***Unstable!***' : '' + }` + ); + result.push(character); } - return [description.join("\n"), result] + return [description.join('\n'), result]; } } diff --git a/src/commands/heal.ts b/src/commands/heal.ts index 5e0ad1b..2899660 100644 --- a/src/commands/heal.ts +++ b/src/commands/heal.ts @@ -1,77 +1,85 @@ -import { - ApplicationCommandType, - AutocompleteContext, type CommandContext, - CommandOptionType, Message, - SlashCommand, - type SlashCreator -} from "slash-create"; -import {type GameCharacter, listCharacters, loadCharacter, saveCharacter} from "../character.js"; -import {renderStatus} from "../renderStatus.js"; -import {readFile} from "fs/promises"; -import {join} from "path"; +import { ApplicationCommandType, type CommandContext, CommandOptionType, type SlashCreator } from 'slash-create'; import { AbstractCharacterStatusCommand, CharacterOptionTemplate, + type CharacterStatusOptions, type GameCharacterData, type LoadedCharacterData -} from "./base.js"; +} from './base.js'; export class HealCharacterCommand extends AbstractCharacterStatusCommand { - constructor(creator: SlashCreator) { + constructor(creator: SlashCreator, opts: CharacterStatusOptions) { super(creator, { - name: "heal", - description: "Heals the given character(s).", + ...opts, + name: 'heal', + description: 'Heals the given character(s).', type: ApplicationCommandType.CHAT_INPUT, guildIDs: process.env.DEVELOPMENT_GUILD_ID, options: [ { ...CharacterOptionTemplate, - name: "character", - description: "The name of the character(s) to heal.", - required: true, + name: 'character', + description: 'The name of the character(s) to heal.', + required: true }, { type: CommandOptionType.INTEGER, - name: "healing", - description: "The amount of healing to apply to the character(s).", + name: 'healing', + description: 'The amount of healing to apply to the character(s).', max_value: 99, min_value: 0, - required: true, + required: true }, { type: CommandOptionType.BOOLEAN, - name: "stabilize", - description: "If true, repairs the unstable status of the character(s).", - }, + name: 'stabilize', + description: 'If true, repairs the unstable status of the character(s).' + } ] }); } - async process(ctx: CommandContext, characters: Map): Promise { - const healing: number = ctx.options["healing"] - const stabilize: boolean = ctx.options["stabilize"] ?? false - const description: string[] = [] - const result: LoadedCharacterData[] = [] - for (const character of characters.get("character")!) { + async process( + ctx: CommandContext, + { characters }: { characters: Map } + ): Promise< + | readonly [string, LoadedCharacterData[]] + | readonly [string, LoadedCharacterData] + | readonly LoadedCharacterData[] + | LoadedCharacterData + | string + > { + const healing: number = ctx.options['healing']; + const stabilize: boolean = ctx.options['stabilize'] ?? false; + const description: string[] = []; + const result: LoadedCharacterData[] = []; + for (const character of characters.get('character')!) { if (!character.success) { - description.push(`**${character.name}** healed ${healing} Harm${healing > 0 ? "!" : "."}${stabilize ? " ***Stabilized!***" : ""}`) - continue + description.push( + `**${character.name}** healed ${healing} Harm${healing > 0 ? '!' : '.'}${ + stabilize ? ' ***Stabilized!***' : '' + }` + ); + continue; } character.newData = { ...(character.newData ?? character.originalData) - } - const wasUnstable = character.newData.unstable ?? false - const wasAlive = (character.newData.health ?? 8) > 0 - character.newData.health = Math.min((character.newData.health ?? 8) + healing, 8) + }; + const wasUnstable = character.newData.unstable ?? false; + const wasAlive = (character.newData.health ?? 8) > 0; + character.newData.health = Math.min((character.newData.health ?? 8) + healing, 8); if (stabilize) { - character.newData.unstable = false + character.newData.unstable = false; } - const isUnstable = character.newData.unstable ?? false - const isAlive = character.newData.health > 0 - description.push(`**${character.name}** healed ${healing} Harm${healing > 0 ? "!" : "."}${ - !wasAlive && isAlive ? " ***Revived!***" : wasUnstable && !isUnstable ? " ***Stabilized!***" : ""}`) - result.push(character) + const isUnstable = character.newData.unstable ?? false; + const isAlive = character.newData.health > 0; + description.push( + `**${character.name}** healed ${healing} Harm${healing > 0 ? '!' : '.'}${ + !wasAlive && isAlive ? ' ***Revived!***' : wasUnstable && !isUnstable ? ' ***Stabilized!***' : '' + }` + ); + result.push(character); } - return [description.join("\n"), result] + return [description.join('\n'), result]; } } diff --git a/src/commands/luck.ts b/src/commands/luck.ts index c188361..2c92308 100644 --- a/src/commands/luck.ts +++ b/src/commands/luck.ts @@ -1,66 +1,72 @@ -import { - ApplicationCommandType, - AutocompleteContext, type CommandContext, - CommandOptionType, Message, - SlashCommand, - type SlashCreator -} from "slash-create"; -import {type GameCharacter, listCharacters, loadCharacter, saveCharacter} from "../character.js"; -import {renderStatus} from "../renderStatus.js"; -import {readFile} from "fs/promises"; -import {join} from "path"; +import { ApplicationCommandType, type CommandContext, CommandOptionType, type SlashCreator } from 'slash-create'; import { AbstractCharacterStatusCommand, CharacterOptionTemplate, + type CharacterStatusOptions, type GameCharacterData, type LoadedCharacterData -} from "./base.js"; +} from './base.js'; export class LuckCharacterCommand extends AbstractCharacterStatusCommand { - constructor(creator: SlashCreator) { + constructor(creator: SlashCreator, opts: CharacterStatusOptions) { super(creator, { - name: "luck", - description: "Modifies the luck of the given character(s).", + ...opts, + name: 'luck', + description: 'Modifies the luck of the given character(s).', type: ApplicationCommandType.CHAT_INPUT, guildIDs: process.env.DEVELOPMENT_GUILD_ID, options: [ { ...CharacterOptionTemplate, - name: "character", - description: "The name of the character(s) to grant luck to or remove luck from.", - required: true, + name: 'character', + description: 'The name of the character(s) to grant luck to or remove luck from.', + required: true }, { type: CommandOptionType.INTEGER, - name: "delta", - description: "The amount of luck to apply to the character(s) (default -1).", + name: 'delta', + description: 'The amount of luck to apply to the character(s) (default -1).', max_value: 7, min_value: -7, - required: false, - }, + required: false + } ] }); } - async process(ctx: CommandContext, characters: Map): Promise { - const delta: number = ctx.options["delta"] - const description: string[] = [] - const result: LoadedCharacterData[] = [] - for (const character of characters.get("character")!) { + async process( + ctx: CommandContext, + { characters }: { characters: Map } + ): Promise< + | readonly [string, LoadedCharacterData[]] + | readonly [string, LoadedCharacterData] + | readonly LoadedCharacterData[] + | LoadedCharacterData + | string + > { + const delta: number = ctx.options['delta'] ?? -1; + const description: string[] = []; + const result: LoadedCharacterData[] = []; + for (const character of characters.get('character')!) { if (!character.success) { - description.push(`**${character.name}** ${delta > 0 ? "recovered" : "spent"} ${Math.abs(delta)} Luck${delta !== 0 ? "!" : "."}`) - continue + description.push( + `**${character.name}** ${delta > 0 ? 'recovered' : 'spent'} ${Math.abs(delta)} Luck${delta !== 0 ? '!' : '.'}` + ); + continue; } character.newData = { ...(character.newData ?? character.originalData) - } - const wasDoomed = (character.newData.luck ?? 7) === 0 - character.newData.luck = Math.max(0, Math.min((character.newData.luck ?? 7) + delta, 7)) - const isDoomed = character.newData.luck === 0 - description.push(`**${character.name}** ${delta > 0 ? "recovered" : "spent"} ${Math.abs(delta)} Luck${delta !== 0 ? "!" : "."}${ - !wasDoomed && isDoomed ? " ***Doomed...***" : wasDoomed && !isDoomed ? " ***Fate averted!***" : ""}`) - result.push(character) + }; + const wasDoomed = (character.newData.luck ?? 7) === 0; + character.newData.luck = Math.max(0, Math.min((character.newData.luck ?? 7) + delta, 7)); + const isDoomed = character.newData.luck === 0; + description.push( + `**${character.name}** ${delta > 0 ? 'recovered' : 'spent'} ${Math.abs(delta)} Luck${delta !== 0 ? '!' : '.'}${ + !wasDoomed && isDoomed ? ' ***Doomed...***' : wasDoomed && !isDoomed ? ' ***Fate averted!***' : '' + }` + ); + result.push(character); } - return [description.join("\n"), result] + return [description.join('\n'), result]; } } diff --git a/src/commands/party.ts b/src/commands/party.ts new file mode 100644 index 0000000..42a00db --- /dev/null +++ b/src/commands/party.ts @@ -0,0 +1,88 @@ +import { + AbstractCharacterStatusCommand, + CharacterOptionTemplate, + type CharacterStatusOptions, + type GameCharacterData, + type LoadedCharacterData +} from './base.js'; +import { ApplicationCommandType, type CommandContext, CommandOptionType, type SlashCreator } from 'slash-create'; +import {type GameParty, saveParty} from '../character.js'; + +export class PartyCommand extends AbstractCharacterStatusCommand { + constructor(creator: SlashCreator, opts: CharacterStatusOptions) { + super(creator, { + ...opts, + name: 'party', + description: 'Gets or sets the current party list.', + type: ApplicationCommandType.CHAT_INPUT, + guildIDs: process.env.DEVELOPMENT_GUILD_ID, + options: [ + { + ...CharacterOptionTemplate, + name: 'characters', + description: 'The name of the character(s) to become the current party. If not set, shows the party instead.', + required: false + }, + { + type: CommandOptionType.BOOLEAN, + name: 'replace', + description: + 'If true, the party is being entirely replaced, so show the character list instead of the delta.', + required: false + } + ] + }); + } + + async process( + ctx: CommandContext, + { characters, party }: { characters: Map; party: GameParty } + ): Promise< + | readonly [string, LoadedCharacterData[]] + | readonly [string, LoadedCharacterData] + | readonly LoadedCharacterData[] + | LoadedCharacterData + | string + > { + const replace: boolean | undefined = ctx.options.replace; + const oldPartyMemberNames = party.activeParty; + const newPartyMemberData = characters.get('party'); + if (!newPartyMemberData || newPartyMemberData.length === 0) { + return [ + `The current active party is:\n **${oldPartyMemberNames.join('**\n **')}**`, + (await this.loadCharacters(oldPartyMemberNames)).flatMap((c) => (c.success ? [c] : [])) + ]; + } + const newPartyMemberNames = newPartyMemberData.map(c => c.name) + await saveParty(this.dataDir, { + ...party, + activeParty: newPartyMemberNames, + }) + const oldPartySet = new Set(oldPartyMemberNames); + const newPartySet = new Set(newPartyMemberNames); + const leftSet = new Set(); + for (const member of oldPartySet) { + if (!newPartySet.has(member)) { + leftSet.add(member); + } + } + const joinedSet = new Set(); + for (const member of newPartySet) { + if (!oldPartySet.has(member)) { + joinedSet.add(member); + } + } + const deltas = [ + ...Array.from(joinedSet).map((c) => `**${c}** joined the party.`), + ...Array.from(leftSet).map((c) => `**${c}** left the party.`) + ]; + if (replace || deltas.length === 0 || (replace === false && deltas.length > newPartyMemberNames.length)) { + return [ + `The current active party is:\n **${newPartyMemberData.map((c) => c.name).join('**\n **')}**`, + newPartyMemberData.flatMap((c) => (c.success ? [c] : [])) + ]; + } else { + return [deltas.join('\n'), newPartyMemberData.flatMap((c) => (c.success ? [c] : []))]; + } + } +} diff --git a/src/commands/status.ts b/src/commands/status.ts index 16cfb13..7f6cbf4 100644 --- a/src/commands/status.ts +++ b/src/commands/status.ts @@ -1,36 +1,41 @@ -import { - ApplicationCommandType, - type CommandContext, - CommandOptionType, - SlashCommand, - type SlashCreator -} from "slash-create"; +import { ApplicationCommandType, type CommandContext, type SlashCreator } from 'slash-create'; import { CharacterOptionTemplate, AbstractCharacterStatusCommand, type GameCharacterData, - type LoadedCharacterData -} from "./base.js"; + type LoadedCharacterData, + type CharacterStatusOptions +} from './base.js'; export class CharacterStatusCommand extends AbstractCharacterStatusCommand { - constructor(creator: SlashCreator) { + constructor(creator: SlashCreator, opts: CharacterStatusOptions) { super(creator, { - name: "status", - description: "Gets the status of the given character(s).", + ...opts, + name: 'status', + description: 'Gets the status of the given character(s).', type: ApplicationCommandType.CHAT_INPUT, guildIDs: process.env.DEVELOPMENT_GUILD_ID, options: [ { ...CharacterOptionTemplate, - name: "character", - description: "The name of the character(s) to get the status of.", - required: true, - }, + name: 'character', + description: 'The name of the character(s) to get the status of.', + required: true + } ] }); } - async process(ctx: CommandContext, characters: Map): Promise { - return characters.get("character")!.flatMap((x) => x.success ? [x] : []); + async process( + _ctx: CommandContext, + { characters }: { characters: Map } + ): Promise< + | readonly [string, LoadedCharacterData[]] + | readonly [string, LoadedCharacterData] + | readonly LoadedCharacterData[] + | LoadedCharacterData + | string + > { + return characters.get('character')!.flatMap((x) => (x.success ? [x] : [])); } } diff --git a/src/index.ts b/src/index.ts index ac6032b..ba93d06 100644 --- a/src/index.ts +++ b/src/index.ts @@ -1,13 +1,13 @@ import dotenv from 'dotenv'; import { SlashCreator, FastifyServer } from 'slash-create'; import path from 'path'; -import {fastify} from "fastify"; -import {HealCharacterCommand} from "./commands/heal.js"; -import {HarmCharacterCommand} from "./commands/harm.js"; -import {ExperienceCharacterCommand} from "./commands/experience.js"; -import {LuckCharacterCommand} from "./commands/luck.js"; -import {AbstractCharacterStatusCommand} from "./commands/base.js"; -import {CharacterStatusCommand} from "./commands/status.js"; +import { fastify } from 'fastify'; +import { HealCharacterCommand } from './commands/heal.js'; +import { HarmCharacterCommand } from './commands/harm.js'; +import { ExperienceCharacterCommand } from './commands/experience.js'; +import { LuckCharacterCommand } from './commands/luck.js'; +import { CharacterStatusCommand } from './commands/status.js'; +import { PartyCommand } from './commands/party.js'; let dotenvPath = path.join(process.cwd(), '.env'); if (path.parse(process.cwd()).name === 'dist') dotenvPath = path.join(process.cwd(), '..', '.env'); @@ -16,11 +16,11 @@ dotenv.config({ path: dotenvPath }); const creator = new SlashCreator({ applicationID: process.env.DISCORD_APP_ID!, - publicKey: process.env.DISCORD_PUBLIC_KEY, - token: process.env.DISCORD_BOT_TOKEN, - serverPort: parseInt(process.env.PORT ?? "0", 10) || 8020, - serverHost: '0.0.0.0', - endpointPath: "/interactions", + publicKey: process.env.DISCORD_PUBLIC_KEY!, + token: process.env.DISCORD_BOT_TOKEN!, + serverPort: parseInt(process.env.PORT ?? '0', 10) || 8020, + serverHost: process.env.HOST ?? '0.0.0.0', + endpointPath: '/interactions' }); creator.on('debug', (message) => console.log(message)); @@ -34,18 +34,33 @@ creator.on('commandRegister', (command) => console.info(`Registered command ${co creator.on('commandError', (command, error) => console.error(`Command ${command.commandName}:`, error)); const server = fastify({ - logger: true, -}) - -creator.withServer(new FastifyServer(server)).registerCommands([HealCharacterCommand, HarmCharacterCommand, ExperienceCharacterCommand, LuckCharacterCommand, CharacterStatusCommand]).startServer().then(() => { - console.info("startServer completed") - if (process.env.DEVELOPMENT_GUILD_ID) { - creator.syncCommandsIn(process.env.DEVELOPMENT_GUILD_ID).then(() => { - console.info("synchronized commands") - }) - } -}).catch((err) => { - console.error(err) + logger: true }); +const options = { dataDir: process.env.DATA_DIR ?? '../data' }; + +creator + .withServer(new FastifyServer(server)) + .registerCommands([ + new HealCharacterCommand(creator, options), + new HarmCharacterCommand(creator, options), + new ExperienceCharacterCommand(creator, options), + new LuckCharacterCommand(creator, options), + new CharacterStatusCommand(creator, options), + new PartyCommand(creator, options) + ]); +creator + .startServer() + .then(() => { + console.info('startServer completed'); + if (process.env.DEVELOPMENT_GUILD_ID) { + creator.syncCommandsIn(process.env.DEVELOPMENT_GUILD_ID).then(() => { + console.info('synchronized commands'); + }); + } + }) + .catch((err: unknown) => { + console.error(err); + }); + console.info(`Starting server at "localhost:${creator.options.serverPort}/interactions"`); diff --git a/src/renderStatus.ts b/src/renderStatus.ts index a133ea7..1aa03f8 100644 --- a/src/renderStatus.ts +++ b/src/renderStatus.ts @@ -1,185 +1,189 @@ -import {Resvg} from "@resvg/resvg-js"; -import {JSDOM} from "jsdom"; +import { Resvg } from '@resvg/resvg-js'; +import { JSDOM } from 'jsdom'; + +export interface Element { + remove(): void; +} export interface GameStatus { - health: number - unstable: boolean - healthDelta: number - experience: number - experienceDelta: number - luck: number - luckDelta: number + health: number; + unstable: boolean; + healthDelta: number; + experience: number; + experienceDelta: number; + luck: number; + luckDelta: number; } export interface GameStatusWithPortrait extends GameStatus { - portrait: Buffer + portrait: Buffer; } function removeElement(dom: Element): void { - dom.remove() + dom.remove(); } function healthBelow(health: number): (status: GameStatus) => boolean { - return (s) => s.health < health + return (s) => s.health < health; } function luckBelow(luck: number): (status: GameStatus) => boolean { - return (s) => s.luck < luck + return (s) => s.luck < luck; } function experienceBelow(exp: number): (status: GameStatus) => boolean { - return (s) => s.experience < exp + return (s) => s.experience < exp; } function healthNotEqual(health: number): (status: GameStatus) => boolean { - return (s) => s.health !== health + return (s) => s.health !== health; } function experienceDeltaNotIncludes(index: number): (status: GameStatus) => boolean { return (s) => { if (s.experienceDelta <= 0) { - return true + return true; } - const effectiveMax = Math.min(5, s.experience) - return !(index <= effectiveMax && index > effectiveMax - s.experienceDelta) - } + const effectiveMax = Math.min(5, s.experience); + return !(index <= effectiveMax && index > effectiveMax - s.experienceDelta); + }; } function luckDeltaNotIncludes(index: number): (status: GameStatus) => boolean { return (s) => { if (s.luckDelta === 0) { - return true + return true; } else if (s.luckDelta > 0) { - return !((index <= s.luck) && (index > s.luck - s.luckDelta)) + return !(index <= s.luck && index > s.luck - s.luckDelta); } else { - return !((index > s.luck) && (index <= s.luck - s.luckDelta)) + return !(index > s.luck && index <= s.luck - s.luckDelta); } - } + }; } function healthDamageNotIncludes(index: number): (status: GameStatus) => boolean { return (s) => { if (s.healthDelta >= 0) { - return true + return true; } - return !((index > s.health) && (index <= s.health - s.healthDelta)) - } + return !(index > s.health && index <= s.health - s.healthDelta); + }; } function healthRecoveredNotIncludes(index: number): (status: GameStatus) => boolean { return (s) => { if (s.healthDelta <= 0) { - return true + return true; } - return !((index <= s.health) && (index > s.health - s.healthDelta)) - } + return !(index <= s.health && index > s.health - s.healthDelta); + }; } function notStableAlive(): (status: GameStatus) => boolean { - return (status) => status.unstable || status.health <= 0 + return (status) => status.unstable || status.health <= 0; } function notUnstableAlive(): (status: GameStatus) => boolean { - return (status) => !status.unstable || status.health <= 0 + return (status) => !status.unstable || status.health <= 0; } function notDead(): (status: GameStatus) => boolean { - return (status) => status.health > 0 + return (status) => status.health > 0; } function dead(): (status: GameStatus) => boolean { - return (status) => status.health <= 0 + return (status) => status.health <= 0; } const mappings: [filter: (status: GameStatus) => boolean, selector: string, hit: (dom: Element) => void][] = [ - [healthBelow(8), "#health8", removeElement], - [healthBelow(7), "#health7", removeElement], - [healthBelow(6), "#health6", removeElement], - [healthBelow(5), "#health5", removeElement], - [healthBelow(4), "#health4", removeElement], - [healthBelow(3), "#health3", removeElement], - [healthBelow(2), "#health2", removeElement], - [healthBelow(1), "#health1", removeElement], - - [luckBelow(7), "#luck7", removeElement], - [luckBelow(6), "#luck6", removeElement], - [luckBelow(5), "#luck5", removeElement], - [luckBelow(4), "#luck4", removeElement], - [luckBelow(3), "#luck3", removeElement], - [luckBelow(2), "#luck2", removeElement], - [luckBelow(1), "#luck1", removeElement], - - [experienceBelow(5), "#experienceLevelUpReady", removeElement], - [experienceBelow(5), "#experience5", removeElement], - [experienceBelow(4), "#experience4", removeElement], - [experienceBelow(3), "#experience3", removeElement], - [experienceBelow(2), "#experience2", removeElement], - [experienceBelow(1), "#experience1", removeElement], - - [healthDamageNotIncludes(8), "#healthDamage8", removeElement], - [healthDamageNotIncludes(7), "#healthDamage7", removeElement], - [healthDamageNotIncludes(6), "#healthDamage6", removeElement], - [healthDamageNotIncludes(5), "#healthDamage5", removeElement], - [healthDamageNotIncludes(4), "#healthDamage4", removeElement], - [healthDamageNotIncludes(3), "#healthDamage3", removeElement], - [healthDamageNotIncludes(2), "#healthDamage2", removeElement], - [healthDamageNotIncludes(1), "#healthDamage1", removeElement], - - [healthRecoveredNotIncludes(8), "#healthRecovery8", removeElement], - [healthRecoveredNotIncludes(7), "#healthRecovery7", removeElement], - [healthRecoveredNotIncludes(6), "#healthRecovery6", removeElement], - [healthRecoveredNotIncludes(5), "#healthRecovery5", removeElement], - [healthRecoveredNotIncludes(4), "#healthRecovery4", removeElement], - [healthRecoveredNotIncludes(3), "#healthRecovery3", removeElement], - [healthRecoveredNotIncludes(2), "#healthRecovery2", removeElement], - [healthRecoveredNotIncludes(1), "#healthRecovery1", removeElement], - - [healthNotEqual(8), "#healthCounter8", removeElement], - [healthNotEqual(7), "#healthCounter7", removeElement], - [healthNotEqual(6), "#healthCounter6", removeElement], - [healthNotEqual(5), "#healthCounter5", removeElement], - [healthNotEqual(4), "#healthCounter4", removeElement], - [healthNotEqual(3), "#healthCounter3", removeElement], - [healthNotEqual(2), "#healthCounter2", removeElement], - [healthNotEqual(1), "#healthCounter1", removeElement], - [healthNotEqual(0), "#healthCounter0", removeElement], - - [luckDeltaNotIncludes(7), "#luckShine7", removeElement], - [luckDeltaNotIncludes(6), "#luckShine6", removeElement], - [luckDeltaNotIncludes(5), "#luckShine5", removeElement], - [luckDeltaNotIncludes(4), "#luckShine4", removeElement], - [luckDeltaNotIncludes(3), "#luckShine3", removeElement], - [luckDeltaNotIncludes(2), "#luckShine2", removeElement], - [luckDeltaNotIncludes(1), "#luckShine1", removeElement], - - [experienceDeltaNotIncludes(5), "#experienceUp5", removeElement], - [experienceDeltaNotIncludes(4), "#experienceUp4", removeElement], - [experienceDeltaNotIncludes(3), "#experienceUp3", removeElement], - [experienceDeltaNotIncludes(2), "#experienceUp2", removeElement], - [experienceDeltaNotIncludes(1), "#experienceUp1", removeElement], - - [notStableAlive(), "#healthIcon", removeElement], - [notUnstableAlive(), "#healthLowIcon", removeElement], - [notDead(), "#healthEmptyIcon", removeElement], - [notDead(), "#characterDyingFace", removeElement], - [dead(), "#characterFaceImage", removeElement] -] + [healthBelow(8), '#health8', removeElement], + [healthBelow(7), '#health7', removeElement], + [healthBelow(6), '#health6', removeElement], + [healthBelow(5), '#health5', removeElement], + [healthBelow(4), '#health4', removeElement], + [healthBelow(3), '#health3', removeElement], + [healthBelow(2), '#health2', removeElement], + [healthBelow(1), '#health1', removeElement], + + [luckBelow(7), '#luck7', removeElement], + [luckBelow(6), '#luck6', removeElement], + [luckBelow(5), '#luck5', removeElement], + [luckBelow(4), '#luck4', removeElement], + [luckBelow(3), '#luck3', removeElement], + [luckBelow(2), '#luck2', removeElement], + [luckBelow(1), '#luck1', removeElement], + + [experienceBelow(5), '#experienceLevelUpReady', removeElement], + [experienceBelow(5), '#experience5', removeElement], + [experienceBelow(4), '#experience4', removeElement], + [experienceBelow(3), '#experience3', removeElement], + [experienceBelow(2), '#experience2', removeElement], + [experienceBelow(1), '#experience1', removeElement], + + [healthDamageNotIncludes(8), '#healthDamage8', removeElement], + [healthDamageNotIncludes(7), '#healthDamage7', removeElement], + [healthDamageNotIncludes(6), '#healthDamage6', removeElement], + [healthDamageNotIncludes(5), '#healthDamage5', removeElement], + [healthDamageNotIncludes(4), '#healthDamage4', removeElement], + [healthDamageNotIncludes(3), '#healthDamage3', removeElement], + [healthDamageNotIncludes(2), '#healthDamage2', removeElement], + [healthDamageNotIncludes(1), '#healthDamage1', removeElement], + + [healthRecoveredNotIncludes(8), '#healthRecovery8', removeElement], + [healthRecoveredNotIncludes(7), '#healthRecovery7', removeElement], + [healthRecoveredNotIncludes(6), '#healthRecovery6', removeElement], + [healthRecoveredNotIncludes(5), '#healthRecovery5', removeElement], + [healthRecoveredNotIncludes(4), '#healthRecovery4', removeElement], + [healthRecoveredNotIncludes(3), '#healthRecovery3', removeElement], + [healthRecoveredNotIncludes(2), '#healthRecovery2', removeElement], + [healthRecoveredNotIncludes(1), '#healthRecovery1', removeElement], + + [healthNotEqual(8), '#healthCounter8', removeElement], + [healthNotEqual(7), '#healthCounter7', removeElement], + [healthNotEqual(6), '#healthCounter6', removeElement], + [healthNotEqual(5), '#healthCounter5', removeElement], + [healthNotEqual(4), '#healthCounter4', removeElement], + [healthNotEqual(3), '#healthCounter3', removeElement], + [healthNotEqual(2), '#healthCounter2', removeElement], + [healthNotEqual(1), '#healthCounter1', removeElement], + [healthNotEqual(0), '#healthCounter0', removeElement], + + [luckDeltaNotIncludes(7), '#luckShine7', removeElement], + [luckDeltaNotIncludes(6), '#luckShine6', removeElement], + [luckDeltaNotIncludes(5), '#luckShine5', removeElement], + [luckDeltaNotIncludes(4), '#luckShine4', removeElement], + [luckDeltaNotIncludes(3), '#luckShine3', removeElement], + [luckDeltaNotIncludes(2), '#luckShine2', removeElement], + [luckDeltaNotIncludes(1), '#luckShine1', removeElement], + + [experienceDeltaNotIncludes(5), '#experienceUp5', removeElement], + [experienceDeltaNotIncludes(4), '#experienceUp4', removeElement], + [experienceDeltaNotIncludes(3), '#experienceUp3', removeElement], + [experienceDeltaNotIncludes(2), '#experienceUp2', removeElement], + [experienceDeltaNotIncludes(1), '#experienceUp1', removeElement], + + [notStableAlive(), '#healthIcon', removeElement], + [notUnstableAlive(), '#healthLowIcon', removeElement], + [notDead(), '#healthEmptyIcon', removeElement], + [notDead(), '#characterDyingFace', removeElement], + [dead(), '#characterFaceImage', removeElement] +]; export async function renderStatus(svgTemplate: string, status: GameStatusWithPortrait): Promise { const dom = new JSDOM(svgTemplate, { - contentType: "image/svg+xml", + contentType: 'image/svg+xml', pretendToBeVisual: false, includeNodeLocations: false, - url: "https://localhost/status.xml" - }) + url: 'https://localhost/status.xml' + }); for (const [filter, selector, action] of mappings) { if (filter(status)) { for (const el of dom.window.document.querySelectorAll(selector)) { - action(el) + action(el); } } } - const resvg = new Resvg(dom.window.document.documentElement.outerHTML, {}) - resvg.resolveImage("https://invalid.invalid/face.png", status.portrait) - return resvg.render().asPng() + const resvg = new Resvg(dom.window.document.documentElement.outerHTML, {}); + resvg.resolveImage('https://invalid.invalid/face.png', status.portrait); + return resvg.render().asPng(); }